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