make usb_serial work again. Also know as "make sure arrays are allocated at their...
[kugel-rb.git] / apps / codecs / aiff_enc.c
blob749c3a13a1b954f33061f941c8fec28d71558e2a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Antonius Hellmann
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #ifndef SIMULATOR
22 #include <inttypes.h>
23 #include "codeclib.h"
25 CODEC_ENC_HEADER
27 struct aiff_header
29 uint8_t form_id[4]; /* 00h - 'FORM' */
30 uint32_t form_size; /* 04h - size of file - 8 */
31 uint8_t aiff_id[4]; /* 08h - 'AIFF' */
32 uint8_t comm_id[4]; /* 0Ch - 'COMM' */
33 int32_t comm_size; /* 10h - num_channels through sample_rate
34 (18) */
35 int16_t num_channels; /* 14h - 1=M, 2=S, etc. */
36 uint32_t num_sample_frames; /* 16h - num samples for each channel */
37 int16_t sample_size; /* 1ah - 1-32 bits per sample */
38 uint8_t sample_rate[10]; /* 1ch - IEEE 754 80-bit floating point */
39 uint8_t ssnd_id[4]; /* 26h - "SSND" */
40 int32_t ssnd_size; /* 2ah - size of chunk from offset to
41 end of pcm data */
42 uint32_t offset; /* 2eh - data offset from end of header */
43 uint32_t block_size; /* 32h - pcm data alignment */
44 /* 36h */
45 } __attribute__((packed));
47 #define PCM_DEPTH_BYTES 2
48 #define PCM_DEPTH_BITS 16
49 #define PCM_SAMP_PER_CHUNK 2048
50 #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4)
52 /* Template headers */
53 struct aiff_header aiff_header =
55 { 'F', 'O', 'R', 'M' }, /* form_id */
56 0, /* form_size (*) */
57 { 'A', 'I', 'F', 'F' }, /* aiff_id */
58 { 'C', 'O', 'M', 'M' }, /* comm_id */
59 H_TO_BE32(18), /* comm_size */
60 0, /* num_channels (*) */
61 0, /* num_sample_frames (*) */
62 H_TO_BE16(PCM_DEPTH_BITS), /* sample_size */
63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* sample_rate (*) */
64 { 'S', 'S', 'N', 'D' }, /* ssnd_id */
65 0, /* ssnd_size (*) */
66 H_TO_BE32(0), /* offset */
67 H_TO_BE32(0), /* block_size */
70 /* (*) updated when finalizing file */
72 static int num_channels IBSS_ATTR;
73 static uint32_t sample_rate;
74 static uint32_t enc_size;
75 static int32_t err IBSS_ATTR;
77 /* convert unsigned 32 bit value to 80-bit floating point number */
78 STATICIRAM void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l)
79 ICODE_ATTR;
80 STATICIRAM void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l)
82 int32_t exp;
84 ci->memset(f, 0, 10);
86 if (l == 0)
87 return;
89 for (exp = 30; (l & (1ul << 31)) == 0; exp--)
90 l <<= 1;
92 /* sign always zero - bit 79 */
93 /* exponent is 0-31 (normalized: 31 - shift + 16383) - bits 64-78 */
94 f[0] = 0x40;
95 f[1] = (uint8_t)exp;
96 /* mantissa is value left justified with most significant non-zero
97 bit stored in bit 63 - bits 0-63 */
98 *(uint32_t *)&f[2] = htobe32(l);
99 } /* uint32_h_to_ieee754_extended_be */
101 /* called version often - inline */
102 static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
103 static inline bool is_file_data_ok(struct enc_file_event_data *data)
105 return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
106 } /* is_file_data_ok */
108 /* called version often - inline */
109 static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
110 static inline bool on_write_chunk(struct enc_file_event_data *data)
112 if (!is_file_data_ok(data))
113 return false;
115 if (data->chunk->enc_data == NULL)
117 #ifdef ROCKBOX_HAS_LOGF
118 ci->logf("aiff enc: NULL data");
119 #endif
120 return true;
123 if (ci->write(data->rec_file, data->chunk->enc_data,
124 data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
125 return false;
127 data->num_pcm_samples += data->chunk->num_pcm;
128 return true;
129 } /* on_write_chunk */
131 static bool on_start_file(struct enc_file_event_data *data)
133 if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
134 return false;
136 data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
138 if (data->rec_file < 0)
139 return false;
141 /* reset sample count */
142 data->num_pcm_samples = 0;
144 /* write template headers */
145 if (ci->write(data->rec_file, &aiff_header, sizeof (aiff_header))
146 != sizeof (aiff_header))
148 return false;
151 data->new_enc_size += sizeof(aiff_header);
152 return true;
153 } /* on_start_file */
155 static bool on_end_file(struct enc_file_event_data *data)
157 /* update template headers */
158 struct aiff_header hdr;
159 uint32_t data_size;
161 if (!is_file_data_ok(data))
162 return false;
164 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
165 ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
167 return false;
170 data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES;
172 /* 'FORM' chunk */
173 hdr.form_size = htobe32(data_size + sizeof (hdr) - 8);
175 /* 'COMM' chunk */
176 hdr.num_channels = htobe16(num_channels);
177 hdr.num_sample_frames = htobe32(data->num_pcm_samples);
178 uint32_h_to_ieee754_extended_be(hdr.sample_rate, sample_rate);
180 /* 'SSND' chunk */
181 hdr.ssnd_size = htobe32(data_size + 8);
183 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
184 ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr) ||
185 ci->close(data->rec_file) != 0)
187 return false;
190 data->rec_file = -1;
192 return true;
193 } /* on_end_file */
195 STATICIRAM void enc_events_callback(enum enc_events event, void *data)
196 ICODE_ATTR;
197 STATICIRAM void enc_events_callback(enum enc_events event, void *data)
199 if (event == ENC_WRITE_CHUNK)
201 if (on_write_chunk((struct enc_file_event_data *)data))
202 return;
204 else if (event == ENC_START_FILE)
206 if (on_start_file((struct enc_file_event_data *)data))
207 return;
209 else if (event == ENC_END_FILE)
211 if (on_end_file((struct enc_file_event_data *)data))
212 return;
214 else
216 return;
219 ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
220 } /* enc_events_callback */
222 /* convert native pcm samples to aiff format samples */
223 static inline void sample_to_mono(uint32_t **src, uint32_t **dst)
225 int32_t lr1, lr2;
227 lr1 = *(*src)++;
228 lr1 = (int16_t)lr1 + (lr1 >> 16) + err;
229 err = lr1 & 1;
230 lr1 >>= 1;
232 lr2 = *(*src)++;
233 lr2 = (int16_t)lr2 + (lr2 >> 16) + err;
234 err = lr2 & 1;
235 lr2 >>= 1;
236 *(*dst)++ = swap_odd_even_le32((lr1 << 16) | (uint16_t)lr2);
237 } /* sample_to_mono */
239 STATICIRAM void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) ICODE_ATTR;
240 STATICIRAM void chunk_to_aiff_format(uint32_t *src, uint32_t *dst)
242 if (num_channels == 1)
244 /* On big endian:
245 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
246 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
247 * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
249 * On little endian:
250 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
251 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
252 * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
254 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
258 sample_to_mono(&src, &dst);
259 sample_to_mono(&src, &dst);
260 sample_to_mono(&src, &dst);
261 sample_to_mono(&src, &dst);
262 sample_to_mono(&src, &dst);
263 sample_to_mono(&src, &dst);
264 sample_to_mono(&src, &dst);
265 sample_to_mono(&src, &dst);
267 while (src < src_end);
269 else
271 #ifdef ROCKBOX_BIG_ENDIAN
272 /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
273 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
275 ci->memcpy(dst, src, PCM_CHUNK_SIZE);
276 #else
277 /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
278 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
280 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
284 *dst++ = swap_odd_even32(*src++);
285 *dst++ = swap_odd_even32(*src++);
286 *dst++ = swap_odd_even32(*src++);
287 *dst++ = swap_odd_even32(*src++);
288 *dst++ = swap_odd_even32(*src++);
289 *dst++ = swap_odd_even32(*src++);
290 *dst++ = swap_odd_even32(*src++);
291 *dst++ = swap_odd_even32(*src++);
293 while (src < src_end);
294 #endif
296 } /* chunk_to_aiff_format */
298 static bool init_encoder(void)
300 struct enc_inputs inputs;
301 struct enc_parameters params;
303 if (ci->enc_get_inputs == NULL ||
304 ci->enc_set_parameters == NULL ||
305 ci->enc_get_chunk == NULL ||
306 ci->enc_finish_chunk == NULL ||
307 ci->enc_get_pcm_data == NULL )
308 return false;
310 ci->enc_get_inputs(&inputs);
312 if (inputs.config->afmt != AFMT_AIFF)
313 return false;
315 sample_rate = inputs.sample_rate;
316 num_channels = inputs.num_channels;
317 err = 0;
319 /* configure the buffer system */
320 params.afmt = AFMT_AIFF;
321 enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2;
322 params.chunk_size = enc_size;
323 params.enc_sample_rate = sample_rate;
324 params.reserve_bytes = 0;
325 params.events_callback = enc_events_callback;
326 ci->enc_set_parameters(&params);
328 return true;
329 } /* init_encoder */
331 /* main codec entry point */
332 enum codec_status codec_main(void)
334 if (!init_encoder())
336 ci->enc_codec_loaded = -1;
337 return CODEC_ERROR;
340 /* main application waits for this flag during encoder loading */
341 ci->enc_codec_loaded = 1;
343 /* main encoding loop */
344 while(!ci->stop_encoder)
346 uint32_t *src;
348 while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
350 struct enc_chunk_hdr *chunk;
352 if (ci->stop_encoder)
353 break;
355 chunk = ci->enc_get_chunk();
356 chunk->enc_size = enc_size;
357 chunk->num_pcm = PCM_SAMP_PER_CHUNK;
358 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
360 chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data);
362 ci->enc_finish_chunk();
363 ci->yield();
366 ci->yield();
369 /* reset parameters to initial state */
370 ci->enc_set_parameters(NULL);
372 /* main application waits for this flag during encoder removing */
373 ci->enc_codec_loaded = 0;
375 return CODEC_OK;
376 } /* codec_start */
378 #endif /* ndef SIMULATOR */