1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - DSP - demos.TWL - snd-mic
3   File:     main.c
4 
5   Copyright 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:: 2010-05-17#$
14   $Rev: 11335 $
15   $Author: kitase_hirotake $
16  *---------------------------------------------------------------------------*/
17 
18 
19 #include <twl.h>
20 #include <twl/dsp.h>
21 #include <twl/dsp/common/g711.h>
22 
23 #include <DEMO.h>
24 
25 
26 /*---------------------------------------------------------------------------*/
27 /* Constants */
28 
29 #define TEST_BUFFER_SIZE    (1024 * 32)
30 #define WAV_BUFFER_SIZE     (1024 * 512)
31 
32 
33 /*---------------------------------------------------------------------------*/
34 /* Variables */
35 
36 // Audio buffer for sound playback test
37 static u8           gWavData[WAV_BUFFER_SIZE] ATTRIBUTE_ALIGN(4);
38 static u32          gWavSize;
39 
40 // Ring buffer for microphone sampling test
41 static u8           gDspData[TEST_BUFFER_SIZE] ATTRIBUTE_ALIGN(2);
42 
43 // Control information for MIC library sampling run as comparison against DSP
44 static MICAutoParam gMicAutoParam;
45 static u8           gMicData[TEST_BUFFER_SIZE] ATTRIBUTE_ALIGN(HW_CACHE_LINE_SIZE);
46 
47 
48 /*---------------------------------------------------------------------------*/
49 /* Functions */
50 
51 /*---------------------------------------------------------------------------*
52   Name:         NormalizeRingBuffer
53 
54   Description:  Gets an amount of the newest ring buffer data equal to HW_LCD_HEIGHT samples.
55 
56   Arguments:    dst: Where the sample is to be stored
57                 type: The MICSamplingType type indicating sample type
58                 buffer: The starting address for the ring buffer where the sample is stored.
59                 position: The final sampling position (in bytes)
60 
61   Returns:      None.
62  *---------------------------------------------------------------------------*/
NormalizeRingBuffer(void * dst,MICSamplingType type,const void * buffer,int position)63 static void NormalizeRingBuffer(void *dst, MICSamplingType type, const void *buffer, int position)
64 {
65     const u8   *src = (const u8 *)buffer;
66     u8         *tmp = (u8 *)dst;
67     int         smp = 1;
68     switch (type)
69     {
70     case MIC_SAMPLING_TYPE_8BIT:
71     case MIC_SAMPLING_TYPE_SIGNED_8BIT:
72         smp = sizeof(u8);
73         break;
74     case MIC_SAMPLING_TYPE_12BIT:
75     case MIC_SAMPLING_TYPE_12BIT_FILTER_OFF:
76     case MIC_SAMPLING_TYPE_SIGNED_12BIT:
77     case MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF:
78         smp = sizeof(u16);
79         break;
80     }
81     {
82         int     max = TEST_BUFFER_SIZE / smp;
83         int     ofs = (position / smp - (HW_LCD_HEIGHT - 1)) & (max - 1);
84         int     pos = 0;
85         while (pos < HW_LCD_HEIGHT)
86         {
87             int     n = MATH_MIN(HW_LCD_HEIGHT - pos, max - ofs);
88             MI_CpuCopy8(&src[ofs * smp], &tmp[pos * smp], (u32)(n * smp));
89             ofs = (ofs + n) & (max - 1);
90             pos += n;
91         }
92     }
93 }
94 
95 /*---------------------------------------------------------------------------*
96   Name:         DrawWaveGraph
97 
98   Description:  Renders waveforms with triangular polygons.
99 
100   Arguments:    type: The MICSamplingType type indicating sample type
101                 color: Waveform color
102                 buffer: Waveform array stored in the specified sample type
103 
104   Returns:      None.
105  *---------------------------------------------------------------------------*/
DrawWaveGraph(MICSamplingType type,GXRgb color,const void * buffer)106 static void DrawWaveGraph(MICSamplingType type, GXRgb color, const void *buffer)
107 {
108     int     i;
109     int     bits = 8;
110     BOOL    isSigned = FALSE;
111     switch (type)
112     {
113     default:
114     case MIC_SAMPLING_TYPE_8BIT:
115         bits = 8, isSigned = FALSE;
116         break;
117     case MIC_SAMPLING_TYPE_SIGNED_8BIT:
118         bits = 8, isSigned = TRUE;
119         break;
120     case MIC_SAMPLING_TYPE_12BIT:
121     case MIC_SAMPLING_TYPE_12BIT_FILTER_OFF:
122         bits = 16, isSigned = FALSE;
123         break;
124     case MIC_SAMPLING_TYPE_SIGNED_12BIT:
125     case MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF:
126         bits = 16, isSigned = TRUE;
127         break;
128     }
129     for (i = 0; i < HW_LCD_HEIGHT - 1; ++i)
130     {
131         u8      cur8 = (u8)((bits == 8) ? ((const u8*)buffer)[i] : (((const u16*)buffer)[i] >> 8));
132         u8      nxt8 = (u8)((bits == 8) ? ((const u8*)buffer)[i + 1] : (((const u16*)buffer)[i + 1] >> 8));
133         int     cur = isSigned ? (((s8)cur8) + 128) : cur8;
134         int     nxt = isSigned ? (((s8)nxt8) + 128) : nxt8;
135         fx16    fsx = (fx16)(((cur - 128) * 0x1000) / 128);
136         fx16    fsy = (fx16)(((96 - i) * 0x1000) / 96);
137         fx16    fex = (fx16)(((nxt - 128) * 0x1000) / 128);
138         fx16    fey = (fx16)(((96 - i + 1) * 0x1000) / 96);
139         G3_Begin(GX_BEGIN_TRIANGLES);
140         {
141             G3_Color(color);
142             G3_Vtx(fsx, fsy, 0);
143             G3_Color(color);
144             G3_Vtx(fex, fey, 0);
145             G3_Color(color);
146             G3_Vtx(fsx, fsy, 1);
147         }
148         G3_End();
149     }
150 }
151 
152 /*---------------------------------------------------------------------------*
153   Name:         TwlMain
154 
155   Description:  Main
156 
157   Arguments:    None.
158 
159   Returns:      None.
160  *---------------------------------------------------------------------------*/
TwlMain(void)161 void TwlMain(void)
162 {
163     // OS initialization
164     OS_Init();
165     OS_InitTick();
166     OS_InitAlarm();
167     (void)OS_EnableIrq();
168     (void)OS_EnableInterrupts();
169 
170     // When in NITRO mode, stopped by Panic
171     DEMOCheckRunOnTWL();
172 
173     FS_Init(FS_DMA_NOT_USE);
174     SNDEX_Init();
175 
176     // Initialize screen display
177     DEMOInitCommon();
178     DEMOInitVRAM();
179     DEMOInitDisplayBitmap();
180     DEMOHookConsole();
181     G3X_InitMtxStack();
182     DEMOSetBitmapTextColor(GX_RGBA(31, 31, 0, 1));
183     DEMOSetBitmapGroundColor(DEMO_RGB_CLEAR);
184     DEMOStartDisplay();
185 
186     OS_TPrintf("A button: start DSP sampling\n");
187     OS_TPrintf("B button: stop DSP sampling\n");
188     OS_TPrintf("X button: pause rendering\n");
189     OS_TPrintf("Y button: play oneshot sound\n");
190     DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
191     DEMODrawText(0, 170, "--- DSP");
192     DEMOSetBitmapTextColor(GX_RGBA(31, 31,  0, 1));
193     DEMODrawText(0, 180, "--- MIC");
194     DEMOSetBitmapTextColor(GX_RGBA( 0, 31,  0, 1));
195     DEMODrawText(220,   5, "OLD");
196     DEMODrawText(220, 180, "NEW");
197 
198     // Turn the microphone module power ON
199     (void)PM_SetAmp(PM_AMP_ON);
200 
201     // Start the MIC library's autosampling
202     {
203         MIC_Init();
204         gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT;
205         gMicAutoParam.buffer = (void *)gMicData;
206         gMicAutoParam.size = TEST_BUFFER_SIZE;
207         gMicAutoParam.rate = MIC_SAMPLING_RATE_32730;
208         gMicAutoParam.loop_enable = TRUE;
209         gMicAutoParam.full_callback = NULL;
210         for (;;)
211         {
212             MICResult   result = MIC_StartLimitedSampling(&gMicAutoParam);
213             if (result == MIC_RESULT_SUCCESS)
214             {
215                 break;
216             }
217             else if ((result == MIC_RESULT_BUSY) || (result == MIC_RESULT_SEND_ERROR))
218             {
219                 OS_Sleep(1);
220             }
221             else if (result == MIC_RESULT_ILLEGAL_STATUS)
222             {
223                 OS_TWarning("Already started sampling.\n");
224                 break;
225             }
226             else if (result == MIC_RESULT_ILLEGAL_PARAMETER)
227             {
228                 OS_TWarning("Illegal parameter to start automatic sampling.\n");
229                 break;
230             }
231             else
232             {
233                 OS_TPanic("MIC_StartLimtedSampling() replied fatal error (%d).\n", result);
234             }
235         }
236     }
237 
238     // Load the DSP components
239     // (Any component is fine, so we use G.711 here.)
240     {
241         (void)MI_FreeWram_B(MI_WRAM_ARM9);
242         (void)MI_CancelWram_B(MI_WRAM_ARM9);
243         (void)MI_FreeWram_C(MI_WRAM_ARM9);
244         (void)MI_CancelWram_C(MI_WRAM_ARM9);
245         (void)MI_FreeWram_B( MI_WRAM_ARM7 );
246         (void)MI_CancelWram_B( MI_WRAM_ARM7 );
247         (void)MI_FreeWram_C( MI_WRAM_ARM7 );
248         (void)MI_CancelWram_C( MI_WRAM_ARM7 );
249         {
250             FSFile  file[1];
251             DSP_OpenStaticComponentG711(file);
252             if (!DSP_LoadG711(file, 0xFF, 0xFF))
253             {
254                 OS_TPanic("can't allocate WRAM Slot");
255             }
256         }
257     }
258 
259     // Prepare the PCM waveform for sound playback testing
260     {
261         FSFile  file[1];
262         u32     chunk;
263         FS_InitFile(file);
264         if (!FS_OpenFileEx(file, "rom:/fanfare.32.wav", FS_FILEMODE_R) ||
265             !FS_SeekFile(file, 0x24, FS_SEEK_SET) ||
266             (FS_ReadFile(file, &chunk, 4) != 4) ||
267             (chunk != (('d'<<0)|('a'<<8)|('t'<<16) |('a'<<24))) ||
268             (FS_ReadFile(file, &gWavSize, 4) != 4) ||
269             (FS_ReadFile(file, gWavData, (s32)gWavSize) != gWavSize))
270         {
271             OS_TPanic("cannot prepare sample waveform!");
272         }
273         (void)FS_CloseFile(file);
274         DC_StoreRange(gWavData, gWavSize);
275     }
276 
277     // Set DSP sound to 100%
278     (void)SNDEX_SetDSPMixRate(0);
279 
280     // Main loop
281     for (;;)
282     {
283         static BOOL pauseRendering = FALSE;
284 
285         DEMOReadKey();
286 
287         // Start and stop DSP sampling with the A and B Buttons
288         if (DEMO_IS_TRIG(PAD_BUTTON_A))
289         {
290             DSP_StartSampling(gDspData, sizeof(gDspData));
291         }
292         if (DEMO_IS_TRIG(PAD_BUTTON_B))
293         {
294             DSP_StopSampling();
295         }
296         // Pause waveform rendering with the X Button
297         if (DEMO_IS_TRIG(PAD_BUTTON_X))
298         {
299             pauseRendering = !pauseRendering;
300         }
301         // Play sound with the Y Button
302         if (DEMO_IS_TRIG(PAD_BUTTON_Y))
303         {
304             DSP_PlaySound(gWavData, gWavSize, FALSE);
305         }
306 
307         // For comparison's sake, get the MIC and DSP sampling position as simultaneously as possible
308         {
309             const u8   *dsp, *mic;
310 
311             // No need to invalidate the cache because the CPU periodically synchronizes it with the DSP's internal sampling buffer
312             //
313             DSP_SyncSamplingBuffer();
314             dsp = (const u8 *)DSP_GetLastSamplingAddress();
315             mic = (const u8 *)MIC_GetLastSamplingAddress();
316             // Explicit synchronization is not needed with the MIC library because the ARM7 writes directly to main memory, but cache invalidation is needed
317             //
318             DC_InvalidateRange(gMicData, sizeof(gMicData));
319 
320             // Render the most recent waveforms for both
321             if (!pauseRendering)
322             {
323                 G3X_Reset();
324                 G3_Identity();
325                 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
326 
327                 {
328                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
329                     const u8   *src = gDspData;
330                     MICSamplingType type = MIC_SAMPLING_TYPE_SIGNED_12BIT;
331                     NormalizeRingBuffer(tmp, type, src, dsp - src);
332                     DrawWaveGraph(type, GX_RGB(31, 31, 31), tmp);
333                 }
334 
335                 if (mic != NULL)
336                 {
337                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
338                     const u8   *src = gMicData;
339                     MICSamplingType type = gMicAutoParam.type;
340                     NormalizeRingBuffer(tmp, type, src, mic - src);
341                     DrawWaveGraph(type, GX_RGB(31, 31,  0), tmp);
342                 }
343 
344                 G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
345             }
346         }
347 
348         DEMO_DrawFlip();
349         OS_WaitVBlankIntr();
350     }
351 
352     OS_Terminate();
353 }
354