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