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:: 2009-09-24#$
14   $Rev: 11063 $
15   $Author: okubata_ryoma $
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         {
246             FSFile  file[1];
247             DSP_OpenStaticComponentG711(file);
248             if (!DSP_LoadG711(file, 0xFF, 0xFF))
249             {
250                 OS_TPanic("can't allocate WRAM Slot");
251             }
252         }
253     }
254 
255     // Prepare the PCM waveform for sound playback testing
256     {
257         FSFile  file[1];
258         u32     chunk;
259         FS_InitFile(file);
260         if (!FS_OpenFileEx(file, "rom:/fanfare.32.wav", FS_FILEMODE_R) ||
261             !FS_SeekFile(file, 0x24, FS_SEEK_SET) ||
262             (FS_ReadFile(file, &chunk, 4) != 4) ||
263             (chunk != (('d'<<0)|('a'<<8)|('t'<<16) |('a'<<24))) ||
264             (FS_ReadFile(file, &gWavSize, 4) != 4) ||
265             (FS_ReadFile(file, gWavData, (s32)gWavSize) != gWavSize))
266         {
267             OS_TPanic("cannot prepare sample waveform!");
268         }
269         (void)FS_CloseFile(file);
270         DC_StoreRange(gWavData, gWavSize);
271     }
272 
273     // Set DSP sound to 100%
274     (void)SNDEX_SetDSPMixRate(0);
275 
276     // Main loop
277     for (;;)
278     {
279         static BOOL pauseRendering = FALSE;
280 
281         DEMOReadKey();
282 
283         // Start and stop DSP sampling with the A and B Buttons
284         if (DEMO_IS_TRIG(PAD_BUTTON_A))
285         {
286             DSP_StartSampling(gDspData, sizeof(gDspData));
287         }
288         if (DEMO_IS_TRIG(PAD_BUTTON_B))
289         {
290             DSP_StopSampling();
291         }
292         // Pause waveform rendering with the X Button
293         if (DEMO_IS_TRIG(PAD_BUTTON_X))
294         {
295             pauseRendering = !pauseRendering;
296         }
297         // Play sound with the Y Button
298         if (DEMO_IS_TRIG(PAD_BUTTON_Y))
299         {
300             DSP_PlaySound(gWavData, gWavSize, FALSE);
301         }
302 
303         // For comparison's sake, get the MIC and DSP sampling position as simultaneously as possible
304         {
305             const u8   *dsp, *mic;
306 
307             // No need to invalidate the cache because the CPU periodically synchronizes it with the DSP's internal sampling buffer
308             //
309             DSP_SyncSamplingBuffer();
310             dsp = (const u8 *)DSP_GetLastSamplingAddress();
311             mic = (const u8 *)MIC_GetLastSamplingAddress();
312             // Explicit synchronization is not needed with the MIC library because the ARM7 writes directly to main memory, but cache invalidation is needed
313             //
314             DC_InvalidateRange(gMicData, sizeof(gMicData));
315 
316             // Render the most recent waveforms for both
317             if (!pauseRendering)
318             {
319                 G3X_Reset();
320                 G3_Identity();
321                 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
322 
323                 {
324                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
325                     const u8   *src = gDspData;
326                     MICSamplingType type = MIC_SAMPLING_TYPE_SIGNED_12BIT;
327                     NormalizeRingBuffer(tmp, type, src, dsp - src);
328                     DrawWaveGraph(type, GX_RGB(31, 31, 31), tmp);
329                 }
330 
331                 if (mic != NULL)
332                 {
333                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
334                     const u8   *src = gMicData;
335                     MICSamplingType type = gMicAutoParam.type;
336                     NormalizeRingBuffer(tmp, type, src, mic - src);
337                     DrawWaveGraph(type, GX_RGB(31, 31,  0), tmp);
338                 }
339 
340                 G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
341             }
342         }
343 
344         DEMO_DrawFlip();
345         OS_WaitVBlankIntr();
346     }
347 
348     OS_Terminate();
349 }
350