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:: 2008-12-08#$
14   $Rev: 9562 $
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     FS_Init(FS_DMA_NOT_USE);
170     SNDEX_Init();
171 
172     // Initialize screen display
173     DEMOInitCommon();
174     DEMOInitVRAM();
175     DEMOInitDisplayBitmap();
176     DEMOHookConsole();
177     G3X_InitMtxStack();
178     DEMOSetBitmapTextColor(GX_RGBA(31, 31, 0, 1));
179     DEMOSetBitmapGroundColor(DEMO_RGB_CLEAR);
180     DEMOStartDisplay();
181 
182     OS_TPrintf("A button: start DSP sampling\n");
183     OS_TPrintf("B button: stop DSP sampling\n");
184     OS_TPrintf("X button: pause rendering\n");
185     OS_TPrintf("Y button: play oneshot sound\n");
186     DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
187     DEMODrawText(0, 170, "--- DSP");
188     DEMOSetBitmapTextColor(GX_RGBA(31, 31,  0, 1));
189     DEMODrawText(0, 180, "--- MIC");
190     DEMOSetBitmapTextColor(GX_RGBA( 0, 31,  0, 1));
191     DEMODrawText(220,   5, "OLD");
192     DEMODrawText(220, 180, "NEW");
193 
194     // Turn the microphone module power ON
195     (void)PM_SetAmp(PM_AMP_ON);
196 
197     // Start the MIC library's autosampling
198     {
199         MIC_Init();
200         gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT;
201         gMicAutoParam.buffer = (void *)gMicData;
202         gMicAutoParam.size = TEST_BUFFER_SIZE;
203         gMicAutoParam.rate = MIC_SAMPLING_RATE_32730;
204         gMicAutoParam.loop_enable = TRUE;
205         gMicAutoParam.full_callback = NULL;
206         for (;;)
207         {
208             MICResult   result = MIC_StartLimitedSampling(&gMicAutoParam);
209             if (result == MIC_RESULT_SUCCESS)
210             {
211                 break;
212             }
213             else if ((result == MIC_RESULT_BUSY) || (result == MIC_RESULT_SEND_ERROR))
214             {
215                 OS_Sleep(1);
216             }
217             else if (result == MIC_RESULT_ILLEGAL_STATUS)
218             {
219                 OS_TWarning("Already started sampling.\n");
220                 break;
221             }
222             else if (result == MIC_RESULT_ILLEGAL_PARAMETER)
223             {
224                 OS_TWarning("Illegal parameter to start automatic sampling.\n");
225                 break;
226             }
227             else
228             {
229                 OS_TPanic("MIC_StartLimtedSampling() replied fatal error (%d).\n", result);
230             }
231         }
232     }
233 
234     // Load the DSP components.
235     // (Any component is fine, so we use G.711 here.)
236     {
237         (void)MI_FreeWram_B(MI_WRAM_ARM9);
238         (void)MI_CancelWram_B(MI_WRAM_ARM9);
239         (void)MI_FreeWram_C(MI_WRAM_ARM9);
240         (void)MI_CancelWram_C(MI_WRAM_ARM9);
241         {
242             FSFile  file[1];
243             DSP_OpenStaticComponentG711(file);
244             if (!DSP_LoadG711(file, 0xFF, 0xFF))
245             {
246                 OS_TPanic("can't allocate WRAM Slot");
247             }
248         }
249     }
250 
251     // Prepare the PCM waveform for sound playback testing
252     {
253         FSFile  file[1];
254         u32     chunk;
255         FS_InitFile(file);
256         if (!FS_OpenFileEx(file, "rom:/fanfare.32.wav", FS_FILEMODE_R) ||
257             !FS_SeekFile(file, 0x24, FS_SEEK_SET) ||
258             (FS_ReadFile(file, &chunk, 4) != 4) ||
259             (chunk != (('d'<<0)|('a'<<8)|('t'<<16) |('a'<<24))) ||
260             (FS_ReadFile(file, &gWavSize, 4) != 4) ||
261             (FS_ReadFile(file, gWavData, (s32)gWavSize) != gWavSize))
262         {
263             OS_TPanic("cannot prepare sample waveform!");
264         }
265         (void)FS_CloseFile(file);
266         DC_StoreRange(gWavData, gWavSize);
267     }
268 
269     // Set DSP sound to 100%
270     (void)SNDEX_SetDSPMixRate(0);
271 
272     // Main loop
273     for (;;)
274     {
275         static BOOL pauseRendering = FALSE;
276 
277         DEMOReadKey();
278 
279         // Start and stop DSP sampling with the A and B Buttons
280         if (DEMO_IS_TRIG(PAD_BUTTON_A))
281         {
282             DSP_StartSampling(gDspData, sizeof(gDspData));
283         }
284         if (DEMO_IS_TRIG(PAD_BUTTON_B))
285         {
286             DSP_StopSampling();
287         }
288         // Pause waveform rendering with the X Button
289         if (DEMO_IS_TRIG(PAD_BUTTON_X))
290         {
291             pauseRendering = !pauseRendering;
292         }
293         // Play sound with the Y Button
294         if (DEMO_IS_TRIG(PAD_BUTTON_Y))
295         {
296             DSP_PlaySound(gWavData, gWavSize, FALSE);
297         }
298 
299         // For comparison's sake, get the MIC and DSP sampling position as simultaneously as possible
300         {
301             const u8   *dsp, *mic;
302 
303             // No need to invalidate the cache because the CPU periodically synchronizes it with the DSP's internal sampling buffer
304             //
305             DSP_SyncSamplingBuffer();
306             dsp = (const u8 *)DSP_GetLastSamplingAddress();
307             mic = (const u8 *)MIC_GetLastSamplingAddress();
308             // Explicit synchronization is not needed with the MIC library because the ARM7 writes directly to main memory, but cache invalidation is needed
309             //
310             DC_InvalidateRange(gMicData, sizeof(gMicData));
311 
312             // Render the most recent waveforms for both
313             if (!pauseRendering)
314             {
315                 G3X_Reset();
316                 G3_Identity();
317                 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
318 
319                 {
320                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
321                     const u8   *src = gDspData;
322                     MICSamplingType type = MIC_SAMPLING_TYPE_SIGNED_12BIT;
323                     NormalizeRingBuffer(tmp, type, src, dsp - src);
324                     DrawWaveGraph(type, GX_RGB(31, 31, 31), tmp);
325                 }
326 
327                 if (mic != NULL)
328                 {
329                     u8          tmp[HW_LCD_HEIGHT * sizeof(u16)];
330                     const u8   *src = gMicData;
331                     MICSamplingType type = gMicAutoParam.type;
332                     NormalizeRingBuffer(tmp, type, src, mic - src);
333                     DrawWaveGraph(type, GX_RGB(31, 31,  0), tmp);
334                 }
335 
336                 G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
337             }
338         }
339 
340         DEMO_DrawFlip();
341         OS_WaitVBlankIntr();
342     }
343 
344     OS_Terminate();
345 }
346