diff options
-rw-r--r-- | firmware/mpeg.c | 131 |
1 files changed, 87 insertions, 44 deletions
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index eb065d5a51..f2cdcf6fa9 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -34,13 +34,12 @@ | |||
34 | #include "file.h" | 34 | #include "file.h" |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #define MPEG_CHUNKSIZE 0x20000 | 37 | #define MPEG_FIRST_CHUNKSIZE 0x20000 |
38 | #ifdef ARCHOS_RECORDER | 38 | #define MPEG_CHUNKSIZE 0x180000 |
39 | /* recorder is slower and needs more load time */ | 39 | #define MPEG_FIRST_SWAP_CHUNKSIZE 0x20000 |
40 | #define MPEG_LOW_WATER 0x40000 | 40 | #define MPEG_SWAP_CHUNKSIZE 0x8000 |
41 | #else | 41 | #define MPEG_HIGHWATER 0x10000 |
42 | #define MPEG_LOW_WATER 0x30000 | 42 | #define MPEG_LOW_WATER 0x30000 |
43 | #endif | ||
44 | 43 | ||
45 | #define MPEG_PLAY 1 | 44 | #define MPEG_PLAY 1 |
46 | #define MPEG_STOP 2 | 45 | #define MPEG_STOP 2 |
@@ -49,6 +48,7 @@ | |||
49 | #define MPEG_NEXT 5 | 48 | #define MPEG_NEXT 5 |
50 | #define MPEG_PREV 6 | 49 | #define MPEG_PREV 6 |
51 | #define MPEG_NEED_DATA 100 | 50 | #define MPEG_NEED_DATA 100 |
51 | #define MPEG_SWAP_DATA 101 | ||
52 | 52 | ||
53 | extern char* peek_next_track(int type); | 53 | extern char* peek_next_track(int type); |
54 | extern char* peek_prev_track(int type); | 54 | extern char* peek_prev_track(int type); |
@@ -274,6 +274,7 @@ extern unsigned char mp3end[]; | |||
274 | 274 | ||
275 | static int mp3buflen; | 275 | static int mp3buflen; |
276 | static int mp3buf_write; | 276 | static int mp3buf_write; |
277 | static int mp3buf_swapwrite; | ||
277 | static int mp3buf_read; | 278 | static int mp3buf_read; |
278 | 279 | ||
279 | static int last_dma_chunk_size; | 280 | static int last_dma_chunk_size; |
@@ -355,14 +356,14 @@ static void dma_tick(void) | |||
355 | { | 356 | { |
356 | if(playing) | 357 | if(playing) |
357 | { | 358 | { |
358 | /* Start DMA if it is disabled and the DEMAND pin is high */ | 359 | /* Start DMA if it is disabled and the DEMAND pin is high */ |
359 | if(!dma_on && (PBDR & 0x4000)) | 360 | if(!dma_on && (PBDR & 0x4000)) |
360 | { | 361 | { |
361 | if(!(SCR0 & 0x80)) | 362 | if(!(SCR0 & 0x80)) |
362 | start_dma(); | 363 | start_dma(); |
363 | } | 364 | } |
364 | id3tags[0].id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; | 365 | id3tags[0].id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; |
365 | last_dma_tick = current_tick; | 366 | last_dma_tick = current_tick; |
366 | } | 367 | } |
367 | } | 368 | } |
368 | 369 | ||
@@ -379,6 +380,7 @@ static void reset_mp3_buffer(void) | |||
379 | { | 380 | { |
380 | mp3buf_read = 0; | 381 | mp3buf_read = 0; |
381 | mp3buf_write = 0; | 382 | mp3buf_write = 0; |
383 | mp3buf_swapwrite = 0; | ||
382 | } | 384 | } |
383 | 385 | ||
384 | #pragma interrupt | 386 | #pragma interrupt |
@@ -436,7 +438,7 @@ void DEI3(void) | |||
436 | { | 438 | { |
437 | DEBUGF("No more MP3 data. Stopping.\n"); | 439 | DEBUGF("No more MP3 data. Stopping.\n"); |
438 | CHCR3 = 0; /* Stop DMA interrupt */ | 440 | CHCR3 = 0; /* Stop DMA interrupt */ |
439 | playing = false; | 441 | playing = false; |
440 | } | 442 | } |
441 | } | 443 | } |
442 | 444 | ||
@@ -486,7 +488,7 @@ static void stop_playing(void) | |||
486 | playing = false; | 488 | playing = false; |
487 | filling = false; | 489 | filling = false; |
488 | if(mpeg_file >= 0) | 490 | if(mpeg_file >= 0) |
489 | close(mpeg_file); | 491 | close(mpeg_file); |
490 | mpeg_file = -1; | 492 | mpeg_file = -1; |
491 | stop_dma(); | 493 | stop_dma(); |
492 | } | 494 | } |
@@ -497,6 +499,7 @@ static void mpeg_thread(void) | |||
497 | int len; | 499 | int len; |
498 | int free_space_left; | 500 | int free_space_left; |
499 | int amount_to_read; | 501 | int amount_to_read; |
502 | int amount_to_swap; | ||
500 | 503 | ||
501 | play_pending = false; | 504 | play_pending = false; |
502 | playing = false; | 505 | playing = false; |
@@ -505,6 +508,7 @@ static void mpeg_thread(void) | |||
505 | while(1) | 508 | while(1) |
506 | { | 509 | { |
507 | DEBUGF("S\n"); | 510 | DEBUGF("S\n"); |
511 | yield(); | ||
508 | queue_wait(&mpeg_queue, &ev); | 512 | queue_wait(&mpeg_queue, &ev); |
509 | switch(ev.id) | 513 | switch(ev.id) |
510 | { | 514 | { |
@@ -545,7 +549,7 @@ static void mpeg_thread(void) | |||
545 | 549 | ||
546 | case MPEG_STOP: | 550 | case MPEG_STOP: |
547 | DEBUGF("MPEG_STOP\n"); | 551 | DEBUGF("MPEG_STOP\n"); |
548 | stop_playing(); | 552 | stop_playing(); |
549 | break; | 553 | break; |
550 | 554 | ||
551 | case MPEG_PAUSE: | 555 | case MPEG_PAUSE: |
@@ -614,6 +618,50 @@ static void mpeg_thread(void) | |||
614 | } | 618 | } |
615 | break; | 619 | break; |
616 | 620 | ||
621 | case MPEG_SWAP_DATA: | ||
622 | free_space_left = mp3buf_write - mp3buf_swapwrite; | ||
623 | |||
624 | if(free_space_left == 0) | ||
625 | break; | ||
626 | |||
627 | if(free_space_left < 0) | ||
628 | free_space_left = mp3buflen + free_space_left; | ||
629 | |||
630 | if(play_pending) | ||
631 | amount_to_swap = MIN(MPEG_FIRST_SWAP_CHUNKSIZE, | ||
632 | free_space_left); | ||
633 | else | ||
634 | amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); | ||
635 | amount_to_swap = MIN(mp3buflen - mp3buf_swapwrite, | ||
636 | amount_to_swap); | ||
637 | |||
638 | DEBUGF("B %x\n", amount_to_swap); | ||
639 | bitswap((unsigned short *)(mp3buf + mp3buf_swapwrite), | ||
640 | (amount_to_swap+1)/2); | ||
641 | |||
642 | mp3buf_swapwrite += amount_to_swap; | ||
643 | if(mp3buf_swapwrite >= mp3buflen) | ||
644 | { | ||
645 | mp3buf_swapwrite = 0; | ||
646 | DEBUGF("BW\n"); | ||
647 | } | ||
648 | |||
649 | /* Tell ourselves that we must swap more data */ | ||
650 | queue_post(&mpeg_queue, MPEG_SWAP_DATA, 0); | ||
651 | |||
652 | /* And while we're at it, see if we have started | ||
653 | playing yet. If not, do it. */ | ||
654 | if(play_pending) | ||
655 | { | ||
656 | play_pending = false; | ||
657 | playing = true; | ||
658 | |||
659 | last_dma_tick = current_tick; | ||
660 | init_dma(); | ||
661 | start_dma(); | ||
662 | } | ||
663 | break; | ||
664 | |||
617 | case MPEG_NEED_DATA: | 665 | case MPEG_NEED_DATA: |
618 | free_space_left = mp3buf_read - mp3buf_write; | 666 | free_space_left = mp3buf_read - mp3buf_write; |
619 | 667 | ||
@@ -621,16 +669,26 @@ static void mpeg_thread(void) | |||
621 | if(free_space_left <= 0) | 669 | if(free_space_left <= 0) |
622 | free_space_left = mp3buflen + free_space_left; | 670 | free_space_left = mp3buflen + free_space_left; |
623 | 671 | ||
672 | /* Make sure that we don't fill the entire buffer */ | ||
673 | free_space_left -= 2; | ||
674 | |||
624 | /* do we have any more buffer space to fill? */ | 675 | /* do we have any more buffer space to fill? */ |
625 | if(free_space_left <= MPEG_CHUNKSIZE) | 676 | if(free_space_left <= MPEG_HIGHWATER) |
626 | { | 677 | { |
627 | DEBUGF("0\n"); | 678 | DEBUGF("0\n"); |
628 | filling = false; | 679 | filling = false; |
629 | ata_sleep(); | 680 | ata_sleep(); |
630 | break; | 681 | break; |
631 | } | 682 | } |
632 | 683 | ||
633 | amount_to_read = MIN(MPEG_CHUNKSIZE, free_space_left); | 684 | if(play_pending) |
685 | { | ||
686 | amount_to_read = MIN(MPEG_FIRST_CHUNKSIZE, free_space_left); | ||
687 | } | ||
688 | else | ||
689 | { | ||
690 | amount_to_read = MIN(MPEG_CHUNKSIZE, free_space_left); | ||
691 | } | ||
634 | amount_to_read = MIN(mp3buflen - mp3buf_write, amount_to_read); | 692 | amount_to_read = MIN(mp3buflen - mp3buf_write, amount_to_read); |
635 | 693 | ||
636 | /* Read in a few seconds worth of MP3 data. We don't want to | 694 | /* Read in a few seconds worth of MP3 data. We don't want to |
@@ -643,11 +701,9 @@ static void mpeg_thread(void) | |||
643 | len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read); | 701 | len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read); |
644 | if(len > 0) | 702 | if(len > 0) |
645 | { | 703 | { |
646 | DEBUGF("B\n"); | 704 | /* Tell ourselves that we need to swap some data */ |
705 | queue_post(&mpeg_queue, MPEG_SWAP_DATA, 0); | ||
647 | 706 | ||
648 | bitswap((unsigned short *)(mp3buf + mp3buf_write), | ||
649 | (len+1)/2); | ||
650 | |||
651 | mp3buf_write += len; | 707 | mp3buf_write += len; |
652 | if(mp3buf_write >= mp3buflen) | 708 | if(mp3buf_write >= mp3buflen) |
653 | { | 709 | { |
@@ -657,18 +713,6 @@ static void mpeg_thread(void) | |||
657 | 713 | ||
658 | /* Tell ourselves that we want more data */ | 714 | /* Tell ourselves that we want more data */ |
659 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | 715 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); |
660 | |||
661 | /* And while we're at it, see if we have started | ||
662 | playing yet. If not, do it. */ | ||
663 | if(play_pending) | ||
664 | { | ||
665 | play_pending = false; | ||
666 | playing = true; | ||
667 | |||
668 | last_dma_tick = current_tick; | ||
669 | init_dma(); | ||
670 | start_dma(); | ||
671 | } | ||
672 | } | 716 | } |
673 | else | 717 | else |
674 | { | 718 | { |
@@ -696,20 +740,19 @@ static void mpeg_thread(void) | |||
696 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | 740 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); |
697 | } | 741 | } |
698 | } | 742 | } |
699 | yield(); /* To be safe */ | ||
700 | } | 743 | } |
701 | break; | 744 | break; |
702 | 745 | ||
703 | case SYS_USB_CONNECTED: | 746 | case SYS_USB_CONNECTED: |
704 | stop_playing(); | 747 | stop_playing(); |
705 | 748 | ||
706 | /* Tell the USB thread that we are safe */ | 749 | /* Tell the USB thread that we are safe */ |
707 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | 750 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); |
708 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 751 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
709 | 752 | ||
710 | /* Wait until the USB cable is extracted again */ | 753 | /* Wait until the USB cable is extracted again */ |
711 | usb_wait_for_disconnect(&mpeg_queue); | 754 | usb_wait_for_disconnect(&mpeg_queue); |
712 | break; | 755 | break; |
713 | } | 756 | } |
714 | } | 757 | } |
715 | } | 758 | } |
@@ -996,7 +1039,7 @@ void mpeg_init(int volume, int bass, int treble) | |||
996 | 1039 | ||
997 | queue_init(&mpeg_queue); | 1040 | queue_init(&mpeg_queue); |
998 | create_thread(mpeg_thread, mpeg_stack, | 1041 | create_thread(mpeg_thread, mpeg_stack, |
999 | sizeof(mpeg_stack), mpeg_thread_name); | 1042 | sizeof(mpeg_stack), mpeg_thread_name); |
1000 | mas_poll_start(2); | 1043 | mas_poll_start(2); |
1001 | 1044 | ||
1002 | #ifndef ARCHOS_RECORDER | 1045 | #ifndef ARCHOS_RECORDER |