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