1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - library - dsp
3 File: dsp_util.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:: 2009-01-07#$
14 $Rev: 9790 $
15 $Author: kitase_hirotake $
16 *---------------------------------------------------------------------------*/
17 #include <twl.h>
18 #include <twl/dsp.h>
19 #include <twl/dsp/common/pipe.h>
20 #include <twl/dsp/common/audio.h>
21
22 #include "dsp_process.h"
23
24 /*---------------------------------------------------------------------------*/
25 /* Constants */
26
27 // Sound playback priority
28 #define DSP_SOUND_PRIORITY_SHUTTER 0
29 #define DSP_SOUND_PRIORITY_NORMAL 16
30 #define DSP_SOUND_PRIORITY_NONE 32
31
32 // For WAVE file parsing
33 #define MAKE_FOURCC(cc1, cc2, cc3, cc4) (u32)((cc1) | (cc2 << 8) | (cc3 << 16) | (cc4 << 24))
34 #define MAKE_TAG_DATA(ca) (u32)((*(ca)) | (*(ca+1) << 8) | (*(ca+2) << 16) | (*(ca+3) << 24))
35 #define FOURCC_RIFF MAKE_FOURCC('R', 'I', 'F', 'F')
36 #define FOURCC_WAVE MAKE_FOURCC('W', 'A', 'V', 'E')
37 #define FOURCC_fmt MAKE_FOURCC('f', 'm', 't', ' ')
38 #define FOURCC_data MAKE_FOURCC('d', 'a', 't', 'a')
39
40 // Wait (in ms) inserted before playback of shutter sound
41 #define DSP_WAIT_SHUTTER 60
42
43 /*---------------------------------------------------------------------------*/
44 /* Variables */
45
46 // DSP sound playback flag
47 static BOOL DSPiSoundPlaying = FALSE;
48
49 // Current DSP sound playback priority
50 static int DSPiSoundPriority = DSP_SOUND_PRIORITY_NONE;
51
52 // DSP sampling control information
53 typedef struct DSPAudioCaptureInfo
54 {
55 DSPAddr bufferAddress;
56 DSPWord bufferLength;
57 DSPWord currentPosition;
58 }
59 DSPAudioCaptureInfo;
60 static DSPAudioCaptureInfo DSPiAudioCapture;
61 extern DSPAddr DSPiAudioCaptureAddress;
62 static DSPAddr DSPiReadPosition = 0;
63
64 // Local buffer on the ARM9 side
65 static u32 DSPiLocalRingLength = 0;
66 static u8 *DSPiLocalRingBuffer = NULL;
67 static int DSPiLocalRingOffset = 0;
68 static DSPAddr DSPiAudioCaptureAddress = 0;
69
70 static BOOL DSPiPlayingShutter = FALSE;
71
72 // Function that returns the sound setting when shutter sound playback is completed
DSPiShutterPostProcessCallback(SNDEXResult result,void * arg)73 static void DSPiShutterPostProcessCallback( SNDEXResult result, void* arg )
74 {
75 #pragma unused(arg)
76 if(result == SNDEX_RESULT_EXCLUSIVE)
77 {
78 // Function that returns the shutter sound setting always succeeds
79 OS_TPanic("SNDEXi_PostProcessForShutterSound SNDEX_RESULT_EXCLUSIVE ... DSP_PlayShutterSound\n");
80 }
81 if(result != SNDEX_RESULT_SUCCESS)
82 {
83 // Function that returns the shutter sound setting always succeeds
84 OS_TPanic("SNDEXi_PostProcessForShutterSound Error ... DSP_PlayShutterSound\n");
85 }
86 DSPiPlayingShutter = FALSE;
87 }
88
89 /*---------------------------------------------------------------------------*/
90 /* Functions */
91
92 /*---------------------------------------------------------------------------*
93 Name: DSPi_PipeCallbackForSound
94
95 Description: Sound playback completed callback
96
97 Arguments: userdata: Optional user-defined argument
98 port: Port number
99 peer: Transmission direction
100
101 Returns: None.
102 *---------------------------------------------------------------------------*/
DSPi_PipeCallbackForSound(void * userdata,int port,int peer)103 static void DSPi_PipeCallbackForSound(void *userdata, int port, int peer)
104 {
105 (void)userdata;
106 if (peer == DSP_PIPE_INPUT)
107 {
108 // Receive command response from DSP
109 DSPAudioDriverResponse response;
110 DSPPipe pipe[1];
111 (void)DSP_LoadPipe(pipe, port, peer);
112 if (DSP_GetPipeReadableSize(pipe) >= sizeof(response))
113 {
114 DSP_ReadPipe(pipe, &response, sizeof(response));
115 response.ctrl = DSP_32BIT_TO_DSP(response.ctrl);
116 response.result = DSP_32BIT_TO_DSP(response.result);
117 // Audio output command
118 if ((response.ctrl & DSP_AUDIO_DRIVER_TARGET_MASK) == DSP_AUDIO_DRIVER_TARGET_OUTPUT)
119 {
120 // Stop command
121 if ((response.ctrl & DSP_AUDIO_DRIVER_CONTROL_MASK) == DSP_AUDIO_DRIVER_CONTROL_STOP)
122 {
123 DSPiSoundPlaying = FALSE;
124 if(DSPiSoundPriority == DSP_SOUND_PRIORITY_SHUTTER)
125 {
126 // Function that returns the shutter sound setting always succeeds
127 (void)SNDEXi_PostProcessForShutterSound(DSPiShutterPostProcessCallback, 0);
128 }
129 DSPiSoundPriority = DSP_SOUND_PRIORITY_NONE;
130 }
131 }
132 // Audio input command
133 if ((response.ctrl & DSP_AUDIO_DRIVER_TARGET_MASK) == DSP_AUDIO_DRIVER_TARGET_INPUT)
134 {
135 // Start command
136 if ((response.ctrl & DSP_AUDIO_DRIVER_CONTROL_MASK) == DSP_AUDIO_DRIVER_CONTROL_START)
137 {
138 DSPiAudioCaptureAddress = (DSPAddr)response.result;
139 }
140 }
141 }
142 }
143 }
144
145 /*---------------------------------------------------------------------------*
146 Name: DSPi_PlaySoundEx
147
148 Description: Plays sound directly from DSP sound output.
149
150 Arguments: src: Sampling data that is the source data
151 It is necessary to use a 4-byte boundary alignment with PCM16bit32768kHz
152 len: Sampling data byte size
153 ctrl: Combination with DSP_AUDIO_DRIVER_MODE_*
154 priority: Playback priority
155
156 Returns: None.
157 *---------------------------------------------------------------------------*/
DSPi_PlaySoundEx(const void * src,u32 len,u32 ctrl,int priority)158 static void DSPi_PlaySoundEx(const void *src, u32 len, u32 ctrl, int priority)
159 {
160 // Ignore if the component has not started anything up
161 DSPProcessContext *context = DSP_FindProcess(NULL);
162 if (context)
163 {
164 // If priority is lower than the sound that is currently in playback, do not playback
165 if (DSPiSoundPriority < priority)
166 {
167 OS_TWarning("still now playing high-priority sound.\n");
168 }
169 else
170 {
171 DSPiSoundPriority = priority;
172 ctrl |= DSP_AUDIO_DRIVER_TARGET_OUTPUT;
173 ctrl |= DSP_AUDIO_DRIVER_CONTROL_START;
174 // Change from byte size to half-word size
175 len >>= 1;
176 // Set the callback for completion notification
177 DSP_SetPipeCallback(DSP_PIPE_AUDIO, DSPi_PipeCallbackForSound, NULL);
178 DSPiSoundPlaying = TRUE;
179 {
180 DSPAudioDriverCommand command;
181 command.ctrl = DSP_32BIT_TO_DSP(ctrl);
182 command.buf = DSP_32BIT_TO_DSP(src);
183 command.len = DSP_32BIT_TO_DSP(len);
184 command.opt = DSP_32BIT_TO_DSP(0);
185 DSP_WriteProcessPipe(context, DSP_PIPE_AUDIO, &command, sizeof(command));
186 }
187 }
188 }
189 }
190
191 /*---------------------------------------------------------------------------*
192 Name: DSP_PlaySound
193
194 Description: Plays sound directly from DSP sound output.
195
196 Arguments: src: Sampling data that is the source data
197 It is necessary to use a 4-byte boundary alignment with PCM16bit32768kHz
198 len: Sampling data byte size
199 stereo: If stereo, TRUE. If monoaural, FALSE
200
201
202 Returns: None.
203 *---------------------------------------------------------------------------*/
DSPi_PlaySoundCore(const void * src,u32 len,BOOL stereo)204 void DSPi_PlaySoundCore(const void *src, u32 len, BOOL stereo)
205 {
206 u32 ctrl = (stereo != FALSE) ? DSP_AUDIO_DRIVER_MODE_STEREO : DSP_AUDIO_DRIVER_MODE_MONAURAL;
207 DSPi_PlaySoundEx(src, len, ctrl, DSP_SOUND_PRIORITY_NORMAL);
208 }
209
210 /*---------------------------------------------------------------------------*
211 Name: DSP_PlayShutterSound
212
213 Description: Plays sound directly from DSP sound output.
214
215 Arguments: src: Sampling data that is the source data
216 It is necessary to use a 4-byte boundary alignment with PCM16bit32768kHz
217 len: Sampling data byte size
218
219
220 Returns: If SNDEX function is successful, returns TRUE
221 *---------------------------------------------------------------------------*/
222 #if 0 // Do not apply a thorough WAVE check up to here
223 BOOL DSPi_PlayShutterSoundCore(const void *src, u32 len)
224 {
225 u8* wave_data = (u8*)src;
226 u32 cur = 0;
227 u32 tag;
228 u32 wave_len;
229 u32 raw_len;
230 BOOL fFmt = FALSE, fData = FALSE;
231
232 static SNDEXFrequency freq;
233 u32 sampling;
234 u32 chunkSize;
235
236 // Check whether the given data is a WAVE file
237 if(len < cur+12)
238 return FALSE;
239 tag = MAKE_TAG_DATA(wave_data+cur);
240 if(tag != FOURCC_RIFF)
241 return FALSE;
242 cur+=4;
243
244 wave_len = MAKE_TAG_DATA(wave_data+cur);
245 cur+=4;
246
247 tag = MAKE_TAG_DATA(wave_data+cur);
248 if(tag != FOURCC_WAVE)
249 return FALSE;
250 cur+=4;
251
252 while (wave_len > 0)
253 {
254 if(len < cur+8)
255 return FALSE;
256 tag = MAKE_TAG_DATA(wave_data+cur);
257 cur+=4;
258 chunkSize = MAKE_TAG_DATA(wave_data+cur);
259 cur+=4;
260
261 if(len < cur+chunkSize)
262 return FALSE;
263
264 switch (tag)
265 {
266 case FOURCC_fmt:
267 // Check the sampling rate from the format information
268 // If not playing back the shutter sound, get the frequency
269 if(!DSPi_IsShutterSoundPlayingCore)
270 {
271 if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
272 return FALSE;
273 }
274 sampling = MAKE_TAG_DATA(wave_data+cur+4);
275 cur+=chunkSize;
276 if( ((freq == SNDEX_FREQUENCY_32730)&&(sampling != 32730))||((freq == SNDEX_FREQUENCY_47610)&&(sampling != 47610)) )
277 return FALSE;
278 fFmt = TRUE;
279 break;
280 case FOURCC_data:
281 raw_len = chunkSize;
282 fData = TRUE;
283 break;
284 default:
285 cur+=chunkSize;
286 break;
287 }
288 if(fFmt && fData)
289 break;
290 wave_len -= chunkSize;
291 }
292 if(!(fFmt && fData))
293 return FALSE;
294
295 // When headphones are connected, turn off the system speaker
296 // Insert an approximately 60-msec wait before playback of the shutter sound to stabilize output
297 // This wait should be inserted in any situation to unify the sense of operation
298 OS_SpinWait(67 * DSP_WAIT_SHUTTER * 1000); // Approx. 60 msec
299
300 // Change the sound output mode in the function
301 while(SNDEXi_PreProcessForShutterSound() != SNDEX_RESULT_SUCCESS)
302 {
303 OS_Sleep(1); // Retry until successful
304 }
305
306 {
307 u32 ctrl = DSP_AUDIO_DRIVER_MODE_MONAURAL;
308 // Reduce the shutter sound on the left and right 50%
309 ctrl |= DSP_AUDIO_DRIVER_MODE_HALFVOL;
310 DSPi_PlaySoundEx((wave_data+cur), raw_len, ctrl, DSP_SOUND_PRIORITY_SHUTTER);
311 DSPiPlayingShutter = TRUE;
312 }
313
314 return TRUE;
315 }
316 #else // The purpose of the check is only for not making the shutter sound with a different frequency
DSPi_PlayShutterSoundCore(const void * src,u32 len)317 BOOL DSPi_PlayShutterSoundCore(const void *src, u32 len)
318 {
319 #pragma unused(len)
320 u32 cur;
321 u32 sampling;
322 u32 raw_len;
323 u8* wave_data = (u8*)src;
324 static SNDEXFrequency freq;
325
326 if(len < 44)
327 return FALSE;
328
329 if(MAKE_TAG_DATA(wave_data) != FOURCC_RIFF)
330 return FALSE;
331
332 if(MAKE_TAG_DATA(wave_data+8) != FOURCC_WAVE)
333 return FALSE;
334
335 cur = 24;
336 sampling = MAKE_TAG_DATA(wave_data+cur);
337
338 // Check the sampling rate from the format information
339 // If not playing back the shutter sound, get the frequency
340 if(!DSPi_IsShutterSoundPlayingCore)
341 {
342 if(SNDEX_GetI2SFrequency(&freq) != SNDEX_RESULT_SUCCESS)
343 return FALSE;
344 }
345 if( ((freq == SNDEX_FREQUENCY_32730)&&(sampling != 32730))||((freq == SNDEX_FREQUENCY_47610)&&(sampling != 47610)) )
346 return FALSE;
347
348 cur += 16;
349 raw_len = MAKE_TAG_DATA(wave_data+cur);
350 cur += 4;
351
352 if(len < cur+raw_len)
353 return FALSE;
354
355 // When headphones are connected, turn off the system speaker
356 // Insert an approximately 60-ms wait before playback of the shutter sound to stabilize output
357 // This wait should be inserted in any situation to unify the sense of operation
358 OS_SpinWait(67 * DSP_WAIT_SHUTTER * 1000); // Approximately 60 ms
359
360 // Change the sound output mode in the function
361 while(SNDEXi_PreProcessForShutterSound() != SNDEX_RESULT_SUCCESS)
362 {
363 OS_Sleep(1); // Retry until successful
364 }
365
366 {
367 u32 ctrl = DSP_AUDIO_DRIVER_MODE_MONAURAL;
368 // Reduce the shutter sound on the left and right 50%
369 ctrl |= DSP_AUDIO_DRIVER_MODE_HALFVOL;
370 DSPi_PlaySoundEx((wave_data+cur), raw_len, ctrl, DSP_SOUND_PRIORITY_SHUTTER);
371 DSPiPlayingShutter = TRUE;
372 }
373
374 return TRUE;
375 }
376 #endif
377
378 /*---------------------------------------------------------------------------*
379 Name: DSP_StopSound
380
381 Description: Stops playback from DSP sound output.
382
383 Arguments: None.
384
385 Returns: None.
386 *---------------------------------------------------------------------------*/
DSPi_StopSoundCore(void)387 void DSPi_StopSoundCore(void)
388 {
389 // Ignore if the component has not started anything up
390 DSPProcessContext *context = DSP_FindProcess(NULL);
391 if (context && DSPiSoundPlaying)
392 {
393 int ctrl = 0;
394 ctrl |= DSP_AUDIO_DRIVER_TARGET_OUTPUT;
395 ctrl |= DSP_AUDIO_DRIVER_CONTROL_STOP;
396 {
397 DSPAudioDriverCommand command;
398 command.ctrl = DSP_32BIT_TO_DSP(ctrl);
399 command.buf = DSP_32BIT_TO_DSP(0);
400 command.len = DSP_32BIT_TO_DSP(0);
401 command.opt = DSP_32BIT_TO_DSP(0);
402 DSP_WriteProcessPipe(context, DSP_PIPE_AUDIO, &command, sizeof(command));
403 }
404 }
405 }
406
407 /*---------------------------------------------------------------------------*
408 Name: DSP_IsSoundPlaying
409
410 Description: Determines whether DSP sound output is currently in playback.
411
412 Arguments: None.
413
414 Returns: TRUE if DSP sound output is currently in playback.
415 *---------------------------------------------------------------------------*/
DSPi_IsSoundPlayingCore(void)416 BOOL DSPi_IsSoundPlayingCore(void)
417 {
418 return DSPiSoundPlaying;
419 }
420
421 /*---------------------------------------------------------------------------*
422 Name: DSP_IsShutterSoundPlaying
423
424 Description: Determines whether DSP sound output is playing back the current shutter sound.
425
426 Arguments: None.
427
428 Returns: TRUE if DSP sound output is playing back the current shutter sound.
429 *---------------------------------------------------------------------------*/
DSPi_IsShutterSoundPlayingCore(void)430 BOOL DSPi_IsShutterSoundPlayingCore(void)
431 {
432 return DSPiPlayingShutter;
433 }
434
435 /*---------------------------------------------------------------------------*
436 Name: DSP_StartSampling
437
438 Description: Samples microphone sound directly from DSP sound input.
439
440 Arguments: buffer: Ring buffer used in sampling
441 It is necessary to align the boundary to 16-bit integer multiples
442 length: Ring buffer size
443 It is necessary to align the boundary to 16-bit integer multiples
444
445 Returns: None.
446 *---------------------------------------------------------------------------*/
DSPi_StartSamplingCore(void * buffer,u32 length)447 void DSPi_StartSamplingCore(void *buffer, u32 length)
448 {
449 SDK_ALIGN2_ASSERT(buffer);
450 SDK_ALIGN2_ASSERT(length);
451 {
452 // Ignore if the component has not started anything up
453 DSPProcessContext *context = DSP_FindProcess(NULL);
454 if (context)
455 {
456 int ctrl = 0;
457 ctrl |= DSP_AUDIO_DRIVER_TARGET_INPUT;
458 ctrl |= DSP_AUDIO_DRIVER_CONTROL_START;
459 DSPiLocalRingLength = length;
460 DSPiLocalRingBuffer = (u8 *)buffer;
461 DSPiLocalRingOffset = 0;
462 DSPiAudioCaptureAddress = 0;
463 // Set the callback for completion notification
464 DSP_SetPipeCallback(DSP_PIPE_AUDIO, DSPi_PipeCallbackForSound, NULL);
465 {
466 DSPAudioDriverCommand command;
467 command.ctrl = DSP_32BIT_TO_DSP(ctrl);
468 command.buf = DSP_32BIT_TO_DSP(0);
469 command.len = DSP_32BIT_TO_DSP(0);
470 command.opt = DSP_32BIT_TO_DSP(0);
471 DSP_WriteProcessPipe(context, DSP_PIPE_AUDIO, &command, sizeof(command));
472 }
473 }
474 }
475 }
476
477 /*---------------------------------------------------------------------------*
478 Name: DSP_StopSampling
479
480 Description: Stops sampling from DSP sound input.
481
482 Arguments: None.
483
484
485 Returns: None.
486 *---------------------------------------------------------------------------*/
DSPi_StopSamplingCore(void)487 void DSPi_StopSamplingCore(void)
488 {
489 // Ignore if the component has not started anything up
490 DSPProcessContext *context = DSP_FindProcess(NULL);
491 if (context)
492 {
493 int ctrl = 0;
494 ctrl |= DSP_AUDIO_DRIVER_TARGET_INPUT;
495 ctrl |= DSP_AUDIO_DRIVER_CONTROL_STOP;
496 // Set the callback for completion notification
497 DSP_SetPipeCallback(DSP_PIPE_AUDIO, DSPi_PipeCallbackForSound, NULL);
498 {
499 DSPAudioDriverCommand command;
500 command.ctrl = DSP_32BIT_TO_DSP(ctrl);
501 command.buf = DSP_32BIT_TO_DSP(0);
502 command.len = DSP_32BIT_TO_DSP(0);
503 command.opt = DSP_32BIT_TO_DSP(0);
504 DSP_WriteProcessPipe(context, DSP_PIPE_AUDIO, &command, sizeof(command));
505 }
506 }
507 }
508
509 /*---------------------------------------------------------------------------*
510 Name: DSP_SyncSamplingBuffer
511
512 Description: Reads only the updated portions from the ring buffer in DSP to the ARM9 processor.
513
514 Arguments: None.
515
516 Returns: None.
517 *---------------------------------------------------------------------------*/
DSPi_SyncSamplingBufferCore(void)518 void DSPi_SyncSamplingBufferCore(void)
519 {
520 // If not receiving the monitoring address of DSP, do nothing
521 if (DSPiAudioCaptureAddress != 0)
522 {
523 // Get the capture information in DSP and read if not read
524 DSP_LoadData(DSP_ADDR_TO_ARM(DSPiAudioCaptureAddress), &DSPiAudioCapture, sizeof(DSPiAudioCapture));
525 if (DSPiAudioCapture.currentPosition != DSPiReadPosition)
526 {
527 // Because the sizes of the ring buffers are different on the DSP and ARM9 processor, be careful of the end as you copy them
528 //
529 int cur = DSPiAudioCapture.currentPosition;
530 int end = (DSPiReadPosition > cur) ? DSPiAudioCapture.bufferLength : cur;
531 int len = end - DSPiReadPosition;
532 DSP_LoadData(DSP_ADDR_TO_ARM(DSPiAudioCapture.bufferAddress + DSPiReadPosition),
533 &DSPiLocalRingBuffer[DSPiLocalRingOffset], DSP_WORD_TO_ARM(len));
534 DSPiReadPosition += len;
535 if (DSPiReadPosition >= DSPiAudioCapture.bufferLength)
536 {
537 DSPiReadPosition -= DSPiAudioCapture.bufferLength;
538 }
539 DSPiLocalRingOffset += len * sizeof(s16);
540 if (DSPiLocalRingOffset >= DSPiLocalRingLength)
541 {
542 DSPiLocalRingOffset = 0;
543 }
544 }
545 }
546 }
547
548 /*---------------------------------------------------------------------------*
549 Name: DSP_GetLastSamplingAddress
550
551 Description: Gets the latest sampling position of the local ring buffer loaded to ARM9.
552
553
554 Arguments: None.
555
556 Returns: Latest sampling position.
557 *---------------------------------------------------------------------------*/
DSPi_GetLastSamplingAddressCore(void)558 const u8* DSPi_GetLastSamplingAddressCore(void)
559 {
560 int offset = DSPiLocalRingOffset - (int)sizeof(u16);
561 if (offset < 0)
562 {
563 offset += DSPiLocalRingLength;
564 }
565 return &DSPiLocalRingBuffer[offset];
566 }
567