1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 uint8_t riff_id
[4]; /* 00h - "RIFF" */
30 uint32_t riff_size
; /* 04h - sz following headers + data_size */
32 uint8_t format
[4]; /* 08h - "WAVE" */
33 uint8_t format_id
[4]; /* 0Ch - "fmt " */
34 uint32_t format_size
; /* 10h - 16 for PCM (sz format data) */
36 uint16_t audio_format
; /* 14h - 1=PCM */
37 uint16_t num_channels
; /* 16h - 1=M, 2=S, etc. */
38 uint32_t sample_rate
; /* 18h - HZ */
39 uint32_t byte_rate
; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
40 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 /* Not for audio_format=1 (PCM) */
43 /* unsigned short extra_param_size; 24h - size of extra data */
44 /* unsigned char *extra_params; */
46 uint8_t data_id
[4]; /* 24h - "data" */
47 uint32_t data_size
; /* 28h - num_samples*num_channels*bits_per_sample/8 */
48 /* unsigned char *data; 2ch - actual sound data */
49 } __attribute__((packed
));
51 #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
52 #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
53 #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
55 #define PCM_DEPTH_BYTES 2
56 #define PCM_DEPTH_BITS 16
57 #define PCM_SAMP_PER_CHUNK 2048
58 #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4)
60 static int num_channels IBSS_ATTR
;
61 static uint32_t sample_rate
;
62 static uint32_t enc_size
;
63 static int32_t err IBSS_ATTR
;
65 static const struct riff_header riff_header
=
68 { 'R', 'I', 'F', 'F' }, /* riff_id */
69 0, /* riff_size (*) */
71 { 'W', 'A', 'V', 'E' }, /* format */
72 { 'f', 'm', 't', ' ' }, /* format_id */
73 H_TO_LE32(16), /* format_size */
75 H_TO_LE16(1), /* audio_format */
76 0, /* num_channels (*) */
77 0, /* sample_rate (*) */
78 0, /* byte_rate (*) */
79 0, /* block_align (*) */
80 H_TO_LE16(PCM_DEPTH_BITS
), /* bits_per_sample */
82 { 'd', 'a', 't', 'a' }, /* data_id */
84 /* (*) updated during ENC_END_FILE event */
87 /* called version often - inline */
88 static inline bool is_file_data_ok(struct enc_file_event_data
*data
) ICODE_ATTR
;
89 static inline bool is_file_data_ok(struct enc_file_event_data
*data
)
91 return data
->rec_file
>= 0 && (long)data
->chunk
->flags
>= 0;
92 } /* is_file_data_ok */
94 /* called version often - inline */
95 static inline bool on_write_chunk(struct enc_file_event_data
*data
) ICODE_ATTR
;
96 static inline bool on_write_chunk(struct enc_file_event_data
*data
)
98 if (!is_file_data_ok(data
))
101 if (data
->chunk
->enc_data
== NULL
)
103 #ifdef ROCKBOX_HAS_LOGF
104 ci
->logf("wav enc: NULL data");
109 if (ci
->write(data
->rec_file
, data
->chunk
->enc_data
,
110 data
->chunk
->enc_size
) != (ssize_t
)data
->chunk
->enc_size
)
113 data
->num_pcm_samples
+= data
->chunk
->num_pcm
;
115 } /* on_write_chunk */
117 static bool on_start_file(struct enc_file_event_data
*data
)
119 if ((data
->chunk
->flags
& CHUNKF_ERROR
) || *data
->filename
== '\0')
122 data
->rec_file
= ci
->open(data
->filename
, O_RDWR
|O_CREAT
|O_TRUNC
);
124 if (data
->rec_file
< 0)
127 /* reset sample count */
128 data
->num_pcm_samples
= 0;
130 /* write template header */
131 if (ci
->write(data
->rec_file
, &riff_header
, sizeof (riff_header
))
132 != sizeof (riff_header
))
137 data
->new_enc_size
+= sizeof (riff_header
);
139 } /* on_start_file */
141 static bool on_end_file(struct enc_file_event_data
*data
)
143 /* update template header */
144 struct riff_header hdr
;
147 if (!is_file_data_ok(data
))
150 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
) != 0 ||
151 ci
->read(data
->rec_file
, &hdr
, sizeof (hdr
)) != sizeof (hdr
))
156 data_size
= data
->num_pcm_samples
*num_channels
*PCM_DEPTH_BYTES
;
159 hdr
.riff_size
= htole32(RIFF_FMT_HEADER_SIZE
+ RIFF_FMT_DATA_SIZE
160 + RIFF_DATA_HEADER_SIZE
+ data_size
);
163 hdr
.num_channels
= htole16(num_channels
);
164 hdr
.sample_rate
= htole32(sample_rate
);
165 hdr
.byte_rate
= htole32(sample_rate
*num_channels
* PCM_DEPTH_BYTES
);
166 hdr
.block_align
= htole16(num_channels
*PCM_DEPTH_BYTES
);
169 hdr
.data_size
= htole32(data_size
);
171 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
) != 0 ||
172 ci
->write(data
->rec_file
, &hdr
, sizeof (hdr
)) != sizeof (hdr
) ||
173 ci
->close(data
->rec_file
) != 0)
183 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
185 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
187 if (event
== ENC_WRITE_CHUNK
)
189 if (on_write_chunk((struct enc_file_event_data
*)data
))
192 else if (event
== ENC_START_FILE
)
194 if (on_start_file((struct enc_file_event_data
*)data
))
197 else if (event
== ENC_END_FILE
)
199 if (on_end_file((struct enc_file_event_data
*)data
))
207 ((struct enc_file_event_data
*)data
)->chunk
->flags
|= CHUNKF_ERROR
;
208 } /* enc_events_callback */
210 /* convert native pcm samples to wav format samples */
211 static inline void sample_to_mono(uint32_t **src
, uint32_t **dst
)
216 lr1
= (int16_t)lr1
+ (lr1
>> 16) + err
;
221 lr2
= (int16_t)lr2
+ (lr2
>> 16) + err
;
224 *(*dst
)++ = swap_odd_even_be32((lr1
<< 16) | (uint16_t)lr2
);
225 } /* sample_to_mono */
227 STATICIRAM
void chunk_to_wav_format(uint32_t *src
, uint32_t *dst
) ICODE_ATTR
;
228 STATICIRAM
void chunk_to_wav_format(uint32_t *src
, uint32_t *dst
)
230 if (num_channels
== 1)
233 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
234 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
235 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
238 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
239 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
240 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
242 uint32_t *src_end
= src
+ PCM_SAMP_PER_CHUNK
;
246 sample_to_mono(&src
, &dst
);
247 sample_to_mono(&src
, &dst
);
248 sample_to_mono(&src
, &dst
);
249 sample_to_mono(&src
, &dst
);
250 sample_to_mono(&src
, &dst
);
251 sample_to_mono(&src
, &dst
);
252 sample_to_mono(&src
, &dst
);
253 sample_to_mono(&src
, &dst
);
255 while (src
< src_end
);
259 #ifdef ROCKBOX_BIG_ENDIAN
260 /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
261 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
263 uint32_t *src_end
= src
+ PCM_SAMP_PER_CHUNK
;
267 *dst
++ = swap_odd_even32(*src
++);
268 *dst
++ = swap_odd_even32(*src
++);
269 *dst
++ = swap_odd_even32(*src
++);
270 *dst
++ = swap_odd_even32(*src
++);
271 *dst
++ = swap_odd_even32(*src
++);
272 *dst
++ = swap_odd_even32(*src
++);
273 *dst
++ = swap_odd_even32(*src
++);
274 *dst
++ = swap_odd_even32(*src
++);
276 while (src
< src_end
);
278 /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
279 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
281 ci
->memcpy(dst
, src
, PCM_CHUNK_SIZE
);
284 } /* chunk_to_wav_format */
286 static bool init_encoder(void)
288 struct enc_inputs inputs
;
289 struct enc_parameters params
;
291 if (ci
->enc_get_inputs
== NULL
||
292 ci
->enc_set_parameters
== NULL
||
293 ci
->enc_get_chunk
== NULL
||
294 ci
->enc_finish_chunk
== NULL
||
295 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
296 ci
->enc_pcm_buf_near_empty
== NULL
||
298 ci
->enc_get_pcm_data
== NULL
)
301 ci
->enc_get_inputs(&inputs
);
303 if (inputs
.config
->afmt
!= AFMT_PCM_WAV
)
306 sample_rate
= inputs
.sample_rate
;
307 num_channels
= inputs
.num_channels
;
310 /* configure the buffer system */
311 params
.afmt
= AFMT_PCM_WAV
;
312 enc_size
= PCM_CHUNK_SIZE
*inputs
.num_channels
/ 2;
313 params
.chunk_size
= enc_size
;
314 params
.enc_sample_rate
= sample_rate
;
315 params
.reserve_bytes
= 0;
316 params
.events_callback
= enc_events_callback
;
317 ci
->enc_set_parameters(¶ms
);
322 /* main codec entry point */
323 enum codec_status
codec_main(void)
325 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
331 ci
->enc_codec_loaded
= -1;
335 /* main application waits for this flag during encoder loading */
336 ci
->enc_codec_loaded
= 1;
338 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
343 /* main encoding loop */
344 while(!ci
->stop_encoder
)
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
)
355 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
356 if (!cpu_boosted
&& ci
->enc_pcm_buf_near_empty() == 0)
362 chunk
= ci
->enc_get_chunk();
363 chunk
->enc_size
= enc_size
;
364 chunk
->num_pcm
= PCM_SAMP_PER_CHUNK
;
365 chunk
->enc_data
= ENC_CHUNK_SKIP_HDR(chunk
->enc_data
, chunk
);
367 chunk_to_wav_format(src
, (uint32_t *)chunk
->enc_data
);
369 ci
->enc_finish_chunk();
373 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
374 if (cpu_boosted
&& ci
->enc_pcm_buf_near_empty() != 0)
376 ci
->cpu_boost(false);
383 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
384 if (cpu_boosted
) /* set initial boost state */
385 ci
->cpu_boost(false);
388 /* reset parameters to initial state */
389 ci
->enc_set_parameters(NULL
);
391 /* main application waits for this flag during encoder removing */
392 ci
->enc_codec_loaded
= 0;
397 #endif /* ndef SIMULATOR */