summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rbcodec/codecs/aiff_enc.c399
-rw-r--r--lib/rbcodec/codecs/codecs.h45
-rw-r--r--lib/rbcodec/codecs/mp3_enc.c813
-rw-r--r--lib/rbcodec/codecs/wav_enc.c376
-rw-r--r--lib/rbcodec/codecs/wavpack_enc.c453
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
52static int num_channels;
53static uint32_t sample_rate;
54static size_t frame_size;
55static size_t pcm_size;
56static uint32_t num_sample_frames;
51 57
52/* Template headers */ 58/* Template headers */
53struct aiff_header aiff_header = 59static 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 */ 77static inline void frame_htobe(uint32_t *p, size_t size)
71 78{
72static int num_channels IBSS_ATTR; 79#ifdef ROCKBOX_LITTLE_ENDIAN
73static int rec_mono_mode IBSS_ATTR; 80 /* Byte-swap samples, stereo or mono */
74static uint32_t sample_rate; 81 do
75static uint32_t enc_size; 82 {
76static 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 */
79static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) 99static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l)
80 ICODE_ATTR;
81static 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 */
106static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
107static 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 */ 121static int on_stream_data(struct enc_chunk_data *data)
113static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
114static 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
135static bool on_start_file(struct enc_file_event_data *data) 134static 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
159static bool on_end_file(struct enc_file_event_data *data) 149static 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
199static void enc_events_callback(enum enc_events event, void *data) 192/* this is the codec entry point */
200 ICODE_ATTR; 193enum codec_status codec_main(enum codec_entry_call_reason reason)
201static 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 */
232static inline void sample_to_mono(uint32_t **src, uint32_t **dst) 200enum 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
269static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; 213 /* First obtain output buffer; when available, get PCM data */
270static 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
328static 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(&params);
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);
363enum 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 */
378enum codec_status codec_run(void) 239int 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 */
83enum codec_entry_call_reason { 83enum 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);
277int codec_load_buf(int hid, struct codec_api *api); 275int codec_load_buf(int hid, struct codec_api *api);
278int codec_load_file(const char* codec, struct codec_api *api); 276int codec_load_file(const char* codec, struct codec_api *api);
279int codec_run_proc(void); 277int codec_run_proc(void);
280int codec_halt(void);
281int codec_close(void); 278int codec_close(void);
279#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
280enc_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 */
284enum codec_status codec_start(enum codec_entry_call_reason reason); 286enum codec_status codec_start(enum codec_entry_call_reason reason);
285enum codec_status codec_main(enum codec_entry_call_reason reason); 287enum codec_status codec_main(enum codec_entry_call_reason reason);
286enum codec_status codec_run(void); 288enum codec_status codec_run(void);
289#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
290int 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
38CODEC_ENC_HEADER 39CODEC_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
81typedef struct { 74typedef 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
96typedef struct { 95typedef 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
121static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ 120static short mfbuf [2*(1152+512)] IBSS_ATTR
121 /* for memcpy and 32-bit access */ MEM_ALIGN_ATTR; /* 3328 Bytes */
122static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ 122static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */
123static int mdct_freq [SAMPL2] IBSS_ATTR; /* 2304 Bytes */ 123static int mdct_freq [SAMPL2] IBSS_ATTR; /* 2304 Bytes */
124static char mdct_sign [SAMPL2] IBSS_ATTR; /* 576 Bytes */ 124static char mdct_sign [SAMPL2] IBSS_ATTR; /* 576 Bytes */
@@ -171,12 +171,7 @@ static uint8_t t16l [256] IBSS_ATTR;
171static uint8_t t24l [256] IBSS_ATTR; 171static uint8_t t24l [256] IBSS_ATTR;
172static struct huffcodetab ht [HTN] IBSS_ATTR; 172static struct huffcodetab ht [HTN] IBSS_ATTR;
173 173
174static unsigned pcm_chunk_size IBSS_ATTR;
175static unsigned samp_per_frame IBSS_ATTR;
176
177static config_t cfg IBSS_ATTR; 174static config_t cfg IBSS_ATTR;
178static char *res_buffer;
179static int32_t err IBSS_ATTR;
180static uint8_t band_scale_f[22]; 175static uint8_t band_scale_f[22];
181 176
182static const uint8_t ht_count_const[2][2][16] = 177static 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 );
848static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, 843static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1,
849 int *bits); 844 int *bits);
850 845
846static 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
878static 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}
852static void encodeSideInfo( side_info_t si[2][2] ) 890static 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 */
1504void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) ICODE_ATTR; 1513static void ICODE_ATTR window_subband1(short *wk, int sb0[SBLIMIT],
1505void 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
1764void window_subband2(short *x1, int a[SBLIMIT]) ICODE_ATTR; 1773static void ICODE_ATTR window_subband2(short *x1, int a[SBLIMIT])
1765void 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
1882void mdct_long(int *out, int *in) ICODE_ATTR; 1890static void ICODE_ATTR mdct_long(int *out, int *in)
1883void 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
1972static bool init_mp3_encoder_engine(int sample_rate, 1979static 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
1990static 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
2085static 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
2113static void to_mono_mm(void) ICODE_ATTR;
2114static 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 */
2138static 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
2158static void set_scale_facs(int *mdct_freq) 2097static 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
2191static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) 2130static size_t ICODE_ATTR mp3_encoder_encode_frame(uint8_t *outbuf)
2192 ICODE_ATTR;
2193static 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;
2385static 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
2390static unsigned char mp3_data[16384] __attribute__((aligned(4)));
2391static unsigned int mp3_data_len; /* current data size in buffer */
2392 2307
2393/* called very often - inline */ 2308/*======== Codec section ========*/
2394static 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, 2316static 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; 2352static ssize_t header_size;
2415 } 2353static 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); 2356static 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 */
2365static 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
2426static 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. */
2375static 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
2445static 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
2467static 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
2511static void enc_events_callback(enum enc_events event, void *data) 2480 header_size = size;
2481 return true;
2482}
2483
2484static 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: 2504static 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: 2514static 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
2545static 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(&params);
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 */
2588enum codec_status codec_main(enum codec_entry_call_reason reason) 2563enum 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 */
2603enum codec_status codec_run(void) 2574enum 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(&param);
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 */
2651int 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
60static int num_channels IBSS_ATTR; 60static int num_channels;
61static int rec_mono_mode IBSS_ATTR;
62static uint32_t sample_rate; 61static uint32_t sample_rate;
63static uint32_t enc_size; 62static size_t frame_size;
64static int32_t err IBSS_ATTR; 63static size_t data_size;
65 64
66static const struct riff_header riff_header = 65static 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 */ 87static inline void frame_htole(uint32_t *p, size_t size)
89static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
90static 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 */
96static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
97static 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, 108static 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
118static 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
120static 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
142static bool on_end_file(struct enc_file_event_data *data) 133static 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
185static void enc_events_callback(enum enc_events event, void *data) 173/* this is the codec entry point */
186 ICODE_ATTR; 174enum codec_status codec_main(enum codec_entry_call_reason reason)
187static 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 */
218static inline void sample_to_mono(uint32_t **src, uint32_t **dst) 181enum 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
255static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; 194 /* First obtain output buffer; when available, get PCM data */
256static 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
314static 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(&params);
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);
349enum 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 */
364enum codec_status codec_run(void) 220int 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
63struct 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 **/
68static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR; 75static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR;
69static WavpackConfig config IBSS_ATTR; 76
77static WavpackConfig config IBSS_ATTR;
70static WavpackContext *wpc; 78static WavpackContext *wpc;
71static int32_t data_size, input_size, input_step IBSS_ATTR; 79static uint32_t sample_rate;
72static int32_t err IBSS_ATTR; 80static int num_channels;
81static uint32_t total_samples;
82static size_t out_reqsize;
83static size_t frame_size;
73 84
74static const WavpackMetadataHeader wvpk_mdh = 85static 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
80static const struct riff_header riff_header = 91static 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
102static inline void sample_to_int32_mono(int32_t **src, int32_t **dst) 113static 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
111static 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
121static void chunk_to_int32(int32_t *src) ICODE_ATTR; 125static void ICODE_ATTR input_buffer_to_int32(size_t size)
122static 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 */
190static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
191static 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 */ 146static int on_stream_data(struct wvpk_chunk_data *wpdata)
197static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
198static 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
223static 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
160static 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
249static bool on_end_file(struct enc_file_event_data *data) 178static 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
310static 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;
312static 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
343static 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(&params);
388
389 return true;
390} /* init_encoder */
391 232
392/* this is the codec entry point */ 233/* this is the codec entry point */
393enum codec_status codec_main(enum codec_entry_call_reason reason) 234enum 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 */
409enum codec_status codec_run(void) 243enum 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 */
292int 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}