summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/mp3_playback.h8
-rw-r--r--firmware/export/mpeg.h4
-rw-r--r--firmware/mp3_playback.c156
-rw-r--r--firmware/mpeg.c276
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);
40void mpeg_set_pitch(int percent); 40void mpeg_set_pitch(int percent);
41#endif 41#endif
42 42
43
44/* exported just for mpeg.c, to keep the recording there */
45#ifdef HAVE_MAS3587F
46void demand_irq_enable(bool on);
47#endif
48
43/* new functions, to be exported to plugin API */ 49/* new functions, to be exported to plugin API */
44void mp3_play_init(void); 50void mp3_play_init(void);
45void mp3_play_data(unsigned char* start, int size, 51void mp3_play_data(unsigned char* start, int size,
@@ -47,6 +53,8 @@ void mp3_play_data(unsigned char* start, int size,
47); 53);
48void mp3_play_pause(bool play); 54void mp3_play_pause(bool play);
49void mp3_play_stop(void); 55void mp3_play_stop(void);
56long mp3_get_playtime(void);
57void mp3_reset_playtime(void);
50 58
51 59
52#define SOUND_VOLUME 0 60#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);
90unsigned int mpeg_error(void); 90unsigned int mpeg_error(void);
91void mpeg_error_clear(void); 91void mpeg_error_clear(void);
92 92
93/* in order to keep the recording here, I have to expose this */
94void rec_tick(void);
95void playback_tick(void); /* FixMe: get rid of this, use mp3_get_playtime() */
96
93#define MPEG_STATUS_PLAY 1 97#define MPEG_STATUS_PLAY 1
94#define MPEG_STATUS_PAUSE 2 98#define MPEG_STATUS_PAUSE 2
95#define MPEG_STATUS_RECORD 4 99#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 @@
34#include "hwcompat.h" 34#include "hwcompat.h"
35#endif 35#endif
36 36
37/* hacking into mpeg.c, recording is still there */
38#ifdef HAVE_MAS3587F
39enum
40{
41 MPEG_DECODER,
42 MPEG_ENCODER
43} mpeg_mode;
44#endif /* #ifdef HAVE_MAS3587F */
45
46/**** globals ****/
47
48/* own version, independent of mpeg.c */
49static bool paused; /* playback is paused */
50static bool playing; /* We are playing an MP3 stream */
51
52#ifndef SIMULATOR
53/* for measuring the play time */
54static long playstart_tick;
55static long cumulative_ticks;
56
57/* the registered callback function to ask for more mp3 data */
58static void (*callback_for_more)(unsigned char**, int*);
59#endif /* #ifndef SIMULATOR */
60
37static char *units[] = 61static char *units[] =
38{ 62{
39 "%", /* Volume */ 63 "%", /* Volume */
@@ -283,10 +307,65 @@ static void mas_poll_start(int interval_in_ms)
283 307
284 TSTR |= 0x02; /* Start timer 1 */ 308 TSTR |= 0x02; /* Start timer 1 */
285} 309}
310#else
311static void postpone_dma_tick(void)
312{
313 unsigned int count;
314
315 count = FREQ / 1000 / 8;
316
317 /* We are using timer 1 */
318
319 TSTR &= ~0x02; /* Stop the timer */
320 TSNC &= ~0x02; /* No synchronization */
321 TMDR &= ~0x02; /* Operate normally */
322
323 TCNT1 = 0; /* Start counting at 0 */
324 GRA1 = count;
325 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
326
327 /* Enable interrupt on level 5 */
328 IPRC = (IPRC & ~0x000f) | 0x0005;
329
330 TSR1 &= ~0x02;
331 TIER1 = 0xf9; /* Enable GRA match interrupt */
332
333 TSTR |= 0x02; /* Start timer 1 */
334}
286#endif 335#endif
287 336
288/* the registered callback function ta ask for more mp3 data */ 337
289static void (*callback_for_more)(unsigned char**, int*); 338#ifdef HAVE_MAS3587F
339void demand_irq_enable(bool on)
340{
341 int oldlevel = set_irq_level(15);
342
343 if(on)
344 {
345 IPRA = (IPRA & 0xfff0) | 0x000b;
346 ICR &= ~0x0010; /* IRQ3 level sensitive */
347 }
348 else
349 IPRA &= 0xfff0;
350
351 set_irq_level(oldlevel);
352}
353#endif /* #ifdef HAVE_MAS3587F */
354
355
356void play_tick(void)
357{
358 if(playing && !paused)
359 {
360 /* Start DMA if it is disabled and the DEMAND pin is high */
361 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
362 {
363 SCR0 |= 0x80;
364 }
365
366 playback_tick(); /* dirty call to mpeg.c */
367 }
368}
290 369
291#pragma interrupt 370#pragma interrupt
292void DEI3(void) 371void DEI3(void)
@@ -313,10 +392,36 @@ void DEI3(void)
313} 392}
314 393
315#pragma interrupt 394#pragma interrupt
395void IMIA1(void) /* Timer 1 interrupt */
396{
397 if(playing)
398 play_tick();
399 TSR1 &= ~0x01;
400#ifdef HAVE_MAS3587F
401 /* Disable interrupt */
402 IPRC &= ~0x000f;
403#endif /* #ifdef HAVE_MAS3587F */
404}
405
406#pragma interrupt
316void IRQ6(void) /* PB14: MAS stop demand IRQ */ 407void IRQ6(void) /* PB14: MAS stop demand IRQ */
317{ 408{
318 mp3_play_pause(false); 409 SCR0 &= ~0x80;
410}
411
412#ifdef HAVE_MAS3587F
413#pragma interrupt
414void IRQ3(void) /* PA15: MAS demand IRQ */
415{
416 /* Begin with setting the IRQ to edge sensitive */
417 ICR |= 0x0010;
418
419 if(mpeg_mode == MPEG_ENCODER)
420 rec_tick();
421 else
422 postpone_dma_tick();
319} 423}
424#endif /* #ifdef HAVE_MAS3587F */
320 425
321static void setup_sci0(void) 426static void setup_sci0(void)
322{ 427{
@@ -404,6 +509,8 @@ static void init_playback(void)
404 509
405 mpeg_sound_channel_config(MPEG_SOUND_STEREO); 510 mpeg_sound_channel_config(MPEG_SOUND_STEREO);
406 511
512 mpeg_mode = MPEG_DECODER;
513
407 /* set IRQ6 to edge detect */ 514 /* set IRQ6 to edge detect */
408 ICR |= 0x02; 515 ICR |= 0x02;
409 516
@@ -893,6 +1000,9 @@ void mp3_init(int volume, int bass, int treble, int balance, int loudness,
893 mpeg_sound_set(SOUND_AVC, avc); 1000 mpeg_sound_set(SOUND_AVC, avc);
894#endif 1001#endif
895#endif /* !SIMULATOR */ 1002#endif /* !SIMULATOR */
1003
1004 playing = false;
1005 paused = true;
896} 1006}
897 1007
898 1008
@@ -905,7 +1015,10 @@ void mp3_play_init(void)
905#ifdef HAVE_MAS3587F 1015#ifdef HAVE_MAS3587F
906 init_playback(); 1016 init_playback();
907#endif 1017#endif
1018 playing = false;
1019 paused = true;
908 callback_for_more = NULL; 1020 callback_for_more = NULL;
1021 mp3_reset_playtime();
909} 1022}
910 1023
911void mp3_play_data(unsigned char* start, int size, 1024void mp3_play_data(unsigned char* start, int size,
@@ -923,21 +1036,54 @@ void mp3_play_data(unsigned char* start, int size,
923 SAR3 = (unsigned int)start; 1036 SAR3 = (unsigned int)start;
924 DTCR3 = size & 0xffff; 1037 DTCR3 = size & 0xffff;
925 1038
1039 playing = true;
1040 paused = true;
1041
926 CHCR3 |= 0x0001; /* Enable DMA IRQ */ 1042 CHCR3 |= 0x0001; /* Enable DMA IRQ */
1043
1044#ifdef HAVE_MAS3587F
1045 demand_irq_enable(true);
1046#endif
927} 1047}
928 1048
929void mp3_play_pause(bool play) 1049void mp3_play_pause(bool play)
930{ 1050{
931 if (play) 1051 if (paused && play)
1052 { /* resume playback */
932 SCR0 |= 0x80; 1053 SCR0 |= 0x80;
933 else 1054 paused = false;
1055 playstart_tick = current_tick;
1056 }
1057 else if (!paused && !play)
1058 { /* stop playback */
934 SCR0 &= 0x7f; 1059 SCR0 &= 0x7f;
1060 paused = true;
1061 cumulative_ticks += current_tick - playstart_tick;
1062 }
935} 1063}
936 1064
937void mp3_play_stop(void) 1065void mp3_play_stop(void)
938{ 1066{
1067 playing = false;
939 mp3_play_pause(false); 1068 mp3_play_pause(false);
940 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ 1069 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
1070#ifdef HAVE_MAS3587F
1071 demand_irq_enable(false);
1072#endif
1073}
1074
1075long mp3_get_playtime(void)
1076{
1077 if (paused)
1078 return cumulative_ticks;
1079 else
1080 return cumulative_ticks + current_tick - playstart_tick;
1081}
1082
1083void mp3_reset_playtime(void)
1084{
1085 cumulative_ticks = 0;
1086 playstart_tick = current_tick;
941} 1087}
942 1088
943#endif /* #ifndef SIMULATOR */ 1089#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);
74#define MPEG_STOP_DONE 103 74#define MPEG_STOP_DONE 103
75 75
76#ifdef HAVE_MAS3587F 76#ifdef HAVE_MAS3587F
77static enum 77extern enum /* from mp3_playback.c */
78{ 78{
79 MPEG_DECODER, 79 MPEG_DECODER,
80 MPEG_ENCODER 80 MPEG_ENCODER
@@ -371,33 +371,6 @@ void mpeg_get_debugdata(struct mpeg_debug *dbgdata)
371 dbgdata->lowest_watermark_level = lowest_watermark_level; 371 dbgdata->lowest_watermark_level = lowest_watermark_level;
372} 372}
373 373
374#ifndef HAVE_MAS3507D
375static void postpone_dma_tick(void)
376{
377 unsigned int count;
378
379 count = FREQ / 1000 / 8;
380
381 /* We are using timer 1 */
382
383 TSTR &= ~0x02; /* Stop the timer */
384 TSNC &= ~0x02; /* No synchronization */
385 TMDR &= ~0x02; /* Operate normally */
386
387 TCNT1 = 0; /* Start counting at 0 */
388 GRA1 = count;
389 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
390
391 /* Enable interrupt on level 5 */
392 IPRC = (IPRC & ~0x000f) | 0x0005;
393
394 TSR1 &= ~0x02;
395 TIER1 = 0xf9; /* Enable GRA match interrupt */
396
397 TSTR |= 0x02; /* Start timer 1 */
398}
399#endif /* #ifndef HAVE_MAS3507D */
400
401#ifdef DEBUG 374#ifdef DEBUG
402static void dbg_timer_start(void) 375static void dbg_timer_start(void)
403{ 376{
@@ -524,134 +497,122 @@ static void drain_dma_buffer(void)
524 497
525#endif /* #ifdef HAVE_MAS3587F */ 498#endif /* #ifdef HAVE_MAS3587F */
526 499
527static void dma_tick (void) __attribute__ ((section (".icode"))); 500void rec_tick (void) __attribute__ ((section (".icode")));
528static void dma_tick(void) 501void rec_tick(void)
529{ 502{
530#ifdef HAVE_MAS3587F 503#ifdef HAVE_MAS3587F
531 if(mpeg_mode == MPEG_DECODER) 504 int i;
532 { 505 int num_bytes;
533#endif /* #ifdef HAVE_MAS3587F */ 506 if(is_recording && (PBDR & 0x4000))
534 if(playing && !paused)
535 {
536 /* Start DMA if it is disabled and the DEMAND pin is high */
537 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
538 {
539 mp3_play_pause(true);
540 }
541 id3tags[tag_read_idx]->id3.elapsed +=
542 (current_tick - last_dma_tick) * 1000 / HZ;
543 last_dma_tick = current_tick;
544 }
545#ifdef HAVE_MAS3587F
546 }
547 else /* MPEG_ENCODER */
548 { 507 {
549 int i;
550 int num_bytes;
551 if(is_recording && (PBDR & 0x4000))
552 {
553#ifdef DEBUG 508#ifdef DEBUG
554 timing_info[timing_info_index++] = current_tick; 509 timing_info[timing_info_index++] = current_tick;
555 TCNT2 = 0; 510 TCNT2 = 0;
556#endif /* #ifdef DEBUG */ 511#endif /* #ifdef DEBUG */
557 /* We read as long as EOD is high, but max 30 bytes. 512 /* We read as long as EOD is high, but max 30 bytes.
558 This code is optimized, and should probably be 513 This code is optimized, and should probably be
559 written in assembler instead. */ 514 written in assembler instead. */
560 if(inverted_pr) 515 if(inverted_pr)
516 {
517 i = 0;
518 while((*((volatile unsigned char *)PBDR_ADDR) & 0x40)
519 && i < 30)
561 { 520 {
562 i = 0; 521 or_b(0x08, &PADRH);
563 while((*((volatile unsigned char *)PBDR_ADDR) & 0x40)
564 && i < 30)
565 {
566 or_b(0x08, &PADRH);
567 522
568 while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); 523 while(*((volatile unsigned char *)PBDR_ADDR) & 0x80);
569 524
570 /* It must take at least 5 cycles before 525 /* It must take at least 5 cycles before
571 the data is read */ 526 the data is read */
572 asm(" nop\n nop\n nop\n"); 527 asm(" nop\n nop\n nop\n");
573 mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; 528 mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000;
574 529
575 if(mp3buf_write >= mp3buflen) 530 if(mp3buf_write >= mp3buflen)
576 mp3buf_write = 0; 531 mp3buf_write = 0;
577 532
578 i++; 533 i++;
579 534
580 and_b(~0x08, &PADRH); 535 and_b(~0x08, &PADRH);
581 536
582 /* No wait for /RTW, cause it's not necessary */ 537 /* No wait for /RTW, cause it's not necessary */
583 }
584 } 538 }
585 else /* !inverted_pr */ 539 }
540 else /* !inverted_pr */
541 {
542 i = 0;
543 while((*((volatile unsigned char *)PBDR_ADDR) & 0x40)
544 && i < 30)
586 { 545 {
587 i = 0; 546 and_b(~0x08, &PADRH);
588 while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) 547
589 && i < 30) 548 while(*((volatile unsigned char *)PBDR_ADDR) & 0x80);
590 { 549
591 and_b(~0x08, &PADRH); 550 /* It must take at least 5 cycles before
592 551 the data is read */
593 while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); 552 asm(" nop\n nop\n nop\n");
594 553 mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000;
595 /* It must take at least 5 cycles before 554
596 the data is read */ 555 if(mp3buf_write >= mp3buflen)
597 asm(" nop\n nop\n nop\n"); 556 mp3buf_write = 0;
598 mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000;
599
600 if(mp3buf_write >= mp3buflen)
601 mp3buf_write = 0;
602 557
603 i++; 558 i++;
604 559
605 or_b(0x08, &PADRH); 560 or_b(0x08, &PADRH);
606 561
607 /* No wait for /RTW, cause it's not necessary */ 562 /* No wait for /RTW, cause it's not necessary */
608 }
609 } 563 }
564 }
610#ifdef DEBUG 565#ifdef DEBUG
611 timing_info[timing_info_index++] = TCNT2 + (i << 16); 566 timing_info[timing_info_index++] = TCNT2 + (i << 16);
612 timing_info_index &= 0x3ff; 567 timing_info_index &= 0x3ff;
613#endif /* #ifdef DEBUG */ 568#endif /* #ifdef DEBUG */
614 569
615 num_rec_bytes += i; 570 num_rec_bytes += i;
616 571
617 if(is_prerecording) 572 if(is_prerecording)
573 {
574 if(TIME_AFTER(current_tick, prerecord_timeout))
618 { 575 {
619 if(TIME_AFTER(current_tick, prerecord_timeout)) 576 prerecord_timeout = current_tick + HZ;
620 {
621 prerecord_timeout = current_tick + HZ;
622 577
623 /* Store the write pointer every second */ 578 /* Store the write pointer every second */
624 prerecord_buffer[prerecord_index++] = mp3buf_write; 579 prerecord_buffer[prerecord_index++] = mp3buf_write;
625 580
626 /* Wrap if necessary */ 581 /* Wrap if necessary */
627 if(prerecord_index == prerecording_max_seconds) 582 if(prerecord_index == prerecording_max_seconds)
628 prerecord_index = 0; 583 prerecord_index = 0;
629 584
630 /* Update the number of seconds recorded */ 585 /* Update the number of seconds recorded */
631 if(prerecord_count < prerecording_max_seconds) 586 if(prerecord_count < prerecording_max_seconds)
632 prerecord_count++; 587 prerecord_count++;
633 }
634 } 588 }
635 else 589 }
590 else
591 {
592 /* Signal to save the data if we are running out of buffer
593 space */
594 num_bytes = mp3buf_write - mp3buf_read;
595 if(num_bytes < 0)
596 num_bytes += mp3buflen;
597
598 if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving)
636 { 599 {
637 /* Signal to save the data if we are running out of buffer 600 saving = true;
638 space */ 601 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
639 num_bytes = mp3buf_write - mp3buf_read; 602 wake_up_thread();
640 if(num_bytes < 0)
641 num_bytes += mp3buflen;
642
643 if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving)
644 {
645 saving = true;
646 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
647 wake_up_thread();
648 }
649 } 603 }
650 } 604 }
651 } 605 }
652#endif /* #ifdef HAVE_MAS3587F */ 606#endif /* #ifdef HAVE_MAS3587F */
653} 607}
654 608
609void playback_tick(void)
610{
611 id3tags[tag_read_idx]->id3.elapsed +=
612 (current_tick - last_dma_tick) * 1000 / HZ;
613 last_dma_tick = current_tick;
614}
615
655static void reset_mp3_buffer(void) 616static void reset_mp3_buffer(void)
656{ 617{
657 mp3buf_read = 0; 618 mp3buf_read = 0;
@@ -751,48 +712,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize)
751 wake_up_thread(); 712 wake_up_thread();
752} 713}
753 714
754#ifdef HAVE_MAS3587F
755static void demand_irq_enable(bool on)
756{
757 int oldlevel = set_irq_level(15);
758
759 if(on)
760 {
761 IPRA = (IPRA & 0xfff0) | 0x000b;
762 ICR &= ~0x0010; /* IRQ3 level sensitive */
763 }
764 else
765 IPRA &= 0xfff0;
766
767 set_irq_level(oldlevel);
768}
769#endif /* #ifdef HAVE_MAS3587F */
770
771#pragma interrupt
772void IMIA1(void) /* Timer 1 interrupt */
773{
774 dma_tick();
775 TSR1 &= ~0x01;
776#ifdef HAVE_MAS3587F
777 /* Disable interrupt */
778 IPRC &= ~0x000f;
779#endif /* #ifdef HAVE_MAS3587F */
780}
781
782#ifdef HAVE_MAS3587F
783#pragma interrupt
784void IRQ3(void) /* PA15: MAS demand IRQ */
785{
786 /* Begin with setting the IRQ to edge sensitive */
787 ICR |= 0x0010;
788
789 if(mpeg_mode == MPEG_ENCODER)
790 dma_tick();
791 else
792 postpone_dma_tick();
793}
794#endif /* #ifdef HAVE_MAS3587F */
795
796static int add_track_to_tag_list(char *filename) 715static int add_track_to_tag_list(char *filename)
797{ 716{
798 struct id3tag *t = NULL; 717 struct id3tag *t = NULL;
@@ -892,15 +811,12 @@ static int new_file(int steps)
892static void stop_playing(void) 811static void stop_playing(void)
893{ 812{
894 /* Stop the current stream */ 813 /* Stop the current stream */
895#ifdef HAVE_MAS3587F 814 mp3_play_stop();
896 demand_irq_enable(false);
897#endif /* #ifdef HAVE_MAS3587F */
898 playing = false; 815 playing = false;
899 filling = false; 816 filling = false;
900 if(mpeg_file >= 0) 817 if(mpeg_file >= 0)
901 close(mpeg_file); 818 close(mpeg_file);
902 mpeg_file = -1; 819 mpeg_file = -1;
903 mp3_play_pause(false);
904 remove_all_tags(); 820 remove_all_tags();
905} 821}
906 822
@@ -967,17 +883,14 @@ static void start_playback_if_ready(void)
967 play_pending = false; 883 play_pending = false;
968 playing = true; 884 playing = true;
969 885
970 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
971 mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end);
972 dma_underrun = false;
973
974 if (!paused) 886 if (!paused)
975 { 887 {
888 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
889 mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end);
890 dma_underrun = false;
891
976 last_dma_tick = current_tick; 892 last_dma_tick = current_tick;
977 mp3_play_pause(true); 893 mp3_play_pause(true);
978#ifdef HAVE_MAS3587F
979 demand_irq_enable(true);
980#endif /* #ifdef HAVE_MAS3587F */
981 } 894 }
982 895
983 /* Tell ourselves that we need more data */ 896 /* Tell ourselves that we need more data */
@@ -2002,10 +1915,7 @@ static void mpeg_thread(void)
2002 case MPEG_INIT_PLAYBACK: 1915 case MPEG_INIT_PLAYBACK:
2003 /* Stop the prerecording */ 1916 /* Stop the prerecording */
2004 stop_recording(); 1917 stop_recording();
2005
2006 mp3_play_init(); 1918 mp3_play_init();
2007 mpeg_mode = MPEG_DECODER;
2008
2009 init_playback_done = true; 1919 init_playback_done = true;
2010 break; 1920 break;
2011 1921