/*---------------------------------------------------------------------------* Project: TwlSDK - demos.TWL - spi - mic-4 File: main.c Copyright 2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-11#$ $Rev: 8401 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* This sample controls microphone sampling, and outputs sampling data. USAGE: UP, DOWN: Control sampling span. LEFT, RIGHT: Control sampling bit range. ( 8bit or 12 bit etc. ) A: start / stop sampling. (toggle) B: force-stop. (stop and ignore rest data) SELECT: Terminate program. HOWTO: 1. Initialize MIC library and SNDEX library. 2. When sampling is stopped, you can change parameters and start automatic microphone sampling. Debug-output is sampling data for tool "mic2wav.exe". 3. Debug-output log can make its waveform files by tool "mic2wav.exe". > $(TWLSDK_ROOT)/tools/bin/mic2wav.exe [logfile] [,directory] Each set of sampling data (separated by A-Button) creates a waveform file in "[directory]/%08X.wav". NOTE: 1. The speed of debug-output is later than sampling. When you stop sampling, then please wait all data is printed. *---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------* Constant Definitions *---------------------------------------------------------------------------*/ #define TEST_BUFFER_SIZE (1024 * 1024) // 1 Mbyte #define RETRY_MAX_COUNT 8 /*---------------------------------------------------------------------------* Internal Function Definitions *---------------------------------------------------------------------------*/ static void StartSampling(const MICAutoParam* param); static void StopSampling(void); static SNDEXFrequency GetI2SFrequency(void); static void SetI2SFrequency(SNDEXFrequency freq); static void SwitchI2SFrequency(void); static void StepUpSamplingRate(void); static void StepDownSamplingRate(void); static void OnSamplingDone(MICResult result, void* arg); static void OutputSampleWave(void* dat, MICSamplingType type); static void StartSamplingOutput(void); static void StopSamplingOutput(void); static void SetDrawData(void *address, MICSamplingType type); static void VBlankIntr(void); static void Init3D(void); static void Draw3D(void); static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey); /*---------------------------------------------------------------------------* Internal Variable Definitions *---------------------------------------------------------------------------*/ static MICAutoParam gMicAutoParam; static u8 gDrawData[192]; static u8 gMicData[TEST_BUFFER_SIZE] ATTRIBUTE_ALIGN(HW_CACHE_LINE_SIZE); static volatile BOOL g_sample_busy = FALSE; static void* g_record_smps = NULL; /*---------------------------------------------------------------------------* Name: TwlMain Description: Initialization and main loop. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void TwlMain(void) { /* Various types of initialization */ OS_Init(); FX_Init(); GX_Init(); GX_DispOff(); GXS_DispOff(); /* Initializes display settings */ GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); (void)GX_DisableBankForLCDC(); MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE); MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE); MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE); MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE); /* 3D-related initialization */ Init3D(); /* Interrupt settings */ OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr); (void)OS_EnableIrqMask(OS_IE_V_BLANK); (void)OS_EnableIrq(); (void)OS_EnableInterrupts(); (void)GX_VBlankIntr(TRUE); /* Initialize related libraries*/ { (void)PM_SetAmp(PM_AMP_ON); SNDEX_Init(); MIC_Init(); gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT; gMicAutoParam.buffer = (void *)gMicData; gMicAutoParam.size = TEST_BUFFER_SIZE; if ((OS_IsRunOnTwl() == TRUE) && (GetI2SFrequency() == SNDEX_FREQUENCY_47610)) { gMicAutoParam.rate = MIC_SAMPLING_RATE_23810; } else { gMicAutoParam.rate = MIC_SAMPLING_RATE_16360; } gMicAutoParam.loop_enable = FALSE; gMicAutoParam.full_callback = OnSamplingDone; } /* Initialize internal variables */ MI_CpuFill8(gDrawData, 0x80, sizeof(gDrawData)); /* LCD display start */ GX_DispOn(); GXS_DispOn(); /* Debug string output */ OS_Printf("# mic-4 demo started.\n"); OS_Printf("# up/down -> change sampling rate\n"); OS_Printf("# left/right -> change bit range\n"); OS_Printf("# A -> start / stop\n"); OS_Printf("# B -> force-stop\n"); OS_Printf("# select -> terminate\n"); /* Empty call for getting key input data (strategy for pressing A Button in the IPL) */ (void)PAD_Read(); { u16 keyOld = 0; u16 keyTrg; u16 keyNow; /* Main loop */ while (TRUE) { /* Get key input data */ keyNow = PAD_Read(); keyTrg = (u16)((keyOld ^ keyNow) & keyNow); keyOld = keyNow; /* Start/stop sampling with the A Button*/ if (keyTrg & PAD_BUTTON_A) { if (!g_sample_busy) { g_sample_busy = TRUE; g_record_smps = gMicData; StartSamplingOutput(); StartSampling(&gMicAutoParam); } else { StopSampling(); OnSamplingDone(MIC_RESULT_SUCCESS, NULL); } } /* B Button stops sampling, ignores remaining data*/ if (keyTrg & PAD_BUTTON_B) { if (g_sample_busy) { StopSampling(); OnSamplingDone(MIC_RESULT_SUCCESS, NULL); } if (g_record_smps) { StopSamplingOutput(); } } /* SELECT Button forcibly quits the program*/ if (keyTrg & PAD_BUTTON_SELECT) { OS_Exit(0); } /* Change variable parameters */ if (!g_record_smps) { /* Change sampling type (bit width) */ if (keyTrg & (PAD_KEY_LEFT | PAD_KEY_RIGHT)) { if (gMicAutoParam.type == MIC_SAMPLING_TYPE_8BIT) { gMicAutoParam.type = MIC_SAMPLING_TYPE_12BIT; } else { gMicAutoParam.type = MIC_SAMPLING_TYPE_8BIT; } StartSamplingOutput(); } /* Change sampling rate */ if (keyTrg & PAD_KEY_UP) { StepUpSamplingRate(); StartSamplingOutput(); } if (keyTrg & PAD_KEY_DOWN) { StepDownSamplingRate(); StartSamplingOutput(); } } /* Output a log of sampling results*/ OutputSampleWave(MIC_GetLastSamplingAddress(), gMicAutoParam.type); /* Render waveform */ if (g_sample_busy) { SetDrawData(MIC_GetLastSamplingAddress(), gMicAutoParam.type); Draw3D(); } /* Waiting for the V-Blank */ OS_WaitVBlankIntr(); } } } /*---------------------------------------------------------------------------* Name: StartSampling Description: Calls the MIC_StartLimitedSampling function and performs error processing. Arguments: param: Parameter passed to the microphone functions Returns: None. *---------------------------------------------------------------------------*/ static void StartSampling(const MICAutoParam* param) { MICResult result; s32 retry = 0; while (TRUE) { result = MIC_StartLimitedSampling(param); switch (result) { case MIC_RESULT_SUCCESS: // Success return; case MIC_RESULT_BUSY: // Microphone in use by other thread case MIC_RESULT_SEND_ERROR: // PXI queue is full if (++ retry <= RETRY_MAX_COUNT) { OS_Sleep(1); continue; } OS_TWarning("Retry count overflow.\n"); return; case MIC_RESULT_ILLEGAL_STATUS: // Not in an autosampling stopped state OS_TWarning("Already started sampling.\n"); return; case MIC_RESULT_ILLEGAL_PARAMETER: // The specified parameter is not supported OS_TWarning("Illegal parameter to start automatic sampling.\n"); return; default: // Other fatal error OS_Panic("Fatal error (%d).\n", result); /* Never return */ } } } /*---------------------------------------------------------------------------* Name: StopSampling Description: Calls the MIC_StopLimitedSampling function and performs error processing. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void StopSampling(void) { MICResult result; s32 retry = 0; while (TRUE) { result = MIC_StopLimitedSampling(); switch (result) { case MIC_RESULT_SUCCESS: // Success case MIC_RESULT_ILLEGAL_STATUS: // Not in an auto-sampling state. return; case MIC_RESULT_BUSY: // Microphone in use by other thread case MIC_RESULT_SEND_ERROR: // PXI queue is full if (++ retry <= RETRY_MAX_COUNT) { OS_Sleep(1); continue; } OS_TWarning("Retry count overflow.\n"); return; default: // Other fatal error OS_Panic("Fatal error (%d).\n", result); /* Never return */ } } } #include /*---------------------------------------------------------------------------* Name: GetI2SFrequency Description: Gets the I2S operating frequency. Arguments: None. Returns: SDNEXFrequency: Returns the I2S operating frequency. *---------------------------------------------------------------------------*/ static SNDEXFrequency GetI2SFrequency(void) { SNDEXResult result; SNDEXFrequency freq; s32 retry = 0; while (TRUE) { result = SNDEX_GetI2SFrequency(&freq); switch (result) { case SNDEX_RESULT_SUCCESS: // Success return freq; case SNDEX_RESULT_EXCLUSIVE: // Exclusion error case SNDEX_RESULT_PXI_SEND_ERROR: // PXI queue is full if (++ retry <= RETRY_MAX_COUNT) { OS_Sleep(1); continue; } OS_TWarning("Retry count overflow.\n"); break; case SNDEX_RESULT_BEFORE_INIT: // Pre-initialization case SNDEX_RESULT_ILLEGAL_STATE: // Abnormal state OS_TWarning("Illegal state to get I2S frequency.\n"); break; case SNDEX_RESULT_FATAL_ERROR: // Fatal error default: OS_Panic("Fatal error (%d).\n", result); /* Never return */ } } return SNDEX_FREQUENCY_32730; } /*---------------------------------------------------------------------------* Name: SetI2SFrequency Description: Changes the I2S operating frequency. Arguments: freq: I2S operating frequency Returns: None. *---------------------------------------------------------------------------*/ static void SetI2SFrequency(SNDEXFrequency freq) { SNDEXResult result; s32 retry = 0; while (TRUE) { result = SNDEX_SetI2SFrequency(freq); switch (result) { case SNDEX_RESULT_SUCCESS: // Success return; case SNDEX_RESULT_EXCLUSIVE: // Exclusion error case SNDEX_RESULT_PXI_SEND_ERROR: // PXI queue is full if (++ retry <= RETRY_MAX_COUNT) { OS_Sleep(1); continue; } OS_TWarning("Retry count overflow.\n"); return; case SNDEX_RESULT_BEFORE_INIT: // Pre-initialization case SNDEX_RESULT_ILLEGAL_STATE: // Abnormal state OS_TWarning("Illegal state to set I2S frequency.\n"); return; case SNDEX_RESULT_INVALID_PARAM: // Abnormal argument OS_TWarning("Could not set I2S frequency into %d.\n", freq); return; case SNDEX_RESULT_FATAL_ERROR: // Fatal error default: OS_Panic("Fatal error (%d)\n", result); /* Never return */ } } } /*---------------------------------------------------------------------------* Name: SwitchI2SFrequency Description: Changes the I2S operating frequency in conjunction with the microphone sampling frequency. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void SwitchI2SFrequency(void) { SNDEXFrequency freq; freq = GetI2SFrequency(); switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_8180: case MIC_SAMPLING_RATE_10910: case MIC_SAMPLING_RATE_16360: case MIC_SAMPLING_RATE_32730: if (freq != SNDEX_FREQUENCY_32730) { SetI2SFrequency(SNDEX_FREQUENCY_32730); } break; case MIC_SAMPLING_RATE_11900: case MIC_SAMPLING_RATE_15870: case MIC_SAMPLING_RATE_23810: case MIC_SAMPLING_RATE_47610: if (freq != SNDEX_FREQUENCY_47610) { SetI2SFrequency(SNDEX_FREQUENCY_47610); } break; } } #include /*---------------------------------------------------------------------------* Name: StepUpSamplingRate Description: Increases the microphone sampling frequency by one level. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void StepUpSamplingRate(void) { if (OS_IsRunOnTwl() == TRUE) { switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_8180: // 32.73k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_10910; break; case MIC_SAMPLING_RATE_10910: // 32.73k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_11900; break; case MIC_SAMPLING_RATE_11900: // 47.61k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_15870; break; case MIC_SAMPLING_RATE_15870: // 47.61k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_16360; break; case MIC_SAMPLING_RATE_16360: // 32.73k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_23810; break; case MIC_SAMPLING_RATE_23810: // 47.61k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_32730; break; case MIC_SAMPLING_RATE_32730: // 32.73k / 1 gMicAutoParam.rate = MIC_SAMPLING_RATE_47610; break; case MIC_SAMPLING_RATE_47610: // 47.61k / 1 default: /* Do nothing */ return; } SwitchI2SFrequency(); } else { switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_8180: // 32.73k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_10910; break; case MIC_SAMPLING_RATE_10910: // 32.73k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_11900; break; case MIC_SAMPLING_RATE_11900: // 47.61k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_15870; break; case MIC_SAMPLING_RATE_15870: // 47.61k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_16360; break; case MIC_SAMPLING_RATE_16360: // 32.73k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_23810; break; case MIC_SAMPLING_RATE_23810: // 47.61k / 2 default: /* Do nothing */ return; } } } /*---------------------------------------------------------------------------* Name: StepUpSamplingRate Description: Decreases the microphone sampling frequency by one level. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void StepDownSamplingRate(void) { if (OS_IsRunOnTwl() == TRUE) { switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_47610: // 47.61k / 1 gMicAutoParam.rate = MIC_SAMPLING_RATE_32730; break; case MIC_SAMPLING_RATE_32730: // 32.73k / 1 gMicAutoParam.rate = MIC_SAMPLING_RATE_23810; break; case MIC_SAMPLING_RATE_23810: // 47.61k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_16360; break; case MIC_SAMPLING_RATE_16360: // 32.73k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_15870; break; case MIC_SAMPLING_RATE_15870: // 47.61k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_11900; break; case MIC_SAMPLING_RATE_11900: // 47.61k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_10910; break; case MIC_SAMPLING_RATE_10910: // 32.73k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_8180; break; case MIC_SAMPLING_RATE_8180: // 32.73k / 4 default: /* Do nothing */ return; } SwitchI2SFrequency(); } else { switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_23810: // 47.61k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_16360; break; case MIC_SAMPLING_RATE_16360: // 32.73k / 2 gMicAutoParam.rate = MIC_SAMPLING_RATE_15870; break; case MIC_SAMPLING_RATE_15870: // 47.61k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_11900; break; case MIC_SAMPLING_RATE_11900: // 47.61k / 4 gMicAutoParam.rate = MIC_SAMPLING_RATE_10910; break; case MIC_SAMPLING_RATE_10910: // 32.73k / 3 gMicAutoParam.rate = MIC_SAMPLING_RATE_8180; break; case MIC_SAMPLING_RATE_8180: // 32.73k / 4 default: /* Do nothing */ return; } } } /*---------------------------------------------------------------------------* Name: OnSamplingDone Description: Updates the status flag when autosampling completes. Arguments: result: Unused arg: Unused Returns: None. *---------------------------------------------------------------------------*/ static void OnSamplingDone(MICResult result, void* arg) { #pragma unused(result, arg) if (g_sample_busy) { g_sample_busy = FALSE; } } /*---------------------------------------------------------------------------* Name: OutputSampleWave Description: Debug output of sampling data. Arguments: dat: Starting address of data to be output type: Microphone sampling type Returns: None. *---------------------------------------------------------------------------*/ static void OutputSampleWave(void* dat, MICSamplingType type) { /* Up to 2 lines at once with 16-sample units. If you output more than this amount, the log may contain omissions. */ enum { smps_per_line = 16, max_line_per_frame = 2 }; char buf[1 + (((MATH_MAX(sizeof(u8), sizeof(u16)) * 2) + 1) * smps_per_line) + 2]; char* s; int lines, i, j; u32 sample; u8 temp; if (!g_record_smps || !dat) { return; } DC_InvalidateRange((void*)g_record_smps, (u32)((u8*)dat - (u8*)g_record_smps)); switch (type) { case MIC_SAMPLING_TYPE_8BIT: /* In the case of 8-bit sampling */ for (lines = 0; (lines < max_line_per_frame) && ((u8*)g_record_smps + smps_per_line <= (u8*)dat); lines ++) { s = buf; *s ++ = '|'; for (i = 0; i < smps_per_line; i ++) { sample = (u32)(((u8*)g_record_smps)[i]); for (j = 0; j < (sizeof(u8) * 2); j ++) { temp = (u8)((sample >> (((sizeof(u8) * 2) - 1 - j) * 4)) & 0x0f); *s ++ = (char)((temp < 10) ? ('0' + temp) : ('A' + temp - 10)); } *s ++ = ','; } *s ++ = '\n'; *s = '\0'; OS_FPutString(OS_PRINT_OUTPUT_CURRENT, buf); g_record_smps = (void*)((u8*)g_record_smps + smps_per_line); } break; case MIC_SAMPLING_TYPE_12BIT: /* In the case of 12-bit sampling */ for (lines = 0; (lines < max_line_per_frame) && ((u16*)g_record_smps + smps_per_line <= (u16*)dat); lines ++) { s = buf; *s ++ = '|'; for (i = 0; i < smps_per_line; i ++) { sample = (u32)(((u16*)g_record_smps)[i]); for (j = 0; j < (sizeof(u16) * 2); j ++) { temp = (u8)((sample >> (((sizeof(u16) * 2) - 1 - j) * 4)) & 0x0f); *s ++ = (char)((temp < 10) ? ('0' + temp) : ('A' + temp - 10)); } *s ++ = ','; } *s ++ = '\n'; *s = '\0'; OS_FPutString(OS_PRINT_OUTPUT_CURRENT, buf); g_record_smps = (void*)((u16*)g_record_smps + smps_per_line); } break; } if (!g_sample_busy && g_record_smps) { if (((u8*)g_record_smps + (smps_per_line * max_line_per_frame)) >= (u8*)dat) { StopSamplingOutput(); } } } /*---------------------------------------------------------------------------* Name: StartSamplingOutput Description: Debug output of string indicating start of sampling output. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void StartSamplingOutput(void) { s32 range = 0; s32 rate = 0; switch (gMicAutoParam.type) { case MIC_SAMPLING_TYPE_8BIT: range = 8; break; case MIC_SAMPLING_TYPE_12BIT: range = 16; break; } switch (gMicAutoParam.rate) { case MIC_SAMPLING_RATE_32730: rate = 32730; break; case MIC_SAMPLING_RATE_16360: rate = 16360; break; case MIC_SAMPLING_RATE_10910: rate = 10910; break; case MIC_SAMPLING_RATE_8180: rate = 8180; break; case MIC_SAMPLING_RATE_47610: rate = 47610; break; case MIC_SAMPLING_RATE_23810: rate = 23810; break; case MIC_SAMPLING_RATE_15870: rate = 15870; break; case MIC_SAMPLING_RATE_11900: rate = 11900; break; } OS_Printf("$rate=%d\n$bits=%d\n", rate, range); } /*---------------------------------------------------------------------------* Name: StopSamplingOutput Description: Debug output of string indicating end of sampling output. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void StopSamplingOutput(void) { OS_Printf("$end\n\n"); g_record_smps = NULL; } /*---------------------------------------------------------------------------* Name: SetDrawData Description: Stores the current newest sampled data in the buffer that puts it on the display. Arguments: address: Location in main memory where the most recent sampling data was stored by the component type: Sampling type (bit width) Returns: None. *---------------------------------------------------------------------------*/ static void SetDrawData(void *address, MICSamplingType type) { s32 i; /* If sampling has never been performed, do nothing and stop. (Because it would delete memory cache(s) unrelated to the microphone) */ if ((address < gMicData) || (address >= (gMicData + TEST_BUFFER_SIZE))) { return; } switch (type) { case MIC_SAMPLING_TYPE_8BIT: /* In the case of 8-bit sampling */ { u8 *p; p = (u8 *)((u32)address - 191); if (p < gMicData) { p = (u8 *)((u32)p + TEST_BUFFER_SIZE); } DC_InvalidateRange((void *)((u32)p & ~(HW_CACHE_LINE_SIZE - 1)), HW_CACHE_LINE_SIZE); for (i = 0; i < 192; i++) { gDrawData[i] = *p; p++; if ((u32)p >= (u32)(gMicData + TEST_BUFFER_SIZE)) { p -= TEST_BUFFER_SIZE; } if (((u32)p % HW_CACHE_LINE_SIZE) == 0) { DC_InvalidateRange(p, HW_CACHE_LINE_SIZE); } } } break; case MIC_SAMPLING_TYPE_12BIT: /* For 12-bit sampling*/ { u16 *p; p = (u16 *)((u32)address - 382); if ((u32)p < (u32)gMicData) { p = (u16 *)((u32)p + TEST_BUFFER_SIZE); } DC_InvalidateRange((void *)((u32)p & ~(HW_CACHE_LINE_SIZE - 1)), HW_CACHE_LINE_SIZE); for (i = 0; i < 192; i++) { gDrawData[i] = (u8)((*p >> 8) & 0x00ff); p++; if ((u32)p >= (u32)(gMicData + TEST_BUFFER_SIZE)) { p = (u16 *)((u32)p - TEST_BUFFER_SIZE); } if (((u32)p % HW_CACHE_LINE_SIZE) == 0) { DC_InvalidateRange(p, HW_CACHE_LINE_SIZE); } } } break; } } /*---------------------------------------------------------------------------* Name: VBlankIntr Description: V-Blank interrupt vector. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void VBlankIntr(void) { /* Sets the IRQ check flag */ OS_SetIrqCheckFlag(OS_IE_V_BLANK); } /*---------------------------------------------------------------------------* Name: Init3D Description: Initialization for 3D display. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void Init3D(void) { G3X_Init(); G3X_InitMtxStack(); GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_3D); GX_SetVisiblePlane(GX_PLANEMASK_BG0); G2_SetBG0Priority(0); G3X_AlphaTest(FALSE, 0); G3X_AntiAlias(TRUE); G3X_EdgeMarking(FALSE); G3X_SetFog(FALSE, (GXFogBlend)0, (GXFogSlope)0, 0); G3X_SetClearColor(0, 0, 0x7fff, 63, FALSE); G3_ViewPort(0, 0, 255, 191); G3_MtxMode(GX_MTXMODE_POSITION_VECTOR); } /*---------------------------------------------------------------------------* Name: Draw3D Description: Displays waveforms in 3D Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void Draw3D(void) { G3X_Reset(); G3_Identity(); G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0); { s32 i; if ((gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_8BIT) || (gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_12BIT) || (gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF)) { for (i = 0; i < 191; i++) { DrawLine((s16)((s8)gDrawData[i]), (s16)i, (s16)((s8)gDrawData[i + 1]), (s16)(i + 1)); } } else { for (i = 0; i < 191; i++) { DrawLine((s16)(gDrawData[i]), (s16)i, (s16)(gDrawData[i + 1]), (s16)(i + 1)); } } } G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W); } /*---------------------------------------------------------------------------* Name: DrawLine Description: Renders lines with triangular polygons. Arguments: sx: X-coordinate of line's starting point sy: Y-coordinate of line's starting point ex: X-coordinate of line's ending point ey: Y-coordinate of line's ending point Returns: None. *---------------------------------------------------------------------------*/ static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey) { fx16 fsx = (fx16)(((sx - 128) * 0x1000) / 128); fx16 fsy = (fx16)(((96 - sy) * 0x1000) / 96); fx16 fex = (fx16)(((ex - 128) * 0x1000) / 128); fx16 fey = (fx16)(((96 - ey) * 0x1000) / 96); G3_Begin(GX_BEGIN_TRIANGLES); { G3_Color(GX_RGB(31, 31, 31)); G3_Vtx(fsx, fsy, 0); G3_Color(GX_RGB(31, 31, 31)); G3_Vtx(fex, fey, 0); G3_Color(GX_RGB(31, 31, 31)); G3_Vtx(fsx, fsy, 1); } G3_End(); } /*---------------------------------------------------------------------------* End of file *---------------------------------------------------------------------------*/