fixed MP3 playback

although still plays back far to slow!
also minor refactoring
This commit is contained in:
Robin Jones 2017-11-13 20:22:43 +00:00
parent d52179c4d5
commit 2785f5f50a
5 changed files with 329 additions and 258 deletions

View File

@ -15,7 +15,7 @@ If you want to build the menu, you need an n64 toolchain. When using windows 10
* Windows 10 (Aniversary Update or above) / Ubuntu 16.04 (or above) * Windows 10 (Aniversary Update or above) / Ubuntu 16.04 (or above)
* [libdragon](https://github.com/DragonMinded/libdragon) * [libdragon](https://github.com/DragonMinded/libdragon)
* [libmikmod (with n64 driver)](https://github.com/networkfusion/libmikmod) * [libmikmod (with n64 driver)](https://github.com/networkfusion/libmikmod)
* [libmad-n64](https://github.com/parasyte/libmad-n64) * [libmad-n64](https://github.com/networkfusion/libmad-n64)
* [libyaml](http://pyyaml.org/wiki/LibYAML) * [libyaml](http://pyyaml.org/wiki/LibYAML)
### Build the Toolchain ### Build the Toolchain

View File

@ -129,7 +129,7 @@
#define IO_WRITE(addr,data) (*(volatile u32*)PHYS_TO_K1(addr)=(u32)(data)) #define IO_WRITE(addr,data) (*(volatile u32*)PHYS_TO_K1(addr)=(u32)(data))
#define SAVE_SIZE_SRAM 32768 #define SAVE_SIZE_SRAM 32768
#define SAVE_SIZE_SRAM96 131072 #define SAVE_SIZE_SRAM96 131072 //TODO: or should this be 98304
#define SAVE_SIZE_EEP4k 4096 #define SAVE_SIZE_EEP4k 4096
#define SAVE_SIZE_EEP16k 16384 #define SAVE_SIZE_EEP16k 16384
#define SAVE_SIZE_FLASH 131072 #define SAVE_SIZE_FLASH 131072

View File

@ -141,7 +141,7 @@ u16 cursor_history[32];
u16 cursor_history_pos = 0; u16 cursor_history_pos = 0;
u8 empty = 0; u8 empty = 0;
u8 playing = 0; int mp3playing = 0;
u8 gb_load_y = 0; u8 gb_load_y = 0;
FATFS *fs; FATFS *fs;
@ -850,7 +850,7 @@ void configure()
asm_date = memRomRead32(0x38); //TODO: this should be displayed somewhere... asm_date = memRomRead32(0x38); //TODO: this should be displayed somewhere...
evd_setCfgBit(ED_CFG_SDRAM_ON, 1); evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
firm = evd_readReg(REG_VER); //TODO: why not just use evd_getFirmVersion() firm = evd_getFirmVersion();
if (firm >= 0x0200) if (firm >= 0x0200)
{ {
@ -864,17 +864,20 @@ void configure()
{ {
msg |= 1 << 14; msg |= 1 << 14;
evd_writeReg(REG_MAX_MSG, msg); evd_writeReg(REG_MAX_MSG, msg);
if (firm == 0x0214) //need to take into account different default firmware versions for each ED64 version
{//TODO: use a case statement instead switch(firm) //need to take into account different default firmware versions for each ED64 version
{
case 0x0214:
updateFirmware("/firmware/firmware_v2.bin"); updateFirmware("/firmware/firmware_v2.bin");
} break;
else if (firm == 0x0250) case 0x0250:
{
updateFirmware("/firmware/firmware_v2_5.bin"); updateFirmware("/firmware/firmware_v2_5.bin");
} break;
else if (firm == 0x0300) case 0x0300:
{
updateFirmware("/firmware/firmware_v3.bin"); updateFirmware("/firmware/firmware_v3.bin");
break;
default:
break;
} }
sleep(1); sleep(1);
@ -3171,27 +3174,31 @@ void loadFile(display_context_t disp)
display_show(disp); display_show(disp);
break; break;
case 10: case 10:
{
while (!(disp = display_lock()))
;
clearScreen(disp);
drawShortInfoBox(disp, " Loading...", 0);
display_show(disp);
long long start = 0, end = 0, curr, pause = 0, samples;
int rate = 44100, last_rate = 44100, channels = 2;
audio_init(44100, 4);
buf_size = audio_get_buffer_length() * 4; buf_size = audio_get_buffer_length() * 4;
buf_ptr = malloc(buf_size); buf_ptr = malloc(buf_size);
mp3_Start(name_file, &samples, &rate, &channels);
mp3playing = 1;
select_mode = 9;
while (!(disp = display_lock())) while (!(disp = display_lock()))
; ;
clearScreen(disp); clearScreen(disp);
drawShortInfoBox(disp, " playback", 0); drawShortInfoBox(disp, " MP3 Playback", 0);
long long start = 0, end = 0, curr, pause = 0, samples;
int rate = 44100, last_rate = 44100, channels = 2;
audio_init(44100, 2);
mp3_Start(name_file, &samples, &rate, &channels);
playing = 1;
select_mode = 9;
input_mapping = mp3; //mp3 stop
display_show(disp); display_show(disp);
input_mapping = mp3; //mp3 stop
break; break;
}
default: default:
break; break;
} }
@ -4291,11 +4298,13 @@ void handleInput(display_context_t disp, sprite_t *contr)
break; break;
case mp3: case mp3:
//stop mp3
mp3_Stop(); mp3_Stop();
playing = 0; mp3playing = 0;
audio_close();
free(buf_ptr);
buf_ptr = 0;
clearScreen(disp); //part clear? clearScreen(disp); //part clear?
display_dir(list, cursor, page, MAX_LIST, count, disp); display_dir(list, cursor, page, MAX_LIST, count, disp);
@ -4475,8 +4484,15 @@ int main(void)
handleInput(disp, contr); handleInput(disp, contr);
if (playing == 1) if (mp3playing && audio_can_write())
playing = mp3_Update(buf_ptr, buf_size); {
mp3playing = mp3_Update(buf_ptr, buf_size);
if (mp3playing)
{
audio_write((short *)buf_ptr);
}
}
if (input_mapping == file_manager) if (input_mapping == file_manager)
sleep(60); sleep(60);

311
src/mp3.c
View File

@ -1,6 +1,6 @@
// //
// Copyright (c) 2017 The Altra64 project contributors // Copyright (c) 2017 The Altra64 project contributors
// Portions (c) 2013 saturnu (Alt64) based on libdragon, Neo64Menu, ED64IO, libn64-hkz, libmikmod // Portions (c) 2010 chillywilly (https://www.neoflash.com/forum/index.php?topic=6311.0)
// See LICENSE file in the project root for full license information. // See LICENSE file in the project root for full license information.
// //
@ -31,95 +31,89 @@ static unsigned char fileBuffer[INPUT_BUFFER_SIZE];
static unsigned char readBuffer[INPUT_BUFFER_SIZE]; static unsigned char readBuffer[INPUT_BUFFER_SIZE];
static int useReadBuffer; static int useReadBuffer;
static int readPos; static int readPos;
static unsigned int readLen; static UINT readLen;
static int samplesRead; static int samplesRead;
char * mp3File; static FIL mp3File;
char * mp3Fd; static FRESULT mp3Fd;
long mp3File_fptr=0;
int mp3File_fsize;
extern int gBrowser;
extern char path[1024];
extern void c2wstrcpy(void *dst, void *src); static int mp3_seek(int offset, int whence)
extern void c2wstrcat(void *dst, void *src); {
DWORD offs = 0;
static int mp3_seek(char* fd, int offset, int whence) {
//todo filesize and mp3File_fptr;
long offs = 0;
// libff routine
switch (whence) switch (whence)
{ {
case SEEK_SET: case SEEK_SET:
offs = offset; offs = offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
offs = mp3File_fptr + offset; offs = mp3File.fptr + offset;
break; break;
case SEEK_END: case SEEK_END:
offs = mp3File_fsize + offset; offs = f_size(&mp3File) + offset;
break; break;
} }
//f_lseek(&mp3File, offs); f_lseek(&mp3File, offs);
mp3File_fptr=offs;
return offs; return offs;
} }
static int mp3_size(char* fd) { static int mp3_size()
FRESULT result;
FILINFO fno;
//TODO: error
result = f_stat (fd, &fno);
mp3File_fsize = fno.fsize;
return mp3File_fsize;
}
static void _f_read(char* fname, unsigned char *readBuffer, int size){
//TODO: function not working... probably worth switching to http://www.underbit.com/products/mad/ anyway...
FRESULT result;
FIL file;
UINT bytesread;
result = f_open(&file, fname, FA_READ);
if (result == FR_OK)
{
int fsize = f_size(&file);
mp3File_fsize = fsize;
f_lseek(&file, mp3File_fptr);
result =
f_read (
&file, /* [IN] File object */
readBuffer, /* [OUT] Buffer to store read data */
size, /* [IN] Number of bytes to read */
&bytesread /* [OUT] Number of bytes read */
);
f_close(&file);
mp3File_fptr+=bytesread;
}
}
static int mp3_read(char* fd, unsigned char *ptr, int size)
{ {
int ts=size; return f_size(&mp3File);
_f_read(fd, ptr, size); }
static int mp3_read(unsigned char *ptr, int size)
{
UINT ts;
if (useReadBuffer)
{
int total = 0;
while (size)
{
if (!readLen)
{
f_read (
&mp3File, /* [IN] File object */
readBuffer, /* [OUT] Buffer to store read data */
INPUT_BUFFER_SIZE, /* [IN] Number of bytes to read */
&readLen /* [OUT] Number of bytes read */
);
readPos = 0;
if (readLen == 0)
return total; // EOF
}
int rlen = (size<readLen) ? size : readLen;
memcpy(ptr, readBuffer + readPos, rlen);
readPos += rlen;
readLen -= rlen;
ptr += rlen;
size -= rlen;
total += rlen;
}
return total;
}
f_read (
&mp3File, /* [IN] File object */
ptr, /* [OUT] Buffer to store read data */
size, /* [IN] Number of bytes to read */
&ts /* [OUT] Number of bytes read */
);
return ts; return ts;
} }
static int id3_tag_size(unsigned char const *buf, int remaining) { static int id3_tag_size(unsigned char const *buf, int remaining)
{
int size; int size;
int exheadersize = 0;
if (remaining < 10) if (remaining < 10)
return 0; return 0;
if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found
{ {
unsigned int version = buf[3];
version = (size<<7) | buf[4];
unsigned int headerflags = buf[5];
//get the real size from the syncsafe int //get the real size from the syncsafe int
size = buf[6]; size = buf[6];
size = (size<<7) | buf[7]; size = (size<<7) | buf[7];
@ -128,7 +122,17 @@ static int id3_tag_size(unsigned char const *buf, int remaining) {
size += 10; size += 10;
if (buf[5] & 0x10) //has footer
if (headerflags & 0x20) //has extended header
{
exheadersize = buf[10];
exheadersize = (exheadersize<<7) | buf[11];
exheadersize = (exheadersize<<7) | buf[12];
exheadersize = (exheadersize<<7) | buf[13];
size += exheadersize;
}
if (headerflags & 0x10) //has footer
size += 10; size += 10;
} }
return size; return size;
@ -137,18 +141,22 @@ static int id3_tag_size(unsigned char const *buf, int remaining) {
//Seek next valid frame after ID3/EA3 header //Seek next valid frame after ID3/EA3 header
//NOTE: adapted from Music prx 0.55 source //NOTE: adapted from Music prx 0.55 source
// credit goes to joek2100. // credit goes to joek2100.
static int MP3_SkipHdr(char* fd) static int MP3_SkipHdr()
{ {
int offset = 0; int offset = 0;
unsigned char buf[1024]; unsigned char buf[1024];
unsigned char *pBuffer; unsigned char *pBuffer;
int i; int i;
int size = 0; int size = 0;
int exheadersize = 0;
offset = mp3_seek(fd, 0, SEEK_CUR); offset = mp3_seek(0, SEEK_CUR);
mp3_read(fd, buf, sizeof(buf)); mp3_read(buf, sizeof(buf));
if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found
{ {
unsigned int version = buf[3];
version = (size<<7) | buf[4];
unsigned int headerflags = buf[5];
//get the real size from the syncsafe int //get the real size from the syncsafe int
size = buf[6]; size = buf[6];
size = (size<<7) | buf[7]; size = (size<<7) | buf[7];
@ -157,42 +165,56 @@ static int MP3_SkipHdr(char* fd)
size += 10; size += 10;
if (buf[5] & 0x10) //has footer
if (headerflags & 0x20) //has extended header
{
exheadersize = buf[10];
exheadersize = (exheadersize<<7) | buf[11];
exheadersize = (exheadersize<<7) | buf[12];
exheadersize = (exheadersize<<7) | buf[13];
size += exheadersize;
}
if (headerflags & 0x10) //has footer
size += 10; size += 10;
offset += size; offset += size;
} }
mp3_seek(fd, offset, SEEK_SET); mp3_seek(offset, SEEK_SET);
//now seek for a sync //now seek for a sync
for ( ;;) { for ( ;; )
offset = mp3_seek(fd, 0, SEEK_CUR); {
size = mp3_read(fd, buf, sizeof(buf)); offset = mp3_seek(0, SEEK_CUR);
size = mp3_read(buf, sizeof(buf));
if (size <= 2)//at end of file if (size <= 2)//at end of file
return -1; return -1;
if (!strncmp((char*)buf, "EA3", 3)) //oma mp3 files have non-safe ints in the EA3 header if (!strncmp((char*)buf, "EA3", 3)) //oma mp3 files have non-safe ints in the EA3 header
{ {
mp3_seek(fd, (buf[4]<<8)+buf[5], SEEK_CUR); mp3_seek((buf[4]<<8)+buf[5], SEEK_CUR);
continue; continue;
} }
pBuffer = buf; pBuffer = buf;
for( i = 0; i < size; i++) { for( i = 0; i < size; i++)
{
//if this is a valid frame sync (0xe0 is for mpeg version 2.5,2+1) //if this is a valid frame sync (0xe0 is for mpeg version 2.5,2+1)
if ( (pBuffer[i] == 0xff) && ((pBuffer[i+1] & 0xE0) == 0xE0) ) { if ( (pBuffer[i] == 0xff) && ((pBuffer[i+1] & 0xE0) == 0xE0) )
{
offset += i; offset += i;
mp3_seek(fd, offset, SEEK_SET); mp3_seek(offset, SEEK_SET);
return offset; return offset;
} }
} }
//go back two bytes to catch any syncs that on the boundary //go back two bytes to catch any syncs that on the boundary
mp3_seek(fd, -2, SEEK_CUR); mp3_seek(-2, SEEK_CUR);
} }
} }
static short convertSample(mad_fixed_t Fixed) { static short convertSample(mad_fixed_t Fixed)
{
/* Clipping */ /* Clipping */
if (Fixed >= MAD_F_ONE) if (Fixed >= MAD_F_ONE)
return (32767); return (32767);
@ -205,7 +227,8 @@ static short convertSample(mad_fixed_t Fixed) {
return ((short)Fixed); return ((short)Fixed);
} }
static int fillFileBuffer() { static int fillFileBuffer()
{
int leftOver = Stream.bufend - Stream.next_frame; int leftOver = Stream.bufend - Stream.next_frame;
int want = INPUT_BUFFER_SIZE - leftOver; int want = INPUT_BUFFER_SIZE - leftOver;
@ -215,8 +238,9 @@ static int fillFileBuffer() {
// fill remainder of buffer // fill remainder of buffer
unsigned char* bufferPos = fileBuffer + leftOver; unsigned char* bufferPos = fileBuffer + leftOver;
while (want > 0) { while (want > 0)
int got = mp3_read(mp3Fd, bufferPos, want); {
int got = mp3_read(bufferPos, want);
if (got <= 0) if (got <= 0)
return 1; // EOF return 1; // EOF
@ -226,19 +250,25 @@ static int fillFileBuffer() {
return 0; return 0;
} }
static void decode() { static void decode()
while (mad_frame_decode(&Frame, &Stream) == -1) { {
if ((Stream.error == MAD_ERROR_BUFLEN) || (Stream.error == MAD_ERROR_BUFPTR)) { while (mad_frame_decode(&Frame, &Stream) == -1)
if (fillFileBuffer()) { {
if ((Stream.error == MAD_ERROR_BUFLEN) || (Stream.error == MAD_ERROR_BUFPTR))
{
if (fillFileBuffer())
{
eos = 1; eos = 1;
break; break;
} }
mad_stream_buffer(&Stream, fileBuffer, INPUT_BUFFER_SIZE); mad_stream_buffer(&Stream, fileBuffer, INPUT_BUFFER_SIZE);
} }
else if (Stream.error == MAD_ERROR_LOSTSYNC) { else if (Stream.error == MAD_ERROR_LOSTSYNC)
{
/* LOSTSYNC - due to ID3 tags? */ /* LOSTSYNC - due to ID3 tags? */
int tagsize = id3_tag_size(Stream.this_frame, Stream.bufend - Stream.this_frame); int tagsize = id3_tag_size(Stream.this_frame, Stream.bufend - Stream.this_frame);
if (tagsize > 0) { if (tagsize > 0)
{
mad_stream_skip (&Stream, tagsize); mad_stream_skip (&Stream, tagsize);
continue; continue;
} }
@ -249,38 +279,45 @@ static void decode() {
mad_synth_frame(&Synth, &Frame); mad_synth_frame(&Synth, &Frame);
} }
static void convertLeftSamples(Sample* first, Sample* last, const mad_fixed_t* src) { static void convertLeftSamples(Sample* first, Sample* last, const mad_fixed_t* src)
{
for (Sample *dst = first; dst != last; ++dst) for (Sample *dst = first; dst != last; ++dst)
dst->left = convertSample(*src++); dst->left = convertSample(*src++);
} }
static void convertRightSamples(Sample* first, Sample* last, const mad_fixed_t* src) { static void convertRightSamples(Sample* first, Sample* last, const mad_fixed_t* src)
{
for (Sample *dst = first; dst != last; ++dst) for (Sample *dst = first; dst != last; ++dst)
dst->right = convertSample(*src++); dst->right = convertSample(*src++);
} }
static void MP3_Callback(void *buffer, unsigned int samplesToWrite) { static void MP3_Callback(void *buffer, unsigned int samplesToWrite)
{
Sample *destination = (Sample*)buffer; Sample *destination = (Sample*)buffer;
while (samplesToWrite > 0) { while (samplesToWrite > 0)
{
while (!eos && (Synth.pcm.length == 0)) while (!eos && (Synth.pcm.length == 0))
decode(); decode();
if (eos) { if (eos)
{
// done // done
memset(destination, 0, samplesToWrite*4); memset(destination, 0, samplesToWrite*4);
break; break;
} }
unsigned int samplesAvailable = Synth.pcm.length - samplesRead; unsigned int samplesAvailable = Synth.pcm.length - samplesRead;
if (samplesAvailable > samplesToWrite) { if (samplesAvailable > samplesToWrite)
{
convertLeftSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]); convertLeftSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[0][samplesRead]);
convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[1][samplesRead]); convertRightSamples(destination, destination + samplesToWrite, &Synth.pcm.samples[1][samplesRead]);
samplesRead += samplesToWrite; samplesRead += samplesToWrite;
samplesToWrite = 0; samplesToWrite = 0;
} }
else { else
{
convertLeftSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[0][samplesRead]); convertLeftSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[0][samplesRead]);
convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[1][samplesRead]); convertRightSamples(destination, destination + samplesAvailable, &Synth.pcm.samples[1][samplesRead]);
@ -293,7 +330,8 @@ static void MP3_Callback(void *buffer, unsigned int samplesToWrite) {
} }
} }
static void MP3_Init() { static void MP3_Init()
{
/* First the structures used by libmad must be initialized. */ /* First the structures used by libmad must be initialized. */
mad_stream_init(&Stream); mad_stream_init(&Stream);
mad_header_init(&Header); mad_header_init(&Header);
@ -302,23 +340,25 @@ static void MP3_Init() {
mad_timer_reset(&Timer); mad_timer_reset(&Timer);
} }
static void MP3_Exit() { static void MP3_Exit()
{
mad_synth_finish(&Synth); mad_synth_finish(&Synth);
mad_header_finish(&Header); mad_header_finish(&Header);
mad_frame_finish(&Frame); mad_frame_finish(&Frame);
mad_stream_finish(&Stream); mad_stream_finish(&Stream);
} }
static void MP3_GetInfo(long long *samples, int *rate) { static void MP3_GetInfo(long long *samples, int *rate)
{
unsigned long FrameCount = 0; unsigned long FrameCount = 0;
int bufferSize = 1024*512; int bufferSize = 1024*512;
unsigned char *localBuffer; unsigned char *localBuffer;
long red = 0; long bytesread = 0;
double totalBitrate = 0.0; double totalBitrate = 0.0;
double mediumBitrate = 0.0; double mediumBitrate = 0.0;
struct mad_stream stream; struct mad_stream stream;
struct mad_header header; struct mad_header header;
int size = mp3_size(mp3Fd); long size = mp3_size();
long count = size; long count = size;
mad_stream_init (&stream); mad_stream_init (&stream);
@ -326,28 +366,32 @@ static void MP3_GetInfo(long long *samples, int *rate) {
localBuffer = (unsigned char *)malloc(bufferSize); localBuffer = (unsigned char *)malloc(bufferSize);
for (int i=0; i<3; i++) { for (int i=0; i<3; i++)
{
memset(localBuffer, 0, bufferSize); memset(localBuffer, 0, bufferSize);
if (count > bufferSize) if (count > bufferSize)
red = mp3_read(mp3Fd, localBuffer, bufferSize); bytesread = mp3_read(localBuffer, bufferSize);
else else
red = mp3_read(mp3Fd, localBuffer, count); bytesread = mp3_read(localBuffer, count);
count -= red; count -= bytesread;
if (!red) if (!bytesread)
break; // ran out of data break; // ran out of data
mad_stream_buffer (&stream, localBuffer, red); mad_stream_buffer (&stream, localBuffer, bytesread);
for ( ;; ) { for ( ;; )
if (mad_header_decode(&header, &stream) == -1) { {
if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { if (mad_header_decode(&header, &stream) == -1)
{
if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
break; break;
} else if (MAD_RECOVERABLE(stream.error))
else if (MAD_RECOVERABLE(stream.error)) { {
continue; continue;
} }
else { else
{
break; break;
} }
} }
@ -367,45 +411,44 @@ static void MP3_GetInfo(long long *samples, int *rate) {
if (localBuffer) if (localBuffer)
free(localBuffer); free(localBuffer);
mp3_seek(mp3Fd, 0, SEEK_SET); mp3_seek(0, SEEK_SET);
} }
void mp3_Start(char *fname, long long *samples, int *rate, int *channels) { void mp3_Start(char *fname, long long *samples, int *rate, int *channels)
sprintf(mp3Fd, "%s", fname); {
//if (mp3Fd[0]!=0) mp3Fd = f_open(&mp3File, fname, FA_READ);
//{
if (mp3Fd == FR_OK)
{
useReadBuffer = 0; useReadBuffer = 0;
MP3_GetInfo(samples, rate); MP3_GetInfo(samples, rate);
*channels = 2; *channels = 2;
MP3_Init(); MP3_Init();
MP3_SkipHdr(mp3Fd); MP3_SkipHdr();
eos = readLen = readPos = 0; eos = readLen = readPos = 0;
useReadBuffer = 1; useReadBuffer = 1;
return; return;
//}
//*samples = 0;
}
void mp3_Stop(void) {
MP3_Exit();
mp3File_fptr=0;
/*
if (mp3Fd > 0)
{
if (gBrowser)
f_close(&mp3File);
else
dfs_close(mp3Fd);
} }
mp3Fd = -1;
*/ *samples = 0;
return;
} }
int mp3_Update(char *buf, int bytes) { void mp3_Stop(void)
{
MP3_Exit();
if (mp3Fd == FR_OK)
{
f_close(&mp3File);
}
mp3Fd = FR_NO_FILE;
}
int mp3_Update(char *buf, int bytes)
{
MP3_Callback(buf, bytes/4); MP3_Callback(buf, bytes/4);
return eos ? 0 : 1; return eos ? 0 : 1;
} }

View File

@ -67,6 +67,18 @@ LIBS="-ldragon -lc -ldragonsys -lnosys" \
make make
make install make install
cd ..
# install libmad (custom version)
git clone https://github.com/networkfusion/libmad-n64
cd libmad-n64
export PATH=$PATH:$N64_INST/bin
CFLAGS="-std=gnu99 -march=vr4300 -mtune=vr4300" \
LDFLAGS="-L$N64_INST/lib -Tn64ld.x" \
LIBS="-ldragon -lc -ldragonsys -lnosys" \
./configure --host=mips64-elf --prefix=$N64_INST
make
make install
cd .. cd ..
# Perform cleanup # Perform cleanup