1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WM - demos - wmPadRead-child
3 File: main.c
4
5 Copyright 2007-2009 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-08-31#$
14 $Rev: 11030 $
15 $Author: tominaga_masafumi $
16 *---------------------------------------------------------------------------*/
17
18 //
19 // This is the child program distributed by the mpdldemo/mpdlntr2rvl demo included with RevoEX, a development kit for the Wii's wireless features.
20 //
21 // It communicates with the Wii and sends button input.
22 //
23
24 /*
25 * This demo uses the WH library for wireless communications, but does not perform wireless shutdown processing.
26 *
27 * For details on WH library wireless shutdown processing, see the comments at the top of the WH library source code or the wm/dataShare-Model demo.
28 *
29 *
30 */
31
32 #ifdef SDK_TWL
33 #include <twl.h>
34 #else
35 #include <nitro.h>
36 #endif
37
38 #include <nitro/wm.h>
39 #include "data.h"
40 #include "wh.h"
41
42 #include "tpdata.h"
43
44 /*---------------------------------------------------------------------------*
45 Constant definitions
46 *---------------------------------------------------------------------------*/
47 #define PICTURE_FRAME_PER_GAME_FRAME 1
48
49 /* The GGID used in this demo */
50 #define MY_GGID SDK_MAKEGGID_SYSTEM(0x20)
51
52 #define DMA_NO 3
53
54 #define SAMPLING_BUFFER_SIZE ( 1024 * 1024 ) // 1M
55
56 #define FFT_NSHIFT 9
57 #define FFT_N (1 << FFT_NSHIFT)
58
59 /*---------------------------------------------------------------------------*
60 Variable Definitions
61 *---------------------------------------------------------------------------*/
62
63 static WMBssDesc mbParentBssDesc ATTRIBUTE_ALIGN(32);
64 static BOOL isMultiBooted;
65
66 static GXOamAttr oamBak[128];
67
68 typedef struct MyPadData {
69 u16 keyData;
70 u8 touchPanel_x;
71 u8 touchPanel_y;
72 u8 mic;
73 u8 touch;
74 u8 padding[2];
75 } MyPadData;
76
77 // Send/receive buffer for display
78 static MyPadData gRecvData[1 + WH_CHILD_MAX]; // Touch information for all players, delivered by the parent
79 static BOOL gRecvFlag[1 + WH_CHILD_MAX];
80
81 u16 keyData;
82
83 static GXOamAttr gOam[128];
84
85 TPData raw_point;
86 TPData disp_point;
87 TPCalibrateParam calibrate;
88
89 static BOOL input_mic;
90 static MICAutoParam gMicAutoParam;
91 static u8 *gMicData;
92
93
94 // FFT buffers
95 static fx16 sinTable[FFT_N - FFT_N / 4];
96 #ifdef USE_FFTREAL
97 static fx16 sinTable2[(FFT_N - FFT_N / 4) / 2];
98 static fx32 data[FFT_N];
99 #else
100 static fx32 data[FFT_N * 2];
101 #endif
102 static s32 power[FFT_N/2+1];
103 static s32 smoothedPower[FFT_N/2+1];
104
105 /*---------------------------------------------------------------------------*
106 Function Declarations
107 *---------------------------------------------------------------------------*/
108 static void InitializeAllocateSystem(void);
109 static void SetPoint16x16(int objNo, u16 pos_x, u16 pos_y, int charNo, int paletteNo);
110 static void Initialize(void);
111 static BOOL DoConnect(void);
112 static void DoPadSharing(void);
113 static BOOL CheckMicData(void *address);
114 static void ObjSet(int objNo, int x, int y, int charNo, int paletteNo);
115 static void VBlankIntr(void);
116
117
118 //================================================================================
119 /*---------------------------------------------------------------------------*
120 Name: NitroMain / TwlMain
121
122 Description: Main
123
124 Arguments: None.
125
126 Returns: None.
127 *---------------------------------------------------------------------------*/
128 #ifdef SDK_TWL
TwlMain()129 void TwlMain()
130 #else
131 void NitroMain()
132 #endif
133 {
134 Initialize();
135
136 // Initialize shared data
137 MI_CpuClear8( gRecvData, sizeof(gRecvData) );
138
139 // The local host checks to see if it is a child started from multiboot.
140 isMultiBooted = MB_IsMultiBootChild();
141
142 if (isMultiBooted)
143 {
144 //--------------------------------------------------------------
145 // If it was started from multi-boot, it will be reset once, and communication will be disconnected.
146 // The child maintains the BssDesc of the parent that booted it. Use this information to reconnect to the parent.
147 //
148 // There is no particular problem with extracting the MAC address from BssDesc, then specifying that MAC address and scanning for and connecting to that parent. However, to connect to the parent directly using the stored BssDesc, it is necessary to set the parent's and child's communications size and transfer mode to match ahead of time.
149 //
150 //
151 //
152 //--------------------------------------------------------------
153
154 /*
155 * Gets parent data for reconnecting to the parent.
156 * The WMBssDesc used for the connection must be 32-byte aligned.
157 * When reconnecting without using the parent's MAC address to rescan, make the KS/CS flags and the maximum send size match in advance for the parent and the child.
158 *
159 * All of these values may be 0 if you rescan before connecting.
160 */
161 MB_ReadMultiBootParentBssDesc(&mbParentBssDesc,
162 WH_PARENT_MAX_SIZE, // Maximum parent send size
163 WH_CHILD_MAX_SIZE, // Maximum child send size
164 0, // Reserved region (always 0)
165 0); // Reserved region (always 0)
166 }
167
168 while (TRUE)
169 {
170 int connectedFlag = FALSE;
171
172 // Initialize wireless
173 if (!WH_Initialize())
174 {
175 OS_Panic("WH_Initialize failed.");
176 }
177
178 connectedFlag = DoConnect();
179 // At this point the transition to the child state is complete
180
181 if (connectedFlag)
182 {
183 DoPadSharing();
184 // Control does not return here until exiting from communication mode
185 }
186
187 WH_Finalize();
188 }
189 }
190
Initialize(void)191 void Initialize(void)
192 {
193 //================ Initialization
194 //---- OS Initialization
195 OS_Init();
196
197 //---- TP Initialization
198 TP_Init();
199
200 // Get CalibrateParameter from FlashMemory
201 if (!TP_GetUserInfo(&calibrate))
202 {
203 OS_Panic("FATAL ERROR: can't read UserOwnerInfo\n");
204 }
205 else
206 {
207 OS_Printf("Get Calibration Parameter from NVRAM\n");
208 }
209
210 TP_SetCalibrateParam(&calibrate);
211
212 //---- GX Initialization
213 GX_Init();
214
215 //================ Initial settings
216 //---- All Power ON
217 GX_SetPower(GX_POWER_ALL);
218
219 //---- Enable V-Blank interrupt
220 (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
221 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
222 (void)OS_EnableIrq();
223
224 //---- V-Blank occurrence settings
225 (void)GX_VBlankIntr(TRUE);
226
227 //---- Clear VRAM
228 GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
229 MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
230 (void)GX_DisableBankForLCDC();
231
232 //---- OAM and palette clear
233 MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
234 MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
235
236 MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
237 MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
238
239 //---- Set bank A for OBJ
240 GX_SetBankForOBJ(GX_VRAM_OBJ_128_A);
241
242 GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_128_D);
243
244 //---- Set to graphics display mode
245 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
246
247 //---- Set only OBJ display ON
248 GX_SetVisiblePlane(GX_PLANEMASK_OBJ);
249
250 //---- Used with 32-KB OBJ in 2D mapping mode
251 GX_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_2D);
252
253 //---- Data load
254 GX_LoadOBJ( sampleCharData, 0, sizeof(sampleCharData) );
255 GX_LoadOBJPltt( samplePlttData, 0, sizeof(samplePlttData) );
256
257 GXS_SetGraphicsMode(GX_BGMODE_0); // BGMODE 0
258
259 GXS_SetVisiblePlane(GX_PLANEMASK_OBJ); // Make OBJ visible
260 GXS_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K); // 2D mapping OBJ
261
262 /* Load character bitmap data */
263 GXS_LoadOBJ( sampleCharData, 0, sizeof(sampleCharData) );
264 GXS_LoadOBJPltt( samplePlttData, 0, sizeof(samplePlttData) );
265
266 //---- Move hidden OBJ off screen
267 MI_DmaFill32(DMA_NO, oamBak, 0xc0, sizeof(oamBak));
268
269 //================ Miscellaneous initialization
270
271 /////////////////////
272 // Memory allocation
273 InitializeAllocateSystem();
274
275 /////////////////////
276 // Microphone-related initialization
277
278 //---- MIC Initialization
279 MIC_Init();
280
281 //---- PMIC Initialization
282 PM_Init();
283 // AMP on
284 (void)PM_SetAmp(PM_AMP_ON);
285 // Adjust AMP gain
286 (void)PM_SetAmpGain(PM_AMPGAIN_80);
287
288 // Auto sampling settings
289 // Because the memory allocated with OS_Alloc is 32-byte aligned, other memory is not destroyed even if the cache is manipulated
290 //
291 gMicData = (u8 *)OS_Alloc(SAMPLING_BUFFER_SIZE);
292 // Perform 12-bit sampling to increase the accuracy of Fourier transforms
293 gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT;
294 gMicAutoParam.buffer = (void *)gMicData;
295 gMicAutoParam.size = SAMPLING_BUFFER_SIZE;
296 gMicAutoParam.loop_enable = TRUE;
297 gMicAutoParam.full_callback = NULL;
298 #ifdef SDK_TWL
299 gMicAutoParam.rate = MIC_SAMPLING_RATE_8180;
300 (void)MIC_StartLimitedSampling(&gMicAutoParam);
301 #else // ifdef SDK_TWL
302 gMicAutoParam.rate = MIC_SAMPLING_RATE_8K;
303 (void)MIC_StartAutoSampling(&gMicAutoParam);
304 #endif // ifdef SDK_TWL else
305
306 /////////////////////
307 // FFT-related
308
309 MATH_MakeFFTSinTable(sinTable, FFT_NSHIFT);
310 #ifdef USE_FFTREAL
311 MATH_MakeFFTSinTable(sinTable2, FFT_NSHIFT - 1);
312 #endif
313
314 //Start display
315 OS_WaitVBlankIntr();
316 GX_DispOn();
317
318 GXS_DispOn();
319 }
320
DoConnect(void)321 BOOL DoConnect(void)
322 {
323 s32 retry = 0;
324 enum
325 {
326 MAX_RETRY = 5
327 };
328
329 ObjSet(0, 100, 80, 'C', 4);
330 ObjSet(1, 110, 80, 'O', 4);
331 ObjSet(2, 120, 80, 'N', 4);
332 ObjSet(3, 130, 80, 'N', 4);
333 ObjSet(4, 140, 80, 'E', 4);
334 ObjSet(5, 150, 80, 'C', 4);
335 ObjSet(6, 160, 80, 'T', 4);
336 MI_CpuClear8( (GXOamAttr *)&oamBak[7], sizeof(GXOamAttr) * 12);
337
338 //---- Wait for V-Blank interrupt completion
339 OS_WaitVBlankIntr();
340
341 // If this is multiboot, use the GGID declared by the parent device.
342 // Normally, this should match MY_GGID.
343 WH_SetGgid(isMultiBooted ? mbParentBssDesc.gameInfo.ggid : MY_GGID);
344 retry = 0;
345
346 while (TRUE)
347 {
348 // Distributes processes based on communication status
349 switch (WH_GetSystemState())
350 {
351 case WH_SYSSTATE_CONNECT_FAIL:
352 {
353 // Because the internal WM state is invalid if the WM_StartConnect function fails, WM_Reset must be called once to reset the state to IDLE
354 //
355 WH_Reset();
356 }
357 break;
358 case WH_SYSSTATE_IDLE:
359 {
360 if (retry < MAX_RETRY)
361 {
362 // Scan for a parent device and connect.
363 // When the local device was multibooted, use the parent device BSSID it remembers and connect only to the parent device that was the multiboot source.
364 //
365 (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, isMultiBooted ? mbParentBssDesc.bssid : NULL, 0);
366 retry++;
367 break;
368 }
369 // If connection to parent is not possible after MAX_RETRY, display ERROR
370 }
371 case WH_SYSSTATE_ERROR:
372 return FALSE;
373
374 case WH_SYSSTATE_DATASHARING:
375 return TRUE;
376
377 case WH_SYSSTATE_BUSY:
378 case WH_SYSSTATE_SCANNING:
379 case WH_SYSSTATE_CONNECTED:
380 default:
381 break;
382 }
383
384 OS_WaitVBlankIntr();
385 }
386
387 // Can't reach here
388 return FALSE;
389 }
390
DoPadSharing(void)391 void DoPadSharing(void)
392 {
393 int myAid;
394 myAid = WM_GetAID();
395
396 //================ Main loop
397 while (TRUE)
398 {
399 // Draw Marker by calibrated point
400 while (TP_RequestRawSampling(&raw_point) != 0)
401 {
402 };
403 TP_GetCalibratedPoint(&disp_point, &raw_point);
404
405 if (disp_point.touch)
406 {
407 SetPoint16x16(0, disp_point.x, disp_point.y, myAid + '0', 1);
408
409 switch (disp_point.validity)
410 {
411 case TP_VALIDITY_VALID:
412 OS_TPrintf("( %d, %d ) -> ( %d, %d )\n", raw_point.x, raw_point.y, disp_point.x,
413 disp_point.y);
414 break;
415 case TP_VALIDITY_INVALID_X:
416 OS_TPrintf("( *%d, %d ) -> ( *%d, %d )\n", raw_point.x, raw_point.y, disp_point.x,
417 disp_point.y);
418 break;
419 case TP_VALIDITY_INVALID_Y:
420 OS_TPrintf("( %d, *%d ) -> ( %d, *%d )\n", raw_point.x, raw_point.y, disp_point.x,
421 disp_point.y);
422 break;
423 case TP_VALIDITY_INVALID_XY:
424 OS_TPrintf("( *%d, *%d ) -> ( *%d, *%d )\n", raw_point.x, raw_point.y, disp_point.x,
425 disp_point.y);
426 break;
427 }
428 }
429 //---- Wait for V-Blank interrupt completion
430 OS_WaitVBlankIntr();
431
432 //---- Load pad data
433 keyData = PAD_Read();
434
435 {
436 static MyPadData sendData ATTRIBUTE_ALIGN(32);
437 int i;
438
439 // Prepare data to send
440 MI_CpuClear8(&sendData, sizeof(sendData));
441 sendData.keyData = (u16)(keyData | (PAD_DetectFold() ? PAD_DETECT_FOLD_MASK : 0));
442 sendData.touch = (u8)disp_point.touch;
443 sendData.touchPanel_x = (u8)disp_point.x;
444 sendData.touchPanel_y = (u8)disp_point.y;
445 sendData.mic = (u8)input_mic;
446
447 if ( WH_StepDS((void*)&sendData) )
448 {
449 for (i = 0; i < (1 + WH_CHILD_MAX); i++)
450 {
451 u8* data;
452
453 data = (u8 *)WH_GetSharedDataAdr((u16)i);
454
455 if (data != NULL)
456 {
457 gRecvFlag[i] = TRUE;
458 MI_CpuCopy8(data, &gRecvData[i], sizeof(gRecvData[0]));
459 }
460 else
461 {
462 gRecvFlag[i] = FALSE;
463 }
464 }
465 }
466 }
467
468 //---- Display pad information as OBJ
469 ObjSet(0, 200, 90, 'A', (keyData & PAD_BUTTON_A) ? 1 : 2);
470 ObjSet(1, 180, 95, 'B', (keyData & PAD_BUTTON_B) ? 1 : 2);
471
472 ObjSet(2, 60, 50, 'L', (keyData & PAD_BUTTON_L) ? 1 : 2);
473 ObjSet(3, 180, 50, 'R', (keyData & PAD_BUTTON_R) ? 1 : 2);
474
475 ObjSet(4, 60, 80, 'U', (keyData & PAD_KEY_UP) ? 1 : 2);
476 ObjSet(5, 60, 100, 'D', (keyData & PAD_KEY_DOWN) ? 1 : 2);
477 ObjSet(6, 50, 90, 'L', (keyData & PAD_KEY_LEFT) ? 1 : 2);
478 ObjSet(7, 70, 90, 'R', (keyData & PAD_KEY_RIGHT) ? 1 : 2);
479
480 ObjSet(8, 130, 95, 'S', (keyData & PAD_BUTTON_START) ? 1 : 2);
481 ObjSet(9, 110, 95, 'S', (keyData & PAD_BUTTON_SELECT) ? 1 : 2);
482
483 ObjSet(10, 200, 75, 'X', (keyData & PAD_BUTTON_X) ? 1 : 2);
484 ObjSet(11, 180, 80, 'Y', (keyData & PAD_BUTTON_Y) ? 1 : 2);
485
486 //---- Display Folding Detect Status with OBJ
487 ObjSet(12, 120, 30, 'F', (PAD_DetectFold())? 1 : 2);
488
489 ObjSet(13, 100, 5, 'A', 4);
490 ObjSet(14, 110, 5, 'I', 4);
491 ObjSet(15, 120, 5, 'D', 4);
492 ObjSet(16, 130, 5, (myAid / 10) ? (myAid / 10) + '0' : ' ', 4);
493 ObjSet(17, 140, 5, (myAid % 10) + '0', 4);
494
495 // Microphone input check
496 input_mic = CheckMicData(MIC_GetLastSamplingAddress());
497 ObjSet(18, 120, 120, 'M', input_mic ? 1 : 2);
498
499 if( WH_GetSystemState() != WH_SYSSTATE_DATASHARING )
500 {
501 break;
502 }
503
504 // Render all players' touch information from the received information
505 {
506 int i;
507
508 for(i = 0; i < WH_CHILD_MAX + 1; i++)
509 {
510 if( i != myAid && gRecvData[i].touch )
511 {
512 SetPoint16x16(i+1, gRecvData[i].touchPanel_x, gRecvData[i].touchPanel_y, '0'+i, 2);
513 }
514 }
515 }
516 }
517 }
518
519 //--------------------------------------------------------------------------------
520 // Set OBJ
521 //
ObjSet(int objNo,int x,int y,int charNo,int paletteNo)522 void ObjSet(int objNo, int x, int y, int charNo, int paletteNo)
523 {
524 G2_SetOBJAttr((GXOamAttr *)&oamBak[objNo],
525 x,
526 y,
527 0,
528 GX_OAM_MODE_NORMAL,
529 FALSE,
530 GX_OAM_EFFECT_NONE, GX_OAM_SHAPE_8x8, GX_OAM_COLOR_16, charNo, paletteNo, 0);
531 }
532
533
534 //--------------------------------------------------------------------------------
535 // V-Blank interrupt process
536 //
VBlankIntr(void)537 void VBlankIntr(void)
538 {
539 //---- OAM updating
540 DC_FlushRange(oamBak, sizeof(oamBak));
541 /* I/O register is accessed using DMA operation, so cache wait is not needed */
542 // DC_WaitWriteBufferEmpty();
543 MI_DmaCopy32(DMA_NO, oamBak, (void *)HW_OAM, sizeof(oamBak));
544
545 /* Flush cache of OAM buffers to main memory */
546 DC_FlushRange(gOam, sizeof(gOam));
547 /* I/O register is accessed using DMA operation, so cache wait is not needed */
548 // DC_WaitWriteBufferEmpty();
549 GXS_LoadOAM(gOam, 0, sizeof(gOam));
550 MI_DmaFill32(3, gOam, 192, sizeof(gOam)); // Clear OAM buffer
551
552 //---- Interrupt check flag
553 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
554 }
555
556 /*---------------------------------------------------------------------------*
557 Name: InitializeAllocateSystem
558
559 Description: Initializes the memory allocation system within the main memory arena.
560
561 Arguments: None.
562
563 Returns: None.
564 *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)565 static void InitializeAllocateSystem(void)
566 {
567 void *tempLo;
568 OSHeapHandle hh;
569
570 // Based on the premise that OS_Init has been already called
571 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
572 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
573 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
574 if (hh < 0)
575 {
576 OS_Panic("ARM9: Fail to create heap...\n");
577 }
578 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
579 }
580
581 /*---------------------------------------------------------------------------*
582 Name: SetPoint16x16
583
584 Description: Displays a 16x16 OBJ at indicated point.
585
586 Arguments: x: Position X
587 y: Position Y
588
589 Returns: None.
590 *---------------------------------------------------------------------------*/
SetPoint16x16(int objNo,u16 pos_x,u16 pos_y,int charNo,int paletteNo)591 static void SetPoint16x16(int objNo, u16 pos_x, u16 pos_y, int charNo, int paletteNo)
592 {
593 G2_SetOBJAttr((GXOamAttr *)&gOam[objNo],
594 pos_x - 8,
595 pos_y - 8,
596 0,
597 GX_OAM_MODE_NORMAL,
598 FALSE,
599 GX_OAM_EFFECT_NONE, GX_OAM_SHAPE_8x8, GX_OAM_COLOR_16, charNo, paletteNo, 0);
600 }
601
602 /*---------------------------------------------------------------------------*
603 Name: CheckMicData
604
605 Arguments: address: Mic sampling data
606
607 Returns: Whether mic input exists.
608 *---------------------------------------------------------------------------*/
CheckMicData(void * address)609 static BOOL CheckMicData(void *address)
610 {
611 s32 i;
612
613 u16 *p;
614
615 // If sampling has never been performed, do nothing and stop.
616 // (Because it would delete memory cache(s) unrelated to the microphone)
617 if ((address < gMicData) || (address >= (gMicData + SAMPLING_BUFFER_SIZE)))
618 {
619 return FALSE;
620 }
621
622 // Apply a FFT for the FFT_N most recent sampling values
623 // With 12-bit sampling, each value is two bytes
624 p = (u16 *)((u32)address - (FFT_N-1)*2);
625 if ((u32)p < (u32)gMicData)
626 {
627 p = (u16 *)((u32)p + SAMPLING_BUFFER_SIZE);
628 }
629 DC_InvalidateRange((void *)((u32)p & 0xffffffe0), 32);
630 for (i = 0; i < FFT_N; i++)
631 {
632 #ifdef USE_FFTREAL
633 data[i] = ((*p) << (FX32_SHIFT - (16 - 12)));
634 #else
635 data[i * 2] = ((*p) << (FX32_SHIFT - (16 - 12)));
636 data[i * 2 + 1] = 0; // Substitute 0 in the imaginary part
637 #endif
638 p++;
639 if ((u32)p >= (u32)(gMicData + SAMPLING_BUFFER_SIZE))
640 {
641 p = (u16 *)((u32)p - SAMPLING_BUFFER_SIZE);
642 }
643 if (((u32)p % 32) == 0)
644 {
645 DC_InvalidateRange(p, 32);
646 }
647 }
648
649 #ifdef USE_FFTREAL
650 MATH_FFTReal(data, FFT_NSHIFT, sinTable, sinTable2);
651 #else
652 MATH_FFT(data, FFT_NSHIFT, sinTable);
653 #endif
654
655 // Do not calculate above FFT_N/2, because only conjugated, inverted values of FFT_N/2 and below will be yielded
656 for (i = 0; i <= FFT_N/2; i++)
657 {
658 fx32 real;
659 fx32 imm;
660
661 #ifdef USE_FFTREAL
662 if (0 < i && i < FFT_N/2)
663 {
664 real = data[i * 2];
665 imm = data[i * 2 + 1];
666 }
667 else
668 {
669 if (i == 0)
670 {
671 real = data[0];
672 }
673 else // i == FFT_N/2
674 {
675 real = data[1];
676 }
677 imm = 0;
678 }
679 #else
680 real = data[i * 2];
681 imm = data[i * 2 + 1];
682 #endif
683
684 // Calculate the power of each frequency
685 // If only the relative value size is necessary, omitting the sqrt can result in a speed increase
686 power[i] = FX_Whole(FX_Sqrt(FX_MUL(real, real) + FX_MUL(imm, imm)));
687
688 // Record the accumulated time values for the power of each frequency
689 // Perform damping a little at a time
690 smoothedPower[i] += power[i] - (smoothedPower[i]/8);
691 }
692
693 // Microphone input check
694 {
695 s32 totalPower = 0;
696
697 #define FILTER_LOW 12 // ((8000 Hz/2)/(FFT_N/2)) * 12 = 187.5 Hz
698 #define FILTER_HIGH 64 // ((8000 Hz/2)/(FFT_N/2)) * 64 = 1000.5 Hz
699 for (i = FILTER_LOW; i < FILTER_HIGH; i++)
700 {
701 totalPower += smoothedPower[i];
702 }
703 //OS_TPrintf("totalPower = %d, ave = %d\n", totalPower, totalPower/(FILTER_HIGH-FILTER_LOW));
704 // Check whether the input value is above a fixed amount
705 if (totalPower > (FILTER_HIGH-FILTER_LOW)*64)
706 {
707 return TRUE;
708 }
709 }
710 return FALSE;
711 }
712
713 /*====== End of main.c ======*/
714