fixed MP3 playback
although still plays back far to slow! also minor refactoring
This commit is contained in:
parent
d52179c4d5
commit
2785f5f50a
@ -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
|
||||||
|
@ -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
|
||||||
|
74
src/main.c
74
src/main.c
@ -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);
|
||||||
|
289
src/mp3.c
289
src/mp3.c
@ -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;
|
return f_size(&mp3File);
|
||||||
//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){
|
static int mp3_read(unsigned char *ptr, int size)
|
||||||
//TODO: function not working... probably worth switching to http://www.underbit.com/products/mad/ anyway...
|
{
|
||||||
FRESULT result;
|
UINT ts;
|
||||||
FIL file;
|
if (useReadBuffer)
|
||||||
UINT bytesread;
|
{
|
||||||
result = f_open(&file, fname, FA_READ);
|
int total = 0;
|
||||||
|
while (size)
|
||||||
if (result == FR_OK)
|
{
|
||||||
|
if (!readLen)
|
||||||
{
|
{
|
||||||
int fsize = f_size(&file);
|
|
||||||
|
|
||||||
mp3File_fsize = fsize;
|
|
||||||
|
|
||||||
f_lseek(&file, mp3File_fptr);
|
|
||||||
|
|
||||||
result =
|
|
||||||
f_read (
|
f_read (
|
||||||
&file, /* [IN] File object */
|
&mp3File, /* [IN] File object */
|
||||||
readBuffer, /* [OUT] Buffer to store read data */
|
readBuffer, /* [OUT] Buffer to store read data */
|
||||||
size, /* [IN] Number of bytes to read */
|
INPUT_BUFFER_SIZE, /* [IN] Number of bytes to read */
|
||||||
&bytesread /* [OUT] Number of bytes read */
|
&readLen /* [OUT] Number of bytes read */
|
||||||
);
|
);
|
||||||
|
readPos = 0;
|
||||||
f_close(&file);
|
if (readLen == 0)
|
||||||
|
return total; // EOF
|
||||||
mp3File_fptr+=bytesread;
|
|
||||||
}
|
}
|
||||||
|
int rlen = (size<readLen) ? size : readLen;
|
||||||
|
memcpy(ptr, readBuffer + readPos, rlen);
|
||||||
|
readPos += rlen;
|
||||||
|
readLen -= rlen;
|
||||||
|
ptr += rlen;
|
||||||
|
size -= rlen;
|
||||||
|
total += rlen;
|
||||||
}
|
}
|
||||||
|
return total;
|
||||||
static int mp3_read(char* fd, unsigned char *ptr, int size)
|
}
|
||||||
{
|
f_read (
|
||||||
int ts=size;
|
&mp3File, /* [IN] File object */
|
||||||
_f_read(fd, ptr, size);
|
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) {
|
*samples = 0;
|
||||||
MP3_Exit();
|
return;
|
||||||
mp3File_fptr=0;
|
}
|
||||||
/*
|
|
||||||
if (mp3Fd > 0)
|
void mp3_Stop(void)
|
||||||
|
{
|
||||||
|
MP3_Exit();
|
||||||
|
if (mp3Fd == FR_OK)
|
||||||
{
|
{
|
||||||
if (gBrowser)
|
|
||||||
f_close(&mp3File);
|
f_close(&mp3File);
|
||||||
else
|
|
||||||
dfs_close(mp3Fd);
|
|
||||||
}
|
}
|
||||||
mp3Fd = -1;
|
mp3Fd = FR_NO_FILE;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mp3_Update(char *buf, int bytes) {
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user