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