diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/playback.c | 53 | ||||
-rw-r--r-- | apps/plugins/codecwav.c | 131 |
2 files changed, 183 insertions, 1 deletions
diff --git a/apps/playback.c b/apps/playback.c index 71cb479059..4cefed20c2 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -598,7 +598,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) | |||
598 | int rc, i; | 598 | int rc, i; |
599 | int copy_n; | 599 | int copy_n; |
600 | /* Used by the FLAC metadata parser */ | 600 | /* Used by the FLAC metadata parser */ |
601 | unsigned long totalsamples; | 601 | unsigned long totalsamples,bytespersample,channels,bitspersample,numbytes; |
602 | unsigned char* buf; | 602 | unsigned char* buf; |
603 | 603 | ||
604 | if (track_count >= MAX_TRACK) | 604 | if (track_count >= MAX_TRACK) |
@@ -677,6 +677,57 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) | |||
677 | tracks[track_widx].taginfo_ready = true; | 677 | tracks[track_widx].taginfo_ready = true; |
678 | break ; | 678 | break ; |
679 | 679 | ||
680 | case AFMT_PCM_WAV: | ||
681 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
682 | buf=tracks[track_widx].id3.path; | ||
683 | |||
684 | lseek(fd, 0, SEEK_SET); | ||
685 | |||
686 | rc = read(fd, buf, 44); | ||
687 | if (rc < 44) { | ||
688 | close(fd); | ||
689 | return false; | ||
690 | } | ||
691 | |||
692 | if ((memcmp(buf,"RIFF",4)!=0) || | ||
693 | (memcmp(&buf[8],"WAVEfmt",7)!=0)) { | ||
694 | logf("%s is not a WAV file\n",trackname); | ||
695 | close(fd); | ||
696 | return(false); | ||
697 | } | ||
698 | |||
699 | /* FIX: Correctly parse WAV header - we assume canonical | ||
700 | 44-byte header */ | ||
701 | |||
702 | bitspersample=buf[34]; | ||
703 | channels=buf[22]; | ||
704 | |||
705 | if ((bitspersample!=16) || (channels != 2)) { | ||
706 | logf("Unsupported WAV file - %d bitspersample, %d channels\n", | ||
707 | bitspersample,channels); | ||
708 | close(fd); | ||
709 | return(false); | ||
710 | } | ||
711 | |||
712 | bytespersample=((bitspersample/8)*channels); | ||
713 | numbytes=(buf[40]|(buf[41]<<8)|(buf[42]<<16)|(buf[43]<<24)); | ||
714 | totalsamples=numbytes/bytespersample; | ||
715 | |||
716 | tracks[track_widx].id3.vbr=false; /* All WAV files are CBR */ | ||
717 | tracks[track_widx].id3.filesize=filesize(fd); | ||
718 | tracks[track_widx].id3.frequency=buf[24]|(buf[25]<<8)|(buf[26]<<16)|(buf[27]<<24); | ||
719 | |||
720 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | ||
721 | tracks[track_widx].id3.length=(totalsamples/tracks[track_widx].id3.frequency)*1000; | ||
722 | tracks[track_widx].id3.bitrate=(tracks[track_widx].id3.frequency*bytespersample)/1024; | ||
723 | |||
724 | lseek(fd, 0, SEEK_SET); | ||
725 | strncpy(tracks[track_widx].id3.path,trackname,sizeof(tracks[track_widx].id3.path)); | ||
726 | tracks[track_widx].taginfo_ready = true; | ||
727 | |||
728 | break; | ||
729 | |||
730 | |||
680 | case AFMT_FLAC: | 731 | case AFMT_FLAC: |
681 | /* A simple parser to read vital metadata from a FLAC file - length, frequency, bitrate etc. */ | 732 | /* A simple parser to read vital metadata from a FLAC file - length, frequency, bitrate etc. */ |
682 | /* This code should either be moved to a seperate file, or discarded in favour of the libFLAC code */ | 733 | /* This code should either be moved to a seperate file, or discarded in favour of the libFLAC code */ |
diff --git a/apps/plugins/codecwav.c b/apps/plugins/codecwav.c new file mode 100644 index 0000000000..a02f2cdbff --- /dev/null +++ b/apps/plugins/codecwav.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "plugin.h" | ||
21 | #include "playback.h" | ||
22 | #include "lib/codeclib.h" | ||
23 | |||
24 | #ifndef SIMULATOR | ||
25 | extern char iramcopy[]; | ||
26 | extern char iramstart[]; | ||
27 | extern char iramend[]; | ||
28 | #endif | ||
29 | |||
30 | /* This is probably a waste of IRAM, but why not? */ | ||
31 | static unsigned char wavbuf[16384] IDATA_ATTR; | ||
32 | |||
33 | /* this is the plugin entry point */ | ||
34 | enum plugin_status plugin_start(struct plugin_api* api, void* parm) | ||
35 | { | ||
36 | struct plugin_api* rb = (struct plugin_api*)api; | ||
37 | struct codec_api* ci = (struct codec_api*)parm; | ||
38 | unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples; | ||
39 | int channels,bytespersample,bitspersample; | ||
40 | unsigned int i,j,n; | ||
41 | int endofstream; | ||
42 | |||
43 | /* Generic plugin initialisation */ | ||
44 | TEST_PLUGIN_API(api); | ||
45 | |||
46 | /* if you are using a global api pointer, don't forget to copy it! | ||
47 | otherwise you will get lovely "I04: IllInstr" errors... :-) */ | ||
48 | rb = api; | ||
49 | |||
50 | #ifndef SIMULATOR | ||
51 | rb->memcpy(iramstart, iramcopy, iramend-iramstart); | ||
52 | #endif | ||
53 | |||
54 | ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); | ||
55 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); | ||
56 | |||
57 | next_track: | ||
58 | |||
59 | if (codec_init(api, ci)) { | ||
60 | return PLUGIN_ERROR; | ||
61 | } | ||
62 | |||
63 | /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ | ||
64 | |||
65 | n=(unsigned)(ci->read_filebuf(wavbuf,44)); | ||
66 | if (n!=44) { | ||
67 | return PLUGIN_ERROR; | ||
68 | } | ||
69 | if ((memcmp(wavbuf,"RIFF",4)!=0) || (memcmp(&wavbuf[8],"WAVEfmt",7)!=0)) { | ||
70 | return PLUGIN_ERROR; | ||
71 | } | ||
72 | |||
73 | samplerate=wavbuf[24]|(wavbuf[25]<<8)|(wavbuf[26]<<16)|(wavbuf[27]<<24); | ||
74 | bitspersample=wavbuf[34]; | ||
75 | channels=wavbuf[22]; | ||
76 | bytespersample=((bitspersample/8)*channels); | ||
77 | numbytes=(wavbuf[40]|(wavbuf[41]<<8)|(wavbuf[42]<<16)|(wavbuf[43]<<24)); | ||
78 | totalsamples=numbytes/bytespersample; | ||
79 | |||
80 | if ((bitspersample!=16) || (channels != 2)) { | ||
81 | return PLUGIN_ERROR; | ||
82 | } | ||
83 | |||
84 | /* The main decoder loop */ | ||
85 | |||
86 | samplesdone=0; | ||
87 | ci->set_elapsed(0); | ||
88 | endofstream=0; | ||
89 | while (!endofstream) { | ||
90 | rb->yield(); | ||
91 | if (ci->stop_codec || ci->reload_codec) { | ||
92 | break; | ||
93 | } | ||
94 | |||
95 | n=(unsigned)(ci->read_filebuf(wavbuf,sizeof(wavbuf))); | ||
96 | |||
97 | rb->yield(); | ||
98 | |||
99 | if (n==0) break; /* End of stream */ | ||
100 | |||
101 | nsamples=(n/bytespersample); | ||
102 | |||
103 | /* WAV files can contain extra data at the end - so we can't just | ||
104 | process until the end of the file */ | ||
105 | |||
106 | if (samplesdone+nsamples > totalsamples) { | ||
107 | nsamples=(totalsamples-samplesdone); | ||
108 | n=nsamples*bytespersample; | ||
109 | endofstream=1; | ||
110 | } | ||
111 | |||
112 | /* Byte-swap data */ | ||
113 | for (i=0;i<n;i+=2) { | ||
114 | j=wavbuf[i]; | ||
115 | wavbuf[i]=wavbuf[i+1]; | ||
116 | wavbuf[i+1]=j; | ||
117 | } | ||
118 | |||
119 | samplesdone+=nsamples; | ||
120 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); | ||
121 | |||
122 | rb->yield(); | ||
123 | while (!ci->audiobuffer_insert(wavbuf, n)) | ||
124 | rb->yield(); | ||
125 | } | ||
126 | |||
127 | if (ci->request_next_track()) | ||
128 | goto next_track; | ||
129 | |||
130 | return PLUGIN_OK; | ||
131 | } | ||