summaryrefslogtreecommitdiff
path: root/apps/codecs/wav_enc.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2006-11-06 18:07:30 +0000
committerMichael Sevakis <jethead71@rockbox.org>2006-11-06 18:07:30 +0000
commit0f5cb94aa4a334366a746fcbb22f3335ca413265 (patch)
tree8f89a96628c1810d51ee9816daf78edb8c76fcd4 /apps/codecs/wav_enc.c
parent0b22795e26ee09de14f6ac23219adeda12f2fd5b (diff)
downloadrockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.tar.gz
rockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.zip
Big Patch adds primarily: Samplerate and format selection to recording for SWCODEC. Supprort for samplerates changing in playback (just goes with the recording part inseparably). Samplerates to all encoders. Encoders can be configured individually on a menu specific to the encoder in the recording menu. File creation is delayed until flush time to reduce spinups when splitting. Misc: statusbar icons for numbers are individual digits to display any number. Audio buffer was rearranged to maximize memory available to recording and properly reinitialized when trashed. ColdFire PCM stuff moved to target tree to avoid a complicated mess when adding samplerate switching. Some needed API changes and to neaten up growing gap between hardware and software codecs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11452 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/wav_enc.c')
-rw-r--r--apps/codecs/wav_enc.c419
1 files changed, 322 insertions, 97 deletions
diff --git a/apps/codecs/wav_enc.c b/apps/codecs/wav_enc.c
index 5aabb5d8e8..974a903310 100644
--- a/apps/codecs/wav_enc.c
+++ b/apps/codecs/wav_enc.c
@@ -19,140 +19,364 @@
19 19
20#ifndef SIMULATOR 20#ifndef SIMULATOR
21 21
22#include <inttypes.h>
22#include "codeclib.h" 23#include "codeclib.h"
23 24
24CODEC_HEADER 25CODEC_ENC_HEADER
26
27#ifdef USE_IRAM
28extern char iramcopy[];
29extern char iramstart[];
30extern char iramend[];
31extern char iedata[];
32extern char iend[];
33#endif
34
35struct riff_header
36{
37 uint8_t riff_id[4]; /* 00h - "RIFF" */
38 uint32_t riff_size; /* 04h - sz following headers + data_size */
39 /* format header */
40 uint8_t format[4]; /* 08h - "WAVE" */
41 uint8_t format_id[4]; /* 0Ch - "fmt " */
42 uint32_t format_size; /* 10h - 16 for PCM (sz format data) */
43 /* format data */
44 uint16_t audio_format; /* 14h - 1=PCM */
45 uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */
46 uint32_t sample_rate; /* 18h - HZ */
47 uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
48 uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */
49 uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */
50 /* Not for audio_format=1 (PCM) */
51/* unsigned short extra_param_size; 24h - size of extra data */
52/* unsigned char *extra_params; */
53 /* data header */
54 uint8_t data_id[4]; /* 24h - "data" */
55 uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */
56/* unsigned char *data; 2ch - actual sound data */
57};
58
59#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
60#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
61#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
62
63#define PCM_DEPTH_BYTES 2
64#define PCM_DEPTH_BITS 16
65#define PCM_SAMP_PER_CHUNK 2048
66#define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4)
25 67
26static struct codec_api *ci; 68static struct codec_api *ci;
27static int enc_channels; 69static int num_channels;
70uint32_t sample_rate;
71uint32_t enc_size;
28 72
29#define CHUNK_SIZE 8192 73static const struct riff_header riff_header =
74{
75 /* "RIFF" header */
76 { 'R', 'I', 'F', 'F' }, /* riff_id */
77 0, /* riff_size (*) */
78 /* format header */
79 { 'W', 'A', 'V', 'E' }, /* format */
80 { 'f', 'm', 't', ' ' }, /* format_id */
81 H_TO_LE32(16), /* format_size */
82 /* format data */
83 H_TO_LE16(1), /* audio_format */
84 0, /* num_channels (*) */
85 0, /* sample_rate (*) */
86 0, /* byte_rate (*) */
87 0, /* block_align (*) */
88 H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */
89 /* data header */
90 { 'd', 'a', 't', 'a' }, /* data_id */
91 0 /* data_size (*) */
92 /* (*) updated during ENC_END_FILE event */
93};
30 94
31static unsigned char wav_header[44] = 95/* called version often - inline */
32{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, 96static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
33 0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0}; 97static inline bool is_file_data_ok(struct enc_file_event_data *data)
98{
99 return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
100} /* is_file_data_ok */
34 101
35static unsigned char wav_header_mono[44] = 102/* called version often - inline */
36{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, 103static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
37 0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0}; 104static inline bool on_write_chunk(struct enc_file_event_data *data)
105{
106 if (!is_file_data_ok(data))
107 return false;
38 108
39/* update file header info callback function (called by main application) */ 109 if (data->chunk->enc_data == NULL)
40void enc_set_header(void *head_buffer, /* ptr to the file header data */ 110 {
41 int head_size, /* size of this header data */ 111#ifdef ROCKBOX_HAS_LOGF
42 int num_pcm_samples, /* amount of processed pcm samples */ 112 ci->logf("wav enc: NULL data");
43 bool is_file_header) 113#endif
114 return true;
115 }
116
117 if (ci->write(data->rec_file, data->chunk->enc_data,
118 data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
119 return false;
120
121 data->num_pcm_samples += data->chunk->num_pcm;
122 return true;
123} /* on_write_chunk */
124
125static bool on_start_file(struct enc_file_event_data *data)
44{ 126{
45 int num_file_bytes = num_pcm_samples * 2 * enc_channels; 127 if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
128 return false;
129
130 data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
131
132 if (data->rec_file < 0)
133 return false;
134
135 /* reset sample count */
136 data->num_pcm_samples = 0;
46 137
47 if(is_file_header) 138 /* write template header */
139 if (ci->write(data->rec_file, &riff_header, sizeof (riff_header))
140 != sizeof (riff_header))
48 { 141 {
49 /* update file header before file closing */ 142 return false;
50 if((int)sizeof(wav_header) < head_size) 143 }
144
145 data->new_enc_size += sizeof (riff_header);
146 return true;
147} /* on_start_file */
148
149static bool on_end_file(struct enc_file_event_data *data)
150{
151 /* update template header */
152 struct riff_header hdr;
153 uint32_t data_size;
154
155 if (!is_file_data_ok(data))
156 return false;
157
158 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
159 ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
160 {
161 return false;
162 }
163
164 data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES;
165
166 /* "RIFF" header */
167 hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE
168 + RIFF_DATA_HEADER_SIZE + data_size);
169
170 /* format data */
171 hdr.num_channels = htole16(num_channels);
172 hdr.sample_rate = htole32(sample_rate);
173 hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES);
174 hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES);
175
176 /* data header */
177 hdr.data_size = htole32(data_size);
178
179 if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
180 ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
181 {
182 return false;
183 }
184
185 ci->fsync(data->rec_file);
186 ci->close(data->rec_file);
187 data->rec_file = -1;
188
189 return true;
190} /* on_end_file */
191
192static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR;
193static void enc_events_callback(enum enc_events event, void *data)
194{
195 if (event == ENC_WRITE_CHUNK)
196 {
197 if (on_write_chunk((struct enc_file_event_data *)data))
198 return;
199 }
200 else if (event == ENC_START_FILE)
201 {
202 if (on_start_file((struct enc_file_event_data *)data))
203 return;
204 }
205 else if (event == ENC_END_FILE)
206 {
207 if (on_end_file((struct enc_file_event_data *)data))
208 return;
209 }
210 else
211 {
212 return;
213 }
214
215 ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
216} /* enc_events_callback */
217
218/* convert native pcm samples to wav format samples */
219static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR;
220static void chunk_to_wav_format(uint32_t *src, uint32_t *dst)
221{
222 if (num_channels == 1)
223 {
224 /* On big endian:
225 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
226 * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
227 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
228 *
229 * On little endian:
230 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
231 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
232 * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
233 */
234 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
235
236 inline void to_mono(uint32_t **src, uint32_t **dst)
51 { 237 {
52 /* update wave header size entries: special to WAV format */ 238 int32_t lr1, lr2;
53 *(long*)(head_buffer+ 4) = htole32(num_file_bytes + 36); 239
54 *(long*)(head_buffer+40) = htole32(num_file_bytes); 240 lr1 = *(*src)++;
241 lr1 = ((int16_t)lr1 + (lr1 >> 16)) >> 1;
242
243 lr2 = *(*src)++;
244 lr2 = ((int16_t)lr2 + (lr2 >> 16)) >> 1;
245 *(*dst)++ = swap_odd_even_be32((lr1 << 16) | (uint16_t)lr2);
246 } /* to_mono */
247
248 do
249 {
250 to_mono(&src, &dst);
251 to_mono(&src, &dst);
252 to_mono(&src, &dst);
253 to_mono(&src, &dst);
254 to_mono(&src, &dst);
255 to_mono(&src, &dst);
256 to_mono(&src, &dst);
257 to_mono(&src, &dst);
55 } 258 }
259 while (src < src_end);
56 } 260 }
57} 261 else
262 {
263#ifdef ROCKBOX_BIG_ENDIAN
264 /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
265 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
266 */
267 uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
58 268
59/* main codec entry point */ 269 do
60enum codec_status codec_start(struct codec_api* api) 270 {
271 *dst++ = swap_odd_even32(*src++);
272 *dst++ = swap_odd_even32(*src++);
273 *dst++ = swap_odd_even32(*src++);
274 *dst++ = swap_odd_even32(*src++);
275 *dst++ = swap_odd_even32(*src++);
276 *dst++ = swap_odd_even32(*src++);
277 *dst++ = swap_odd_even32(*src++);
278 *dst++ = swap_odd_even32(*src++);
279 }
280 while (src < src_end);
281#else
282 /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
283 * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
284 */
285 ci->memcpy(dst, src, PCM_CHUNK_SIZE);
286#endif
287 }
288} /* chunk_to_wav_format */
289
290static bool init_encoder(void)
61{ 291{
62 int i; 292 struct enc_inputs inputs;
63 long lr; 293 struct enc_parameters params;
64 unsigned long t;
65 unsigned long *src;
66 unsigned long *dst;
67 int chunk_size, num_chunks, samp_per_chunk;
68 int enc_buffer_size;
69 int enc_quality;
70 bool cpu_boosted = true; /* start boosted */
71 294
72 ci = api; // copy to global api pointer 295 if (ci->enc_get_inputs == NULL ||
296 ci->enc_set_parameters == NULL ||
297 ci->enc_get_chunk == NULL ||
298 ci->enc_finish_chunk == NULL ||
299 ci->enc_pcm_buf_near_empty == NULL ||
300 ci->enc_get_pcm_data == NULL )
301 return false;
73 302
74 if(ci->enc_get_inputs == NULL || 303 ci->enc_get_inputs(&inputs);
75 ci->enc_set_parameters == NULL ||
76 ci->enc_alloc_chunk == NULL ||
77 ci->enc_free_chunk == NULL ||
78 ci->enc_wavbuf_near_empty == NULL ||
79 ci->enc_get_wav_data == NULL ||
80 ci->enc_set_header_callback == NULL )
81 return CODEC_ERROR;
82 304
83 ci->cpu_boost(true); 305 if (inputs.config->afmt != AFMT_PCM_WAV)
306 return false;
84 307
85 *ci->enc_set_header_callback = enc_set_header; 308 sample_rate = inputs.sample_rate;
86 ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); 309 num_channels = inputs.num_channels;
87 310
88 /* configure the buffer system */ 311 /* configure the buffer system */
89 chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; 312 params.afmt = AFMT_PCM_WAV;
90 num_chunks = enc_buffer_size / chunk_size; 313 enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2;
91 samp_per_chunk = CHUNK_SIZE / 4; 314 params.chunk_size = enc_size;
315 params.enc_sample_rate = sample_rate;
316 params.reserve_bytes = 0;
317 params.events_callback = enc_events_callback;
318 ci->enc_set_parameters(&params);
319
320 return true;
321} /* init_encoder */
322
323/* main codec entry point */
324enum codec_status codec_start(struct codec_api* api)
325{
326 bool cpu_boosted;
92 327
93 /* inform the main program about buffer dimensions and other params */ 328 ci = api; // copy to global api pointer
94 ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk, 329
95 (enc_channels == 2) ? wav_header : wav_header_mono, 330#ifdef USE_IRAM
96 sizeof(wav_header), AFMT_PCM_WAV); 331 ci->memcpy(iramstart, iramcopy, iramend - iramstart);
332 ci->memset(iedata, 0, iend - iedata);
333#endif
334
335 if (!init_encoder())
336 {
337 ci->enc_codec_loaded = -1;
338 return CODEC_ERROR;
339 }
97 340
98 /* main application waits for this flag during encoder loading */ 341 /* main application waits for this flag during encoder loading */
99 ci->enc_codec_loaded = true; 342 ci->enc_codec_loaded = 1;
343
344 ci->cpu_boost(true);
345 cpu_boosted = true;
100 346
101 /* main encoding loop */ 347 /* main encoding loop */
102 while(!ci->stop_codec) 348 while(!ci->stop_codec)
103 { 349 {
104 while((src = (unsigned long*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) 350 uint32_t *src;
351
352 while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
105 { 353 {
106 if(ci->stop_codec) 354 struct enc_chunk_hdr *chunk;
355
356 if (ci->stop_codec)
107 break; 357 break;
108 358
109 if(ci->enc_wavbuf_near_empty() == 0) 359 if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
110 { 360 {
111 if(!cpu_boosted) 361 ci->cpu_boost(true);
112 { 362 cpu_boosted = true;
113 ci->cpu_boost(true);
114 cpu_boosted = true;
115 }
116 } 363 }
117 364
118 dst = (unsigned long*)ci->enc_alloc_chunk(); 365 chunk = ci->enc_get_chunk();
119 *dst++ = CHUNK_SIZE * enc_channels / 2; /* set size info */ 366 chunk->enc_size = enc_size;
367 chunk->num_pcm = PCM_SAMP_PER_CHUNK;
368 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
120 369
121 if(enc_channels == 2) 370 chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
122 {
123 /* swap byte order & copy to destination */
124 for (i=0; i<CHUNK_SIZE/4; i++)
125 {
126 t = *src++;
127 *dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
128 }
129 }
130 else
131 {
132 /* mix left/right, swap byte order & copy to destination */
133 for (i=0; i<CHUNK_SIZE/8; i++)
134 {
135 lr = (long)*src++;
136 lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
137 t = (lr << 16);
138 lr = (long)*src++;
139 lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
140 t |= lr & 0xffff;
141 *dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
142 }
143 }
144 371
145 ci->enc_free_chunk(); 372 ci->enc_finish_chunk();
146 ci->yield(); 373 ci->yield();
147 } 374 }
148 375
149 if(ci->enc_wavbuf_near_empty()) 376 if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0)
150 { 377 {
151 if(cpu_boosted) 378 ci->cpu_boost(false);
152 { 379 cpu_boosted = false;
153 ci->cpu_boost(false);
154 cpu_boosted = false;
155 }
156 } 380 }
157 381
158 ci->yield(); 382 ci->yield();
@@ -162,11 +386,12 @@ enum codec_status codec_start(struct codec_api* api)
162 ci->cpu_boost(false); 386 ci->cpu_boost(false);
163 387
164 /* reset parameters to initial state */ 388 /* reset parameters to initial state */
165 ci->enc_set_parameters(0, 0, 0, 0, 0, 0); 389 ci->enc_set_parameters(NULL);
166 390
167 /* main application waits for this flag during encoder removing */ 391 /* main application waits for this flag during encoder removing */
168 ci->enc_codec_loaded = false; 392 ci->enc_codec_loaded = 0;
169 393
170 return CODEC_OK; 394 return CODEC_OK;
171} 395} /* codec_start */
172#endif 396
397#endif /* ndef SIMULATOR */