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