1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - snd - extraFunc
3 File: main.c
4
5 Copyright 2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2009-09-24#$
14 $Rev: 11063 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 /*---------------------------------------------------------------------------*
19 A sample that uses the SNDEX library.
20
21 USAGE:
22 UP, DOWN: Switch item to control.
23 LEFT, RIGHT: Set configuration related to selected item.
24
25 HOWTO:
26 1. Initialize SNDEX library.
27 2. Call functions to set/get each configuration.
28 *---------------------------------------------------------------------------*/
29
30 #include <twl.h>
31 #include "font.h"
32 #include "snd_data.h"
33 #include "DEMO.h"
34
35 /*---------------------------------------------------------------------------*
36 Constant definitions
37 *---------------------------------------------------------------------------*/
38 #define INDEX_MAX 4
39
40 /*---------------------------------------------------------------------------*
41 Internal Variable Definitions
42 *---------------------------------------------------------------------------*/
43 static u16 screen[32 * 32] ATTRIBUTE_ALIGN(HW_CACHE_LINE_SIZE);
44 static s32 index = 0;
45
46 static SNDEXMute mute = SNDEX_MUTE_OFF;
47 static SNDEXFrequency freq = SNDEX_FREQUENCY_32730;
48 static u8 rate = 0;
49 static u8 volume = 0;
50 static BOOL shutter = FALSE;
51
52
53 /*---------------------------------------------------------------------------*
54 Internal Function Definitions
55 *---------------------------------------------------------------------------*/
56 static BOOL CheckResult (SNDEXResult result);
57 static void UpdateScreen (void);
58 static void VBlankIntr (void);
59 static void PrintString (s16 x, s16 y, u8 palette, char *text, ...);
60 static void VolumeSwitchCallback(SNDEXResult result, void* arg);
61
62 /*---------------------------------------------------------------------------*
63 Name: TwlMain
64
65 Description: Initialization and main loop.
66
67 Arguments: None.
68
69 Returns: None.
70 *---------------------------------------------------------------------------*/
71 void
TwlMain(void)72 TwlMain (void)
73 {
74 /* Initialization */
75 OS_Init();
76 GX_Init();
77 GX_DispOff();
78 GXS_DispOff();
79
80 // When in NITRO mode, stopped by Panic
81 DEMOCheckRunOnTWL();
82
83 /* Initializes display settings */
84 GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
85 MI_CpuClearFast((void*)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
86 (void)GX_DisableBankForLCDC();
87 MI_CpuFillFast((void*)HW_OAM, GX_LCD_SIZE_Y, HW_OAM_SIZE);
88 MI_CpuClearFast((void*)HW_PLTT, HW_PLTT_SIZE);
89 MI_CpuFillFast((void*)HW_DB_OAM, GX_LCD_SIZE_Y, HW_DB_OAM_SIZE);
90 MI_CpuClearFast((void*)HW_DB_PLTT, HW_DB_PLTT_SIZE);
91 GX_SetBankForBG(GX_VRAM_BG_128_A);
92 G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256,
93 GX_BG_COLORMODE_16,
94 GX_BG_SCRBASE_0xf800, // SCR base block 31
95 GX_BG_CHARBASE_0x00000, // CHR base block 0
96 GX_BG_EXTPLTT_01);
97 G2_SetBG0Priority(0);
98 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
99 GX_SetVisiblePlane(GX_PLANEMASK_BG0);
100 GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
101 GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
102 MI_CpuClearFast((void*)screen, sizeof(screen));
103 DC_FlushRange(screen, sizeof(screen));
104 GX_LoadBG0Scr(screen, 0, sizeof(screen));
105
106 /* Interrupt settings */
107 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
108 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
109 (void)GX_VBlankIntr(TRUE);
110 (void)OS_EnableIrq();
111 (void)OS_EnableInterrupts();
112
113 /* Initialize sound */
114 SND_Init();
115 SND_AssignWaveArc((SNDBankData*)sound_bank_data, 0, (SNDWaveArc*)sound_wave_data);
116 SND_StartSeq(0, sound_seq_data, 0, (SNDBankData*)sound_bank_data);
117
118 /* Initialize extended sound features */
119 SNDEX_Init();
120 (void)CheckResult(SNDEX_GetMute(&mute));
121 (void)CheckResult(SNDEX_GetI2SFrequency(&freq));
122 (void)CheckResult(SNDEX_GetDSPMixRate(&rate));
123 (void)CheckResult(SNDEX_GetVolume(&volume));
124 UpdateScreen();
125
126 /* Set the callback function for when the volume button is pressed */
127 SNDEX_SetVolumeSwitchCallback(VolumeSwitchCallback, NULL);
128
129 /* LCD display start */
130 GX_DispOn();
131 GXS_DispOn();
132
133 {
134 u16 keyOld = PAD_Read();
135 u16 keyTrg;
136 u16 keyNow;
137 SNDEXHeadphone hp;
138
139 /* Main loop */
140 while (TRUE)
141 {
142 /* Get key input data */
143 keyNow = PAD_Read();
144 keyTrg = (u16)((keyOld ^ keyNow) & keyNow);
145 keyOld = keyNow;
146
147 /* Perform various operations in accordance with input */
148 if (keyTrg & PAD_KEY_UP)
149 {
150 index = (index + INDEX_MAX - 1) % INDEX_MAX;
151 }
152 if (keyTrg & PAD_KEY_DOWN)
153 {
154 index = (index + 1) % INDEX_MAX;
155 }
156 if (keyTrg & PAD_KEY_RIGHT)
157 {
158 switch (index)
159 {
160 case 0: // Mute control
161 if (mute == SNDEX_MUTE_OFF)
162 {
163 if (CheckResult(SNDEX_SetMute(SNDEX_MUTE_ON)) == TRUE)
164 {
165 mute = SNDEX_MUTE_ON;
166 }
167 }
168 break;
169 case 1: // I2S frequency control
170 if (freq == SNDEX_FREQUENCY_32730)
171 {
172 if (CheckResult(SNDEX_SetI2SFrequency(SNDEX_FREQUENCY_47610)) == TRUE)
173 {
174 freq = SNDEX_FREQUENCY_47610;
175 }
176 }
177 break;
178 case 2: // DSP mix rate control
179 if (rate < SNDEX_DSP_MIX_RATE_MAX)
180 {
181 if (CheckResult(SNDEX_SetDSPMixRate((u8)(rate + 1))) == TRUE)
182 {
183 rate ++;
184 }
185 }
186 break;
187 case 3: // Volume control
188 if (volume < SNDEX_VOLUME_MAX)
189 {
190 if (CheckResult(SNDEX_SetVolume((u8)(volume + 1))) == TRUE)
191 {
192 volume ++;
193 }
194 }
195 break;
196 }
197 }
198 if (keyTrg & PAD_KEY_LEFT)
199 {
200 switch (index)
201 {
202 case 0: // Mute control
203 if (mute == SNDEX_MUTE_ON)
204 {
205 if (CheckResult(SNDEX_SetMute(SNDEX_MUTE_OFF)) == TRUE)
206 {
207 mute = SNDEX_MUTE_OFF;
208 }
209 }
210 break;
211 case 1: // I2S frequency control
212 if (freq == SNDEX_FREQUENCY_47610)
213 {
214 if (CheckResult(SNDEX_SetI2SFrequency(SNDEX_FREQUENCY_32730)) == TRUE)
215 {
216 freq = SNDEX_FREQUENCY_32730;
217 }
218 }
219 break;
220 case 2: // DSP mix rate control
221 if (rate > SNDEX_DSP_MIX_RATE_MIN)
222 {
223 if (CheckResult(SNDEX_SetDSPMixRate((u8)(rate - 1))) == TRUE)
224 {
225 rate --;
226 }
227 }
228 break;
229 case 3: // Volume control
230 if (volume > SNDEX_VOLUME_MIN)
231 {
232 if (CheckResult(SNDEX_SetVolume((u8)(volume - 1))) == TRUE)
233 {
234 volume --;
235 }
236 }
237 break;
238 }
239 }
240 if (keyTrg & PAD_BUTTON_A)
241 {
242 /* Determine if headphones are connected */
243 if (SNDEX_PXI_RESULT_SUCCESS == SNDEX_IsConnectedHeadphone(&hp))
244 {
245 if (hp == SNDEX_HEADPHONE_CONNECT)
246 {
247 OS_TPrintf("Headphone is connected.\n");
248 }
249 else
250 {
251 OS_TPrintf("Headphone is unconnected.\n");
252 }
253 }
254 }
255
256 /* Main sound processing */
257 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
258 {
259 }
260 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
261
262 /* Make the 'volume' value change in response to changes in audio volume */
263 (void)CheckResult(SNDEX_GetVolume(&volume));
264
265 /* Screen update */
266 UpdateScreen();
267
268 /* Wait for V-Blank */
269 OS_WaitVBlankIntr();
270 }
271 }
272 }
273
274 /*---------------------------------------------------------------------------*
275 Name: CheckResult
276
277 Description: Confirms the results of SNDEX library function calls.
278
279 Arguments: result: Value returned from the function
280
281 Returns: BOOL: Returns TRUE when the function call was successful.
282 Returns FALSE if there was a failure for any reason.
283 *---------------------------------------------------------------------------*/
284 static BOOL
CheckResult(SNDEXResult result)285 CheckResult (SNDEXResult result)
286 {
287 switch (result)
288 {
289 case SNDEX_RESULT_SUCCESS:
290 return TRUE;
291 case SNDEX_RESULT_BEFORE_INIT:
292 /* Before library initialization.
293 The SNDEX_Init function must be called before any other functions. */
294 OS_TWarning("Not initialized.\n");
295 break;
296 case SNDEX_RESULT_INVALID_PARAM:
297 /* Unknown parameter.
298 Review the argument(s) being passed to the function. */
299 OS_TWarning("Invalid parameter.\n");
300 break;
301 case SNDEX_RESULT_EXCLUSIVE:
302 /* Mutex is in effect.
303 Do not make consecutive calls of asynchronous functions or use the SNDEX library asynchronously from multiple threads.
304 */
305 OS_TWarning("Overlapped requests.\n");
306 break;
307 case SNDEX_RESULT_ILLEGAL_STATE:
308 /* Abnormal state.
309 The SNDEX library can only be used with TWL hardware.
310 Synchronous functions can't be called from within exception handlers.
311 When the CODEC is in DS Mode, you cannot switch to forced audio output.
312 When the CODEC is in DS Mode, when audio output is being forced, or when the microphone is auto-sampling, the I2S frequency cannot be changed.
313 */
314 OS_TWarning("In unavailable state.\n");
315 break;
316 case SNDEX_RESULT_PXI_SEND_ERROR:
317 /* PXI send error.
318 The data sending queue from ARM9 to ARM7 is full. Please wait a little before retrying so that ARM7 can delete data within the queue.
319 */
320 OS_TWarning("PXI queue full.\n");
321 break;
322 case SNDEX_RESULT_DEVICE_ERROR:
323 /* Failed to operate device.
324 An attempt was made to access an external CPU device (the microprocessor) to get or change volume, but that access failed.
325 If conditions don't improve even after multiple retries, consider it a success and move on, since the problem is likely caused by a runaway microprocessor, malfunctioning hardware, or some other thing not recoverable by software.
326
327 */
328 OS_TWarning("Micro controller unusual.\n");
329 return TRUE;
330 case SNDEX_RESULT_FATAL_ERROR:
331 default:
332 /* Fatal error.
333 By the library's logic, this cannot occur. It's possible this occurred (1) when a PXI command was directly issued to ARM7 (ignoring the library's internal status management), (2) when memory damage resulted in inconsistencies in internal status management, or (3) when this was combined with an unexpected ARM7 component, or for some similar reason.
334
335
336 */
337 OS_TWarning("Fatal error.\n");
338 break;
339 }
340 return FALSE;
341 }
342
343 /*---------------------------------------------------------------------------*
344 Name: UpdateScreen
345
346 Description: Updates the displayed screen content.
347
348 Arguments: None.
349
350 Returns: None.
351 *---------------------------------------------------------------------------*/
352 static void
UpdateScreen(void)353 UpdateScreen (void)
354 {
355 /* Clear the virtual screen */
356 MI_CpuClearFast((void*)screen, sizeof(screen));
357
358 /* Edit a string on the virtual screen */
359 PrintString(2, 1, 0xf, "Mute : %d/1 [ %s ]", mute, ((mute == SNDEX_MUTE_OFF) ? "OFF" : "ON"));
360 PrintString(2, 3, 0xf, "I2S freq : %d/1 [ %s ]", freq, ((freq == SNDEX_FREQUENCY_32730) ? "32K" : "48K"));
361 PrintString(2, 5, 0xf, "DSP mix : %d/8", rate);
362 PrintString(2, 7, 0xf, "Volume : %d/%d", volume, (u8)SNDEX_VOLUME_MAX);
363
364 PrintString(0, 11, 0xe, "- [A] : Check Headphone");
365 PrintString(0, 13, 0xe, "- [Volume Button] : Print log");
366
367 /* Change the selected item's display color */
368 PrintString(0, (s16)(index * 2 + 1), 0xf, ">");
369 {
370 s32 i;
371 s32 j;
372
373 for (i = 0; i < 32; i ++)
374 {
375 j = ((index * 2 + 1) * 32) + i;
376 screen[j] &= (u16)(~(0xf << 12));
377 screen[j] |= (u16)(0x4 << 12);
378 }
379 }
380 }
381
382 /*---------------------------------------------------------------------------*
383 Name: VBlankIntr
384
385 Description: V-Blank interrupt vector.
386
387 Arguments: None.
388
389 Returns: None.
390 *---------------------------------------------------------------------------*/
391 static void
VBlankIntr(void)392 VBlankIntr (void)
393 {
394 /* Reflect virtual screen in VRAM */
395 DC_FlushRange(screen, sizeof(screen));
396 GX_LoadBG0Scr(screen, 0, sizeof(screen));
397
398 /* Sets the IRQ check flag */
399 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
400 }
401
402 /*---------------------------------------------------------------------------*
403 Name: PrintString
404
405 Description: Positions the text string on the virtual screen. The string can be up to 32 chars.
406
407 Arguments: x: X-coordinate where character string starts (x 8 pixels).
408 y: Y-coordinate where character string starts (x 8 pixels).
409 palette: Specify text color by palette number.
410 text: Text string to position. Null-terminated.
411 ...: Virtual argument.
412
413 Returns: None.
414 *---------------------------------------------------------------------------*/
415 static void
PrintString(s16 x,s16 y,u8 palette,char * text,...)416 PrintString (s16 x, s16 y, u8 palette, char *text, ...)
417 {
418 va_list vlist;
419 char temp[32 + 2];
420 s32 i;
421
422 va_start(vlist, text);
423 (void)vsnprintf(temp, 33, text, vlist);
424 va_end(vlist);
425
426 *((u16*)(&temp[32])) = 0x0000;
427 for (i = 0; ; i++)
428 {
429 if (temp[i] == 0x00)
430 {
431 break;
432 }
433 screen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
434 }
435 }
436
437 /*---------------------------------------------------------------------------*
438 Name: VolumeSwitchCallback
439
440 Description: Callback function executed when the volume button on the TWL is pressed.
441
442 Arguments: result: Result of pressing the volume button
443 arg: Argument passed when this function is called as a callback function
444
445
446 Returns: None.
447 *---------------------------------------------------------------------------*/
VolumeSwitchCallback(SNDEXResult result,void * arg)448 static void VolumeSwitchCallback(SNDEXResult result, void* arg)
449 {
450 #pragma unused( arg )
451 #pragma unused( result )
452
453 /* SNDEX library functions cannot be used during callback processing.*
454 * SNDEX_RESULT_EXCLUSIVE is returned. */
455 OS_TPrintf("volume switch pressed.\n");
456 }
457