diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/id3.c | 86 | ||||
-rw-r--r-- | firmware/id3.h | 12 | ||||
-rw-r--r-- | firmware/mpeg.c | 132 | ||||
-rw-r--r-- | firmware/mpeg.h | 1 |
4 files changed, 191 insertions, 40 deletions
diff --git a/firmware/id3.c b/firmware/id3.c index 743ff74902..62150e1ac8 100644 --- a/firmware/id3.c +++ b/firmware/id3.c | |||
@@ -383,7 +383,7 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
383 | unsigned int filetime = 0; | 383 | unsigned int filetime = 0; |
384 | unsigned long header=0; | 384 | unsigned long header=0; |
385 | unsigned char tmp; | 385 | unsigned char tmp; |
386 | unsigned char frame[64]; | 386 | unsigned char frame[156]; |
387 | unsigned char* xing; | 387 | unsigned char* xing; |
388 | 388 | ||
389 | int version; | 389 | int version; |
@@ -412,7 +412,7 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
412 | 412 | ||
413 | /* Loop trough file until we find a frame header */ | 413 | /* Loop trough file until we find a frame header */ |
414 | bytecount = 0; | 414 | bytecount = 0; |
415 | restart: | 415 | restart: |
416 | do { | 416 | do { |
417 | header <<= 8; | 417 | header <<= 8; |
418 | if(!read(fd, &tmp, 1)) | 418 | if(!read(fd, &tmp, 1)) |
@@ -441,29 +441,29 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
441 | #endif | 441 | #endif |
442 | /* MPEG Audio Version */ | 442 | /* MPEG Audio Version */ |
443 | switch((header & 0x180000) >> 19) { | 443 | switch((header & 0x180000) >> 19) { |
444 | case 2: | 444 | case 2: |
445 | version = 2; | 445 | version = 2; |
446 | break; | 446 | break; |
447 | case 3: | 447 | case 3: |
448 | version = 1; | 448 | version = 1; |
449 | break; | 449 | break; |
450 | default: | 450 | default: |
451 | goto restart; | 451 | goto restart; |
452 | } | 452 | } |
453 | 453 | ||
454 | /* Layer */ | 454 | /* Layer */ |
455 | switch((header & 0x060000) >> 17) { | 455 | switch((header & 0x060000) >> 17) { |
456 | case 1: | 456 | case 1: |
457 | layer = 3; | 457 | layer = 3; |
458 | break; | 458 | break; |
459 | case 2: | 459 | case 2: |
460 | layer = 2; | 460 | layer = 2; |
461 | break; | 461 | break; |
462 | case 3: | 462 | case 3: |
463 | layer = 1; | 463 | layer = 1; |
464 | break; | 464 | break; |
465 | default: | 465 | default: |
466 | goto restart; | 466 | goto restart; |
467 | } | 467 | } |
468 | 468 | ||
469 | /* Bitrate */ | 469 | /* Bitrate */ |
@@ -488,24 +488,27 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
488 | 488 | ||
489 | /* Calculate bytes per frame, calculation depends on layer */ | 489 | /* Calculate bytes per frame, calculation depends on layer */ |
490 | switch(layer) { | 490 | switch(layer) { |
491 | case 1: | 491 | case 1: |
492 | bpf = bitrate_table[version - 1][layer - 1][bitindex]; | 492 | bpf = bitrate_table[version - 1][layer - 1][bitindex]; |
493 | bpf *= 48000; | 493 | bpf *= 48000; |
494 | bpf /= freqtab[version-1][freqindex] << (version - 1); | 494 | bpf /= freqtab[version-1][freqindex] << (version - 1); |
495 | break; | 495 | break; |
496 | case 2: | 496 | case 2: |
497 | case 3: | 497 | case 3: |
498 | bpf = bitrate_table[version - 1][layer - 1][bitindex]; | 498 | bpf = bitrate_table[version - 1][layer - 1][bitindex]; |
499 | bpf *= 144000; | 499 | bpf *= 144000; |
500 | bpf /= freqtab[version-1][freqindex] << (version - 1); | 500 | bpf /= freqtab[version-1][freqindex] << (version - 1); |
501 | break; | 501 | break; |
502 | default: | 502 | default: |
503 | bpf = 1; | 503 | bpf = 1; |
504 | } | 504 | } |
505 | 505 | ||
506 | /* Calculate time per frame */ | 506 | /* Calculate time per frame */ |
507 | tpf = bs[layer] / (freqtab[version-1][freqindex] << (version - 1)); | 507 | tpf = bs[layer] / (freqtab[version-1][freqindex] << (version - 1)); |
508 | 508 | ||
509 | entry->bpf = bpf; | ||
510 | entry->tpf = tpf; | ||
511 | |||
509 | /* OK, we have found a frame. Let's see if it has a Xing header */ | 512 | /* OK, we have found a frame. Let's see if it has a Xing header */ |
510 | if(read(fd, frame, sizeof frame) < 0) | 513 | if(read(fd, frame, sizeof frame) < 0) |
511 | return -1; | 514 | return -1; |
@@ -535,21 +538,26 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
535 | /* Yes, it is a VBR file */ | 538 | /* Yes, it is a VBR file */ |
536 | entry->vbr = true; | 539 | entry->vbr = true; |
537 | 540 | ||
538 | if (xing[7] & 0x01) /* Is the frame count there? */ | 541 | if (entry->vbrflags & VBR_FRAMES_FLAG) /* Is the frame count there? */ |
539 | { | 542 | { |
540 | int framecount = (xing[8] << 24) | (xing[9] << 16) | | 543 | int framecount = (xing[8] << 24) | (xing[9] << 16) | |
541 | (xing[10] << 8) | xing[11]; | 544 | (xing[10] << 8) | xing[11]; |
542 | 545 | ||
543 | filetime = framecount * tpf; | 546 | filetime = framecount * tpf; |
544 | } | 547 | } |
545 | if (xing[7] & 0x02) /* is byte count there? */ | 548 | |
549 | if (entry->vbrflags & VBR_BYTES_FLAG) /* is byte count there? */ | ||
546 | { | 550 | { |
547 | int bytecount = (xing[12] << 24) | (xing[13] << 16) | | 551 | int bytecount = (xing[12] << 24) | (xing[13] << 16) | |
548 | (xing[14] << 8) | xing[15]; | 552 | (xing[14] << 8) | xing[15]; |
549 | 553 | ||
550 | bitrate = bytecount * 8 / filetime; | 554 | bitrate = bytecount * 8 / filetime; |
551 | } | 555 | } |
552 | /* We don't care about the TOC just yet. Maybe another time. */ | 556 | |
557 | if (entry->vbrflags & VBR_TOC_FLAG) /* is table-of-contents there? */ | ||
558 | { | ||
559 | memcpy( entry->toc, xing+16, 100 ); | ||
560 | } | ||
553 | } | 561 | } |
554 | 562 | ||
555 | entry->bitrate = bitrate; | 563 | entry->bitrate = bitrate; |
diff --git a/firmware/id3.h b/firmware/id3.h index 203e997073..1a5bc7441e 100644 --- a/firmware/id3.h +++ b/firmware/id3.h | |||
@@ -29,7 +29,6 @@ struct mp3entry { | |||
29 | int tracknum; | 29 | int tracknum; |
30 | int version; | 30 | int version; |
31 | int layer; | 31 | int layer; |
32 | bool vbr; | ||
33 | unsigned int bitrate; | 32 | unsigned int bitrate; |
34 | unsigned int frequency; | 33 | unsigned int frequency; |
35 | unsigned int id3v2len; | 34 | unsigned int id3v2len; |
@@ -37,12 +36,23 @@ struct mp3entry { | |||
37 | unsigned int filesize; /* in bytes */ | 36 | unsigned int filesize; /* in bytes */ |
38 | unsigned int length; /* song length */ | 37 | unsigned int length; /* song length */ |
39 | unsigned int elapsed; /* ms played */ | 38 | unsigned int elapsed; /* ms played */ |
39 | long bpf; /* bytes per frame */ | ||
40 | long tpf; /* time per frame */ | ||
41 | |||
42 | /* Xing VBR fields */ | ||
43 | bool vbr; | ||
44 | unsigned char vbrflags; | ||
45 | unsigned char toc[100];/* table of contents */ | ||
40 | 46 | ||
41 | /* these following two fields are used for local buffering */ | 47 | /* these following two fields are used for local buffering */ |
42 | char id3v2buf[300]; | 48 | char id3v2buf[300]; |
43 | char id3v1buf[3][32]; | 49 | char id3v1buf[3][32]; |
44 | }; | 50 | }; |
45 | 51 | ||
52 | #define VBR_FRAMES_FLAG 0x01 | ||
53 | #define VBR_BYTES_FLAG 0x02 | ||
54 | #define VBR_TOC_FLAG 0x04 | ||
55 | |||
46 | bool mp3info(struct mp3entry *entry, char *filename); | 56 | bool mp3info(struct mp3entry *entry, char *filename); |
47 | 57 | ||
48 | #endif | 58 | #endif |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index ab2fefc872..4c75345f66 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #define MPEG_RESUME 4 | 47 | #define MPEG_RESUME 4 |
48 | #define MPEG_NEXT 5 | 48 | #define MPEG_NEXT 5 |
49 | #define MPEG_PREV 6 | 49 | #define MPEG_PREV 6 |
50 | #define MPEG_FF_REWIND 7 | ||
50 | #define MPEG_NEED_DATA 100 | 51 | #define MPEG_NEED_DATA 100 |
51 | #define MPEG_SWAP_DATA 101 | 52 | #define MPEG_SWAP_DATA 101 |
52 | #define MPEG_TRACK_CHANGE 102 | 53 | #define MPEG_TRACK_CHANGE 102 |
@@ -216,6 +217,22 @@ static void remove_current_tag(void) | |||
216 | } | 217 | } |
217 | } | 218 | } |
218 | 219 | ||
220 | static void remove_all_non_current_tags(void) | ||
221 | { | ||
222 | int i = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; | ||
223 | |||
224 | while (i != tag_write_idx) | ||
225 | { | ||
226 | id3tags[i]->used = false; | ||
227 | id3tags[i] = NULL; | ||
228 | |||
229 | i = (i+1) & MAX_ID3_TAGS_MASK; | ||
230 | } | ||
231 | |||
232 | tag_write_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; | ||
233 | debug_tags(); | ||
234 | } | ||
235 | |||
219 | static void remove_all_tags(void) | 236 | static void remove_all_tags(void) |
220 | { | 237 | { |
221 | int i; | 238 | int i; |
@@ -823,6 +840,112 @@ static void mpeg_thread(void) | |||
823 | break; | 840 | break; |
824 | } | 841 | } |
825 | 842 | ||
843 | case MPEG_FF_REWIND: { | ||
844 | struct mp3entry *id3 = mpeg_current_track(); | ||
845 | int newtime = id3->elapsed + (int)ev.data; | ||
846 | int curpos, newpos, diffpos; | ||
847 | DEBUGF("MPEG_FF_REWIND\n"); | ||
848 | |||
849 | if (id3->vbr && (id3->vbrflags & VBR_TOC_FLAG)) | ||
850 | { | ||
851 | /* Use the TOC to find the new position */ | ||
852 | int percent = (newtime*100)/id3->length; | ||
853 | int curtoc, nexttoc, nextpos, remainder; | ||
854 | |||
855 | if (percent > 99) | ||
856 | percent = 99; | ||
857 | |||
858 | curtoc = id3->toc[percent]; | ||
859 | |||
860 | if (percent < 99) | ||
861 | nexttoc = id3->toc[percent+1]; | ||
862 | else | ||
863 | nexttoc = 256; | ||
864 | |||
865 | newpos = (curtoc*id3->filesize)/256; | ||
866 | |||
867 | /* Use the remainder to get a more accurate position */ | ||
868 | nextpos = (nexttoc*id3->filesize)/256; | ||
869 | remainder = (newtime*10000)/id3->length - (percent*100); | ||
870 | newpos += ((nextpos-newpos)*remainder)/100; | ||
871 | } | ||
872 | else if (id3->bpf && id3->tpf) | ||
873 | newpos = (newtime*id3->bpf)/id3->tpf; | ||
874 | else | ||
875 | /* Not enough information to FF/Rewind */ | ||
876 | break; | ||
877 | |||
878 | newpos = newpos & ~1; | ||
879 | curpos = lseek(mpeg_file, 0, SEEK_CUR); | ||
880 | |||
881 | if (num_tracks_in_memory() > 1) | ||
882 | { | ||
883 | /* We have started loading other tracks that need to be | ||
884 | accounted for */ | ||
885 | int i = tag_read_idx; | ||
886 | int j = tag_write_idx - 1; | ||
887 | |||
888 | if (j < 0) | ||
889 | j = MAX_ID3_TAGS - 1; | ||
890 | |||
891 | while (i != j) | ||
892 | { | ||
893 | curpos += id3tags[i]->id3.filesize; | ||
894 | i = (i+1) & MAX_ID3_TAGS_MASK; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | diffpos = curpos - newpos; | ||
899 | |||
900 | #warning "Borde inte mp3buflen vara mp3buf_write?" | ||
901 | if(diffpos >= 0 && diffpos < mp3buflen) | ||
902 | { | ||
903 | /* We are changing to a position that's already in | ||
904 | memory */ | ||
905 | mp3buf_read = mp3buf_write - diffpos; | ||
906 | if (mp3buf_read < 0) | ||
907 | { | ||
908 | mp3buf_read += mp3buflen; | ||
909 | } | ||
910 | |||
911 | playing = true; | ||
912 | last_dma_tick = current_tick; | ||
913 | init_dma(); | ||
914 | start_dma(); | ||
915 | } | ||
916 | else | ||
917 | { | ||
918 | /* Move to the new position in the file and start | ||
919 | loading data */ | ||
920 | reset_mp3_buffer(); | ||
921 | |||
922 | if (num_tracks_in_memory() > 1) | ||
923 | { | ||
924 | /* We have to reload the current track */ | ||
925 | close(mpeg_file); | ||
926 | remove_all_non_current_tags(); | ||
927 | |||
928 | mpeg_file = open(id3->path, O_RDONLY); | ||
929 | if (mpeg_file < 0) | ||
930 | break; | ||
931 | } | ||
932 | |||
933 | if(-1 == lseek(mpeg_file, newpos, SEEK_SET)) | ||
934 | break; | ||
935 | |||
936 | filling = true; | ||
937 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
938 | |||
939 | /* Tell the file loading code that we want to start playing | ||
940 | as soon as we have some data */ | ||
941 | play_pending = true; | ||
942 | } | ||
943 | |||
944 | id3->elapsed = newtime; | ||
945 | |||
946 | break; | ||
947 | } | ||
948 | |||
826 | case MPEG_SWAP_DATA: | 949 | case MPEG_SWAP_DATA: |
827 | free_space_left = mp3buf_write - mp3buf_swapwrite; | 950 | free_space_left = mp3buf_write - mp3buf_swapwrite; |
828 | 951 | ||
@@ -1128,6 +1251,15 @@ void mpeg_prev(void) | |||
1128 | #endif | 1251 | #endif |
1129 | } | 1252 | } |
1130 | 1253 | ||
1254 | void mpeg_ff_rewind(int change) | ||
1255 | { | ||
1256 | #ifndef SIMULATOR | ||
1257 | queue_post(&mpeg_queue, MPEG_FF_REWIND, (void *)change); | ||
1258 | #else | ||
1259 | (void)change; | ||
1260 | #endif | ||
1261 | } | ||
1262 | |||
1131 | bool mpeg_is_playing(void) | 1263 | bool mpeg_is_playing(void) |
1132 | { | 1264 | { |
1133 | return playing || play_pending; | 1265 | return playing || play_pending; |
diff --git a/firmware/mpeg.h b/firmware/mpeg.h index 4ea0001e25..2838c47d45 100644 --- a/firmware/mpeg.h +++ b/firmware/mpeg.h | |||
@@ -28,6 +28,7 @@ void mpeg_pause(void); | |||
28 | void mpeg_resume(void); | 28 | void mpeg_resume(void); |
29 | void mpeg_next(void); | 29 | void mpeg_next(void); |
30 | void mpeg_prev(void); | 30 | void mpeg_prev(void); |
31 | void mpeg_ff_rewind(int change); | ||
31 | bool mpeg_is_playing(void); | 32 | bool mpeg_is_playing(void); |
32 | void mpeg_sound_set(int setting, int value); | 33 | void mpeg_sound_set(int setting, int value); |
33 | int mpeg_sound_min(int setting); | 34 | int mpeg_sound_min(int setting); |