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 ****************************************************************************/
25 #include "libwavpack/wavpack.h"
32 uint8_t type
; /* Type of metadata */
33 uint8_t word_size
; /* Size of metadata in words */
34 } __attribute__((packed
)) WavpackMetadataHeader
;
38 uint8_t riff_id
[4]; /* 00h - "RIFF" */
39 uint32_t riff_size
; /* 04h - sz following headers + data_size */
41 uint8_t format
[4]; /* 08h - "WAVE" */
42 uint8_t format_id
[4]; /* 0Ch - "fmt " */
43 uint32_t format_size
; /* 10h - 16 for PCM (sz format data) */
45 uint16_t audio_format
; /* 14h - 1=PCM */
46 uint16_t num_channels
; /* 16h - 1=M, 2=S, etc. */
47 uint32_t sample_rate
; /* 18h - HZ */
48 uint32_t byte_rate
; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
49 uint16_t block_align
; /* 20h - num_channels*bits_per_samples/8 */
50 uint16_t bits_per_sample
; /* 22h - 8=8 bits, 16=16 bits, etc. */
51 /* Not for audio_format=1 (PCM) */
52 /* unsigned short extra_param_size; 24h - size of extra data */
53 /* unsigned char *extra_params; */
55 uint8_t data_id
[4]; /* 24h - "data" */
56 uint32_t data_size
; /* 28h - num_samples*num_channels*bits_per_sample/8 */
57 /* unsigned char *data; 2ch - actual sound data */
58 } __attribute__((packed
));
60 #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
61 #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
62 #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
64 #define PCM_DEPTH_BITS 16
65 #define PCM_DEPTH_BYTES 2
66 #define PCM_SAMP_PER_CHUNK 5000
67 #define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK)
70 static int8_t input_buffer
[PCM_CHUNK_SIZE
*2] IBSS_ATTR
;
71 static WavpackConfig config IBSS_ATTR
;
72 static WavpackContext
*wpc
;
73 static int32_t data_size
, input_size
, input_step IBSS_ATTR
;
74 static int32_t err IBSS_ATTR
;
76 static const WavpackMetadataHeader wvpk_mdh
=
79 sizeof (struct riff_header
) / sizeof (uint16_t),
82 static const struct riff_header riff_header
=
85 { 'R', 'I', 'F', 'F' }, /* riff_id */
86 0, /* riff_size (*) */
88 { 'W', 'A', 'V', 'E' }, /* format */
89 { 'f', 'm', 't', ' ' }, /* format_id */
90 H_TO_LE32(16), /* format_size */
92 H_TO_LE16(1), /* audio_format */
93 0, /* num_channels (*) */
94 0, /* sample_rate (*) */
95 0, /* byte_rate (*) */
96 0, /* block_align (*) */
97 H_TO_LE16(PCM_DEPTH_BITS
), /* bits_per_sample */
99 { 'd', 'a', 't', 'a' }, /* data_id */
100 0 /* data_size (*) */
101 /* (*) updated during ENC_END_FILE event */
104 static inline void sample_to_int32_mono(int32_t **src
, int32_t **dst
)
106 int32_t t
= *(*src
)++;
107 /* endianness irrelevant */
108 t
= (int16_t)t
+ (t
>> 16) + err
;
111 } /* sample_to_int32_mono */
113 static inline void sample_to_int32_stereo(int32_t **src
, int32_t **dst
)
115 int32_t t
= *(*src
)++;
116 #ifdef ROCKBOX_BIG_ENDIAN
117 *(*dst
)++ = t
>> 16, *(*dst
)++ = (int16_t)t
;
119 *(*dst
)++ = (int16_t)t
, *(*dst
)++ = t
>> 16;
121 } /* sample_to_int32_stereo */
123 STATICIRAM
void chunk_to_int32(int32_t *src
) ICODE_ATTR
;
124 STATICIRAM
void chunk_to_int32(int32_t *src
)
126 int32_t *src_end
, *dst
;
128 /* copy to IRAM before converting data */
129 dst
= (int32_t *)input_buffer
+ PCM_SAMP_PER_CHUNK
;
130 src_end
= dst
+ PCM_SAMP_PER_CHUNK
;
132 memcpy(dst
, src
, PCM_CHUNK_SIZE
);
136 src_end
= src
+ PCM_SAMP_PER_CHUNK
;
139 dst
= (int32_t *)input_buffer
;
141 if (config
.num_channels
== 1)
144 * |llllllllllllllll|rrrrrrrrrrrrrrrr| =>
145 * |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm|
149 /* read 10 longs and write 10 longs */
150 sample_to_int32_mono(&src
, &dst
);
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 sample_to_int32_mono(&src
, &dst
);
159 sample_to_int32_mono(&src
, &dst
);
161 while(src
< src_end
);
168 * |llllllllllllllll|rrrrrrrrrrrrrrrr| =>
169 * |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
173 /* read 10 longs and write 20 longs */
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 sample_to_int32_stereo(&src
, &dst
);
183 sample_to_int32_stereo(&src
, &dst
);
185 while (src
< src_end
);
189 } /* chunk_to_int32 */
191 /* called very often - inline */
192 static inline bool is_file_data_ok(struct enc_file_event_data
*data
) ICODE_ATTR
;
193 static inline bool is_file_data_ok(struct enc_file_event_data
*data
)
195 return data
->rec_file
>= 0 && (long)data
->chunk
->flags
>= 0;
196 } /* is_file_data_ok */
198 /* called very often - inline */
199 static inline bool on_write_chunk(struct enc_file_event_data
*data
) ICODE_ATTR
;
200 static inline bool on_write_chunk(struct enc_file_event_data
*data
)
202 if (!is_file_data_ok(data
))
205 if (data
->chunk
->enc_data
== NULL
)
207 #ifdef ROCKBOX_HAS_LOGF
208 ci
->logf("wvpk enc: NULL data");
213 /* update timestamp (block_index) */
214 ((WavpackHeader
*)data
->chunk
->enc_data
)->block_index
=
215 htole32(data
->num_pcm_samples
);
217 if (ci
->write(data
->rec_file
, data
->chunk
->enc_data
,
218 data
->chunk
->enc_size
) != (ssize_t
)data
->chunk
->enc_size
)
221 data
->num_pcm_samples
+= data
->chunk
->num_pcm
;
223 } /* on_write_chunk */
225 static bool on_start_file(struct enc_file_event_data
*data
)
227 if ((data
->chunk
->flags
& CHUNKF_ERROR
) || *data
->filename
== '\0')
230 data
->rec_file
= ci
->open(data
->filename
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
232 if (data
->rec_file
< 0)
235 /* reset sample count */
236 data
->num_pcm_samples
= 0;
238 /* write template headers */
239 if (ci
->write(data
->rec_file
, &wvpk_mdh
, sizeof (wvpk_mdh
))
240 != sizeof (wvpk_mdh
) ||
241 ci
->write(data
->rec_file
, &riff_header
, sizeof (riff_header
))
242 != sizeof (riff_header
))
247 data
->new_enc_size
+= sizeof(wvpk_mdh
) + sizeof(riff_header
);
249 } /* on_start_file */
251 static bool on_end_file(struct enc_file_event_data
*data
)
255 WavpackMetadataHeader wpmdh
;
256 struct riff_header rhdr
;
258 } __attribute__ ((packed
)) h
;
262 if (data
->rec_file
< 0)
263 return false; /* file already closed, nothing more we can do */
265 /* always _try_ to write the file header, even on error */
267 /* read template headers at start */
268 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
) != 0 ||
269 ci
->read(data
->rec_file
, &h
, sizeof (h
)) != sizeof (h
))
272 data_size
= data
->num_pcm_samples
*config
.num_channels
*PCM_DEPTH_BYTES
;
274 /** "RIFF" header **/
275 h
.rhdr
.riff_size
= htole32(RIFF_FMT_HEADER_SIZE
+
276 RIFF_FMT_DATA_SIZE
+ RIFF_DATA_HEADER_SIZE
+ data_size
);
279 h
.rhdr
.num_channels
= htole16(config
.num_channels
);
280 h
.rhdr
.sample_rate
= htole32(config
.sample_rate
);
281 h
.rhdr
.byte_rate
= htole32(config
.sample_rate
*config
.num_channels
*
283 h
.rhdr
.block_align
= htole16(config
.num_channels
*PCM_DEPTH_BYTES
);
286 h
.rhdr
.data_size
= htole32(data_size
);
288 /** Wavpack header **/
289 h
.wph
.ckSize
= htole32(letoh32(h
.wph
.ckSize
) + sizeof (h
.wpmdh
)
291 h
.wph
.total_samples
= htole32(data
->num_pcm_samples
);
293 /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */
294 if (ci
->lseek(data
->rec_file
, 0, SEEK_SET
)
296 ci
->write(data
->rec_file
, &h
.wph
, sizeof (h
.wph
))
298 ci
->write(data
->rec_file
, &h
.wpmdh
, sizeof (h
.wpmdh
))
299 != sizeof (h
.wpmdh
) ||
300 ci
->write(data
->rec_file
, &h
.rhdr
, sizeof (h
.rhdr
))
301 != sizeof (h
.rhdr
) ||
302 ci
->close(data
->rec_file
) != 0 )
312 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
314 STATICIRAM
void enc_events_callback(enum enc_events event
, void *data
)
318 case ENC_WRITE_CHUNK
:
319 if (on_write_chunk((struct enc_file_event_data
*)data
))
325 /* write metadata header and RIFF header */
326 if (on_start_file((struct enc_file_event_data
*)data
))
332 if (on_end_file((struct enc_file_event_data
*)data
))
341 /* Something failed above. Signal error back to core. */
342 ((struct enc_file_event_data
*)data
)->chunk
->flags
|= CHUNKF_ERROR
;
343 } /* enc_events_callback */
345 static bool init_encoder(void)
347 struct enc_inputs inputs
;
348 struct enc_parameters params
;
352 if (ci
->enc_get_inputs
== NULL
||
353 ci
->enc_set_parameters
== NULL
||
354 ci
->enc_get_chunk
== NULL
||
355 ci
->enc_finish_chunk
== NULL
||
356 ci
->enc_get_pcm_data
== NULL
||
357 ci
->enc_unget_pcm_data
== NULL
)
360 ci
->enc_get_inputs(&inputs
);
362 if (inputs
.config
->afmt
!= AFMT_WAVPACK
)
365 memset(&config
, 0, sizeof (config
));
366 config
.bits_per_sample
= PCM_DEPTH_BITS
;
367 config
.bytes_per_sample
= PCM_DEPTH_BYTES
;
368 config
.sample_rate
= inputs
.sample_rate
;
369 config
.num_channels
= inputs
.num_channels
;
371 wpc
= WavpackOpenFileOutput ();
373 if (!WavpackSetConfiguration(wpc
, &config
, -1))
378 /* configure the buffer system */
379 params
.afmt
= AFMT_WAVPACK
;
380 input_size
= PCM_CHUNK_SIZE
*inputs
.num_channels
/ 2;
381 data_size
= 105*input_size
/ 100;
383 input_step
= input_size
/ 4;
384 params
.chunk_size
= data_size
;
385 params
.enc_sample_rate
= inputs
.sample_rate
;
386 params
.reserve_bytes
= 0;
387 params
.events_callback
= enc_events_callback
;
389 ci
->enc_set_parameters(¶ms
);
394 enum codec_status
codec_main(void)
396 /* initialize params and config */
399 ci
->enc_codec_loaded
= -1;
403 /* main application waits for this flag during encoder loading */
404 ci
->enc_codec_loaded
= 1;
406 /* main encoding loop */
407 while(!ci
->stop_encoder
)
411 while ((src
= ci
->enc_get_pcm_data(PCM_CHUNK_SIZE
)) != NULL
)
413 struct enc_chunk_hdr
*chunk
;
423 chunk
= ci
->enc_get_chunk();
425 /* reset counts and pointer */
428 chunk
->enc_data
= NULL
;
430 dst
= ENC_CHUNK_SKIP_HDR(dst
, chunk
);
432 WavpackStartBlock(wpc
, dst
, dst
+ data_size
);
434 chunk_to_int32((uint32_t*)src
);
436 src_end
= src
+ input_size
;
438 /* encode chunk in four steps yielding between each */
441 if (WavpackPackSamples(wpc
, (int32_t *)src
,
442 PCM_SAMP_PER_CHUNK
/4))
444 chunk
->num_pcm
+= PCM_SAMP_PER_CHUNK
/4;
446 /* could've been stopped in some way */
447 abort_chunk
= ci
->stop_encoder
||
448 (chunk
->flags
& CHUNKF_ABORT
);
453 while (!abort_chunk
&& src
< src_end
);
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 */
461 chunk
->enc_size
= WavpackFinishBlock(wpc
);
462 ci
->enc_finish_chunk();
469 /* reset parameters to initial state */
470 ci
->enc_set_parameters(NULL
);
472 /* main application waits for this flag during encoder removing */
473 ci
->enc_codec_loaded
= 0;
478 #endif /* ndef SIMULATOR */