From ec5d44627fb8a409c445741264cc4f2995a17721 Mon Sep 17 00:00:00 2001 From: Jörg Hohensohn Date: Sat, 10 Jan 2004 15:39:56 +0000 Subject: next round of playback function split: everything in place, working and used; except for the playtime git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4218 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/mp3_playback.h | 8 ++ firmware/export/mpeg.h | 4 + firmware/mp3_playback.c | 156 ++++++++++++++++++++++- firmware/mpeg.c | 276 ++++++++++++++--------------------------- 4 files changed, 256 insertions(+), 188 deletions(-) diff --git a/firmware/export/mp3_playback.h b/firmware/export/mp3_playback.h index 2767092b75..3c190f2691 100644 --- a/firmware/export/mp3_playback.h +++ b/firmware/export/mp3_playback.h @@ -40,6 +40,12 @@ int mpeg_sound_numdecimals(int setting); void mpeg_set_pitch(int percent); #endif + +/* exported just for mpeg.c, to keep the recording there */ +#ifdef HAVE_MAS3587F +void demand_irq_enable(bool on); +#endif + /* new functions, to be exported to plugin API */ void mp3_play_init(void); void mp3_play_data(unsigned char* start, int size, @@ -47,6 +53,8 @@ void mp3_play_data(unsigned char* start, int size, ); void mp3_play_pause(bool play); void mp3_play_stop(void); +long mp3_get_playtime(void); +void mp3_reset_playtime(void); #define SOUND_VOLUME 0 diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index 2a629f4b45..ff003e62f5 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h @@ -90,6 +90,10 @@ void mpeg_set_buffer_margin(int seconds); unsigned int mpeg_error(void); void mpeg_error_clear(void); +/* in order to keep the recording here, I have to expose this */ +void rec_tick(void); +void playback_tick(void); /* FixMe: get rid of this, use mp3_get_playtime() */ + #define MPEG_STATUS_PLAY 1 #define MPEG_STATUS_PAUSE 2 #define MPEG_STATUS_RECORD 4 diff --git a/firmware/mp3_playback.c b/firmware/mp3_playback.c index 9930f10824..fe16676624 100644 --- a/firmware/mp3_playback.c +++ b/firmware/mp3_playback.c @@ -34,6 +34,30 @@ #include "hwcompat.h" #endif +/* hacking into mpeg.c, recording is still there */ +#ifdef HAVE_MAS3587F +enum +{ + MPEG_DECODER, + MPEG_ENCODER +} mpeg_mode; +#endif /* #ifdef HAVE_MAS3587F */ + +/**** globals ****/ + +/* own version, independent of mpeg.c */ +static bool paused; /* playback is paused */ +static bool playing; /* We are playing an MP3 stream */ + +#ifndef SIMULATOR +/* for measuring the play time */ +static long playstart_tick; +static long cumulative_ticks; + +/* the registered callback function to ask for more mp3 data */ +static void (*callback_for_more)(unsigned char**, int*); +#endif /* #ifndef SIMULATOR */ + static char *units[] = { "%", /* Volume */ @@ -283,10 +307,65 @@ static void mas_poll_start(int interval_in_ms) TSTR |= 0x02; /* Start timer 1 */ } +#else +static void postpone_dma_tick(void) +{ + unsigned int count; + + count = FREQ / 1000 / 8; + + /* We are using timer 1 */ + + TSTR &= ~0x02; /* Stop the timer */ + TSNC &= ~0x02; /* No synchronization */ + TMDR &= ~0x02; /* Operate normally */ + + TCNT1 = 0; /* Start counting at 0 */ + GRA1 = count; + TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ + + /* Enable interrupt on level 5 */ + IPRC = (IPRC & ~0x000f) | 0x0005; + + TSR1 &= ~0x02; + TIER1 = 0xf9; /* Enable GRA match interrupt */ + + TSTR |= 0x02; /* Start timer 1 */ +} #endif -/* the registered callback function ta ask for more mp3 data */ -static void (*callback_for_more)(unsigned char**, int*); + +#ifdef HAVE_MAS3587F +void demand_irq_enable(bool on) +{ + int oldlevel = set_irq_level(15); + + if(on) + { + IPRA = (IPRA & 0xfff0) | 0x000b; + ICR &= ~0x0010; /* IRQ3 level sensitive */ + } + else + IPRA &= 0xfff0; + + set_irq_level(oldlevel); +} +#endif /* #ifdef HAVE_MAS3587F */ + + +void play_tick(void) +{ + if(playing && !paused) + { + /* Start DMA if it is disabled and the DEMAND pin is high */ + if(!(SCR0 & 0x80) && (PBDR & 0x4000)) + { + SCR0 |= 0x80; + } + + playback_tick(); /* dirty call to mpeg.c */ + } +} #pragma interrupt void DEI3(void) @@ -312,11 +391,37 @@ void DEI3(void) CHCR3 &= ~0x0002; /* Clear DMA interrupt */ } +#pragma interrupt +void IMIA1(void) /* Timer 1 interrupt */ +{ + if(playing) + play_tick(); + TSR1 &= ~0x01; +#ifdef HAVE_MAS3587F + /* Disable interrupt */ + IPRC &= ~0x000f; +#endif /* #ifdef HAVE_MAS3587F */ +} + #pragma interrupt void IRQ6(void) /* PB14: MAS stop demand IRQ */ { - mp3_play_pause(false); + SCR0 &= ~0x80; +} + +#ifdef HAVE_MAS3587F +#pragma interrupt +void IRQ3(void) /* PA15: MAS demand IRQ */ +{ + /* Begin with setting the IRQ to edge sensitive */ + ICR |= 0x0010; + + if(mpeg_mode == MPEG_ENCODER) + rec_tick(); + else + postpone_dma_tick(); } +#endif /* #ifdef HAVE_MAS3587F */ static void setup_sci0(void) { @@ -404,6 +509,8 @@ static void init_playback(void) mpeg_sound_channel_config(MPEG_SOUND_STEREO); + mpeg_mode = MPEG_DECODER; + /* set IRQ6 to edge detect */ ICR |= 0x02; @@ -893,6 +1000,9 @@ void mp3_init(int volume, int bass, int treble, int balance, int loudness, mpeg_sound_set(SOUND_AVC, avc); #endif #endif /* !SIMULATOR */ + + playing = false; + paused = true; } @@ -905,7 +1015,10 @@ void mp3_play_init(void) #ifdef HAVE_MAS3587F init_playback(); #endif + playing = false; + paused = true; callback_for_more = NULL; + mp3_reset_playtime(); } void mp3_play_data(unsigned char* start, int size, @@ -923,21 +1036,54 @@ void mp3_play_data(unsigned char* start, int size, SAR3 = (unsigned int)start; DTCR3 = size & 0xffff; + playing = true; + paused = true; + CHCR3 |= 0x0001; /* Enable DMA IRQ */ + +#ifdef HAVE_MAS3587F + demand_irq_enable(true); +#endif } void mp3_play_pause(bool play) { - if (play) + if (paused && play) + { /* resume playback */ SCR0 |= 0x80; - else + paused = false; + playstart_tick = current_tick; + } + else if (!paused && !play) + { /* stop playback */ SCR0 &= 0x7f; + paused = true; + cumulative_ticks += current_tick - playstart_tick; + } } void mp3_play_stop(void) { + playing = false; mp3_play_pause(false); CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ +#ifdef HAVE_MAS3587F + demand_irq_enable(false); +#endif +} + +long mp3_get_playtime(void) +{ + if (paused) + return cumulative_ticks; + else + return cumulative_ticks + current_tick - playstart_tick; +} + +void mp3_reset_playtime(void) +{ + cumulative_ticks = 0; + playstart_tick = current_tick; } #endif /* #ifndef SIMULATOR */ diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 29836dd14e..12d71a1dbd 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c @@ -74,7 +74,7 @@ static int get_unswapped_space(void); #define MPEG_STOP_DONE 103 #ifdef HAVE_MAS3587F -static enum +extern enum /* from mp3_playback.c */ { MPEG_DECODER, MPEG_ENCODER @@ -371,33 +371,6 @@ void mpeg_get_debugdata(struct mpeg_debug *dbgdata) dbgdata->lowest_watermark_level = lowest_watermark_level; } -#ifndef HAVE_MAS3507D -static void postpone_dma_tick(void) -{ - unsigned int count; - - count = FREQ / 1000 / 8; - - /* We are using timer 1 */ - - TSTR &= ~0x02; /* Stop the timer */ - TSNC &= ~0x02; /* No synchronization */ - TMDR &= ~0x02; /* Operate normally */ - - TCNT1 = 0; /* Start counting at 0 */ - GRA1 = count; - TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ - - /* Enable interrupt on level 5 */ - IPRC = (IPRC & ~0x000f) | 0x0005; - - TSR1 &= ~0x02; - TIER1 = 0xf9; /* Enable GRA match interrupt */ - - TSTR |= 0x02; /* Start timer 1 */ -} -#endif /* #ifndef HAVE_MAS3507D */ - #ifdef DEBUG static void dbg_timer_start(void) { @@ -524,134 +497,122 @@ static void drain_dma_buffer(void) #endif /* #ifdef HAVE_MAS3587F */ -static void dma_tick (void) __attribute__ ((section (".icode"))); -static void dma_tick(void) +void rec_tick (void) __attribute__ ((section (".icode"))); +void rec_tick(void) { #ifdef HAVE_MAS3587F - if(mpeg_mode == MPEG_DECODER) - { -#endif /* #ifdef HAVE_MAS3587F */ - if(playing && !paused) - { - /* Start DMA if it is disabled and the DEMAND pin is high */ - if(!(SCR0 & 0x80) && (PBDR & 0x4000)) - { - mp3_play_pause(true); - } - id3tags[tag_read_idx]->id3.elapsed += - (current_tick - last_dma_tick) * 1000 / HZ; - last_dma_tick = current_tick; - } -#ifdef HAVE_MAS3587F - } - else /* MPEG_ENCODER */ + int i; + int num_bytes; + if(is_recording && (PBDR & 0x4000)) { - int i; - int num_bytes; - if(is_recording && (PBDR & 0x4000)) - { #ifdef DEBUG - timing_info[timing_info_index++] = current_tick; - TCNT2 = 0; + timing_info[timing_info_index++] = current_tick; + TCNT2 = 0; #endif /* #ifdef DEBUG */ - /* We read as long as EOD is high, but max 30 bytes. - This code is optimized, and should probably be - written in assembler instead. */ - if(inverted_pr) + /* We read as long as EOD is high, but max 30 bytes. + This code is optimized, and should probably be + written in assembler instead. */ + if(inverted_pr) + { + i = 0; + while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) + && i < 30) { - i = 0; - while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) - && i < 30) - { - or_b(0x08, &PADRH); + or_b(0x08, &PADRH); - while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); - - /* It must take at least 5 cycles before - the data is read */ - asm(" nop\n nop\n nop\n"); - mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; - - if(mp3buf_write >= mp3buflen) - mp3buf_write = 0; + while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); + + /* It must take at least 5 cycles before + the data is read */ + asm(" nop\n nop\n nop\n"); + mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; + + if(mp3buf_write >= mp3buflen) + mp3buf_write = 0; - i++; - - and_b(~0x08, &PADRH); + i++; + + and_b(~0x08, &PADRH); - /* No wait for /RTW, cause it's not necessary */ - } + /* No wait for /RTW, cause it's not necessary */ } - else /* !inverted_pr */ + } + else /* !inverted_pr */ + { + i = 0; + while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) + && i < 30) { - i = 0; - while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) - && i < 30) - { - and_b(~0x08, &PADRH); - - while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); - - /* It must take at least 5 cycles before - the data is read */ - asm(" nop\n nop\n nop\n"); - mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; - - if(mp3buf_write >= mp3buflen) - mp3buf_write = 0; + and_b(~0x08, &PADRH); + + while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); + + /* It must take at least 5 cycles before + the data is read */ + asm(" nop\n nop\n nop\n"); + mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; + + if(mp3buf_write >= mp3buflen) + mp3buf_write = 0; - i++; - - or_b(0x08, &PADRH); + i++; + + or_b(0x08, &PADRH); - /* No wait for /RTW, cause it's not necessary */ - } + /* No wait for /RTW, cause it's not necessary */ } + } #ifdef DEBUG - timing_info[timing_info_index++] = TCNT2 + (i << 16); - timing_info_index &= 0x3ff; + timing_info[timing_info_index++] = TCNT2 + (i << 16); + timing_info_index &= 0x3ff; #endif /* #ifdef DEBUG */ - num_rec_bytes += i; - - if(is_prerecording) + num_rec_bytes += i; + + if(is_prerecording) + { + if(TIME_AFTER(current_tick, prerecord_timeout)) { - if(TIME_AFTER(current_tick, prerecord_timeout)) - { - prerecord_timeout = current_tick + HZ; + prerecord_timeout = current_tick + HZ; - /* Store the write pointer every second */ - prerecord_buffer[prerecord_index++] = mp3buf_write; + /* Store the write pointer every second */ + prerecord_buffer[prerecord_index++] = mp3buf_write; - /* Wrap if necessary */ - if(prerecord_index == prerecording_max_seconds) - prerecord_index = 0; + /* Wrap if necessary */ + if(prerecord_index == prerecording_max_seconds) + prerecord_index = 0; - /* Update the number of seconds recorded */ - if(prerecord_count < prerecording_max_seconds) - prerecord_count++; - } + /* Update the number of seconds recorded */ + if(prerecord_count < prerecording_max_seconds) + prerecord_count++; } - else + } + else + { + /* Signal to save the data if we are running out of buffer + space */ + num_bytes = mp3buf_write - mp3buf_read; + if(num_bytes < 0) + num_bytes += mp3buflen; + + if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) { - /* Signal to save the data if we are running out of buffer - space */ - num_bytes = mp3buf_write - mp3buf_read; - if(num_bytes < 0) - num_bytes += mp3buflen; - - if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) - { - saving = true; - queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); - wake_up_thread(); - } + saving = true; + queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); + wake_up_thread(); } } } #endif /* #ifdef HAVE_MAS3587F */ } +void playback_tick(void) +{ + id3tags[tag_read_idx]->id3.elapsed += + (current_tick - last_dma_tick) * 1000 / HZ; + last_dma_tick = current_tick; +} + static void reset_mp3_buffer(void) { mp3buf_read = 0; @@ -751,48 +712,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize) wake_up_thread(); } -#ifdef HAVE_MAS3587F -static void demand_irq_enable(bool on) -{ - int oldlevel = set_irq_level(15); - - if(on) - { - IPRA = (IPRA & 0xfff0) | 0x000b; - ICR &= ~0x0010; /* IRQ3 level sensitive */ - } - else - IPRA &= 0xfff0; - - set_irq_level(oldlevel); -} -#endif /* #ifdef HAVE_MAS3587F */ - -#pragma interrupt -void IMIA1(void) /* Timer 1 interrupt */ -{ - dma_tick(); - TSR1 &= ~0x01; -#ifdef HAVE_MAS3587F - /* Disable interrupt */ - IPRC &= ~0x000f; -#endif /* #ifdef HAVE_MAS3587F */ -} - -#ifdef HAVE_MAS3587F -#pragma interrupt -void IRQ3(void) /* PA15: MAS demand IRQ */ -{ - /* Begin with setting the IRQ to edge sensitive */ - ICR |= 0x0010; - - if(mpeg_mode == MPEG_ENCODER) - dma_tick(); - else - postpone_dma_tick(); -} -#endif /* #ifdef HAVE_MAS3587F */ - static int add_track_to_tag_list(char *filename) { struct id3tag *t = NULL; @@ -892,15 +811,12 @@ static int new_file(int steps) static void stop_playing(void) { /* Stop the current stream */ -#ifdef HAVE_MAS3587F - demand_irq_enable(false); -#endif /* #ifdef HAVE_MAS3587F */ + mp3_play_stop(); playing = false; filling = false; if(mpeg_file >= 0) close(mpeg_file); mpeg_file = -1; - mp3_play_pause(false); remove_all_tags(); } @@ -967,17 +883,14 @@ static void start_playback_if_ready(void) play_pending = false; playing = true; - last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end); - dma_underrun = false; - if (!paused) { + last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); + mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end); + dma_underrun = false; + last_dma_tick = current_tick; mp3_play_pause(true); -#ifdef HAVE_MAS3587F - demand_irq_enable(true); -#endif /* #ifdef HAVE_MAS3587F */ } /* Tell ourselves that we need more data */ @@ -2002,10 +1915,7 @@ static void mpeg_thread(void) case MPEG_INIT_PLAYBACK: /* Stop the prerecording */ stop_recording(); - mp3_play_init(); - mpeg_mode = MPEG_DECODER; - init_playback_done = true; break; -- cgit v1.2.3