forked from len0rd/rockbox
Beginning of an mpeg thread
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@570 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1dd21edacf
commit
bbdeba6d8c
2 changed files with 228 additions and 131 deletions
|
@ -50,7 +50,7 @@ install:
|
||||||
mount /mnt/archos; cp archos.mod /mnt/archos; umount /mnt/archos
|
mount /mnt/archos; cp archos.mod /mnt/archos; umount /mnt/archos
|
||||||
|
|
||||||
thread.o: ../../thread.c
|
thread.o: ../../thread.c
|
||||||
$(CC) -O $(CFLAGS) -c $<
|
$(CC) -O $(CFLAGS) -fomit-frame-pointer -c $<
|
||||||
|
|
||||||
ata.o: ../../drivers/ata.c
|
ata.o: ../../drivers/ata.c
|
||||||
$(CC) -O $(CFLAGS) -c $<
|
$(CC) -O $(CFLAGS) -c $<
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "types.h"
|
#include <stdbool.h>
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "mas.h"
|
#include "mas.h"
|
||||||
#include "sh7034.h"
|
#include "sh7034.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
#include "thread.h"
|
||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "fat.h"
|
#include "fat.h"
|
||||||
|
@ -34,6 +35,15 @@
|
||||||
#define MIN(a, b) (((a)<(b))?(a):(b))
|
#define MIN(a, b) (((a)<(b))?(a):(b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MPEG_PLAY 1
|
||||||
|
#define MPEG_STOP 2
|
||||||
|
#define MPEG_PAUSE 3
|
||||||
|
#define MPEG_RESUME 4
|
||||||
|
#define MPEG_NEED_DATA 100
|
||||||
|
|
||||||
|
#define MP3_LOW_WATER 0x30000
|
||||||
|
#define MP3_CHUNK_SIZE 0x20000
|
||||||
|
|
||||||
unsigned char fliptable[] =
|
unsigned char fliptable[] =
|
||||||
{
|
{
|
||||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||||
|
@ -81,8 +91,20 @@ int mp3buf_write;
|
||||||
int mp3buf_read;
|
int mp3buf_read;
|
||||||
int last_dma_chunk_size;
|
int last_dma_chunk_size;
|
||||||
|
|
||||||
bool dma_on;
|
bool dma_on; /* The DMA is active */
|
||||||
|
bool playing; /* We are playing an MP3 stream */
|
||||||
|
bool filling; /* We are filling the buffer with data from disk */
|
||||||
|
|
||||||
|
struct event_queue mpeg_queue;
|
||||||
|
|
||||||
static void mas_poll_start(unsigned int interval_in_ms);
|
static void mas_poll_start(unsigned int interval_in_ms);
|
||||||
|
void mpeg_thread(void);
|
||||||
|
|
||||||
|
void reset_mp3_buffer(void)
|
||||||
|
{
|
||||||
|
mp3buf_read = 0;
|
||||||
|
mp3buf_write = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void setup_sci0(void)
|
void setup_sci0(void)
|
||||||
{
|
{
|
||||||
|
@ -124,13 +146,9 @@ void setup_sci0(void)
|
||||||
IPRC = (IPRC & 0xf0ff) | 0x0800;
|
IPRC = (IPRC & 0xf0ff) | 0x0800;
|
||||||
|
|
||||||
/* Enable Tx (only!) */
|
/* Enable Tx (only!) */
|
||||||
// SCR0 |= 0xa0;
|
SCR0 |= 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mas_tx_ready(void)
|
|
||||||
{
|
|
||||||
return (SSR0 & SCI_TDRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_dma(void)
|
void init_dma(void)
|
||||||
{
|
{
|
||||||
|
@ -141,23 +159,25 @@ void init_dma(void)
|
||||||
last_dma_chunk_size = MIN(65536, mp3buf_write - mp3buf_read);
|
last_dma_chunk_size = MIN(65536, mp3buf_write - mp3buf_read);
|
||||||
DTCR3 = last_dma_chunk_size & 0xffff;
|
DTCR3 = last_dma_chunk_size & 0xffff;
|
||||||
DMAOR = 0x0001; /* Enable DMA */
|
DMAOR = 0x0001; /* Enable DMA */
|
||||||
|
CHCR3 |= 0x0001; /* Enable DMA IRQ */
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_dma(void)
|
void start_dma(void)
|
||||||
{
|
{
|
||||||
SCR0 |= 0x80;
|
SCR0 |= 0x80;
|
||||||
dma_on = TRUE;
|
dma_on = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_dma(void)
|
void stop_dma(void)
|
||||||
{
|
{
|
||||||
SCR0 &= 0x7f;
|
SCR0 &= 0x7f;
|
||||||
dma_on = FALSE;
|
dma_on = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dma_tick(void)
|
void dma_tick(void)
|
||||||
{
|
{
|
||||||
if(!dma_on)
|
/* Start DMA if it isn't running */
|
||||||
|
if(playing && !dma_on)
|
||||||
{
|
{
|
||||||
if(PBDR & 0x4000)
|
if(PBDR & 0x4000)
|
||||||
{
|
{
|
||||||
|
@ -176,9 +196,6 @@ void bitswap(unsigned char *data, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct event_queue disk_queue;
|
|
||||||
int filling;
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
char buf[40];
|
char buf[40];
|
||||||
|
@ -186,12 +203,6 @@ int main(void)
|
||||||
int i=0;
|
int i=0;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
int f;
|
|
||||||
int free_space_left;
|
|
||||||
int mp3_space_left;
|
|
||||||
int amount_to_read;
|
|
||||||
int play_song;
|
|
||||||
struct event *ev;
|
|
||||||
|
|
||||||
/* Clear it all! */
|
/* Clear it all! */
|
||||||
SSR1 &= ~(SCI_RDRF | SCI_ORER | SCI_PER | SCI_FER);
|
SSR1 &= ~(SCI_RDRF | SCI_ORER | SCI_PER | SCI_FER);
|
||||||
|
@ -205,7 +216,7 @@ int main(void)
|
||||||
|
|
||||||
i2c_init();
|
i2c_init();
|
||||||
|
|
||||||
dma_on = TRUE;
|
dma_on = true;
|
||||||
|
|
||||||
kernel_init();
|
kernel_init();
|
||||||
|
|
||||||
|
@ -270,100 +281,20 @@ int main(void)
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
f = open("/machinae_supremacy_-_arcade.mp3", O_RDONLY);
|
queue_init(&mpeg_queue);
|
||||||
if(f < 0)
|
|
||||||
{
|
|
||||||
debugf("Couldn't open file\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
mp3buf_read = mp3buf_write = 0;
|
create_thread(mpeg_thread, stack - 0x2000, 0x4000);
|
||||||
|
|
||||||
/* First read in a few seconds worth of MP3 data */
|
mas_poll_start(2);
|
||||||
i = read(f, mp3buf, 0x20000);
|
|
||||||
debugf("Read %d bytes\n", i);
|
|
||||||
|
|
||||||
ata_spindown(-1);
|
|
||||||
|
|
||||||
debugf("bit swapping...\n");
|
|
||||||
bitswap(mp3buf + mp3buf_write, i);
|
|
||||||
|
|
||||||
mp3buf_write = i;
|
|
||||||
|
|
||||||
queue_init(&disk_queue);
|
|
||||||
|
|
||||||
mas_poll_start(1);
|
|
||||||
|
|
||||||
debugf("let's play...\n");
|
debugf("let's play...\n");
|
||||||
init_dma();
|
|
||||||
|
|
||||||
dma_on = TRUE;
|
queue_post(&mpeg_queue, MPEG_PLAY, 0);
|
||||||
|
|
||||||
/* Enable Tx & TXIE */
|
while(1)
|
||||||
SCR0 |= 0xa0;
|
|
||||||
|
|
||||||
CHCR3 |= 1;
|
|
||||||
|
|
||||||
#define MP3_LOW_WATER 0x30000
|
|
||||||
#define MP3_CHUNK_SIZE 0x20000
|
|
||||||
|
|
||||||
play_song = 1;
|
|
||||||
filling = 1;
|
|
||||||
|
|
||||||
while(play_song)
|
|
||||||
{
|
{
|
||||||
if(filling)
|
sleep(HZ*1000);
|
||||||
{
|
|
||||||
free_space_left = mp3buf_read - mp3buf_write;
|
|
||||||
if(free_space_left < 0)
|
|
||||||
free_space_left = MP3BUF_LEN + free_space_left;
|
|
||||||
|
|
||||||
if(free_space_left <= MP3_CHUNK_SIZE)
|
|
||||||
{
|
|
||||||
debugf("0\n");
|
|
||||||
ata_spindown(-1);
|
|
||||||
filling = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_to_read = MIN(MP3_CHUNK_SIZE, free_space_left);
|
|
||||||
amount_to_read = MIN(MP3BUF_LEN - mp3buf_write, amount_to_read);
|
|
||||||
|
|
||||||
/* Read in a few seconds worth of MP3 data. We don't want to
|
|
||||||
read too large chunks because the bitswapping will take
|
|
||||||
too much time. We must keep the DMA happy and also give
|
|
||||||
the other threads a chance to run. */
|
|
||||||
debugf("R\n", i);
|
|
||||||
i = read(f, mp3buf+mp3buf_write, amount_to_read);
|
|
||||||
if(i)
|
|
||||||
{
|
|
||||||
debugf("B\n");
|
|
||||||
bitswap(mp3buf + mp3buf_write, i);
|
|
||||||
|
|
||||||
mp3buf_write += i;
|
|
||||||
if(mp3buf_write >= MP3BUF_LEN)
|
|
||||||
{
|
|
||||||
mp3buf_write = 0;
|
|
||||||
debugf("W\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
play_song = 0;
|
|
||||||
ata_spindown(-1);
|
|
||||||
filling = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debugf("S\n");
|
|
||||||
ev = queue_wait(&disk_queue);
|
|
||||||
debugf("Q\n");
|
|
||||||
debugf("1\n");
|
|
||||||
filling = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debugf("Song is finished\n");
|
|
||||||
while(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma interrupt
|
#pragma interrupt
|
||||||
|
@ -377,6 +308,9 @@ void DEI3(void)
|
||||||
{
|
{
|
||||||
int unplayed_space_left;
|
int unplayed_space_left;
|
||||||
int space_until_end_of_buffer;
|
int space_until_end_of_buffer;
|
||||||
|
|
||||||
|
if(playing)
|
||||||
|
{
|
||||||
mp3buf_read += last_dma_chunk_size;
|
mp3buf_read += last_dma_chunk_size;
|
||||||
if(mp3buf_read >= MP3BUF_LEN)
|
if(mp3buf_read >= MP3BUF_LEN)
|
||||||
mp3buf_read = 0;
|
mp3buf_read = 0;
|
||||||
|
@ -389,7 +323,7 @@ void DEI3(void)
|
||||||
|
|
||||||
if(!filling && unplayed_space_left < MP3_LOW_WATER)
|
if(!filling && unplayed_space_left < MP3_LOW_WATER)
|
||||||
{
|
{
|
||||||
queue_post(&disk_queue, 1, 0);
|
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(unplayed_space_left)
|
if(unplayed_space_left)
|
||||||
|
@ -398,13 +332,15 @@ void DEI3(void)
|
||||||
last_dma_chunk_size = MIN(last_dma_chunk_size, space_until_end_of_buffer);
|
last_dma_chunk_size = MIN(last_dma_chunk_size, space_until_end_of_buffer);
|
||||||
DTCR3 = last_dma_chunk_size & 0xffff;
|
DTCR3 = last_dma_chunk_size & 0xffff;
|
||||||
SAR3 = (unsigned int)mp3buf + mp3buf_read;
|
SAR3 = (unsigned int)mp3buf + mp3buf_read;
|
||||||
CHCR3 &= ~0x0002;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debugf("No more MP3 data. Stopping.\n");
|
debugf("No more MP3 data. Stopping.\n");
|
||||||
CHCR3 = 0;
|
CHCR3 = 0; /* Stop DMA interrupt */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CHCR3 &= ~0x0002; /* Clear DMA interrupt */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mas_poll_start(unsigned int interval_in_ms)
|
static void mas_poll_start(unsigned int interval_in_ms)
|
||||||
|
@ -446,3 +382,164 @@ void IMIA1(void)
|
||||||
TSR1 &= ~0x01;
|
TSR1 &= ~0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *tracks[] =
|
||||||
|
{
|
||||||
|
"/machinae_supremacy_-_arcade.mp3"
|
||||||
|
};
|
||||||
|
|
||||||
|
char *peek_next_track(int index)
|
||||||
|
{
|
||||||
|
return tracks[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int mpeg_file = -1;
|
||||||
|
|
||||||
|
int new_file(void)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char *trackname;
|
||||||
|
|
||||||
|
trackname = peek_next_track(0);
|
||||||
|
|
||||||
|
debugf("playing %s\n", trackname);
|
||||||
|
mpeg_file = open(trackname, O_RDONLY);
|
||||||
|
if(mpeg_file < 0)
|
||||||
|
{
|
||||||
|
debugf("Couldn't open file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First read in a few seconds worth of MP3 data */
|
||||||
|
len = read(mpeg_file, mp3buf + mp3buf_write, MP3_CHUNK_SIZE);
|
||||||
|
|
||||||
|
ata_spindown(-1);
|
||||||
|
|
||||||
|
bitswap(mp3buf + mp3buf_write, len);
|
||||||
|
|
||||||
|
mp3buf_write = len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpeg_thread(void)
|
||||||
|
{
|
||||||
|
struct event ev;
|
||||||
|
int len;
|
||||||
|
int free_space_left;
|
||||||
|
int amount_to_read;
|
||||||
|
|
||||||
|
playing = false;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
debugf("S\n");
|
||||||
|
queue_wait(&mpeg_queue, &ev);
|
||||||
|
switch(ev.id)
|
||||||
|
{
|
||||||
|
case MPEG_PLAY:
|
||||||
|
/* Stop the current stream */
|
||||||
|
playing = false;
|
||||||
|
stop_dma();
|
||||||
|
|
||||||
|
reset_mp3_buffer();
|
||||||
|
|
||||||
|
new_file();
|
||||||
|
|
||||||
|
/* Make it read more data */
|
||||||
|
filling = true;
|
||||||
|
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||||
|
|
||||||
|
playing = true;
|
||||||
|
|
||||||
|
init_dma();
|
||||||
|
start_dma();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPEG_STOP:
|
||||||
|
/* Stop the current stream */
|
||||||
|
playing = false;
|
||||||
|
stop_dma();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPEG_PAUSE:
|
||||||
|
/* Stop the current stream */
|
||||||
|
playing = false;
|
||||||
|
stop_dma();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPEG_RESUME:
|
||||||
|
/* Stop the current stream */
|
||||||
|
playing = true;
|
||||||
|
start_dma();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPEG_NEED_DATA:
|
||||||
|
free_space_left = mp3buf_read - mp3buf_write;
|
||||||
|
if(free_space_left < 0)
|
||||||
|
free_space_left = MP3BUF_LEN + free_space_left;
|
||||||
|
|
||||||
|
if(free_space_left <= MP3_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
debugf("0\n");
|
||||||
|
ata_spindown(-1);
|
||||||
|
filling = false;
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
|
||||||
|
amount_to_read = MIN(MP3_CHUNK_SIZE, free_space_left);
|
||||||
|
amount_to_read = MIN(MP3BUF_LEN - mp3buf_write, amount_to_read);
|
||||||
|
|
||||||
|
/* Read in a few seconds worth of MP3 data. We don't want to
|
||||||
|
read too large chunks because the bitswapping will take
|
||||||
|
too much time. We must keep the DMA happy and also give
|
||||||
|
the other threads a chance to run. */
|
||||||
|
debugf("R\n");
|
||||||
|
len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read);
|
||||||
|
if(len)
|
||||||
|
{
|
||||||
|
debugf("B\n");
|
||||||
|
bitswap(mp3buf + mp3buf_write, len);
|
||||||
|
|
||||||
|
mp3buf_write += len;
|
||||||
|
if(mp3buf_write >= MP3BUF_LEN)
|
||||||
|
{
|
||||||
|
mp3buf_write = 0;
|
||||||
|
debugf("W\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell ourselves that we want more data */
|
||||||
|
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(mpeg_file);
|
||||||
|
|
||||||
|
/* Make sure that the write pointer is at a word
|
||||||
|
boundary */
|
||||||
|
mp3buf_write &= 0xfffffffe;
|
||||||
|
|
||||||
|
if(new_file() < 0)
|
||||||
|
{
|
||||||
|
/* No more data to play */
|
||||||
|
debugf("Finished playing\n");
|
||||||
|
playing = false;
|
||||||
|
ata_spindown(-1);
|
||||||
|
filling = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Tell ourselves that we want more data */
|
||||||
|
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Newlib trap honeypot */
|
||||||
|
void __trap34(void)
|
||||||
|
{
|
||||||
|
debugf("newlib trap34\n");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue