diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/flac2wav.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/apps/plugins/flac2wav.c b/apps/plugins/flac2wav.c new file mode 100644 index 0000000000..6fa7940535 --- /dev/null +++ b/apps/plugins/flac2wav.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Björn Stenberg | ||
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 | |||
22 | #if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) | ||
23 | /* software codec platforms, not for simulator */ | ||
24 | |||
25 | #include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h> | ||
26 | |||
27 | #include "lib/xxx2wav.h" /* Helper functions common to test decoders */ | ||
28 | |||
29 | #define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608 | ||
30 | #define FLAC_MAX_SUPPORTED_CHANNELS 2 | ||
31 | |||
32 | static struct plugin_api* rb; | ||
33 | |||
34 | /* Called when the FLAC decoder needs some FLAC data to decode */ | ||
35 | FLAC__SeekableStreamDecoderReadStatus flac_read_handler(const FLAC__SeekableStreamDecoder *dec, | ||
36 | FLAC__byte buffer[], unsigned *bytes, void *data) | ||
37 | { (void)dec; | ||
38 | |||
39 | file_info_struct *p = (file_info_struct *) data; | ||
40 | |||
41 | if (p->curpos >= p->filesize) { | ||
42 | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | ||
43 | } | ||
44 | |||
45 | rb->memcpy(buffer,&filebuf[p->curpos],*bytes); | ||
46 | p->curpos+=*bytes; | ||
47 | |||
48 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | ||
49 | } | ||
50 | |||
51 | /* Called when the FLAC decoder has some decoded PCM data to write */ | ||
52 | FLAC__StreamDecoderWriteStatus flac_write_handler(const FLAC__SeekableStreamDecoder *dec, | ||
53 | const FLAC__Frame *frame, | ||
54 | const FLAC__int32 * const buf[], | ||
55 | void *data) | ||
56 | { | ||
57 | unsigned int c_samp, c_chan, d_samp; | ||
58 | file_info_struct *p = (file_info_struct *) data; | ||
59 | uint32_t data_size = frame->header.blocksize * frame->header.channels * (p->bitspersample / 8); | ||
60 | uint32_t samples = frame->header.blocksize; | ||
61 | |||
62 | // FIXME: This should not be on the stack! | ||
63 | static unsigned char ldb[FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS*2]; | ||
64 | |||
65 | if (samples*frame->header.channels > (FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS)) { | ||
66 | // ERROR!!! | ||
67 | #ifdef SIMULATOR | ||
68 | fprintf(stderr,"ERROR: samples*frame->header.channels=%d\n",samples*frame->header.channels); | ||
69 | #endif | ||
70 | return(FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE); | ||
71 | } | ||
72 | |||
73 | (void)dec; | ||
74 | (void)data_size; | ||
75 | for(c_samp = d_samp = 0; c_samp < samples; c_samp++) { | ||
76 | for(c_chan = 0; c_chan < frame->header.channels; c_chan++, d_samp++) { | ||
77 | ldb[d_samp*2] = buf[c_chan][c_samp]&0xff; | ||
78 | ldb[(d_samp*2)+1] = (buf[c_chan][c_samp]&0xff00)>>8; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | rb->write(p->outfile,ldb,data_size); | ||
83 | |||
84 | p->current_sample += samples; | ||
85 | |||
86 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | ||
87 | } | ||
88 | |||
89 | void flac_metadata_handler(const FLAC__SeekableStreamDecoder *dec, | ||
90 | const FLAC__StreamMetadata *meta, void *data) | ||
91 | { | ||
92 | file_info_struct *p = (file_info_struct *) data; | ||
93 | (void)dec; | ||
94 | |||
95 | if(meta->type == FLAC__METADATA_TYPE_STREAMINFO) { | ||
96 | p->bitspersample = meta->data.stream_info.bits_per_sample; | ||
97 | p->samplerate = meta->data.stream_info.sample_rate; | ||
98 | p->channels = meta->data.stream_info.channels; | ||
99 | // FLAC__ASSERT(meta->data.stream_info.total_samples < 0x100000000); /* we can handle < 4 gigasamples */ | ||
100 | p->total_samples = (unsigned) | ||
101 | (meta->data.stream_info.total_samples & 0xffffffff); | ||
102 | p->current_sample = 0; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | void flac_error_handler(const FLAC__SeekableStreamDecoder *dec, | ||
108 | FLAC__StreamDecoderErrorStatus status, void *data) | ||
109 | { | ||
110 | (void)dec; | ||
111 | (void)status; | ||
112 | (void)data; | ||
113 | } | ||
114 | |||
115 | FLAC__SeekableStreamDecoderSeekStatus flac_seek_handler (const FLAC__SeekableStreamDecoder *decoder, | ||
116 | FLAC__uint64 absolute_byte_offset, | ||
117 | void *client_data) | ||
118 | { | ||
119 | (void)decoder; | ||
120 | file_info_struct *p = (file_info_struct *) client_data; | ||
121 | rb->lseek(p->infile,SEEK_SET,absolute_byte_offset); | ||
122 | return(FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK); | ||
123 | } | ||
124 | |||
125 | FLAC__SeekableStreamDecoderTellStatus flac_tell_handler (const FLAC__SeekableStreamDecoder *decoder, | ||
126 | FLAC__uint64 *absolute_byte_offset, void *client_data) | ||
127 | { | ||
128 | file_info_struct *p = (file_info_struct *) client_data; | ||
129 | |||
130 | (void)decoder; | ||
131 | *absolute_byte_offset=rb->lseek(p->infile,SEEK_CUR,0); | ||
132 | return(FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK); | ||
133 | } | ||
134 | |||
135 | FLAC__SeekableStreamDecoderLengthStatus flac_length_handler (const FLAC__SeekableStreamDecoder *decoder, | ||
136 | FLAC__uint64 *stream_length, void *client_data) | ||
137 | { | ||
138 | file_info_struct *p = (file_info_struct *) client_data; | ||
139 | |||
140 | (void)decoder; | ||
141 | *stream_length=p->filesize; | ||
142 | return(FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK); | ||
143 | } | ||
144 | |||
145 | FLAC__bool flac_eof_handler (const FLAC__SeekableStreamDecoder *decoder, | ||
146 | void *client_data) | ||
147 | { | ||
148 | file_info_struct *p = (file_info_struct *) client_data; | ||
149 | |||
150 | (void)decoder; | ||
151 | if (p->curpos >= p->filesize) { | ||
152 | return(true); | ||
153 | } else { | ||
154 | return(false); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | |||
159 | /* this is the plugin entry point */ | ||
160 | enum plugin_status plugin_start(struct plugin_api* api, void* file) | ||
161 | { | ||
162 | FLAC__SeekableStreamDecoder* flacDecoder; | ||
163 | file_info_struct file_info; | ||
164 | |||
165 | TEST_PLUGIN_API(api); | ||
166 | |||
167 | /* if you are using a global api pointer, don't forget to copy it! | ||
168 | otherwise you will get lovely "I04: IllInstr" errors... :-) */ | ||
169 | rb = api; | ||
170 | |||
171 | |||
172 | /* This function sets up the buffers and reads the file into RAM */ | ||
173 | |||
174 | if (local_init(file,"/flactest.wav",&file_info,api)) { | ||
175 | return PLUGIN_ERROR; | ||
176 | } | ||
177 | |||
178 | /* Create a decoder instance */ | ||
179 | |||
180 | flacDecoder=FLAC__seekable_stream_decoder_new(); | ||
181 | |||
182 | /* Set up the decoder and the callback functions - this must be done before init */ | ||
183 | |||
184 | /* The following are required for stream_decoder and higher */ | ||
185 | FLAC__seekable_stream_decoder_set_client_data(flacDecoder,&file_info); | ||
186 | FLAC__seekable_stream_decoder_set_write_callback(flacDecoder, flac_write_handler); | ||
187 | FLAC__seekable_stream_decoder_set_read_callback(flacDecoder, flac_read_handler); | ||
188 | FLAC__seekable_stream_decoder_set_metadata_callback(flacDecoder, flac_metadata_handler); | ||
189 | FLAC__seekable_stream_decoder_set_error_callback(flacDecoder, flac_error_handler); | ||
190 | FLAC__seekable_stream_decoder_set_metadata_respond(flacDecoder, FLAC__METADATA_TYPE_STREAMINFO); | ||
191 | |||
192 | /* The following are only for the seekable_stream_decoder */ | ||
193 | FLAC__seekable_stream_decoder_set_seek_callback(flacDecoder, flac_seek_handler); | ||
194 | FLAC__seekable_stream_decoder_set_tell_callback(flacDecoder, flac_tell_handler); | ||
195 | FLAC__seekable_stream_decoder_set_length_callback(flacDecoder, flac_length_handler); | ||
196 | FLAC__seekable_stream_decoder_set_eof_callback(flacDecoder, flac_eof_handler); | ||
197 | |||
198 | if (FLAC__seekable_stream_decoder_init(flacDecoder)) { | ||
199 | return PLUGIN_ERROR; | ||
200 | } | ||
201 | |||
202 | /* The first thing to do is to parse the metadata */ | ||
203 | FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder); | ||
204 | |||
205 | file_info.frames_decoded=0; | ||
206 | file_info.start_tick=*(rb->current_tick); | ||
207 | while (FLAC__seekable_stream_decoder_get_state(flacDecoder)!=2) { | ||
208 | FLAC__seekable_stream_decoder_process_single(flacDecoder); | ||
209 | file_info.frames_decoded++; | ||
210 | |||
211 | display_status(&file_info); | ||
212 | |||
213 | if (rb->button_get(false)!=BUTTON_NONE) { | ||
214 | close_wav(&file_info); | ||
215 | return PLUGIN_OK; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | close_wav(&file_info); | ||
220 | rb->splash(HZ*2, true, "FINISHED!"); | ||
221 | |||
222 | /* Flush internal buffers etc */ | ||
223 | //No need for this. flacResult=FLAC__seekable_stream_decoder_reset(flacDecoder); | ||
224 | |||
225 | // audio_close(); | ||
226 | |||
227 | return PLUGIN_OK; | ||
228 | } | ||
229 | #endif /* CONFIG_HWCODEC == MASNONE */ | ||