1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     snd.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  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   $Rev: 46365 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn.h>
17 #include <nn/os.h>
18 #include <nn/fnd.h>
19 #include <nn/math.h>
20 
21 #include <nn/dsp.h>
22 #include <nn/snd.h>
23 
24 #include "snd.h"
25 
26 // Heap for application
27 extern nn::fnd::ExpHeap s_AppHeap;
28 
29 namespace
30 {
31     nn::snd::Voice* pVoice;
32     s16* pMemory;
33     nn::snd::WaveBuffer waveBuffer;
34     const int nBufferSize = 2048;
35     bool isPlaying = false;
36     f32 pitch = 1.0f;
37     f32 volume = 0.0f;
38 
39     // Generate sine wave
MakeSineWave(s16 * p,s32 n)40     void MakeSineWave(s16* p, s32 n)
41     {
42         for (int i = 0; i < n; i++)
43         {
44             p[i] = (32767.0f * nn::math::SinFIdx(4.0f*i));
45         }
46     }
47 
48     // Sound thread related
49     const int SOUND_THREAD_PRIORITY = 2;
50     const int SOUND_THREAD_STACK_SIZE = 1024;
51     nn::os::Thread threadSound;
52     bool threadSoundFlag;
SoundThreadFunc(uptr arg)53     void SoundThreadFunc(uptr arg)
54     {
55         (void)arg;
56         threadSoundFlag = true;
57 
58         // Specify stereo output
59         nn::snd::SetSoundOutputMode(nn::snd::OUTPUT_MODE_STEREO);
60 
61         // Set master volume
62         nn::snd::SetMasterVolume(1.0f);
63 
64         // Get and confirm contiguous memory region
65         pMemory = reinterpret_cast<s16*>(s_AppHeap.Allocate(nBufferSize * sizeof(s16), 32));
66         NN_TASSERT_(pMemory);
67         MakeSineWave(pMemory, nBufferSize);
68         nn::snd::FlushDataCache(reinterpret_cast<uptr>(pMemory), nBufferSize * sizeof(s16));
69 
70         pVoice = nn::snd::AllocVoice(128, NULL, NULL);
71         NN_TASSERT_(pVoice);
72 
73         pVoice->SetChannelCount(1);
74         pVoice->SetSampleFormat(nn::snd::SAMPLE_FORMAT_PCM16);
75 
76         // Set volume
77         nn::snd::MixParam mix;
78         mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT ] = 0.707f; // Main volume (L)
79         mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = 0.707f; // Main volume (R)
80         pVoice->SetMixParam(mix);
81         pVoice->SetVolume(volume);
82 
83         // Set pitch
84         pVoice->SetSampleRate(NN_SND_HW_I2S_CLOCK_32KHZ);
85         pVoice->SetPitch(pitch);
86 
87         nn::snd::InitializeWaveBuffer(&waveBuffer);
88         waveBuffer.bufferAddress = pMemory;
89         waveBuffer.sampleLength  = nn::snd::GetSampleLength(nBufferSize * sizeof(s16), nn::snd::SAMPLE_FORMAT_PCM16, 1);
90         waveBuffer.loopFlag = true;
91         pVoice->AppendWaveBuffer(&waveBuffer);
92 
93         pVoice->SetState(nn::snd::Voice::STATE_PLAY);
94 
95         while (threadSoundFlag)
96         {
97             nn::snd::WaitForDspSync();  // Wait for receiving data from DSP.
98             nn::snd::SendParameterToDsp();  // Send parameters to the DSP.
99         }
100 
101         // End playback
102         pVoice->SetState(nn::snd::Voice::STATE_STOP);
103         FreeVoice(pVoice);
104     }
105 }
106 
InitializeSnd()107 void InitializeSnd()
108 {
109     nn::Result result;
110 
111     // Initialize dsp and snd libraries
112     result = nn::dsp::Initialize();
113     NN_UTIL_PANIC_IF_FAILED(result);
114     result = nn::dsp::LoadDefaultComponent();
115     NN_UTIL_PANIC_IF_FAILED(result);
116     result = nn::snd::Initialize();
117     NN_UTIL_PANIC_IF_FAILED(result);
118 
119     // Start the sound thread (wait for DSP interrupt event)
120     threadSound.StartUsingAutoStack(
121         SoundThreadFunc,
122         NULL,
123         SOUND_THREAD_STACK_SIZE,
124         SOUND_THREAD_PRIORITY
125     );
126 }
127 
FinalizeSnd(void)128 void FinalizeSnd(void)
129 {
130     // Destroy the sound thread
131     threadSoundFlag = false;
132     threadSound.Join();
133     threadSound.Finalize();
134 
135     // Finalize SND
136     nn::Result result = nn::snd::Finalize();
137     NN_UTIL_PANIC_IF_FAILED(result);
138 
139     // Finalize DSP
140     result = nn::dsp::UnloadComponent();
141     NN_UTIL_PANIC_IF_FAILED(result);
142     nn::dsp::Finalize();
143 
144     // Free heap.
145     s_AppHeap.Free(pMemory);
146 }
147 
PlaySound(void)148 void PlaySound(void)
149 {
150     if (!isPlaying)
151     {
152         pitch = 1.0f;
153         volume = 1.0f;
154         isPlaying = true;
155     }
156     else
157     {
158         pitch -= 0.02f;
159         if (pitch < 0.0f)
160         {
161             pitch = 0.0f;
162         }
163         volume -= 0.03f;
164         if (volume < 0.0f)
165         {
166             volume = 0.0f;
167         }
168     }
169     pVoice->SetPitch(pitch);
170     pVoice->SetVolume(volume);
171 }
172 
StopSound(void)173 void StopSound(void)
174 {
175     isPlaying = false;
176 
177     volume = 0.0f;
178     pVoice->SetVolume(volume);
179 }
180 
181 /*---------------------------------------------------------------------------*
182   End of file
183  *---------------------------------------------------------------------------*/
184