1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: main.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: $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/snd.h>
21 #include <nn/snd.h> // snd_Bcwav.h
22 #include "demolib.h"
23 #include "simple.csid"
24
25 class WithSdkApp : public nw::snd::demolib::AppBase
26 {
27 protected:
28 virtual void OnInitialize();
29 virtual void OnFinalize();
30 virtual void OnDrawUpLCD( nw::font::TextWriter& );
31 virtual void OnDrawDownLCD( nw::font::TextWriter& );
32 virtual void OnUpdatePad( nw::demo::Pad& );
33 virtual void OnUpdate();
34
35 private:
36 void InitializeSoundSystem();
37 void InitializeSdkVoice();
38
39 nw::snd::RomSoundArchive m_Archive;
40 nw::snd::SoundArchivePlayer m_ArchivePlayer;
41 nw::snd::SoundDataManager m_DataManager;
42 nw::snd::SoundHeap m_Heap;
43 nw::snd::SoundHandle m_Handle;
44
45 void* m_pMemoryForSoundSystem;
46 void* m_pMemoryForInfoBlock;
47 void* m_pMemoryForSoundDataManager;
48 void* m_pMemoryForSoundArchivePlayer;
49 void* m_pMemoryForSoundHeap;
50 void* m_pMemoryForStreamBuffer;
51 };
52
53 namespace
54 {
55
56 const s32 SOUND_THREAD_PRIORITY = 4;
57 const s32 LOAD_THREAD_PRIORITY = 3;
58 const s32 SOUND_HEAP_SIZE = 1 * 1024 * 1024;
59 const char SOUND_ARC_PATH[] = NW_SND_DEMO_PATH_PREFIX "simple.bcsar";
60 const char DEMO_TITLE[] = "WithSdk";
61
62 const char* SDK_WAV_NAME = NW_SND_DEMO_PATH_PREFIX "sin440.dspadpcm.bcwav";
63
PanToMixParam(nn::snd::MixParam & mix,int pan)64 void PanToMixParam( nn::snd::MixParam& mix, int pan )
65 {
66 std::memset( &mix, 0, sizeof(mix) ); // ひとまずすべてゼロに初期化
67
68 pan = nw::ut::Clamp( pan, 0, 100 );
69 mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT] = 1.0f - pan / 100.f;
70 mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = pan / 100.f;
71 }
72
73
74 // for nn::snd
75 // (ループ付きモノラル DSP ADPCM 波形を鳴らす)
76 nn::snd::Voice* s_pVoice;
77 nn::snd::WaveBuffer s_WaveBuffer[2]; // ループ波形再生には 2 つの WaveBuffer が必要
78 const nn::snd::Bcwav::DspAdpcmInfo* m_sDspAdpcmInfo;
79 int s_SdkVoicePan; // 0 = 左、100 = 右とする
80 bool s_IsSdkVoicePause;
81 bool s_IsSdkVoicePausePre;
82 bool s_SdkVoicePauseTrigger;
83 void* s_pMemoryForSdkVoice;
84
MySoundFrameProcess(uptr)85 void MySoundFrameProcess( uptr )
86 {
87 // SetSoundFrameUserCallback で設定したコールバック関数の中なので、
88 // SoundThreadScopedLock でサウンドスレッドをロックする必要はありません。
89 if ( s_pVoice )
90 {
91 nn::snd::MixParam mix;
92 PanToMixParam( mix, s_SdkVoicePan );
93 s_pVoice->SetMixParam( mix );
94
95 if ( s_SdkVoicePauseTrigger )
96 {
97 nn::snd::Voice::State state =
98 s_IsSdkVoicePause ? nn::snd::Voice::STATE_PAUSE : nn::snd::Voice::STATE_PLAY;
99 s_pVoice->SetState( state );
100 s_SdkVoicePauseTrigger = false;
101 }
102 }
103 }
104
105 } // anonymous namespace
106
OnInitialize()107 void WithSdkApp::OnInitialize()
108 {
109 InitializeSoundSystem();
110
111 // サウンドデータのロード
112 if ( ! m_DataManager.LoadData( SEQ_MARIOKART, &m_Heap ) )
113 {
114 NW_ASSERTMSG( false, "LoadData(SEQ_MARIOKART) failed." );
115 }
116 if ( ! m_DataManager.LoadData( SE_YOSHI, &m_Heap ) )
117 {
118 NW_ASSERTMSG( false, "LoadData(SE_YOSHI) failed." );
119 }
120
121 InitializeSdkVoice();
122 }
123
InitializeSoundSystem()124 void WithSdkApp::InitializeSoundSystem()
125 {
126 // サウンドシステムの初期化
127 {
128 nw::snd::SoundSystem::SoundSystemParam param;
129 size_t workMemSize = nw::snd::SoundSystem::GetRequiredMemSize( param );
130 m_pMemoryForSoundSystem = MemAlloc( workMemSize );
131
132 // nn::snd::Voice で 1 ボイスだけ再生させるため、
133 // nw::snd で利用するボイス数を 1 つ減らす
134 nw::snd::SoundSystem::SetMaxVoiceCount( 23 );
135 nw::snd::SoundSystem::Initialize(
136 param,
137 reinterpret_cast<uptr>( m_pMemoryForSoundSystem ),
138 workMemSize );
139 }
140
141 // サウンドアーカイブの初期化
142 if ( ! m_Archive.Open( SOUND_ARC_PATH ) )
143 {
144 NW_ASSERTMSG( 0, "cannot open bcsar(%s)\n", SOUND_ARC_PATH );
145 }
146
147 // INFO ブロックのロード
148 {
149 size_t infoBlockSize = m_Archive.GetHeaderSize();
150 m_pMemoryForInfoBlock = MemAlloc( infoBlockSize );
151 if ( ! m_Archive.LoadHeader( m_pMemoryForInfoBlock, infoBlockSize ) )
152 {
153 NW_ASSERTMSG( 0, "cannot load infoBlock(%s)", SOUND_ARC_PATH );
154 }
155 }
156
157 // サウンドデータマネージャーの初期化
158 {
159 size_t setupSize = m_DataManager.GetRequiredMemSize( &m_Archive );
160 m_pMemoryForSoundDataManager = MemAlloc( setupSize );
161 m_DataManager.Initialize( &m_Archive, m_pMemoryForSoundDataManager, setupSize );
162 }
163
164 // サウンドアーカイブプレイヤーの初期化
165 {
166 size_t setupSize = m_ArchivePlayer.GetRequiredMemSize( &m_Archive );
167 m_pMemoryForSoundArchivePlayer = MemAlloc( setupSize, 32 );
168 size_t setupStrmBufferSize =
169 m_ArchivePlayer.GetRequiredStreamBufferSize( &m_Archive );
170 m_pMemoryForStreamBuffer = MemAlloc( setupStrmBufferSize, 32 );
171 bool result = m_ArchivePlayer.Initialize(
172 &m_Archive,
173 &m_DataManager,
174 m_pMemoryForSoundArchivePlayer, setupSize,
175 m_pMemoryForStreamBuffer, setupStrmBufferSize );
176 NW_ASSERT( result );
177 }
178
179 // サウンドヒープの構築
180 {
181 m_pMemoryForSoundHeap = MemAlloc( SOUND_HEAP_SIZE );
182 bool result = m_Heap.Create( m_pMemoryForSoundHeap, SOUND_HEAP_SIZE );
183 NW_ASSERT( result );
184 }
185 }
186
InitializeSdkVoice()187 void WithSdkApp::InitializeSdkVoice()
188 {
189 // パラメータ初期化
190 {
191 s_pVoice = NULL;
192 for ( int i = 0; i < 2; i++ )
193 {
194 nn::snd::InitializeWaveBuffer( &s_WaveBuffer[i] );
195 }
196 m_sDspAdpcmInfo = NULL;
197 s_SdkVoicePan = 50;
198 s_IsSdkVoicePause = s_IsSdkVoicePausePre = s_SdkVoicePauseTrigger = false;
199 s_pMemoryForSdkVoice = NULL;
200 }
201
202 // ファイル読み込み
203 {
204 nn::fs::FileReader fileReader;
205 nn::Result result = fileReader.TryInitialize( SDK_WAV_NAME );
206 NN_UTIL_PANIC_IF_FAILED( result );
207
208 size_t fileSize = fileReader.GetSize();
209 s_pMemoryForSdkVoice = MemAlloc( fileSize, 32 );
210 s32 readSize = fileReader.Read( s_pMemoryForSdkVoice, fileSize );
211 fileReader.Finalize();
212
213 nn::snd::FlushDataCache( reinterpret_cast<uptr>(s_pMemoryForSdkVoice), readSize );
214 }
215
216 // bcwav ファイル読み込み、ボイススタート
217 {
218 const nn::snd::Bcwav::WaveInfo& info = nn::snd::Bcwav::GetWaveInfo( s_pMemoryForSdkVoice );
219 const void* wave = nn::snd::Bcwav::GetWave( s_pMemoryForSdkVoice, 0 );
220
221 if ( info.encoding == 2 ) // DSP ADPCM
222 {
223 m_sDspAdpcmInfo = const_cast<nn::snd::Bcwav::DspAdpcmInfo*>(
224 nn::snd::Bcwav::GetDspAdpcmInfo( s_pMemoryForSdkVoice, 0 ) );
225 }
226
227 // アプリケーションコアでサウンドスレッドを動作させている状況下で、
228 // SetSoundFrameUserCallback で設定したコールバック関数の外から s_pVoice を操作する場合は、
229 // SoundThreadScopedLock でサウンドスレッドをロックする必要があります。
230 {
231 nw::snd::SoundSystem::SoundThreadScopedLock lock;
232
233 // システムコア動作時は、優先度を nn::snd::VOICE_PRIORITY_NODROP にする必要がある
234 s_pVoice = nn::snd::AllocVoice( 128, NULL, NULL );
235 // s_pVoice = nn::snd::AllocVoice( nn::snd::VOICE_PRIORITY_NODROP, NULL, NULL );
236 NN_TASSERT_(s_pVoice);
237
238 if ( info.encoding == 2 )
239 {
240 s_pVoice->SetAdpcmParam( m_sDspAdpcmInfo->param );
241 }
242 s_pVoice->SetChannelCount( 1 );
243 s_pVoice->SetSampleFormat( static_cast<nn::snd::SampleFormat>( info.encoding ) );
244 s_pVoice->SetSampleRate( info.sampleRate );
245 s_pVoice->SetVolume( 1.0f );
246 s_pVoice->SetPitch( 1.0f );
247
248 nn::snd::MixParam mix;
249 PanToMixParam( mix, s_SdkVoicePan );
250 s_pVoice->SetMixParam( mix );
251
252 s_WaveBuffer[0].bufferAddress = wave;
253 s_WaveBuffer[0].sampleLength = info.loopEndFrame;
254 s_WaveBuffer[0].loopFlag = false;
255 if ( info.encoding == 2 )
256 {
257 s_WaveBuffer[0].pAdpcmContext = &m_sDspAdpcmInfo->context;
258 }
259 s_pVoice->AppendWaveBuffer( &s_WaveBuffer[0] );
260
261 if ( info.isLoop )
262 {
263 int offset = nn::snd::Bcwav::FrameToByte( info.encoding, info.loopStartFrame );
264 s_WaveBuffer[1].bufferAddress = nn::snd::Bcwav::AddOffsetToPtr( wave, offset );
265 s_WaveBuffer[1].sampleLength = info.loopEndFrame - info.loopStartFrame;
266 s_WaveBuffer[1].loopFlag = true;
267 if ( info.encoding == 2 )
268 {
269 s_WaveBuffer[1].pAdpcmContext = &m_sDspAdpcmInfo->loopContext;
270 }
271 s_pVoice->AppendWaveBuffer( &s_WaveBuffer[1] );
272 }
273 s_pVoice->SetState( nn::snd::Voice::STATE_PLAY );
274 }
275 }
276
277 // nw::snd サウンドフレーム処理への処理追加
278 nw::snd::SoundSystem::SetSoundFrameUserCallback( MySoundFrameProcess, NULL );
279 }
280
OnFinalize()281 void WithSdkApp::OnFinalize()
282 {
283 nw::snd::SoundSystem::ClearSoundFrameUserCallback();
284
285 m_Heap.Destroy();
286 m_ArchivePlayer.Finalize();
287 m_DataManager.Finalize();
288 m_Archive.Close();
289
290 nw::snd::SoundSystem::Finalize();
291
292 MemFree( m_pMemoryForSoundSystem );
293 MemFree( m_pMemoryForInfoBlock );
294 MemFree( m_pMemoryForSoundDataManager );
295 MemFree( m_pMemoryForSoundArchivePlayer );
296 MemFree( m_pMemoryForSoundHeap );
297 MemFree( m_pMemoryForStreamBuffer );
298 }
299
OnDrawUpLCD(nw::font::TextWriter & writer)300 void WithSdkApp::OnDrawUpLCD( nw::font::TextWriter& writer )
301 {
302 writer.Printf(" DEMO nw::snd %s\n\n", DEMO_TITLE);
303
304 writer.Print(" -- usage --\n\n");
305 writer.Print(" [A] Play Sequence Sound\n");
306 writer.Print(" [Y] Play Stream Sound\n");
307 writer.Print(" [B] Stop Sound\n\n");
308
309 writer.Print(" [X] SDK Voice Pause / Start\n");
310 writer.Print(" [R] SDK Voice Pan to Right\n");
311 writer.Print(" [L] SDK Voice Pan to Left\n");
312
313 writer.Print(" [START] Restart SoundSystem\n\n");
314 }
315
OnDrawDownLCD(nw::font::TextWriter & writer)316 void WithSdkApp::OnDrawDownLCD( nw::font::TextWriter& writer )
317 {
318 writer.Print(" -- SDK Voice Status --\n\n");
319 writer.Printf(" isPause : %3d\n", s_IsSdkVoicePause );
320 writer.Printf(" pan : %3d (0:Left / 100:Right)\n", s_SdkVoicePan);
321 }
322
OnUpdatePad(nw::demo::Pad & pad)323 void WithSdkApp::OnUpdatePad( nw::demo::Pad& pad )
324 {
325 // nw::snd 操作
326 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_A ) )
327 {
328 m_Handle.Stop( 0 );
329 bool result = m_ArchivePlayer.StartSound( &m_Handle, SEQ_MARIOKART ).IsSuccess();
330 NN_LOG("[SEQ] SEQ_MARIOKART ... (%d)\n", result);
331 }
332
333 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_Y ) )
334 {
335 m_Handle.Stop( 0 );
336 bool result = m_ArchivePlayer.StartSound( &m_Handle, STRM_MARIOKART ).IsSuccess();
337 NN_LOG("[STRM] STRM_MARIOKART ... (%d)\n", result );
338 }
339
340 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_B ) )
341 {
342 m_Handle.Stop( 3 );
343 }
344
345
346 // SDK ボイス操作
347 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_X ) )
348 {
349 s_IsSdkVoicePause = ! s_IsSdkVoicePause;
350 }
351
352
353 if ( pad.IsButtonRepeatFast( nw::demo::Pad::BUTTON_R ) )
354 {
355 s_SdkVoicePan += 10;
356 if ( s_SdkVoicePan > 100 ) s_SdkVoicePan = 100;
357 }
358 if ( pad.IsButtonRepeatFast( nw::demo::Pad::BUTTON_L ) )
359 {
360 s_SdkVoicePan -= 10;
361 if ( s_SdkVoicePan < 0 ) s_SdkVoicePan = 0;
362 }
363
364 // nn::snd, nw::snd 再起動
365 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_START ) )
366 {
367 // 終了処理
368 {
369 {
370 nw::snd::SoundSystem::SoundThreadScopedLock();
371 s_pVoice->SetState( nn::snd::Voice::STATE_STOP );
372 }
373
374 OnFinalize();
375 NN_LOG("nw::snd Finalized\n");
376
377 nn::Result result = nn::snd::Finalize();
378 NN_LOG("nn::snd::Finalize ... %d\n", result.IsSuccess());
379 NN_UTIL_PANIC_IF_FAILED( result );
380 result = nn::dsp::UnloadComponent();
381 NN_LOG("nn::dsp::UnloadComponent ... %d\n", result.IsSuccess());
382 NN_UTIL_PANIC_IF_FAILED( result );
383 }
384
385 // 再初期化処理
386 {
387 nn::Result result = nn::dsp::LoadDefaultComponent();
388 NN_LOG("nn::dsp::LoadDefaultComponent ... %d\n", result.IsSuccess());
389 NN_UTIL_PANIC_IF_FAILED( result );
390 result = nn::snd::Initialize();
391 NN_LOG("nn::snd::Initialize ... %d\n", result.IsSuccess());
392 NN_UTIL_PANIC_IF_FAILED( result );
393
394 OnInitialize();
395 NN_LOG("nw::snd Initialized\n");
396 }
397 }
398 }
399
OnUpdate()400 void WithSdkApp::OnUpdate()
401 {
402 m_ArchivePlayer.Update();
403
404 {
405 if ( s_IsSdkVoicePausePre != s_IsSdkVoicePause )
406 {
407 s_SdkVoicePauseTrigger = true;
408 }
409 else
410 {
411 s_SdkVoicePauseTrigger = false;
412 }
413 s_IsSdkVoicePausePre = s_IsSdkVoicePause;
414 }
415 }
416
417
418
nnMain()419 void nnMain()
420 {
421 WithSdkApp app;
422
423 app.Initialize();
424 app.Run();
425 app.Finalize();
426 }
427