diff options
Diffstat (limited to 'firmware/mpeg.c')
-rw-r--r-- | firmware/mpeg.c | 203 |
1 files changed, 152 insertions, 51 deletions
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 00b2d660a3..359db614ce 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "id3.h" | 23 | #include "id3.h" |
24 | #include "mpeg.h" | 24 | #include "mpeg.h" |
25 | #include "ata.h" | 25 | #include "ata.h" |
26 | #include "malloc.h" | ||
27 | #include "string.h" | ||
26 | #ifndef SIMULATOR | 28 | #ifndef SIMULATOR |
27 | #include "i2c.h" | 29 | #include "i2c.h" |
28 | #include "mas.h" | 30 | #include "mas.h" |
@@ -139,15 +141,93 @@ int mpeg_sound_default(int setting) | |||
139 | } | 141 | } |
140 | 142 | ||
141 | /* list of tracks in memory */ | 143 | /* list of tracks in memory */ |
142 | #define MAX_ID3_TAGS 12 | 144 | #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */ |
143 | static struct { | 145 | #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1) |
146 | |||
147 | struct id3tag | ||
148 | { | ||
144 | struct mp3entry id3; | 149 | struct mp3entry id3; |
145 | int mempos; | 150 | int mempos; |
146 | } id3tags[MAX_ID3_TAGS]; | 151 | }; |
152 | |||
153 | static struct id3tag *id3tags[MAX_ID3_TAGS]; | ||
154 | |||
147 | static unsigned int current_track_counter = 0; | 155 | static unsigned int current_track_counter = 0; |
148 | static unsigned int last_track_counter = 0; | 156 | static unsigned int last_track_counter = 0; |
149 | 157 | ||
150 | #ifndef SIMULATOR | 158 | #ifndef SIMULATOR |
159 | |||
160 | static int tag_read_idx = 0; | ||
161 | static int tag_write_idx = 0; | ||
162 | |||
163 | static int num_tracks_in_memory(void) | ||
164 | { | ||
165 | return (tag_write_idx - tag_read_idx) & MAX_ID3_TAGS_MASK; | ||
166 | } | ||
167 | #endif | ||
168 | |||
169 | #ifndef SIMULATOR | ||
170 | static void debug_tags(void) | ||
171 | { | ||
172 | #ifdef DEBUG | ||
173 | int i; | ||
174 | |||
175 | for(i = 0;i < MAX_ID3_TAGS;i++) | ||
176 | { | ||
177 | DEBUGF("id3tags[%d]: %08x", i, id3tags[i]); | ||
178 | if(id3tags[i]) | ||
179 | DEBUGF(" - %s", id3tags[i]->id3.path); | ||
180 | DEBUGF("\n"); | ||
181 | } | ||
182 | DEBUGF("read: %d, write :%d\n", tag_read_idx, tag_write_idx); | ||
183 | DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | static bool append_tag(struct id3tag *tag) | ||
188 | { | ||
189 | if(num_tracks_in_memory() < MAX_ID3_TAGS - 1) | ||
190 | { | ||
191 | id3tags[tag_write_idx] = tag; | ||
192 | tag_write_idx = (tag_write_idx+1) & MAX_ID3_TAGS_MASK; | ||
193 | debug_tags(); | ||
194 | return true; | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | DEBUGF("Tag memory is full\n"); | ||
199 | return false; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void remove_current_tag(void) | ||
204 | { | ||
205 | int oldidx = tag_read_idx; | ||
206 | struct id3tag *tag = id3tags[tag_read_idx]; | ||
207 | |||
208 | if(num_tracks_in_memory() > 0) | ||
209 | { | ||
210 | /* First move the index, so nobody tries to access the tag */ | ||
211 | tag_read_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; | ||
212 | |||
213 | /* Now delete it */ | ||
214 | id3tags[oldidx] = NULL; | ||
215 | free(tag); | ||
216 | debug_tags(); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static void remove_all_tags(void) | ||
221 | { | ||
222 | int i; | ||
223 | |||
224 | for(i = 0;i < MAX_ID3_TAGS;i++) | ||
225 | remove_current_tag(); | ||
226 | debug_tags(); | ||
227 | } | ||
228 | #endif | ||
229 | |||
230 | #ifndef SIMULATOR | ||
151 | static int last_tag = 0; | 231 | static int last_tag = 0; |
152 | static int last_dma_tick = 0; | 232 | static int last_dma_tick = 0; |
153 | static int pause_tick = 0; | 233 | static int pause_tick = 0; |
@@ -380,7 +460,8 @@ static void dma_tick(void) | |||
380 | if(!(SCR0 & 0x80)) | 460 | if(!(SCR0 & 0x80)) |
381 | start_dma(); | 461 | start_dma(); |
382 | } | 462 | } |
383 | id3tags[0].id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; | 463 | id3tags[tag_read_idx]->id3.elapsed += |
464 | (current_tick - last_dma_tick) * 1000 / HZ; | ||
384 | last_dma_tick = current_tick; | 465 | last_dma_tick = current_tick; |
385 | } | 466 | } |
386 | } | 467 | } |
@@ -412,7 +493,7 @@ void DEI3(void) | |||
412 | { | 493 | { |
413 | int unplayed_space_left; | 494 | int unplayed_space_left; |
414 | int space_until_end_of_buffer; | 495 | int space_until_end_of_buffer; |
415 | int track_offset = 0; | 496 | int track_offset = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; |
416 | 497 | ||
417 | if(playing) | 498 | if(playing) |
418 | { | 499 | { |
@@ -421,12 +502,12 @@ void DEI3(void) | |||
421 | mp3buf_read = 0; | 502 | mp3buf_read = 0; |
422 | 503 | ||
423 | /* First, check if we are on a track boundary */ | 504 | /* First, check if we are on a track boundary */ |
424 | if (last_tag > 1) | 505 | if (num_tracks_in_memory() > 0) |
425 | { | 506 | { |
426 | if (mp3buf_read == id3tags[1].mempos) | 507 | if (mp3buf_read == id3tags[track_offset]->mempos) |
427 | { | 508 | { |
428 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | 509 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); |
429 | track_offset = 1; | 510 | track_offset = (track_offset+1) & MAX_ID3_TAGS_MASK; |
430 | } | 511 | } |
431 | } | 512 | } |
432 | 513 | ||
@@ -449,15 +530,15 @@ void DEI3(void) | |||
449 | space_until_end_of_buffer); | 530 | space_until_end_of_buffer); |
450 | 531 | ||
451 | /* several tracks loaded? */ | 532 | /* several tracks loaded? */ |
452 | if ((last_tag - track_offset) > 1) | 533 | if (num_tracks_in_memory() > 1) |
453 | { | 534 | { |
454 | /* will we move across the track boundary? */ | 535 | /* will we move across the track boundary? */ |
455 | if (( mp3buf_read < id3tags[1+track_offset].mempos ) && | 536 | if (( mp3buf_read < id3tags[track_offset]->mempos ) && |
456 | ((mp3buf_read+last_dma_chunk_size) > | 537 | ((mp3buf_read+last_dma_chunk_size) > |
457 | id3tags[1+track_offset].mempos )) | 538 | id3tags[track_offset]->mempos )) |
458 | { | 539 | { |
459 | /* Make sure that we end exactly on the boundary */ | 540 | /* Make sure that we end exactly on the boundary */ |
460 | last_dma_chunk_size = id3tags[1+track_offset].mempos | 541 | last_dma_chunk_size = id3tags[track_offset]->mempos |
461 | - mp3buf_read; | 542 | - mp3buf_read; |
462 | } | 543 | } |
463 | } | 544 | } |
@@ -468,6 +549,7 @@ void DEI3(void) | |||
468 | else | 549 | else |
469 | { | 550 | { |
470 | DEBUGF("No more MP3 data. Stopping.\n"); | 551 | DEBUGF("No more MP3 data. Stopping.\n"); |
552 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
471 | CHCR3 = 0; /* Stop DMA interrupt */ | 553 | CHCR3 = 0; /* Stop DMA interrupt */ |
472 | playing = false; | 554 | playing = false; |
473 | } | 555 | } |
@@ -483,11 +565,34 @@ void IMIA1(void) | |||
483 | TSR1 &= ~0x01; | 565 | TSR1 &= ~0x01; |
484 | } | 566 | } |
485 | 567 | ||
568 | static void add_track_to_tag_list(char *filename) | ||
569 | { | ||
570 | struct id3tag *t; | ||
571 | |||
572 | /* grab id3 tag of new file and | ||
573 | remember where in memory it starts */ | ||
574 | t = malloc(sizeof(struct id3tag)); | ||
575 | if(t) | ||
576 | { | ||
577 | mp3info(&(t->id3), filename); | ||
578 | t->mempos = mp3buf_write; | ||
579 | t->id3.elapsed = 0; | ||
580 | if(!append_tag(t)) | ||
581 | { | ||
582 | free(t); | ||
583 | DEBUGF("Tag list is full\n"); | ||
584 | } | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | DEBUGF("No memory available for id3 tag"); | ||
589 | } | ||
590 | } | ||
591 | |||
486 | /* If next_track is true, opens the next track, if false, opens prev track */ | 592 | /* If next_track is true, opens the next track, if false, opens prev track */ |
487 | static int new_file(bool next_track) | 593 | static int new_file(bool next_track) |
488 | { | 594 | { |
489 | char *trackname; | 595 | char *trackname; |
490 | int i; | ||
491 | 596 | ||
492 | do { | 597 | do { |
493 | trackname = peek_next_track( next_track ? 1 : -1 ); | 598 | trackname = peek_next_track( next_track ? 1 : -1 ); |
@@ -500,18 +605,9 @@ static int new_file(bool next_track) | |||
500 | if(mpeg_file < 0) { | 605 | if(mpeg_file < 0) { |
501 | DEBUGF("Couldn't open file: %s\n",trackname); | 606 | DEBUGF("Couldn't open file: %s\n",trackname); |
502 | } | 607 | } |
503 | else { | 608 | else |
504 | /* grab id3 tag of new file and remember where | 609 | { |
505 | in memory it starts */ | 610 | add_track_to_tag_list(trackname); |
506 | if ( last_tag < MAX_ID3_TAGS ) { | ||
507 | mp3info(&(id3tags[last_tag].id3), trackname); | ||
508 | id3tags[last_tag].mempos = mp3buf_write; | ||
509 | last_tag++; | ||
510 | for(i = 0;i < last_tag;i++) | ||
511 | { | ||
512 | DEBUGF("nf: %d, %x\n", i, id3tags[i].mempos); | ||
513 | } | ||
514 | } | ||
515 | } | 611 | } |
516 | } while ( mpeg_file < 0 ); | 612 | } while ( mpeg_file < 0 ); |
517 | 613 | ||
@@ -527,6 +623,7 @@ static void stop_playing(void) | |||
527 | close(mpeg_file); | 623 | close(mpeg_file); |
528 | mpeg_file = -1; | 624 | mpeg_file = -1; |
529 | stop_dma(); | 625 | stop_dma(); |
626 | remove_all_tags(); | ||
530 | } | 627 | } |
531 | 628 | ||
532 | static void mpeg_thread(void) | 629 | static void mpeg_thread(void) |
@@ -537,7 +634,6 @@ static void mpeg_thread(void) | |||
537 | int unplayed_space_left; | 634 | int unplayed_space_left; |
538 | int amount_to_read; | 635 | int amount_to_read; |
539 | int amount_to_swap; | 636 | int amount_to_swap; |
540 | int i; | ||
541 | 637 | ||
542 | play_pending = false; | 638 | play_pending = false; |
543 | playing = false; | 639 | playing = false; |
@@ -559,6 +655,7 @@ static void mpeg_thread(void) | |||
559 | stop_dma(); | 655 | stop_dma(); |
560 | 656 | ||
561 | reset_mp3_buffer(); | 657 | reset_mp3_buffer(); |
658 | remove_all_tags(); | ||
562 | 659 | ||
563 | if(mpeg_file >= 0) | 660 | if(mpeg_file >= 0) |
564 | close(mpeg_file); | 661 | close(mpeg_file); |
@@ -569,13 +666,8 @@ static void mpeg_thread(void) | |||
569 | if ( new_file(true) == -1 ) | 666 | if ( new_file(true) == -1 ) |
570 | return; | 667 | return; |
571 | } | 668 | } |
572 | 669 | ||
573 | /* grab id3 tag of new file and | 670 | add_track_to_tag_list((char *)ev.data); |
574 | remember where in memory it starts */ | ||
575 | mp3info(&(id3tags[0].id3), ev.data); | ||
576 | id3tags[0].mempos = mp3buf_write; | ||
577 | last_tag=1; | ||
578 | id3tags[0].id3.elapsed = 0; | ||
579 | 671 | ||
580 | /* Make it read more data */ | 672 | /* Make it read more data */ |
581 | filling = true; | 673 | filling = true; |
@@ -618,12 +710,13 @@ static void mpeg_thread(void) | |||
618 | stop_dma(); | 710 | stop_dma(); |
619 | 711 | ||
620 | reset_mp3_buffer(); | 712 | reset_mp3_buffer(); |
713 | |||
621 | /* Open the next file */ | 714 | /* Open the next file */ |
622 | if (mpeg_file >= 0) | 715 | if (mpeg_file >= 0) |
623 | close(mpeg_file); | 716 | close(mpeg_file); |
624 | last_tag=0; | 717 | last_tag=0; |
625 | if (new_file(true) < 0) { | 718 | if (new_file(true) < 0) { |
626 | DEBUGF("Finished Playing!\n"); | 719 | DEBUGF("No more files to play\n"); |
627 | filling = false; | 720 | filling = false; |
628 | } else { | 721 | } else { |
629 | /* Make it read more data */ | 722 | /* Make it read more data */ |
@@ -651,7 +744,7 @@ static void mpeg_thread(void) | |||
651 | close(mpeg_file); | 744 | close(mpeg_file); |
652 | last_tag=0; | 745 | last_tag=0; |
653 | if (new_file(false) < 0) { | 746 | if (new_file(false) < 0) { |
654 | DEBUGF("Finished Playing!\n"); | 747 | DEBUGF("No more files to play\n"); |
655 | filling = false; | 748 | filling = false; |
656 | } else { | 749 | } else { |
657 | /* Make it read more data */ | 750 | /* Make it read more data */ |
@@ -701,7 +794,11 @@ static void mpeg_thread(void) | |||
701 | playing yet. If not, do it. */ | 794 | playing yet. If not, do it. */ |
702 | if(play_pending) | 795 | if(play_pending) |
703 | { | 796 | { |
704 | if((mp3buf_swapwrite - mp3buf_read) >= MPEG_LOW_WATER) | 797 | /* If the filling has stopped, and we still haven't reached |
798 | the watermark, the file must be smaller than the | ||
799 | watermark. We must still play it. */ | ||
800 | if(((mp3buf_swapwrite - mp3buf_read) >= MPEG_LOW_WATER) || | ||
801 | !filling) | ||
705 | { | 802 | { |
706 | DEBUGF("P\n"); | 803 | DEBUGF("P\n"); |
707 | play_pending = false; | 804 | play_pending = false; |
@@ -779,11 +876,8 @@ static void mpeg_thread(void) | |||
779 | DEBUGF("W\n"); | 876 | DEBUGF("W\n"); |
780 | } | 877 | } |
781 | 878 | ||
782 | if(!play_pending) | 879 | /* Tell ourselves that we want more data */ |
783 | { | 880 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); |
784 | /* Tell ourselves that we want more data */ | ||
785 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
786 | } | ||
787 | } | 881 | } |
788 | else | 882 | else |
789 | { | 883 | { |
@@ -802,7 +896,7 @@ static void mpeg_thread(void) | |||
802 | if(new_file(1) < 0) | 896 | if(new_file(1) < 0) |
803 | { | 897 | { |
804 | /* No more data to play */ | 898 | /* No more data to play */ |
805 | DEBUGF("Finished playing\n"); | 899 | DEBUGF("No more files to play\n"); |
806 | filling = false; | 900 | filling = false; |
807 | } | 901 | } |
808 | else | 902 | else |
@@ -821,13 +915,7 @@ static void mpeg_thread(void) | |||
821 | /* Reset the AVC */ | 915 | /* Reset the AVC */ |
822 | mpeg_sound_set(SOUND_AVC, -1); | 916 | mpeg_sound_set(SOUND_AVC, -1); |
823 | #endif | 917 | #endif |
824 | /* shift array so index 0 is current track */ | 918 | remove_current_tag(); |
825 | for (i=0; i<last_tag-1; i++) | ||
826 | { | ||
827 | id3tags[i] = id3tags[i+1]; | ||
828 | DEBUGF("tc: %d, %x\n", i, id3tags[i].mempos); | ||
829 | } | ||
830 | last_tag--; | ||
831 | 919 | ||
832 | current_track_counter++; | 920 | current_track_counter++; |
833 | break; | 921 | break; |
@@ -890,9 +978,20 @@ static void setup_sci0(void) | |||
890 | } | 978 | } |
891 | #endif /* SIMULATOR */ | 979 | #endif /* SIMULATOR */ |
892 | 980 | ||
981 | #ifdef SIMULATOR | ||
982 | static struct mp3entry taginfo; | ||
983 | #endif | ||
984 | |||
893 | struct mp3entry* mpeg_current_track(void) | 985 | struct mp3entry* mpeg_current_track(void) |
894 | { | 986 | { |
895 | return &(id3tags[0].id3); | 987 | #ifdef SIMULATOR |
988 | return &taginfo; | ||
989 | #else | ||
990 | if(num_tracks_in_memory()) | ||
991 | return &(id3tags[tag_read_idx]->id3); | ||
992 | else | ||
993 | return NULL; | ||
994 | #endif | ||
896 | } | 995 | } |
897 | 996 | ||
898 | bool mpeg_has_changed_track(void) | 997 | bool mpeg_has_changed_track(void) |
@@ -908,7 +1007,7 @@ bool mpeg_has_changed_track(void) | |||
908 | void mpeg_play(char* trackname) | 1007 | void mpeg_play(char* trackname) |
909 | { | 1008 | { |
910 | #ifdef SIMULATOR | 1009 | #ifdef SIMULATOR |
911 | mp3info(&(id3tags[0].id3), trackname); | 1010 | mp3info(&taginfo, trackname); |
912 | #else | 1011 | #else |
913 | queue_post(&mpeg_queue, MPEG_PLAY, trackname); | 1012 | queue_post(&mpeg_queue, MPEG_PLAY, trackname); |
914 | #endif | 1013 | #endif |
@@ -1217,4 +1316,6 @@ void mpeg_init(int volume, int bass, int treble, int loudness, int bass_boost, i | |||
1217 | mpeg_sound_set(SOUND_AVC, avc); | 1316 | mpeg_sound_set(SOUND_AVC, avc); |
1218 | #endif | 1317 | #endif |
1219 | #endif /* !SIMULATOR */ | 1318 | #endif /* !SIMULATOR */ |
1319 | |||
1320 | memset(id3tags, sizeof(id3tags), 0); | ||
1220 | } | 1321 | } |