diff options
author | Dave Chapman <dave@dchapman.com> | 2005-02-16 15:13:39 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2005-02-16 15:13:39 +0000 |
commit | 594b690af2df95d14cb927c6fff6717461d4873e (patch) | |
tree | 2ed1fe075c82c0ab44f985f79fa5543fef31f723 /apps | |
parent | 253094cb1f9ecfd468203a4ef1ebb73b6bcc2974 (diff) | |
download | rockbox-594b690af2df95d14cb927c6fff6717461d4873e.tar.gz rockbox-594b690af2df95d14cb927c6fff6717461d4873e.zip |
Start to clean up a52towav.c and move common xxx2wav code into xxx2wav.h
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5979 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/a52towav.c | 312 | ||||
-rw-r--r-- | apps/plugins/xxx2wav.h | 240 |
2 files changed, 278 insertions, 274 deletions
diff --git a/apps/plugins/a52towav.c b/apps/plugins/a52towav.c index 17b6c91e51..552479b0b0 100644 --- a/apps/plugins/a52towav.c +++ b/apps/plugins/a52towav.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2002 Björn Stenberg | 10 | * Copyright (C) 2005 Dave Chapman |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 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. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -27,7 +27,18 @@ | |||
27 | #include <codecs/liba52/config.h> | 27 | #include <codecs/liba52/config.h> |
28 | #include <codecs/liba52/a52.h> | 28 | #include <codecs/liba52/a52.h> |
29 | 29 | ||
30 | /* Currently used for WAV output */ | 30 | static struct plugin_api* rb; |
31 | |||
32 | /* Helper functions common to all decoder test viewers (uses rb) */ | ||
33 | |||
34 | #include "xxx2wav.h" | ||
35 | |||
36 | /* FIX: We can remove this warning when the build system has a | ||
37 | mechanism for auto-detecting the endianness of the target CPU - | ||
38 | WORDS_BIGENDIAN is defined in liba52/config.h and is also used | ||
39 | internally by liba52. | ||
40 | */ | ||
41 | |||
31 | #ifdef WORDS_BIGENDIAN | 42 | #ifdef WORDS_BIGENDIAN |
32 | #warning ************************************* BIG ENDIAN | 43 | #warning ************************************* BIG ENDIAN |
33 | #define LE_S16(x) ( (uint16_t) ( ((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8) ) ) | 44 | #define LE_S16(x) ( (uint16_t) ( ((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8) ) ) |
@@ -35,192 +46,16 @@ | |||
35 | #define LE_S16(x) (x) | 46 | #define LE_S16(x) (x) |
36 | #endif | 47 | #endif |
37 | 48 | ||
38 | typedef struct ao_sample_format { | ||
39 | int bits; /* bits per sample */ | ||
40 | int rate; /* samples per second (in a single channel) */ | ||
41 | int channels; /* number of audio channels */ | ||
42 | int byte_format; /* Byte ordering in sample, see constants below */ | ||
43 | } ao_sample_format; | ||
44 | |||
45 | #define AO_FMT_LITTLE 1 | ||
46 | #define AO_FMT_BIG 2 | ||
47 | #define AO_FMT_NATIVE 4 | ||
48 | |||
49 | /* the main data structure of the program */ | ||
50 | typedef struct { | ||
51 | int infile; | ||
52 | int outfile; | ||
53 | off_t curpos; | ||
54 | off_t filesize; | ||
55 | ao_sample_format samfmt; /* bits, rate, channels, byte_format */ | ||
56 | // ao_device *ao_dev; | ||
57 | unsigned long total_samples; | ||
58 | unsigned long current_sample; | ||
59 | float total_time; /* seconds */ | ||
60 | float elapsed_time; /* seconds */ | ||
61 | } file_info_struct; | ||
62 | |||
63 | file_info_struct file_info; | ||
64 | |||
65 | #define MALLOC_BUFSIZE (512*1024) | ||
66 | 49 | ||
67 | int mem_ptr; | ||
68 | int bufsize; | ||
69 | unsigned char* mp3buf; // The actual MP3 buffer from Rockbox | ||
70 | unsigned char* mallocbuf; // 512K from the start of MP3 buffer | ||
71 | unsigned char* filebuf; // The rest of the MP3 buffer | ||
72 | |||
73 | |||
74 | |||
75 | #define BUFFER_SIZE 4096 | ||
76 | //static uint8_t buffer[BUFFER_SIZE]; | ||
77 | static float gain = 1; | 50 | static float gain = 1; |
78 | static a52_state_t * state; | 51 | static a52_state_t * state; |
79 | 52 | ||
80 | int output; | ||
81 | |||
82 | // DAVE: I'm not sure what these are for. | ||
83 | int disable_accel=0; | ||
84 | int disable_adjust=0; | ||
85 | int disable_dynrng=0; | ||
86 | |||
87 | /* welcome to the example rockbox plugin */ | ||
88 | |||
89 | /* here is a global api struct pointer. while not strictly necessary, | ||
90 | it's nice not to have to pass the api pointer in all function calls | ||
91 | in the plugin */ | ||
92 | static struct plugin_api* rb; | ||
93 | |||
94 | void* malloc(size_t size) { | ||
95 | void* x; | ||
96 | char s[32]; | ||
97 | |||
98 | x=&mallocbuf[mem_ptr]; | ||
99 | mem_ptr+=size+(size%4); // Keep memory 32-bit aligned (if it was already?) | ||
100 | |||
101 | rb->snprintf(s,30,"Memory used: %d\r",mem_ptr); | ||
102 | rb->lcd_putsxy(0,80,s); | ||
103 | rb->lcd_update(); | ||
104 | return(x); | ||
105 | } | ||
106 | |||
107 | void* calloc(size_t nmemb, size_t size) { | ||
108 | void* x; | ||
109 | x=malloc(nmemb*size); | ||
110 | rb->memset(x,0,nmemb*size); | ||
111 | return(x); | ||
112 | } | ||
113 | |||
114 | void free(void* ptr) { | ||
115 | (void)ptr; | ||
116 | } | ||
117 | |||
118 | void* realloc(void* ptr, size_t size) { | ||
119 | void* x; | ||
120 | (void)ptr; | ||
121 | x=malloc(size); | ||
122 | return(x); | ||
123 | } | ||
124 | |||
125 | void *memcpy(void *dest, const void *src, size_t n) { | ||
126 | return(rb->memcpy(dest,src,n)); | ||
127 | } | ||
128 | |||
129 | void *memset(void *s, int c, size_t n) { | ||
130 | return(rb->memset(s,c,n)); | ||
131 | } | ||
132 | |||
133 | int memcmp(const void *s1, const void *s2, size_t n) { | ||
134 | return(rb->memcmp(s1,s2,n)); | ||
135 | } | ||
136 | |||
137 | void* memmove(const void *s1, const void *s2, size_t n) { | ||
138 | char* dest=(char*)s1; | ||
139 | char* src=(char*)s2; | ||
140 | size_t i; | ||
141 | |||
142 | for (i=0;i<n;i++) { dest[i]=src[i]; } | ||
143 | // while(n>0) { *(dest++)=*(src++); n--; } | ||
144 | return(dest); | ||
145 | } | ||
146 | |||
147 | void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)) { | ||
148 | rb->qsort(base,nmemb,size,compar); | ||
149 | } | ||
150 | |||
151 | |||
152 | |||
153 | |||
154 | static unsigned char wav_header[44]={'R','I','F','F', // 0 - ChunkID | ||
155 | 0,0,0,0, // 4 - ChunkSize (filesize-8) | ||
156 | 'W','A','V','E', // 8 - Format | ||
157 | 'f','m','t',' ', // 12 - SubChunkID | ||
158 | 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM | ||
159 | 1,0, // 20 - AudioFormat (1=16-bit) | ||
160 | 2,0, // 22 - NumChannels | ||
161 | 0,0,0,0, // 24 - SampleRate in Hz | ||
162 | 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8) | ||
163 | 4,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8) | ||
164 | 16,0, // 34 - BitsPerSample | ||
165 | 'd','a','t','a', // 36 - Subchunk2ID | ||
166 | 0,0,0,0 // 40 - Subchunk2Size | ||
167 | }; | ||
168 | |||
169 | void close_wav(file_info_struct* file_info) { | ||
170 | int x; | ||
171 | int filesize=rb->filesize(file_info->outfile); | ||
172 | |||
173 | /* We assume 16-bit, Stereo */ | ||
174 | |||
175 | rb->lseek(file_info->outfile,0,SEEK_SET); | ||
176 | |||
177 | // ChunkSize | ||
178 | x=filesize-8; | ||
179 | wav_header[4]=(x&0xff); | ||
180 | wav_header[5]=(x&0xff00)>>8; | ||
181 | wav_header[6]=(x&0xff0000)>>16; | ||
182 | wav_header[7]=(x&0xff000000)>>24; | ||
183 | |||
184 | // Samplerate | ||
185 | wav_header[24]=file_info->samfmt.rate&0xff; | ||
186 | wav_header[25]=(file_info->samfmt.rate&0xff00)>>8; | ||
187 | wav_header[26]=(file_info->samfmt.rate&0xff0000)>>16; | ||
188 | wav_header[27]=(file_info->samfmt.rate&0xff000000)>>24; | ||
189 | |||
190 | // ByteRate | ||
191 | x=file_info->samfmt.rate*4; | ||
192 | wav_header[28]=(x&0xff); | ||
193 | wav_header[29]=(x&0xff00)>>8; | ||
194 | wav_header[30]=(x&0xff0000)>>16; | ||
195 | wav_header[31]=(x&0xff000000)>>24; | ||
196 | |||
197 | // Subchunk2Size | ||
198 | x=filesize-44; | ||
199 | wav_header[40]=(x&0xff); | ||
200 | wav_header[41]=(x&0xff00)>>8; | ||
201 | wav_header[42]=(x&0xff0000)>>16; | ||
202 | wav_header[43]=(x&0xff000000)>>24; | ||
203 | |||
204 | rb->write(file_info->outfile,wav_header,sizeof(wav_header)); | ||
205 | rb->close(file_info->outfile); | ||
206 | } | ||
207 | |||
208 | static inline int16_t convert (int32_t i) | 53 | static inline int16_t convert (int32_t i) |
209 | { | 54 | { |
210 | i >>= 15; | 55 | i >>= 15; |
211 | return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i); | 56 | return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i); |
212 | } | 57 | } |
213 | 58 | ||
214 | void convert2s16_2 (sample_t * _f, int16_t * s16) | ||
215 | { | ||
216 | int i; | ||
217 | int32_t * f = (int32_t *) _f; | ||
218 | for (i = 0; i < 256; i++) { | ||
219 | s16[2*i] = LE_S16(convert (f[i])); | ||
220 | s16[2*i+1] = LE_S16(convert (f[i+256])); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | void ao_play(file_info_struct* file_info,sample_t* samples,int flags) { | 59 | void ao_play(file_info_struct* file_info,sample_t* samples,int flags) { |
225 | int i; | 60 | int i; |
226 | static int16_t int16_samples[256*2]; | 61 | static int16_t int16_samples[256*2]; |
@@ -228,7 +63,6 @@ void ao_play(file_info_struct* file_info,sample_t* samples,int flags) { | |||
228 | flags &= A52_CHANNEL_MASK | A52_LFE; | 63 | flags &= A52_CHANNEL_MASK | A52_LFE; |
229 | 64 | ||
230 | if (flags==A52_STEREO) { | 65 | if (flags==A52_STEREO) { |
231 | // convert2s16_2(samples,int16_samples,flags); | ||
232 | for (i = 0; i < 256; i++) { | 66 | for (i = 0; i < 256; i++) { |
233 | int16_samples[2*i] = LE_S16(convert (samples[i])); | 67 | int16_samples[2*i] = LE_S16(convert (samples[i])); |
234 | int16_samples[2*i+1] = LE_S16(convert (samples[i+256])); | 68 | int16_samples[2*i+1] = LE_S16(convert (samples[i+256])); |
@@ -239,13 +73,8 @@ void ao_play(file_info_struct* file_info,sample_t* samples,int flags) { | |||
239 | #endif | 73 | #endif |
240 | } | 74 | } |
241 | 75 | ||
76 | /* FIX: Buffer the disk write to write larger amounts at one */ | ||
242 | i=rb->write(file_info->outfile,int16_samples,256*2*2); | 77 | i=rb->write(file_info->outfile,int16_samples,256*2*2); |
243 | |||
244 | #ifdef SIMULATOR | ||
245 | if (i!=(256*2*2)) { | ||
246 | fprintf(stderr,"Attempted to write %d bytes, wrote %d bytes\n",256*2*2,i); | ||
247 | } | ||
248 | #endif | ||
249 | } | 78 | } |
250 | 79 | ||
251 | 80 | ||
@@ -304,13 +133,10 @@ void a52_decode_data (file_info_struct* file_info, uint8_t * start, uint8_t * en | |||
304 | 133 | ||
305 | if (a52_frame (state, buf, &flags, &level, bias)) | 134 | if (a52_frame (state, buf, &flags, &level, bias)) |
306 | goto error; | 135 | goto error; |
136 | file_info->frames_decoded++; | ||
307 | 137 | ||
308 | if (output==0) { | 138 | /* We assume this never changes */ |
309 | file_info->samfmt.bits=16; | 139 | file_info->samplerate=sample_rate; |
310 | file_info->samfmt.rate=sample_rate; | ||
311 | output=1; | ||
312 | // output=ao_open(&format); | ||
313 | } | ||
314 | 140 | ||
315 | // An A52 frame consists of 6 blocks of 256 samples | 141 | // An A52 frame consists of 6 blocks of 256 samples |
316 | // So we decode and output them one block at a time | 142 | // So we decode and output them one block at a time |
@@ -323,7 +149,6 @@ void a52_decode_data (file_info_struct* file_info, uint8_t * start, uint8_t * en | |||
323 | } | 149 | } |
324 | bufptr = buf; | 150 | bufptr = buf; |
325 | bufpos = buf + 7; | 151 | bufpos = buf + 7; |
326 | // print_fps (0); | ||
327 | continue; | 152 | continue; |
328 | error: | 153 | error: |
329 | #ifdef SIMULATOR | 154 | #ifdef SIMULATOR |
@@ -336,111 +161,47 @@ void a52_decode_data (file_info_struct* file_info, uint8_t * start, uint8_t * en | |||
336 | } | 161 | } |
337 | } | 162 | } |
338 | 163 | ||
164 | |||
165 | #define BUFFER_SIZE 4096 | ||
166 | |||
339 | /* this is the plugin entry point */ | 167 | /* this is the plugin entry point */ |
340 | enum plugin_status plugin_start(struct plugin_api* api, void* file) | 168 | enum plugin_status plugin_start(struct plugin_api* api, void* file) |
341 | { | 169 | { |
342 | int i,n,bytesleft; | 170 | /* Generic plugin initialisation */ |
343 | char s[32]; | ||
344 | unsigned long ticks_taken; | ||
345 | unsigned long start_tick; | ||
346 | unsigned long long speed; | ||
347 | unsigned long xspeed; | ||
348 | int accel=0; // ??? This is the parameter to a52_init(). | ||
349 | |||
350 | /* this macro should be called as the first thing you do in the plugin. | ||
351 | it test that the api version and model the plugin was compiled for | ||
352 | matches the machine it is running on */ | ||
353 | TEST_PLUGIN_API(api); | ||
354 | 171 | ||
355 | /* if you are using a global api pointer, don't forget to copy it! | 172 | TEST_PLUGIN_API(api); |
356 | otherwise you will get lovely "I04: IllInstr" errors... :-) */ | ||
357 | rb = api; | 173 | rb = api; |
358 | 174 | ||
359 | /* now go ahead and have fun! */ | ||
360 | // rb->splash(HZ*2, true, "Hello world!"); | ||
361 | 175 | ||
362 | mem_ptr=0; | 176 | /* This function sets up the buffers and reads the file into RAM */ |
363 | mp3buf=rb->plugin_get_mp3_buffer(&bufsize); | ||
364 | mallocbuf=mp3buf; | ||
365 | filebuf=&mp3buf[MALLOC_BUFSIZE]; | ||
366 | 177 | ||
367 | rb->snprintf(s,32,"mp3 bufsize: %d\r",bufsize); | 178 | if (local_init(file,&file_info)) { |
368 | rb->lcd_putsxy(0,100,s); | ||
369 | rb->lcd_update(); | ||
370 | |||
371 | file_info.infile=rb->open(file,O_RDONLY); | ||
372 | file_info.outfile=rb->creat("/ac3test.wav",O_WRONLY); | ||
373 | rb->write(file_info.outfile,wav_header,sizeof(wav_header)); | ||
374 | file_info.curpos=0; | ||
375 | file_info.filesize=rb->filesize(file_info.infile); | ||
376 | |||
377 | if (file_info.filesize > (bufsize-MALLOC_BUFSIZE)) { | ||
378 | rb->close(file_info.infile); | ||
379 | rb->splash(HZ*2, true, "File too large"); | ||
380 | return PLUGIN_ERROR; | 179 | return PLUGIN_ERROR; |
381 | } | 180 | } |
382 | 181 | ||
383 | rb->snprintf(s,32,"Loading file..."); | 182 | /* Intialise the A52 decoder and check for success */ |
384 | rb->lcd_putsxy(0,0,s); | 183 | state = a52_init (0); // Parameter is "accel" |
385 | rb->lcd_update(); | ||
386 | |||
387 | bytesleft=file_info.filesize; | ||
388 | i=0; | ||
389 | while (bytesleft > 0) { | ||
390 | n=rb->read(file_info.infile,&filebuf[i],bytesleft); | ||
391 | if (n < 0) { | ||
392 | rb->close(file_info.infile); | ||
393 | rb->splash(HZ*2, true, "ERROR READING FILE"); | ||
394 | return PLUGIN_ERROR; | ||
395 | } | ||
396 | i+=n; bytesleft-=n; | ||
397 | } | ||
398 | rb->close(file_info.infile); | ||
399 | 184 | ||
400 | state = a52_init (accel); | ||
401 | if (state == NULL) { | 185 | if (state == NULL) { |
402 | //fprintf (stderr, "A52 init failed\n"); | 186 | rb->splash(HZ*2, true, "a52_init failed"); |
403 | return PLUGIN_ERROR; | 187 | return PLUGIN_ERROR; |
404 | } | 188 | } |
405 | 189 | ||
406 | i=0; | 190 | /* The main decoding loop */ |
407 | start_tick=*(rb->current_tick); | 191 | |
192 | file_info.start_tick=*(rb->current_tick); | ||
408 | while (file_info.curpos < file_info.filesize) { | 193 | while (file_info.curpos < file_info.filesize) { |
409 | i++; | 194 | |
410 | if ((file_info.curpos+BUFFER_SIZE) < file_info.filesize) { | 195 | if ((file_info.curpos+BUFFER_SIZE) < file_info.filesize) { |
411 | a52_decode_data (&file_info,&filebuf[file_info.curpos],&filebuf[file_info.curpos+BUFFER_SIZE]); | 196 | a52_decode_data(&file_info,&filebuf[file_info.curpos],&filebuf[file_info.curpos+BUFFER_SIZE]); |
412 | file_info.curpos+=BUFFER_SIZE; | 197 | file_info.curpos+=BUFFER_SIZE; |
413 | } else { | 198 | } else { |
414 | a52_decode_data (&file_info,&filebuf[file_info.curpos],&filebuf[file_info.filesize-1]); | 199 | a52_decode_data(&file_info,&filebuf[file_info.curpos],&filebuf[file_info.filesize-1]); |
415 | file_info.curpos=file_info.filesize; | 200 | file_info.curpos=file_info.filesize; |
416 | } | 201 | } |
417 | 202 | ||
418 | rb->snprintf(s,32,"Bytes read: %d\r",file_info.curpos); | 203 | display_status(&file_info); |
419 | rb->lcd_putsxy(0,0,s); | ||
420 | rb->snprintf(s,32,"Samples Decoded: %d\r",file_info.current_sample); | ||
421 | rb->lcd_putsxy(0,20,s); | ||
422 | rb->snprintf(s,32,"Frames Decoded: %d\r",i); | ||
423 | rb->lcd_putsxy(0,40,s); | ||
424 | |||
425 | ticks_taken=*(rb->current_tick)-start_tick; | ||
426 | |||
427 | /* e.g.: | ||
428 | ticks_taken=500 | ||
429 | sam_fmt.rate=44,100 | ||
430 | samples_decoded=172,400 | ||
431 | (samples_decoded/sam_fmt.rate)*100=400 (time it should have taken) | ||
432 | % Speed=(400/500)*100=80% | ||
433 | |||
434 | */ | ||
435 | 204 | ||
436 | if (ticks_taken==0) { ticks_taken=1; } // Avoid fp exception. | ||
437 | |||
438 | speed=(100*file_info.current_sample)/file_info.samfmt.rate; | ||
439 | xspeed=(speed*10000)/ticks_taken; | ||
440 | rb->snprintf(s,32,"Speed %ld.%02ld %% Secs: %d",(xspeed/100),(xspeed%100),ticks_taken/100); | ||
441 | rb->lcd_putsxy(0,60,s); | ||
442 | |||
443 | rb->lcd_update(); | ||
444 | if (rb->button_get(false)!=BUTTON_NONE) { | 205 | if (rb->button_get(false)!=BUTTON_NONE) { |
445 | close_wav(&file_info); | 206 | close_wav(&file_info); |
446 | return PLUGIN_OK; | 207 | return PLUGIN_OK; |
@@ -448,7 +209,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file) | |||
448 | } | 209 | } |
449 | close_wav(&file_info); | 210 | close_wav(&file_info); |
450 | 211 | ||
451 | //NO NEED: a52_free (state); | 212 | /* Cleanly close and exit */ |
213 | |||
214 | //NOT NEEDED: a52_free (state); | ||
215 | |||
452 | rb->splash(HZ*2, true, "FINISHED!"); | 216 | rb->splash(HZ*2, true, "FINISHED!"); |
453 | return PLUGIN_OK; | 217 | return PLUGIN_OK; |
454 | } | 218 | } |
diff --git a/apps/plugins/xxx2wav.h b/apps/plugins/xxx2wav.h new file mode 100644 index 0000000000..96942824fd --- /dev/null +++ b/apps/plugins/xxx2wav.h | |||
@@ -0,0 +1,240 @@ | |||
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 | /* Various "helper functions" common to all the xxx2wav decoder plugins | ||
21 | |||
22 | We include them as a .h because the plugin build system links | ||
23 | exactly one .c file with exactly one .rock file. | ||
24 | */ | ||
25 | |||
26 | |||
27 | /* the main data structure of the program */ | ||
28 | typedef struct { | ||
29 | int infile; | ||
30 | int outfile; | ||
31 | off_t curpos; | ||
32 | off_t filesize; | ||
33 | int samplerate; | ||
34 | int channels; | ||
35 | int frames_decoded; | ||
36 | unsigned long total_samples; | ||
37 | unsigned long current_sample; | ||
38 | unsigned long start_tick; | ||
39 | } file_info_struct; | ||
40 | |||
41 | file_info_struct file_info; | ||
42 | |||
43 | #define MALLOC_BUFSIZE (512*1024) | ||
44 | |||
45 | int mem_ptr; | ||
46 | int bufsize; | ||
47 | unsigned char* mp3buf; // The actual MP3 buffer from Rockbox | ||
48 | unsigned char* mallocbuf; // 512K from the start of MP3 buffer | ||
49 | unsigned char* filebuf; // The rest of the MP3 buffer | ||
50 | |||
51 | void* malloc(size_t size) { | ||
52 | void* x; | ||
53 | char s[32]; | ||
54 | |||
55 | x=&mallocbuf[mem_ptr]; | ||
56 | mem_ptr+=size+(size%4); // Keep memory 32-bit aligned (if it was already?) | ||
57 | |||
58 | rb->snprintf(s,30,"Memory used: %d\r",mem_ptr); | ||
59 | rb->lcd_putsxy(0,80,s); | ||
60 | rb->lcd_update(); | ||
61 | return(x); | ||
62 | } | ||
63 | |||
64 | void* calloc(size_t nmemb, size_t size) { | ||
65 | void* x; | ||
66 | x=malloc(nmemb*size); | ||
67 | rb->memset(x,0,nmemb*size); | ||
68 | return(x); | ||
69 | } | ||
70 | |||
71 | void free(void* ptr) { | ||
72 | (void)ptr; | ||
73 | } | ||
74 | |||
75 | void* realloc(void* ptr, size_t size) { | ||
76 | void* x; | ||
77 | (void)ptr; | ||
78 | x=malloc(size); | ||
79 | return(x); | ||
80 | } | ||
81 | |||
82 | void *memcpy(void *dest, const void *src, size_t n) { | ||
83 | return(rb->memcpy(dest,src,n)); | ||
84 | } | ||
85 | |||
86 | void *memset(void *s, int c, size_t n) { | ||
87 | return(rb->memset(s,c,n)); | ||
88 | } | ||
89 | |||
90 | int memcmp(const void *s1, const void *s2, size_t n) { | ||
91 | return(rb->memcmp(s1,s2,n)); | ||
92 | } | ||
93 | |||
94 | void* memmove(const void *s1, const void *s2, size_t n) { | ||
95 | char* dest=(char*)s1; | ||
96 | char* src=(char*)s2; | ||
97 | size_t i; | ||
98 | |||
99 | for (i=0;i<n;i++) { dest[i]=src[i]; } | ||
100 | // while(n>0) { *(dest++)=*(src++); n--; } | ||
101 | return(dest); | ||
102 | } | ||
103 | |||
104 | void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)) { | ||
105 | rb->qsort(base,nmemb,size,compar); | ||
106 | } | ||
107 | |||
108 | void display_status(file_info_struct* file_info) { | ||
109 | char s[32]; | ||
110 | unsigned long ticks_taken; | ||
111 | unsigned long long speed; | ||
112 | unsigned long xspeed; | ||
113 | |||
114 | rb->snprintf(s,32,"Bytes read: %d\r",file_info->curpos); | ||
115 | rb->lcd_putsxy(0,0,s); | ||
116 | rb->snprintf(s,32,"Samples Decoded: %d\r",file_info->current_sample); | ||
117 | rb->lcd_putsxy(0,20,s); | ||
118 | rb->snprintf(s,32,"Frames Decoded: %d\r",file_info->frames_decoded); | ||
119 | rb->lcd_putsxy(0,40,s); | ||
120 | |||
121 | ticks_taken=*(rb->current_tick)-file_info->start_tick; | ||
122 | |||
123 | /* e.g.: | ||
124 | ticks_taken=500 | ||
125 | sam_fmt.rate=44,100 | ||
126 | samples_decoded=172,400 | ||
127 | (samples_decoded/sam_fmt.rate)*100=400 (time it should have taken) | ||
128 | % Speed=(400/500)*100=80% | ||
129 | */ | ||
130 | |||
131 | if (ticks_taken==0) { ticks_taken=1; } // Avoid fp exception. | ||
132 | |||
133 | speed=(100*file_info->current_sample)/file_info->samplerate; | ||
134 | xspeed=(speed*10000)/ticks_taken; | ||
135 | rb->snprintf(s,32,"Speed %ld.%02ld %% Secs: %d",(xspeed/100),(xspeed%100),ticks_taken/100); | ||
136 | rb->lcd_putsxy(0,60,s); | ||
137 | |||
138 | rb->lcd_update(); | ||
139 | } | ||
140 | |||
141 | static unsigned char wav_header[44]={'R','I','F','F', // 0 - ChunkID | ||
142 | 0,0,0,0, // 4 - ChunkSize (filesize-8) | ||
143 | 'W','A','V','E', // 8 - Format | ||
144 | 'f','m','t',' ', // 12 - SubChunkID | ||
145 | 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM | ||
146 | 1,0, // 20 - AudioFormat (1=16-bit) | ||
147 | 2,0, // 22 - NumChannels | ||
148 | 0,0,0,0, // 24 - SampleRate in Hz | ||
149 | 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8) | ||
150 | 4,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8) | ||
151 | 16,0, // 34 - BitsPerSample | ||
152 | 'd','a','t','a', // 36 - Subchunk2ID | ||
153 | 0,0,0,0 // 40 - Subchunk2Size | ||
154 | }; | ||
155 | |||
156 | |||
157 | int local_init(char* file, file_info_struct* file_info) { | ||
158 | char s[32]; | ||
159 | int i,n,bytesleft; | ||
160 | |||
161 | mem_ptr=0; | ||
162 | mp3buf=rb->plugin_get_mp3_buffer(&bufsize); | ||
163 | mallocbuf=mp3buf; | ||
164 | filebuf=&mp3buf[MALLOC_BUFSIZE]; | ||
165 | |||
166 | rb->snprintf(s,32,"mp3 bufsize: %d\r",bufsize); | ||
167 | rb->lcd_putsxy(0,100,s); | ||
168 | rb->lcd_update(); | ||
169 | |||
170 | file_info->infile=rb->open(file,O_RDONLY); | ||
171 | file_info->outfile=rb->creat("/ac3test.wav",O_WRONLY); | ||
172 | rb->write(file_info->outfile,wav_header,sizeof(wav_header)); | ||
173 | file_info->curpos=0; | ||
174 | file_info->frames_decoded=0; | ||
175 | file_info->filesize=rb->filesize(file_info->infile); | ||
176 | |||
177 | if (file_info->filesize > (bufsize-MALLOC_BUFSIZE)) { | ||
178 | rb->close(file_info->infile); | ||
179 | rb->splash(HZ*2, true, "File too large"); | ||
180 | return(1); | ||
181 | } | ||
182 | |||
183 | rb->snprintf(s,32,"Loading file..."); | ||
184 | rb->lcd_putsxy(0,0,s); | ||
185 | rb->lcd_update(); | ||
186 | |||
187 | bytesleft=file_info->filesize; | ||
188 | i=0; | ||
189 | while (bytesleft > 0) { | ||
190 | n=rb->read(file_info->infile,&filebuf[i],bytesleft); | ||
191 | if (n < 0) { | ||
192 | rb->close(file_info->infile); | ||
193 | rb->splash(HZ*2, true, "ERROR READING FILE"); | ||
194 | return(1); | ||
195 | } | ||
196 | i+=n; bytesleft-=n; | ||
197 | } | ||
198 | rb->close(file_info->infile); | ||
199 | return(0); | ||
200 | } | ||
201 | |||
202 | void close_wav(file_info_struct* file_info) { | ||
203 | int x; | ||
204 | int filesize=rb->filesize(file_info->outfile); | ||
205 | |||
206 | /* We assume 16-bit, Stereo */ | ||
207 | |||
208 | rb->lseek(file_info->outfile,0,SEEK_SET); | ||
209 | |||
210 | // ChunkSize | ||
211 | x=filesize-8; | ||
212 | wav_header[4]=(x&0xff); | ||
213 | wav_header[5]=(x&0xff00)>>8; | ||
214 | wav_header[6]=(x&0xff0000)>>16; | ||
215 | wav_header[7]=(x&0xff000000)>>24; | ||
216 | |||
217 | // Samplerate | ||
218 | wav_header[24]=file_info->samplerate&0xff; | ||
219 | wav_header[25]=(file_info->samplerate&0xff00)>>8; | ||
220 | wav_header[26]=(file_info->samplerate&0xff0000)>>16; | ||
221 | wav_header[27]=(file_info->samplerate&0xff000000)>>24; | ||
222 | |||
223 | // ByteRate | ||
224 | x=file_info->samplerate*4; | ||
225 | wav_header[28]=(x&0xff); | ||
226 | wav_header[29]=(x&0xff00)>>8; | ||
227 | wav_header[30]=(x&0xff0000)>>16; | ||
228 | wav_header[31]=(x&0xff000000)>>24; | ||
229 | |||
230 | // Subchunk2Size | ||
231 | x=filesize-44; | ||
232 | wav_header[40]=(x&0xff); | ||
233 | wav_header[41]=(x&0xff00)>>8; | ||
234 | wav_header[42]=(x&0xff0000)>>16; | ||
235 | wav_header[43]=(x&0xff000000)>>24; | ||
236 | |||
237 | rb->write(file_info->outfile,wav_header,sizeof(wav_header)); | ||
238 | rb->close(file_info->outfile); | ||
239 | } | ||
240 | |||