1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MATH - demos
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-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro.h>
19 #include <nitro/fx/fx_trig.h>
20 
21 #include <nitro/spi/common/pm_common.h>
22 #include <nitro/spi/ARM9/pm.h>
23 
24 
25 /*---------------------------------------------------------------------------*
26     Constant Definitions
27  *---------------------------------------------------------------------------*/
28 
29 #define USE_FFTREAL
30 
31 enum {
32     DRAWMODE_REALTIME,
33     DRAWMODE_BAR,
34     DRAWMODE_SCALE,
35     DRAWMODE_MAX
36 };
37 
38 #define KEY_REPEAT_START    25     // Number of frames until key repeat starts
39 #define KEY_REPEAT_SPAN     10     // Number of frames between key repeats
40 #define SAMPLING_BUFFER_SIZE ( 1024 * 1024 ) // 1M
41 
42 #define FFT_NSHIFT         11
43 #define FFT_N              (1 << FFT_NSHIFT)      // Number of samples on which an FFT will be applied
44 #define DRAW_STEP          MATH_MAX(FFT_N/2/256,1)    // Number of steps to render
45 #define DRAW_MAX           MATH_MIN(FFT_N/2/DRAW_STEP, 256) // Independent power values other than the DC component, and the minimum screen width
46 
47 #define SCALE_SAMPLING_OCTAVES 5
48 
49 // Sound output related
50 #define CHANNEL_NUM 4
51 #define ALARM_NUM 0
52 #define STREAM_THREAD_PRIO 12
53 #define THREAD_STACK_SIZE 1024
54 #define STRM_BUF_PAGESIZE 64*32
55 #define STRM_BUF_SIZE STRM_BUF_PAGESIZE*2
56 #define STRM_SAMPLE_RATE 44100
57 #define OSC_MAX_VOLUME 32767
58 
59 // Derive the frequency from the key number
60 #define GetFreq(pitch) (SND_TIMER_CLOCK / SND_CalcTimer((SND_TIMER_CLOCK / 440), (pitch - 69 * 64)))
61 
62 /*---------------------------------------------------------------------------*
63     Structure Definitions
64  *---------------------------------------------------------------------------*/
65 // Key input data
66 typedef struct KeyInformation
67 {
68     u16     cnt;                       // Unprocessed input value
69     u16     trg;                       // Push trigger input
70     u16     up;                        // Release trigger input
71     u16     rep;                       // Press and hold repeat input
72 
73 }
74 KeyInformation;
75 
76 // Sound output related
77 // Stream object
78 typedef struct StreamInfo
79 {
80     u32     bufPage;
81 }
82 StreamInfo;
83 
84 // Touch panel
85 typedef struct TpInformation
86 {
87     int     touch:1;
88     int     trg:1;
89     int     rls:1;
90     u16     x;
91     u16     y;
92 }
93 TpInformation;
94 
95 // Oscillator
96 typedef struct Oscillator
97 {
98     fx16    index;
99     fx16    step;
100     fx32    rate;                      // Output sampling rate
101     u16     gain;
102     u16     dummy;
103 }
104 Oscillator;
105 
106 /*---------------------------------------------------------------------------*
107     Internal Function Definitions
108  *---------------------------------------------------------------------------*/
109 static void InitializeAllocateSystem(void);
110 static void Init3D(void);
111 static void Draw3D_Realtime(void);
112 static void Draw3D_Bar(void);
113 static void Draw3D_Scale(void);
114 static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey);
115 static void DrawBar(s16 sx, s16 sy, s16 ex, s16 ey);
116 static void DrawBarWithColor(s16 sx, s16 sy, s16 ex, s16 ey, u32 c);
117 static void VBlankIntr(void);
118 static void KeyRead(KeyInformation * pKey);
119 static void SetDrawData(void *address);
120 static void PrintfVariableData(void);
121 
122 // Sound output related
123 static void SoundAlarmHandler(void *arg);
124 static void StrmThread(void *arg);
125 static void Play(StreamInfo * strm);
126 static void Stop();
127 static void MakeStreamData(StreamInfo * strm);
128 static void TpRead(TpInformation* tp);
129 
130 /*---------------------------------------------------------------------------*
131     Internal Variable Definitions
132  *---------------------------------------------------------------------------*/
133 static MICAutoParam gMicAutoParam;
134 static u8 *gMicData;
135 static u8 gDrawData[DRAW_MAX];
136 
137 // FFT buffers
138 static fx16 sinTable[FFT_N - FFT_N / 4];
139 #ifdef USE_FFTREAL
140 static fx16 sinTable2[(FFT_N - FFT_N / 4) / 2];
141 static fx32 data[FFT_N];
142 #else
143 static fx32 data[FFT_N * 2];
144 #endif
145 static s32 power[FFT_N/2+1];
146 static s32 smoothedPower[FFT_N/2+1];
147 
148 static BOOL drawMode;
149 static u8 blockCount;
150 
151 // Sound output related
152 static u64 strmThreadStack[THREAD_STACK_SIZE / sizeof(u64)];
153 static OSThread strmThread;
154 static OSMessageQueue msgQ;
155 static OSMessage msgBuf[1];
156 
157 static u8 strmBuf[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
158 
159 static Oscillator osc;
160 static TPCalibrateParam calibrate;
161 
162 /*---------------------------------------------------------------------------*
163   Name:         NitroMain
164 
165   Description:  Initialization and main loop
166 
167   Arguments:    None
168 
169   Returns:      None
170  *---------------------------------------------------------------------------*/
NitroMain(void)171 void NitroMain(void)
172 {
173     KeyInformation key;
174     TpInformation tp;
175     StreamInfo strm;
176 
177     // Various types of initialization
178     OS_Init();
179     OS_InitTick();
180     OS_InitThread();
181     FX_Init();
182     GX_Init();
183     GX_DispOff();
184     GXS_DispOff();
185     SND_Init();
186     TP_Init();
187 
188     // initializes display settings
189     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
190     MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
191     (void)GX_DisableBankForLCDC();
192     MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
193     MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
194     MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
195     MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
196 
197     // 3D related initialization
198     Init3D();
199 
200     // Initializes touch panel read
201     (void)TP_GetUserInfo(&calibrate);
202     TP_SetCalibrateParam(&calibrate);
203 
204     // Oscillator settings
205     osc.rate = STRM_SAMPLE_RATE << FX32_SHIFT;
206 
207     // Interrupt settings
208     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
209     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
210     (void)OS_EnableIrq();
211     (void)OS_EnableInterrupts();
212     (void)GX_VBlankIntr(TRUE);
213 
214     //****************************************************************
215     // Initialize MIC.
216     InitializeAllocateSystem();
217     // Because the memory allocated with OS_Alloc is 32-byte aligned, other memory is not destroyed even if the cache is manipulated
218     //
219     gMicData = (u8 *)OS_Alloc(SAMPLING_BUFFER_SIZE);
220     SDK_NULL_ASSERT(gMicData);
221     MIC_Init();
222 
223     // Initialize PMIC
224     PM_Init();
225     // AMP on
226     (void)PM_SetAmp(PM_AMP_ON);
227     // Adjust AMP gain
228     (void)PM_SetAmpGain(PM_AMPGAIN_80);
229 
230     // Perform 12-bit sampling to increase the accuracy of Fourier transforms
231     gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT;
232     gMicAutoParam.buffer = (void *)gMicData;
233     gMicAutoParam.size = SAMPLING_BUFFER_SIZE;
234     gMicAutoParam.loop_enable = TRUE;
235     gMicAutoParam.full_callback = NULL;
236 #ifdef SDK_TWL
237     gMicAutoParam.rate = MIC_SAMPLING_RATE_8180;
238     (void)MIC_StartLimitedSampling(&gMicAutoParam);
239 #else   // ifdef SDK_TWL
240     gMicAutoParam.rate = MIC_SAMPLING_RATE_8K;
241     (void)MIC_StartAutoSampling(&gMicAutoParam);
242 #endif  // ifdef SDK_TWL else
243 
244     //****************************************************************
245 
246     // Initialize internal variables
247     MATH_MakeFFTSinTable(sinTable, FFT_NSHIFT);
248 #ifdef USE_FFTREAL
249     MATH_MakeFFTSinTable(sinTable2, FFT_NSHIFT - 1);
250 #endif
251     MI_CpuClear8(gDrawData, sizeof(gDrawData));
252 
253     // LCD display start
254     GX_DispOn();
255     GXS_DispOn();
256 
257     // Debug string output
258     OS_Printf("ARM9: FFT spectrum demo started.\n");
259     OS_Printf("   up/down    -> change bar width (Bar Mode)\n");
260     OS_Printf("   left/right -> change draw mode\n");
261     OS_Printf("\n");
262     PrintfVariableData();
263 
264     // Empty call for getting key input data (strategy for pressing A Button in the IPL)
265     KeyRead(&key);
266 
267     // Lock the channel
268     SND_LockChannel(1 << CHANNEL_NUM, 0);
269 
270     /* Startup stream thread */
271     OS_CreateThread(&strmThread,
272                     StrmThread,
273                     NULL,
274                     strmThreadStack + THREAD_STACK_SIZE / sizeof(u64),
275                     THREAD_STACK_SIZE, STREAM_THREAD_PRIO);
276     OS_WakeupThreadDirect(&strmThread);
277 
278     // The initial display mode is bar display
279     drawMode = DRAWMODE_BAR;
280     blockCount = 4;
281 
282     // Main loop
283     while (TRUE)
284     {
285         // Receive ARM7 command reply
286         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
287         {
288         }
289 
290         // Get key input data
291         KeyRead(&key);
292 
293         // Read the touch panel
294         TpRead(&tp);
295 
296         // Change variable parameters
297         {
298 
299             // Change display mode
300             if ((key.trg | key.rep) & (PAD_KEY_LEFT | PAD_KEY_RIGHT))
301             {
302                 if ((key.trg | key.rep) & PAD_KEY_RIGHT)
303                 {
304                     drawMode++;
305                 }
306                 if ((key.trg | key.rep) & PAD_KEY_LEFT)
307                 {
308                     drawMode--;
309                 }
310 
311                 if (drawMode < 0)
312                 {
313                     drawMode += DRAWMODE_MAX;
314                 }
315                 if (drawMode >= DRAWMODE_MAX)
316                 {
317                     drawMode -= DRAWMODE_MAX;
318                 }
319 
320                 // Initialize accumulated data when switching display modes
321                 MI_CpuClear32(smoothedPower, sizeof(smoothedPower));
322             }
323 
324             // Update block count
325             if ((key.trg | key.rep) & PAD_KEY_UP)
326             {
327                 blockCount += 1;
328                 if (blockCount >= 16)
329                 {
330                     blockCount = 16;
331                 }
332                 OS_Printf("block = %d\n", blockCount);
333             }
334             if ((key.trg | key.rep) & PAD_KEY_DOWN)
335             {
336                 blockCount -= 1;
337                 if (blockCount <= 2)
338                 {
339                     blockCount = 2;
340                 }
341                 OS_TPrintf("block = %d\n", blockCount);
342             }
343         }
344 
345         // Calculate waveform data
346         SetDrawData(MIC_GetLastSamplingAddress());
347 
348         // Render waveform
349         // Switch for each drawMode
350         switch (drawMode)
351         {
352         case DRAWMODE_REALTIME:
353             Draw3D_Realtime();
354             break;
355 
356         case DRAWMODE_BAR:
357             Draw3D_Bar();
358             break;
359 
360         case DRAWMODE_SCALE:
361             Draw3D_Scale();
362             break;
363         }
364 
365         // Output the waveform that corresponds to the position touched on the Touch Panel
366         if (tp.touch)
367         {
368             osc.step = (fx16)FX_Div(GetFreq(tp.x * 12 + 60 * 64) << FX32_SHIFT, osc.rate);
369             osc.gain = (u16)(tp.y * OSC_MAX_VOLUME / 192);
370         }
371 
372         // Plays the PSG square wave
373         if (tp.trg)
374         {
375             Play(&strm);
376         }
377 
378         if (tp.rls)
379         {
380             Stop();
381         }
382 
383         // Command flush
384         (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
385         // Waiting for the V-Blank
386         OS_WaitVBlankIntr();
387     }
388 }
389 
390 /*---------------------------------------------------------------------------*
391   Name:         InitializeAllocateSystem
392 
393   Description:  Initializes the memory allocation system within the main memory arena
394 
395   Arguments:    None
396 
397   Returns:      None
398  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)399 static void InitializeAllocateSystem(void)
400 {
401     void   *tempLo;
402     OSHeapHandle hh;
403 
404     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
405     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
406     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
407     if (hh < 0)
408     {
409         OS_Panic("ARM9: Fail to create heap...\n");
410     }
411     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
412 }
413 
414 /*---------------------------------------------------------------------------*
415   Name:         Init3D
416 
417   Description:  Initialization for 3D display
418 
419   Arguments:    None
420 
421   Returns:      None
422  *---------------------------------------------------------------------------*/
Init3D(void)423 static void Init3D(void)
424 {
425     G3X_Init();
426     G3X_InitMtxStack();
427     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_3D);
428     GX_SetVisiblePlane(GX_PLANEMASK_BG0);
429     G2_SetBG0Priority(0);
430     G3X_AlphaTest(FALSE, 0);
431     G3X_AntiAlias(TRUE);
432     G3X_EdgeMarking(FALSE);
433     G3X_SetFog(FALSE, (GXFogBlend)0, (GXFogSlope)0, 0);
434     G3X_SetClearColor(0, 0, 0x7fff, 63, FALSE);
435     G3_ViewPort(0, 0, 255, 191);
436     G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
437 }
438 
439 /*---------------------------------------------------------------------------*
440   Name:         Draw3D_Realtime
441 
442   Description:  Displays 3D waveforms in real-time
443 
444   Arguments:    None
445 
446   Returns:      None
447  *---------------------------------------------------------------------------*/
Draw3D_Realtime(void)448 static void Draw3D_Realtime(void)
449 {
450     G3X_Reset();
451     G3_Identity();
452     G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
453 
454     {
455         s32     i;
456 
457         for (i = 0; i < DRAW_MAX-1; i++)
458         {
459             DrawLine((s16)i, (s16)(192 - gDrawData[i]),
460                      (s16)(i + 1), (s16)(192 - gDrawData[i + 1]));
461         }
462     }
463 
464     G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
465 }
466 
467 /*---------------------------------------------------------------------------*
468   Name:         Draw3D_Bar
469 
470   Description:  Bar display for waveforms in 3D
471 
472   Arguments:    None
473 
474   Returns:      None
475  *---------------------------------------------------------------------------*/
Draw3D_Bar(void)476 static void Draw3D_Bar(void)
477 {
478     G3X_Reset();
479     G3_Identity();
480     G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
481 
482     {
483         s32     i;
484 
485         for (i = 0; i < DRAW_MAX-1; i += blockCount)
486         {
487             DrawBar((s16)i, (s16)(192 - gDrawData[i]), (s16)(i + blockCount), (s16)192);
488         }
489     }
490 
491     G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
492 }
493 
494 /*---------------------------------------------------------------------------*
495   Name:         Draw3D_Scale
496 
497   Description:  Displays waveforms in 3D by musical scale
498 
499   Arguments:    None
500 
501   Returns:      None
502  *---------------------------------------------------------------------------*/
Draw3D_Scale(void)503 static void Draw3D_Scale(void)
504 {
505     G3X_Reset();
506     G3_Identity();
507     G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
508 
509     {
510         s32     i;
511 
512         for (i = 0; i < 12; i++)
513         {
514             s32     j;
515             for (j = 0; j < SCALE_SAMPLING_OCTAVES; j++)
516             {
517                 DrawBarWithColor((s16)((i * (SCALE_SAMPLING_OCTAVES + 2) + j) * 3 + 2),
518                                  (s16)(192 - gDrawData[i * SCALE_SAMPLING_OCTAVES + j]),
519                                  (s16)((i * (SCALE_SAMPLING_OCTAVES + 2) + j) * 3 + 5),
520                                  (s16)192, (u32)(j + 1));
521             }
522         }
523     }
524 
525     G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
526 }
527 
528 const GXRgb ColorTable[8] =
529 {
530     GX_RGB( 0,  0,  0),
531     GX_RGB(20, 20, 31),
532     GX_RGB(20, 31, 20),
533     GX_RGB(28, 31, 20),
534     GX_RGB(31, 25, 20),
535     GX_RGB(31, 20, 20),
536     GX_RGB(31, 24, 24),
537     GX_RGB(31, 31, 31),
538 };
539 
540 /*---------------------------------------------------------------------------*
541   Name:         DrawLine
542 
543   Description:  Renders lines with triangular polygons
544 
545   Arguments:    sx:   x coordinate of line's starting point
546                 sy:   y coordinate of line's starting point
547                 ex:   x coordinate of line's ending point
548                 ey:   y coordinate of line's ending point
549 
550   Returns:      None
551  *---------------------------------------------------------------------------*/
DrawLine(s16 sx,s16 sy,s16 ex,s16 ey)552 static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey)
553 {
554     fx16    fsx = (fx16)(((sx - 128) * 0x1000) / 128);
555     fx16    fsy = (fx16)(((96 - sy) * 0x1000) / 96);
556     fx16    fex = (fx16)(((ex - 128) * 0x1000) / 128);
557     fx16    fey = (fx16)(((96 - ey) * 0x1000) / 96);
558 
559     G3_Begin(GX_BEGIN_TRIANGLES);
560     {
561         G3_Color(GX_RGB(31, 31, 31));
562         G3_Vtx(fsx, fsy, 0);
563         G3_Color(GX_RGB(31, 31, 31));
564         G3_Vtx(fex, fey, 0);
565         G3_Color(GX_RGB(31, 31, 31));
566         G3_Vtx(fsx, fsy, 1);
567     }
568     G3_End();
569 }
570 
571 /*---------------------------------------------------------------------------*
572   Name:         DrawBar
573 
574   Description:  Render a bar with square (rectangular) polygons.
575 
576   Arguments:    sx:   Upper-left x coordinate of square to render
577                 sy:   Upper-left y coordinate of square to render
578                 ex:   Lower-right x coordinate of square to render
579                 ey:   Lower-right y coordinate of square to render
580 
581   Returns:      None.
582  *---------------------------------------------------------------------------*/
DrawBar(s16 sx,s16 sy,s16 ex,s16 ey)583 static void DrawBar(s16 sx, s16 sy, s16 ex, s16 ey)
584 {
585     fx16    fsx = (fx16)(((sx - 128) * 0x1000) / 128);
586     fx16    fsy = (fx16)(((96 - sy) * 0x1000) / 96);
587     fx16    fex = (fx16)(((ex - 128) * 0x1000) / 128);
588     fx16    fey = (fx16)(((96 - ey) * 0x1000) / 96);
589 
590     G3_Begin(GX_BEGIN_QUADS);
591     {
592         G3_Color(GX_RGB(31, 31, 31));
593         G3_Vtx(fsx, fsy, 0);
594         G3_Color(GX_RGB(31, 31, 31));
595         G3_Vtx(fsx, fey, 0);
596         G3_Color(GX_RGB(31, 31, 31));
597         G3_Vtx(fex, fey, 0);
598         G3_Color(GX_RGB(31, 31, 31));
599         G3_Vtx(fex, fsy, 0);
600     }
601     G3_End();
602 }
603 
604 /*---------------------------------------------------------------------------*
605   Name:         DrawBarWithColor
606 
607   Description:  Render a bar with square (rectangular) polygons.
608 
609   Arguments:    sx:   Upper-left x coordinate of square to render
610                 sy:   Upper-left y coordinate of square to render
611                 ex:   Lower-right x coordinate of square to render
612                 ey:   Lower-right y coordinate of square to render
613                 c:    Color to render in
614 
615   Returns:      None.
616  *---------------------------------------------------------------------------*/
DrawBarWithColor(s16 sx,s16 sy,s16 ex,s16 ey,u32 c)617 static void DrawBarWithColor(s16 sx, s16 sy, s16 ex, s16 ey, u32 c)
618 {
619     fx16    fsx = (fx16)(((sx - 128) * 0x1000) / 128);
620     fx16    fsy = (fx16)(((96 - sy) * 0x1000) / 96);
621     fx16    fex = (fx16)(((ex - 128) * 0x1000) / 128);
622     fx16    fey = (fx16)(((96 - ey) * 0x1000) / 96);
623     GXRgb color;
624 
625     if ( c >= sizeof(ColorTable)/sizeof(ColorTable[0]) )
626     {
627         c = 0;
628     }
629     color = ColorTable[c];
630 
631     G3_Begin(GX_BEGIN_QUADS);
632     {
633         G3_Color(color);
634         G3_Vtx(fsx, fsy, 0);
635         G3_Color(color);
636         G3_Vtx(fsx, fey, 0);
637         G3_Color(color);
638         G3_Vtx(fex, fey, 0);
639         G3_Color(color);
640         G3_Vtx(fex, fsy, 0);
641     }
642     G3_End();
643 }
644 
645 /*---------------------------------------------------------------------------*
646   Name:         VBlankIntr
647 
648   Description:  V-Blank interrupt vector.
649 
650   Arguments:    None.
651 
652   Returns:      None.
653  *---------------------------------------------------------------------------*/
VBlankIntr(void)654 static void VBlankIntr(void)
655 {
656     // Sets the IRQ check flag
657     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
658 }
659 
660 /*---------------------------------------------------------------------------*
661   Name:         KeyRead
662 
663   Description:  Edits key input data.
664                 Detects press trigger, release trigger, and press-and-hold repeat.
665 
666   Arguments:    pKey:   Structure that holds key input data to be edited
667 
668   Returns:      None.
669  *---------------------------------------------------------------------------*/
KeyRead(KeyInformation * pKey)670 static void KeyRead(KeyInformation * pKey)
671 {
672     static u16 repeat_count[12];
673     int     i;
674     u16     r;
675 
676     r = PAD_Read();
677     pKey->trg = 0x0000;
678     pKey->up = 0x0000;
679     pKey->rep = 0x0000;
680 
681     for (i = 0; i < 12; i++)
682     {
683         if (r & (0x0001 << i))
684         {
685             if (!(pKey->cnt & (0x0001 << i)))
686             {
687                 pKey->trg |= (0x0001 << i);     // Press trigger
688                 repeat_count[i] = 1;
689             }
690             else
691             {
692                 if (repeat_count[i] > KEY_REPEAT_START)
693                 {
694                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
695                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
696                 }
697                 else
698                 {
699                     repeat_count[i]++;
700                 }
701             }
702         }
703         else
704         {
705             if (pKey->cnt & (0x0001 << i))
706             {
707                 pKey->up |= (0x0001 << i);      // Release trigger
708             }
709         }
710     }
711     pKey->cnt = r;                     // Unprocessed key input
712 }
713 
714 // Index in array of Fourier transforms, each corresponding to a musical scale
715 // Reference Information:
716 //   According to sampling theory, the maximum frequency for which coefficients can be obtained by a Fourier transform is half of the sampling frequency (4000 Hz).
717 //
718 //   Also, there can be FFT_N/2 independent power values obtained by the Fourier transform.
719 //   The spectral frequency resolution that can be obtained as the result of the Fourier transform is 4000Hz / (FFT_N/2).
720 //
721 //   (1) To increase the frequency resolution:
722 //     Increase FFT_N, which will increase the processing time and decrease the time resolution.
723 //     Decrease the sampling frequency (cull input data), which will lower the frequency band
724 //   (2) To raise the frequency band:
725 //     Increase the sampling frequency, which will decrease the frequency resolution.
726 static u32 scaleSamplingPoints[12][SCALE_SAMPLING_OCTAVES][2] =
727 {
728     // FFT_N = 2048
729     { // C
730         { 33 , 34  }, /* (130.813 Hz : 33.4881) */
731         { 65 , 69  }, /* (261.626 Hz : 66.9761) */
732         { 130, 138 }, /* (523.251 Hz : 133.952) */
733         { 260, 276 }, /* (1046.5 Hz : 267.905) */
734         { 521, 552 }, /* (2093 Hz : 535.809) */
735     },
736     { // C#
737         { 34 , 37  }, /* (138.591 Hz : 35.4794) */
738         { 69 , 73  }, /* (277.183 Hz : 70.9588) */
739         { 138, 146 }, /* (554.365 Hz : 141.918) */
740         { 276, 292 }, /* (1108.73 Hz : 283.835) */
741         { 552, 584 }, /* (2217.46 Hz : 567.67 ) */
742     },
743     { // D
744         { 37 , 39  }, /* (146.832 Hz : 37.5891) */
745         { 73 , 77  }, /* (293.665 Hz : 75.1782) */
746         { 146, 155 }, /* (587.33 Hz : 150.356) */
747         { 292, 310 }, /* (1174.66 Hz : 300.713) */
748         { 584, 619 }, /* (2349.32 Hz : 601.425) */
749     },
750     { // D#
751         { 39 , 41  }, /* (155.563 Hz : 39.8243) */
752         { 77 , 82  }, /* (311.127 Hz : 79.6485) */
753         { 155, 164 }, /* (622.254 Hz : 159.297) */
754         { 310, 328 }, /* (1244.51 Hz : 318.594) */
755         { 619, 656 }, /* (2489.02 Hz : 637.188) */
756     },
757     { // E
758         { 41 , 43  }, /* (164.814 Hz : 42.1923) */
759         { 82 , 87  }, /* (329.628 Hz : 84.3847) */
760         { 164, 174 }, /* (659.255 Hz : 168.769) */
761         { 328, 347 }, /* (1318.51 Hz : 337.539) */
762         { 656, 695 }, /* (2637.02 Hz : 675.077) */
763     },
764     { // F
765         { 43 , 46  }, /* (174.614 Hz : 44.7012) */
766         { 87 , 92  }, /* (349.228 Hz : 89.4024) */
767         { 174, 184 }, /* (698.456 Hz : 178.805) */
768         { 347, 368 }, /* (1396.91 Hz : 357.61 ) */
769         { 695, 736 }, /* (2793.83 Hz : 715.219) */
770     },
771     { // F#
772         { 46 , 49  }, /* (184.997 Hz : 47.3593) */
773         { 92 , 97  }, /* (369.994 Hz : 94.7186) */
774         { 184, 195 }, /* (739.989 Hz : 189.437) */
775         { 368, 390 }, /* (1479.98 Hz : 378.874) */
776         { 736, 780 }, /* (2959.96 Hz : 757.749) */
777     },
778     { // G
779         { 49 , 52  }, /* (195.998 Hz : 50.1754) */
780         { 97 , 103 }, /* (391.995 Hz : 100.351) */
781         { 195, 207 }, /* (783.991 Hz : 200.702) */
782         { 390, 413 }, /* (1567.98 Hz : 401.403) */
783         { 780, 826 }, /* (3135.96 Hz : 802.807) */
784     },
785     { // G#
786         { 52 , 55  }, /* (207.652 Hz : 53.159 ) */
787         { 103, 109 }, /* (415.305 Hz : 106.318) */
788         { 207, 219 }, /* (830.609 Hz : 212.636) */
789         { 413, 438 }, /* (1661.22 Hz : 425.272) */
790         { 826, 875 }, /* (3322.44 Hz : 850.544) */
791     },
792     { // A
793         { 55 , 58  }, /* (220 Hz : 56.32  ) */
794         { 109, 116 }, /* (440 Hz : 112.64 ) */
795         { 219, 232 }, /* (880 Hz : 225.28 ) */
796         { 438, 464 }, /* (1760 Hz : 450.56 ) */
797         { 875, 928 }, /* (3520 Hz : 901.12 ) */
798     },
799     { // A#
800         { 58 , 61  }, /* (233.082 Hz : 59.669 ) */
801         { 116, 123 }, /* (466.164 Hz : 119.338) */
802         { 232, 246 }, /* (932.328 Hz : 238.676) */
803         { 464, 491 }, /* (1864.66 Hz : 477.352) */
804         { 928, 983 }, /* (3729.31 Hz : 954.703) */
805     },
806     { // B
807         { 61 , 65  }, /* (246.942 Hz : 63.2171) */
808         { 123, 130 }, /* (493.883 Hz : 126.434) */
809         { 246, 260 }, /* (987.767 Hz : 252.868) */
810         { 491, 521 }, /* (1975.53 Hz : 505.737) */
811         { 983, 1023 }, /* (3951.07 Hz : 1011.47) */
812     },
813 };
814 
815 /*---------------------------------------------------------------------------*
816   Name:         SetDrawData
817 
818   Description:  Stores the current newest sampled data in the buffer that puts it on the display.
819 
820 
821   Arguments:    address: Location in main memory where the most recent sampling data was stored by the component
822 
823 
824   Returns:      None.
825  *---------------------------------------------------------------------------*/
SetDrawData(void * address)826 static void SetDrawData(void *address)
827 {
828     s32     i;
829     u16    *p;
830 
831     // If sampling has never been performed, do nothing and stop.
832     // (Because it would delete memory cache(s) unrelated to the microphone)
833     if ((address < gMicData) || (address >= (gMicData + SAMPLING_BUFFER_SIZE)))
834     {
835         return;
836     }
837 
838     // Apply a FFT for the FFT_N most recent sampling values
839     // With 12-bit sampling, each value is two bytes
840     p = (u16 *)((u32)address - (FFT_N-1)*2);
841     if ((u32)p < (u32)gMicData)
842     {
843         p = (u16 *)((u32)p + SAMPLING_BUFFER_SIZE);
844     }
845     DC_InvalidateRange((void *)((u32)p & 0xffffffe0), 32);
846     for (i = 0; i < FFT_N; i++)
847     {
848 #ifdef USE_FFTREAL
849         data[i] = ((*p) << (FX32_SHIFT - (16 - 12)));
850 #else
851         data[i * 2] = ((*p) << (FX32_SHIFT - (16 - 12)));
852         data[i * 2 + 1] = 0; // Substitute 0 in the imaginary part
853 #endif
854         p++;
855         if ((u32)p >= (u32)(gMicData + SAMPLING_BUFFER_SIZE))
856         {
857             p = (u16 *)((u32)p - SAMPLING_BUFFER_SIZE);
858         }
859         if (((u32)p % 32) == 0)
860         {
861             DC_InvalidateRange(p, 32);
862         }
863     }
864 
865 #ifdef USE_FFTREAL
866     MATH_FFTReal(data, FFT_NSHIFT, sinTable, sinTable2);
867 #else
868     MATH_FFT(data, FFT_NSHIFT, sinTable);
869 #endif
870 
871     // Do not calculate above FFT_N/2 because only conjugated, inverted values of those below FFT_N/2 can be obtained
872     for (i = 0; i <= FFT_N/2; i++)
873     {
874         fx32 real;
875         fx32 imm;
876 
877 #ifdef USE_FFTREAL
878         if (0 < i  && i < FFT_N/2)
879         {
880             real = data[i * 2];
881             imm  = data[i * 2 + 1];
882         }
883         else
884         {
885             // Process the results of the MATH_FFTReal function because they are stored specially
886             if (i == 0)
887             {
888                 real = data[0];
889             }
890             else // i == FFT_N/2
891             {
892                 real = data[1];
893             }
894             imm  = 0;
895         }
896 #else
897         real = data[i * 2];
898         imm  = data[i * 2 + 1];
899 #endif
900 
901         // Calculate the power of each frequency
902         // If only the relative value size is necessary, omitting the sqrt can result in a speed increase
903         power[i] = FX_Whole(FX_Sqrt(FX_MUL(real, real) + FX_MUL(imm, imm)));
904 
905         // Record the accumulated time values for the power of each frequency
906         // Perform damping a little at a time
907         smoothedPower[i] += power[i] - (smoothedPower[i]/8);
908     }
909 
910     switch (drawMode)
911     {
912     case DRAWMODE_REALTIME:
913         // Real-time display
914 
915         for (i = 0; i < DRAW_MAX; i++)
916         {
917             s32     j, index;
918             fx32    tmpPower;
919 
920             // Reason for adding 1: The data in power[0] is the DC component, so it is not displayed
921             index = i * DRAW_STEP + 1;
922             tmpPower = 0;
923             for (j = 0; j < DRAW_STEP; j++)
924             {
925                 tmpPower += power[index];
926                 index++;
927             }
928             SDK_ASSERT(index <= sizeof(power)/sizeof(power[0]));
929             tmpPower /= DRAW_STEP /*j*/;
930 
931             // Multiply by a factor suitable to scale the values to be on-screen coordinate values.
932             // Display expands in the vertical direction, so only up to 192 can be displayed
933             gDrawData[i] = (u8)MATH_MIN(tmpPower, 191);
934         }
935 
936         break;
937 
938     case DRAWMODE_BAR:
939         // Bar display
940 
941         for (i = 0; i < DRAW_MAX; i += blockCount)
942         {
943             s32     j, index;
944             fx32    tmpPower;
945 
946             // Reason for adding 1: The data in power[0] is the DC component, so it is not displayed
947             index = i * DRAW_STEP + 1;
948             tmpPower = 0;
949             for (j = 0; j < blockCount * DRAW_STEP && index < sizeof(smoothedPower)/sizeof(smoothedPower[0]); j++)
950             {
951                 tmpPower += smoothedPower[index];
952                 index++;
953             }
954             tmpPower /= j;
955 
956             // Multiply by a factor suitable to scale the values to be on-screen coordinate values.
957             // Display expands in the vertical direction, so only up to 192 can be displayed
958             gDrawData[i] = (u8)MATH_MIN(tmpPower/8, 191);
959         }
960         break;
961 
962     case DRAWMODE_SCALE:
963         // Musical scale display
964 
965         for (i = 0; i < 12; i ++)
966         {
967             s32     j;
968 
969             for (j = 0; j < SCALE_SAMPLING_OCTAVES ; j++)
970             {
971                 u32 k;
972                 fx32 maxPower;
973 
974                 // Maximum value in each musical scale's frequency band
975                 maxPower = 0;
976                 for (k = scaleSamplingPoints[i][j][0]; k < scaleSamplingPoints[i][j][1]; k++)
977                 {
978                     fx32 tmpPower;
979                     // Take the sum of adjacent values to handle any peaks that may occur between frequencies
980                     // scaleSamplingPoints has been configured in such a way that k+1 will not overflow [1, FFT_N/2-1]
981                     tmpPower = smoothedPower[k] + smoothedPower[k+1];
982                     if ( maxPower < tmpPower )
983                     {
984                         maxPower = tmpPower;
985                     }
986                 }
987 
988                 // Multiply by a factor suitable to scale the values to be on-screen coordinate values.
989                 // Display expands in the vertical direction, so only up to 192 can be displayed
990                 gDrawData[i * SCALE_SAMPLING_OCTAVES + j] = (u8)MATH_MIN(maxPower/16, 191);
991             }
992         }
993     }
994 }
995 
996 /*---------------------------------------------------------------------------*
997   Name:         PrintfVariableData
998 
999   Description:  Print-output the variable sampling settings.
1000 
1001   Arguments:    None.
1002 
1003   Returns:      None.
1004  *---------------------------------------------------------------------------*/
PrintfVariableData(void)1005 static void PrintfVariableData(void)
1006 {
1007     s32     range = 0;
1008 
1009     OS_Printf(" sampling-span: %d , bit-range: ", gMicAutoParam.rate);
1010     switch (gMicAutoParam.type)
1011     {
1012     case MIC_SAMPLING_TYPE_8BIT:
1013         OS_Printf("8");
1014         break;
1015     case MIC_SAMPLING_TYPE_12BIT:
1016         OS_Printf("12");
1017         break;
1018     case MIC_SAMPLING_TYPE_SIGNED_8BIT:
1019         OS_Printf("signed 8");
1020         break;
1021     case MIC_SAMPLING_TYPE_SIGNED_12BIT:
1022         OS_Printf("signed 12");
1023         break;
1024     case MIC_SAMPLING_TYPE_12BIT_FILTER_OFF:
1025         OS_Printf("12(filter off)");
1026         break;
1027     case MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF:
1028         OS_Printf("signed 12(filter off)");
1029         break;
1030     }
1031     if (gMicAutoParam.loop_enable)
1032     {
1033         OS_Printf(" , loop: on\n");
1034     }
1035     else
1036     {
1037         OS_Printf(" , loop: off\n");
1038     }
1039 }
1040 
1041 
1042 /*---------------------------------------------------------------------------*
1043   Name:         Play
1044 
1045   Description:  Plays streaming playback.
1046 
1047   Arguments:    strm:   Stream object
1048                 filename:   Name of the streaming playback file
1049 
1050   Returns:      None.
1051  *---------------------------------------------------------------------------*/
Play(StreamInfo * strm)1052 static void Play(StreamInfo * strm)
1053 {
1054     s32     timerValue;
1055     u32     alarmPeriod;
1056 
1057     osc.index = 0;
1058 
1059     /* Set parameters */
1060     timerValue = SND_TIMER_CLOCK / STRM_SAMPLE_RATE;
1061     alarmPeriod = timerValue * (STRM_BUF_PAGESIZE / sizeof(s16)) / 32;
1062 
1063     // Read initial stream data
1064     strm->bufPage = 0;
1065     MakeStreamData(strm);
1066     MakeStreamData(strm);
1067 
1068     // Set up the channel and alarm
1069     SND_SetupChannelPcm(CHANNEL_NUM,
1070                         SND_WAVE_FORMAT_PCM16,
1071                         strmBuf,
1072                         SND_CHANNEL_LOOP_REPEAT,
1073                         0,
1074                         STRM_BUF_SIZE / sizeof(u32),
1075                         127, SND_CHANNEL_DATASHIFT_NONE, timerValue, 0);
1076     SND_SetupAlarm(ALARM_NUM, alarmPeriod, alarmPeriod, SoundAlarmHandler, strm);
1077     SND_StartTimer(1 << CHANNEL_NUM, 0, 1 << ALARM_NUM, 0);
1078 }
1079 
1080 /*---------------------------------------------------------------------------*
1081   Name:         StopStream
1082 
1083   Description:  Stops streaming playback.
1084 
1085   Arguments:    strm:   Stream object
1086 
1087   Returns:      None.
1088  *---------------------------------------------------------------------------*/
Stop()1089 static void Stop()
1090 {
1091     SND_StopTimer(1 << CHANNEL_NUM, 0, 1 << ALARM_NUM, 0);
1092 }
1093 
1094 /*---------------------------------------------------------------------------*
1095   Name:         StrmThread
1096 
1097   Description:  The stream thread.
1098 
1099   Arguments:    arg - user data (unused)
1100 
1101   Returns:      None.
1102  *---------------------------------------------------------------------------*/
StrmThread(void * arg)1103 static void StrmThread(void * arg)
1104 {
1105 #pragma unused(arg)
1106     OSMessage message;
1107 
1108     OS_InitMessageQueue(&msgQ, msgBuf, 1);
1109 
1110     while (1)
1111     {
1112         (void)OS_ReceiveMessage(&msgQ, &message, OS_MESSAGE_BLOCK);
1113         (void)MakeStreamData((StreamInfo *) message);
1114     }
1115 }
1116 
1117 /*---------------------------------------------------------------------------*
1118   Name:         SoundAlarmHandler
1119 
1120   Description:  alarm callback function
1121 
1122   Arguments:    arg - stream object
1123 
1124   Returns:      None.
1125  *---------------------------------------------------------------------------*/
SoundAlarmHandler(void * arg)1126 static void SoundAlarmHandler(void *arg)
1127 {
1128     (void)OS_SendMessage(&msgQ, (OSMessage)arg, OS_MESSAGE_NOBLOCK);
1129 }
1130 
1131 /*---------------------------------------------------------------------------*
1132   Name:         MakeStreamData
1133 
1134   Description:  Generates stream data.
1135 
1136   Arguments:    strm:   Stream object
1137 
1138   Returns:      None.
1139  *---------------------------------------------------------------------------*/
MakeStreamData(StreamInfo * strm)1140 static void MakeStreamData(StreamInfo * strm)
1141 {
1142     u8     *buf;
1143     int     i;
1144 
1145     // Buffer page settings
1146     if (strm->bufPage == 0)
1147     {
1148         buf = strmBuf;
1149         strm->bufPage = 1;
1150     }
1151     else
1152     {
1153         buf = strmBuf + STRM_BUF_PAGESIZE;
1154         strm->bufPage = 0;
1155     }
1156 
1157     // Generates data
1158     for (i = 0; i < STRM_BUF_PAGESIZE / sizeof(s16); i++)
1159     {
1160         ((s16 *)buf)[i] = (s16)FX_Whole(FX_Mul32x64c(osc.gain << FX32_SHIFT,
1161                                                      FX_SinFx64c(FX_Mul32x64c(osc.index,
1162                                                                               FX64C_TWOPI))));
1163         osc.index += osc.step;
1164         osc.index &= FX32_DEC_MASK;
1165     }
1166 }
1167 
1168 /*---------------------------------------------------------------------------*
1169   Name:         TpRead
1170 
1171   Description:  Reads the touch panel.
1172 
1173   Arguments:    None.
1174 
1175   Returns:      None.
1176  *---------------------------------------------------------------------------*/
TpRead(TpInformation * tp)1177 void TpRead(TpInformation* tp)
1178 {
1179     TPData  tp_data;
1180     TPData  tp_raw;
1181     int     old;
1182 
1183     old = tp->touch;
1184     while (TP_RequestRawSampling(&tp_raw) != 0)
1185     {
1186     };
1187     TP_GetCalibratedPoint(&tp_data, &tp_raw);
1188 
1189     tp->touch = tp_data.touch;
1190     tp->trg = tp->touch & (tp->touch ^ old);
1191     tp->rls = old & (old ^ tp->touch);
1192 
1193     switch (tp_data.validity)
1194     {
1195     case TP_VALIDITY_VALID:
1196         tp->x = tp_data.x;
1197         tp->y = tp_data.y;
1198         break;
1199     case TP_VALIDITY_INVALID_X:
1200         tp->y = tp_data.y;
1201         break;
1202     case TP_VALIDITY_INVALID_Y:
1203         tp->x = tp_data.x;
1204         break;
1205     case TP_VALIDITY_INVALID_XY:
1206         break;
1207     default:
1208         break;
1209     }
1210 }
1211 
1212 /*---------------------------------------------------------------------------*
1213   End of file
1214  *---------------------------------------------------------------------------*/
1215