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
[2][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
++)
152 DCFlushRangeNoSync(data
,len
);
153 LWP_ThreadSignal(thQueue
);
159 static __inline__ s32
buf_put(struct _outbuffer_s
*buf
,void *data
,s32 len
)
164 while(len
>buf_space(buf
))
165 LWP_ThreadSleep(thQueue
);
168 cnt
= ((u32
)buf
->bs
+ DATABUFFER_SIZE
- (u32
)buf
->put
);
170 for(i
=0;i
<(cnt
>>2);i
++)
173 for(i
=0;i
<((len
-cnt
)>>2);i
++)
176 for(i
=0;i
<(len
>>2);i
++)
180 if(buf
->buf_filled
==0 && buf_used(buf
)>=(DATABUFFER_SIZE
>>1)) {
182 memset(OutputBuffer
[CurrentBuffer
],0,ADMA_BUFFERSIZE
);
185 DCFlushRange(OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
186 AUDIO_InitDMA((u32
)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
190 SND_SetVoice(0,VOICE_STEREO_16BIT
,48000,0,(void*)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
,mp3_volume
,mp3_volume
,DataTransferCallback
);
199 static s32
_mp3ramcopy(void *usr_data
,void *buffer
,s32 len
)
201 struct _rambuffer
*ram
= (struct _rambuffer
*)usr_data
;
202 const void *ptr
= ((u8
*)ram
->buf_addr
+ram
->pos
);
204 if((ram
->pos
+len
)>ram
->len
) {
205 len
= (ram
->len
- ram
->pos
);
209 memcpy(buffer
,ptr
,len
);
215 void MP3Player_Init()
221 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ
);
229 s32
MP3Player_PlayBuffer(const void *buffer
,s32 len
,void (*filterfunc
)(struct mad_stream
*,struct mad_frame
*))
231 if(thr_running
==TRUE
) return -1;
233 rambuffer
.buf_addr
= buffer
;
237 mp3cb_data
= &rambuffer
;
238 mp3read
= _mp3ramcopy
;
239 mp3filterfunc
= filterfunc
;
240 if(LWP_CreateThread(&hStreamPlay
,StreamPlay
,NULL
,StreamPlay_Stack
,STACKSIZE
,80)<0) {
246 s32
MP3Player_PlayFile(void *cb_data
,s32 (*reader
)(void *,void *,s32
),void (*filterfunc
)(struct mad_stream
*,struct mad_frame
*))
248 if(thr_running
==TRUE
) return -1;
250 mp3cb_data
= cb_data
;
252 mp3filterfunc
= filterfunc
;
253 if(LWP_CreateThread(&hStreamPlay
,StreamPlay
,NULL
,StreamPlay_Stack
,STACKSIZE
,80)<0) {
259 void MP3Player_Stop()
261 if(thr_running
==FALSE
) return;
264 LWP_JoinThread(hStreamPlay
,NULL
);
267 BOOL
MP3Player_IsPlaying()
272 static void *StreamPlay(void *arg
)
276 struct mad_stream Stream
;
277 struct mad_frame Frame
;
278 struct mad_synth Synth
;
285 memset(OutputBuffer
[0],0,ADMA_BUFFERSIZE
);
286 memset(OutputBuffer
[1],0,ADMA_BUFFERSIZE
);
288 buf_init(&OutputRingBuffer
);
289 LWP_InitQueue(&thQueue
);
290 Init3BandState(&eqs
[0],880,5000,48000);
291 Init3BandState(&eqs
[1],880,5000,48000);
294 AUDIO_RegisterDMACallback(DataTransferCallback
);
297 mad_stream_init(&Stream
);
298 mad_frame_init(&Frame
);
299 mad_synth_init(&Synth
);
300 mad_timer_reset(&Timer
);
304 while(atend
==FALSE
&& thr_running
==TRUE
) {
305 if(Stream
.buffer
==NULL
|| Stream
.error
==MAD_ERROR_BUFLEN
) {
307 s32 ReadSize
, Remaining
;
309 if(Stream
.next_frame
!=NULL
) {
310 Remaining
= Stream
.bufend
- Stream
.next_frame
;
311 memmove(InputBuffer
,Stream
.next_frame
,Remaining
);
312 ReadStart
= InputBuffer
+ Remaining
;
313 ReadSize
= DATABUFFER_SIZE
- Remaining
;
315 ReadSize
= DATABUFFER_SIZE
;
316 ReadStart
= InputBuffer
;
321 ReadSize
= mp3read(mp3cb_data
,ReadStart
,ReadSize
);
323 GuardPtr
= ReadStart
;
324 memset(GuardPtr
,0,MAD_BUFFER_GUARD
);
325 ReadSize
= MAD_BUFFER_GUARD
;
329 mad_stream_buffer(&Stream
,InputBuffer
,(ReadSize
+ Remaining
));
333 if(mad_frame_decode(&Frame
,&Stream
)) {
334 if(MAD_RECOVERABLE(Stream
.error
)) {
335 if(Stream
.error
!=MAD_ERROR_LOSTSYNC
336 || Stream
.this_frame
!=GuardPtr
) continue;
338 if(Stream
.error
!=MAD_ERROR_BUFLEN
) break;
343 mp3filterfunc(&Stream
,&Frame
);
345 mad_timer_add(&Timer
,Frame
.header
.duration
);
346 mad_synth_frame(&Synth
,&Frame
);
348 Resample(&Synth
.pcm
,eqs
,(MAD_NCHANNELS(&Frame
.header
)==2),Frame
.header
.samplerate
);
351 mad_synth_finish(&Synth
);
352 mad_frame_finish(&Frame
);
353 mad_stream_finish(&Stream
);
355 while(MP3Playing
==TRUE
)
356 LWP_ThreadSleep(thQueue
);
360 AUDIO_RegisterDMACallback(NULL
);
365 LWP_CloseQueue(thQueue
);
380 static void Resample(struct mad_pcm
*Pcm
,EQState eqs
[2],u32 stereo
,u32 src_samplerate
)
388 incr
= (u32
)(((f32
)src_samplerate
/48000.0F
)*65536.0F
);
389 while(pos
.aword
.hi
<Pcm
->length
) {
390 val16
= Do3Band(&eqs
[0],FixedToShort(Pcm
->samples
[0][pos
.aword
.hi
]));
393 if(stereo
) val16
= Do3Band(&eqs
[1],FixedToShort(Pcm
->samples
[1][pos
.aword
.hi
]));
396 buf_put(&OutputRingBuffer
,&val32
,sizeof(u32
));
401 static void Init3BandState(EQState
*es
,s32 lowfreq
,s32 highfreq
,s32 mixfreq
)
403 memset(es
,0,sizeof(EQState
));
409 es
->lf
= 2.0F
*sinf(M_PI
*((f32
)lowfreq
/(f32
)mixfreq
));
410 es
->hf
= 2.0F
*sinf(M_PI
*((f32
)highfreq
/(f32
)mixfreq
));
413 static s16
Do3Band(EQState
*es
,s16 sample
)
417 es
->f1p0
+= (es
->lf
*((f32
)sample
- es
->f1p0
))+VSA
;
418 es
->f1p1
+= (es
->lf
*(es
->f1p0
- es
->f1p1
));
419 es
->f1p2
+= (es
->lf
*(es
->f1p1
- es
->f1p2
));
420 es
->f1p3
+= (es
->lf
*(es
->f1p2
- es
->f1p3
));
423 es
->f2p0
+= (es
->hf
*((f32
)sample
- es
->f2p0
))+VSA
;
424 es
->f2p1
+= (es
->hf
*(es
->f2p0
- es
->f2p1
));
425 es
->f2p2
+= (es
->hf
*(es
->f2p1
- es
->f2p2
));
426 es
->f2p3
+= (es
->hf
*(es
->f2p2
- es
->f2p3
));
427 h
= es
->sdm3
- es
->f2p3
;
429 m
= es
->sdm3
- (h
+l
);
437 es
->sdm1
= (f32
)sample
;
442 static void DataTransferCallback()
446 AUDIO_InitDMA((u32
)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
);
450 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
452 if(thr_running
!=TRUE
) {
453 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
456 if(have_samples
==1) {
457 if(SND_AddVoice(0,(void*)OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)==SND_OK
) {
462 if(!(SND_TestPointer(0,(void*)OutputBuffer
[CurrentBuffer
]) && SND_StatusVoice(0)!=SND_UNUSED
)) {
463 if(have_samples
==0) {
464 MP3Playing
= (buf_get(&OutputRingBuffer
,OutputBuffer
[CurrentBuffer
],ADMA_BUFFERSIZE
)>0);
471 void MP3Player_Volume(u32 volume
)
473 if(volume
>255) volume
= 255;
477 SND_ChangeVolumeVoice(0,volume
,volume
);