1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - SND - demos - capture
3 File: main.c
4
5 Copyright 2007-2008 Nintendo. 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 $Date:: 2008-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 //---------------------------------------------------------------------------
19 // USAGE:
20 // A: Start Bgm
21 // B: Stop Bgm
22 // X : Start Capture
23 // Y : Stop Capture
24 //---------------------------------------------------------------------------
25
26 #ifdef SDK_TWL
27 #include <twl.h>
28 #else
29 #include <nitro.h>
30 #endif
31
32 #include "fanfare.32.h"
33
34 #define CAPTURE_BUF_PAGESIZE 64*32
35 #define CAPTURE_BUF_SIZE CAPTURE_BUF_PAGESIZE*2
36 #define CAPTURE_SAMPLE_RATE 44100
37 #define CAPTURE_FIFO_SIZE 32
38 #define THREAD_STACK_SIZE 1024
39
40 #define CHANNEL_NUM 4
41 #define ALARM_NUM 0
42 #define CAPTURE_THREAD_PRIO 12
43 #define MAX_VOLUME 127
44 #define CENTER_PAN 64
45 #define FILTER_SIZE 12
46
47 typedef s16 smp_t;
48
49 typedef struct EffectCallbackInfo
50 {
51 smp_t sample[FILTER_SIZE - 1][2];
52 }
53 EffectCallbackInfo;
54
55 typedef struct CaptureInfo
56 {
57 u32 bufPage;
58 EffectCallbackInfo callbackInfo;
59 }
60 CaptureInfo;
61
62 static void SoundAlarmHandler(void *arg);
63 static void CaptureThread(void *arg);
64 static void CaptureFunc(CaptureInfo * cap);
65 static void VBlankIntr(void);
66 void EffectCallback(void *bufferL_p, void *bufferR_p, u32 len, SNDCaptureFormat format,
67 void *arg);
68
69 u16 Cont;
70 u16 Trg;
71
72 static u64 captureThreadStack[THREAD_STACK_SIZE / sizeof(u64)];
73 static OSThread captureThread;
74 static OSMessageQueue msgQ;
75 static OSMessage msgBuf[1];
76
77 static u8 captureBufL[CAPTURE_BUF_SIZE] ATTRIBUTE_ALIGN(32);
78 static u8 captureBufR[CAPTURE_BUF_SIZE] ATTRIBUTE_ALIGN(32);
79
80 /*---------------------------------------------------------------------------*
81 Name: NitroMain
82
83 Description: Main.
84
85 Arguments: None.
86
87 Returns: None.
88 *---------------------------------------------------------------------------*/
NitroMain()89 void NitroMain()
90 {
91 CaptureInfo cap;
92
93 // Initialization
94 OS_Init();
95 GX_Init();
96 SND_Init();
97
98 // V-Blank interrupt settings
99 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
100 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
101 (void)OS_EnableIrq();
102 (void)GX_VBlankIntr(TRUE);
103
104 // Print usage
105 OS_Printf("=================================\n");
106 OS_Printf("USAGE:\n");
107 OS_Printf(" A : start sound\n");
108 OS_Printf(" B : stop sound\n");
109 OS_Printf(" X : start capture(effect)\n");
110 OS_Printf(" Y : stop capture(effect)\n");
111 OS_Printf("=================================\n");
112
113 // Lock the channel
114 SND_LockChannel((1 << CHANNEL_NUM) | (1 << 1) | (1 << 3), 0);
115
116 /* Startup stream thread */
117 OS_CreateThread(&captureThread,
118 CaptureThread,
119 NULL,
120 captureThreadStack + THREAD_STACK_SIZE / sizeof(u64),
121 THREAD_STACK_SIZE, CAPTURE_THREAD_PRIO);
122 OS_WakeupThreadDirect(&captureThread);
123
124 while (1)
125 {
126 u16 ReadData;
127
128 OS_WaitVBlankIntr();
129
130 // Receive ARM7 command reply
131 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
132 {
133 }
134
135 ReadData = PAD_Read();
136 Trg = (u16)(ReadData & (ReadData ^ Cont));
137 Cont = ReadData;
138
139 // Play PCM
140 if (Trg & PAD_BUTTON_A)
141 {
142 SND_SetupChannelPcm(CHANNEL_NUM,
143 FANFARE_32_FORMAT,
144 fanfare_32,
145 FANFARE_32_LOOPFLAG ? SND_CHANNEL_LOOP_REPEAT :
146 SND_CHANNEL_LOOP_1SHOT, FANFARE_32_LOOPSTART, FANFARE_32_LOOPLEN,
147 MAX_VOLUME, SND_CHANNEL_DATASHIFT_NONE, FANFARE_32_TIMER,
148 CENTER_PAN);
149 SND_StartTimer(1 << CHANNEL_NUM, 0, 0, 0);
150 }
151
152 // Stop PCM
153 if (Trg & PAD_BUTTON_B)
154 {
155 SND_StopTimer(1 << CHANNEL_NUM, 0, 0, 0);
156 }
157
158 // Start capture
159 if (Trg & PAD_BUTTON_X)
160 {
161 int timerValue;
162 u32 alarmPeriod;
163 u32 alarmFirst;
164
165 timerValue = SND_TIMER_CLOCK / CAPTURE_SAMPLE_RATE;
166 alarmPeriod = timerValue * (CAPTURE_BUF_PAGESIZE / sizeof(s16)) / 32;
167 alarmFirst =
168 timerValue * ((CAPTURE_BUF_PAGESIZE + CAPTURE_FIFO_SIZE) / sizeof(s16)) / 32;
169 cap.bufPage = 0;
170
171 // Selector change: Output only channels 1 and 3
172 SND_SetOutputSelector(SND_OUTPUT_CHANNEL1,
173 SND_OUTPUT_CHANNEL3,
174 SND_CHANNEL_OUT_BYPASS, SND_CHANNEL_OUT_BYPASS);
175 // Play sound for capture 0 buffer
176 SND_SetupChannelPcm(1,
177 SND_WAVE_FORMAT_PCM16,
178 captureBufL,
179 SND_CHANNEL_LOOP_REPEAT,
180 0,
181 CAPTURE_BUF_SIZE / sizeof(u32),
182 MAX_VOLUME, SND_CHANNEL_DATASHIFT_NONE, timerValue, 0);
183 // Play sound for capture 1 buffer
184 SND_SetupChannelPcm(3,
185 SND_WAVE_FORMAT_PCM16,
186 captureBufR,
187 SND_CHANNEL_LOOP_REPEAT,
188 0,
189 CAPTURE_BUF_SIZE / sizeof(u32),
190 MAX_VOLUME, SND_CHANNEL_DATASHIFT_NONE, timerValue, 127);
191 // Capture 0 settings
192 SND_SetupCapture(SND_CAPTURE_0,
193 SND_CAPTURE_FORMAT_PCM16,
194 captureBufL,
195 CAPTURE_BUF_SIZE / sizeof(u32),
196 TRUE, SND_CAPTURE_IN_MIXER, SND_CAPTURE_OUT_NORMAL);
197 // Capture 1 settings
198 SND_SetupCapture(SND_CAPTURE_1,
199 SND_CAPTURE_FORMAT_PCM16,
200 captureBufR,
201 CAPTURE_BUF_SIZE / sizeof(u32),
202 TRUE, SND_CAPTURE_IN_MIXER, SND_CAPTURE_OUT_NORMAL);
203 // Alarm settings
204 SND_SetupAlarm(ALARM_NUM, alarmFirst, // Consider size of FIFO buffer the first time
205 alarmPeriod, SoundAlarmHandler, &cap);
206 SND_StartTimer((1 << 1) | (1 << 3),
207 (1 << SND_CAPTURE_0) | (1 << SND_CAPTURE_1), 1 << ALARM_NUM, 0);
208 OS_Printf("capture start\n");
209 }
210
211 // Stop capture
212 if (Trg & PAD_BUTTON_Y)
213 {
214 SND_StopTimer((1 << 1) | (1 << 3),
215 (1 << SND_CAPTURE_0) | (1 << SND_CAPTURE_1), 1 << ALARM_NUM, 0);
216 // Selector change: Output from mixer
217 SND_SetOutputSelector(SND_OUTPUT_MIXER,
218 SND_OUTPUT_MIXER, SND_CHANNEL_OUT_MIXER, SND_CHANNEL_OUT_MIXER);
219
220 OS_Printf("capture stop\n");
221 }
222
223 // Command flush
224 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
225 }
226 }
227
228 //--------------------------------------------------------------------------------
229 // V-Blank interrupt process
230 //
VBlankIntr(void)231 void VBlankIntr(void)
232 {
233 OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
234 }
235
236
237 /*---------------------------------------------------------------------------*
238 Name: CaptureThread
239
240 Description: The stream thread.
241
242 Arguments: arg: User data (unused)
243
244 Returns: None.
245 *---------------------------------------------------------------------------*/
CaptureThread(void *)246 static void CaptureThread(void * /*arg */ )
247 {
248 OSMessage message;
249
250 OS_InitMessageQueue(&msgQ, msgBuf, 1);
251
252 while (1)
253 {
254 (void)OS_ReceiveMessage(&msgQ, &message, OS_MESSAGE_BLOCK);
255 (void)CaptureFunc((CaptureInfo *) message);
256 }
257 }
258
259 /*---------------------------------------------------------------------------*
260 Name: SoundAlarmHandler
261
262 Description: Alarm callback function.
263
264 Arguments: arg: Stream object
265
266 Returns: None.
267 *---------------------------------------------------------------------------*/
SoundAlarmHandler(void * arg)268 static void SoundAlarmHandler(void *arg)
269 {
270 if (!OS_SendMessage(&msgQ, (OSMessage)arg, OS_MESSAGE_NOBLOCK))
271 OS_Printf("faild to send message\n");
272 }
273
274 /*---------------------------------------------------------------------------*
275 Name: CaptureFunc
276
277 Description: Generates stream data.
278
279 Arguments: strm: Stream object
280
281 Returns: None.
282 *---------------------------------------------------------------------------*/
CaptureFunc(CaptureInfo * cap)283 static void CaptureFunc(CaptureInfo * cap)
284 {
285 u8 *bufL, *bufR;
286
287 // Buffer page settings
288 if (cap->bufPage == 0)
289 {
290 bufL = captureBufL;
291 bufR = captureBufR;
292 cap->bufPage = 1;
293 }
294 else
295 {
296 bufL = captureBufL + CAPTURE_BUF_PAGESIZE;
297 bufR = captureBufR + CAPTURE_BUF_PAGESIZE;
298 cap->bufPage = 0;
299 }
300
301 EffectCallback(bufL, bufR, CAPTURE_BUF_PAGESIZE, SND_CAPTURE_FORMAT_PCM16, &cap->callbackInfo);
302 }
303
304
GetSample(smp_t * p,int x,int n,const EffectCallbackInfo * info)305 static inline smp_t GetSample(smp_t * p, int x, int n, const EffectCallbackInfo * info)
306 {
307 if (x >= 0)
308 return p[x];
309 x += FILTER_SIZE - 1;
310 return info->sample[x][n];
311 }
312
EffectCallback(void * bufferL_p,void * bufferR_p,u32 len,SNDCaptureFormat format,void * arg)313 void EffectCallback(void *bufferL_p, void *bufferR_p, u32 len, SNDCaptureFormat format, void *arg)
314 {
315 smp_t *lp = (smp_t *) bufferL_p;
316 smp_t *rp = (smp_t *) bufferR_p;
317 EffectCallbackInfo *info = (EffectCallbackInfo *) arg;
318 smp_t org[FILTER_SIZE - 1][2];
319 u32 samples;
320 int x;
321 long i, j;
322
323 samples = (format == SND_CAPTURE_FORMAT_PCM8) ? len : (len >> 1);
324
325 // store original sample data
326 for (i = 0; i < FILTER_SIZE - 1; i++)
327 {
328 org[i][0] = lp[i + samples - FILTER_SIZE + 1];
329 org[i][1] = rp[i + samples - FILTER_SIZE + 1];
330 }
331
332 // filtering
333 for (i = (long)(samples - 1); i >= FILTER_SIZE - 1; i--)
334 {
335 x = 0;
336 for (j = 0; j < FILTER_SIZE; j++)
337 {
338 x += lp[i - j];
339 }
340 x /= FILTER_SIZE;
341 lp[i] = (smp_t) x;
342
343 x = 0;
344 for (j = 0; j < FILTER_SIZE; j++)
345 {
346 x += rp[i - j];
347 }
348 x /= FILTER_SIZE;
349 rp[i] = (smp_t) x;
350 }
351
352 #if FILTER_SIZE >= 2
353 for (i = FILTER_SIZE - 2; i >= 0; i--)
354 {
355 x = lp[i];
356 for (j = 1; j < FILTER_SIZE; j++)
357 {
358 x += GetSample(lp, i - j, 0, info);
359 }
360 x /= FILTER_SIZE;
361 lp[i] = (smp_t) x;
362
363 x = rp[i];
364 for (j = 1; j < FILTER_SIZE; j++)
365 {
366 x += GetSample(rp, i - j, 1, info);
367 }
368 x /= FILTER_SIZE;
369 rp[i] = (smp_t) x;
370 }
371 #endif
372
373 // Store last samples for next callback
374 for (i = 0; i < FILTER_SIZE - 1; i++)
375 {
376 info->sample[i][0] = org[i][0];
377 info->sample[i][1] = org[i][1];
378 }
379
380 DC_FlushRange(bufferL_p, len);
381 DC_FlushRange(bufferR_p, len);
382 DC_WaitWriteBufferEmpty();
383
384 }
385