1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_StreamSoundPlayer.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 29727 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/snd/snd_StreamSoundPlayer.h>
19 #include <nw/snd/snd_StreamSoundFileLoader.h>
20 #include <nw/snd/snd_StreamBufferPool.h>
21 #include <nw/snd/snd_TaskManager.h>
22 
23 // #define DEBUG_STRM
24 
25 namespace
26 {
27 #ifdef DEBUG_STRM
28     FILE* s_pFile;
29     const char* DUMP_FILE = "_StreamSoundPlayer.dump";
30 #endif
31 
32 } // anonymous namespace
33 
34 
35 namespace nw {
36 namespace snd {
37 namespace internal {
38 namespace driver {
39 
40 
41 NN_ATTRIBUTE_ALIGN(32)
42 u8 StreamSoundPlayer::s_LoadBuffer[ StreamSoundPlayer::LOAD_BUFFER_SIZE ];
43 
StreamSoundPlayer()44 StreamSoundPlayer::StreamSoundPlayer()
45 {
46     u32 taskCount = m_StreamDataLoadTaskPool.Create(
47         m_StreamDataLoadTaskArea,
48         sizeof(m_StreamDataLoadTaskArea)
49     );
50     NW_ASSERT( taskCount == BUFFER_BLOCK_COUNT_MAX );
51 }
52 
~StreamSoundPlayer()53 StreamSoundPlayer::~StreamSoundPlayer()
54 {
55     Finalize();
56 
57     NW_ASSERT( m_StreamDataLoadTaskPool.Count() == BUFFER_BLOCK_COUNT_MAX );
58     m_StreamDataLoadTaskPool.Destroy(
59             m_StreamDataLoadTaskArea, sizeof(m_StreamDataLoadTaskArea) );
60 }
61 
Initialize()62 void StreamSoundPlayer::Initialize()
63 {
64     BasicSoundPlayer::Initialize();
65 
66     m_IsInitialized = false;
67     m_DataOffsetFromFileHead = 0;
68     m_pFileStream = NULL;
69 
70     m_IsPrepared          = false;
71     m_LoadFinishFlag      = false;
72     m_PauseStatus         = false;
73     m_LoadWaitFlag        = false;
74     m_IsNoRealtimeLoad    = false;
75     m_PlayFinishFlag      = false;
76     m_SkipUpdateAdpcmLoop = false;
77     m_ValidAdpcmLoop      = false;
78 
79     m_LoopCounter         = 0;
80     m_LoadWaitCount       = 0;
81 
82     // トラックの初期化
83     for ( int trackIndex = 0; trackIndex < STRM_TRACK_NUM; trackIndex++ )
84     {
85         StreamTrack& track  = m_Tracks[ trackIndex ];
86         track.m_ActiveFlag    = false;
87         track.m_Volume      = 1.0f;
88         track.m_Pan         = 0.0f;
89         track.m_SurroundPan = 0.0f;
90 #ifdef NW_PLATFORM_CTRWIN
91         track.m_pVoice      = NULL;
92 #endif
93     }
94 
95     // チャンネルの初期化
96     for ( int channelIndex = 0; channelIndex < STRM_CHANNEL_NUM; channelIndex++ )
97     {
98         StreamChannel& channel = m_Channels[ channelIndex ];
99         channel.m_pBufferAddress = NULL;
100 #ifdef NW_PLATFORM_CTR
101         channel.m_pVoice = NULL;
102 #endif
103     }
104 }
105 
106 /*---------------------------------------------------------------------------*
107   Name:         Setup
108 
109   Description:  ストリームプレイヤーのセットアップ
110 
111   Arguments:    pBufferPool - ストリームバッファのメモリプール
112 
113   Returns:      セットアップに成功したかどうか
114  *---------------------------------------------------------------------------*/
Setup(StreamBufferPool * pBufferPool,u32 allocChannelCount,u16 allocTrackFlag)115 StreamSoundPlayer::SetupResult StreamSoundPlayer::Setup(
116     StreamBufferPool* pBufferPool,
117     u32 allocChannelCount,
118     u16 allocTrackFlag
119 )
120 {
121     NW_NULL_ASSERT( pBufferPool );
122 
123     m_ChannelCount = ut::Min( allocChannelCount, STRM_CHANNEL_NUM );
124 
125     u32 bitMask = allocTrackFlag;
126     u32 trackIndex = 0;
127     while ( bitMask != 0 )
128     {
129         if ( bitMask & 0x01 )
130         {
131             if ( trackIndex >= STRM_TRACK_NUM )
132             {
133                 NW_WARNING(
134                     false, "Too large track index (%d). Max track index is %d.",
135                     trackIndex, STRM_TRACK_NUM-1
136                 );
137                 break;
138             }
139 
140             m_Tracks[ trackIndex ].m_ActiveFlag = true;
141         }
142 
143         bitMask >>= 1;
144         trackIndex++;
145     }
146     m_TrackCount = ut::Min( trackIndex, STRM_TRACK_NUM );
147     if ( m_TrackCount == 0 ) return SETUP_ERR_UNKNOWN;
148 
149     m_pBufferPool = pBufferPool;
150 //    NN_LOG("m_pBufferPool %08x\n",m_pBufferPool);
151 
152     {
153         // ストリームバッファ確保
154         if ( ! AllocStreamBuffers() )
155         {
156             NW_WARNING(false, "Failed to start stream sound for not enough stream channel instance." );
157             return SETUP_ERR_CANNOT_ALLOCATE_BUFFER;
158         }
159     }
160 
161 #ifdef NW_PLATFORM_CTR
162     for ( int ch = 0; ch < m_ChannelCount; ch++ )
163     {
164         StreamChannel& channel = m_Channels[ ch ];
165     }
166 #endif
167 
168     m_IsInitialized = true;
169 
170 #ifdef DEBUG_STRM
171     s_pFile = std::fopen( DUMP_FILE, "wb" );
172 #endif
173 
174     return SETUP_SUCCESS;
175 }
176 
177 /*---------------------------------------------------------------------------*
178   Name:         Finalize
179 
180   Description:  ストリームプレイヤーのシャットダウン
181 
182   Arguments:    None.
183 
184   Returns:      None.
185  *---------------------------------------------------------------------------*/
Finalize()186 void StreamSoundPlayer::Finalize()
187 {
188     if ( ! m_IsInitialized ) return;
189 
190     // タスクのキャンセル
191     TaskManager::GetInstance().CancelTaskById( reinterpret_cast<u32>(this) );
192 
193     // タスクの完了待ち
194     m_StreamHeaderLoadTask.Wait();
195     for ( StreamDataLoadTaskList::Iterator itr = m_StreamDataLoadTaskList.GetBeginIter();
196           itr != m_StreamDataLoadTaskList.GetEndIter();
197     )
198     {
199         StreamDataLoadTaskList::Iterator curItr = itr++;
200         StreamDataLoadTask* task = &*curItr;
201         task->Wait();
202         m_StreamDataLoadTaskList.Erase( task );
203         m_StreamDataLoadTaskPool.Free( task );
204 //            NN_LOG( "Task Cancel %08x\n", task );
205     }
206 
207     // ボイスとチャンネルの解放
208     FreeStreamBuffers();
209     FreeVoices();
210 
211     // ファイルストリームを閉じる
212     if ( m_pFileStream != NULL ) {
213         m_pFileStream->Close();
214         m_pFileStream = NULL;
215     }
216 
217     m_pBufferPool = NULL;
218 
219 #ifdef DEBUG_STRM
220     std::fclose( s_pFile );
221 #endif
222 
223     m_ActiveFlag = false;
224 
225     m_IsInitialized = false;
226 
227     BasicSoundPlayer::Finalize();
228 }
229 
230 /*---------------------------------------------------------------------------*
231   Name:         Prepare
232 
233   Description:  ストリーム再生の準備開始
234 
235   Arguments:    pFileStream - ストリームファイルのファイルストリーム
236                 startOffsetType - 開始オフセットタイプ
237                 startOffset - 開始オフセット
238 
239   Returns:      準備開始に成功したかどうか
240                 注:準備に成功したかどうかは、返り値では判断できない
241  *---------------------------------------------------------------------------*/
Prepare(io::FileStream * pFileStream,StartOffsetType startOffsetType,int startOffset)242 bool StreamSoundPlayer::Prepare(
243     io::FileStream* pFileStream,
244     StartOffsetType startOffsetType,
245     int startOffset
246 )
247 {
248     NW_ASSERT( m_IsInitialized );
249     NW_NULL_ASSERT( pFileStream );
250     NW_ASSERT( pFileStream->CanRead() );
251     NW_ASSERT( pFileStream->CanSeek() );
252 
253     m_pFileStream     = pFileStream;
254     m_StartOffsetType = startOffsetType;
255     m_StartOffset     = startOffset;
256 
257     m_IsTaskError    = false;
258     m_IsLoadingDelay = false;
259     m_ActiveFlag       = true;
260 
261     // ヘッダロードタスクの発行
262     m_StreamHeaderLoadTask.m_PlayerHandle    = this;
263     m_StreamHeaderLoadTask.m_pFileStream     = m_pFileStream;
264     m_StreamHeaderLoadTask.m_StartOffsetType = m_StartOffsetType;
265     m_StreamHeaderLoadTask.m_StartOffset     = m_StartOffset;
266 
267     m_StreamHeaderLoadTask.SetId(reinterpret_cast<u32>(this));
268     internal::TaskManager::GetInstance().AppendTask(
269             &m_StreamHeaderLoadTask,
270             internal::TaskManager::PRIORITY_MIDDLE );
271 
272     return true;
273 }
274 
275 /*---------------------------------------------------------------------------*
276   Description:  ストリームの再生開始
277 
278   Returns:      再生に成功したかどうか
279  *---------------------------------------------------------------------------*/
Start()280 void StreamSoundPlayer::Start()
281 {
282     if ( ! m_IsPrepared ) return;
283 
284     if ( ! m_StartedFlag )
285     {
286         s32 blockIndex = 0;
287         u32 blockOffset = 0;
288         s32 loopCount = 0;
289         if ( ! CalcStartOffset( &blockIndex, &blockOffset, &loopCount ) )
290         {
291             NW_ASSERT( false );
292             return;
293         }
294         m_LoopCounter += loopCount;
295 
296         const size_t sampleBufferLen =
297             static_cast<size_t>( m_DataBlockSize * m_PlayingBufferBlockCount );
298         const u32 sampleCount = Util::GetSampleByByte(
299                 sampleBufferLen, WaveFileReader::GetSampleFormat(m_StreamInfo.encodeMethod) );
300 
301         for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
302         {
303             StreamTrack& track = m_Tracks[ trackIndex ];
304             if ( ! track.m_ActiveFlag ) continue;
305 
306             // ボイスセットアップ
307             WaveInfo waveInfo;
308             waveInfo.sampleFormat = WaveFileReader::GetSampleFormat( m_StreamInfo.encodeMethod );
309             waveInfo.channelCount = track.m_TrackInfo.channelCount;
310             waveInfo.sampleRate   = m_StreamInfo.sampleRate;
311 
312         #ifdef NW_PLATFORM_CTRWIN
313             waveInfo.loopFlag     = true;
314 
315             if ( m_IsNoRealtimeLoad )
316             {
317                 if ( m_StreamInfo.isLoop )
318                 {
319                     waveInfo.loopStartFrame = m_StreamInfo.loopStart;
320                 }
321                 else
322                 {
323                     waveInfo.loopStartFrame = 0;
324                 }
325                 waveInfo.loopEndFrame = m_StreamInfo.frameCount;
326             }
327             else
328             {
329                 // ふだんはコチラ
330                 waveInfo.loopStartFrame = 0;
331                 waveInfo.loopEndFrame = sampleCount;
332             }
333 
334             for( int channelIndex = 0;
335                  channelIndex < track.m_TrackInfo.channelCount;
336                  channelIndex++ )
337             {
338                 StreamChannel* channel = GetTrackChannel( track, channelIndex );
339                 if ( channel == NULL ) continue;
340 
341                 WaveInfo::ChannelParam& channelParam = waveInfo.channelParam[ channelIndex ];
342 
343                 channelParam.dataAddress    = channel->m_pBufferAddress;
344                 channelParam.adpcmParam     = channel->m_AdpcmParam;
345                 channelParam.adpcmLoopParam = channel->m_AdpcmLoopParam;
346 
347                 // NN_LOG("### LOOP CONTEXT  PS(0x%04X) yn1(0x%04X) yn2(0x%04X)\n",
348                 //         channelParam.m_AdpcmLoopParam.loopPredScale,
349                 //         channelParam.m_AdpcmLoopParam.loopYn1,
350                 //         channelParam.m_AdpcmLoopParam.loopYn2 );
351 
352                 // ADPCMのパラメータをブロックの先頭のものに書き換える
353                 // (ブロック内のオフセットスタートはVoiceクラスで処理する)
354                 channelParam.adpcmParam.predScale = *reinterpret_cast<u8*>(
355                     channel->m_pBufferAddress
356                 );
357             }
358 
359             if ( track.m_pVoice != NULL )
360             {
361                 track.m_pVoice->Initialize( waveInfo, blockOffset );
362 
363                 track.m_pVoice->SetVolume( 1.0f );  // TODO: 1.0, 1.0 を入れないといけない
364                                                             // が、対応としてはよろしくない。
365                                                             // (NW4C-0.1.0~)
366                 track.m_pVoice->Start();
367             }
368             if ( m_IsNoRealtimeLoad && ! m_StreamInfo.isLoop )
369             {
370                 SetLoopEndToZeroBuffer( m_StreamInfo.blockCount - 1 );
371             }
372 
373         #else
374             for ( int ch = 0; ch < track.m_TrackInfo.channelCount; ch++ )
375             {
376                 StreamChannel* channel = GetTrackChannel( track, ch );
377                 if ( channel == NULL ) continue;
378 
379                 if ( channel->m_pVoice != NULL )
380                 {
381                     channel->m_pVoice->Initialize( waveInfo, blockOffset );
382                     channel->m_pVoice->Start();
383                 }
384             }
385         #endif
386         }
387 
388     #ifdef NW_PLATFORM_CTRWIN
389         // 途中再生のためのループエンド設定
390         if ( blockIndex == m_StreamInfo.blockCount - 2 )
391         {
392             UpdateDataLoopAddress( 1 );
393         }
394         else if ( blockIndex == m_StreamInfo.blockCount - 1 )
395         {
396             UpdateDataLoopAddress( 0 );
397         }
398     #endif
399 
400         UpdatePauseStatus();
401 
402         // プレイヤー登録
403         SoundThread::GetInstance().RegisterPlayerCallback( this );
404 
405         m_StartedFlag = true;
406     }
407 }
408 
IsDspAdpcm() const409 bool StreamSoundPlayer::IsDspAdpcm() const
410 {
411     if ( WaveFileReader::GetSampleFormat( m_StreamInfo.encodeMethod )
412             == SAMPLE_FORMAT_DSP_ADPCM )
413     {
414         return true;
415     }
416     return false;
417 }
418 
419 /*---------------------------------------------------------------------------*
420   Name:         Stop
421 
422   Description:  ストリームの再生停止
423 
424   Arguments:    None.
425 
426   Returns:      None.
427   *---------------------------------------------------------------------------*/
Stop()428 void StreamSoundPlayer::Stop()
429 {
430     // ボイスの停止
431 #ifdef NW_PLATFORM_CTRWIN
432     for ( int trackIndex = 0; trackIndex < STRM_TRACK_NUM; trackIndex++ )
433     {
434         if ( ! m_Tracks[ trackIndex ].m_ActiveFlag ) continue;
435         Voice* voice = m_Tracks[ trackIndex ].m_pVoice;
436         if ( voice != NULL )
437         {
438             voice->Stop();
439         }
440     }
441 #else
442     for ( int ch = 0; ch < m_ChannelCount; ch++ )
443     {
444         Voice* voice = m_Channels[ch].m_pVoice;
445         if ( voice != NULL )
446         {
447             voice->Stop();
448         }
449     }
450 #endif
451 
452     // プレイヤー登録の解除
453     if ( m_StartedFlag ) {
454         SoundThread::GetInstance().UnregisterPlayerCallback( this );
455         m_StartedFlag = false;
456     }
457 
458     // 停止完了
459     m_IsPrepared = false;
460 }
461 
462 /*---------------------------------------------------------------------------*
463   Name:         Pause
464 
465   Description:  ストリームの一時停止/再開
466 
467   Arguments:    flag - trueで停止、falseで再開
468 
469   Returns:      None.
470  *---------------------------------------------------------------------------*/
471 
Pause(bool flag)472 void StreamSoundPlayer::Pause( bool flag )
473 {
474     m_PauseFlag = flag;
475     if ( flag ) m_LoadWaitFlag = true;
476 
477     UpdatePauseStatus();
478 }
479 
480 /*---------------------------------------------------------------------------*
481   Name:         GetStreamDataInfo
482 
483   Description:  ストリームデータの情報取得
484 
485   Arguments:    info - ストリームデータ情報構造体
486 
487   Returns:      現在の再生しているストリームデータの情報を取得する
488  *---------------------------------------------------------------------------*/
ReadStreamDataInfo(StreamDataInfo * info) const489 bool StreamSoundPlayer::ReadStreamDataInfo( StreamDataInfo* info ) const
490 {
491     SoundThreadLock lock;
492 
493     if ( ! m_IsPrepared ) return false;
494     info->loopFlag    = m_StreamInfo.isLoop != 0;
495     info->sampleRate  = m_StreamInfo.sampleRate;
496     info->loopStart   = m_StreamInfo.loopStart;
497     info->loopEnd     = m_StreamInfo.frameCount;
498     return true;
499 }
500 
501 /*---------------------------------------------------------------------------*
502   Name:         GetPlaySamplePosition
503 
504   Description:  現在の再生位置の取得
505 
506   Arguments:    なし
507 
508   Returns:      現在の再生位置をサンプル単位で返す
509                 再生していない場合は、負の値を返す
510  *---------------------------------------------------------------------------*/
GetPlaySamplePosition() const511 long StreamSoundPlayer::GetPlaySamplePosition() const
512 {
513     SoundThreadLock lock;
514 
515     if ( ! m_ActiveFlag ) return -1;
516     if ( ! m_Tracks[ 0 ].m_ActiveFlag ) return -1;
517     if ( ! m_IsPrepared ) return 0;
518 
519     s32 bufOffset = 0;
520 
521 #ifdef NW_PLATFORM_CTRWIN
522     if ( m_Tracks[ 0 ].m_pVoice != NULL )
523     {
524         bufOffset = static_cast<s32>( m_Tracks[ 0 ].m_pVoice->GetCurrentPlayingSample() );
525     }
526     s32 pos = ( m_PlayingDataBlockIndex - m_PlayingBufferBlockIndex )
527          * static_cast<s32>( m_StreamInfo.oneBlockSamples );
528 #else
529     if ( m_Channels[ 0 ].m_pVoice != NULL )
530     {
531         bufOffset = static_cast<s32>( m_Channels[ 0 ].m_pVoice->GetCurrentPlayingSample() );
532     }
533     s32 pos = ( m_PlayingDataBlockIndex ) * static_cast<s32>( m_StreamInfo.oneBlockSamples );
534 #endif
535     return pos + bufOffset;
536 }
537 
538 /*---------------------------------------------------------------------------*
539   Name:         GetFilledBufferRate
540 
541   Description:  ストリームバッファ中でデータがロードされている割合を取得する
542 
543   Arguments:    なし
544 
545   Returns:      データがロードされている割合を百分率で返す
546  *---------------------------------------------------------------------------*/
GetFilledBufferPercentage() const547 f32 StreamSoundPlayer::GetFilledBufferPercentage() const
548 {
549     SoundThreadLock lock;
550 
551     if ( ! m_ActiveFlag ) return 0.0f;
552     if ( ! m_Tracks[ 0 ].m_ActiveFlag ) return 0.0f;
553     if ( ! m_IsPrepared )
554     {
555         return static_cast<f32>( m_BufferBlockCountBase - m_PrepareCounter ) * 100.f / m_BufferBlockCountBase;
556     }
557 
558     s32 bufOffset = 0;
559 #ifdef NW_PLATFORM_CTRWIN
560     if ( m_Tracks[ 0 ].m_pVoice != NULL )
561     {
562         bufOffset = static_cast<s32>( m_Tracks[ 0 ].m_pVoice->GetCurrentPlayingSample() );
563     }
564 #else
565     if ( m_Channels[ 0 ].m_pVoice != NULL )
566     {
567         bufOffset = static_cast<s32>( m_Channels[ 0 ].m_pVoice->GetCurrentPlayingSample() );
568     }
569 #endif
570 
571     f32 nonFilledBufferBlock =
572         m_StreamDataLoadTaskList.GetSize() +
573         ( static_cast<f32>( bufOffset -
574             ( m_PlayingBufferBlockIndex * static_cast<s32>( m_StreamInfo.oneBlockSamples ) )
575           ) / m_StreamInfo.oneBlockSamples
576         )
577         ;
578 
579     int limit = m_BufferBlockCountBase - 2 + 1;
580 
581     f32 percentage = ( limit - nonFilledBufferBlock ) * 100.0f / limit;
582     percentage = ut::Max( percentage, 0.0f );
583 
584     return percentage;
585 }
586 
587 /* ------------------------------------------------------------------------
588         private functions
589    ------------------------------------------------------------------------ */
590 
591 /*---------------------------------------------------------------------------*
592   Name:         LoadHeader
593 
594   Description:  ストリームファイルヘッダの読み込みと
595                 再生開始のための、セットアップ処理
596 
597   Arguments:    pFileStream - ファイルストリーム
598                 startOffsetType - 開始オフセットタイプ
599                 startOffset - 開始オフセット位置
600 
601   Returns:      成功したかどうか
602  *---------------------------------------------------------------------------*/
LoadHeader(const StreamSoundFile::StreamSoundInfo & streamInfo,const StreamSoundFileReader::TrackInfo trackInfos[],const DspAdpcmParam dspAdpcmParam[],const DspAdpcmLoopParam dspAdpcmLoopParam[],u32 dataBlockOffset,u32 trackCount,u32 channelCount)603 bool StreamSoundPlayer::LoadHeader(
604     const StreamSoundFile::StreamSoundInfo& streamInfo,
605     const StreamSoundFileReader::TrackInfo trackInfos[],
606     const DspAdpcmParam dspAdpcmParam[],
607     const DspAdpcmLoopParam dspAdpcmLoopParam[],
608     u32 dataBlockOffset,
609     u32 trackCount,
610     u32 channelCount
611 )
612 {
613     (void)trackCount;
614     (void)channelCount;
615 
616     if ( ! m_IsInitialized ) {
617         // 終了処理後に、コマンドバッファにたまっていたコマンドが処理され
618         // ここに来る場合がある
619         return false;
620     }
621 
622     m_StreamInfo = streamInfo;
623 
624 #if 0
625     // DEBUG: ストリーム情報ダンプ
626     {
627         NN_LOG("*** STREAM INFO ***\n");
628         NN_LOG("  enc(%d) loop(%d) ch(%d) rate(%d)\n",
629                m_StreamInfo.encodeMethod, m_StreamInfo.isLoop,
630                m_StreamInfo.channelCount, m_StreamInfo.sampleRate );
631         NN_LOG("  LS(%d[0x%08X]) LE(%d[0x%08X] block(%d)\n",
632                m_StreamInfo.loopStart,
633                m_StreamInfo.loopStart,
634                m_StreamInfo.frameCount,
635                m_StreamInfo.frameCount,
636                m_StreamInfo.blockCount );
637         NN_LOG("  [1-Block]   bytes(%d) samples(%d)\n",
638                m_StreamInfo.oneBlockBytes, m_StreamInfo.oneBlockSamples );
639         NN_LOG("  [LastBlock] bytes(%d) samples(%d) paddedBytes(%d)\n",
640                m_StreamInfo.lastBlockBytes, m_StreamInfo.lastBlockSamples,
641                m_StreamInfo.lastBlockPaddedBytes );
642         NN_LOG("  [SEEK] size4one(%d) intervalSamples(%d)\n",
643                m_StreamInfo.sizeofSeekInfoAtom, m_StreamInfo.seekInfoIntervalSamples );
644     }
645 #endif
646 
647     m_DataOffsetFromFileHead =
648         dataBlockOffset     // ファイル先頭から DATA ブロックへのオフセット
649         + sizeof( ut::BinaryBlockHeader )       // DATA ブロックヘッダーサイズ
650         + m_StreamInfo.sampleDataOffset.offset;
651     // DATA ブロックボディから、実データが始まる地点までのオフセット
652 
653     // Setup時に渡された値と同じかどうか
654     NW_ASSERT( m_TrackCount == ut::Min( trackCount, STRM_TRACK_NUM ) );
655     NW_ASSERT( m_ChannelCount == ut::Min( channelCount, STRM_CHANNEL_NUM ) );
656 
657     // トラックの情報を読み取る
658     for ( int i = 0; i < m_TrackCount; i++ )
659     {
660         m_Tracks[i].m_TrackInfo = trackInfos[i];
661 
662 #ifdef NW_PLATFORM_CTR
663         // StreamChannel を StreamTrack に割り当て
664         for ( int j = 0; j < trackInfos[i].channelCount; j++ )
665         {
666             m_Tracks[i].m_pChannels[j] = &m_Channels[ trackInfos[i].globalChannelIndex[j] ];
667         }
668 #endif
669     }
670 
671     if ( IsDspAdpcm() )
672     {
673         // ADPCMの情報を読み取る
674         for ( int ch = 0; ch < m_ChannelCount; ch++ )
675         {
676             m_Channels[ch].m_AdpcmParam = dspAdpcmParam[ch];
677             m_Channels[ch].m_AdpcmLoopParam = dspAdpcmLoopParam[ch];
678 
679 #ifdef NW_PLATFORM_CTR
680             // コンテキストの保持 (ボイスへの係数設定は、AllocVoices の中でやる。)
681             nn::snd::AdpcmContext& context0 =
682                 m_Channels[ch].m_AdpcmContext[StreamChannel::ADPCM_CONTEXT_HEAD];
683             context0.pred_scale = m_Channels[ch].m_AdpcmParam.predScale;
684             context0.yn1 = m_Channels[ch].m_AdpcmParam.yn1;
685             context0.yn2 = m_Channels[ch].m_AdpcmParam.yn2;
686 
687             if ( m_StreamInfo.isLoop )
688             {
689                 nn::snd::AdpcmContext& context1 =
690                     m_Channels[ch].m_AdpcmContext[StreamChannel::ADPCM_CONTEXT_LOOP];
691                 context1.pred_scale = m_Channels[ch].m_AdpcmLoopParam.loopPredScale;
692                 context1.yn1 = m_Channels[ch].m_AdpcmLoopParam.loopYn1;
693                 context1.yn2 = m_Channels[ch].m_AdpcmLoopParam.loopYn2;
694             }
695 #endif
696         }
697     }
698 
699     // ストリームプレイヤーのセットアップ
700     if ( ! SetupPlayer() )
701     {
702         return false;
703     }
704 
705     // セットアップコールバック呼び出し
706     m_PrepareCounter = 0;
707     for ( int i = 0; i < m_BufferBlockCountBase; i++ )
708     {
709         UpdateLoadingBlockIndex();
710         m_PrepareCounter++;
711 
712         if ( m_LoadFinishFlag ) break;
713     }
714 
715 #ifdef NW_PLATFORM_CTRWIN
716     // ブロック数が小さい時は、このタイミングでワンショットに設定する
717     if ( ( m_StreamInfo.blockCount <= 2 ) && !m_StreamInfo.isLoop ) // TODO: Magic Number
718     {
719         SetLoopEndToZeroBuffer( static_cast<int>( m_StreamInfo.blockCount ) - 1 );
720     }
721 #endif
722 
723     // ボイス確保
724     if ( ! AllocVoices() )
725     {
726         FreeStreamBuffers();
727         return false;
728     }
729 
730     return true;
731 }
732 
733 /*---------------------------------------------------------------------------*
734   Name:         LoadStreamData
735 
736   Description:  ストリームデータのロード
737 
738   Arguments:    pFileStream - ファイルストリーム
739                 offset - 読み込みオフセット位置
740                 blockSize - ブロックサイズ
741                 bufferBlockIndex - バッファブロックインデックス
742                 needUpdateAdpcmLoop - ADPCMループ情報の更新が必要かどうか
743 
744   Returns:      ロードに成功したかどうか
745  *---------------------------------------------------------------------------*/
LoadStreamData(int bufferBlockIndex,int dataBlockIndex,u32 blockSamples,bool isDataLoopBlock,bool lastBlockFlag)746 bool StreamSoundPlayer::LoadStreamData(
747     int bufferBlockIndex,
748     int dataBlockIndex,
749     u32 blockSamples,
750     bool isDataLoopBlock,
751     bool lastBlockFlag
752 )
753 {
754     if ( ! m_IsInitialized ) {
755         // 終了処理後に、コマンドバッファにたまっていたコマンドが処理され
756         // ここに来る場合がある
757         return false;
758     }
759 
760     int currentChannel = 0;     // 0 ~ m_ChannelCount でインクリメント
761     while ( currentChannel < m_ChannelCount )
762     {
763         int loadChannelCount = LOAD_BUFFER_CHANNEL_NUM;
764         if ( currentChannel + loadChannelCount > m_ChannelCount )
765         {
766             loadChannelCount = m_ChannelCount - currentChannel;
767         }
768 
769         for ( int i = 0; i < loadChannelCount; i++ )
770         {
771             void* dest = ut::AddOffsetToPtr(
772                 m_Channels[ currentChannel ].m_pBufferAddress,
773                 m_DataBlockSize * bufferBlockIndex
774             );
775 #ifdef NW_PLATFORM_CTR
776             // WaveBuffer への割り付け
777             nn::snd::WaveBuffer* pBuffer =
778                 &m_Channels[currentChannel].m_WaveBuffer[bufferBlockIndex];
779             nn::snd::InitializeWaveBuffer( pBuffer );
780             pBuffer->bufferAddress = dest;
781             pBuffer->sampleLength = blockSamples;
782 
783             // ADPCM コンテキストの設定
784             if ( IsDspAdpcm() )
785             {
786                 if ( dataBlockIndex == 0 )
787                 {
788                     // データ先頭用のコンテキスト設定
789                     pBuffer->pAdpcmContext = &m_Channels[currentChannel].m_AdpcmContext[
790                         StreamChannel::ADPCM_CONTEXT_HEAD];
791                 }
792                 else if ( isDataLoopBlock )
793                 {
794                     // データループ用のコンテキスト設定
795                     pBuffer->pAdpcmContext = &m_Channels[currentChannel].m_AdpcmContext[
796                         StreamChannel::ADPCM_CONTEXT_LOOP];
797                 }
798                 else
799                 {
800                     // コンテキストを NULL に
801                     pBuffer->pAdpcmContext = NULL;
802                 }
803             }
804 
805             // Voice へのアペンド
806             m_Channels[currentChannel].AppendWaveBuffer( pBuffer, lastBlockFlag );
807 #endif
808 
809 //             NN_LOG("bufBlockIdx(%d) currentCh(%d) loadChCnt(%d) mCh(%d)\n",
810 //                     bufferBlockIndex, currentChannel,
811 //                     loadChannelCount, m_ChannelCount );
812 
813             ++currentChannel;
814         }
815     }
816 
817     // バッファ書き換え完了
818     if ( ! m_IsPrepared )
819     {
820         m_PrepareCounter--;
821         if ( m_PrepareCounter == 0 )
822         {
823             m_IsPrepared = true;
824         }
825     }
826 
827     --m_LoadWaitCount;
828 
829     return true;
830 }
831 
832 /*---------------------------------------------------------------------------*
833   Name:         SetupPlayer
834 
835   Description:  ストリームのセットアップ
836 
837   Arguments:    header - ストリームファイルヘッダ
838 
839   Returns:      成功したかどうか
840  *---------------------------------------------------------------------------*/
SetupPlayer()841 bool StreamSoundPlayer::SetupPlayer()
842 {
843     NW_NULL_ASSERT( m_pBufferPool );
844     const size_t strmBufferSize = m_pBufferPool->GetBlockSize();    // 1ch 分のバッファサイズ
845 
846     // 開始オフセットを求める
847     s32 blockIndex = 0;
848     u32 blockOffset = 0;
849     s32 loopCount = 0;
850     if ( ! CalcStartOffset( &blockIndex, &blockOffset, &loopCount ) )
851     {
852         // 再生できない開始オフセット
853         return false;
854     }
855 
856     m_LoopStartBlockIndex = static_cast<int>( m_StreamInfo.loopStart / m_StreamInfo.oneBlockSamples );
857     m_LastBlockIndex = static_cast<int>( m_StreamInfo.blockCount ) - 1;
858 
859     // ブロックサイズの取得
860     m_DataBlockSize = static_cast<int>( m_StreamInfo.oneBlockBytes );
861     if ( m_DataBlockSize > DATA_BLOCK_SIZE_MAX )
862     {
863         NW_WARNING( false, "Too large stream data block size." );
864         return false;
865     }
866     m_BufferBlockCount = strmBufferSize / m_DataBlockSize;
867     if ( m_BufferBlockCount < 4 )
868     {
869         NW_WARNING( false, "Too small stream buffer size." );
870         return false;
871     }
872     if ( m_BufferBlockCount > BUFFER_BLOCK_COUNT_MAX )
873     {
874         // 非同期ロードコマンド発行のため、上限を設定
875         m_BufferBlockCount = BUFFER_BLOCK_COUNT_MAX;
876     }
877     m_BufferBlockCountBase = m_BufferBlockCount - 1;
878     m_ChangeNumBlocks = m_BufferBlockCountBase;
879 
880     m_PlayingDataBlockIndex = blockIndex;
881     m_LoadingDataBlockIndex = blockIndex;
882 
883 // #ifdef NW_PLATFORM_CTRWIN
884     // 全データがバッファに入る場合は、非リアルタイムロードモードで処理する
885 //    m_IsNoRealtimeLoad = ( m_StreamInfo.blockCount <= m_BufferBlockCount ) ? true : false;
886 // #endif
887 
888     m_LoadingBufferBlockIndex = 0;
889     m_PlayingBufferBlockIndex = 0;
890 
891     if ( m_IsNoRealtimeLoad )
892     {
893         m_LoadingBufferBlockCount = static_cast<s32>( m_StreamInfo.blockCount );
894     }
895     else
896     {
897         m_LoadingBufferBlockCount = CalcLoadingBufferBlockCount();
898     }
899 
900     m_PlayingBufferBlockCount = m_LoadingBufferBlockCount;
901 
902     return true;
903 }
904 
905 /*---------------------------------------------------------------------------*
906   Name:         AllocStreamBuffers
907 
908   Description:  全チャンネルのストリームバッファを確保
909 
910   Arguments:    なし
911 
912   Returns:      成功したらtrue
913  *---------------------------------------------------------------------------*/
AllocStreamBuffers()914 bool StreamSoundPlayer::AllocStreamBuffers()
915 {
916     // 全チャンネル分のストリームバッファ確保
917     for( int index = 0; index < m_ChannelCount; index++ )
918     {
919         // 1 ブロック分 (1ch 分) のバッファを確保
920         void* strmBuffer = m_pBufferPool->Alloc();
921         if ( strmBuffer == NULL )
922         {
923             // ひとつでも失敗したら、すべてのバッファを返却し false を返す
924             for( int i = 0 ; i < index ; i++ )
925             {
926                 m_pBufferPool->Free( m_Channels[i].m_pBufferAddress );
927                 m_Channels[i].m_pBufferAddress = NULL;
928             }
929             return false;
930         }
931 
932         m_Channels[ index ].m_pBufferAddress = strmBuffer;
933     }
934     return true;
935 }
936 
937 /*---------------------------------------------------------------------------*
938   Name:         FreeStreamBuffers
939 
940   Description:  全チャンネルのストリームバッファを開放
941 
942   Arguments:    なし
943 
944   Returns:      なし
945  *---------------------------------------------------------------------------*/
FreeStreamBuffers()946 void StreamSoundPlayer::FreeStreamBuffers()
947 {
948     // ストリームバッファ開放
949     for( int index = 0; index < m_ChannelCount; index++ )
950     {
951         if ( m_Channels[ index ].m_pBufferAddress == NULL ) continue;
952 
953         m_pBufferPool->Free( m_Channels[index].m_pBufferAddress );
954         m_Channels[ index ].m_pBufferAddress = NULL;
955     }
956 }
957 
958 // 全 StreamTrack に対し、Voice を割り当てる
AllocVoices()959 bool StreamSoundPlayer::AllocVoices()
960 {
961 #ifdef NW_PLATFORM_CTRWIN
962     for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
963     {
964         StreamTrack& track = m_Tracks[ trackIndex ];
965 
966         if ( ! track.m_ActiveFlag ) continue;
967 
968         // Voice 確保
969         Voice* voice = VoiceManager::GetInstance().AllocVoice(
970             track.m_TrackInfo.channelCount,
971             Voice::PRIORITY_NODROP,
972             VoiceCallbackFunc,
973             &track
974         );
975         if ( voice == NULL )
976         {
977             for ( int i = 0; i < trackIndex; i++ )
978             {
979                 StreamTrack& t = m_Tracks[ i ];
980                 if ( t.m_pVoice != NULL )
981                 {
982                     t.m_pVoice->Free();
983                     t.m_pVoice = NULL;
984                 }
985             }
986             return false;
987         }
988         voice->SetFrontBypass( IsFrontBypass() );
989 
990         track.m_pVoice = voice;
991     }
992 #else
993     for ( int channelIndex = 0; channelIndex < m_ChannelCount; channelIndex++ )
994     {
995         StreamChannel& channel = m_Channels[ channelIndex ];
996 
997         // Voice 確保
998         Voice* voice = VoiceManager::GetInstance().AllocVoice(
999             1,      // channelCount
1000             Voice::PRIORITY_NODROP,
1001             VoiceCallbackFunc,
1002             &channel
1003         );
1004         if ( voice == NULL )
1005         {
1006             for ( int i = 0; i < channelIndex; i++ )
1007             {
1008                 StreamChannel& c = m_Channels[ i ];
1009                 if ( c.m_pVoice != NULL )
1010                 {
1011                     c.m_pVoice->Free();
1012                     c.m_pVoice = NULL;
1013                 }
1014             }
1015             return false;
1016         }
1017         voice->SetFrontBypass( IsFrontBypass() );
1018         channel.m_pVoice = voice;
1019 
1020         // ADPCM 係数の設定
1021         if ( IsDspAdpcm() )
1022         {
1023             // 係数の用意
1024             nn::snd::AdpcmParam param;
1025             for ( int i = 0; i < 16; i++ )
1026             {
1027                 param.coef[i] = channel.m_AdpcmParam.coef[i];
1028             }
1029 
1030             // 係数設定
1031             channel.m_pVoice->SetAdpcmParam( 0, param );
1032         }
1033     }
1034 #endif
1035     return true;
1036 }
1037 
1038 /*---------------------------------------------------------------------------*
1039   Name:         FreeAllTrackVoice
1040 
1041   Description:  ストリーム用チャンネルの解放
1042 
1043   Arguments:    player - ストリームオブジェクト
1044 
1045   Returns:      None.
1046  *---------------------------------------------------------------------------*/
FreeVoices()1047 void StreamSoundPlayer::FreeVoices()
1048 {
1049 #ifdef NW_PLATFORM_CTRWIN
1050     // AXボイス開放
1051     for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1052     {
1053         StreamTrack& track = m_Tracks[ trackIndex ];
1054         if ( ! track.m_ActiveFlag ) continue;
1055 
1056         if ( track.m_pVoice != NULL )
1057         {
1058             track.m_pVoice->Free();
1059             track.m_pVoice = NULL;
1060         }
1061     }
1062 #else
1063     for ( int ch = 0; ch < m_ChannelCount; ch++ )
1064     {
1065         StreamChannel& channel = m_Channels[ ch ];
1066         if ( channel.m_pVoice != NULL )
1067         {
1068             channel.m_pVoice->Free();
1069             channel.m_pVoice = NULL;
1070         }
1071     }
1072 #endif
1073 }
1074 
1075 /*---------------------------------------------------------------------------*
1076   Name:         UpdateTask
1077 
1078   Description:  タスクの状態をチェックし、完了したものの解放処理を行う
1079 
1080   Arguments:    None.
1081 
1082   Returns:      None.
1083  *---------------------------------------------------------------------------*/
UpdateTask()1084 void StreamSoundPlayer::UpdateTask()
1085 {
1086     for ( StreamDataLoadTaskList::Iterator itr = m_StreamDataLoadTaskList.GetBeginIter();
1087           itr != m_StreamDataLoadTaskList.GetEndIter();
1088         )
1089     {
1090         StreamDataLoadTaskList::Iterator curItr = itr++;
1091         StreamDataLoadTask* task = &*curItr;
1092         if ( task->GetStatus() != Task::STATUS_DONE ) break;
1093 
1094         m_StreamDataLoadTaskList.Erase( task );
1095         m_StreamDataLoadTaskPool.Free( task );
1096 
1097 //        NN_LOG("Free %08x %d\n",task,m_StreamDataLoadTaskList.size());
1098     }
1099 }
1100 
1101 /*---------------------------------------------------------------------------*
1102   Name:         Update
1103 
1104   Description:  パラメータ更新
1105                 (サウンドスレッドから呼びだされる)
1106 
1107   Arguments:    None.
1108 
1109   Returns:      None.
1110  *---------------------------------------------------------------------------*/
Update()1111 void StreamSoundPlayer::Update()
1112 {
1113     // タスクエラーのため、停止
1114     if ( m_IsTaskError ) {
1115         NW_WARNING( false, "Task error is occured." );
1116         Stop();
1117         return;
1118     }
1119 
1120     UpdateTask();
1121 
1122     // ストリームチャンネルの停止チェック
1123     if ( m_StartedFlag )
1124     {
1125 #ifdef NW_PLATFORM_CTRWIN
1126         for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1127         {
1128             StreamTrack& track = m_Tracks[ trackIndex ];
1129             if ( ! track.m_ActiveFlag ) continue;
1130             if ( track.m_pVoice == NULL )
1131             {
1132                 Stop();
1133                 m_FinishFlag = true;
1134                 return;
1135             }
1136         }
1137 #else
1138         for ( int ch = 0; ch < m_ChannelCount; ch++ )
1139         {
1140             StreamChannel& channel = m_Channels[ ch ];
1141             if ( channel.m_pVoice == NULL )
1142             {
1143                 Stop();
1144                 m_FinishFlag = true;
1145                 return;
1146             }
1147         }
1148 #endif
1149 
1150         // パラメータのアップデート
1151         for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1152         {
1153             UpdateVoiceParams( &m_Tracks[ trackIndex ] );
1154         }
1155     }
1156 
1157     // ロード待ちが解消されたかをチェック
1158     if ( m_LoadWaitFlag )
1159     {
1160         if ( m_StreamDataLoadTaskList.IsEmpty() &&  ( ! CheckDiskDriveError() ) )
1161         {
1162             m_LoadWaitFlag = false;
1163             UpdatePauseStatus();
1164         }
1165     }
1166 
1167     // ロード遅延メッセージ出力
1168     if ( m_IsLoadingDelay )
1169     {
1170         NW_WARNING( false, "Pause stream because of loading delay." );
1171         m_IsLoadingDelay = false;
1172     }
1173 }
1174 
UpdateVoiceParams(StreamTrack * track)1175 void StreamSoundPlayer::UpdateVoiceParams( StreamTrack* track )
1176 {
1177     if ( ! track->m_ActiveFlag ) return;
1178 
1179     // volume
1180     f32 volume = 1.0f;
1181     volume *= GetVolume();
1182     volume *= static_cast<f32>( track->m_TrackInfo.volume ) / 127.0f;
1183     volume *= track->m_Volume;
1184 
1185     // pitch
1186     f32 pitchRatio = 1.0f;
1187     pitchRatio *= GetPitch();
1188 
1189     // pan
1190     f32 pan = 0.0f;
1191     pan += GetPan();
1192 
1193     // m_TrackInfo.pan の範囲は 0-127。1 と 2 は結果的に同じ値として扱う。
1194     if ( track->m_TrackInfo.pan <= 1 )
1195     {
1196         pan += static_cast<f32>( static_cast<int>( track->m_TrackInfo.pan ) - 63 ) / 63.0f;
1197     }
1198     else
1199     {
1200         pan += static_cast<f32>( static_cast<int>( track->m_TrackInfo.pan ) - 64 ) / 63.0f;
1201     }
1202     pan += track->m_Pan;
1203 
1204     // surround pan
1205     f32 span = 0.0f;
1206     span += track->m_SurroundPan;
1207     span += GetSurroundPan();
1208 
1209     // lpf freq
1210     f32 lpfFreq = 1.0f;
1211     lpfFreq += GetLpfFreq();
1212 
1213     // biquad filter
1214     int biquadType = GetBiquadFilterType();
1215     f32 biquadValue = GetBiquadFilterValue();
1216 
1217     // main send
1218     f32 mainSend = 0.0f;
1219     mainSend += GetMainSend();
1220 
1221     // fx send
1222     f32 fxsend[ AUX_BUS_NUM ];
1223     for ( int i=0; i<AUX_BUS_NUM; i++ )
1224     {
1225         fxsend[ i ] = 0.0f;
1226         fxsend[ i ] += GetFxSend( AuxBus(i) );
1227     }
1228 
1229 
1230 #ifdef NW_PLATFORM_CTRWIN
1231     Voice* voice = track->m_pVoice;
1232     if ( voice != NULL )
1233     {
1234         voice->SetVolume( volume );
1235         voice->SetPitch( pitchRatio );
1236         voice->SetPan( pan );
1237         voice->SetSurroundPan( span );
1238         voice->SetLpfFreq( lpfFreq );
1239         voice->SetBiquadFilter( biquadType, biquadValue );
1240         voice->SetMainSend( mainSend );
1241         for ( int i=0; i<AUX_BUS_NUM; i++ )
1242         {
1243             AuxBus bus = static_cast<AuxBus>( i );
1244             voice->SetFxSend( bus, fxsend[ i ] );
1245         }
1246     }
1247 #else
1248     for ( int ch = 0; ch < track->m_TrackInfo.channelCount; ch++ )
1249     {
1250         Voice* voice = track->m_pChannels[ch]->m_pVoice;
1251 
1252         if ( voice != NULL )
1253         {
1254             voice->SetVolume( volume );
1255             voice->SetPitch( pitchRatio );
1256             voice->SetLpfFreq( lpfFreq );
1257             voice->SetBiquadFilter( biquadType, biquadValue );
1258             voice->SetMainSend( mainSend );
1259             for ( int i=0; i<AUX_BUS_NUM; i++ )
1260             {
1261                 AuxBus bus = static_cast<AuxBus>( i );
1262                 voice->SetFxSend( bus, fxsend[ i ] );
1263             }
1264 
1265             if ( track->m_TrackInfo.channelCount == 1 )
1266             {
1267                 voice->SetPan( pan );
1268             }
1269             else if ( track->m_TrackInfo.channelCount == 2 )
1270             {
1271             #if 0
1272                 // 1trk == 2ch の場合は、パンモード別のパン計算を行う
1273                 switch ( GetPanMode() )
1274                 {
1275                     case nw::snd::PAN_MODE_BALANCE:
1276                         if ( ch == 0 ) { pan = -1.0f; } // L に振る
1277                         if ( ch == 1 ) { pan =  1.0f; } // R に振る
1278                         break;
1279                     case nw::snd::PAN_MODE_DUAL:
1280                         if ( ch == 0 ) { pan -= 1.0f; } // L に寄せる
1281                         if ( ch == 1 ) { pan += 1.0f; } // R に寄せる
1282                         break;
1283                 }
1284                 voice->SetPan( pan );
1285             #else
1286                 // TODO: DualPan, BalancePan に対応するには、
1287                 //       StreamTrack に Voiceを持たせる形にする必要がある。
1288                 //       上記の #if 0 の部分は、実装イメージ。
1289                 //       BalancePan で pan を -1.0f や 1.0f に固定してしまうと、
1290                 //       GetPan() やトラックごとのデータパン・API パンが反映されなく鳴る。
1291                 register f32 voicePan = pan;
1292                 if ( ch == 0 ) { voicePan -= 1.0f; }
1293                 if ( ch == 1 ) { voicePan += 1.0f; }
1294                 voice->SetPan( voicePan );
1295             #endif
1296             }
1297             voice->SetSurroundPan( span );
1298         }
1299     }
1300 #endif
1301 }
1302 
1303 /*---------------------------------------------------------------------------*
1304   Name:         StreamSoundPlayer::CheckDiskDriveError
1305 
1306   Description:  ディスクドライブのエラーが発生しているかどうかチェックします。
1307 
1308   Arguments:    None.
1309 
1310   Returns:      エラーが発生しているかどうかを返します。
1311                 DVDストリームでない場合は、falseを返します。
1312   *---------------------------------------------------------------------------*/
CheckDiskDriveError() const1313 bool StreamSoundPlayer::CheckDiskDriveError() const
1314 {
1315 #if defined( NW_PLATFORM_CTRWIN ) || defined( NW_PLATFORM_CTR )
1316     // TODO: 関数名と挙動があっていない
1317     return nw::snd::SoundSystem::detail_IsStreamLoadWait();
1318 #else
1319     ut::DvdFileStream* dvdFileStream = ut::DynamicCast<ut::DvdFileStream*>( m_pFileStream );
1320     if ( dvdFileStream == NULL ) return false;
1321 
1322     s32 driveStatus = DVDGetDriveStatus();
1323     if ( driveStatus == DVD_STATE_END || driveStatus == DVD_STATE_BUSY )
1324     {
1325         // リクエストは終了しました / リクエストはありません。
1326         // リクエストは、現在処理中です。
1327         return false;
1328     }
1329     else
1330     {
1331         return true;
1332     }
1333 #endif
1334 }
1335 
1336 /*---------------------------------------------------------------------------*
1337   Name:         UpdateBuffer
1338 
1339   Description:  再生バッファの更新
1340                 (AXコールバックから呼びだされる)
1341 
1342   Arguments:    None.
1343 
1344   Returns:      None.
1345  *---------------------------------------------------------------------------*/
UpdateBuffer()1346 void StreamSoundPlayer::UpdateBuffer()
1347 {
1348     if ( ! m_StartedFlag ) return;
1349     if ( ! m_Tracks[ 0 ].m_ActiveFlag ) return;
1350 
1351 #ifdef NW_PLATFORM_CTRWIN
1352     Voice* voice = m_Tracks[ 0 ].m_pVoice;
1353 #else
1354     Voice* voice = m_Channels[ 0 ].m_pVoice;
1355 #endif
1356     if ( voice == NULL ) return;
1357     if ( ! voice->IsRun() ) return;
1358 
1359     if ( CheckDiskDriveError() )
1360     {
1361         m_LoadWaitFlag = true;
1362         UpdatePauseStatus();
1363     }
1364 
1365     // -------------------------
1366     // バッファのアップデート
1367     // バッファブロックの境界を越えたかチェックし、ファイルロードを発行する
1368     if ( ( !m_PlayFinishFlag ) && ( !m_IsNoRealtimeLoad ) && ( !m_LoadWaitFlag ) )
1369     {
1370 #ifdef NW_PLATFORM_CTRWIN
1371         const u32 playingSample = voice->GetCurrentPlayingSample();
1372         const int currentBlockIndex =
1373             static_cast<int>( playingSample / m_StreamInfo.oneBlockSamples );
1374 
1375         while ( m_PlayingBufferBlockIndex != currentBlockIndex )
1376 #else
1377         while ( m_Channels[0].m_WaveBuffer[m_PlayingBufferBlockIndex].status ==
1378                 nn::snd::WaveBuffer::STATUS_DONE )
1379 #endif
1380         {
1381             if ( m_PlayFinishFlag ) break;
1382 
1383 //            NN_LOG("DONE(%d) 0(%d) 1(%d) 2(%d) 3(%d) 4(%d)\n",
1384 //                     m_PlayingBufferBlockIndex,
1385 //                     m_Channels[0].m_WaveBuffer[0].status,
1386 //                     m_Channels[0].m_WaveBuffer[1].status,
1387 //                     m_Channels[0].m_WaveBuffer[2].status,
1388 //                     m_Channels[0].m_WaveBuffer[3].status,
1389 //                     m_Channels[0].m_WaveBuffer[4].status
1390 //                     );
1391             if ( ! m_LoadWaitFlag )
1392             {
1393                 // -------------------------
1394                 // ロードが追いついているかをチェック
1395                 if ( !m_StreamDataLoadTaskList.IsEmpty() &&
1396                      m_LoadWaitCount >= m_BufferBlockCountBase - 2 )
1397                 {
1398                     // ロードが追いついてない
1399                     m_IsLoadingDelay = true;
1400                     m_LoadWaitFlag = true;
1401                     UpdatePauseStatus();
1402                     break;
1403                 }
1404             }
1405 
1406             // 再生ブロックの更新
1407             UpdatePlayingBlockIndex();
1408 
1409             // ロードブロックの更新
1410             UpdateLoadingBlockIndex();
1411         }
1412     }
1413 }
1414 
1415 #ifdef NW_PLATFORM_CTRWIN
1416 /*---------------------------------------------------------------------------*
1417   Name:         UpdateLoopAddress
1418 
1419   Description:  ボイスのループアドレスを更新
1420 
1421   Arguments:    loopStartSamples - ループ開始サンプル位置
1422                 loopEndSamples - ループ終端サンプル位置
1423 
1424   Returns:      None.
1425  *---------------------------------------------------------------------------*/
UpdateLoopAddress(unsigned long loopStartSamples,unsigned long loopEndSamples)1426 void StreamSoundPlayer::UpdateLoopAddress(
1427     unsigned long loopStartSamples,
1428     unsigned long loopEndSamples
1429 )
1430 {
1431     for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1432     {
1433         StreamTrack& track = m_Tracks[ trackIndex ];
1434         if ( ! track.m_ActiveFlag ) continue;
1435         Voice* voice = track.m_pVoice;
1436         if ( voice == NULL ) continue;
1437 
1438         for ( int channelIndex = 0;
1439               channelIndex < track.m_TrackInfo.channelCount;
1440               channelIndex++ )
1441         {
1442             StreamChannel* channel = GetTrackChannel( m_Tracks[ trackIndex ], channelIndex );
1443 
1444             voice->SetLoopStart( channelIndex, channel->m_pBufferAddress, loopStartSamples );
1445             voice->SetLoopEnd( channelIndex, channel->m_pBufferAddress, loopEndSamples );
1446         }
1447         voice->SetLoopFlag( true );
1448     }
1449 }
1450 #endif
1451 
1452 /*---------------------------------------------------------------------------*
1453   Name:         UpdatePlayingBlockIndex
1454 
1455   Description:  再生位置のブロックインデックスを更新
1456 
1457   Arguments:    None.
1458 
1459   Returns:      None.
1460  *---------------------------------------------------------------------------*/
UpdatePlayingBlockIndex()1461 void StreamSoundPlayer::UpdatePlayingBlockIndex()
1462 {
1463     if ( m_PlayFinishFlag ) return;
1464 
1465     u32 playDataIdx = m_PlayingDataBlockIndex;
1466     u32 playBufIdx  = m_PlayingBufferBlockIndex;
1467 
1468     m_PlayingDataBlockIndex++;
1469 
1470     if ( m_PlayingDataBlockIndex > m_LastBlockIndex )
1471     {
1472         // 最終ブロックを再生し終えた
1473         if ( m_StreamInfo.isLoop )
1474         {
1475             // ループスタートへジャンプした
1476             m_PlayingDataBlockIndex = m_LoopStartBlockIndex;
1477             if ( m_LoopCounter < INT_MAX ) m_LoopCounter++;
1478 
1479           #ifdef NW_PLATFORM_CTRWIN
1480             UpdateLoopAddress( 0, m_PlayingBufferBlockCount * m_StreamInfo.oneBlockSamples );
1481           #endif
1482         }
1483     }
1484 
1485     // バッファブロック番号更新
1486     m_PlayingBufferBlockIndex++;
1487     if ( m_PlayingBufferBlockIndex >= m_PlayingBufferBlockCount )
1488     {
1489         // バッファループ発生
1490         m_PlayingBufferBlockIndex = 0;
1491 
1492         // バッファブロック数を、ロード情報に合わせて更新
1493         m_PlayingBufferBlockCount = m_LoadingBufferBlockCount;
1494 
1495       #ifdef NW_PLATFORM_CTRWIN
1496         UpdateLoopAddress( 0, m_PlayingBufferBlockCount * m_StreamInfo.oneBlockSamples );
1497       #endif
1498     }
1499 
1500     if ( m_PlayingBufferBlockIndex == m_PlayingBufferBlockCount-1 )
1501     {
1502         m_ValidAdpcmLoop = false;
1503         m_SkipUpdateAdpcmLoop = false;
1504     }
1505 
1506     // NN_LOG("### PlayingBufferBlockIdx(%d) PlayingDataBlockIdx(%2d)\n",
1507     //         m_PlayingBufferBlockIndex, m_PlayingDataBlockIndex );
1508 
1509     if ( m_PlayingDataBlockIndex >= m_LastBlockIndex - 1 )
1510     {
1511 #ifdef NW_PLATFORM_CTRWIN
1512         const s32 endBufferBlockIndex = m_PlayingBufferBlockIndex + 1;
1513 
1514         UpdateDataLoopAddress( endBufferBlockIndex );
1515 #else
1516         if ( ! m_StreamInfo.isLoop )
1517         {
1518             m_PlayFinishFlag = true;
1519         }
1520 #endif
1521     }
1522 }
1523 
1524 #ifdef NW_PLATFORM_CTRWIN
1525 /*---------------------------------------------------------------------------*
1526   Name:         UpdateDataLoopAddress
1527 
1528   Description:  データループのため、ボイスのアドレスを更新
1529 
1530   Arguments:    endBufferBlockIndex - 終端バッファのブロックインデックス
1531 
1532   Returns:      None.
1533  *---------------------------------------------------------------------------*/
UpdateDataLoopAddress(s32 endBufferBlockIndex)1534 void StreamSoundPlayer::UpdateDataLoopAddress( s32 endBufferBlockIndex )
1535 {
1536     // データループ直前
1537     if ( m_StreamInfo.isLoop )
1538     {
1539         // ループのためにバッファのループスタートとループエンドを動かす
1540 
1541         s32 startBlockNum = endBufferBlockIndex + 1;
1542         if ( startBlockNum >= m_PlayingBufferBlockCount )
1543         {
1544             startBlockNum -= m_PlayingBufferBlockCount;
1545         }
1546 
1547       #ifdef NW_PLATFORM_CTRWIN
1548         UpdateLoopAddress(
1549             startBlockNum * m_StreamInfo.oneBlockSamples,
1550             endBufferBlockIndex * m_StreamInfo.oneBlockSamples + m_StreamInfo.lastBlockSamples
1551         );
1552       #endif
1553 
1554         if ( IsDspAdpcm() )
1555         {
1556             for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1557             {
1558                 StreamTrack& track = m_Tracks[ trackIndex ];
1559                 if ( ! track.m_ActiveFlag ) continue;
1560                 Voice* voice = track.m_pVoice;
1561                 if ( voice == NULL ) continue;
1562 
1563                 if ( voice->GetFormat() == SAMPLE_FORMAT_DSP_ADPCM )
1564                 {
1565                   #ifdef NW_PLATFORM_CTRWIN
1566                     for( int channelIndex = 0;
1567                          channelIndex < track.m_TrackInfo.channelCount;
1568                          channelIndex++ )
1569                     {
1570                         StreamChannel* channel = GetTrackChannel( track, channelIndex );
1571                         voice->SetDspAdpcmLoop(
1572                             channelIndex,
1573                             &channel->m_AdpcmLoopParam
1574                         );
1575                     }
1576                   #endif
1577                 }
1578             }
1579 
1580             if ( endBufferBlockIndex == m_PlayingBufferBlockCount - 1 )
1581             {
1582                 m_SkipUpdateAdpcmLoop = true;
1583             }
1584         }
1585     }
1586     else
1587     {
1588         // ループエンドを変更してゼロバッファへ飛ばし、ワンショットモードにする
1589         SetLoopEndToZeroBuffer( endBufferBlockIndex );
1590     }
1591 }
1592 
1593 /*---------------------------------------------------------------------------*
1594   Name:         SetLoopEndToZeroBuffer
1595 
1596   Description:  データ終端のため、ボイスのアドレスをゼロバッファに飛ばす
1597 
1598   Arguments:    endBufferBlockIndex - 終端バッファのブロックインデックス
1599 
1600   Returns:      None.
1601  *---------------------------------------------------------------------------*/
SetLoopEndToZeroBuffer(int endBufferBlockIndex)1602 void StreamSoundPlayer::SetLoopEndToZeroBuffer( int endBufferBlockIndex )
1603 {
1604     {
1605         // ループエンドを変更してゼロバッファへ飛ばし、ワンショットモードにする
1606         for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1607         {
1608             StreamTrack& track = m_Tracks[ trackIndex ];
1609             if ( ! track.m_ActiveFlag ) continue;
1610             Voice* voice = track.m_pVoice;
1611             if ( voice == NULL ) continue;
1612 
1613             for( int channelIndex = 0;
1614                  channelIndex < track.m_TrackInfo.channelCount;
1615                  channelIndex++ )
1616             {
1617                 StreamChannel* channel = GetTrackChannel( track, channelIndex );
1618 
1619                 voice->StopAtPoint(
1620                     channelIndex,
1621                     channel->m_pBufferAddress,
1622                     endBufferBlockIndex * m_StreamInfo.oneBlockSamples
1623                     + m_StreamInfo.lastBlockSamples
1624                 );
1625             }
1626         }
1627     }
1628 
1629     m_PlayFinishFlag = true;
1630 }
1631 #endif
1632 
1633 
1634 /*---------------------------------------------------------------------------*
1635   Name:         UpdateLoadingBlockIndex
1636 
1637   Description:  ロードブロックインデックスの更新
1638 
1639   Arguments:    None.
1640 
1641   Returns:      None.
1642  *---------------------------------------------------------------------------*/
UpdateLoadingBlockIndex()1643 void StreamSoundPlayer::UpdateLoadingBlockIndex()
1644 {
1645     if ( m_LoadFinishFlag )
1646     {
1647         return;
1648     }
1649 
1650     ++m_LoadWaitCount;
1651 
1652     // コールバックパラメータの設定
1653     size_t blockSize = 0;
1654     u32 blockSamples = 0;
1655     bool lastBlockFlag = false;
1656     if ( m_LoadingDataBlockIndex == m_LastBlockIndex )
1657     {
1658         // 最終ブロック
1659         blockSize = m_StreamInfo.lastBlockPaddedBytes;
1660         blockSamples = m_StreamInfo.lastBlockSamples;
1661         if ( ! m_StreamInfo.isLoop ) {
1662             lastBlockFlag = true;
1663         }
1664     }
1665     else
1666     {
1667         // 通常ブロック
1668         blockSize = m_StreamInfo.oneBlockBytes;
1669         blockSamples = m_StreamInfo.oneBlockSamples;
1670     }
1671 
1672     s32 loadOffset = CalcLoadOffset();
1673 
1674     NW_ALIGN32_ASSERT( blockSize );
1675     NW_ALIGN4_ASSERT( loadOffset );
1676 
1677     // ロードタスクの発行
1678     StreamDataLoadTask* task = m_StreamDataLoadTaskPool.Alloc();
1679     NW_NULL_ASSERT( task );
1680 
1681     task->m_PlayerHandle          = this;
1682     task->m_pFileStream           = m_pFileStream;
1683     task->m_ChannelCount          = m_StreamInfo.channelCount;
1684     task->m_Offset                = loadOffset;
1685     task->m_BlockBytes            = blockSize;      // 1ブロックあたりのバイト数
1686     task->m_BlockSamples          = blockSamples;   // 1ブロックあたりのフレーム数
1687     task->m_BufferBlockIndex      = m_LoadingBufferBlockIndex;
1688     task->m_DataBlockSize         = m_DataBlockSize;
1689     task->m_LoadingDataBlockIndex = m_LoadingDataBlockIndex;
1690     task->m_LastBlockFlag         = lastBlockFlag;
1691 #ifdef NW_PLATFORM_CTRWIN
1692 #else
1693     task->m_IsDataLoopBlock = ( m_LoadingDataBlockIndex == m_LoopStartBlockIndex ) && m_StreamInfo.isLoop;
1694 #endif
1695     task->SetId(reinterpret_cast<u32>(this));
1696 
1697     for(int ch=0;ch<m_StreamInfo.channelCount;ch++){
1698         task->m_BufferAddress[ch] = m_Channels[ ch ].m_pBufferAddress;
1699     }
1700 
1701     m_StreamDataLoadTaskList.PushBack( task );
1702     internal::TaskManager::GetInstance().AppendTask(
1703         task,
1704         m_StartedFlag ? internal::TaskManager::PRIORITY_HIGH :
1705         internal::TaskManager::PRIORITY_MIDDLE
1706     );
1707 //    NN_LOG("loadtask append buf(%d)\n", m_LoadingBufferBlockIndex);
1708 
1709     // ロードデータブロックインデックスの更新
1710     m_LoadingDataBlockIndex++;
1711     if ( m_LoadingDataBlockIndex > m_LastBlockIndex )
1712     {
1713         if ( m_StreamInfo.isLoop )
1714         {
1715             m_LoadingDataBlockIndex = m_LoopStartBlockIndex;
1716         }
1717         else
1718         {
1719             // データ終端
1720             m_LoadFinishFlag = true;
1721             return;
1722         }
1723     }
1724 
1725     // ロードバッファブロックインデックスの更新
1726     m_LoadingBufferBlockIndex++;
1727     if ( m_LoadingBufferBlockIndex >= m_LoadingBufferBlockCount )
1728     {
1729         // ロードバッファループ
1730         m_LoadingBufferBlockIndex = 0;
1731 
1732         m_LoadingBufferBlockCount = CalcLoadingBufferBlockCount();
1733     }
1734 }
1735 
1736 /*---------------------------------------------------------------------------*
1737   Name:         UpdatePauseStatus
1738 
1739   Description:  ボイスのポーズステータスを更新
1740 
1741   Arguments:    None.
1742 
1743   Returns:      None.
1744  *---------------------------------------------------------------------------*/
UpdatePauseStatus()1745 void StreamSoundPlayer::UpdatePauseStatus()
1746 {
1747     bool pauseStatus = false;
1748     if ( m_PauseFlag ) pauseStatus = true;
1749     if ( m_LoadWaitFlag ) pauseStatus = true;
1750 
1751     if ( pauseStatus != m_PauseStatus )
1752     {
1753 #ifdef NW_PLATFORM_CTRWIN
1754         for ( int trackIndex = 0; trackIndex < m_TrackCount; trackIndex++ )
1755         {
1756             if ( ! m_Tracks[ trackIndex ].m_ActiveFlag ) continue;
1757             Voice* voice = m_Tracks[ trackIndex ].m_pVoice;
1758             if ( voice != NULL )
1759             {
1760                 voice->Pause( pauseStatus );
1761             }
1762         }
1763 #else
1764         for ( int ch = 0; ch < m_ChannelCount; ch++ )
1765         {
1766             Voice* voice = m_Channels[ ch ].m_pVoice;
1767             if ( voice != NULL )
1768             {
1769                 voice->Pause( pauseStatus );
1770             }
1771         }
1772 #endif
1773         m_PauseStatus = pauseStatus;
1774     }
1775 }
1776 
1777 /*---------------------------------------------------------------------------*
1778   Name:         CalcLoadingBufferBlockCount
1779 
1780   Description:  ロードバッファブロック数の計算
1781                 データ終端が、バッファの先頭に来ないようにするため、
1782                 必要に応じて、ブロック数を1増やす
1783 
1784   Arguments:    None.
1785 
1786   Returns:      ロードバッファブロック数
1787  *---------------------------------------------------------------------------*/
CalcLoadingBufferBlockCount() const1788 int StreamSoundPlayer::CalcLoadingBufferBlockCount() const
1789 {
1790 #ifdef NW_PLATFORM_CTRWIN
1791     const int restBlockCount =  m_LastBlockIndex - m_LoadingDataBlockIndex + 1;
1792     const int loopBlockCount = m_LastBlockIndex - m_LoopStartBlockIndex + 1;
1793 
1794     // restBlockCount + loopBlockCount * { 0...n } == m_BufferBlockCountBase + 1
1795     // を満たすとき、バッファブロック数を一時的増やして、
1796     // データループエンドがブロック先頭に来ないようにする
1797     if ( ( ( m_BufferBlockCountBase + 1 ) - restBlockCount ) % loopBlockCount == 0 )
1798     {
1799         return m_BufferBlockCountBase + 1;
1800     }
1801     else
1802     {
1803         return m_BufferBlockCountBase;
1804     }
1805 #else
1806     // TODO: [SDK] AppendNextBuffer が実装されたらここはなし
1807     return m_BufferBlockCount;
1808 #endif
1809 }
1810 
1811 /*---------------------------------------------------------------------------*
1812   Name:         CalcStartOffset
1813 
1814   Description:  開始オフセット位置の計算
1815 
1816   Arguments:    pStartBlockIndex - 開始ブロックインデックスを格納するアドレス
1817                 pStartBlockOffset - 開始ブロックオフセットを格納するアドレス
1818                 pLoopCount - ループカウントを格納するアドレス
1819 
1820   Returns:      計算に成功したかどうか
1821  *---------------------------------------------------------------------------*/
CalcStartOffset(s32 * pStartBlockIndex,u32 * pStartBlockOffset,s32 * pLoopCount)1822 bool StreamSoundPlayer::CalcStartOffset(
1823     s32* pStartBlockIndex,
1824     u32* pStartBlockOffset,
1825     s32* pLoopCount
1826 )
1827 {
1828     // 再生開始ブロックの計算
1829     // 設定されている m_StreamInfo と m_StartOffset の値を使って計算する
1830 
1831     if ( m_StreamInfo.oneBlockSamples <= 0 )
1832     {
1833         return false;
1834     }
1835 
1836     u32 startOffsetSamples = 0;
1837     if ( m_StartOffsetType == START_OFFSET_TYPE_SAMPLE )
1838     {
1839         startOffsetSamples = m_StartOffset;
1840     }
1841     else if ( m_StartOffsetType == START_OFFSET_TYPE_MILLISEC )
1842     {
1843         startOffsetSamples = static_cast<u32>(
1844             static_cast<s64>( m_StartOffset ) * m_StreamInfo.sampleRate / 1000
1845         );
1846     }
1847 
1848     *pLoopCount = 0;
1849     if ( startOffsetSamples >= m_StreamInfo.frameCount )
1850     {
1851         if ( m_StreamInfo.isLoop )
1852         {
1853             // ループして折り返す
1854             s32 loopStart = static_cast<s32>( m_StreamInfo.loopStart );
1855             s32 loopEnd = static_cast<s32>( m_StreamInfo.frameCount );
1856             s32 loopLen = loopEnd - loopStart;
1857             s32 startOffset2 = startOffsetSamples - loopEnd;
1858             *pLoopCount = 1 + startOffset2 / loopLen;
1859             startOffsetSamples = loopStart + startOffset2 % loopLen;
1860         }
1861         else
1862         {
1863             // ワンショットで開始位置が波形の終端以降なら再生できない
1864             return false;
1865         }
1866     }
1867 
1868 
1869     *pStartBlockIndex = startOffsetSamples / static_cast<s32>( m_StreamInfo.oneBlockSamples );
1870     *pStartBlockOffset = startOffsetSamples % m_StreamInfo.oneBlockSamples;
1871 
1872     return true;
1873 }
1874 
1875 /*---------------------------------------------------------------------------*
1876   Name:         VoiceCallbackFunc
1877 
1878   Description:  ボイスから呼びだされるコールバック関数
1879 
1880   Arguments:    voice - ボイス
1881                 statuc - コールバックステータス
1882                 arg - ユーザー引数
1883 
1884   Returns:      None.
1885  *---------------------------------------------------------------------------*/
VoiceCallbackFunc(Voice * voice,Voice::VoiceCallbackStatus status,void * arg)1886 void StreamSoundPlayer::VoiceCallbackFunc(
1887     Voice* voice,
1888     Voice::VoiceCallbackStatus status,
1889     void* arg
1890 )
1891 {
1892 #ifdef NW_PLATFORM_CTRWIN
1893     NW_NULL_ASSERT( arg );
1894     StreamTrack* track = reinterpret_cast<StreamTrack*>( arg );
1895 
1896     NW_ASSERT( track->m_pVoice == voice );
1897 
1898     switch ( status )
1899     {
1900     case Voice::CALLBACK_STATUS_FINISH_WAVE:
1901     case Voice::CALLBACK_STATUS_CANCEL:
1902         voice->Free();
1903         track->m_pVoice = NULL;
1904         break;
1905     case Voice::CALLBACK_STATUS_DROP_VOICE:
1906     case Voice::CALLBACK_STATUS_DROP_DSP:
1907         track->m_pVoice = NULL;
1908         break;
1909     default:
1910         NW_ASSERTMSG( false, "Unknown Voice callback status %d", status );
1911         return;
1912     }
1913 #else
1914     NW_NULL_ASSERT( arg );
1915     StreamChannel* channel = reinterpret_cast<StreamChannel*>( arg );
1916 
1917     NW_ASSERT( channel->m_pVoice == voice );
1918 
1919     switch ( status )
1920     {
1921     case Voice::CALLBACK_STATUS_FINISH_WAVE:
1922     case Voice::CALLBACK_STATUS_CANCEL:
1923         voice->Free();
1924         channel->m_pVoice = NULL;
1925         break;
1926     case Voice::CALLBACK_STATUS_DROP_VOICE:
1927     case Voice::CALLBACK_STATUS_DROP_DSP:
1928         channel->m_pVoice = NULL;
1929         break;
1930     default:
1931         NW_ASSERTMSG( false, "Unknown Voice callback status %d", status );
1932         return;
1933     }
1934 #endif
1935 }
1936 
1937 #ifdef NW_PLATFORM_CTRWIN
1938 /*---------------------------------------------------------------------------*
1939   Name:         SetAdpcmLoopContext
1940 
1941   Description:  ADPCMループ情報の設定
1942 
1943   Arguments:    channelNum - チャンネル数
1944                 predScale - プレディクタ/スケール値の配列
1945                             要素数は、channelNum
1946 
1947   Returns:      None.
1948  *---------------------------------------------------------------------------*/
SetAdpcmLoopContext(int channelNum,u16 predScale[])1949 void StreamSoundPlayer::SetAdpcmLoopContext(
1950     int channelNum,
1951     u16 predScale[]
1952 )
1953 {
1954     if ( ! IsDspAdpcm() ) return;
1955 
1956     for ( int channelIndex = 0;
1957          channelIndex < channelNum && channelIndex < STRM_CHANNEL_NUM;
1958          channelIndex++ )
1959     {
1960         m_Channels[ channelIndex ].m_AdpcmPredScale = predScale[ channelIndex ];
1961     }
1962 
1963     m_ValidAdpcmLoop = true;
1964 }
1965 #endif
1966 
1967 /*---------------------------------------------------------------------------*
1968   Name:         GetTrackChannel
1969 
1970   Description:  トラック内のチャンネル番号からチャンネルを取得する
1971 
1972   Arguments:    track - トラック
1973                 channelIndex - トラック内のチャンネル番号
1974 
1975   Returns:
1976  *---------------------------------------------------------------------------*/
1977 StreamChannel*
GetTrackChannel(const StreamTrack & track,int channelIndex)1978 StreamSoundPlayer::GetTrackChannel( const StreamTrack& track, int channelIndex )
1979 {
1980     if ( channelIndex >= STRM_CHANNEL_NUM_PER_TRACK ) return NULL;
1981 
1982     int index = track.m_TrackInfo.globalChannelIndex[ channelIndex ];
1983     if ( index >= STRM_CHANNEL_NUM ) return NULL;
1984 
1985     return &m_Channels[ index ];
1986 }
1987 
1988 
SetTrackVolume(u32 trackBitFlag,f32 volume)1989 void StreamSoundPlayer::SetTrackVolume( u32 trackBitFlag, f32 volume )
1990 {
1991     for( int trackNo = 0;
1992          trackNo < m_TrackCount && trackBitFlag != 0;
1993          trackNo++, trackBitFlag >>= 1
1994     )
1995     {
1996         if ( ( trackBitFlag & 0x01 ) == 0 ) continue;
1997         m_Tracks[ trackNo ].m_Volume = volume;
1998     }
1999 }
2000 
SetTrackPan(u32 trackBitFlag,f32 pan)2001 void StreamSoundPlayer::SetTrackPan( u32 trackBitFlag, f32 pan )
2002 {
2003     for( int trackNo = 0;
2004          trackNo < m_TrackCount && trackBitFlag != 0;
2005          trackNo++, trackBitFlag >>= 1
2006     )
2007     {
2008         if ( ( trackBitFlag & 0x01 ) == 0 ) continue;
2009         m_Tracks[ trackNo ].m_Pan = pan;
2010     }
2011 }
2012 
SetTrackSurroundPan(u32 trackBitFlag,f32 span)2013 void StreamSoundPlayer::SetTrackSurroundPan( u32 trackBitFlag, f32 span )
2014 {
2015     for( int trackNo = 0;
2016          trackNo < m_TrackCount && trackBitFlag != 0;
2017          trackNo++, trackBitFlag >>= 1
2018     )
2019     {
2020         if ( ( trackBitFlag & 0x01 ) == 0 ) continue;
2021         m_Tracks[ trackNo ].m_SurroundPan = span;
2022     }
2023 }
2024 
GetPlayerTrack(int trackNo)2025 StreamTrack* StreamSoundPlayer::GetPlayerTrack( int trackNo )
2026 {
2027     if ( trackNo > STRM_TRACK_NUM - 1 ) return NULL;
2028 
2029     return &m_Tracks[ trackNo ];
2030 }
2031 
GetPlayerTrack(int trackNo) const2032 const StreamTrack* StreamSoundPlayer::GetPlayerTrack( int trackNo ) const
2033 {
2034     if ( trackNo > STRM_TRACK_NUM - 1 ) return NULL;
2035 
2036     return &m_Tracks[ trackNo ];
2037 }
2038 
CalcLoadOffset() const2039 s32 StreamSoundPlayer::CalcLoadOffset() const
2040 {
2041     s32 loadOffset = static_cast<s32>(
2042         m_DataOffsetFromFileHead +
2043         m_LoadingDataBlockIndex *
2044         ( m_StreamInfo.oneBlockBytes * m_StreamInfo.channelCount )
2045     );
2046     return loadOffset;
2047 }
2048 
2049 /* ========================================================================
2050         StreamSoundPlayer::StreamHeaderLoadTask class
2051    ======================================================================== */
2052 
StreamHeaderLoadTask()2053 StreamSoundPlayer::StreamHeaderLoadTask::StreamHeaderLoadTask()
2054 : m_PlayerHandle( NULL ),
2055   m_pFileStream( NULL ),
2056   m_StartOffset( 0 )
2057 {
2058 }
2059 
Execute()2060 void StreamSoundPlayer::StreamHeaderLoadTask::Execute()
2061 {
2062     bool result = LoadHeader();
2063     if ( ! result ) {
2064         m_PlayerHandle->SetTaskErrorFlag();
2065         return;
2066     }
2067 }
2068 
LoadHeader()2069 bool StreamSoundPlayer::StreamHeaderLoadTask::LoadHeader()
2070 {
2071     // ファイルヘッダのロード
2072     internal::StreamSoundFileLoader loader( *m_pFileStream );
2073     if ( ! loader.LoadFileHeader( s_LoadBuffer, StreamSoundPlayer::LOAD_BUFFER_SIZE ) )
2074     {
2075         return false;
2076     }
2077 
2078     // ストリーム情報の読み取り
2079     DriverCommandManager& cmdmgr = DriverCommandManager::GetInstanceForTaskThread();
2080     DriverCommandStreamSoundLoadHeader* command =
2081         cmdmgr.AllocCommand<DriverCommandStreamSoundLoadHeader>();
2082     command->id = DRIVER_COMMAND_STRM_LOADHEADER;
2083     command->player = m_PlayerHandle;
2084 
2085     if ( ! loader.ReadStreamInfo( &command->streamInfo ) )
2086     {
2087         return false;
2088     }
2089 
2090     command->dataBlockOffset = loader.GetDataBlockOffset();
2091     command->trackCount = loader.GetTrackCount();
2092     command->channelCount = loader.GetChannelCount();
2093 
2094     // トラックの情報を読み取る
2095     NW_ASSERT( command->trackCount <= DriverCommandStreamSoundLoadHeader::TRACK_MAX );
2096     for ( unsigned int i = 0; i < command->trackCount; i++ )
2097     {
2098         if ( ! loader.ReadStreamTrackInfo( &command->trackInfoArray[i], i ) )
2099         {
2100             return false;
2101         }
2102     }
2103 
2104     if ( WaveFileReader::GetSampleFormat( command->streamInfo.encodeMethod ) == SAMPLE_FORMAT_DSP_ADPCM )
2105     {
2106         // ADPCMの情報を読み取る
2107         NW_ASSERT( command->channelCount <= DriverCommandStreamSoundLoadHeader::CHANNEL_MAX );
2108         for ( unsigned int ch = 0; ch < command->channelCount; ch++ )
2109         {
2110             if ( ! loader.ReadDspAdpcmChannelInfo(
2111                      &command->dspAdpcmParam[ch],
2112                      &command->dspAdpcmLoopParam[ch],
2113                      ch ) )
2114             {
2115                 return false;
2116             }
2117         }
2118 
2119         // ADPCMで途中再生するための情報を取得する
2120         if ( m_StartOffset != 0 )
2121         {
2122             int startOffsetSamples = 0;
2123             if ( m_StartOffsetType == START_OFFSET_TYPE_SAMPLE )
2124             {
2125                 startOffsetSamples = m_StartOffset;
2126             }
2127             else if ( m_StartOffsetType == START_OFFSET_TYPE_MILLISEC )
2128             {
2129                 startOffsetSamples = m_StartOffset * command->streamInfo.sampleRate / 1000;
2130             }
2131 
2132             s32 blockIndex = startOffsetSamples /
2133                              static_cast<s32>( command->streamInfo.oneBlockSamples );
2134             u16 yn1[ STRM_CHANNEL_NUM ];
2135             u16 yn2[ STRM_CHANNEL_NUM ];
2136             if ( ! loader.ReadAdpcBlockData(
2137                      yn1,
2138                      yn2,
2139                      blockIndex,
2140                      command->channelCount
2141                  ) )
2142             {
2143                 return false;
2144             }
2145             for ( unsigned int i=0; i<command->channelCount; i++ )
2146             {
2147                 command->dspAdpcmParam[i].yn1 = yn1[i];
2148                 command->dspAdpcmParam[i].yn2 = yn2[i];
2149             }
2150         }
2151     }
2152 
2153     cmdmgr.PushCommand(command);
2154     cmdmgr.FlushCommand(true);
2155 
2156     return true;
2157 }
2158 
2159 /* ========================================================================
2160         StreamSoundPlayer::StreamDataLoadTask class
2161    ======================================================================== */
2162 
StreamDataLoadTask()2163 StreamSoundPlayer::StreamDataLoadTask::StreamDataLoadTask()
2164 : m_PlayerHandle( NULL ),
2165   m_pFileStream( NULL ),
2166   // m_Size( 0 ),
2167   m_Offset( 0 ),
2168   m_BlockBytes( 0 ),
2169   m_BufferBlockIndex( -1 ),
2170   m_BlockSamples( 0 ),
2171   m_IsDataLoopBlock( false )
2172 {
2173 }
2174 
Execute()2175 void StreamSoundPlayer::StreamDataLoadTask::Execute()
2176 {
2177     // NN_LOG("exec(0x%p): bufIdx(%d)\n", this, m_BufferBlockIndex );
2178     bool result = LoadStreamData();
2179 
2180     if ( ! result ) {
2181         m_PlayerHandle->SetTaskErrorFlag();
2182     }
2183 
2184 }
2185 
LoadStreamData()2186 bool StreamSoundPlayer::StreamDataLoadTask::LoadStreamData()
2187 {
2188     NW_ALIGN4_ASSERT( m_Offset );
2189     NW_ALIGN32_ASSERT( m_BlockBytes );
2190 
2191 #ifdef NW_PLATFORM_CTR
2192     nn::snd::InvalidateDataCache( reinterpret_cast<uptr>( s_LoadBuffer ), sizeof( s_LoadBuffer ) );
2193 #endif
2194 
2195     int loadOffset = m_Offset;
2196 
2197     unsigned int currentChannel = 0;     // 0 ~ m_ChannelCount でインクリメント
2198     while ( currentChannel < m_ChannelCount )
2199     {
2200         NW_ALIGN4_ASSERT( loadOffset );
2201 
2202         int loadChannelCount = LOAD_BUFFER_CHANNEL_NUM;
2203         if ( currentChannel + loadChannelCount > m_ChannelCount )
2204         {
2205             loadChannelCount = m_ChannelCount - currentChannel;
2206         }
2207         size_t loadSize = m_BlockBytes * loadChannelCount;
2208         NW_ASSERT( loadSize <= LOAD_BUFFER_SIZE );
2209 
2210         // データのロード
2211         m_pFileStream->Seek( loadOffset, io::FILE_STREAM_SEEK_BEGIN );
2212         s32 resultSize = m_pFileStream->Read( s_LoadBuffer, loadSize );
2213         loadOffset += loadSize;
2214 
2215     #ifdef DEBUG_STRM
2216         std::fwrite( s_LoadBuffer, loadSize, 1, s_pFile );
2217     #endif
2218 
2219         if ( resultSize != loadSize )
2220         {
2221             return false;
2222         }
2223 
2224         for ( int i = 0; i < loadChannelCount; i++ )
2225         {
2226             // ロード用バッファ (s_LoadBuffer) から、ストリームバッファにコピー
2227             u32 len = static_cast<u32>( m_BlockBytes );
2228             const void* source = ut::AddOffsetToPtr( s_LoadBuffer, m_BlockBytes * i );
2229             void* dest = ut::AddOffsetToPtr(
2230                 m_BufferAddress[ currentChannel ],
2231                 m_DataBlockSize * m_BufferBlockIndex
2232             );
2233             std::memcpy( dest, source, len );
2234 
2235 #ifndef NW_PLATFORM_CTRWIN
2236             nn::snd::FlushDataCache( reinterpret_cast<uptr>(dest), len );
2237 #endif
2238 
2239             // NN_LOG("bufBlockIdx(%d) currentCh(%d) loadChCnt(%d) mCh(%d) loadSize(%d)\n",
2240             //         bufferBlockIndex, currentChannel,
2241             //         loadChannelCount, m_ChannelCount, loadSize );
2242 
2243             ++currentChannel;
2244         }
2245     }
2246 
2247     DriverCommandManager& cmdmgr = DriverCommandManager::GetInstanceForTaskThread();
2248     DriverCommandStreamSoundLoadData* command =
2249         cmdmgr.AllocCommand<DriverCommandStreamSoundLoadData>();
2250     command->id = DRIVER_COMMAND_STRM_LOADDATA;
2251     command->player = m_PlayerHandle;
2252     command->bufferBlockIndex = m_BufferBlockIndex;
2253     command->blockSamples = m_BlockSamples;
2254     command->dataBlockIndex = m_LoadingDataBlockIndex;
2255     command->isDataLoopBlock = m_IsDataLoopBlock;
2256     command->lastBlockFlag = m_LastBlockFlag;
2257     cmdmgr.PushCommand(command);
2258     cmdmgr.FlushCommand(true);
2259 
2260 
2261     return true;
2262 }
2263 
2264 } // namespace nw::snd::internal::driver
2265 } // namespace nw::snd::internal
2266 } // namespace nw::snd
2267 } // namespace nw
2268 
2269