1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Antonius Hellmann
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
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
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
42 uint32_t offset
; /* 2eh - data offset from end of header */
43 uint32_t block_size
; /* 32h - pcm data alignment */
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 htobe32(18), /* comm_size */
60 0, /* num_channels (*) */
61 0, /* num_sample_frames (*) */
62 htobe16(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 htobe32(0), /* offset */
67 htobe32(0), /* block_size */
70 /* (*) updated when finalizing file */
72 static int num_channels IBSS_ATTR
;
73 static int rec_mono_mode IBSS_ATTR
;
74 static uint32_t sample_rate
;
75 static uint32_t enc_size
;
76 static int32_t err IBSS_ATTR
;
78 /* convert unsigned 32 bit value to 80-bit floating point number */
79 STATICIRAM
void uint32_h_to_ieee754_extended_be(uint8_t f
[10], uint32_t l
)
81 STATICIRAM
void uint32_h_to_ieee754_extended_be(uint8_t f
[10], uint32_t l
)
90 for (exp
= 30; (l
& (1ul << 31)) == 0; exp
--)
93 /* sign always zero - bit 79 */
94 /* exponent is 0-31 (normalized: 31 - shift + 16383) - bits 64-78 */
97 /* mantissa is value left justified with most significant non-zero
98 bit stored in bit 63 - bits 0-63 */
99 f
[2] = (uint8_t)(l
>> 24);
100 f
[3] = (uint8_t)(l
>> 16);
101 f
[4] = (uint8_t)(l
>> 8);
102 f
[5] = (uint8_t)(l
>> 0);
103 } /* uint32_h_to_ieee754_extended_be */
105 /* called version often - inline */
106 static inline bool is_file_data_ok(struct enc_file_event_data
*data
) ICODE_ATTR
;
107 static inline bool is_file_data_ok(struct enc_file_event_data
*data
)
109 return data
->rec_file
>= 0 && (long)data
->chunk
->flags
>= 0;
110 } /* is_file_data_ok */
112 /* called version often - inline */
113 static inline bool on_write_chunk(struct enc_file_event_data
*data
) ICODE_ATTR
;
114 static inline bool on_write_chunk(struct enc_file_event_data
*data
)
116 if (!is_file_data_ok(data
))
119 if (data
->chunk
->enc_data
== NULL
)
121 #ifdef ROCKBOX_HAS_LOGF
122 ci
->logf("aiff enc: NULL data");
127 if (ci
->write(data
->rec_file
, data
->chunk
->enc_data
,
128 data
->chunk
->enc_size
) != (ssize_t
)data
->chunk
->enc_size
)
131 data
->num_pcm_samples
+= data
->chunk
->num_pcm
;
133 } /* on_write_chunk */
135 static bool on_start_file(struct enc_file_event_data
*data
)
137 if ((data
->chunk
->flags
& CHUNKF_ERROR
) || *data
->filename
== '\0')
140 data
->rec_file
= ci
->open(data
->filename
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
142 if (data
->rec_file
< 0)
145 /* reset sample count */
146 data
->num_pcm_samples
= 0;
148 /* write template headers */
149 if (ci
->write(data
->rec_file
, &aiff_header
, sizeof (aiff_header
))
150 != sizeof (aiff_header
))
155 data
->new_enc_size
+= sizeof(aiff_header
);
157 } /* on_start_file */
159 static bool on_end_file(struct enc_file_event_data
*data
)
161 /* update template headers */
162 struct aiff_header hdr
;
165 if (!is_file_data_ok(data
))
168 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
) != 0 ||
169 ci
->read(data
->rec_file
, &hdr
, sizeof (hdr
)) != sizeof (hdr
))
174 data_size
= data
->num_pcm_samples
*num_channels
*PCM_DEPTH_BYTES
;
177 hdr
.form_size
= htobe32(data_size
+ sizeof (hdr
) - 8);
180 hdr
.num_channels
= htobe16(num_channels
);
181 hdr
.num_sample_frames
= htobe32(data
->num_pcm_samples
);
182 uint32_h_to_ieee754_extended_be(hdr
.sample_rate
, sample_rate
);
185 hdr
.ssnd_size
= htobe32(data_size
+ 8);
187 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
) != 0 ||
188 ci
->write(data
->rec_file
, &hdr
, sizeof (hdr
)) != sizeof (hdr
) ||
189 ci
->close(data
->rec_file
) != 0)
199 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
201 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
205 case ENC_WRITE_CHUNK
:
206 if (on_write_chunk((struct enc_file_event_data
*)data
))
212 if (on_start_file((struct enc_file_event_data
*)data
))
218 if (on_end_file((struct enc_file_event_data
*)data
))
227 /* Something failed above. Signal error back to core. */
228 ((struct enc_file_event_data
*)data
)->chunk
->flags
|= CHUNKF_ERROR
;
229 } /* enc_events_callback */
231 /* convert native pcm samples to aiff format samples */
232 static inline void sample_to_mono(uint32_t **src
, uint32_t **dst
)
236 switch(rec_mono_mode
)
256 lr1
= (int16_t)lr1
+ (lr1
>> 16) + err
;
261 lr2
= (int16_t)lr2
+ (lr2
>> 16) + err
;
266 *(*dst
)++ = htobe32((lr1
<< 16) | (uint16_t)lr2
);
267 } /* sample_to_mono */
269 STATICIRAM
void chunk_to_aiff_format(uint32_t *src
, uint32_t *dst
) ICODE_ATTR
;
270 STATICIRAM
void chunk_to_aiff_format(uint32_t *src
, uint32_t *dst
)
272 if (num_channels
== 1)
275 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
276 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
277 * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
280 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
281 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
282 * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
284 uint32_t *src_end
= src
+ PCM_SAMP_PER_CHUNK
;
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
);
297 while (src
< src_end
);
301 #ifdef ROCKBOX_BIG_ENDIAN
302 /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
303 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
305 ci
->memcpy(dst
, src
, PCM_CHUNK_SIZE
);
307 /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
308 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
310 uint32_t *src_end
= src
+ PCM_SAMP_PER_CHUNK
;
314 *dst
++ = swap_odd_even32(*src
++);
315 *dst
++ = swap_odd_even32(*src
++);
316 *dst
++ = swap_odd_even32(*src
++);
317 *dst
++ = swap_odd_even32(*src
++);
318 *dst
++ = swap_odd_even32(*src
++);
319 *dst
++ = swap_odd_even32(*src
++);
320 *dst
++ = swap_odd_even32(*src
++);
321 *dst
++ = swap_odd_even32(*src
++);
323 while (src
< src_end
);
326 } /* chunk_to_aiff_format */
328 static bool init_encoder(void)
330 struct enc_inputs inputs
;
331 struct enc_parameters params
;
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
)
340 ci
->enc_get_inputs(&inputs
);
342 if (inputs
.config
->afmt
!= AFMT_AIFF
)
345 sample_rate
= inputs
.sample_rate
;
346 num_channels
= inputs
.num_channels
;
347 rec_mono_mode
= inputs
.rec_mono_mode
;
350 /* configure the buffer system */
351 params
.afmt
= AFMT_AIFF
;
352 enc_size
= PCM_CHUNK_SIZE
*inputs
.num_channels
/ 2;
353 params
.chunk_size
= enc_size
;
354 params
.enc_sample_rate
= sample_rate
;
355 params
.reserve_bytes
= 0;
356 params
.events_callback
= enc_events_callback
;
357 ci
->enc_set_parameters(¶ms
);
362 /* main codec entry point */
363 enum codec_status
codec_main(void)
367 ci
->enc_codec_loaded
= -1;
371 /* main application waits for this flag during encoder loading */
372 ci
->enc_codec_loaded
= 1;
374 /* main encoding loop */
375 while(!ci
->stop_encoder
)
379 while ((src
= (uint32_t *)ci
->enc_get_pcm_data(PCM_CHUNK_SIZE
)) != NULL
)
381 struct enc_chunk_hdr
*chunk
;
383 if (ci
->stop_encoder
)
386 chunk
= ci
->enc_get_chunk();
387 chunk
->enc_size
= enc_size
;
388 chunk
->num_pcm
= PCM_SAMP_PER_CHUNK
;
389 chunk
->enc_data
= ENC_CHUNK_SKIP_HDR(chunk
->enc_data
, chunk
);
391 chunk_to_aiff_format(src
, (uint32_t *)chunk
->enc_data
);
393 ci
->enc_finish_chunk();
400 /* reset parameters to initial state */
401 ci
->enc_set_parameters(NULL
);
403 /* main application waits for this flag during encoder removing */
404 ci
->enc_codec_loaded
= 0;