summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/id3.c86
-rw-r--r--firmware/id3.h12
-rw-r--r--firmware/mpeg.c132
-rw-r--r--firmware/mpeg.h1
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
46bool mp3info(struct mp3entry *entry, char *filename); 56bool 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
220static 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
219static void remove_all_tags(void) 236static 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
1254void 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
1131bool mpeg_is_playing(void) 1263bool 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);
28void mpeg_resume(void); 28void mpeg_resume(void);
29void mpeg_next(void); 29void mpeg_next(void);
30void mpeg_prev(void); 30void mpeg_prev(void);
31void mpeg_ff_rewind(int change);
31bool mpeg_is_playing(void); 32bool mpeg_is_playing(void);
32void mpeg_sound_set(int setting, int value); 33void mpeg_sound_set(int setting, int value);
33int mpeg_sound_min(int setting); 34int mpeg_sound_min(int setting);