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