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 // システムコア動作時は、優先度を nn::snd::VOICE_PRIORITY_NODROP にする必要がある
232 s_pVoice = nn::snd::AllocVoice( 128, NULL, NULL );
233 // s_pVoice = nn::snd::AllocVoice( nn::snd::VOICE_PRIORITY_NODROP, NULL, NULL );
234 NN_TASSERT_(s_pVoice);
235
236 if ( info.encoding == 2 )
237 {
238 s_pVoice->SetAdpcmParam( m_sDspAdpcmInfo->param );
239 }
240 s_pVoice->SetChannelCount( 1 );
241 s_pVoice->SetSampleFormat( static_cast<nn::snd::SampleFormat>( info.encoding ) );
242 s_pVoice->SetSampleRate( info.sampleRate );
243 s_pVoice->SetVolume( 1.0f );
244 s_pVoice->SetPitch( 1.0f );
245
246 nn::snd::MixParam mix;
247 PanToMixParam( mix, s_SdkVoicePan );
248 s_pVoice->SetMixParam( mix );
249
250 s_WaveBuffer[0].bufferAddress = wave;
251 s_WaveBuffer[0].sampleLength = info.loopEndFrame;
252 s_WaveBuffer[0].loopFlag = false;
253 if ( info.encoding == 2 )
254 {
255 s_WaveBuffer[0].pAdpcmContext = &m_sDspAdpcmInfo->context;
256 }
257 s_pVoice->AppendWaveBuffer( &s_WaveBuffer[0] );
258
259 if ( info.isLoop )
260 {
261 int offset = nn::snd::Bcwav::FrameToByte( info.encoding, info.loopStartFrame );
262 s_WaveBuffer[1].bufferAddress = nn::snd::Bcwav::AddOffsetToPtr( wave, offset );
263 s_WaveBuffer[1].sampleLength = info.loopEndFrame - info.loopStartFrame;
264 s_WaveBuffer[1].loopFlag = true;
265 if ( info.encoding == 2 )
266 {
267 s_WaveBuffer[1].pAdpcmContext = &m_sDspAdpcmInfo->loopContext;
268 }
269 s_pVoice->AppendWaveBuffer( &s_WaveBuffer[1] );
270 }
271 s_pVoice->SetState( nn::snd::Voice::STATE_PLAY );
272 }
273 }
274
275 // nw::snd サウンドフレーム処理への処理追加
276 nw::snd::SoundSystem::SetSoundFrameUserCallback( MySoundFrameProcess, NULL );
277 }
278
OnFinalize()279 void WithSdkApp::OnFinalize()
280 {
281 nw::snd::SoundSystem::ClearSoundFrameUserCallback();
282
283 m_Heap.Destroy();
284 m_ArchivePlayer.Finalize();
285 m_DataManager.Finalize();
286 m_Archive.Close();
287
288 nw::snd::SoundSystem::Finalize();
289
290 MemFree( m_pMemoryForSoundSystem );
291 MemFree( m_pMemoryForInfoBlock );
292 MemFree( m_pMemoryForSoundDataManager );
293 MemFree( m_pMemoryForSoundArchivePlayer );
294 MemFree( m_pMemoryForSoundHeap );
295 MemFree( m_pMemoryForStreamBuffer );
296 }
297
OnDrawUpLCD(nw::font::TextWriter & writer)298 void WithSdkApp::OnDrawUpLCD( nw::font::TextWriter& writer )
299 {
300 writer.Printf(" DEMO nw::snd %s\n\n", DEMO_TITLE);
301
302 writer.Print(" -- usage --\n\n");
303 writer.Print(" [A] Play Sequence Sound\n");
304 writer.Print(" [Y] Play Stream Sound\n");
305 writer.Print(" [B] Stop Sound\n\n");
306
307 writer.Print(" [X] SDK Voice Pause / Start\n");
308 writer.Print(" [R] SDK Voice Pan to Right\n");
309 writer.Print(" [L] SDK Voice Pan to Left\n");
310
311 writer.Print(" [START] Restart SoundSystem\n\n");
312 }
313
OnDrawDownLCD(nw::font::TextWriter & writer)314 void WithSdkApp::OnDrawDownLCD( nw::font::TextWriter& writer )
315 {
316 writer.Print(" -- SDK Voice Status --\n\n");
317 writer.Printf(" isPause : %3d\n", s_IsSdkVoicePause );
318 writer.Printf(" pan : %3d (0:Left / 100:Right)\n", s_SdkVoicePan);
319 }
320
OnUpdatePad(nw::demo::Pad & pad)321 void WithSdkApp::OnUpdatePad( nw::demo::Pad& pad )
322 {
323 // nw::snd 操作
324 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_A ) )
325 {
326 m_Handle.Stop( 0 );
327 bool result = m_ArchivePlayer.StartSound( &m_Handle, SEQ_MARIOKART ).IsSuccess();
328 NN_LOG("[SEQ] SEQ_MARIOKART ... (%d)\n", result);
329 }
330
331 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_Y ) )
332 {
333 m_Handle.Stop( 0 );
334 bool result = m_ArchivePlayer.StartSound( &m_Handle, STRM_MARIOKART ).IsSuccess();
335 NN_LOG("[STRM] STRM_MARIOKART ... (%d)\n", result );
336 }
337
338 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_B ) )
339 {
340 m_Handle.Stop( 3 );
341 }
342
343
344 // SDK ボイス操作
345 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_X ) )
346 {
347 s_IsSdkVoicePause = ! s_IsSdkVoicePause;
348 }
349
350
351 if ( pad.IsButtonRepeatFast( nw::demo::Pad::BUTTON_R ) )
352 {
353 s_SdkVoicePan += 10;
354 if ( s_SdkVoicePan > 100 ) s_SdkVoicePan = 100;
355 }
356 if ( pad.IsButtonRepeatFast( nw::demo::Pad::BUTTON_L ) )
357 {
358 s_SdkVoicePan -= 10;
359 if ( s_SdkVoicePan < 0 ) s_SdkVoicePan = 0;
360 }
361
362 // nn::snd, nw::snd 再起動
363 if ( pad.IsButtonDown( nw::demo::Pad::BUTTON_START ) )
364 {
365 // 終了処理
366 {
367 {
368 nw::snd::SoundSystem::SoundThreadScopedLock();
369 s_pVoice->SetState( nn::snd::Voice::STATE_STOP );
370 }
371
372 OnFinalize();
373 NN_LOG("nw::snd Finalized\n");
374
375 nn::Result result = nn::snd::Finalize();
376 NN_LOG("nn::snd::Finalize ... %d\n", result.IsSuccess());
377 NN_UTIL_PANIC_IF_FAILED( result );
378 result = nn::dsp::UnloadComponent();
379 NN_LOG("nn::dsp::UnloadComponent ... %d\n", result.IsSuccess());
380 NN_UTIL_PANIC_IF_FAILED( result );
381 }
382
383 // 再初期化処理
384 {
385 nn::Result result = nn::dsp::LoadDefaultComponent();
386 NN_LOG("nn::dsp::LoadDefaultComponent ... %d\n", result.IsSuccess());
387 NN_UTIL_PANIC_IF_FAILED( result );
388 result = nn::snd::Initialize();
389 NN_LOG("nn::snd::Initialize ... %d\n", result.IsSuccess());
390 NN_UTIL_PANIC_IF_FAILED( result );
391
392 OnInitialize();
393 NN_LOG("nw::snd Initialized\n");
394 }
395 }
396 }
397
OnUpdate()398 void WithSdkApp::OnUpdate()
399 {
400 m_ArchivePlayer.Update();
401
402 {
403 if ( s_IsSdkVoicePausePre != s_IsSdkVoicePause )
404 {
405 s_SdkVoicePauseTrigger = true;
406 }
407 else
408 {
409 s_SdkVoicePauseTrigger = false;
410 }
411 s_IsSdkVoicePausePre = s_IsSdkVoicePause;
412 }
413 }
414
415
416
nnMain()417 void nnMain()
418 {
419 WithSdkApp app;
420
421 app.Initialize();
422 app.Run();
423 app.Finalize();
424 }
425