diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/codecs/aiff_enc.c | 399 | ||||
-rw-r--r-- | lib/rbcodec/codecs/codecs.h | 45 | ||||
-rw-r--r-- | lib/rbcodec/codecs/mp3_enc.c | 813 | ||||
-rw-r--r-- | lib/rbcodec/codecs/wav_enc.c | 376 | ||||
-rw-r--r-- | lib/rbcodec/codecs/wavpack_enc.c | 453 |
5 files changed, 862 insertions, 1224 deletions
diff --git a/lib/rbcodec/codecs/aiff_enc.c b/lib/rbcodec/codecs/aiff_enc.c index 8e9246d2bb..fb8db384a3 100644 --- a/lib/rbcodec/codecs/aiff_enc.c +++ b/lib/rbcodec/codecs/aiff_enc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Antonius Hellmann | 10 | * Copyright (C) 2006 Antonius Hellmann |
11 | * Copyright (C) 2006-2013 Michael Sevakis | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -47,10 +48,15 @@ struct aiff_header | |||
47 | #define PCM_DEPTH_BYTES 2 | 48 | #define PCM_DEPTH_BYTES 2 |
48 | #define PCM_DEPTH_BITS 16 | 49 | #define PCM_DEPTH_BITS 16 |
49 | #define PCM_SAMP_PER_CHUNK 2048 | 50 | #define PCM_SAMP_PER_CHUNK 2048 |
50 | #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4) | 51 | |
52 | static int num_channels; | ||
53 | static uint32_t sample_rate; | ||
54 | static size_t frame_size; | ||
55 | static size_t pcm_size; | ||
56 | static uint32_t num_sample_frames; | ||
51 | 57 | ||
52 | /* Template headers */ | 58 | /* Template headers */ |
53 | struct aiff_header aiff_header = | 59 | static const struct aiff_header aiff_template_header = |
54 | { | 60 | { |
55 | { 'F', 'O', 'R', 'M' }, /* form_id */ | 61 | { 'F', 'O', 'R', 'M' }, /* form_id */ |
56 | 0, /* form_size (*) */ | 62 | 0, /* form_size (*) */ |
@@ -65,336 +71,193 @@ struct aiff_header aiff_header = | |||
65 | 0, /* ssnd_size (*) */ | 71 | 0, /* ssnd_size (*) */ |
66 | htobe32(0), /* offset */ | 72 | htobe32(0), /* offset */ |
67 | htobe32(0), /* block_size */ | 73 | htobe32(0), /* block_size */ |
74 | /* (*) updated when finalizing stream */ | ||
68 | }; | 75 | }; |
69 | 76 | ||
70 | /* (*) updated when finalizing file */ | 77 | static inline void frame_htobe(uint32_t *p, size_t size) |
71 | 78 | { | |
72 | static int num_channels IBSS_ATTR; | 79 | #ifdef ROCKBOX_LITTLE_ENDIAN |
73 | static int rec_mono_mode IBSS_ATTR; | 80 | /* Byte-swap samples, stereo or mono */ |
74 | static uint32_t sample_rate; | 81 | do |
75 | static uint32_t enc_size; | 82 | { |
76 | static int32_t err IBSS_ATTR; | 83 | uint32_t t; |
84 | t = swap_odd_even32(*p); *p++ = t; | ||
85 | t = swap_odd_even32(*p); *p++ = t; | ||
86 | t = swap_odd_even32(*p); *p++ = t; | ||
87 | t = swap_odd_even32(*p); *p++ = t; | ||
88 | t = swap_odd_even32(*p); *p++ = t; | ||
89 | t = swap_odd_even32(*p); *p++ = t; | ||
90 | t = swap_odd_even32(*p); *p++ = t; | ||
91 | t = swap_odd_even32(*p); *p++ = t; | ||
92 | } | ||
93 | while (size -= 8 * 2 * PCM_DEPTH_BYTES); | ||
94 | #endif /* ROCKBOX_LITTLE_ENDIAN */ | ||
95 | (void)p; (void)size; | ||
96 | } | ||
77 | 97 | ||
78 | /* convert unsigned 32 bit value to 80-bit floating point number */ | 98 | /* convert unsigned 32 bit value to 80-bit floating point number */ |
79 | static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) | 99 | static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) |
80 | ICODE_ATTR; | ||
81 | static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) | ||
82 | { | 100 | { |
83 | int32_t exp; | ||
84 | |||
85 | ci->memset(f, 0, 10); | 101 | ci->memset(f, 0, 10); |
86 | 102 | ||
87 | if (l == 0) | 103 | if (l == 0) |
88 | return; | 104 | return; |
89 | 105 | ||
90 | for (exp = 30; (l & (1ul << 31)) == 0; exp--) | 106 | int shift = __builtin_clz(l); |
91 | l <<= 1; | ||
92 | 107 | ||
93 | /* sign always zero - bit 79 */ | 108 | /* sign always zero - bit 79 */ |
94 | /* exponent is 0-31 (normalized: 31 - shift + 16383) - bits 64-78 */ | 109 | /* exponent is 0-31 (normalized: 30 - shift + 16383) - bits 64-78 */ |
95 | f[0] = 0x40; | 110 | f[0] = 0x40; |
96 | f[1] = (uint8_t)exp; | 111 | f[1] = (uint8_t)(30 - shift); |
97 | /* mantissa is value left justified with most significant non-zero | 112 | /* mantissa is value left justified with most significant non-zero |
98 | bit stored in bit 63 - bits 0-63 */ | 113 | bit stored in bit 63 - bits 0-63 */ |
114 | l <<= shift; | ||
99 | f[2] = (uint8_t)(l >> 24); | 115 | f[2] = (uint8_t)(l >> 24); |
100 | f[3] = (uint8_t)(l >> 16); | 116 | f[3] = (uint8_t)(l >> 16); |
101 | f[4] = (uint8_t)(l >> 8); | 117 | f[4] = (uint8_t)(l >> 8); |
102 | f[5] = (uint8_t)(l >> 0); | 118 | f[5] = (uint8_t)(l >> 0); |
103 | } /* uint32_h_to_ieee754_extended_be */ | 119 | } |
104 | |||
105 | /* called version often - inline */ | ||
106 | static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; | ||
107 | static inline bool is_file_data_ok(struct enc_file_event_data *data) | ||
108 | { | ||
109 | return data->rec_file >= 0 && (long)data->chunk->flags >= 0; | ||
110 | } /* is_file_data_ok */ | ||
111 | 120 | ||
112 | /* called version often - inline */ | 121 | static int on_stream_data(struct enc_chunk_data *data) |
113 | static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; | ||
114 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
115 | { | 122 | { |
116 | if (!is_file_data_ok(data)) | 123 | size_t size = data->hdr.size; |
117 | return false; | ||
118 | 124 | ||
119 | if (data->chunk->enc_data == NULL) | 125 | if (ci->enc_stream_write(data->data, size) != (ssize_t)size) |
120 | { | 126 | return -1; |
121 | #ifdef ROCKBOX_HAS_LOGF | ||
122 | ci->logf("aiff enc: NULL data"); | ||
123 | #endif | ||
124 | return true; | ||
125 | } | ||
126 | 127 | ||
127 | if (ci->write(data->rec_file, data->chunk->enc_data, | 128 | pcm_size += size; |
128 | data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) | 129 | num_sample_frames += data->pcm_count; |
129 | return false; | ||
130 | 130 | ||
131 | data->num_pcm_samples += data->chunk->num_pcm; | 131 | return 0; |
132 | return true; | 132 | } |
133 | } /* on_write_chunk */ | ||
134 | 133 | ||
135 | static bool on_start_file(struct enc_file_event_data *data) | 134 | static int on_stream_start(void) |
136 | { | 135 | { |
137 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | ||
138 | return false; | ||
139 | |||
140 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); | ||
141 | |||
142 | if (data->rec_file < 0) | ||
143 | return false; | ||
144 | |||
145 | /* reset sample count */ | 136 | /* reset sample count */ |
146 | data->num_pcm_samples = 0; | 137 | pcm_size = 0; |
138 | num_sample_frames = 0; | ||
147 | 139 | ||
148 | /* write template headers */ | 140 | /* write template header */ |
149 | if (ci->write(data->rec_file, &aiff_header, sizeof (aiff_header)) | 141 | if (ci->enc_stream_write(&aiff_template_header, |
150 | != sizeof (aiff_header)) | 142 | sizeof (struct aiff_header)) |
151 | { | 143 | != sizeof (struct aiff_header)) |
152 | return false; | 144 | return -1; |
153 | } | ||
154 | 145 | ||
155 | data->new_enc_size += sizeof(aiff_header); | 146 | return 0; |
156 | return true; | 147 | } |
157 | } /* on_start_file */ | ||
158 | 148 | ||
159 | static bool on_end_file(struct enc_file_event_data *data) | 149 | static int on_stream_end(union enc_chunk_hdr *hdr) |
160 | { | 150 | { |
161 | /* update template headers */ | 151 | /* update template header */ |
162 | struct aiff_header hdr; | 152 | struct aiff_header aiff; |
163 | uint32_t data_size; | ||
164 | 153 | ||
165 | if (!is_file_data_ok(data)) | 154 | if (hdr->err) |
166 | return false; | ||
167 | |||
168 | if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || | ||
169 | ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr)) | ||
170 | { | 155 | { |
171 | return false; | 156 | /* Called for stream error; get correct data size */ |
157 | ssize_t size = ci->enc_stream_lseek(0, SEEK_END); | ||
158 | |||
159 | if (size > (ssize_t)sizeof (aiff)) | ||
160 | { | ||
161 | pcm_size = size - sizeof (aiff); | ||
162 | num_sample_frames = pcm_size / (PCM_DEPTH_BYTES*num_channels); | ||
163 | } | ||
172 | } | 164 | } |
173 | 165 | ||
174 | data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES; | 166 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0) |
167 | return -1; | ||
168 | |||
169 | if (ci->enc_stream_read(&aiff, sizeof (aiff)) != sizeof (aiff)) | ||
170 | return -2; | ||
175 | 171 | ||
176 | /* 'FORM' chunk */ | 172 | /* 'FORM' chunk */ |
177 | hdr.form_size = htobe32(data_size + sizeof (hdr) - 8); | 173 | aiff.form_size = htobe32(pcm_size + sizeof (aiff) - 8); |
178 | 174 | ||
179 | /* 'COMM' chunk */ | 175 | /* 'COMM' chunk */ |
180 | hdr.num_channels = htobe16(num_channels); | 176 | aiff.num_channels = htobe16(num_channels); |
181 | hdr.num_sample_frames = htobe32(data->num_pcm_samples); | 177 | aiff.num_sample_frames = htobe32(num_sample_frames); |
182 | uint32_h_to_ieee754_extended_be(hdr.sample_rate, sample_rate); | 178 | uint32_h_to_ieee754_extended_be(aiff.sample_rate, sample_rate); |
183 | 179 | ||
184 | /* 'SSND' chunk */ | 180 | /* 'SSND' chunk */ |
185 | hdr.ssnd_size = htobe32(data_size + 8); | 181 | aiff.ssnd_size = htobe32(pcm_size + 8); |
186 | 182 | ||
187 | if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || | 183 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0) |
188 | ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr) || | 184 | return -3; |
189 | ci->close(data->rec_file) != 0) | ||
190 | { | ||
191 | return false; | ||
192 | } | ||
193 | 185 | ||
194 | data->rec_file = -1; | 186 | if (ci->enc_stream_write(&aiff, sizeof (aiff)) != sizeof (aiff)) |
187 | return -4; | ||
195 | 188 | ||
196 | return true; | 189 | return 0; |
197 | } /* on_end_file */ | 190 | } |
198 | 191 | ||
199 | static void enc_events_callback(enum enc_events event, void *data) | 192 | /* this is the codec entry point */ |
200 | ICODE_ATTR; | 193 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
201 | static void enc_events_callback(enum enc_events event, void *data) | ||
202 | { | 194 | { |
203 | switch (event) | 195 | return CODEC_OK; |
204 | { | 196 | (void)reason; |
205 | case ENC_WRITE_CHUNK: | 197 | } |
206 | if (on_write_chunk((struct enc_file_event_data *)data)) | ||
207 | return; | ||
208 | |||
209 | break; | ||
210 | |||
211 | case ENC_START_FILE: | ||
212 | if (on_start_file((struct enc_file_event_data *)data)) | ||
213 | return; | ||
214 | |||
215 | break; | ||
216 | |||
217 | case ENC_END_FILE: | ||
218 | if (on_end_file((struct enc_file_event_data *)data)) | ||
219 | return; | ||
220 | |||
221 | break; | ||
222 | |||
223 | default: | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | /* Something failed above. Signal error back to core. */ | ||
228 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | ||
229 | } /* enc_events_callback */ | ||
230 | 198 | ||
231 | /* convert native pcm samples to aiff format samples */ | 199 | /* this is called for each file to process */ |
232 | static inline void sample_to_mono(uint32_t **src, uint32_t **dst) | 200 | enum codec_status ICODE_ATTR codec_run(void) |
233 | { | 201 | { |
234 | int32_t lr1, lr2; | 202 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; |
203 | struct enc_chunk_data *data = NULL; | ||
235 | 204 | ||
236 | switch(rec_mono_mode) | 205 | /* main encoding loop */ |
206 | while (1) | ||
237 | { | 207 | { |
238 | case 1: | 208 | enum codec_command_action action = ci->get_command(NULL); |
239 | /* mono = L */ | 209 | |
240 | lr1 = *(*src)++; | 210 | if (action != CODEC_ACTION_NULL) |
241 | lr1 = lr1 >> 16; | ||
242 | lr2 = *(*src)++; | ||
243 | lr2 = lr2 >> 16; | ||
244 | break; | ||
245 | case 2: | ||
246 | /* mono = R */ | ||
247 | lr1 = *(*src)++; | ||
248 | lr1 = (int16_t)lr1; | ||
249 | lr2 = *(*src)++; | ||
250 | lr2 = (int16_t)lr2; | ||
251 | break; | ||
252 | case 0: | ||
253 | default: | ||
254 | /* mono = (L+R)/2 */ | ||
255 | lr1 = *(*src)++; | ||
256 | lr1 = (int16_t)lr1 + (lr1 >> 16) + err; | ||
257 | err = lr1 & 1; | ||
258 | lr1 >>= 1; | ||
259 | |||
260 | lr2 = *(*src)++; | ||
261 | lr2 = (int16_t)lr2 + (lr2 >> 16) + err; | ||
262 | err = lr2 & 1; | ||
263 | lr2 >>= 1; | ||
264 | break; | 211 | break; |
265 | } | ||
266 | *(*dst)++ = htobe32((lr1 << 16) | (uint16_t)lr2); | ||
267 | } /* sample_to_mono */ | ||
268 | 212 | ||
269 | static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; | 213 | /* First obtain output buffer; when available, get PCM data */ |
270 | static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) | 214 | switch (getbuf) |
271 | { | ||
272 | if (num_channels == 1) | ||
273 | { | ||
274 | /* On big endian: | ||
275 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| | ||
276 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => | ||
277 | * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm| | ||
278 | * | ||
279 | * On little endian: | ||
280 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| | ||
281 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => | ||
282 | * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm| | ||
283 | */ | ||
284 | uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; | ||
285 | |||
286 | do | ||
287 | { | ||
288 | sample_to_mono(&src, &dst); | ||
289 | sample_to_mono(&src, &dst); | ||
290 | sample_to_mono(&src, &dst); | ||
291 | sample_to_mono(&src, &dst); | ||
292 | sample_to_mono(&src, &dst); | ||
293 | sample_to_mono(&src, &dst); | ||
294 | sample_to_mono(&src, &dst); | ||
295 | sample_to_mono(&src, &dst); | ||
296 | } | ||
297 | while (src < src_end); | ||
298 | } | ||
299 | else | ||
300 | { | ||
301 | #ifdef ROCKBOX_BIG_ENDIAN | ||
302 | /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => | ||
303 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| | ||
304 | */ | ||
305 | ci->memcpy(dst, src, PCM_CHUNK_SIZE); | ||
306 | #else | ||
307 | /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => | ||
308 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| | ||
309 | */ | ||
310 | uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; | ||
311 | |||
312 | do | ||
313 | { | 215 | { |
314 | *dst++ = swap_odd_even32(*src++); | 216 | case GETBUF_ENC: |
315 | *dst++ = swap_odd_even32(*src++); | 217 | if (!(data = ci->enc_encbuf_get_buffer(frame_size))) |
316 | *dst++ = swap_odd_even32(*src++); | 218 | continue; |
317 | *dst++ = swap_odd_even32(*src++); | 219 | getbuf = GETBUF_PCM; |
318 | *dst++ = swap_odd_even32(*src++); | 220 | case GETBUF_PCM: |
319 | *dst++ = swap_odd_even32(*src++); | 221 | if (!ci->enc_pcmbuf_read(data->data, PCM_SAMP_PER_CHUNK)) |
320 | *dst++ = swap_odd_even32(*src++); | 222 | continue; |
321 | *dst++ = swap_odd_even32(*src++); | 223 | getbuf = GETBUF_ENC; |
322 | } | 224 | } |
323 | while (src < src_end); | ||
324 | #endif | ||
325 | } | ||
326 | } /* chunk_to_aiff_format */ | ||
327 | 225 | ||
328 | static bool init_encoder(void) | 226 | data->hdr.size = frame_size; |
329 | { | 227 | data->pcm_count = PCM_SAMP_PER_CHUNK; |
330 | struct enc_inputs inputs; | ||
331 | struct enc_parameters params; | ||
332 | |||
333 | if (ci->enc_get_inputs == NULL || | ||
334 | ci->enc_set_parameters == NULL || | ||
335 | ci->enc_get_chunk == NULL || | ||
336 | ci->enc_finish_chunk == NULL || | ||
337 | ci->enc_get_pcm_data == NULL ) | ||
338 | return false; | ||
339 | |||
340 | ci->enc_get_inputs(&inputs); | ||
341 | |||
342 | if (inputs.config->afmt != AFMT_AIFF) | ||
343 | return false; | ||
344 | |||
345 | sample_rate = inputs.sample_rate; | ||
346 | num_channels = inputs.num_channels; | ||
347 | rec_mono_mode = inputs.rec_mono_mode; | ||
348 | err = 0; | ||
349 | |||
350 | /* configure the buffer system */ | ||
351 | params.afmt = AFMT_AIFF; | ||
352 | enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; | ||
353 | params.chunk_size = enc_size; | ||
354 | params.enc_sample_rate = sample_rate; | ||
355 | params.reserve_bytes = 0; | ||
356 | params.events_callback = enc_events_callback; | ||
357 | ci->enc_set_parameters(¶ms); | ||
358 | |||
359 | return true; | ||
360 | } /* init_encoder */ | ||
361 | 228 | ||
362 | /* this is the codec entry point */ | 229 | frame_htobe((uint32_t *)data->data, frame_size); |
363 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 230 | |
364 | { | 231 | ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); |
365 | if (reason == CODEC_LOAD) { | 232 | ci->enc_encbuf_finish_buffer(); |
366 | if (!init_encoder()) | ||
367 | return CODEC_ERROR; | ||
368 | } | ||
369 | else if (reason == CODEC_UNLOAD) { | ||
370 | /* reset parameters to initial state */ | ||
371 | ci->enc_set_parameters(NULL); | ||
372 | } | 233 | } |
373 | 234 | ||
374 | return CODEC_OK; | 235 | return CODEC_OK; |
375 | } | 236 | } |
376 | 237 | ||
377 | /* this is called for each file to process */ | 238 | /* this is called by recording system */ |
378 | enum codec_status codec_run(void) | 239 | int ICODE_ATTR enc_callback(enum enc_callback_reason reason, |
240 | void *params) | ||
379 | { | 241 | { |
380 | /* main encoding loop */ | 242 | if (LIKELY(reason == ENC_CB_STREAM)) |
381 | while (ci->get_command(NULL) != CODEC_ACTION_HALT) | ||
382 | { | 243 | { |
383 | uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); | 244 | switch (((union enc_chunk_hdr *)params)->type) |
384 | struct enc_chunk_hdr *chunk; | 245 | { |
385 | 246 | case CHUNK_T_DATA: | |
386 | if (src == NULL) | 247 | return on_stream_data(params); |
387 | continue; | 248 | case CHUNK_T_STREAM_START: |
388 | 249 | return on_stream_start(); | |
389 | chunk = ci->enc_get_chunk(); | 250 | case CHUNK_T_STREAM_END: |
390 | chunk->enc_size = enc_size; | 251 | return on_stream_end(params); |
391 | chunk->num_pcm = PCM_SAMP_PER_CHUNK; | 252 | } |
392 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | 253 | } |
393 | 254 | else if (reason == ENC_CB_INPUTS) | |
394 | chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data); | 255 | { |
395 | 256 | struct enc_inputs *inputs = params; | |
396 | ci->enc_finish_chunk(); | 257 | sample_rate = inputs->sample_rate; |
258 | num_channels = inputs->num_channels; | ||
259 | frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; | ||
397 | } | 260 | } |
398 | 261 | ||
399 | return CODEC_OK; | 262 | return 0; |
400 | } | 263 | } |
diff --git a/lib/rbcodec/codecs/codecs.h b/lib/rbcodec/codecs/codecs.h index ae4233b7a6..672b1ded53 100644 --- a/lib/rbcodec/codecs/codecs.h +++ b/lib/rbcodec/codecs/codecs.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #endif | 36 | #endif |
37 | #if (CONFIG_CODEC == SWCODEC) | 37 | #if (CONFIG_CODEC == SWCODEC) |
38 | #ifdef HAVE_RECORDING | 38 | #ifdef HAVE_RECORDING |
39 | #include "pcm_record.h" | 39 | #include "enc_base.h" |
40 | #endif | 40 | #endif |
41 | #include "dsp_core.h" | 41 | #include "dsp_core.h" |
42 | #include "dsp_misc.h" | 42 | #include "dsp_misc.h" |
@@ -72,12 +72,12 @@ | |||
72 | #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ | 72 | #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ |
73 | 73 | ||
74 | /* increase this every time the api struct changes */ | 74 | /* increase this every time the api struct changes */ |
75 | #define CODEC_API_VERSION 45 | 75 | #define CODEC_API_VERSION 46 |
76 | 76 | ||
77 | /* update this to latest version if a change to the api struct breaks | 77 | /* update this to latest version if a change to the api struct breaks |
78 | backwards compatibility (and please take the opportunity to sort in any | 78 | backwards compatibility (and please take the opportunity to sort in any |
79 | new function which are "waiting" at the end of the function table) */ | 79 | new function which are "waiting" at the end of the function table) */ |
80 | #define CODEC_MIN_API_VERSION 45 | 80 | #define CODEC_MIN_API_VERSION 46 |
81 | 81 | ||
82 | /* reasons for calling codec main entrypoint */ | 82 | /* reasons for calling codec main entrypoint */ |
83 | enum codec_entry_call_reason { | 83 | enum codec_entry_call_reason { |
@@ -96,6 +96,9 @@ enum codec_command_action { | |||
96 | CODEC_ACTION_HALT = -1, | 96 | CODEC_ACTION_HALT = -1, |
97 | CODEC_ACTION_NULL = 0, | 97 | CODEC_ACTION_NULL = 0, |
98 | CODEC_ACTION_SEEK_TIME = 1, | 98 | CODEC_ACTION_SEEK_TIME = 1, |
99 | #ifdef HAVE_RECORDING | ||
100 | CODEC_ACTION_STREAM_FINISH = 2, | ||
101 | #endif | ||
99 | }; | 102 | }; |
100 | 103 | ||
101 | /* NOTE: To support backwards compatibility, only add new functions at | 104 | /* NOTE: To support backwards compatibility, only add new functions at |
@@ -200,24 +203,18 @@ struct codec_api { | |||
200 | #endif | 203 | #endif |
201 | 204 | ||
202 | #ifdef HAVE_RECORDING | 205 | #ifdef HAVE_RECORDING |
203 | void (*enc_get_inputs)(struct enc_inputs *inputs); | 206 | int (*enc_pcmbuf_read)(void *buf, int count); |
204 | void (*enc_set_parameters)(struct enc_parameters *params); | 207 | int (*enc_pcmbuf_advance)(int count); |
205 | struct enc_chunk_hdr * (*enc_get_chunk)(void); | 208 | struct enc_chunk_data * (*enc_encbuf_get_buffer)(size_t need); |
206 | void (*enc_finish_chunk)(void); | 209 | void (*enc_encbuf_finish_buffer)(void); |
207 | unsigned char * (*enc_get_pcm_data)(size_t size); | 210 | ssize_t (*enc_stream_read)(void *buf, size_t count); |
208 | size_t (*enc_unget_pcm_data)(size_t size); | 211 | off_t (*enc_stream_lseek)(off_t offset, int whence); |
209 | 212 | ssize_t (*enc_stream_write)(const void *buf, size_t count); | |
210 | /* file */ | ||
211 | int (*open)(const char* pathname, int flags, ...); | ||
212 | int (*close)(int fd); | ||
213 | ssize_t (*read)(int fd, void* buf, size_t count); | ||
214 | off_t (*lseek)(int fd, off_t offset, int whence); | ||
215 | ssize_t (*write)(int fd, const void* buf, size_t count); | ||
216 | int (*round_value_to_list32)(unsigned long value, | 213 | int (*round_value_to_list32)(unsigned long value, |
217 | const unsigned long list[], | 214 | const unsigned long list[], |
218 | int count, | 215 | int count, |
219 | bool signd); | 216 | bool signd); |
220 | #endif | 217 | #endif /* HAVE_RECORDING */ |
221 | 218 | ||
222 | /* new stuff at the end, sort into place next time | 219 | /* new stuff at the end, sort into place next time |
223 | the API gets incompatible */ | 220 | the API gets incompatible */ |
@@ -229,6 +226,7 @@ struct codec_header { | |||
229 | enum codec_status(*entry_point)(enum codec_entry_call_reason reason); | 226 | enum codec_status(*entry_point)(enum codec_entry_call_reason reason); |
230 | enum codec_status(*run_proc)(void); | 227 | enum codec_status(*run_proc)(void); |
231 | struct codec_api **api; | 228 | struct codec_api **api; |
229 | void * rec_extension[]; /* extension for encoders */ | ||
232 | }; | 230 | }; |
233 | 231 | ||
234 | #ifdef CODEC | 232 | #ifdef CODEC |
@@ -249,7 +247,7 @@ extern unsigned char plugin_end_addr[]; | |||
249 | __attribute__ ((section (".header")))= { \ | 247 | __attribute__ ((section (".header")))= { \ |
250 | { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ | 248 | { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ |
251 | plugin_start_addr, plugin_end_addr }, codec_start, \ | 249 | plugin_start_addr, plugin_end_addr }, codec_start, \ |
252 | codec_run, &ci }; | 250 | codec_run, &ci, { enc_callback } }; |
253 | 251 | ||
254 | #else /* def SIMULATOR */ | 252 | #else /* def SIMULATOR */ |
255 | /* decoders */ | 253 | /* decoders */ |
@@ -262,7 +260,7 @@ extern unsigned char plugin_end_addr[]; | |||
262 | #define CODEC_ENC_HEADER \ | 260 | #define CODEC_ENC_HEADER \ |
263 | const struct codec_header __header = { \ | 261 | const struct codec_header __header = { \ |
264 | { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ | 262 | { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ |
265 | codec_start, codec_run, &ci }; | 263 | codec_start, codec_run, &ci, { enc_callback } }; |
266 | #endif /* SIMULATOR */ | 264 | #endif /* SIMULATOR */ |
267 | #endif /* CODEC */ | 265 | #endif /* CODEC */ |
268 | 266 | ||
@@ -277,12 +275,19 @@ void *codec_get_buffer_callback(size_t *size); | |||
277 | int codec_load_buf(int hid, struct codec_api *api); | 275 | int codec_load_buf(int hid, struct codec_api *api); |
278 | int codec_load_file(const char* codec, struct codec_api *api); | 276 | int codec_load_file(const char* codec, struct codec_api *api); |
279 | int codec_run_proc(void); | 277 | int codec_run_proc(void); |
280 | int codec_halt(void); | ||
281 | int codec_close(void); | 278 | int codec_close(void); |
279 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) | ||
280 | enc_callback_t codec_get_enc_callback(void); | ||
281 | #else | ||
282 | #define codec_get_enc_callback() NULL | ||
283 | #endif | ||
282 | 284 | ||
283 | /* defined by the codec */ | 285 | /* defined by the codec */ |
284 | enum codec_status codec_start(enum codec_entry_call_reason reason); | 286 | enum codec_status codec_start(enum codec_entry_call_reason reason); |
285 | enum codec_status codec_main(enum codec_entry_call_reason reason); | 287 | enum codec_status codec_main(enum codec_entry_call_reason reason); |
286 | enum codec_status codec_run(void); | 288 | enum codec_status codec_run(void); |
289 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) | ||
290 | int enc_callback(enum enc_callback_reason reason, void *params); | ||
291 | #endif | ||
287 | 292 | ||
288 | #endif /* _CODECS_H_ */ | 293 | #endif /* _CODECS_H_ */ |
diff --git a/lib/rbcodec/codecs/mp3_enc.c b/lib/rbcodec/codecs/mp3_enc.c index 000eedd849..a349f99f25 100644 --- a/lib/rbcodec/codecs/mp3_enc.c +++ b/lib/rbcodec/codecs/mp3_enc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Antonius Hellmann | 10 | * Copyright (C) 2006 Antonius Hellmann |
11 | * Copyright (C) 2006-2013 Michael Sevakis | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -37,17 +38,9 @@ | |||
37 | 38 | ||
38 | CODEC_ENC_HEADER | 39 | CODEC_ENC_HEADER |
39 | 40 | ||
40 | #define ENC_PADDING_FRAMES1 2 | 41 | #define SAMPL2 576 |
41 | #define ENC_PADDING_FRAMES2 4 | 42 | #define SBLIMIT 32 |
42 | #define ENC_DELAY_SAMP 576 | 43 | #define HTN 16 |
43 | #define ENC_DELAY_SIZE (ENC_DELAY_SAMP*4) | ||
44 | #define SAMP_PER_FRAME1 1152 | ||
45 | #define SAMP_PER_FRAME2 576 | ||
46 | #define PCM_CHUNK_SIZE1 (SAMP_PER_FRAME1*4) | ||
47 | #define PCM_CHUNK_SIZE2 (SAMP_PER_FRAME2*4) | ||
48 | #define SAMPL2 576 | ||
49 | #define SBLIMIT 32 | ||
50 | #define HTN 16 | ||
51 | #define memcpy ci->memcpy | 44 | #define memcpy ci->memcpy |
52 | #define memset ci->memset | 45 | #define memset ci->memset |
53 | #define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ | 46 | #define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ |
@@ -79,18 +72,24 @@ typedef struct { | |||
79 | } side_info_t; | 72 | } side_info_t; |
80 | 73 | ||
81 | typedef struct { | 74 | typedef struct { |
82 | side_info_t cod_info[2][2]; | 75 | side_info_t cod_info[2][2]; |
83 | mpeg_t mpg; | 76 | mpeg_t mpg; |
84 | long frac_per_frame; | 77 | long frac_per_frame; |
85 | long byte_per_frame; | 78 | long byte_per_frame; |
86 | long slot_lag; | 79 | long req_byte_per_frame; |
87 | int sideinfo_len; | 80 | long slot_lag; |
88 | int mean_bits; | 81 | int sideinfo_len; |
89 | int ResvSize; | 82 | int mean_bits; |
90 | int channels; | 83 | int ResvSize; |
91 | int rec_mono_mode; | 84 | int channels; |
92 | int granules; | 85 | int granules; |
93 | long samplerate; | 86 | long src_samplerate; |
87 | long samplerate; | ||
88 | short *samp_buffer; | ||
89 | unsigned samp_per_frame; | ||
90 | int flush_frames; | ||
91 | int delay; | ||
92 | int padding; | ||
94 | } config_t; | 93 | } config_t; |
95 | 94 | ||
96 | typedef struct { | 95 | typedef struct { |
@@ -118,7 +117,8 @@ struct huffcodebig { | |||
118 | #define shft_n(x,n) ((x) >> n) | 117 | #define shft_n(x,n) ((x) >> n) |
119 | #define SQRT 724 /* sqrt(2) * 512 */ | 118 | #define SQRT 724 /* sqrt(2) * 512 */ |
120 | 119 | ||
121 | static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ | 120 | static short mfbuf [2*(1152+512)] IBSS_ATTR |
121 | /* for memcpy and 32-bit access */ MEM_ALIGN_ATTR; /* 3328 Bytes */ | ||
122 | static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ | 122 | static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ |
123 | static int mdct_freq [SAMPL2] IBSS_ATTR; /* 2304 Bytes */ | 123 | static int mdct_freq [SAMPL2] IBSS_ATTR; /* 2304 Bytes */ |
124 | static char mdct_sign [SAMPL2] IBSS_ATTR; /* 576 Bytes */ | 124 | static char mdct_sign [SAMPL2] IBSS_ATTR; /* 576 Bytes */ |
@@ -171,12 +171,7 @@ static uint8_t t16l [256] IBSS_ATTR; | |||
171 | static uint8_t t24l [256] IBSS_ATTR; | 171 | static uint8_t t24l [256] IBSS_ATTR; |
172 | static struct huffcodetab ht [HTN] IBSS_ATTR; | 172 | static struct huffcodetab ht [HTN] IBSS_ATTR; |
173 | 173 | ||
174 | static unsigned pcm_chunk_size IBSS_ATTR; | ||
175 | static unsigned samp_per_frame IBSS_ATTR; | ||
176 | |||
177 | static config_t cfg IBSS_ATTR; | 174 | static config_t cfg IBSS_ATTR; |
178 | static char *res_buffer; | ||
179 | static int32_t err IBSS_ATTR; | ||
180 | static uint8_t band_scale_f[22]; | 175 | static uint8_t band_scale_f[22]; |
181 | 176 | ||
182 | static const uint8_t ht_count_const[2][2][16] = | 177 | static const uint8_t ht_count_const[2][2][16] = |
@@ -848,42 +843,56 @@ static int count_bit1 ( short *ix, uint32_t start, uint32_t end, int *bits ); | |||
848 | static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, | 843 | static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, |
849 | int *bits); | 844 | int *bits); |
850 | 845 | ||
846 | static inline uint32_t encodeHeader( int padding, long bitr_id ) | ||
847 | { | ||
848 | /* | ||
849 | * MPEG header layout: | ||
850 | * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM | ||
851 | * A (31-21) = frame sync | ||
852 | * B (20-19) = MPEG type | ||
853 | * C (18-17) = MPEG layer | ||
854 | * D (16) = protection bit | ||
855 | * E (15-12) = bitrate index | ||
856 | * F (11-10) = samplerate index | ||
857 | * G (9) = padding bit | ||
858 | * H (8) = private bit | ||
859 | * I (7-6) = channel mode | ||
860 | * J (5-4) = mode extension (jstereo only) | ||
861 | * K (3) = copyright bit | ||
862 | * L (2) = original | ||
863 | * M (1-0) = emphasis | ||
864 | */ | ||
865 | return (0xffe00000 ) /* frame sync (AAAAAAAAA AAA) */ | ||
866 | | (0x2 << 19) /* mp3 type (upper): 1 (BB) */ | ||
867 | | (cfg.mpg.type << 19) | ||
868 | | (0x1 << 17) /* mp3 layer: 01 (CC) */ | ||
869 | | (0x1 << 16) /* mp3 crc: 1 (D) */ | ||
870 | | (bitr_id << 12) | ||
871 | | (cfg.mpg.smpl_id << 10) | ||
872 | | (padding << 9) | ||
873 | | (cfg.mpg.mode << 6) | ||
874 | | (0x1 << 2); /* mp3 org: 1 (L) */ | ||
875 | /* no emphasis (bits 0-1) */ | ||
876 | } | ||
877 | |||
878 | static long calcFrameSize(int bitr_id, long *frac) | ||
879 | { | ||
880 | unsigned long v = bitr_index[cfg.mpg.type][bitr_id]; | ||
881 | v = SAMPL2 * 16000 * v / (2 - cfg.mpg.type); | ||
882 | v /= cfg.samplerate; | ||
883 | |||
884 | if (frac) | ||
885 | *frac = v % 64; | ||
886 | |||
887 | return v / 64; | ||
851 | 888 | ||
889 | } | ||
852 | static void encodeSideInfo( side_info_t si[2][2] ) | 890 | static void encodeSideInfo( side_info_t si[2][2] ) |
853 | { | 891 | { |
854 | int gr, ch, header; | 892 | int gr, ch; |
855 | uint32_t cc=0, sz=0; | 893 | uint32_t cc=0, sz=0; |
856 | 894 | ||
857 | /* | 895 | putbits( encodeHeader( cfg.mpg.padding, cfg.mpg.bitr_id ), 32 ); |
858 | * MPEG header layout: | ||
859 | * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM | ||
860 | * A (31-21) = frame sync | ||
861 | * B (20-19) = MPEG type | ||
862 | * C (18-17) = MPEG layer | ||
863 | * D (16) = protection bit | ||
864 | * E (15-12) = bitrate index | ||
865 | * F (11-10) = samplerate index | ||
866 | * G (9) = padding bit | ||
867 | * H (8) = private bit | ||
868 | * I (7-6) = channel mode | ||
869 | * J (5-4) = mode extension (jstereo only) | ||
870 | * K (3) = copyright bit | ||
871 | * L (2) = original | ||
872 | * M (1-0) = emphasis | ||
873 | */ | ||
874 | |||
875 | header = (0xfff00000) | /* frame sync (AAAAAAAAA AAA) | ||
876 | mp3 type (upper): 1 (B) */ | ||
877 | (0x01 << 17) | /* mp3 layer: 01 (CC) */ | ||
878 | ( 0x1 << 16) | /* mp3 crc: 1 (D) */ | ||
879 | ( 0x1 << 2); /* mp3 org: 1 (L) */ | ||
880 | header |= cfg.mpg.type << 19; | ||
881 | header |= cfg.mpg.bitr_id << 12; | ||
882 | header |= cfg.mpg.smpl_id << 10; | ||
883 | header |= cfg.mpg.padding << 9; | ||
884 | header |= cfg.mpg.mode << 6; | ||
885 | /* no emphasis (bits 0-1) */ | ||
886 | putbits( header, 32 ); | ||
887 | 896 | ||
888 | if(cfg.mpg.type == 1) | 897 | if(cfg.mpg.type == 1) |
889 | { /* MPEG1 */ | 898 | { /* MPEG1 */ |
@@ -1501,8 +1510,8 @@ static void iteration_loop(int *xr, side_info_t *si, int gr_cnt) | |||
1501 | 1510 | ||
1502 | 1511 | ||
1503 | /* returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 */ | 1512 | /* returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 */ |
1504 | void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) ICODE_ATTR; | 1513 | static void ICODE_ATTR window_subband1(short *wk, int sb0[SBLIMIT], |
1505 | void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) | 1514 | int sb1[SBLIMIT]) |
1506 | { | 1515 | { |
1507 | int k, i, u, v; | 1516 | int k, i, u, v; |
1508 | short *wp, *x1, *x2; | 1517 | short *wp, *x1, *x2; |
@@ -1761,8 +1770,7 @@ void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) | |||
1761 | #endif | 1770 | #endif |
1762 | } | 1771 | } |
1763 | 1772 | ||
1764 | void window_subband2(short *x1, int a[SBLIMIT]) ICODE_ATTR; | 1773 | static void ICODE_ATTR window_subband2(short *x1, int a[SBLIMIT]) |
1765 | void window_subband2(short *x1, int a[SBLIMIT]) | ||
1766 | { | 1774 | { |
1767 | int xr; | 1775 | int xr; |
1768 | short *wp = enwindow; | 1776 | short *wp = enwindow; |
@@ -1879,8 +1887,7 @@ void window_subband2(short *x1, int a[SBLIMIT]) | |||
1879 | xr = a[29]; a[29] += a[ 2]; a[ 2] -= xr; | 1887 | xr = a[29]; a[29] += a[ 2]; a[ 2] -= xr; |
1880 | } | 1888 | } |
1881 | 1889 | ||
1882 | void mdct_long(int *out, int *in) ICODE_ATTR; | 1890 | static void ICODE_ATTR mdct_long(int *out, int *in) |
1883 | void mdct_long(int *out, int *in) | ||
1884 | { | 1891 | { |
1885 | int ct,st; | 1892 | int ct,st; |
1886 | int tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; | 1893 | int tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; |
@@ -1969,44 +1976,51 @@ static int find_samplerate_index(long freq, int *mp3_type) | |||
1969 | return i; | 1976 | return i; |
1970 | } | 1977 | } |
1971 | 1978 | ||
1972 | static bool init_mp3_encoder_engine(int sample_rate, | 1979 | static void mp3_encoder_reset(void) |
1973 | int num_channels, | 1980 | { |
1974 | int rec_mono_mode, | 1981 | memset(&cfg.cod_info, 0, sizeof(cfg.cod_info)); |
1975 | struct encoder_config *enc_cfg) | 1982 | memset(mfbuf , 0, sizeof(mfbuf )); |
1983 | memset(mdct_freq , 0, sizeof(mdct_freq )); | ||
1984 | memset(enc_data , 0, sizeof(enc_data )); | ||
1985 | memset(sb_data , 0, sizeof(sb_data )); | ||
1986 | memset(&CodedData , 0, sizeof(CodedData )); | ||
1987 | cfg.slot_lag = 0; | ||
1988 | } | ||
1989 | |||
1990 | static void mp3_encoder_init(unsigned long sample_rate, int num_channels, | ||
1991 | unsigned long bitrate) | ||
1976 | { | 1992 | { |
1977 | const bool stereo = num_channels > 1; | 1993 | mp3_encoder_reset(); |
1978 | uint32_t avg_byte_per_frame; | 1994 | |
1979 | 1995 | const bool stereo = num_channels > 1; | |
1980 | cfg.channels = stereo ? 2 : 1; | 1996 | cfg.channels = stereo ? 2 : 1; |
1981 | cfg.rec_mono_mode = rec_mono_mode; | 1997 | cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ |
1982 | cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ | 1998 | cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); |
1983 | cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); | 1999 | cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; |
1984 | cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; | 2000 | cfg.src_samplerate = sample_rate; |
1985 | cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, | 2001 | cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, bitrate, stereo); |
1986 | enc_cfg->mp3_enc.bitrate, | 2002 | cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; |
1987 | stereo); | 2003 | cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; |
1988 | cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; | ||
1989 | cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; | ||
1990 | 2004 | ||
1991 | if (cfg.mpg.type == 1) | 2005 | if (cfg.mpg.type == 1) |
1992 | { | 2006 | { |
1993 | cfg.granules = 2; | 2007 | cfg.granules = 2; |
1994 | pcm_chunk_size = PCM_CHUNK_SIZE1; | 2008 | cfg.samp_per_frame = 1152; |
1995 | samp_per_frame = SAMP_PER_FRAME1; | 2009 | cfg.flush_frames = 2; |
1996 | } | 2010 | } |
1997 | else | 2011 | else |
1998 | { | 2012 | { |
1999 | cfg.granules = 1; | 2013 | cfg.granules = 1; |
2000 | pcm_chunk_size = PCM_CHUNK_SIZE2; | 2014 | cfg.samp_per_frame = 576; |
2001 | samp_per_frame = SAMP_PER_FRAME2; | 2015 | cfg.flush_frames = 3; |
2002 | } | 2016 | } |
2003 | 2017 | ||
2018 | cfg.delay = 576-16; | ||
2019 | cfg.padding = 3*576+16; | ||
2020 | |||
2021 | cfg.samp_buffer = mfbuf + 2*512; | ||
2022 | |||
2004 | memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); | 2023 | memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); |
2005 | memset(mfbuf , 0 , sizeof(mfbuf )); | ||
2006 | memset(mdct_freq , 0 , sizeof(mdct_freq )); | ||
2007 | memset(enc_data , 0 , sizeof(enc_data )); | ||
2008 | memset(sb_data , 0 , sizeof(sb_data )); | ||
2009 | memset(&CodedData, 0 , sizeof(CodedData )); | ||
2010 | memcpy(ca , ca_const , sizeof(ca )); | 2024 | memcpy(ca , ca_const , sizeof(ca )); |
2011 | memcpy(cs , cs_const , sizeof(cs )); | 2025 | memcpy(cs , cs_const , sizeof(cs )); |
2012 | memcpy(cx , cx_const , sizeof(cx )); | 2026 | memcpy(cx , cx_const , sizeof(cx )); |
@@ -2052,6 +2066,7 @@ static bool init_mp3_encoder_engine(int sample_rate, | |||
2052 | memcpy(t16l , t16l_const , sizeof(t16l )); | 2066 | memcpy(t16l , t16l_const , sizeof(t16l )); |
2053 | memcpy(t24l , t24l_const , sizeof(t24l )); | 2067 | memcpy(t24l , t24l_const , sizeof(t24l )); |
2054 | memcpy(ht , ht_const , sizeof(ht )); | 2068 | memcpy(ht , ht_const , sizeof(ht )); |
2069 | memset(band_scale_f, 0 , sizeof(band_scale_f)); | ||
2055 | 2070 | ||
2056 | ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ | 2071 | ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ |
2057 | ht[ 1].table = t1HB; ht[ 1].hlen = t1l; | 2072 | ht[ 1].table = t1HB; ht[ 1].hlen = t1l; |
@@ -2071,90 +2086,14 @@ static bool init_mp3_encoder_engine(int sample_rate, | |||
2071 | ht[15].table = t15HB; ht[15].hlen = t15l; | 2086 | ht[15].table = t15HB; ht[15].hlen = t15l; |
2072 | 2087 | ||
2073 | /* Figure average number of 'bytes' per frame */ | 2088 | /* Figure average number of 'bytes' per frame */ |
2074 | avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); | 2089 | cfg.byte_per_frame = calcFrameSize(cfg.mpg.bitr_id, &cfg.frac_per_frame); |
2075 | avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; | ||
2076 | cfg.byte_per_frame = avg_byte_per_frame / 64; | ||
2077 | cfg.frac_per_frame = avg_byte_per_frame & 63; | ||
2078 | cfg.slot_lag = 0; | ||
2079 | cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) | 2090 | cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) |
2080 | : (cfg.channels == 1 ? 72 : 136)); | 2091 | : (cfg.channels == 1 ? 72 : 136)); |
2081 | 2092 | ||
2082 | return true; | 2093 | cfg.req_byte_per_frame = ALIGN_UP(cfg.byte_per_frame + 1, |
2094 | sizeof (uint32_t)); | ||
2083 | } | 2095 | } |
2084 | 2096 | ||
2085 | static inline void to_mono(uint16_t **samp) | ||
2086 | { | ||
2087 | int16_t l = **samp; | ||
2088 | int16_t r = *(*samp+1); | ||
2089 | int32_t m; | ||
2090 | |||
2091 | switch(cfg.rec_mono_mode) | ||
2092 | { | ||
2093 | case 1: | ||
2094 | /* mono = L */ | ||
2095 | m = l; | ||
2096 | break; | ||
2097 | case 2: | ||
2098 | /* mono = R */ | ||
2099 | m = r; | ||
2100 | break; | ||
2101 | case 0: | ||
2102 | default: | ||
2103 | /* mono = (L+R)/2 */ | ||
2104 | m = l + r + err; | ||
2105 | err = m & 1; | ||
2106 | m >>= 1; | ||
2107 | break; | ||
2108 | } | ||
2109 | *(*samp)++ = (uint16_t)m; | ||
2110 | *(*samp)++ = (uint16_t)m; | ||
2111 | } /* to_mono */ | ||
2112 | |||
2113 | static void to_mono_mm(void) ICODE_ATTR; | ||
2114 | static void to_mono_mm(void) | ||
2115 | { | ||
2116 | /* |llllllllllllllll|rrrrrrrrrrrrrrrr| => | ||
2117 | * |mmmmmmmmmmmmmmmm|mmmmmmmmmmmmmmmm| | ||
2118 | */ | ||
2119 | uint16_t *samp = &mfbuf[2*512]; | ||
2120 | uint16_t *samp_end = samp + 2*samp_per_frame; | ||
2121 | |||
2122 | do | ||
2123 | { | ||
2124 | to_mono(&samp); | ||
2125 | to_mono(&samp); | ||
2126 | to_mono(&samp); | ||
2127 | to_mono(&samp); | ||
2128 | to_mono(&samp); | ||
2129 | to_mono(&samp); | ||
2130 | to_mono(&samp); | ||
2131 | to_mono(&samp); | ||
2132 | } | ||
2133 | while (samp < samp_end); | ||
2134 | } /* to_mono_mm */ | ||
2135 | |||
2136 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
2137 | /* Swaps a frame to big endian */ | ||
2138 | static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, | ||
2139 | size_t size) | ||
2140 | { | ||
2141 | uint32_t *src_end = SKIPBYTES(src, size); | ||
2142 | |||
2143 | do | ||
2144 | { | ||
2145 | *dst++ = swap32(*src++); | ||
2146 | *dst++ = swap32(*src++); | ||
2147 | *dst++ = swap32(*src++); | ||
2148 | *dst++ = swap32(*src++); | ||
2149 | *dst++ = swap32(*src++); | ||
2150 | *dst++ = swap32(*src++); | ||
2151 | *dst++ = swap32(*src++); | ||
2152 | *dst++ = swap32(*src++); | ||
2153 | } | ||
2154 | while(src < src_end); | ||
2155 | } /* byte_swap_frame32 */ | ||
2156 | #endif /* ROCKBOX_LITTLE_ENDIAN */ | ||
2157 | |||
2158 | static void set_scale_facs(int *mdct_freq) | 2097 | static void set_scale_facs(int *mdct_freq) |
2159 | { | 2098 | { |
2160 | unsigned int i, is, ie, k, s; | 2099 | unsigned int i, is, ie, k, s; |
@@ -2188,12 +2127,10 @@ static void set_scale_facs(int *mdct_freq) | |||
2188 | } | 2127 | } |
2189 | } | 2128 | } |
2190 | 2129 | ||
2191 | static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) | 2130 | static size_t ICODE_ATTR mp3_encoder_encode_frame(uint8_t *outbuf) |
2192 | ICODE_ATTR; | ||
2193 | static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) | ||
2194 | { | 2131 | { |
2195 | int gr, gr_cnt; | 2132 | int gr, gr_cnt; |
2196 | uint32_t max; | 2133 | uint32_t max; |
2197 | 2134 | ||
2198 | /* encode one mp3 frame in this loop */ | 2135 | /* encode one mp3 frame in this loop */ |
2199 | CodedData.bitpos = 0; | 2136 | CodedData.bitpos = 0; |
@@ -2211,28 +2148,6 @@ static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) | |||
2211 | - cfg.sideinfo_len) / cfg.granules / cfg.channels | 2148 | - cfg.sideinfo_len) / cfg.granules / cfg.channels |
2212 | - 42; // reserved for scale_facs | 2149 | - 42; // reserved for scale_facs |
2213 | 2150 | ||
2214 | /* shift out old samples */ | ||
2215 | memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); | ||
2216 | |||
2217 | if (chunk->flags & CHUNKF_START_FILE) | ||
2218 | { | ||
2219 | /* prefix silent samples for encoder delay */ | ||
2220 | memset(mfbuf + 2*512, 0, ENC_DELAY_SIZE); | ||
2221 | /* read new samples to iram for further processing */ | ||
2222 | memcpy(mfbuf + 2*512 + ENC_DELAY_SIZE/2, | ||
2223 | buffer, pcm_chunk_size - ENC_DELAY_SIZE); | ||
2224 | chunk->num_pcm = samp_per_frame - ENC_DELAY_SAMP; | ||
2225 | } | ||
2226 | else | ||
2227 | { | ||
2228 | /* read new samples to iram for further processing */ | ||
2229 | memcpy(mfbuf + 2*512, buffer, pcm_chunk_size); | ||
2230 | chunk->num_pcm = samp_per_frame; | ||
2231 | } | ||
2232 | |||
2233 | if (cfg.channels == 1) | ||
2234 | to_mono_mm(); | ||
2235 | |||
2236 | cfg.ResvSize = 0; | 2151 | cfg.ResvSize = 0; |
2237 | gr_cnt = cfg.granules * cfg.channels; | 2152 | gr_cnt = cfg.granules * cfg.channels; |
2238 | CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ | 2153 | CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ |
@@ -2366,264 +2281,398 @@ static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) | |||
2366 | } | 2281 | } |
2367 | } | 2282 | } |
2368 | 2283 | ||
2369 | chunk->enc_size = cfg.byte_per_frame + cfg.mpg.padding; | 2284 | /* shift out old samples */ |
2285 | memmove(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); | ||
2370 | 2286 | ||
2371 | /* finish this chunk by adding sideinfo header data */ | 2287 | /* finish this chunk by adding sideinfo header data */ |
2372 | CodedData.bitpos = 0; | 2288 | CodedData.bitpos = 0; |
2373 | encodeSideInfo( cfg.cod_info ); | 2289 | encodeSideInfo( cfg.cod_info ); |
2374 | 2290 | ||
2375 | #ifdef ROCKBOX_BIG_ENDIAN | 2291 | long size = cfg.byte_per_frame + cfg.mpg.padding; |
2376 | /* copy chunk to enc_buffer */ | 2292 | |
2377 | memcpy(chunk->enc_data, CodedData.bbuf, chunk->enc_size); | 2293 | #ifdef ROCKBOX_LITTLE_ENDIAN |
2294 | /* convert frame to big endian */ | ||
2295 | const uint32_t *src = CodedData.bbuf; | ||
2296 | uint32_t *dst = (uint32_t *)outbuf; | ||
2297 | |||
2298 | for(long i = 0; i < size; i += sizeof(uint32_t)) | ||
2299 | *dst++ = swap32(*src++); | ||
2378 | #else | 2300 | #else |
2379 | /* swap frame to big endian */ | 2301 | memcpy(outbuf, CodedData.bbuf, size); |
2380 | byte_swap_frame32((uint32_t *)chunk->enc_data, CodedData.bbuf, chunk->enc_size); | 2302 | #endif /* ROCKBOX_LITTLE_ENDIAN */ |
2381 | #endif | ||
2382 | } /* encode_frame */ | ||
2383 | 2303 | ||
2384 | /* called very often - inline */ | 2304 | return size; |
2385 | static inline bool is_file_data_ok(struct enc_file_event_data *filed) | 2305 | } |
2386 | { | ||
2387 | return filed->rec_file >= 0 && (long)filed->chunk->flags >= 0; | ||
2388 | } /* is_event_ok */ | ||
2389 | 2306 | ||
2390 | static unsigned char mp3_data[16384] __attribute__((aligned(4))); | ||
2391 | static unsigned int mp3_data_len; /* current data size in buffer */ | ||
2392 | 2307 | ||
2393 | /* called very often - inline */ | 2308 | /*======== Codec section ========*/ |
2394 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
2395 | { | ||
2396 | if (!is_file_data_ok(data)) | ||
2397 | return false; | ||
2398 | 2309 | ||
2399 | if (data->chunk->enc_data == NULL) | 2310 | /* CRC code lovingly ripped from: |
2400 | { | 2311 | * github.com/CFR-maniac/lame/blob/master/libmp3lame/VbrTag.c */ |
2401 | #ifdef ROCKBOX_HAS_LOGF | ||
2402 | ci->logf("mp3 enc: NULL data"); | ||
2403 | #endif | ||
2404 | return true; | ||
2405 | } | ||
2406 | 2312 | ||
2407 | /* if current chunk doesn't fit => write collected data */ | 2313 | /* Lookup table for fast CRC computation |
2408 | if (mp3_data_len + data->chunk->enc_size > sizeof(mp3_data)) | 2314 | * See 'crc_update_lookup' |
2409 | { | 2315 | * Uses the polynomial x^16+x^15+x^2+1 */ |
2410 | if (ci->write(data->rec_file, mp3_data, | 2316 | static const uint16_t crc16_lookup[256] ICONST_ATTR = |
2411 | mp3_data_len) != (ssize_t)mp3_data_len) | 2317 | { |
2412 | return false; | 2318 | 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, |
2319 | 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, | ||
2320 | 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, | ||
2321 | 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, | ||
2322 | 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, | ||
2323 | 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, | ||
2324 | 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, | ||
2325 | 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, | ||
2326 | 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, | ||
2327 | 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, | ||
2328 | 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, | ||
2329 | 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, | ||
2330 | 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, | ||
2331 | 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, | ||
2332 | 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, | ||
2333 | 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, | ||
2334 | 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, | ||
2335 | 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, | ||
2336 | 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, | ||
2337 | 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, | ||
2338 | 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, | ||
2339 | 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, | ||
2340 | 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, | ||
2341 | 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, | ||
2342 | 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, | ||
2343 | 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, | ||
2344 | 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, | ||
2345 | 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, | ||
2346 | 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, | ||
2347 | 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, | ||
2348 | 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, | ||
2349 | 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 | ||
2350 | }; | ||
2413 | 2351 | ||
2414 | mp3_data_len = 0; | 2352 | static ssize_t header_size; |
2415 | } | 2353 | static unsigned int mp3_crc16; |
2416 | 2354 | ||
2417 | memcpy(mp3_data+mp3_data_len, data->chunk->enc_data, | 2355 | /* fast CRC-16 computation - uses table crc16_lookup 8*/ |
2418 | data->chunk->enc_size); | 2356 | static inline unsigned int crc_update_lookup(unsigned int value, |
2357 | unsigned int crc) | ||
2358 | { | ||
2359 | unsigned int tmp = crc ^ value; | ||
2360 | crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff]; | ||
2361 | return crc & 0xffff; | ||
2362 | } | ||
2419 | 2363 | ||
2420 | mp3_data_len += data->chunk->enc_size; | 2364 | /* Calculate position of 'Info' header */ |
2365 | static int get_info_offset(uint32_t header) | ||
2366 | { | ||
2367 | uint32_t type = (header & (0x3 << 19)) >> 19; | ||
2368 | uint32_t mode = (header & (0x3 << 6)) >> 6; | ||
2421 | 2369 | ||
2422 | data->num_pcm_samples += data->chunk->num_pcm; | 2370 | return type == 3 ? (mode == 3 ? 21 : 36) : (mode == 3 ? 13 : 21); |
2423 | return true; | 2371 | } |
2424 | } /* on_write_chunk */ | ||
2425 | 2372 | ||
2426 | static bool on_start_file(struct enc_file_event_data *data) | 2373 | /* Write very basic 'Info' header with delay, padding and a bit of |
2374 | * miscellaneous info. */ | ||
2375 | static bool write_info_header(bool first_encode) | ||
2427 | { | 2376 | { |
2428 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | 2377 | ssize_t size = cfg.byte_per_frame; |
2429 | return false; | ||
2430 | 2378 | ||
2431 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); | 2379 | /* By default the MP3 frame header for the info frame is the same as |
2380 | unpadded audio frames */ | ||
2381 | uint32_t header = encodeHeader(0, cfg.mpg.bitr_id); | ||
2432 | 2382 | ||
2433 | if (data->rec_file < 0) | 2383 | int i = get_info_offset(header); |
2434 | return false; | ||
2435 | 2384 | ||
2436 | /* reset sample count */ | 2385 | if (i + 8 + 36 > size) |
2437 | data->num_pcm_samples = 0; | 2386 | { |
2387 | /* The default frame size too small so find the smallest one that | ||
2388 | may accomodate it by increasing the bit rate for this empty | ||
2389 | MP3 frame */ | ||
2390 | int j; | ||
2391 | for (j = cfg.mpg.bitr_id + 1; j < 15; j++) | ||
2392 | { | ||
2393 | size = calcFrameSize(j, NULL); | ||
2438 | 2394 | ||
2439 | /* reset buffer write position */ | 2395 | if (size >= i + 8 + 36) |
2440 | mp3_data_len = 0; | 2396 | break; |
2397 | } | ||
2441 | 2398 | ||
2442 | return true; | 2399 | if (j >= 15) |
2443 | } /* on_start_file */ | 2400 | { |
2401 | /* Shouldn't really happen but... */ | ||
2402 | header_size = -1; | ||
2403 | return true; | ||
2404 | } | ||
2444 | 2405 | ||
2445 | static bool on_end_file(struct enc_file_event_data *data) | 2406 | header = encodeHeader(0, j); |
2446 | { | 2407 | /* Info offset won't change */ |
2447 | if (data->rec_file < 0) | 2408 | } |
2448 | return false; /* file already closed, nothing more we can do */ | ||
2449 | 2409 | ||
2450 | /* write the remaining mp3_data */ | 2410 | uint8_t frame[size]; |
2451 | if (ci->write(data->rec_file, mp3_data, mp3_data_len) | 2411 | memset(frame, 0, size); |
2452 | != (ssize_t)mp3_data_len) | ||
2453 | return false; | ||
2454 | 2412 | ||
2455 | /* reset buffer write position */ | 2413 | frame[0] = header >> 24; |
2456 | mp3_data_len = 0; | 2414 | frame[1] = header >> 16; |
2415 | frame[2] = header >> 8; | ||
2416 | frame[3] = header >> 0; | ||
2457 | 2417 | ||
2458 | /* always _try_ to write the file header, even on error */ | 2418 | /* 'Info' header (CBR 'Xing') */ |
2459 | if (ci->close(data->rec_file) != 0) | 2419 | memcpy(&frame[i], "Info", 4); |
2460 | return false; | ||
2461 | 2420 | ||
2462 | data->rec_file = -1; | 2421 | /* flags = 0; Info contains no other sections and is 8 bytes */ |
2463 | 2422 | ||
2464 | return true; | 2423 | /* Just mark the LAMEness to indicate header presence; we're not |
2465 | } /* on_end_file */ | 2424 | actually _the_ LAME so 'rbshn' is the version we give */ |
2425 | memcpy(&frame[i + 8], "LAMErbshn", 9); | ||
2466 | 2426 | ||
2467 | static void on_rec_new_stream(struct enc_buffer_event_data *data) | 2427 | /* Fill-in some info about us |
2468 | { | 2428 | * reference: http://gabriel.mp3-tech.org/mp3infotag.html |
2469 | int num_frames = cfg.mpg.type == 1 ? | 2429 | */ |
2470 | ENC_PADDING_FRAMES1 : ENC_PADDING_FRAMES2; | ||
2471 | 2430 | ||
2472 | if (data->flags & CHUNKF_END_FILE) | 2431 | /* Revision + VBR method: |
2473 | { | 2432 | * [7:4] = Revision (0 ??) |
2474 | /* add silent frames to end - encoder will also be flushed for start | 2433 | * [3:0] = VBR method (CBR) |
2475 | of next file if any */ | 2434 | */ |
2476 | memset(res_buffer, 0, pcm_chunk_size); | 2435 | frame[i + 17] = (0 << 4) | (1 << 0); |
2477 | 2436 | ||
2478 | /* the initial chunk given for the end is at enc_wr_index */ | 2437 | /* If first frame since encoder reset is long gone (not unlikely in |
2479 | while (num_frames-- > 0) | 2438 | prerecording), then the delay is long passed and no trimming done |
2480 | { | 2439 | at the start */ |
2481 | data->chunk->enc_data = ENC_CHUNK_SKIP_HDR(data->chunk->enc_data, | 2440 | unsigned int delay = first_encode ? cfg.delay : 0; |
2482 | data->chunk); | 2441 | unsigned int padding = cfg.padding; |
2483 | 2442 | ||
2484 | encode_frame(res_buffer, data->chunk); | 2443 | /* Delay and padding: |
2485 | data->chunk->num_pcm = samp_per_frame; | 2444 | * [23:12] = delay |
2445 | * [11: 0] = padding | ||
2446 | */ | ||
2447 | frame[i + 29] = delay >> 4; | ||
2448 | frame[i + 30] = (delay << 4) | (padding >> 8); | ||
2449 | frame[i + 31] = padding; | ||
2450 | |||
2451 | /* Misc: | ||
2452 | * [7:6] = source frequency | ||
2453 | * [ 5] = unwise settings (of course not :) | ||
2454 | * [4:2] = stereo mode (mono or stereo) | ||
2455 | * [1:0] = noise shaping (who knows, 0) | ||
2456 | */ | ||
2457 | uint8_t misc; | ||
2486 | 2458 | ||
2487 | ci->enc_finish_chunk(); | 2459 | if (cfg.src_samplerate <= 32000) |
2488 | data->chunk = ci->enc_get_chunk(); | 2460 | misc = (0 << 6); |
2489 | } | 2461 | else if (cfg.src_samplerate <= 44100) |
2490 | } | 2462 | misc = (1 << 6); |
2491 | else if (data->flags & CHUNKF_PRERECORD) | 2463 | else if (cfg.src_samplerate <= 48000) |
2492 | { | 2464 | misc = (2 << 6); |
2493 | /* nothing to add and we cannot change prerecorded data */ | 2465 | else /* > 48000 */ |
2494 | } | 2466 | misc = (3 << 6); |
2495 | else if (data->flags & CHUNKF_START_FILE) | ||
2496 | { | ||
2497 | /* starting fresh ... be sure to flush encoder first */ | ||
2498 | struct enc_chunk_hdr *chunk = ENC_CHUNK_HDR(res_buffer); | ||
2499 | 2467 | ||
2500 | chunk->flags = 0; | 2468 | if (cfg.channels > 1) |
2501 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | 2469 | misc |= (1 << 2); /* Stereo */ |
2502 | 2470 | ||
2503 | while (num_frames-- > 0) | 2471 | frame[i + 32] = misc; |
2504 | { | 2472 | |
2505 | memset(chunk->enc_data, 0, pcm_chunk_size); | 2473 | if (ci->enc_stream_write(frame, size) != size) |
2506 | encode_frame(chunk->enc_data, chunk); | 2474 | { |
2507 | } | 2475 | ci->enc_stream_lseek(0, SEEK_SET); |
2476 | header_size = -1; | ||
2477 | return false; | ||
2508 | } | 2478 | } |
2509 | } /* on_rec_new_stream */ | ||
2510 | 2479 | ||
2511 | static void enc_events_callback(enum enc_events event, void *data) | 2480 | header_size = size; |
2481 | return true; | ||
2482 | } | ||
2483 | |||
2484 | static inline int on_stream_data(struct enc_chunk_data *data) | ||
2512 | { | 2485 | { |
2513 | switch (event) | 2486 | ssize_t size = data->hdr.size; |
2487 | |||
2488 | if (header_size > 0) | ||
2514 | { | 2489 | { |
2515 | case ENC_WRITE_CHUNK: | 2490 | /* Header is layed-down; keep running CRC of audio data */ |
2516 | if (on_write_chunk((struct enc_file_event_data *)data)) | 2491 | uint8_t *p = data->data; |
2517 | return; | 2492 | uint8_t *p_end = p + size; |
2518 | 2493 | ||
2519 | break; | 2494 | while (p < p_end) |
2495 | mp3_crc16 = crc_update_lookup(*p++, mp3_crc16); | ||
2496 | } | ||
2520 | 2497 | ||
2521 | case ENC_START_FILE: | 2498 | if (ci->enc_stream_write(data->data, size) != size) |
2522 | if (on_start_file((struct enc_file_event_data *)data)) | 2499 | return -1; |
2523 | return; | ||
2524 | 2500 | ||
2525 | break; | 2501 | return 0; |
2502 | } | ||
2526 | 2503 | ||
2527 | case ENC_END_FILE: | 2504 | static int on_stream_start(struct enc_chunk_file *file) |
2528 | if (on_end_file((struct enc_file_event_data *)data)) | 2505 | { |
2529 | return; | 2506 | mp3_crc16 = 0x0000; |
2530 | 2507 | ||
2531 | break; | 2508 | if (!write_info_header(file->hdr.aux0)) |
2509 | return -1; | ||
2532 | 2510 | ||
2533 | case ENC_REC_NEW_STREAM: | 2511 | return 0; |
2534 | on_rec_new_stream((struct enc_buffer_event_data *)data); | 2512 | } |
2535 | return; | ||
2536 | 2513 | ||
2537 | default: | 2514 | static int on_stream_end(union enc_chunk_hdr *hdr) |
2538 | return; | 2515 | { |
2539 | } | 2516 | ssize_t size = header_size; |
2540 | 2517 | ||
2541 | /* Something failed above. Signal error back to core. */ | 2518 | if (size <= 0) |
2542 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | 2519 | return 0; /* No header possible/none yet written */ |
2543 | } /* enc_events_callback */ | ||
2544 | 2520 | ||
2545 | static bool enc_init(void) | 2521 | /* Update audio CRC and header CRC */ |
2546 | { | 2522 | uint8_t frame[size]; |
2547 | struct enc_inputs inputs; | ||
2548 | struct enc_parameters params; | ||
2549 | |||
2550 | if (ci->enc_get_inputs == NULL || | ||
2551 | ci->enc_set_parameters == NULL || | ||
2552 | ci->enc_get_chunk == NULL || | ||
2553 | ci->enc_finish_chunk == NULL || | ||
2554 | ci->enc_get_pcm_data == NULL || | ||
2555 | ci->enc_unget_pcm_data == NULL ) | ||
2556 | return false; | ||
2557 | 2523 | ||
2558 | ci->enc_get_inputs(&inputs); | 2524 | /* Won't fail this since it could still be useable if some decoder |
2525 | plays loose with the CRC info (like Rockbox :) */ | ||
2526 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0 || | ||
2527 | ci->enc_stream_read(frame, size) != size) | ||
2528 | return 0; | ||
2559 | 2529 | ||
2560 | if (inputs.config->afmt != AFMT_MPA_L3) | 2530 | uint32_t header = (frame[0] << 24) | (frame[1] << 16) | |
2561 | return false; | 2531 | (frame[2] << 8) | (frame[3] << 0); |
2532 | int i = get_info_offset(header); /* Get 'Info' header */ | ||
2562 | 2533 | ||
2563 | init_mp3_encoder_engine(inputs.sample_rate, inputs.num_channels, | 2534 | /* 'Info' header = 8 bytes */ |
2564 | inputs.rec_mono_mode, inputs.config); | ||
2565 | 2535 | ||
2566 | err = 0; | 2536 | /* Fill-in audio data CRC16 */ |
2567 | 2537 | ||
2568 | /* configure the buffer system */ | 2538 | /* On error, fixing data CRC would require scanning file since it |
2569 | params.afmt = AFMT_MPA_L3; | 2539 | has probably dropped something we tried to write and the likely |
2570 | params.chunk_size = cfg.byte_per_frame + 1; | 2540 | reason is that the disk filled; just leave it 0 in that case. */ |
2571 | params.enc_sample_rate = cfg.samplerate; | 2541 | if (!hdr->err) |
2572 | /* need enough reserved bytes to hold one frame of pcm samples + hdr | 2542 | { |
2573 | for padding and flushing */ | 2543 | frame[i + 40] = mp3_crc16 >> 8; |
2574 | params.reserve_bytes = ENC_CHUNK_HDR_SIZE + pcm_chunk_size; | 2544 | frame[i + 41] = mp3_crc16; |
2575 | params.events_callback = enc_events_callback; | 2545 | } |
2576 | ci->enc_set_parameters(¶ms); | ||
2577 | 2546 | ||
2578 | res_buffer = params.reserve_buffer; | 2547 | /* Fill-in header CRC16 */ |
2548 | unsigned int hdr_crc16 = 0x0000; | ||
2549 | for (int j = 0; j < i + 42; j++) | ||
2550 | hdr_crc16 = crc_update_lookup(frame[j], hdr_crc16); | ||
2579 | 2551 | ||
2580 | #ifdef CPU_COLDFIRE | 2552 | frame[i + 42] = hdr_crc16 >> 8; |
2581 | asm volatile ("move.l #0, %macsr"); /* integer mode */ | 2553 | frame[i + 43] = hdr_crc16; |
2582 | #endif | ||
2583 | 2554 | ||
2584 | return true; | 2555 | /* Update file */ |
2585 | } /* enc_init */ | 2556 | if (ci->enc_stream_lseek(0, SEEK_SET) == 0) |
2557 | ci->enc_stream_write(frame, size); | ||
2558 | |||
2559 | return 0; | ||
2560 | } | ||
2586 | 2561 | ||
2587 | /* this is the codec entry point */ | 2562 | /* this is the codec entry point */ |
2588 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 2563 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
2589 | { | 2564 | { |
2590 | if (reason == CODEC_LOAD) { | 2565 | #ifdef CPU_COLDFIRE |
2591 | if (!enc_init()) | 2566 | if (reason == CODEC_LOAD) |
2592 | return CODEC_ERROR; | 2567 | asm volatile ("move.l #0, %macsr"); /* integer mode */ |
2593 | } | 2568 | #endif |
2594 | else if (reason == CODEC_UNLOAD) { | ||
2595 | /* reset parameters to initial state */ | ||
2596 | ci->enc_set_parameters(NULL); | ||
2597 | } | ||
2598 | |||
2599 | return CODEC_OK; | 2569 | return CODEC_OK; |
2570 | (void)reason; | ||
2600 | } | 2571 | } |
2601 | 2572 | ||
2602 | /* this is called for each file to process */ | 2573 | /* this is called for each file to process */ |
2603 | enum codec_status codec_run(void) | 2574 | enum codec_status codec_run(void) |
2604 | { | 2575 | { |
2576 | mp3_encoder_reset(); | ||
2577 | uint32_t first = 1; | ||
2578 | |||
2579 | /* Needs to do stream finishing steps to flush-out all samples */ | ||
2580 | int frames_rem = -1; /* -1 = indeterminate */ | ||
2581 | |||
2582 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; | ||
2583 | struct enc_chunk_data *data = NULL; | ||
2584 | |||
2605 | /* main encoding loop */ | 2585 | /* main encoding loop */ |
2606 | while(ci->get_command(NULL) != CODEC_ACTION_HALT) | 2586 | while (frames_rem) |
2607 | { | 2587 | { |
2608 | char *buffer = buffer = ci->enc_get_pcm_data(pcm_chunk_size); | 2588 | intptr_t param; |
2609 | struct enc_chunk_hdr *chunk; | 2589 | enum codec_command_action action = ci->get_command(¶m); |
2610 | 2590 | ||
2611 | if(buffer == NULL) | 2591 | if (action != CODEC_ACTION_NULL) |
2612 | continue; | 2592 | { |
2593 | if (action != CODEC_ACTION_STREAM_FINISH) | ||
2594 | break; | ||
2613 | 2595 | ||
2614 | chunk = ci->enc_get_chunk(); | 2596 | if (frames_rem < 0) |
2615 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | 2597 | frames_rem = cfg.flush_frames; |
2616 | 2598 | ||
2617 | encode_frame(buffer, chunk); | 2599 | /* Reply with required space */ |
2600 | *(size_t *)param = cfg.req_byte_per_frame*frames_rem; | ||
2601 | } | ||
2618 | 2602 | ||
2619 | if (chunk->num_pcm < samp_per_frame) | 2603 | /* First obtain output buffer; when available, get PCM data */ |
2604 | switch (getbuf) | ||
2620 | { | 2605 | { |
2621 | ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4); | 2606 | case GETBUF_ENC: |
2622 | chunk->num_pcm = samp_per_frame; | 2607 | if (!(data = ci->enc_encbuf_get_buffer(cfg.req_byte_per_frame))) |
2608 | continue; | ||
2609 | getbuf = GETBUF_PCM; | ||
2610 | case GETBUF_PCM: | ||
2611 | if (LIKELY(frames_rem < 0)) | ||
2612 | { | ||
2613 | /* Encoding audio */ | ||
2614 | int count = cfg.samp_per_frame; | ||
2615 | if (!ci->enc_pcmbuf_read(cfg.samp_buffer, count)) | ||
2616 | continue; | ||
2617 | |||
2618 | ci->enc_pcmbuf_advance(cfg.samp_per_frame); | ||
2619 | |||
2620 | if (cfg.channels == 1) | ||
2621 | { | ||
2622 | /* Interleave the mono samples to stereo as required by | ||
2623 | encoder */ | ||
2624 | uint16_t *src = cfg.samp_buffer + count; | ||
2625 | uint32_t *dst = (uint32_t *)(src + count); | ||
2626 | |||
2627 | for (int i = count; i > 0; i--) | ||
2628 | { uint32_t s = *--src; *--dst = s | (s << 16); } | ||
2629 | } | ||
2630 | } | ||
2631 | else | ||
2632 | { | ||
2633 | /* Flushing encoder */ | ||
2634 | memset(cfg.samp_buffer, 0, cfg.samp_per_frame*4); | ||
2635 | frames_rem--; | ||
2636 | } | ||
2637 | getbuf = GETBUF_ENC; | ||
2623 | } | 2638 | } |
2624 | 2639 | ||
2625 | ci->enc_finish_chunk(); | 2640 | data->hdr.aux0 = first; |
2641 | first = 0; | ||
2642 | data->hdr.size = mp3_encoder_encode_frame(data->data); | ||
2643 | data->pcm_count = cfg.samp_per_frame; | ||
2644 | ci->enc_encbuf_finish_buffer(); | ||
2626 | } | 2645 | } |
2627 | 2646 | ||
2628 | return CODEC_OK; | 2647 | return CODEC_OK; |
2629 | } | 2648 | } |
2649 | |||
2650 | /* this is called by recording system */ | ||
2651 | int ICODE_ATTR enc_callback(enum enc_callback_reason reason, | ||
2652 | void *params) | ||
2653 | { | ||
2654 | if (LIKELY(reason == ENC_CB_STREAM)) | ||
2655 | { | ||
2656 | switch (((union enc_chunk_hdr *)params)->type) | ||
2657 | { | ||
2658 | case CHUNK_T_DATA: | ||
2659 | return on_stream_data(params); | ||
2660 | case CHUNK_T_STREAM_START: | ||
2661 | return on_stream_start(params); | ||
2662 | case CHUNK_T_STREAM_END: | ||
2663 | return on_stream_end(params); | ||
2664 | } | ||
2665 | } | ||
2666 | else if (reason == ENC_CB_INPUTS) | ||
2667 | { | ||
2668 | struct enc_inputs *inputs = params; | ||
2669 | |||
2670 | mp3_encoder_init(inputs->sample_rate, inputs->num_channels, | ||
2671 | inputs->config->mp3_enc.bitrate); | ||
2672 | |||
2673 | /* Return the actual configuration */ | ||
2674 | inputs->enc_sample_rate = cfg.samplerate; | ||
2675 | } | ||
2676 | |||
2677 | return 0; | ||
2678 | } | ||
diff --git a/lib/rbcodec/codecs/wav_enc.c b/lib/rbcodec/codecs/wav_enc.c index 01d0f79bcf..71bb652374 100644 --- a/lib/rbcodec/codecs/wav_enc.c +++ b/lib/rbcodec/codecs/wav_enc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Antonius Hellmann | 10 | * Copyright (C) 2006 Antonius Hellmann |
11 | * Copyright (C) 2006-2013 Michael Sevakis | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -40,12 +41,12 @@ struct riff_header | |||
40 | uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ | 41 | uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ |
41 | uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ | 42 | uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ |
42 | /* Not for audio_format=1 (PCM) */ | 43 | /* Not for audio_format=1 (PCM) */ |
43 | /* unsigned short extra_param_size; 24h - size of extra data */ | 44 | /* uint16_t extra_param_size; 24h - size of extra data */ |
44 | /* unsigned char *extra_params; */ | 45 | /* uint8_t extra_params[extra_param_size]; */ |
45 | /* data header */ | 46 | /* data header */ |
46 | uint8_t data_id[4]; /* 24h - "data" */ | 47 | uint8_t data_id[4]; /* 24h - "data" */ |
47 | uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ | 48 | uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ |
48 | /* unsigned char *data; 2ch - actual sound data */ | 49 | /* uint8_t data[data_size]; 2Ch - actual sound data */ |
49 | } __attribute__((packed)); | 50 | } __attribute__((packed)); |
50 | 51 | ||
51 | #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ | 52 | #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ |
@@ -55,19 +56,17 @@ struct riff_header | |||
55 | #define PCM_DEPTH_BYTES 2 | 56 | #define PCM_DEPTH_BYTES 2 |
56 | #define PCM_DEPTH_BITS 16 | 57 | #define PCM_DEPTH_BITS 16 |
57 | #define PCM_SAMP_PER_CHUNK 2048 | 58 | #define PCM_SAMP_PER_CHUNK 2048 |
58 | #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4) | ||
59 | 59 | ||
60 | static int num_channels IBSS_ATTR; | 60 | static int num_channels; |
61 | static int rec_mono_mode IBSS_ATTR; | ||
62 | static uint32_t sample_rate; | 61 | static uint32_t sample_rate; |
63 | static uint32_t enc_size; | 62 | static size_t frame_size; |
64 | static int32_t err IBSS_ATTR; | 63 | static size_t data_size; |
65 | 64 | ||
66 | static const struct riff_header riff_header = | 65 | static const struct riff_header riff_template_header = |
67 | { | 66 | { |
68 | /* "RIFF" header */ | 67 | /* "RIFF" header */ |
69 | { 'R', 'I', 'F', 'F' }, /* riff_id */ | 68 | { 'R', 'I', 'F', 'F' }, /* riff_id */ |
70 | 0, /* riff_size (*) */ | 69 | 0, /* riff_size (*) */ |
71 | /* format header */ | 70 | /* format header */ |
72 | { 'W', 'A', 'V', 'E' }, /* format */ | 71 | { 'W', 'A', 'V', 'E' }, /* format */ |
73 | { 'f', 'm', 't', ' ' }, /* format_id */ | 72 | { 'f', 'm', 't', ' ' }, /* format_id */ |
@@ -82,305 +81,164 @@ static const struct riff_header riff_header = | |||
82 | /* data header */ | 81 | /* data header */ |
83 | { 'd', 'a', 't', 'a' }, /* data_id */ | 82 | { 'd', 'a', 't', 'a' }, /* data_id */ |
84 | 0 /* data_size (*) */ | 83 | 0 /* data_size (*) */ |
85 | /* (*) updated during ENC_END_FILE event */ | 84 | /* (*) updated when finalizing stream */ |
86 | }; | 85 | }; |
87 | 86 | ||
88 | /* called version often - inline */ | 87 | static inline void frame_htole(uint32_t *p, size_t size) |
89 | static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; | ||
90 | static inline bool is_file_data_ok(struct enc_file_event_data *data) | ||
91 | { | 88 | { |
92 | return data->rec_file >= 0 && (long)data->chunk->flags >= 0; | 89 | #ifdef ROCKBOX_BIG_ENDIAN |
93 | } /* is_file_data_ok */ | 90 | /* Byte-swap samples, stereo or mono */ |
94 | 91 | do | |
95 | /* called version often - inline */ | ||
96 | static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; | ||
97 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
98 | { | ||
99 | if (!is_file_data_ok(data)) | ||
100 | return false; | ||
101 | |||
102 | if (data->chunk->enc_data == NULL) | ||
103 | { | 92 | { |
104 | #ifdef ROCKBOX_HAS_LOGF | 93 | uint32_t t; |
105 | ci->logf("wav enc: NULL data"); | 94 | t = swap_odd_even32(*p); *p++ = t; |
106 | #endif | 95 | t = swap_odd_even32(*p); *p++ = t; |
107 | return true; | 96 | t = swap_odd_even32(*p); *p++ = t; |
97 | t = swap_odd_even32(*p); *p++ = t; | ||
98 | t = swap_odd_even32(*p); *p++ = t; | ||
99 | t = swap_odd_even32(*p); *p++ = t; | ||
100 | t = swap_odd_even32(*p); *p++ = t; | ||
101 | t = swap_odd_even32(*p); *p++ = t; | ||
108 | } | 102 | } |
103 | while (size -= 8 * 2 * PCM_DEPTH_BYTES); | ||
104 | #endif /* ROCKBOX_BIG_ENDIAN */ | ||
105 | (void)p; (void)size; | ||
106 | } | ||
109 | 107 | ||
110 | if (ci->write(data->rec_file, data->chunk->enc_data, | 108 | static int on_stream_data(struct enc_chunk_data *data) |
111 | data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) | ||
112 | return false; | ||
113 | |||
114 | data->num_pcm_samples += data->chunk->num_pcm; | ||
115 | return true; | ||
116 | } /* on_write_chunk */ | ||
117 | |||
118 | static bool on_start_file(struct enc_file_event_data *data) | ||
119 | { | 109 | { |
120 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | 110 | size_t size = data->hdr.size; |
121 | return false; | 111 | |
112 | if (ci->enc_stream_write(data->data, size) != (ssize_t)size) | ||
113 | return -1; | ||
122 | 114 | ||
123 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); | 115 | data_size += size; |
124 | 116 | ||
125 | if (data->rec_file < 0) | 117 | return 0; |
126 | return false; | 118 | } |
127 | 119 | ||
120 | static int on_stream_start(void) | ||
121 | { | ||
128 | /* reset sample count */ | 122 | /* reset sample count */ |
129 | data->num_pcm_samples = 0; | 123 | data_size = 0; |
130 | 124 | ||
131 | /* write template header */ | 125 | /* write template header */ |
132 | if (ci->write(data->rec_file, &riff_header, sizeof (riff_header)) | 126 | if (ci->enc_stream_write(&riff_template_header, sizeof (struct riff_header)) |
133 | != sizeof (riff_header)) | 127 | != sizeof (struct riff_header)) |
134 | { | 128 | return -1; |
135 | return false; | ||
136 | } | ||
137 | 129 | ||
138 | data->new_enc_size += sizeof (riff_header); | 130 | return 0; |
139 | return true; | 131 | } |
140 | } /* on_start_file */ | ||
141 | 132 | ||
142 | static bool on_end_file(struct enc_file_event_data *data) | 133 | static int on_stream_end(union enc_chunk_hdr *hdr) |
143 | { | 134 | { |
144 | /* update template header */ | 135 | /* update template header */ |
145 | struct riff_header hdr; | 136 | struct riff_header riff; |
146 | uint32_t data_size; | ||
147 | |||
148 | if (data->rec_file < 0) | ||
149 | return false; /* file already closed, nothing more we can do */ | ||
150 | 137 | ||
151 | /* always _try_ to write the file header, even on error */ | 138 | if (hdr->err) |
152 | if ((ci->lseek(data->rec_file, 0, SEEK_SET)) || | ||
153 | (ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))) | ||
154 | { | 139 | { |
155 | return false; | 140 | /* Called for stream error; get correct data size */ |
141 | ssize_t size = ci->enc_stream_lseek(0, SEEK_END); | ||
142 | |||
143 | if (size > (ssize_t)sizeof (riff)) | ||
144 | data_size = size - sizeof (riff); | ||
156 | } | 145 | } |
157 | 146 | ||
158 | data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES; | 147 | if (ci->enc_stream_lseek(0, SEEK_SET) || |
148 | ci->enc_stream_read(&riff, sizeof (riff)) != sizeof (riff)) | ||
149 | return -1; | ||
159 | 150 | ||
160 | /* "RIFF" header */ | 151 | /* "RIFF" header */ |
161 | hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE | 152 | riff.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE |
162 | + RIFF_DATA_HEADER_SIZE + data_size); | 153 | + RIFF_DATA_HEADER_SIZE + data_size); |
163 | 154 | ||
164 | /* format data */ | 155 | /* format data */ |
165 | hdr.num_channels = htole16(num_channels); | 156 | riff.num_channels = htole16(num_channels); |
166 | hdr.sample_rate = htole32(sample_rate); | 157 | riff.sample_rate = htole32(sample_rate); |
167 | hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES); | 158 | riff.byte_rate = htole32(sample_rate*num_channels*PCM_DEPTH_BYTES); |
168 | hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES); | 159 | riff.block_align = htole16(num_channels*PCM_DEPTH_BYTES); |
169 | 160 | ||
170 | /* data header */ | 161 | /* data header */ |
171 | hdr.data_size = htole32(data_size); | 162 | riff.data_size = htole32(data_size); |
172 | 163 | ||
173 | if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || | 164 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0) |
174 | ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr) || | 165 | return -2; |
175 | ci->close(data->rec_file) != 0) | ||
176 | { | ||
177 | return false; | ||
178 | } | ||
179 | 166 | ||
180 | data->rec_file = -1; | 167 | if (ci->enc_stream_write(&riff, sizeof (riff)) != sizeof (riff)) |
168 | return -3; | ||
181 | 169 | ||
182 | return true; | 170 | return 0; |
183 | } /* on_end_file */ | 171 | } |
184 | 172 | ||
185 | static void enc_events_callback(enum enc_events event, void *data) | 173 | /* this is the codec entry point */ |
186 | ICODE_ATTR; | 174 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
187 | static void enc_events_callback(enum enc_events event, void *data) | ||
188 | { | 175 | { |
189 | switch (event) | 176 | return CODEC_OK; |
190 | { | 177 | (void)reason; |
191 | case ENC_WRITE_CHUNK: | 178 | } |
192 | if (on_write_chunk((struct enc_file_event_data *)data)) | ||
193 | return; | ||
194 | |||
195 | break; | ||
196 | |||
197 | case ENC_START_FILE: | ||
198 | if (on_start_file((struct enc_file_event_data *)data)) | ||
199 | return; | ||
200 | |||
201 | break; | ||
202 | |||
203 | case ENC_END_FILE: | ||
204 | if (on_end_file((struct enc_file_event_data *)data)) | ||
205 | return; | ||
206 | |||
207 | break; | ||
208 | |||
209 | default: | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | /* Something failed above. Signal error back to core. */ | ||
214 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | ||
215 | } /* enc_events_callback */ | ||
216 | 179 | ||
217 | /* convert native pcm samples to wav format samples */ | 180 | /* this is called for each file to process */ |
218 | static inline void sample_to_mono(uint32_t **src, uint32_t **dst) | 181 | enum codec_status ICODE_ATTR codec_run(void) |
219 | { | 182 | { |
220 | int32_t lr1, lr2; | 183 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; |
184 | struct enc_chunk_data *data = NULL; | ||
221 | 185 | ||
222 | switch(rec_mono_mode) | 186 | /* main encoding loop */ |
187 | while (1) | ||
223 | { | 188 | { |
224 | case 1: | 189 | enum codec_command_action action = ci->get_command(NULL); |
225 | /* mono = L */ | 190 | |
226 | lr1 = *(*src)++; | 191 | if (action != CODEC_ACTION_NULL) |
227 | lr1 = lr1 >> 16; | ||
228 | lr2 = *(*src)++; | ||
229 | lr2 = lr2 >> 16; | ||
230 | break; | ||
231 | case 2: | ||
232 | /* mono = R */ | ||
233 | lr1 = *(*src)++; | ||
234 | lr1 = (uint16_t)lr1; | ||
235 | lr2 = *(*src)++; | ||
236 | lr2 = (uint16_t)lr2; | ||
237 | break; | ||
238 | case 0: | ||
239 | default: | ||
240 | /* mono = (L+R)/2 */ | ||
241 | lr1 = *(*src)++; | ||
242 | lr1 = (int16_t)lr1 + (lr1 >> 16) + err; | ||
243 | err = lr1 & 1; | ||
244 | lr1 >>= 1; | ||
245 | |||
246 | lr2 = *(*src)++; | ||
247 | lr2 = (int16_t)lr2 + (lr2 >> 16) + err; | ||
248 | err = lr2 & 1; | ||
249 | lr2 >>= 1; | ||
250 | break; | 192 | break; |
251 | } | ||
252 | *(*dst)++ = htole32((lr2 << 16) | (uint16_t)lr1); | ||
253 | } /* sample_to_mono */ | ||
254 | 193 | ||
255 | static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; | 194 | /* First obtain output buffer; when available, get PCM data */ |
256 | static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) | 195 | switch (getbuf) |
257 | { | ||
258 | if (num_channels == 1) | ||
259 | { | ||
260 | /* On big endian: | ||
261 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| | ||
262 | * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => | ||
263 | * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| | ||
264 | * | ||
265 | * On little endian: | ||
266 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| | ||
267 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => | ||
268 | * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| | ||
269 | */ | ||
270 | uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; | ||
271 | |||
272 | do | ||
273 | { | 196 | { |
274 | sample_to_mono(&src, &dst); | 197 | case GETBUF_ENC: |
275 | sample_to_mono(&src, &dst); | 198 | if (!(data = ci->enc_encbuf_get_buffer(frame_size))) |
276 | sample_to_mono(&src, &dst); | 199 | continue; |
277 | sample_to_mono(&src, &dst); | 200 | getbuf = GETBUF_PCM; |
278 | sample_to_mono(&src, &dst); | 201 | case GETBUF_PCM: |
279 | sample_to_mono(&src, &dst); | 202 | if (!ci->enc_pcmbuf_read(data->data, PCM_SAMP_PER_CHUNK)) |
280 | sample_to_mono(&src, &dst); | 203 | continue; |
281 | sample_to_mono(&src, &dst); | 204 | getbuf = GETBUF_ENC; |
282 | } | 205 | } |
283 | while (src < src_end); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | #ifdef ROCKBOX_BIG_ENDIAN | ||
288 | /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => | ||
289 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| | ||
290 | */ | ||
291 | uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; | ||
292 | 206 | ||
293 | do | 207 | data->hdr.size = frame_size; |
294 | { | 208 | data->pcm_count = PCM_SAMP_PER_CHUNK; |
295 | *dst++ = swap_odd_even32(*src++); | ||
296 | *dst++ = swap_odd_even32(*src++); | ||
297 | *dst++ = swap_odd_even32(*src++); | ||
298 | *dst++ = swap_odd_even32(*src++); | ||
299 | *dst++ = swap_odd_even32(*src++); | ||
300 | *dst++ = swap_odd_even32(*src++); | ||
301 | *dst++ = swap_odd_even32(*src++); | ||
302 | *dst++ = swap_odd_even32(*src++); | ||
303 | } | ||
304 | while (src < src_end); | ||
305 | #else | ||
306 | /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => | ||
307 | * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| | ||
308 | */ | ||
309 | ci->memcpy(dst, src, PCM_CHUNK_SIZE); | ||
310 | #endif | ||
311 | } | ||
312 | } /* chunk_to_wav_format */ | ||
313 | 209 | ||
314 | static bool init_encoder(void) | 210 | frame_htole((uint32_t *)data->data, frame_size); |
315 | { | ||
316 | struct enc_inputs inputs; | ||
317 | struct enc_parameters params; | ||
318 | |||
319 | if (ci->enc_get_inputs == NULL || | ||
320 | ci->enc_set_parameters == NULL || | ||
321 | ci->enc_get_chunk == NULL || | ||
322 | ci->enc_finish_chunk == NULL || | ||
323 | ci->enc_get_pcm_data == NULL ) | ||
324 | return false; | ||
325 | |||
326 | ci->enc_get_inputs(&inputs); | ||
327 | |||
328 | if (inputs.config->afmt != AFMT_PCM_WAV) | ||
329 | return false; | ||
330 | |||
331 | sample_rate = inputs.sample_rate; | ||
332 | num_channels = inputs.num_channels; | ||
333 | rec_mono_mode = inputs.rec_mono_mode; | ||
334 | err = 0; | ||
335 | |||
336 | /* configure the buffer system */ | ||
337 | params.afmt = AFMT_PCM_WAV; | ||
338 | enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; | ||
339 | params.chunk_size = enc_size; | ||
340 | params.enc_sample_rate = sample_rate; | ||
341 | params.reserve_bytes = 0; | ||
342 | params.events_callback = enc_events_callback; | ||
343 | ci->enc_set_parameters(¶ms); | ||
344 | |||
345 | return true; | ||
346 | } /* init_encoder */ | ||
347 | 211 | ||
348 | /* this is the codec entry point */ | 212 | ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); |
349 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 213 | ci->enc_encbuf_finish_buffer(); |
350 | { | ||
351 | if (reason == CODEC_LOAD) { | ||
352 | if (!init_encoder()) | ||
353 | return CODEC_ERROR; | ||
354 | } | ||
355 | else if (reason == CODEC_UNLOAD) { | ||
356 | /* reset parameters to initial state */ | ||
357 | ci->enc_set_parameters(NULL); | ||
358 | } | 214 | } |
359 | 215 | ||
360 | return CODEC_OK; | 216 | return CODEC_OK; |
361 | } | 217 | } |
362 | 218 | ||
363 | /* this is called for each file to process */ | 219 | /* this is called by recording system */ |
364 | enum codec_status codec_run(void) | 220 | int ICODE_ATTR enc_callback(enum enc_callback_reason reason, |
221 | void *params) | ||
365 | { | 222 | { |
366 | /* main encoding loop */ | 223 | if (LIKELY(reason == ENC_CB_STREAM)) |
367 | while(ci->get_command(NULL) != CODEC_ACTION_HALT) | ||
368 | { | 224 | { |
369 | uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); | 225 | switch (((union enc_chunk_hdr *)params)->type) |
370 | struct enc_chunk_hdr *chunk; | 226 | { |
371 | 227 | case CHUNK_T_DATA: | |
372 | if(src == NULL) | 228 | return on_stream_data(params); |
373 | continue; | 229 | case CHUNK_T_STREAM_START: |
374 | 230 | return on_stream_start(); | |
375 | chunk = ci->enc_get_chunk(); | 231 | case CHUNK_T_STREAM_END: |
376 | chunk->enc_size = enc_size; | 232 | return on_stream_end(params); |
377 | chunk->num_pcm = PCM_SAMP_PER_CHUNK; | 233 | } |
378 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | 234 | } |
379 | 235 | else if (reason == ENC_CB_INPUTS) | |
380 | chunk_to_wav_format(src, (uint32_t *)chunk->enc_data); | 236 | { |
381 | 237 | struct enc_inputs *inputs = params; | |
382 | ci->enc_finish_chunk(); | 238 | sample_rate = inputs->sample_rate; |
239 | num_channels = inputs->num_channels; | ||
240 | frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; | ||
383 | } | 241 | } |
384 | 242 | ||
385 | return CODEC_OK; | 243 | return 0; |
386 | } | 244 | } |
diff --git a/lib/rbcodec/codecs/wavpack_enc.c b/lib/rbcodec/codecs/wavpack_enc.c index 1fae2d46a7..864012b4cd 100644 --- a/lib/rbcodec/codecs/wavpack_enc.c +++ b/lib/rbcodec/codecs/wavpack_enc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Antonius Hellmann | 10 | * Copyright (C) 2006 Antonius Hellmann |
11 | * Copyright (C) 2006-2013 Michael Sevakis | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -47,29 +48,39 @@ struct riff_header | |||
47 | uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ | 48 | uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ |
48 | uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ | 49 | uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ |
49 | /* Not for audio_format=1 (PCM) */ | 50 | /* Not for audio_format=1 (PCM) */ |
50 | /* unsigned short extra_param_size; 24h - size of extra data */ | 51 | /* uint16_t extra_param_size; 24h - size of extra data */ |
51 | /* unsigned char *extra_params; */ | 52 | /* uint8_t extra_params[extra_param_size]; */ |
52 | /* data header */ | 53 | /* data header */ |
53 | uint8_t data_id[4]; /* 24h - "data" */ | 54 | uint8_t data_id[4]; /* 24h - "data" */ |
54 | uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ | 55 | uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ |
55 | /* unsigned char *data; 2ch - actual sound data */ | 56 | /* uint8_t data[data_size]; 2Ch - actual sound data */ |
56 | } __attribute__((packed)); | 57 | } __attribute__((packed)); |
57 | 58 | ||
58 | #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ | 59 | #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ |
59 | #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ | 60 | #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ |
60 | #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ | 61 | #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ |
61 | 62 | ||
63 | struct wvpk_chunk_data | ||
64 | { | ||
65 | struct enc_chunk_data ckhdr; /* The base data chunk header */ | ||
66 | WavpackHeader wphdr; /* The block wavpack info */ | ||
67 | uint8_t data[]; /* Encoded audio data */ | ||
68 | }; | ||
69 | |||
62 | #define PCM_DEPTH_BITS 16 | 70 | #define PCM_DEPTH_BITS 16 |
63 | #define PCM_DEPTH_BYTES 2 | 71 | #define PCM_DEPTH_BYTES 2 |
64 | #define PCM_SAMP_PER_CHUNK 5000 | 72 | #define PCM_SAMP_PER_CHUNK 5000 |
65 | #define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK) | ||
66 | 73 | ||
67 | /** Data **/ | 74 | /** Data **/ |
68 | static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR; | 75 | static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR; |
69 | static WavpackConfig config IBSS_ATTR; | 76 | |
77 | static WavpackConfig config IBSS_ATTR; | ||
70 | static WavpackContext *wpc; | 78 | static WavpackContext *wpc; |
71 | static int32_t data_size, input_size, input_step IBSS_ATTR; | 79 | static uint32_t sample_rate; |
72 | static int32_t err IBSS_ATTR; | 80 | static int num_channels; |
81 | static uint32_t total_samples; | ||
82 | static size_t out_reqsize; | ||
83 | static size_t frame_size; | ||
73 | 84 | ||
74 | static const WavpackMetadataHeader wvpk_mdh = | 85 | static const WavpackMetadataHeader wvpk_mdh = |
75 | { | 86 | { |
@@ -77,7 +88,7 @@ static const WavpackMetadataHeader wvpk_mdh = | |||
77 | sizeof (struct riff_header) / sizeof (uint16_t), | 88 | sizeof (struct riff_header) / sizeof (uint16_t), |
78 | }; | 89 | }; |
79 | 90 | ||
80 | static const struct riff_header riff_header = | 91 | static const struct riff_header riff_template_header = |
81 | { | 92 | { |
82 | /* "RIFF" header */ | 93 | /* "RIFF" header */ |
83 | { 'R', 'I', 'F', 'F' }, /* riff_id */ | 94 | { 'R', 'I', 'F', 'F' }, /* riff_id */ |
@@ -96,157 +107,75 @@ static const struct riff_header riff_header = | |||
96 | /* data header */ | 107 | /* data header */ |
97 | { 'd', 'a', 't', 'a' }, /* data_id */ | 108 | { 'd', 'a', 't', 'a' }, /* data_id */ |
98 | 0 /* data_size (*) */ | 109 | 0 /* data_size (*) */ |
99 | /* (*) updated during ENC_END_FILE event */ | 110 | /* (*) updated when finalizing stream */ |
100 | }; | 111 | }; |
101 | 112 | ||
102 | static inline void sample_to_int32_mono(int32_t **src, int32_t **dst) | 113 | static inline void sample_to_int32(int32_t **dst, int32_t **src) |
103 | { | ||
104 | int32_t t = *(*src)++; | ||
105 | /* endianness irrelevant */ | ||
106 | t = (int16_t)t + (t >> 16) + err; | ||
107 | err = t & 1; | ||
108 | *(*dst)++ = t >> 1; | ||
109 | } /* sample_to_int32_mono */ | ||
110 | |||
111 | static inline void sample_to_int32_stereo(int32_t **src, int32_t **dst) | ||
112 | { | 114 | { |
113 | int32_t t = *(*src)++; | 115 | uint32_t t = *(*src)++; |
114 | #ifdef ROCKBOX_BIG_ENDIAN | 116 | #ifdef ROCKBOX_BIG_ENDIAN |
115 | *(*dst)++ = t >> 16, *(*dst)++ = (int16_t)t; | 117 | *(*dst)++ = (int32_t)t >> 16; |
118 | *(*dst)++ = (int16_t)t; | ||
116 | #else | 119 | #else |
117 | *(*dst)++ = (int16_t)t, *(*dst)++ = t >> 16; | 120 | *(*dst)++ = (int16_t)t; |
121 | *(*dst)++ = (int32_t)t >> 16; | ||
118 | #endif | 122 | #endif |
119 | } /* sample_to_int32_stereo */ | 123 | } |
120 | 124 | ||
121 | static void chunk_to_int32(int32_t *src) ICODE_ATTR; | 125 | static void ICODE_ATTR input_buffer_to_int32(size_t size) |
122 | static void chunk_to_int32(int32_t *src) | ||
123 | { | 126 | { |
124 | int32_t *src_end, *dst; | 127 | int32_t *dst = input_buffer; |
125 | #ifdef USE_IRAM | 128 | int32_t *src = input_buffer + PCM_SAMP_PER_CHUNK; |
126 | /* copy to IRAM before converting data */ | ||
127 | dst = (int32_t *)input_buffer + PCM_SAMP_PER_CHUNK; | ||
128 | src_end = dst + PCM_SAMP_PER_CHUNK; | ||
129 | |||
130 | memcpy(dst, src, PCM_CHUNK_SIZE); | ||
131 | |||
132 | src = dst; | ||
133 | #else | ||
134 | src_end = src + PCM_SAMP_PER_CHUNK; | ||
135 | #endif | ||
136 | |||
137 | dst = (int32_t *)input_buffer; | ||
138 | 129 | ||
139 | if (config.num_channels == 1) | 130 | do |
140 | { | 131 | { |
141 | /* | 132 | sample_to_int32(&dst, &src); |
142 | * |llllllllllllllll|rrrrrrrrrrrrrrrr| => | 133 | sample_to_int32(&dst, &src); |
143 | * |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm| | 134 | sample_to_int32(&dst, &src); |
144 | */ | 135 | sample_to_int32(&dst, &src); |
145 | do | 136 | sample_to_int32(&dst, &src); |
146 | { | 137 | sample_to_int32(&dst, &src); |
147 | /* read 10 longs and write 10 longs */ | 138 | sample_to_int32(&dst, &src); |
148 | sample_to_int32_mono(&src, &dst); | 139 | sample_to_int32(&dst, &src); |
149 | sample_to_int32_mono(&src, &dst); | 140 | sample_to_int32(&dst, &src); |
150 | sample_to_int32_mono(&src, &dst); | 141 | sample_to_int32(&dst, &src); |
151 | sample_to_int32_mono(&src, &dst); | ||
152 | sample_to_int32_mono(&src, &dst); | ||
153 | sample_to_int32_mono(&src, &dst); | ||
154 | sample_to_int32_mono(&src, &dst); | ||
155 | sample_to_int32_mono(&src, &dst); | ||
156 | sample_to_int32_mono(&src, &dst); | ||
157 | sample_to_int32_mono(&src, &dst); | ||
158 | } | ||
159 | while(src < src_end); | ||
160 | |||
161 | return; | ||
162 | } | 142 | } |
163 | else | 143 | while (size -= 10 * 2 * PCM_DEPTH_BYTES); |
164 | { | 144 | } |
165 | /* | ||
166 | * |llllllllllllllll|rrrrrrrrrrrrrrrr| => | ||
167 | * |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr| | ||
168 | */ | ||
169 | do | ||
170 | { | ||
171 | /* read 10 longs and write 20 longs */ | ||
172 | sample_to_int32_stereo(&src, &dst); | ||
173 | sample_to_int32_stereo(&src, &dst); | ||
174 | sample_to_int32_stereo(&src, &dst); | ||
175 | sample_to_int32_stereo(&src, &dst); | ||
176 | sample_to_int32_stereo(&src, &dst); | ||
177 | sample_to_int32_stereo(&src, &dst); | ||
178 | sample_to_int32_stereo(&src, &dst); | ||
179 | sample_to_int32_stereo(&src, &dst); | ||
180 | sample_to_int32_stereo(&src, &dst); | ||
181 | sample_to_int32_stereo(&src, &dst); | ||
182 | } | ||
183 | while (src < src_end); | ||
184 | |||
185 | return; | ||
186 | } | ||
187 | } /* chunk_to_int32 */ | ||
188 | |||
189 | /* called very often - inline */ | ||
190 | static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; | ||
191 | static inline bool is_file_data_ok(struct enc_file_event_data *data) | ||
192 | { | ||
193 | return data->rec_file >= 0 && (long)data->chunk->flags >= 0; | ||
194 | } /* is_file_data_ok */ | ||
195 | 145 | ||
196 | /* called very often - inline */ | 146 | static int on_stream_data(struct wvpk_chunk_data *wpdata) |
197 | static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; | ||
198 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
199 | { | 147 | { |
200 | if (!is_file_data_ok(data)) | ||
201 | return false; | ||
202 | |||
203 | if (data->chunk->enc_data == NULL) | ||
204 | { | ||
205 | #ifdef ROCKBOX_HAS_LOGF | ||
206 | ci->logf("wvpk enc: NULL data"); | ||
207 | #endif | ||
208 | return true; | ||
209 | } | ||
210 | |||
211 | /* update timestamp (block_index) */ | 148 | /* update timestamp (block_index) */ |
212 | ((WavpackHeader *)data->chunk->enc_data)->block_index = | 149 | wpdata->wphdr.block_index = htole32(total_samples); |
213 | htole32(data->num_pcm_samples); | ||
214 | 150 | ||
215 | if (ci->write(data->rec_file, data->chunk->enc_data, | 151 | size_t size = wpdata->ckhdr.hdr.size; |
216 | data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) | 152 | if (ci->enc_stream_write(wpdata->ckhdr.data, size) != (ssize_t)size) |
217 | return false; | 153 | return -1; |
218 | 154 | ||
219 | data->num_pcm_samples += data->chunk->num_pcm; | 155 | total_samples += wpdata->ckhdr.pcm_count; |
220 | return true; | ||
221 | } /* on_write_chunk */ | ||
222 | 156 | ||
223 | static bool on_start_file(struct enc_file_event_data *data) | 157 | return 0; |
224 | { | 158 | } |
225 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | ||
226 | return false; | ||
227 | |||
228 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); | ||
229 | |||
230 | if (data->rec_file < 0) | ||
231 | return false; | ||
232 | 159 | ||
160 | static int on_stream_start(void) | ||
161 | { | ||
233 | /* reset sample count */ | 162 | /* reset sample count */ |
234 | data->num_pcm_samples = 0; | 163 | total_samples = 0; |
235 | 164 | ||
236 | /* write template headers */ | 165 | /* write template headers */ |
237 | if (ci->write(data->rec_file, &wvpk_mdh, sizeof (wvpk_mdh)) | 166 | if (ci->enc_stream_write(&wvpk_mdh, sizeof (wvpk_mdh)) |
238 | != sizeof (wvpk_mdh) || | 167 | != sizeof (wvpk_mdh)) |
239 | ci->write(data->rec_file, &riff_header, sizeof (riff_header)) | 168 | return -1; |
240 | != sizeof (riff_header)) | 169 | |
241 | { | 170 | if (ci->enc_stream_write(&riff_template_header, |
242 | return false; | 171 | sizeof (riff_template_header)) |
243 | } | 172 | != sizeof (riff_template_header)) |
173 | return -2; | ||
244 | 174 | ||
245 | data->new_enc_size += sizeof(wvpk_mdh) + sizeof(riff_header); | 175 | return 0; |
246 | return true; | 176 | } |
247 | } /* on_start_file */ | ||
248 | 177 | ||
249 | static bool on_end_file(struct enc_file_event_data *data) | 178 | static int on_stream_end(void) |
250 | { | 179 | { |
251 | struct | 180 | struct |
252 | { | 181 | { |
@@ -255,19 +184,16 @@ static bool on_end_file(struct enc_file_event_data *data) | |||
255 | WavpackHeader wph; | 184 | WavpackHeader wph; |
256 | } __attribute__ ((packed)) h; | 185 | } __attribute__ ((packed)) h; |
257 | 186 | ||
258 | uint32_t data_size; | 187 | /* Correcting sizes on error is a bit of a pain */ |
259 | |||
260 | if (data->rec_file < 0) | ||
261 | return false; /* file already closed, nothing more we can do */ | ||
262 | |||
263 | /* always _try_ to write the file header, even on error */ | ||
264 | 188 | ||
265 | /* read template headers at start */ | 189 | /* read template headers at start */ |
266 | if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || | 190 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0) |
267 | ci->read(data->rec_file, &h, sizeof (h)) != sizeof (h)) | 191 | return -1; |
268 | return false; | ||
269 | 192 | ||
270 | data_size = data->num_pcm_samples*config.num_channels*PCM_DEPTH_BYTES; | 193 | if (ci->enc_stream_read(&h, sizeof (h)) != sizeof (h)) |
194 | return -2; | ||
195 | |||
196 | size_t data_size = total_samples*config.num_channels*PCM_DEPTH_BYTES; | ||
271 | 197 | ||
272 | /** "RIFF" header **/ | 198 | /** "RIFF" header **/ |
273 | h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + | 199 | h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + |
@@ -286,121 +212,29 @@ static bool on_end_file(struct enc_file_event_data *data) | |||
286 | /** Wavpack header **/ | 212 | /** Wavpack header **/ |
287 | h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh) | 213 | h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh) |
288 | + sizeof (h.rhdr)); | 214 | + sizeof (h.rhdr)); |
289 | h.wph.total_samples = htole32(data->num_pcm_samples); | 215 | h.wph.total_samples = htole32(total_samples); |
290 | 216 | ||
291 | /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */ | 217 | /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */ |
292 | if (ci->lseek(data->rec_file, 0, SEEK_SET) | 218 | if (ci->enc_stream_lseek(0, SEEK_SET) != 0) |
293 | != 0 || | 219 | return -3; |
294 | ci->write(data->rec_file, &h.wph, sizeof (h.wph)) | ||
295 | != sizeof (h.wph) || | ||
296 | ci->write(data->rec_file, &h.wpmdh, sizeof (h.wpmdh)) | ||
297 | != sizeof (h.wpmdh) || | ||
298 | ci->write(data->rec_file, &h.rhdr, sizeof (h.rhdr)) | ||
299 | != sizeof (h.rhdr) || | ||
300 | ci->close(data->rec_file) != 0 ) | ||
301 | { | ||
302 | return false; | ||
303 | } | ||
304 | |||
305 | data->rec_file = -1; | ||
306 | |||
307 | return true; | ||
308 | } /* on_end_file */ | ||
309 | 220 | ||
310 | static void enc_events_callback(enum enc_events event, void *data) | 221 | if (ci->enc_stream_write(&h.wph, sizeof (h.wph)) != sizeof (h.wph)) |
311 | ICODE_ATTR; | 222 | return -4; |
312 | static void enc_events_callback(enum enc_events event, void *data) | ||
313 | { | ||
314 | switch (event) | ||
315 | { | ||
316 | case ENC_WRITE_CHUNK: | ||
317 | if (on_write_chunk((struct enc_file_event_data *)data)) | ||
318 | return; | ||
319 | |||
320 | break; | ||
321 | |||
322 | case ENC_START_FILE: | ||
323 | /* write metadata header and RIFF header */ | ||
324 | if (on_start_file((struct enc_file_event_data *)data)) | ||
325 | return; | ||
326 | |||
327 | break; | ||
328 | |||
329 | case ENC_END_FILE: | ||
330 | if (on_end_file((struct enc_file_event_data *)data)) | ||
331 | return; | ||
332 | |||
333 | break; | ||
334 | |||
335 | default: | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | /* Something failed above. Signal error back to core. */ | ||
340 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | ||
341 | } /* enc_events_callback */ | ||
342 | |||
343 | static bool init_encoder(void) | ||
344 | { | ||
345 | struct enc_inputs inputs; | ||
346 | struct enc_parameters params; | ||
347 | |||
348 | codec_init(); | ||
349 | |||
350 | if (ci->enc_get_inputs == NULL || | ||
351 | ci->enc_set_parameters == NULL || | ||
352 | ci->enc_get_chunk == NULL || | ||
353 | ci->enc_finish_chunk == NULL || | ||
354 | ci->enc_get_pcm_data == NULL || | ||
355 | ci->enc_unget_pcm_data == NULL ) | ||
356 | return false; | ||
357 | |||
358 | ci->enc_get_inputs(&inputs); | ||
359 | |||
360 | if (inputs.config->afmt != AFMT_WAVPACK) | ||
361 | return false; | ||
362 | |||
363 | memset(&config, 0, sizeof (config)); | ||
364 | config.bits_per_sample = PCM_DEPTH_BITS; | ||
365 | config.bytes_per_sample = PCM_DEPTH_BYTES; | ||
366 | config.sample_rate = inputs.sample_rate; | ||
367 | config.num_channels = inputs.num_channels; | ||
368 | 223 | ||
369 | wpc = WavpackOpenFileOutput (); | 224 | if (ci->enc_stream_write(&h.wpmdh, sizeof (h.wpmdh)) != sizeof (h.wpmdh)) |
225 | return -5; | ||
370 | 226 | ||
371 | if (!WavpackSetConfiguration(wpc, &config, -1)) | 227 | if (ci->enc_stream_write(&h.rhdr, sizeof (h.rhdr)) != sizeof (h.rhdr)) |
372 | return false; | 228 | return -6; |
373 | 229 | ||
374 | err = 0; | 230 | return 0; |
375 | 231 | } | |
376 | /* configure the buffer system */ | ||
377 | params.afmt = AFMT_WAVPACK; | ||
378 | input_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; | ||
379 | data_size = 105*input_size / 100; | ||
380 | input_size *= 2; | ||
381 | input_step = input_size / 4; | ||
382 | params.chunk_size = data_size; | ||
383 | params.enc_sample_rate = inputs.sample_rate; | ||
384 | params.reserve_bytes = 0; | ||
385 | params.events_callback = enc_events_callback; | ||
386 | |||
387 | ci->enc_set_parameters(¶ms); | ||
388 | |||
389 | return true; | ||
390 | } /* init_encoder */ | ||
391 | 232 | ||
392 | /* this is the codec entry point */ | 233 | /* this is the codec entry point */ |
393 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 234 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
394 | { | 235 | { |
395 | if (reason == CODEC_LOAD) { | 236 | if (reason == CODEC_LOAD) |
396 | /* initialize params and config */ | 237 | codec_init(); |
397 | if (!init_encoder()) | ||
398 | return CODEC_ERROR; | ||
399 | } | ||
400 | else if (reason == CODEC_UNLOAD) { | ||
401 | /* reset parameters to initial state */ | ||
402 | ci->enc_set_parameters(NULL); | ||
403 | } | ||
404 | 238 | ||
405 | return CODEC_OK; | 239 | return CODEC_OK; |
406 | } | 240 | } |
@@ -408,60 +242,89 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
408 | /* this is called for each file to process */ | 242 | /* this is called for each file to process */ |
409 | enum codec_status codec_run(void) | 243 | enum codec_status codec_run(void) |
410 | { | 244 | { |
245 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; | ||
246 | struct enc_chunk_data *data = NULL; | ||
247 | |||
411 | /* main encoding loop */ | 248 | /* main encoding loop */ |
412 | while(ci->get_command(NULL) != CODEC_ACTION_HALT) | 249 | while (1) |
413 | { | 250 | { |
414 | uint8_t *src = (uint8_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); | 251 | enum codec_command_action action = ci->get_command(NULL); |
415 | struct enc_chunk_hdr *chunk; | ||
416 | bool abort_chunk; | ||
417 | uint8_t *dst; | ||
418 | uint8_t *src_end; | ||
419 | |||
420 | if(src == NULL) | ||
421 | continue; | ||
422 | |||
423 | chunk = ci->enc_get_chunk(); | ||
424 | |||
425 | /* reset counts and pointer */ | ||
426 | chunk->enc_size = 0; | ||
427 | chunk->num_pcm = 0; | ||
428 | chunk->enc_data = NULL; | ||
429 | |||
430 | dst = ENC_CHUNK_SKIP_HDR(dst, chunk); | ||
431 | 252 | ||
432 | WavpackStartBlock(wpc, dst, dst + data_size); | 253 | if (action != CODEC_ACTION_NULL) |
254 | break; | ||
433 | 255 | ||
434 | chunk_to_int32((uint32_t*)src); | 256 | /* First obtain output buffer; when available, get PCM data */ |
435 | src = input_buffer; | 257 | switch (getbuf) |
436 | src_end = src + input_size; | ||
437 | |||
438 | /* encode chunk in four steps yielding between each */ | ||
439 | do | ||
440 | { | 258 | { |
441 | abort_chunk = true; | 259 | case GETBUF_ENC: |
442 | if (WavpackPackSamples(wpc, (int32_t *)src, | 260 | if (!(data = ci->enc_encbuf_get_buffer(out_reqsize))) |
443 | PCM_SAMP_PER_CHUNK/4)) | 261 | continue; |
444 | { | 262 | getbuf = GETBUF_PCM; |
445 | chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; | 263 | case GETBUF_PCM: |
446 | ci->yield(); | 264 | if (!ci->enc_pcmbuf_read(input_buffer + PCM_SAMP_PER_CHUNK, |
447 | /* could've been stopped in some way */ | 265 | PCM_SAMP_PER_CHUNK)) |
448 | abort_chunk = chunk->flags & CHUNKF_ABORT; | 266 | continue; |
449 | } | 267 | getbuf = GETBUF_ENC; |
450 | |||
451 | src += input_step; | ||
452 | } | 268 | } |
453 | while (!abort_chunk && src < src_end); | ||
454 | 269 | ||
455 | if (!abort_chunk) | 270 | input_buffer_to_int32(frame_size); |
271 | |||
272 | if (WavpackStartBlock(wpc, data->data, data->data + out_reqsize) && | ||
273 | WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK)) | ||
456 | { | 274 | { |
457 | chunk->enc_data = dst; | ||
458 | if (chunk->num_pcm < PCM_SAMP_PER_CHUNK) | ||
459 | ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4); | ||
460 | /* finish the chunk and store chunk size info */ | 275 | /* finish the chunk and store chunk size info */ |
461 | chunk->enc_size = WavpackFinishBlock(wpc); | 276 | data->hdr.size = WavpackFinishBlock(wpc); |
462 | ci->enc_finish_chunk(); | 277 | data->pcm_count = PCM_SAMP_PER_CHUNK; |
463 | } | 278 | } |
279 | else | ||
280 | { | ||
281 | data->hdr.err = 1; | ||
282 | } | ||
283 | |||
284 | ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); | ||
285 | ci->enc_encbuf_finish_buffer(); | ||
464 | } | 286 | } |
465 | 287 | ||
466 | return CODEC_OK; | 288 | return CODEC_OK; |
467 | } | 289 | } |
290 | |||
291 | /* this is called by recording system */ | ||
292 | int ICODE_ATTR enc_callback(enum enc_callback_reason reason, | ||
293 | void *params) | ||
294 | { | ||
295 | if (LIKELY(reason == ENC_CB_STREAM)) | ||
296 | { | ||
297 | switch (((union enc_chunk_hdr *)params)->type) | ||
298 | { | ||
299 | case CHUNK_T_DATA: | ||
300 | return on_stream_data(params); | ||
301 | case CHUNK_T_STREAM_START: | ||
302 | return on_stream_start(); | ||
303 | case CHUNK_T_STREAM_END: | ||
304 | return on_stream_end(); | ||
305 | } | ||
306 | } | ||
307 | else if (reason == ENC_CB_INPUTS) | ||
308 | { | ||
309 | /* Save parameters */ | ||
310 | struct enc_inputs *inputs = params; | ||
311 | sample_rate = inputs->sample_rate; | ||
312 | num_channels = inputs->num_channels; | ||
313 | frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; | ||
314 | out_reqsize = frame_size*110 / 100; /* Add 10% */ | ||
315 | |||
316 | /* Setup Wavpack encoder */ | ||
317 | memset(&config, 0, sizeof (config)); | ||
318 | config.bits_per_sample = PCM_DEPTH_BITS; | ||
319 | config.bytes_per_sample = PCM_DEPTH_BYTES; | ||
320 | config.sample_rate = sample_rate; | ||
321 | config.num_channels = num_channels; | ||
322 | |||
323 | wpc = WavpackOpenFileOutput(); | ||
324 | |||
325 | if (!WavpackSetConfiguration(wpc, &config, -1)) | ||
326 | return -1; | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | } | ||