1 /***************************************************************************
2 * Low Level MAD Library Implementation for the GameCube *
3 * By Daniel "nForce" Bloemendal *
4 * nForce@Sympatico.ca *
5 ***************************************************************************/
6 // Modified by Hermes to include SNDLIB / ASNDLIB support
22 #include "mp3player.h"
24 static s32 have_samples
= 0;
25 static u32 mp3_volume
= 255;
28 #define ADMA_BUFFERSIZE (4992)
30 #define ADMA_BUFFERSIZE (8192)
32 #define STACKSIZE (32768)
34 #define DATABUFFER_SIZE (32768)
36 typedef struct _eqstate_s
64 u8 buffer
[DATABUFFER_SIZE
];
67 static u8 InputBuffer
[DATABUFFER_SIZE
+MAD_BUFFER_GUARD
];
68 static u8 OutputBuffer
[3][ADMA_BUFFERSIZE
] ATTRIBUTE_ALIGN(32);
69 static struct _outbuffer_s OutputRingBuffer
;
71 static u32 init_done
= 0;
72 static u32 CurrentBuffer
= 0;
73 static f32 VSA
= (1.0/4294967295.0);
74 static BOOL thr_running
= FALSE
;
75 static BOOL MP3Playing
= FALSE
;
76 static void *mp3cb_data
= NULL
;
78 static void* StreamPlay(void *);
79 static u8 StreamPlay_Stack
[STACKSIZE
];
80 static lwp_t hStreamPlay
;
81 static lwpq_t thQueue
;
83 static s32 (*mp3read
)(void*,void *,s32
);
84 static void (*mp3filterfunc
)(struct mad_stream
*,struct mad_frame
*);
86 static void DataTransferCallback();
87 static void Init3BandState(EQState
*es
,s32 lowfreq
,s32 highfreq
,s32 mixfreq
);
88 static s16
Do3Band(EQState
*es
,s16 sample
);
89 static void Resample(struct mad_pcm
*Pcm
,EQState eqs
[2],u32 stereo
,u32 src_samplerate
);
97 static __inline__ s16
FixedToShort(mad_fixed_t Fixed
)
102 if(Fixed
<=-MAD_F_ONE
)
105 Fixed
=Fixed
>>(MAD_F_FRACBITS
-15);
109 static __inline__
void buf_init(struct _outbuffer_s
*buf
)
112 buf
->bs
= buf
->buffer
;
113 buf
->put
= buf
->get
= buf
->bs
;
116 static __inline__ s32
buf_used(struct _outbuffer_s
*buf
)
118 return ((DATABUFFER_SIZE
+ ((u32
)buf
->put
- (u32
)buf
->get
)) % DATABUFFER_SIZE
);
121 static __inline__ s32
buf_space(struct _outbuffer_s
*buf
)
123 return ((DATABUFFER_SIZE
- ((u32
)buf
->put
- (u32
)buf
->get
) - 1) % DATABUFFER_SIZE
);
126 static __inline__ s32
buf_get(struct _outbuffer_s
*buf
,void *data
,s32 len
)
131 if(len
>buf_used(buf
))
135 LWP_ThreadSignal(thQueue
);
140 cnt
= ((u32
)buf
->bs
+ DATABUFFER_SIZE
- (u32
)buf
->get
);
142 for(i
=0;i
<(cnt
>>2);i
++)
145 for(i
=0;i
<((len
-cnt
)>>2);i
++)
148 for(i
=0;i
<(len
>>2);i
++)
153 DCFlushRangeNoSync(data
,len
);
155 LWP_ThreadSignal(thQueue
);
162 static __inline__ s32
buf_put(struct _outbuffer_s
*buf
,void *data
,s32 len
)
167 while(len
>buf_space(buf
))
168 LWP_ThreadSleep(thQueue
);
171 cnt
= ((u32
)buf
->bs
+ DATABUFFER_SIZE
- (u32
)buf
->put
);
173 for(i
=0;i
<(cnt
>>2);i
++)
176 for(i
=0;i
<((len
-cnt
)>>2);i
++)
179 for(i
=0;i
<(len
>>2);i
++)
183 if(buf
->buf_filled
==0 && buf_used(buf
)>=(DATABUFFER_SIZE
>>1)) {
185 memset(OutputBuffer
[CurrentBuffer
],0,ADMA_BUFFERSIZE
);
188 DCFlushRange(OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
189 AUDIO_InitDMA((u32
)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
193 SND_SetVoice(0,VOICE_STEREO_16BIT
,48000,0,(void*)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
,mp3_volume
,mp3_volume
,DataTransferCallback
);
196 CurrentBuffer
= (CurrentBuffer
+1)%3;
202 static s32
_mp3ramcopy(void *usr_data
,void *buffer
,s32 len
)
204 struct _rambuffer
*ram
= (struct _rambuffer
*)usr_data
;
205 const void *ptr
= ((u8
*)ram
->buf_addr
+ram
->pos
);
207 if((ram
->pos
+len
)>ram
->len
) {
208 len
= (ram
->len
- ram
->pos
);
212 memcpy(buffer
,ptr
,len
);
218 void MP3Player_Init()
224 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ
);
232 s32
MP3Player_PlayBuffer(const void *buffer
,s32 len
,void (*filterfunc
)(struct mad_stream
*,struct mad_frame
*))
234 if(thr_running
==TRUE
) return -1;
236 rambuffer
.buf_addr
= buffer
;
240 mp3cb_data
= &rambuffer
;
241 mp3read
= _mp3ramcopy
;
242 mp3filterfunc
= filterfunc
;
243 if(LWP_CreateThread(&hStreamPlay
,StreamPlay
,NULL
,StreamPlay_Stack
,STACKSIZE
,80)<0) {
249 s32
MP3Player_PlayFile(void *cb_data
,s32 (*reader
)(void *,void *,s32
),void (*filterfunc
)(struct mad_stream
*,struct mad_frame
*))
251 if(thr_running
==TRUE
) return -1;
253 mp3cb_data
= cb_data
;
255 mp3filterfunc
= filterfunc
;
256 if(LWP_CreateThread(&hStreamPlay
,StreamPlay
,NULL
,StreamPlay_Stack
,STACKSIZE
,80)<0) {
262 void MP3Player_Stop()
264 if(thr_running
==FALSE
) return;
267 LWP_JoinThread(hStreamPlay
,NULL
);
270 BOOL
MP3Player_IsPlaying()
275 static void *StreamPlay(void *arg
)
279 struct mad_stream Stream
;
280 struct mad_frame Frame
;
281 struct mad_synth Synth
;
288 memset(OutputBuffer
[0],0,ADMA_BUFFERSIZE
);
289 memset(OutputBuffer
[1],0,ADMA_BUFFERSIZE
);
290 memset(OutputBuffer
[2],0,ADMA_BUFFERSIZE
);
292 buf_init(&OutputRingBuffer
);
293 LWP_InitQueue(&thQueue
);
294 Init3BandState(&eqs
[0],880,5000,48000);
295 Init3BandState(&eqs
[1],880,5000,48000);
298 AUDIO_RegisterDMACallback(DataTransferCallback
);
301 mad_stream_init(&Stream
);
302 mad_frame_init(&Frame
);
303 mad_synth_init(&Synth
);
304 mad_timer_reset(&Timer
);
308 while(atend
==FALSE
&& thr_running
==TRUE
) {
309 if(Stream
.buffer
==NULL
|| Stream
.error
==MAD_ERROR_BUFLEN
) {
311 s32 ReadSize
, Remaining
;
313 if(Stream
.next_frame
!=NULL
) {
314 Remaining
= Stream
.bufend
- Stream
.next_frame
;
315 memmove(InputBuffer
,Stream
.next_frame
,Remaining
);
316 ReadStart
= InputBuffer
+ Remaining
;
317 ReadSize
= DATABUFFER_SIZE
- Remaining
;
319 ReadSize
= DATABUFFER_SIZE
;
320 ReadStart
= InputBuffer
;
325 ReadSize
= mp3read(mp3cb_data
,ReadStart
,ReadSize
);
327 GuardPtr
= ReadStart
;
328 memset(GuardPtr
,0,MAD_BUFFER_GUARD
);
329 ReadSize
= MAD_BUFFER_GUARD
;
333 mad_stream_buffer(&Stream
,InputBuffer
,(ReadSize
+ Remaining
));
337 if(mad_frame_decode(&Frame
,&Stream
)) {
338 if(MAD_RECOVERABLE(Stream
.error
)) {
339 if(Stream
.error
!=MAD_ERROR_LOSTSYNC
340 || Stream
.this_frame
!=GuardPtr
) continue;
342 if(Stream
.error
!=MAD_ERROR_BUFLEN
) break;
347 mp3filterfunc(&Stream
,&Frame
);
349 mad_timer_add(&Timer
,Frame
.header
.duration
);
350 mad_synth_frame(&Synth
,&Frame
);
352 Resample(&Synth
.pcm
,eqs
,(MAD_NCHANNELS(&Frame
.header
)==2),Frame
.header
.samplerate
);
355 mad_synth_finish(&Synth
);
356 mad_frame_finish(&Frame
);
357 mad_stream_finish(&Stream
);
359 while(MP3Playing
==TRUE
)
360 LWP_ThreadSleep(thQueue
);
364 AUDIO_RegisterDMACallback(NULL
);
369 LWP_CloseQueue(thQueue
);
384 static void Resample(struct mad_pcm
*Pcm
,EQState eqs
[2],u32 stereo
,u32 src_samplerate
)
392 incr
= (u32
)(((f32
)src_samplerate
/48000.0F
)*65536.0F
);
393 while(pos
.aword
.hi
<Pcm
->length
) {
394 val16
= Do3Band(&eqs
[0],FixedToShort(Pcm
->samples
[0][pos
.aword
.hi
]));
397 if(stereo
) val16
= Do3Band(&eqs
[1],FixedToShort(Pcm
->samples
[1][pos
.aword
.hi
]));
400 buf_put(&OutputRingBuffer
,&val32
,sizeof(u32
));
405 static void Init3BandState(EQState
*es
,s32 lowfreq
,s32 highfreq
,s32 mixfreq
)
407 memset(es
,0,sizeof(EQState
));
413 es
->lf
= 2.0F
*sinf(M_PI
*((f32
)lowfreq
/(f32
)mixfreq
));
414 es
->hf
= 2.0F
*sinf(M_PI
*((f32
)highfreq
/(f32
)mixfreq
));
417 static s16
Do3Band(EQState
*es
,s16 sample
)
421 es
->f1p0
+= (es
->lf
*((f32
)sample
- es
->f1p0
))+VSA
;
422 es
->f1p1
+= (es
->lf
*(es
->f1p0
- es
->f1p1
));
423 es
->f1p2
+= (es
->lf
*(es
->f1p1
- es
->f1p2
));
424 es
->f1p3
+= (es
->lf
*(es
->f1p2
- es
->f1p3
));
427 es
->f2p0
+= (es
->hf
*((f32
)sample
- es
->f2p0
))+VSA
;
428 es
->f2p1
+= (es
->hf
*(es
->f2p0
- es
->f2p1
));
429 es
->f2p2
+= (es
->hf
*(es
->f2p1
- es
->f2p2
));
430 es
->f2p3
+= (es
->hf
*(es
->f2p2
- es
->f2p3
));
431 h
= es
->sdm3
- es
->f2p3
;
433 m
= es
->sdm3
- (h
+l
);
441 es
->sdm1
= (f32
)sample
;
446 static void DataTransferCallback()
449 AUDIO_InitDMA((u32
)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
451 CurrentBuffer
= (CurrentBuffer
+1)%3;
452 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
454 if(thr_running
!=TRUE
) {
455 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
458 if(have_samples
==1) {
459 if(SND_AddVoice(0,(void*)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)==SND_OK
) {
461 CurrentBuffer
= (CurrentBuffer
+1)%3;
464 if(!(SND_TestPointer(0,(void*)OutputBuffer
[CurrentBuffer
]) && SND_StatusVoice(0)!=SND_UNUSED
)) {
465 if(have_samples
==0) {
466 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
473 void MP3Player_Volume(u32 volume
)
475 if(volume
>255) volume
= 255;
479 SND_ChangeVolumeVoice(0,volume
,volume
);