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