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