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