summaryrefslogtreecommitdiff
path: root/apps/codecs/wav_enc.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/wav_enc.c')
-rw-r--r--apps/codecs/wav_enc.c419
1 files changed, 322 insertions, 97 deletions
diff --git a/apps/codecs/wav_enc.c b/apps/codecs/wav_enc.c
index 5aabb5d8e8..974a903310 100644
--- a/apps/codecs/wav_enc.c
+++ b/apps/codecs/wav_enc.c
@@ -19,140 +19,364 @@
19 19
20#ifndef SIMULATOR 20#ifndef SIMULATOR
21 21
22#include <inttypes.h>
22#include "codeclib.h" 23#include "codeclib.h"
23 24
24CODEC_HEADER 25CODEC_ENC_HEADER
26
27#ifdef USE_IRAM
28extern char iramcopy[];
29extern char iramstart[];
30extern char iramend[];
31extern char iedata[];
32extern char iend[];
33#endif
34
35struct riff_header
36{
37 uint8_t riff_id[4]; /* 00h - "RIFF" */
38 uint32_t riff_size; /* 04h - sz following headers + data_size */
39 /* format header */
40 uint8_t format[4]; /* 08h - "WAVE" */
41 uint8_t format_id[4]; /* 0Ch - "fmt " */
42 uint32_t format_size; /* 10h - 16 for PCM (sz format data) */
43 /* format data */
44 uint16_t audio_format; /* 14h - 1=PCM */
45 uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */
46 uint32_t sample_rate; /* 18h - HZ */
47 uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
48 uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */
49 uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */
50 /* Not for audio_format=1 (PCM) */
51/* unsigned short extra_param_size; 24h - size of extra data */
52/* unsigned char *extra_params; */
53 /* data header */
54 uint8_t data_id[4]; /* 24h - "data" */
55 uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */
56/* unsigned char *data; 2ch - actual sound data */
57};
58
59#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
60#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
61#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
62
63#define PCM_DEPTH_BYTES 2
64#define PCM_DEPTH_BITS 16
65#define PCM_SAMP_PER_CHUNK 2048
66#define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4)
25 67
26static struct codec_api *ci; 68static struct codec_api *ci;
27static int enc_channels; 69static int num_channels;
70uint32_t sample_rate;
71uint32_t enc_size;
28 72
29#define CHUNK_SIZE 8192 73static const struct riff_header riff_header =
74{
75 /* "RIFF" header */
76 { 'R', 'I', 'F', 'F' }, /* riff_id */
77 0, /* riff_size (*) */
78 /* format header */
79 { 'W', 'A', 'V', 'E' }, /* format */
80 { 'f', 'm', 't', ' ' }, /* format_id */
81 H_TO_LE32(16), /* format_size */
82 /* format data */
83 H_TO_LE16(1), /* audio_format */
84 0, /* num_channels (*) */
85 0, /* sample_rate (*) */
86 0, /* byte_rate (*) */
87 0, /* block_align (*) */
88 H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */
89 /* data header */
90 { 'd', 'a', 't', 'a' }, /* data_id */
91 0 /* data_size (*) */
92 /* (*) updated during ENC_END_FILE event */
93};
30 94
31static unsigned char wav_header[44] = 95/* called version often - inline */
32{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, 96static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
33 0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0}; 97static inline bool is_file_data_ok(struct enc_file_event_data *data)
98{
99 return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
100} /* is_file_data_ok */
34 101
35static unsigned char wav_header_mono[44] = 102/* called version often - inline */
36{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, 103static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
37 0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0}; 104static inline bool on_write_chunk(struct enc_file_event_data *data)
105{
106 if (!is_file_data_ok(data))
107 return false;
38 108
39/* update file header info callback function (called by main application) */ 109 if (data->chunk->enc_data == NULL)
40void enc_set_header(void *head_buffer, /* ptr to the file header data */ 110 {
41 int head_size, /* size of this header data */ 111#ifdef ROCKBOX_HAS_LOGF
42 int num_pcm_samples, /* amount of processed pcm samples */ 112 ci->logf("wav enc: NULL data");
43 bool is_file_header) 113#endif
114 return true;
115 }
116
117 if (ci->write(data->rec_file, data->chunk->enc_data,
118 data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
119 return false;
120
121 data->num_pcm_samples += data->chunk->num_pcm;
122 return true;
123} /* on_write_chunk */
124
125static bool on_start_file(struct enc_file_event_data *data)
44{ 126{
45 int num_file_bytes = num_pcm_samples * 2 * enc_channels; 127 if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
128 return false;
129
130 data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
131
132 if (data->rec_file < 0)
133 return false;
134
135 /* reset sample count */
136 data->num_pcm_samples = 0;
46 137
47 if(is_file_header) 138 /* write template header */
139 if (ci->write(data->rec_file, &riff_header, sizeof (riff_header))
140 != sizeof (riff_header))
48 { 141 {
49 /* update file header before file closing */ 142 return false;
50 if((int)sizeof(wav_header) < head_size) 143 }
144
145 data->new_enc_size += sizeof (riff_header);
146 return true;
147} /* on_start_file */
148
149static bool on_end_file(struct enc_file_event_data *data)
150{
151 /* update template header */
152 struct riff_header hdr;
153 uint32_t data_size;
154
155 if (!is_file_data_ok(data))
156 return false;
157
158 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
159 ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
160 {
161 return false;
162 }
163
164 data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES;
165
166 /* "RIFF" header */
167 hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE
168 + RIFF_DATA_HEADER_SIZE + data_size);
169
170 /* format data */
171 hdr.num_channels = htole16(num_channels);
172 hdr.sample_rate = htole32(sample_rate);
173 hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES);
174 hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES);
175
176 /* data header */
177 hdr.data_size = htole32(data_size);
178
179 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
180 ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
181 {
182 return false;
183 }
184
185 ci->fsync(data->rec_file);
186 ci->close(data->rec_file);
187 data->rec_file = -1;
188
189 return true;
190} /* on_end_file */
191
192static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR;
193static void enc_events_callback(enum enc_events event, void *data)
194{
195 if (event == ENC_WRITE_CHUNK)
196 {
197 if (on_write_chunk((struct enc_file_event_data *)data))
198 return;
199 }
200 else if (event == ENC_START_FILE)
201 {
202 if (on_start_file((struct enc_file_event_data *)data))
203 return;
204 }
205 else if (event == ENC_END_FILE)
206 {
207 if (on_end_file((struct enc_file_event_data *)data))
208 return;
209 }
210 else
211 {
212 return;
213 }
214
215 ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
216} /* enc_events_callback */
217
218/* convert native pcm samples to wav format samples */
219static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR;
220static void chunk_to_wav_format(uint32_t *src, uint32_t *dst)
221{
222 if (num_channels == 1)
223 {
224 /* On big endian:
225 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
226 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
227 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
228 *
229 * On little endian:
230 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
231 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
232 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
233 */
234 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
235
236 inline void to_mono(uint32_t **src, uint32_t **dst)
51 { 237 {
52 /* update wave header size entries: special to WAV format */ 238 int32_t lr1, lr2;
53 *(long*)(head_buffer+ 4) = htole32(num_file_bytes + 36); 239
54 *(long*)(head_buffer+40) = htole32(num_file_bytes); 240 lr1 = *(*src)++;
241 lr1 = ((int16_t)lr1 + (lr1 >> 16)) >> 1;
242
243 lr2 = *(*src)++;
244 lr2 = ((int16_t)lr2 + (lr2 >> 16)) >> 1;
245 *(*dst)++ = swap_odd_even_be32((lr1 << 16) | (uint16_t)lr2);
246 } /* to_mono */
247
248 do
249 {
250 to_mono(&src, &dst);
251 to_mono(&src, &dst);
252 to_mono(&src, &dst);
253 to_mono(&src, &dst);
254 to_mono(&src, &dst);
255 to_mono(&src, &dst);
256 to_mono(&src, &dst);
257 to_mono(&src, &dst);
55 } 258 }
259 while (src < src_end);
56 } 260 }
57} 261 else
262 {
263#ifdef ROCKBOX_BIG_ENDIAN
264 /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
265 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
266 */
267 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
58 268
59/* main codec entry point */ 269 do
60enum codec_status codec_start(struct codec_api* api) 270 {
271 *dst++ = swap_odd_even32(*src++);
272 *dst++ = swap_odd_even32(*src++);
273 *dst++ = swap_odd_even32(*src++);
274 *dst++ = swap_odd_even32(*src++);
275 *dst++ = swap_odd_even32(*src++);
276 *dst++ = swap_odd_even32(*src++);
277 *dst++ = swap_odd_even32(*src++);
278 *dst++ = swap_odd_even32(*src++);
279 }
280 while (src < src_end);
281#else
282 /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
283 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
284 */
285 ci->memcpy(dst, src, PCM_CHUNK_SIZE);
286#endif
287 }
288} /* chunk_to_wav_format */
289
290static bool init_encoder(void)
61{ 291{
62 int i; 292 struct enc_inputs inputs;
63 long lr; 293 struct enc_parameters params;
64 unsigned long t;
65 unsigned long *src;
66 unsigned long *dst;
67 int chunk_size, num_chunks, samp_per_chunk;
68 int enc_buffer_size;
69 int enc_quality;
70 bool cpu_boosted = true; /* start boosted */
71 294
72 ci = api; // copy to global api pointer 295 if (ci->enc_get_inputs == NULL ||
296 ci->enc_set_parameters == NULL ||
297 ci->enc_get_chunk == NULL ||
298 ci->enc_finish_chunk == NULL ||
299 ci->enc_pcm_buf_near_empty == NULL ||
300 ci->enc_get_pcm_data == NULL )
301 return false;
73 302
74 if(ci->enc_get_inputs == NULL || 303 ci->enc_get_inputs(&inputs);
75 ci->enc_set_parameters == NULL ||
76 ci->enc_alloc_chunk == NULL ||
77 ci->enc_free_chunk == NULL ||
78 ci->enc_wavbuf_near_empty == NULL ||
79 ci->enc_get_wav_data == NULL ||
80 ci->enc_set_header_callback == NULL )
81 return CODEC_ERROR;
82 304
83 ci->cpu_boost(true); 305 if (inputs.config->afmt != AFMT_PCM_WAV)
306 return false;
84 307
85 *ci->enc_set_header_callback = enc_set_header; 308 sample_rate = inputs.sample_rate;
86 ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); 309 num_channels = inputs.num_channels;
87 310
88 /* configure the buffer system */ 311 /* configure the buffer system */
89 chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; 312 params.afmt = AFMT_PCM_WAV;
90 num_chunks = enc_buffer_size / chunk_size; 313 enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2;
91 samp_per_chunk = CHUNK_SIZE / 4; 314 params.chunk_size = enc_size;
315 params.enc_sample_rate = sample_rate;
316 params.reserve_bytes = 0;
317 params.events_callback = enc_events_callback;
318 ci->enc_set_parameters(&params);
319
320 return true;
321} /* init_encoder */
322
323/* main codec entry point */
324enum codec_status codec_start(struct codec_api* api)
325{
326 bool cpu_boosted;
92 327
93 /* inform the main program about buffer dimensions and other params */ 328 ci = api; // copy to global api pointer
94 ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk, 329
95 (enc_channels == 2) ? wav_header : wav_header_mono, 330#ifdef USE_IRAM
96 sizeof(wav_header), AFMT_PCM_WAV); 331 ci->memcpy(iramstart, iramcopy, iramend - iramstart);
332 ci->memset(iedata, 0, iend - iedata);
333#endif
334
335 if (!init_encoder())
336 {
337 ci->enc_codec_loaded = -1;
338 return CODEC_ERROR;
339 }
97 340
98 /* main application waits for this flag during encoder loading */ 341 /* main application waits for this flag during encoder loading */
99 ci->enc_codec_loaded = true; 342 ci->enc_codec_loaded = 1;
343
344 ci->cpu_boost(true);
345 cpu_boosted = true;
100 346
101 /* main encoding loop */ 347 /* main encoding loop */
102 while(!ci->stop_codec) 348 while(!ci->stop_codec)
103 { 349 {
104 while((src = (unsigned long*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) 350 uint32_t *src;
351
352 while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
105 { 353 {
106 if(ci->stop_codec) 354 struct enc_chunk_hdr *chunk;
355
356 if (ci->stop_codec)
107 break; 357 break;
108 358
109 if(ci->enc_wavbuf_near_empty() == 0) 359 if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
110 { 360 {
111 if(!cpu_boosted) 361 ci->cpu_boost(true);
112 { 362 cpu_boosted = true;
113 ci->cpu_boost(true);
114 cpu_boosted = true;
115 }
116 } 363 }
117 364
118 dst = (unsigned long*)ci->enc_alloc_chunk(); 365 chunk = ci->enc_get_chunk();
119 *dst++ = CHUNK_SIZE * enc_channels / 2; /* set size info */ 366 chunk->enc_size = enc_size;
367 chunk->num_pcm = PCM_SAMP_PER_CHUNK;
368 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
120 369
121 if(enc_channels == 2) 370 chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
122 {
123 /* swap byte order & copy to destination */
124 for (i=0; i<CHUNK_SIZE/4; i++)
125 {
126 t = *src++;
127 *dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
128 }
129 }
130 else
131 {
132 /* mix left/right, swap byte order & copy to destination */
133 for (i=0; i<CHUNK_SIZE/8; i++)
134 {
135 lr = (long)*src++;
136 lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
137 t = (lr << 16);
138 lr = (long)*src++;
139 lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
140 t |= lr & 0xffff;
141 *dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
142 }
143 }
144 371
145 ci->enc_free_chunk(); 372 ci->enc_finish_chunk();
146 ci->yield(); 373 ci->yield();
147 } 374 }
148 375
149 if(ci->enc_wavbuf_near_empty()) 376 if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0)
150 { 377 {
151 if(cpu_boosted) 378 ci->cpu_boost(false);
152 { 379 cpu_boosted = false;
153 ci->cpu_boost(false);
154 cpu_boosted = false;
155 }
156 } 380 }
157 381
158 ci->yield(); 382 ci->yield();
@@ -162,11 +386,12 @@ enum codec_status codec_start(struct codec_api* api)
162 ci->cpu_boost(false); 386 ci->cpu_boost(false);
163 387
164 /* reset parameters to initial state */ 388 /* reset parameters to initial state */
165 ci->enc_set_parameters(0, 0, 0, 0, 0, 0); 389 ci->enc_set_parameters(NULL);
166 390
167 /* main application waits for this flag during encoder removing */ 391 /* main application waits for this flag during encoder removing */
168 ci->enc_codec_loaded = false; 392 ci->enc_codec_loaded = 0;
169 393
170 return CODEC_OK; 394 return CODEC_OK;
171} 395} /* codec_start */
172#endif 396
397#endif /* ndef SIMULATOR */