summaryrefslogtreecommitdiff
path: root/firmware/export
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-06-22 16:41:16 -0400
committerMichael Sevakis <jethead71@rockbox.org>2013-06-30 00:40:27 +0200
commit488813197292bd1db8d533d7b42c38852971c2e8 (patch)
tree07ea7247799b1b6b487c5ca73311380fc947700e /firmware/export
parenta9ea1a42695401334717f2e497a7f5576d87691d (diff)
downloadrockbox-488813197292bd1db8d533d7b42c38852971c2e8.tar.gz
rockbox-488813197292bd1db8d533d7b42c38852971c2e8.zip
Update software recording engine to latest codec interface.
Basically, just give it a good rewrite. Software codec recording can be implemented in a more straightforward and simple manner and made more robust through the better codec control now available. Encoded audio buffer uses a packed format instead of fixed-size chunks and uses smaller data headers leading to more efficient usage. The greatest benefit is with a VBR format like wavpack which needs to request a maximum size but only actually ends up committing part of that request. No guard buffers are used for either PCM or encoded audio. PCM is read into the codec's provided buffer and mono conversion done at that time in the core if required. Any highly-specialized sample conversion is still done within the codec itself, such as 32-bit (wavpack) or interleaved mono (mp3). There is no longer a separate filename array. All metadata goes onto the main encoded audio buffer, eliminating any predermined file limit on the buffer as well as not wasting the space for unused path queue slots. The core and codec interface is less awkward and a bit more sensible. Some less useful interface features were removed. Threads are kept on narrow code paths ie. the audio thread never calls encoding functions and the codec thread never calls file functions as before. Codecs no longer call file functions directly. Writes are buffered in the core and data written to storage in larger chunks to speed up flushing of data. In fact, codecs are no longer aware of the stream being a file at all and have no access to the fd. SPDIF frequency detection no longer requires a restart of recording or plugging the source before entering the screen. It will poll for changes and update when stopped or prerecording (which does discard now-invalid prerecorded data). I've seen to it that writing a proper header on full disk works when the format makes it reasonably practical to do so. Other cases may have incorrect data sizes but sample info will be in tact. File left that way may play anyway. mp3_enc.codec acquires the ability to write 'Info' headers with LAME tags to make it gapless (bonus). Change-Id: I670685166d5eb32ef58ef317f50b8af766ceb653 Reviewed-on: http://gerrit.rockbox.org/493 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested-by: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'firmware/export')
-rw-r--r--firmware/export/audio.h5
-rw-r--r--firmware/export/enc_base.h204
2 files changed, 73 insertions, 136 deletions
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index 293956cb37..24e8e9a0e7 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -212,10 +212,7 @@ unsigned long audio_num_recorded_bytes(void);
212 212
213#if CONFIG_CODEC == SWCODEC 213#if CONFIG_CODEC == SWCODEC
214/* SWCODEC recording functions */ 214/* SWCODEC recording functions */
215/* playback.c */ 215unsigned long audio_prerecorded_time(void);
216bool audio_load_encoder(int afmt);
217void audio_remove_encoder(void);
218unsigned char *audio_get_recording_buffer(size_t *buffer_size);
219#endif /* CONFIG_CODEC == SWCODEC */ 216#endif /* CONFIG_CODEC == SWCODEC */
220 217
221#endif /* HAVE_RECORDING */ 218#endif /* HAVE_RECORDING */
diff --git a/firmware/export/enc_base.h b/firmware/export/enc_base.h
index f5dfb65f2a..7228dc4c83 100644
--- a/firmware/export/enc_base.h
+++ b/firmware/export/enc_base.h
@@ -9,7 +9,7 @@
9 * 9 *
10 * Base declarations for working with software encoders 10 * Base declarations for working with software encoders
11 * 11 *
12 * Copyright (C) 2006 Michael Sevakis 12 * Copyright (C) 2006-2013 Michael Sevakis
13 * 13 *
14 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -24,7 +24,9 @@
24#ifndef ENC_BASE_H 24#ifndef ENC_BASE_H
25#define ENC_BASE_H 25#define ENC_BASE_H
26 26
27/** encoder config structures **/ 27#include <sys/types.h>
28
29/** Encoder config structures **/
28 30
29/** aiff_enc.codec **/ 31/** aiff_enc.codec **/
30struct aiff_enc_config 32struct aiff_enc_config
@@ -57,18 +59,22 @@ struct aiff_enc_config
57 59
58/* MPEG 1 */ 60/* MPEG 1 */
59#define MPEG1_SAMPR_CAPS (SAMPR_CAP_32 | SAMPR_CAP_48 | SAMPR_CAP_44) 61#define MPEG1_SAMPR_CAPS (SAMPR_CAP_32 | SAMPR_CAP_48 | SAMPR_CAP_44)
60#define MPEG1_BITR_CAPS (MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ 62#define MPEG1_BITR_CAPS (MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | \
61 MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ 63 MP3_BITR_CAP_48 | MP3_BITR_CAP_56 | \
62 MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ 64 MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \
63 MP3_BITR_CAP_160 | MP3_BITR_CAP_192 | MP3_BITR_CAP_224 | \ 65 MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | \
66 MP3_BITR_CAP_128 | MP3_BITR_CAP_160 | \
67 MP3_BITR_CAP_192 | MP3_BITR_CAP_224 | \
64 MP3_BITR_CAP_256 | MP3_BITR_CAP_320) 68 MP3_BITR_CAP_256 | MP3_BITR_CAP_320)
65 69
66/* MPEG 2 */ 70/* MPEG 2 */
67#define MPEG2_SAMPR_CAPS (SAMPR_CAP_22 | SAMPR_CAP_24 | SAMPR_CAP_16) 71#define MPEG2_SAMPR_CAPS (SAMPR_CAP_22 | SAMPR_CAP_24 | SAMPR_CAP_16)
68#define MPEG2_BITR_CAPS (MP3_BITR_CAP_8 | MP3_BITR_CAP_16 | MP3_BITR_CAP_24 | \ 72#define MPEG2_BITR_CAPS (MP3_BITR_CAP_8 | MP3_BITR_CAP_16 | \
69 MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ 73 MP3_BITR_CAP_24 | MP3_BITR_CAP_32 | \
70 MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ 74 MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \
71 MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ 75 MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | \
76 MP3_BITR_CAP_80 | MP3_BITR_CAP_96 | \
77 MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \
72 MP3_BITR_CAP_144 | MP3_BITR_CAP_160) 78 MP3_BITR_CAP_144 | MP3_BITR_CAP_160)
73 79
74#if 0 80#if 0
@@ -131,6 +137,7 @@ struct wavpack_enc_config
131#endif 137#endif
132}; 138};
133 139
140/* General config information about any encoder */
134struct encoder_config 141struct encoder_config
135{ 142{
136 union 143 union
@@ -149,144 +156,77 @@ struct encoder_config
149}; 156};
150 157
151/** Encoder chunk macros and definitions **/ 158/** Encoder chunk macros and definitions **/
152#define CHUNKF_START_FILE 0x0001ul /* This chunk starts a new file */
153#define CHUNKF_END_FILE 0x0002ul /* This chunk ends the current file */
154#define CHUNKF_PRERECORD 0x0010ul /* This chunk is prerecord data,
155 a new file could start anytime */
156#define CHUNKF_ABORT 0x0020ul /* Encoder should not finish this
157 chunk */
158#define CHUNKF_ERROR (~0ul ^ (~0ul >> 1)) /* An error has occured
159 (passed to/from encoder). Use the
160 sign bit to check (long)flags < 0. */
161#define CHUNKF_ALLFLAGS (0x0033ul | CHUNKF_ERROR)
162
163/* Header at the beginning of every encoder chunk */
164#ifdef DEBUG
165#define H_TO_BE32 htobe32
166#define ENC_CHUNK_MAGIC H_TO_BE32(('P' << 24) | ('T' << 16) | ('Y' << 8) | 'R')
167#endif
168struct enc_chunk_hdr
169{
170#ifdef DEBUG
171 unsigned long id; /* overflow detection - 'PTYR' - acronym for
172 "PTYR Tells You Right" ;) */
173#endif
174 unsigned long flags; /* in/out: flags used by encoder and file
175 writing */
176 size_t enc_size; /* out: amount of encoder data written to
177 chunk */
178 unsigned long num_pcm; /* out: number of PCM samples eaten during
179 processing
180 (<= size of allocated buffer) */
181 unsigned char *enc_data; /* out: pointer to enc_size_written bytes
182 of encoded audio data in chunk */
183 /* Encoder defined data follows header. Can be audio data + any other
184 stuff the encoder needs to handle on a per chunk basis */
185};
186 159
187/* Paranoia: be sure header size is 4-byte aligned */ 160/* What sort of data does the header describe? */
188#define ENC_CHUNK_HDR_SIZE \ 161enum CHUNK_T
189 ALIGN_UP_P2(sizeof (struct enc_chunk_hdr), 2)
190/* Skip the chunk header and return data */
191#define ENC_CHUNK_SKIP_HDR(t, hdr) \
192 ((typeof (t))((char *)hdr + ENC_CHUNK_HDR_SIZE))
193/* Cast p to struct enc_chunk_hdr * */
194#define ENC_CHUNK_HDR(p) \
195 ((struct enc_chunk_hdr *)(p))
196
197enum enc_events
198{ 162{
199 /* File writing events - data points to enc_file_event_data */ 163 CHUNK_T_DATA = 0x0, /* Encoded audio data */
200 ENC_START_FILE = 0, /* a new file has been opened and no data has yet 164 CHUNK_T_STREAM_START = 0x1, /* Stream start marker */
201 been written */ 165 CHUNK_T_STREAM_END = 0x2, /* Stream end marker */
202 ENC_WRITE_CHUNK, /* write the current chunk to disk */ 166 CHUNK_T_WRAP = 0x3 /* Buffer early wrap marker */
203 ENC_END_FILE, /* current file about to be closed and all valid
204 data has been written */
205 /* Encoder buffer events - data points to enc_buffer_event_data */
206 ENC_REC_NEW_STREAM, /* Take steps to finish current stream and start
207 new */
208}; 167};
209 168
210/** 169/* Header for every buffer slot and chunk */
211 * encoder can write extra data to the file such as headers or more encoded 170union enc_chunk_hdr
212 * samples and must update sizes and samples accordingly.
213 */
214struct enc_file_event_data
215{ 171{
216 struct enc_chunk_hdr *chunk; /* Current chunk */ 172 struct
217 size_t new_enc_size; /* New size of chunk */ 173 {
218 unsigned long new_num_pcm; /* New number of pcm in chunk */ 174 uint32_t type : 2; /* Chunk type (CHUNK_T_*) */
219 const char *filename; /* filename to open if ENC_START_FILE */ 175 uint32_t err : 1; /* Encoder error */
220 int rec_file; /* Current file or < 0 if none */ 176 uint32_t pre : 1; /* Chunk is prerecorded data */
221 unsigned long num_pcm_samples; /* Current pcm sample count written to 177 uint32_t aux0 : 1; /* Aux flag 0 - for encoder */
222 file so far. */ 178 uint32_t unused : 3; /* */
223}; 179 uint32_t size : 24; /* size of data */
180 };
181 uint32_t zero; /* Zero-out struct access */
182 intptr_t reserved1; /* Want it at least pointer-sized */
183} __attribute__((__may_alias__));
184
185#define ENC_HDR_SIZE (sizeof (union enc_chunk_hdr))
224 186
225/** 187/* When hdr.type is CHUNK_T_STREAM_START */
226 * encoder may add some data to the end of the last and start of the next 188struct enc_chunk_file
227 * but must never yield when called so any encoding done should be absolutely
228 * minimal.
229 */
230struct enc_buffer_event_data
231{ 189{
232 unsigned long flags; /* in: One or more of: 190 union enc_chunk_hdr hdr; /* This chunk's header */
233 * CHUNKF_PRERECORD 191 /* hdr.size = slot count of chunk */
234 * CHUNKF_END_FILE 192 char path[]; /* NULL-terminated path of file */
235 * CHUNKF_START_FILE 193} __attribute__((__may_alias__));
236 */
237 struct enc_chunk_hdr *pre_chunk; /* in: pointer to first prerecord
238 * chunk
239 */
240 struct enc_chunk_hdr *chunk; /* in,out: chunk were split occurs -
241 * first chunk of start
242 */
243};
244 194
245/** Callbacks called by encoder codec **/ 195/* If flags = CHUNK_T_STREAM_END, just the header exists */
246 196
247/* parameters passed to encoder by enc_get_inputs */ 197/* When hdr.type is CHUNK_T_DATA */
248struct enc_inputs 198struct enc_chunk_data
249{ 199{
250 unsigned long sample_rate; /* out - pcm frequency */ 200 union enc_chunk_hdr hdr; /* IN,OUT: This chunk's header */
251 int num_channels; /* out - number of audio channels */ 201 /* hdr.size = total size of data[] */
252 int rec_mono_mode; /* out - how to create mono */ 202 uint32_t pcm_count; /* OUT: number of PCM samples encoded */
253 struct encoder_config *config; /* out - encoder settings */ 203 uint8_t data[]; /* OUT: encoded audio data */
254}; 204} __attribute__((__may_alias__));
255 205
256void enc_get_inputs(struct enc_inputs *inputs); 206/* CHUNK_T_STREAM_END and CHUNK_T_WRAP consist of only the header */
257 207
258/* parameters pass from encoder to enc_set_parameters */ 208#define ENC_FILE_HDR(hdr) ((struct enc_chunk_file *)(hdr))
259struct enc_parameters 209#define ENC_DATA_HDR(hdr) ((struct enc_chunk_data *)(hdr))
210
211/* Audio and encoder stream parameters */
212struct enc_inputs
260{ 213{
261 /* IN parameters */ 214 /* IN parameters */
262 int afmt; /* AFMT_* id - sanity checker */ 215 unsigned long sample_rate; /* PCM samplerate setting */
263 size_t chunk_size; /* max chunk size required */ 216 int num_channels; /* Number of audio channels */
264 unsigned long enc_sample_rate; /* actual sample rate used by encoder 217 struct encoder_config *config; /* Encoder settings */
265 (for recorded time calculation) */
266 size_t reserve_bytes; /* number of bytes to reserve immediately
267 following chunks */
268 void (*events_callback)(enum enc_events event,
269 void *data); /* pointer to events callback */
270 /* OUT parameters */
271 unsigned char *enc_buffer; /* pointer to enc_buffer */
272 size_t buf_chunk_size; /* size of chunks in enc_buffer */
273 int num_chunks; /* number of chunks allotted to encoder */
274 unsigned char *reserve_buffer; /* pointer to reserve_bytes bytes */
275};
276 218
277/* set the encoder dimensions - called by encoder codec at initialization 219 /* IN,OUT parameters */
278 and termination */ 220 unsigned long enc_sample_rate; /* Actual sample rate accepted by encoder
279void enc_set_parameters(struct enc_parameters *params); 221 (for recorded time calculation) */
280/* returns pointer to next write chunk in circular buffer */ 222};
281struct enc_chunk_hdr * enc_get_chunk(void);
282/* releases the current chunk into the available chunks */
283void enc_finish_chunk(void);
284 223
285#define PCM_MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ 224enum enc_callback_reason
225{
226 ENC_CB_INPUTS, /* 'params' is struct enc_inputs * */
227 ENC_CB_STREAM, /* 'params' is union enc_chunk_hdr * */
228};
286 229
287/* passes a pointer to next chunk of unprocessed wav data */ 230typedef int (* enc_callback_t)(enum enc_callback_reason reason, void *params);
288unsigned char * enc_get_pcm_data(size_t size);
289/* puts some pcm data back in the queue */
290size_t enc_unget_pcm_data(size_t size);
291 231
292#endif /* ENC_BASE_H */ 232#endif /* ENC_BASE_H */