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