1 /*---------------------------------------------------------------------------*
2 Project: THP Simple Player
3 File: THPSimple.c
4
5 Copyright (C)2002-2006 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 $Log: THPSimple.c,v $
14 Revision 1.4 2008/05/12 09:10:33 aka
15 Changed channel conversion from stereo to monaural..
16
17 Revision 1.3 2008/02/28 05:21:27 aka
18 Added THPSimpleSetSoundMode().
19 Added THPSimpleGetSoundMode().
20 Changed MixAudio() enabling to output monaural data.
21
22 Revision 1.2 2006/02/03 11:43:16 aka
23 Changed audio frame from 5msec to 3msec.
24
25 Revision 1.1 2006/02/03 10:01:13 aka
26 Imported from Dolphin tree.
27
28 4 03/11/25 11:24 Dante
29 Japanese to English translation of comments and text strings
30
31 3 02/05/14 9:18a Suzuki
32 Support multi audio track
33
34 2 02/02/28 6:37p Akagi
35 enabled to use with MusyX/AX by Suzuki-san (IRD).
36
37 1 02/01/16 10:54a Akagi
38 Initial revision made by Suzuki-san (IRD).
39
40 $NoKeywords: $
41
42 *---------------------------------------------------------------------------*/
43
44 #include <string.h>
45 #include <revolution.h>
46
47 #include "THPSimple.h"
48 #include "THPDraw.h"
49
50 #define NEXT_BUFFER(p) ((p) + 1 >= READ_BUFFER_NUM ? 0 : (p) + 1)
51 #define GET_DECODE_BUFFER(p) ((p).readBuffer[(p).nextDecodeIndex].ptr)
52 #define GET_READ_BUFFER(p) ((p).readBuffer[(p).readIndex].ptr)
53 #define BUFFER_VALID(p) (SimpleControl.readBuffer[p].isValid)
54 #define NEXT_READ_SIZE(p) *(u32 *)((p).readBuffer[(p).readIndex].ptr)
55 #define GET_COMP_SIZE(p, i) *(u32 *)((p).readBuffer[(p).nextDecodeIndex].ptr + 4 * i + 8)
56
57 #define SAMPLES_PER_AUDIO_FRAME 96 // 3msec (32khz)
58 #define BYTES_PER_AUDIO_FRAME (SAMPLES_PER_AUDIO_FRAME * 4)
59
60 /*---------------------------------------------------------------------------*
61 Static Function
62 *---------------------------------------------------------------------------*/
63
64 static void ReadFrameAsync(void);
65 static BOOL VideoDecode(u8 *videoFrame);
66 static void __THPSimpleDVDCallback(s32 result, DVDFileInfo *fileInfo);
67 static inline void CheckPrefetch(void);
68 static void THPAudioMixCallback(void);
69 static void MixAudio(s16 *destination, s16 *source, u32 sample);
70
71 /*---------------------------------------------------------------------------*
72 Static Variable
73 *---------------------------------------------------------------------------*/
74
75 // 32768 * ((vol * vol) / (127 * 127))
76 static u16 VolumeTable[] =
77 {
78 0, 2, 8, 18, 32, 50, 73, 99,
79 130, 164, 203, 245, 292, 343, 398, 457,
80 520, 587, 658, 733, 812, 895, 983, 1074,
81 1170, 1269, 1373, 1481, 1592, 1708, 1828, 1952,
82 2080, 2212, 2348, 2488, 2632, 2781, 2933, 3090,
83 3250, 3415, 3583, 3756, 3933, 4114, 4298, 4487,
84 4680, 4877, 5079, 5284, 5493, 5706, 5924, 6145,
85 6371, 6600, 6834, 7072, 7313, 7559, 7809, 8063,
86 8321, 8583, 8849, 9119, 9394, 9672, 9954, 10241,
87 10531, 10826, 11125, 11427, 11734, 12045, 12360, 12679,
88 13002, 13329, 13660, 13995, 14335, 14678, 15025, 15377,
89 15732, 16092, 16456, 16823, 17195, 17571, 17951, 18335,
90 18723, 19115, 19511, 19911, 20316, 20724, 21136, 21553,
91 21974, 22398, 22827, 23260, 23696, 24137, 24582, 25031,
92 25484, 25941, 26402, 26868, 27337, 27810, 28288, 28769,
93 29255, 29744, 30238, 30736, 31238, 31744, 32254, 32768
94 };
95
96 static THPSimple SimpleControl;
97 static s32 WorkBuffer[16] ATTRIBUTE_ALIGN(32);
98 static BOOL Initialized = 0;
99 static s16 SoundBuffer[2][SAMPLES_PER_AUDIO_FRAME * 2] ATTRIBUTE_ALIGN(32);
100 static s32 SoundBufferIndex;
101 static AIDCallback OldAIDCallback = NULL;
102 static s16 *LastAudioBuffer;
103 static s16 *CurAudioBuffer;
104 static s32 AudioSystem = 0;
105
106 /*---------------------------------------------------------------------------*
107 Name: THPSimpleInit
108
109 Description: Initializes player and THP library and turns locked cache
110 to ON.
111 Register AI FIFO DMA callback function for single player
112
113 Arguments: audioSystem Specifies the audio library to be used
114 simultaneously.
115 If no audio library is to be used simultaneouly,
116 specifies THP_MODE_ALONE.
117
118 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
119 *---------------------------------------------------------------------------*/
120
THPSimpleInit(s32 audioSystem)121 BOOL THPSimpleInit(s32 audioSystem)
122 {
123 BOOL old;
124
125 ASSERTMSG(audioSystem >= 0 && audioSystem <= THP_MODE_WITH_MUSYX, "audioSystem flag is invalid\n");
126
127 memset(&SimpleControl, 0, sizeof(THPSimple));
128
129 // default sound mode...
130 SimpleControl.soundMode = THP_SOUND_MODE_STEREO;
131
132 LCEnable();
133
134 if (THPInit() == FALSE)
135 {
136 return FALSE;
137 }
138
139 old = OSDisableInterrupts();
140
141 AudioSystem = audioSystem;
142 SoundBufferIndex = 0;
143 LastAudioBuffer = NULL;
144 CurAudioBuffer = NULL;
145
146 OldAIDCallback = AIRegisterDMACallback(THPAudioMixCallback);
147
148 if (OldAIDCallback == NULL && AudioSystem != THP_MODE_ALONE)
149 {
150 AIRegisterDMACallback(NULL);
151
152 OSRestoreInterrupts(old);
153
154 #ifdef _DEBUG
155 OSReport("Please call AXInit or sndInit before you call THPPlayerInit\n");
156 #endif
157 return FALSE;
158 }
159
160 OSRestoreInterrupts(old);
161
162 if (AudioSystem == THP_MODE_ALONE)
163 {
164 memset(SoundBuffer, 0, BYTES_PER_AUDIO_FRAME << 1);
165
166 DCFlushRange(SoundBuffer, BYTES_PER_AUDIO_FRAME << 1);
167
168 AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
169
170 AIStartDMA();
171 }
172
173 Initialized = TRUE;
174
175 return TRUE;
176 }
177
178 /*---------------------------------------------------------------------------*
179 Name: THPSimpleQuit
180
181 Description: Turns locked cache to OFF.
182 Restore AI FIFO DMA callback to the state before THPPlayerInit is called.
183
184 Arguments: None
185
186 Returns: None
187 *---------------------------------------------------------------------------*/
188
THPSimpleQuit(void)189 void THPSimpleQuit(void)
190 {
191 BOOL old;
192
193 LCDisable();
194
195 old = OSDisableInterrupts();
196
197 if (OldAIDCallback)
198 {
199 AIRegisterDMACallback(OldAIDCallback);
200 }
201
202 OSRestoreInterrupts(old);
203
204 Initialized = FALSE;
205
206 return;
207 }
208
209 /*---------------------------------------------------------------------------*
210 Name: THPSimpleOpen
211
212 Description: Opens THP movie file. Reads required data.
213
214 Arguments: fileName THP movie filename
215
216 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
217 *---------------------------------------------------------------------------*/
218
THPSimpleOpen(char * fileName)219 BOOL THPSimpleOpen(char *fileName)
220 {
221 s32 offset, i;
222
223 if (!Initialized)
224 {
225 #ifdef _DEBUG
226 OSReport("You must call THPSimpleInit before you call this function\n");
227 #endif
228 return FALSE;
229 }
230
231 if (SimpleControl.open)
232 {
233 #ifdef _DEBUG
234 OSReport("Cannot open %s. The THP file is already open.\n");
235 #endif
236 return FALSE;
237 }
238
239 // Clear current video data and audio data
240 memset(&SimpleControl.videoInfo, 0, sizeof(THPVideoInfo));
241 memset(&SimpleControl.audioInfo, 0, sizeof(THPAudioInfo));
242
243 if (DVDOpen(fileName, &SimpleControl.fileInfo) == FALSE)
244 {
245 #ifdef _DEBUG
246 OSReport("Cannot open %s\n", fileName);
247 #endif
248 return FALSE;
249 }
250
251 // Get THP header
252 if (DVDRead(&SimpleControl.fileInfo, WorkBuffer, 64, 0) < 0)
253 {
254 #ifdef _DEBUG
255 OSReport("Failed to read the header from THP file\n");
256 #endif
257 DVDClose(&SimpleControl.fileInfo);
258 return FALSE;
259 }
260
261 memcpy(&SimpleControl.header, WorkBuffer, sizeof(THPHeader));
262
263 // Check if THP movie file
264 if (strcmp(SimpleControl.header.magic, "THP") != 0)
265 {
266 #ifdef _DEBUG
267 OSReport("This file is not THP file\n");
268 #endif
269 DVDClose(&SimpleControl.fileInfo);
270 return FALSE;
271 }
272
273 // Check version
274 if (SimpleControl.header.version != THP_VERSION)
275 {
276 #ifdef _DEBUG
277 OSReport("invalid version\n");
278 #endif
279 DVDClose(&SimpleControl.fileInfo);
280 return FALSE;
281 }
282
283 offset = (s32)SimpleControl.header.compInfoDataOffsets;
284
285 // Get component data in frame
286 if (DVDRead(&SimpleControl.fileInfo, WorkBuffer, 32, offset) < 0)
287 {
288 #ifdef _DEBUG
289 OSReport("Failed to read the frame component infomation from THP file\n");
290 #endif
291 DVDClose(&SimpleControl.fileInfo);
292 return FALSE;
293 }
294
295 memcpy(&SimpleControl.compInfo, WorkBuffer, sizeof(THPFrameCompInfo));
296
297 offset += sizeof(THPFrameCompInfo);
298
299 SimpleControl.audioExist = 0;
300
301 // Check components in frame
302 for(i = 0 ; i < SimpleControl.compInfo.numComponents ; i++)
303 {
304 switch(SimpleControl.compInfo.frameComp[i])
305 {
306 case THP_VIDEO_COMP: // Get component video data
307 if (DVDRead(&SimpleControl.fileInfo, WorkBuffer, 32, offset) < 0)
308 {
309 #ifdef _DEBUG
310 OSReport("Failed to read the video infomation from THP file\n");
311 #endif
312 DVDClose(&SimpleControl.fileInfo);
313 return FALSE;
314 }
315 memcpy(&SimpleControl.videoInfo, WorkBuffer, sizeof(THPVideoInfo));
316 offset += sizeof(THPVideoInfo);
317 break;
318 case THP_AUDIO_COMP: // Get component audio data
319 if (DVDRead(&SimpleControl.fileInfo, WorkBuffer, 32, offset) < 0)
320 {
321 #ifdef _DEBUG
322 OSReport("Failed to read the video infomation from THP file\n");
323 #endif
324 DVDClose(&SimpleControl.fileInfo);
325 return FALSE;
326 }
327 memcpy(&SimpleControl.audioInfo, WorkBuffer, sizeof(THPAudioInfo));
328 SimpleControl.audioExist = 1;
329 offset += sizeof(THPAudioInfo);
330
331 break;
332 default:
333 #ifdef _DEBUG
334 OSReport("Unknown frame components\n");
335 #endif
336 return FALSE;
337 }
338 }
339
340 SimpleControl.curOffset = (s32)SimpleControl.header.movieDataOffsets;
341 SimpleControl.readSize = (s32)SimpleControl.header.firstFrameSize;
342 SimpleControl.readIndex = 0;
343 SimpleControl.totalReadFrame = 0;
344 SimpleControl.dvdError = FALSE;
345 SimpleControl.textureSet.frameNumber = -1;
346 SimpleControl.nextDecodeIndex = 0;
347 SimpleControl.audioDecodeIndex = 0;
348 SimpleControl.audioOutputIndex = 0;
349 SimpleControl.preFetchState = FALSE;
350 SimpleControl.audioState = FALSE;
351 SimpleControl.loop = THP_PLAY_ONESHOT;
352 SimpleControl.open = TRUE;
353 SimpleControl.curVolume = 127.0f;
354 SimpleControl.targetVolume = SimpleControl.curVolume;
355 SimpleControl.rampCount = 0;
356
357 return TRUE;
358 }
359
360 /*---------------------------------------------------------------------------*
361 Name: THPSimpleClose
362
363 Description: Closes THP movie file
364
365 Arguments: None
366
367 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
368 *---------------------------------------------------------------------------*/
369
THPSimpleClose(void)370 BOOL THPSimpleClose(void)
371 {
372 if (SimpleControl.open)
373 {
374 if (SimpleControl.preFetchState == FALSE)
375 {
376 if (SimpleControl.audioExist)
377 {
378 if (SimpleControl.audioState == TRUE)
379 {
380 return FALSE;
381 }
382 }
383 else
384 {
385 SimpleControl.audioState = FALSE;
386 }
387
388 if (!SimpleControl.readProgress)
389 {
390 SimpleControl.open = FALSE;
391
392 DVDClose(&SimpleControl.fileInfo);
393
394 return TRUE;
395 }
396 }
397 }
398
399 return FALSE;
400 }
401
402 /*---------------------------------------------------------------------------*
403 Name: THPSimpleCalcNeedMemory
404
405 Description: Calculates required memory for THP movie playback
406
407 Arguments: None
408
409 Returns: If successful, returns required memory size. If unsuccessful,
410 returns 0.
411 *---------------------------------------------------------------------------*/
412
THPSimpleCalcNeedMemory(void)413 u32 THPSimpleCalcNeedMemory(void)
414 {
415 u32 size;
416
417 if (SimpleControl.open)
418 {
419 // Buffer size for read
420 size = OSRoundUp32B(SimpleControl.header.bufSize) * READ_BUFFER_NUM;
421
422 // Texture buffer size
423 size += OSRoundUp32B(SimpleControl.videoInfo.xSize * SimpleControl.videoInfo.ySize); //Y
424 size += OSRoundUp32B(SimpleControl.videoInfo.xSize * SimpleControl.videoInfo.ySize / 4); //U
425 size += OSRoundUp32B(SimpleControl.videoInfo.xSize * SimpleControl.videoInfo.ySize / 4); //V
426
427 // Audio buffer size
428 if (SimpleControl.audioExist)
429 {
430 size += (OSRoundUp32B(SimpleControl.header.audioMaxSamples * 4) * AUDIO_BUFFER_NUM);
431 }
432
433 size += THP_WORK_SIZE;
434
435 return size;
436 }
437
438 return 0;
439 }
440
441 /*---------------------------------------------------------------------------*
442 Name: THPSimpleSetBuffer
443
444 Description: Allocates required memory for THP movie playback to the
445 THPSimple structure.
446
447 Arguments: buffer Pointer for THP movie memory area set aside
448 externally.
449
450 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
451 *---------------------------------------------------------------------------*/
452
THPSimpleSetBuffer(u8 * buffer)453 BOOL THPSimpleSetBuffer(u8 *buffer)
454 {
455 u32 i;
456 u8 *ptr;
457 u32 ysize, uvsize;
458
459 ASSERTMSG(buffer != NULL, "buffer is NULL\n");
460
461 if (SimpleControl.open && SimpleControl.preFetchState == FALSE)
462 {
463 if (SimpleControl.audioState == TRUE)
464 {
465 return FALSE;
466 }
467
468 ysize = OSRoundUp32B(SimpleControl.videoInfo.xSize * SimpleControl.videoInfo.ySize);
469 uvsize = OSRoundUp32B(SimpleControl.videoInfo.xSize * SimpleControl.videoInfo.ySize / 4);
470
471 ptr = buffer;
472
473 // Set texture buffer
474 SimpleControl.textureSet.ytexture = ptr;
475 DCInvalidateRange(ptr, ysize);
476 ptr += ysize;
477 SimpleControl.textureSet.utexture = ptr;
478 DCInvalidateRange(ptr, uvsize);
479 ptr += uvsize;
480 SimpleControl.textureSet.vtexture = ptr;
481 DCInvalidateRange(ptr, uvsize);
482 ptr += uvsize;
483
484 // Set audio buffer
485 for (i = 0 ; i < READ_BUFFER_NUM ; i++)
486 {
487 SimpleControl.readBuffer[i].ptr = ptr;
488 ptr += OSRoundUp32B(SimpleControl.header.bufSize);
489 SimpleControl.readBuffer[i].isValid = FALSE;
490 }
491
492 // Set Audio Buffer
493 if (SimpleControl.audioExist)
494 {
495 for (i = 0 ; i < AUDIO_BUFFER_NUM ; i++)
496 {
497 SimpleControl.audioBuffer[i].buffer = (s16 *)ptr;
498 SimpleControl.audioBuffer[i].curPtr = (s16 *)ptr;
499 SimpleControl.audioBuffer[i].validSample = 0;
500 ptr += OSRoundUp32B(SimpleControl.header.audioMaxSamples * 4);
501 }
502 }
503
504 SimpleControl.thpWork = (void *)ptr;
505 }
506
507 return TRUE;
508 }
509
510 /*---------------------------------------------------------------------------*
511 Name: ReadFrameAsync
512
513 Description: Asynchronous read of 1 frame of movie data
514
515 Arguments: None
516
517 Returns: None
518 *---------------------------------------------------------------------------*/
519
ReadFrameAsync(void)520 static void ReadFrameAsync(void)
521 {
522 if (!SimpleControl.dvdError && SimpleControl.preFetchState == TRUE)
523 {
524 if (SimpleControl.totalReadFrame > SimpleControl.header.numFrames - 1)
525 {
526 // If loop playback, offset and size to starting frame
527 if (SimpleControl.loop == THP_PLAY_LOOP)
528 {
529 SimpleControl.totalReadFrame = 0;
530 SimpleControl.curOffset = (s32)SimpleControl.header.movieDataOffsets;
531 SimpleControl.readSize = (s32)SimpleControl.header.firstFrameSize;
532 }
533 // Do nothing if one-shot playback
534 else
535 {
536 return;
537 }
538 }
539
540 SimpleControl.readProgress = TRUE;
541
542 if (DVDReadAsync(&SimpleControl.fileInfo,
543 GET_READ_BUFFER(SimpleControl),
544 SimpleControl.readSize,
545 SimpleControl.curOffset,
546 __THPSimpleDVDCallback) != TRUE)
547 {
548 SimpleControl.readProgress = FALSE;
549 SimpleControl.dvdError = TRUE;
550 }
551 }
552
553 return;
554 }
555
556 /*---------------------------------------------------------------------------*
557 Name: __THPSimpleDVDCallback
558
559 Description: Callback function specified in DVDReadAsync. If space in
560 read buffer, call DVDReadAsync again and do preloading of
561 THP movie data.
562
563 Arguments: None
564
565 Returns: None
566 *---------------------------------------------------------------------------*/
567
__THPSimpleDVDCallback(s32 result,DVDFileInfo * fileInfo)568 static void __THPSimpleDVDCallback(s32 result, DVDFileInfo *fileInfo)
569 {
570 #pragma unused(fileInfo)
571 // If error occurs, turn on error flag and end
572 if (result == DVD_RESULT_FATAL_ERROR)
573 {
574 SimpleControl.dvdError = TRUE;
575 return;
576 }
577 // Return if canceled
578 else if (result == DVD_RESULT_CANCELED)
579 {
580 return;
581 }
582
583 SimpleControl.readProgress = FALSE;
584
585 // Record frame # of currently completed read
586 SimpleControl.readBuffer[SimpleControl.readIndex].frameNumber = SimpleControl.totalReadFrame;
587
588 SimpleControl.totalReadFrame++;
589
590 SimpleControl.readBuffer[SimpleControl.readIndex].isValid = TRUE;
591 SimpleControl.curOffset += SimpleControl.readSize;
592 SimpleControl.readSize = (s32)NEXT_READ_SIZE(SimpleControl);
593 SimpleControl.readIndex = NEXT_BUFFER(SimpleControl.readIndex);
594
595 // Continue preload if open buffer present
596 if (!BUFFER_VALID(SimpleControl.readIndex))
597 {
598 ReadFrameAsync();
599 }
600
601 return;
602 }
603
604 /*---------------------------------------------------------------------------*
605 Name: CheckPrefetch
606
607 Description: Checks whether preload has stopped. Does preload if preload
608 has stopped and read space in read buffer.
609
610 Arguments: None
611
612 Returns: None
613 *---------------------------------------------------------------------------*/
614
CheckPrefetch(void)615 static inline void CheckPrefetch(void)
616 {
617 BOOL enabled;
618
619 enabled = OSDisableInterrupts();
620
621 if (!BUFFER_VALID(SimpleControl.readIndex) && !SimpleControl.readProgress)
622 {
623 ReadFrameAsync();
624 }
625
626 OSRestoreInterrupts(enabled);
627 }
628
629 /*---------------------------------------------------------------------------*
630 Name: THPSimplePreLoad
631
632 Description: As preparation for movie playback, preload READ_BUFFER_NUM
633 worth of frame data.
634
635 Arguments: loop Specify loop flag.
636
637 Returns: If playback preparations completed returns TRUE.
638 If fail returns FALSE.
639 *---------------------------------------------------------------------------*/
640
THPSimplePreLoad(s32 loop)641 BOOL THPSimplePreLoad(s32 loop)
642 {
643 u32 i, readNum;
644
645 if (SimpleControl.open && (SimpleControl.preFetchState == FALSE))
646 {
647 readNum = READ_BUFFER_NUM;
648
649 if (!loop)
650 {
651 if (SimpleControl.header.numFrames < READ_BUFFER_NUM)
652 {
653 readNum = SimpleControl.header.numFrames;
654 }
655 }
656
657 // Do preload
658 for (i = 0 ; i < readNum ; i++)
659 {
660 if (DVDRead(&SimpleControl.fileInfo,
661 SimpleControl.readBuffer[SimpleControl.readIndex].ptr,
662 SimpleControl.readSize,
663 SimpleControl.curOffset) < 0)
664 {
665 #ifdef _DEBUG
666 OSReport("Failed to read the frame data from THP file.\n");
667 #endif
668 SimpleControl.dvdError = TRUE;
669 return FALSE;
670 }
671
672 SimpleControl.curOffset += SimpleControl.readSize;
673 SimpleControl.readSize = (s32)NEXT_READ_SIZE(SimpleControl);
674
675 SimpleControl.readBuffer[SimpleControl.readIndex].isValid = TRUE;
676 SimpleControl.readBuffer[SimpleControl.readIndex].frameNumber = SimpleControl.totalReadFrame;
677
678 SimpleControl.readIndex = NEXT_BUFFER(SimpleControl.readIndex);
679
680 SimpleControl.totalReadFrame++;
681
682 if (SimpleControl.totalReadFrame > SimpleControl.header.numFrames - 1)
683 {
684 if (SimpleControl.loop == THP_PLAY_LOOP)
685 {
686 SimpleControl.totalReadFrame = 0;
687 SimpleControl.curOffset = (s32)SimpleControl.header.movieDataOffsets;
688 SimpleControl.readSize = (s32)SimpleControl.header.firstFrameSize;
689 }
690 }
691 }
692
693 // Set loop flag
694 SimpleControl.loop = (u8)loop;
695 SimpleControl.preFetchState = TRUE;
696
697 return TRUE;
698 }
699
700 return FALSE;
701 }
702
703 /*---------------------------------------------------------------------------*
704 Name: THPSimpleAudioStart
705
706 Description: Allow mixing of audio data using THPSimpleAudioOutput.
707
708 Arguments: None
709
710 Returns: None
711 *---------------------------------------------------------------------------*/
712
THPSimpleAudioStart(void)713 void THPSimpleAudioStart(void)
714 {
715 SimpleControl.audioState = TRUE;
716
717 return;
718 }
719
720 /*---------------------------------------------------------------------------*
721 Name: THPSimpleAudioStop
722
723 Description: Prohibit mixing of audio data using THPSimpleAudioOutput.
724
725 Arguments: None
726
727 Returns: None
728 *---------------------------------------------------------------------------*/
729
THPSimpleAudioStop(void)730 void THPSimpleAudioStop(void)
731 {
732 SimpleControl.audioState = FALSE;
733
734 return;
735 }
736
737 /*---------------------------------------------------------------------------*
738 Name: THPSimpleLoadStop
739
740 Description: Stop preloading of movie.
741
742 Arguments: None
743
744 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
745 *---------------------------------------------------------------------------*/
746
THPSimpleLoadStop(void)747 BOOL THPSimpleLoadStop(void)
748 {
749 s32 i;
750
751 if (SimpleControl.open && (SimpleControl.audioState == FALSE))
752 {
753 SimpleControl.preFetchState = FALSE;
754
755 // Cancel process if read in progress
756 if (SimpleControl.readProgress)
757 {
758 DVDCancel(&SimpleControl.fileInfo.cb);
759 SimpleControl.readProgress = FALSE;
760 }
761
762 // Intitialize SimpleControl structure members
763 for (i = 0 ; i < READ_BUFFER_NUM ; i++)
764 {
765 SimpleControl.readBuffer[i].isValid = 0;
766 }
767
768 for (i = 0 ; i < AUDIO_BUFFER_NUM ; i++)
769 {
770 SimpleControl.audioBuffer[i].validSample = 0;
771 }
772
773 SimpleControl.textureSet.frameNumber = -1;
774 SimpleControl.curOffset = (s32)SimpleControl.header.movieDataOffsets;
775 SimpleControl.readSize = (s32)SimpleControl.header.firstFrameSize;
776 SimpleControl.readIndex = 0;
777 SimpleControl.totalReadFrame = 0;
778 SimpleControl.dvdError = FALSE;
779 SimpleControl.nextDecodeIndex = 0;
780 SimpleControl.audioDecodeIndex = 0;
781 SimpleControl.audioOutputIndex = 0;
782 SimpleControl.curVolume = SimpleControl.targetVolume;
783 SimpleControl.rampCount = 0;
784
785 return TRUE;
786 }
787
788 return FALSE;
789 }
790
791 /*---------------------------------------------------------------------------*
792 Name: THPSimpleDecode
793
794 Description: Decode THP frame data.
795 If the THP movie has no audio, the audioTrack argument
796 is ignored.
797
798 Arguments: audioTrack Specifies audio track number to be decoded.
799
800 Returns: If successful: THP_DECODE_OK.
801 If failed to decode THP video data: THP_VIDEO_DECODE_FAIL.
802 If no data in read buffer: THP_NO_READ_BUFFER.
803 If no open audio buffer: THP_NO_AUDIO_BUFFER.
804 If specified audio track number is invalid:
805 THP_INVALID_AUDIO_TRACK.
806 *---------------------------------------------------------------------------*/
807
THPSimpleDecode(s32 audioTrack)808 s32 THPSimpleDecode(s32 audioTrack)
809 {
810 BOOL old;
811 u32 i;
812 u8 *ptr;
813 u32 *compSizePtr, sample;
814 s32 flag;
815
816 // Is load for buffer to be decoded complete?
817 if (BUFFER_VALID(SimpleControl.nextDecodeIndex))
818 {
819 compSizePtr = (u32 *)(GET_DECODE_BUFFER(SimpleControl) + 8);
820 ptr = GET_DECODE_BUFFER(SimpleControl) + SimpleControl.compInfo.numComponents * 4
821 + 8;
822
823 if (SimpleControl.audioExist)
824 {
825 if (audioTrack < 0 || audioTrack >= SimpleControl.audioInfo.sndNumTracks)
826 {
827 #ifdef _DEBUG
828 OSReport("Specified audio track number is invalid\n");
829 #endif
830 return THP_INVALID_AUDIO_TRACK;
831 }
832
833 // Is audio buffer free?
834 if (SimpleControl.audioBuffer[SimpleControl.audioDecodeIndex].validSample == 0)
835 {
836 for (i = 0 ; i < SimpleControl.compInfo.numComponents ; i++)
837 {
838 switch (SimpleControl.compInfo.frameComp[i])
839 {
840 // Decode THP video data
841 case THP_VIDEO_COMP:
842 if (VideoDecode(ptr) == FALSE)
843 {
844 return THP_VIDEO_DECODE_FAIL;
845 }
846 break;
847 // Decode THP audio data
848 case THP_AUDIO_COMP:
849 flag = THP_AUDIO_INTERLEAVE;
850 sample = THPAudioDecode(SimpleControl.audioBuffer[SimpleControl.audioDecodeIndex].buffer,
851 ptr + (*compSizePtr) * audioTrack,
852 flag);
853 old = OSDisableInterrupts();
854 // Record decode sample number
855 SimpleControl.audioBuffer[SimpleControl.audioDecodeIndex].validSample = sample;
856 // Set pointer used during playback
857 SimpleControl.audioBuffer[SimpleControl.audioDecodeIndex].curPtr
858 = SimpleControl.audioBuffer[SimpleControl.audioDecodeIndex].buffer;
859 OSRestoreInterrupts(old);
860 SimpleControl.audioDecodeIndex++;
861 if (SimpleControl.audioDecodeIndex >= AUDIO_BUFFER_NUM)
862 {
863 SimpleControl.audioDecodeIndex = 0;
864 }
865 break;
866 }
867 ptr += *compSizePtr;
868 compSizePtr++;
869 }
870 }
871 else
872 {
873 #ifdef _DEBUG
874 OSReport("Cannot decode. There is no free audio buffer\n");
875 #endif
876 return THP_NO_AUDIO_BUFFER;
877 }
878 }
879 else
880 {
881 for (i = 0 ; i < SimpleControl.compInfo.numComponents ; i++)
882 {
883 switch (SimpleControl.compInfo.frameComp[i])
884 {
885 // Decode THP video data
886 case THP_VIDEO_COMP:
887 if (VideoDecode(ptr) == FALSE)
888 {
889 return THP_VIDEO_DECODE_FAIL;
890 }
891 break;
892 }
893 ptr += *compSizePtr;
894 compSizePtr++;
895 }
896 }
897
898 SimpleControl.readBuffer[SimpleControl.nextDecodeIndex].isValid = FALSE;
899 SimpleControl.nextDecodeIndex = NEXT_BUFFER(SimpleControl.nextDecodeIndex);
900
901 // Check if preload is stopped
902 CheckPrefetch();
903
904 return THP_DECODE_OK;
905 }
906
907 #ifdef _DEBUG
908 OSReport("Cannot decode. There is no valid buffer\n");
909 #endif
910
911 return THP_NO_READ_BUFFER;
912 }
913
914 /*---------------------------------------------------------------------------*
915 Name: VideoDecode
916
917 Description: Decode THP video data
918
919 Arguments: videoFrame Pointer to THP video frame
920
921 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
922 *---------------------------------------------------------------------------*/
923
VideoDecode(u8 * videoFrame)924 static BOOL VideoDecode(u8 *videoFrame)
925 {
926 s32 ret;
927
928 ret = THPVideoDecode(videoFrame,
929 SimpleControl.textureSet.ytexture,
930 SimpleControl.textureSet.utexture,
931 SimpleControl.textureSet.vtexture,
932 SimpleControl.thpWork);
933
934 if (ret == THP_OK)
935 {
936 SimpleControl.textureSet.frameNumber
937 = SimpleControl.readBuffer[SimpleControl.nextDecodeIndex].frameNumber;
938
939 return TRUE;
940 }
941
942 return FALSE;
943 }
944
945 /*---------------------------------------------------------------------------*
946 Name: THPSimpleDrawCurrentFrame
947
948 Description: Render decoded THP video data
949
950 Arguments: rmode Pointer for currently set GXRenderModeObj
951 x Upper left x coordinate of TV screen for movie
952 display.
953 y Upper left y coordinate of TV screen for movie
954 display.
955 polygonW Width of polygon for movie display
956 polygonH Height of polygon for movie display
957
958 Returns: If able to draw, returns drawn frame #. If unable to draw,
959 returns -1.
960 *---------------------------------------------------------------------------*/
961
THPSimpleDrawCurrentFrame(GXRenderModeObj * rmode,u32 x,u32 y,u32 polygonW,u32 polygonH)962 s32 THPSimpleDrawCurrentFrame(GXRenderModeObj *rmode, u32 x, u32 y, u32 polygonW, u32 polygonH)
963 {
964 if (SimpleControl.textureSet.frameNumber >= 0)
965 {
966 THPGXYuv2RgbSetup(rmode);
967 THPGXYuv2RgbDraw( SimpleControl.textureSet.ytexture,
968 SimpleControl.textureSet.utexture,
969 SimpleControl.textureSet.vtexture,
970 (s16)x, (s16)y,
971 (s16)SimpleControl.videoInfo.xSize, (s16)SimpleControl.videoInfo.ySize,
972 (s16)polygonW, (s16)polygonH);
973 THPGXRestore();
974
975 return (s32)SimpleControl.textureSet.frameNumber;
976 }
977
978 return -1;
979 }
980
981 /*---------------------------------------------------------------------------*
982 Name: MixAudio
983
984 Description: Mix THP audio data in the specified buffer
985
986 Arguments: destination Buffer in which mixed data is stored
987 source Output buffer from audio library
988 sample Sample number of audio data to be mixed. Specified by stereo sample.
989
990 Returns: Sample number mixed.
991 *---------------------------------------------------------------------------*/
992
MixAudio(s16 * destination,s16 * source,u32 sample)993 static void MixAudio(s16 *destination, s16 *source, u32 sample)
994 {
995 u32 sampleNum, requestSample, i;
996 s32 rmix, lmix;
997 s16 *dst, *libsrc, *thpsrc;
998 u16 attenuation;
999
1000 // When mix with audio library output
1001 if (source)
1002 {
1003 if (SimpleControl.open && (SimpleControl.audioState == TRUE) && SimpleControl.audioExist)
1004 {
1005 requestSample = sample;
1006 dst = destination;
1007 libsrc = source;
1008
1009 while (1)
1010 {
1011 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample)
1012 {
1013 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample >= requestSample)
1014 {
1015 sampleNum = requestSample;
1016 }
1017 else
1018 {
1019 sampleNum = SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample;
1020 }
1021
1022 thpsrc = SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].curPtr;
1023
1024 // Mixing
1025 for (i = 0 ; i < sampleNum ; i++)
1026 {
1027 if (SimpleControl.rampCount)
1028 {
1029 SimpleControl.rampCount--;
1030 SimpleControl.curVolume += SimpleControl.deltaVolume;
1031 }
1032 else
1033 {
1034 SimpleControl.curVolume = SimpleControl.targetVolume;
1035 }
1036
1037 attenuation = VolumeTable[(s32)SimpleControl.curVolume];
1038
1039 // Right
1040 rmix = (attenuation * (*thpsrc)) >> 15;
1041 thpsrc++;
1042
1043 // Left
1044 lmix = (attenuation * (*thpsrc)) >> 15;
1045 thpsrc++;
1046
1047 // monaural convert
1048 if (SimpleControl.soundMode == THP_SOUND_MODE_MONO)
1049 {
1050 // (L + R) / 2
1051 rmix += lmix;
1052 rmix += 1;
1053 rmix >>= 1;
1054 lmix = rmix;
1055 }
1056
1057 // Right
1058 rmix += *libsrc;
1059 libsrc++;
1060
1061 if (rmix < -32768)
1062 {
1063 rmix = -32768;
1064 }
1065
1066 else if (rmix > 32767)
1067 {
1068 rmix = 32767;
1069 }
1070
1071 *dst = (s16)rmix;
1072 dst++;
1073
1074 // Left
1075 lmix += *libsrc;
1076 libsrc++;
1077
1078 if (lmix < -32768)
1079 {
1080 lmix = -32768;
1081 }
1082
1083 else if (lmix > 32767)
1084 {
1085 lmix = 32767;
1086 }
1087
1088 *dst = (s16)lmix;
1089 dst++;
1090 }
1091
1092 requestSample -= sampleNum;
1093
1094 SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample -= sampleNum;
1095 SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].curPtr = thpsrc;
1096
1097 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample == 0)
1098 {
1099 SimpleControl.audioOutputIndex++;
1100 if (SimpleControl.audioOutputIndex >= AUDIO_BUFFER_NUM)
1101 {
1102 SimpleControl.audioOutputIndex = 0;
1103 }
1104 }
1105
1106 if (!requestSample)
1107 {
1108 break;
1109 }
1110 }
1111 else
1112 {
1113 memcpy(dst, libsrc, requestSample << 2);
1114 break;
1115 }
1116 }
1117 }
1118 else
1119 {
1120 memcpy(destination, source, sample << 2);
1121 }
1122 }
1123 else
1124 {
1125 if (SimpleControl.open && (SimpleControl.audioState == TRUE) && SimpleControl.audioExist)
1126 {
1127 requestSample = sample;
1128 dst = destination;
1129
1130 while (1)
1131 {
1132 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample)
1133 {
1134 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample >= requestSample)
1135 {
1136 sampleNum = requestSample;
1137 }
1138 else
1139 {
1140 sampleNum = SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample;
1141 }
1142
1143 thpsrc = SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].curPtr;
1144
1145 // Mixing
1146 for (i = 0 ; i < sampleNum ; i++)
1147 {
1148 if (SimpleControl.rampCount)
1149 {
1150 SimpleControl.rampCount--;
1151 SimpleControl.curVolume += SimpleControl.deltaVolume;
1152 }
1153 else
1154 {
1155 SimpleControl.curVolume = SimpleControl.targetVolume;
1156 }
1157
1158 attenuation = VolumeTable[(s32)SimpleControl.curVolume];
1159
1160 // Right
1161 rmix = (attenuation * (*thpsrc)) >> 15;
1162 thpsrc++;
1163
1164 // Left
1165 lmix = (attenuation * (*thpsrc)) >> 15;
1166 thpsrc++;
1167
1168 // monaural convert
1169 if (SimpleControl.soundMode == THP_SOUND_MODE_MONO)
1170 {
1171 // (L + R) / 2
1172 rmix += lmix;
1173 rmix += 1;
1174 rmix >>= 1;
1175 lmix = rmix;
1176 }
1177
1178 // Right
1179 if (rmix < -32768)
1180 {
1181 rmix = -32768;
1182 }
1183
1184 else if (rmix > 32767)
1185 {
1186 rmix = 32767;
1187 }
1188
1189 *dst = (s16)rmix;
1190 dst++;
1191
1192 // Left
1193 if (lmix < -32768)
1194 {
1195 lmix = -32768;
1196 }
1197
1198 else if (lmix > 32767)
1199 {
1200 lmix = 32767;
1201 }
1202
1203 *dst = (s16)lmix;
1204 dst++;
1205 }
1206
1207 requestSample -= sampleNum;
1208
1209 SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample -= sampleNum;
1210 SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].curPtr = thpsrc;
1211
1212 if (SimpleControl.audioBuffer[SimpleControl.audioOutputIndex].validSample == 0)
1213 {
1214 SimpleControl.audioOutputIndex++;
1215 if (SimpleControl.audioOutputIndex >= AUDIO_BUFFER_NUM)
1216 {
1217 SimpleControl.audioOutputIndex = 0;
1218 }
1219 }
1220
1221 if (!requestSample)
1222 {
1223 break;
1224 }
1225 }
1226 else
1227 {
1228 memset(dst, 0, requestSample << 2);
1229 break;
1230 }
1231 }
1232 }
1233 else
1234 {
1235 memset(destination, 0, sample << 2);
1236 }
1237 }
1238
1239 return;
1240 }
1241
1242 /*---------------------------------------------------------------------------*
1243 Name: THPSimpleGetVideoInfo
1244
1245 Description: Acquire THP movie video data
1246
1247 Arguments: videoInfo Pointer for THPVideoInfo structure
1248
1249 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
1250 *---------------------------------------------------------------------------*/
1251
THPSimpleGetVideoInfo(THPVideoInfo * videoInfo)1252 BOOL THPSimpleGetVideoInfo(THPVideoInfo *videoInfo)
1253 {
1254 if (SimpleControl.open)
1255 {
1256 memcpy(videoInfo, &SimpleControl.videoInfo, sizeof(THPVideoInfo));
1257
1258 return TRUE;
1259 }
1260
1261 return FALSE;
1262 }
1263
1264 /*---------------------------------------------------------------------------*
1265 Name: THPSimpleGetAudioInfo
1266
1267 Description: Acquire THP movie audio data
1268
1269 Arguments: audioInfo Pointer for THPAudioInfo structure
1270
1271 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
1272 *---------------------------------------------------------------------------*/
1273
THPSimpleGetAudioInfo(THPAudioInfo * audioInfo)1274 BOOL THPSimpleGetAudioInfo(THPAudioInfo *audioInfo)
1275 {
1276 if (SimpleControl.open)
1277 {
1278 memcpy(audioInfo, &SimpleControl.audioInfo, sizeof(THPAudioInfo));
1279
1280 return TRUE;
1281 }
1282
1283 return FALSE;
1284 }
1285
1286 /*---------------------------------------------------------------------------*
1287 Name: THPSimpleGetFrameRate
1288
1289 Description: Acquire THP movie frame rate
1290
1291 Arguments: None
1292
1293 Returns: If successful, returns THP file frame rate. If unsuccessful,
1294 returns 0.0f.
1295 *---------------------------------------------------------------------------*/
1296
THPSimpleGetFrameRate(void)1297 f32 THPSimpleGetFrameRate(void)
1298 {
1299 if (SimpleControl.open)
1300 {
1301
1302 return SimpleControl.header.frameRate;
1303 }
1304
1305 return 0.0f;
1306 }
1307
1308 /*---------------------------------------------------------------------------*
1309 Name: THPSimpleGetTotalFrame
1310
1311 Description: Acquire total frame number of THP movie.
1312
1313 Arguments: None
1314
1315 Returns: If successful, returns total frame number of THP file.
1316 If unsuccessful, returns 0.
1317 *---------------------------------------------------------------------------*/
1318
THPSimpleGetTotalFrame(void)1319 u32 THPSimpleGetTotalFrame(void)
1320 {
1321 if (SimpleControl.open)
1322 {
1323 return SimpleControl.header.numFrames;
1324 }
1325
1326 return 0;
1327 }
1328
1329 /*---------------------------------------------------------------------------*
1330 Name: THPAudioMixCallback
1331
1332 Description: AI callback function for player.
1333 Call callback functions of AX and MusyX internally when
1334 used with AX and MusyX, and mix output data of AX and
1335 MusyX with THP audio data.
1336
1337 Arguments: None
1338
1339 Returns: None
1340 *---------------------------------------------------------------------------*/
1341
THPAudioMixCallback(void)1342 static void THPAudioMixCallback(void)
1343 {
1344 BOOL old;
1345
1346 if (AudioSystem == THP_MODE_ALONE)
1347 {
1348 SoundBufferIndex ^= 1;
1349
1350 AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1351
1352 old = OSEnableInterrupts();
1353
1354 MixAudio(SoundBuffer[SoundBufferIndex], NULL, SAMPLES_PER_AUDIO_FRAME);
1355
1356 DCFlushRange(SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1357
1358 OSRestoreInterrupts(old);
1359 }
1360 else
1361 {
1362 if (AudioSystem == THP_MODE_WITH_AX)
1363 {
1364 if (LastAudioBuffer)
1365 {
1366 CurAudioBuffer = LastAudioBuffer;
1367 }
1368
1369 OldAIDCallback();
1370
1371 LastAudioBuffer = (s16 *)OSPhysicalToCached(AIGetDMAStartAddr());
1372 }
1373 else
1374 {
1375 OldAIDCallback();
1376
1377 CurAudioBuffer = (s16 *)OSPhysicalToCached(AIGetDMAStartAddr());
1378 }
1379
1380 SoundBufferIndex ^= 1;
1381
1382 AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1383
1384 old = OSEnableInterrupts();
1385
1386 if (CurAudioBuffer)
1387 {
1388 DCInvalidateRange(CurAudioBuffer, BYTES_PER_AUDIO_FRAME);
1389 }
1390
1391 MixAudio(SoundBuffer[SoundBufferIndex], CurAudioBuffer, SAMPLES_PER_AUDIO_FRAME);
1392
1393 DCFlushRange(SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1394
1395 OSRestoreInterrupts(old);
1396 }
1397 }
1398
1399 /*---------------------------------------------------------------------------*
1400 Name: THPSimpleSetVolume
1401
1402 Description: Set volume for player. Volume will be changed in the
1403 specified time.
1404
1405 Arguments: vol volume to be set (0 - 127)
1406 time Specify the time required to go from current volume to
1407 specified volume in units of milliseconds (0 - 60000)
1408
1409 Returns: If successful, returns TRUE. If unsuccessful, returns FALSE.
1410 *---------------------------------------------------------------------------*/
1411
THPSimpleSetVolume(s32 vol,s32 time)1412 BOOL THPSimpleSetVolume(s32 vol, s32 time)
1413 {
1414 BOOL old;
1415 s32 samplePerMs;
1416
1417 if (SimpleControl.open && SimpleControl.audioExist)
1418 {
1419 if (AIGetDSPSampleRate() == AI_SAMPLERATE_32KHZ)
1420 {
1421 samplePerMs = 32;
1422 }
1423 else
1424 {
1425 samplePerMs = 48;
1426 }
1427
1428 if (vol > 127)
1429 {
1430 vol = 127;
1431 }
1432
1433 if (vol < 0)
1434 {
1435 vol = 0;
1436 }
1437
1438 if (time > 60000)
1439 {
1440 time = 60000;
1441 }
1442
1443 if (time < 0)
1444 {
1445 time = 0;
1446 }
1447
1448 old = OSDisableInterrupts();
1449
1450 SimpleControl.targetVolume = (f32)vol;
1451
1452 if (time)
1453 {
1454 SimpleControl.rampCount = samplePerMs * time;
1455 SimpleControl.deltaVolume = (SimpleControl.targetVolume - SimpleControl.curVolume)
1456 / (f32)SimpleControl.rampCount;
1457 }
1458 else
1459 {
1460 SimpleControl.rampCount = 0;
1461 SimpleControl.curVolume = SimpleControl.targetVolume;
1462 }
1463
1464 OSRestoreInterrupts(old);
1465
1466 return TRUE;
1467 }
1468
1469 return FALSE;
1470 }
1471
1472 /*---------------------------------------------------------------------------*
1473 Name: THPSimpleGetVolume
1474
1475 Description: Acquire current volume of player
1476
1477 Arguments: None
1478
1479 Returns: Returns current playback volume if successful, and -1 if
1480 unsuccessful.
1481 *---------------------------------------------------------------------------*/
1482
THPSimpleGetVolume(void)1483 s32 THPSimpleGetVolume(void)
1484 {
1485 if (SimpleControl.open)
1486 {
1487 return (s32)SimpleControl.curVolume;
1488 }
1489
1490 return -1;
1491 }
1492
1493 /*---------------------------------------------------------------------------*
1494 Name: THPSimpleSetSoundMode
1495
1496 Description: Set sound mode
1497
1498 Arguments: mode sound mode (MONO/STEREO/SURROUND/DPL2)
1499
1500 Returns: none.
1501 *---------------------------------------------------------------------------*/
1502
THPSimpleSetSoundMode(s32 mode)1503 void THPSimpleSetSoundMode(s32 mode)
1504 {
1505 ASSERT(mode >= THP_SOUND_MODE_MONO && mode <= THP_SOUND_MODE_DPL2);
1506
1507 if (mode >= THP_SOUND_MODE_MONO && mode <= THP_SOUND_MODE_DPL2)
1508 {
1509 SimpleControl.soundMode = mode;
1510 }
1511 }
1512
1513 /*---------------------------------------------------------------------------*
1514 Name: THPSimpleGetSoundMode
1515
1516 Description: Get current sound mode
1517
1518 Arguments: none.
1519
1520 Returns: sound mode (MONO/STEREO/SURROUND/DPL2)
1521 *---------------------------------------------------------------------------*/
1522
THPSimpleGetSoundMode(void)1523 s32 THPSimpleGetSoundMode(void)
1524 {
1525 return SimpleControl.soundMode;
1526 }
1527