diff options
58 files changed, 4664 insertions, 2676 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index e1d8e7bbdd..ccfc7fa280 100644 --- a/apps/SOURCES +++ b/apps/SOURCES | |||
@@ -73,6 +73,9 @@ pcmbuf.c | |||
73 | playback.c | 73 | playback.c |
74 | codecs.c | 74 | codecs.c |
75 | dsp.c | 75 | dsp.c |
76 | #ifdef HAVE_RECORDING | ||
77 | enc_config.c | ||
78 | #endif | ||
76 | eq.c | 79 | eq.c |
77 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 80 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) |
78 | dsp_cf.S | 81 | dsp_cf.S |
diff --git a/apps/codecs.c b/apps/codecs.c index f33957eba2..4491dadf49 100644 --- a/apps/codecs.c +++ b/apps/codecs.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include "sound.h" | 50 | #include "sound.h" |
51 | #include "database.h" | 51 | #include "database.h" |
52 | #include "splash.h" | 52 | #include "splash.h" |
53 | #include "general.h" | ||
53 | 54 | ||
54 | #ifdef SIMULATOR | 55 | #ifdef SIMULATOR |
55 | #if CONFIG_CODEC == SWCODEC | 56 | #if CONFIG_CODEC == SWCODEC |
@@ -104,6 +105,7 @@ struct codec_api ci = { | |||
104 | PREFIX(remove), | 105 | PREFIX(remove), |
105 | PREFIX(rename), | 106 | PREFIX(rename), |
106 | PREFIX(ftruncate), | 107 | PREFIX(ftruncate), |
108 | PREFIX(fsync), | ||
107 | fdprintf, | 109 | fdprintf, |
108 | read_line, | 110 | read_line, |
109 | settings_parseline, | 111 | settings_parseline, |
@@ -187,6 +189,7 @@ struct codec_api ci = { | |||
187 | get_time, | 189 | get_time, |
188 | set_time, | 190 | set_time, |
189 | plugin_get_audio_buffer, | 191 | plugin_get_audio_buffer, |
192 | round_value_to_list32, | ||
190 | 193 | ||
191 | #if defined(DEBUG) || defined(SIMULATOR) | 194 | #if defined(DEBUG) || defined(SIMULATOR) |
192 | debugf, | 195 | debugf, |
@@ -213,11 +216,11 @@ struct codec_api ci = { | |||
213 | false, | 216 | false, |
214 | enc_get_inputs, | 217 | enc_get_inputs, |
215 | enc_set_parameters, | 218 | enc_set_parameters, |
216 | enc_alloc_chunk, | 219 | enc_get_chunk, |
217 | enc_free_chunk, | 220 | enc_finish_chunk, |
218 | enc_wavbuf_near_empty, | 221 | enc_pcm_buf_near_empty, |
219 | enc_get_wav_data, | 222 | enc_get_pcm_data, |
220 | &enc_set_header_callback, | 223 | enc_unget_pcm_data |
221 | #endif | 224 | #endif |
222 | 225 | ||
223 | /* new stuff at the end, sort into place next time | 226 | /* new stuff at the end, sort into place next time |
@@ -225,10 +228,10 @@ struct codec_api ci = { | |||
225 | 228 | ||
226 | }; | 229 | }; |
227 | 230 | ||
228 | void codec_get_full_path(char *path, const char *codec_fn) | 231 | void codec_get_full_path(char *path, const char *codec_root_fn) |
229 | { | 232 | { |
230 | /* Create full codec path */ | 233 | snprintf(path, MAX_PATH-1, CODECS_DIR "/%s." CODEC_EXTENSION, |
231 | snprintf(path, MAX_PATH-1, CODECS_DIR "/%s", codec_fn); | 234 | codec_root_fn); |
232 | } | 235 | } |
233 | 236 | ||
234 | int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, | 237 | int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, |
@@ -254,7 +257,11 @@ int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, | |||
254 | hdr = (struct codec_header *)codecbuf; | 257 | hdr = (struct codec_header *)codecbuf; |
255 | 258 | ||
256 | if (size <= (signed)sizeof(struct codec_header) | 259 | if (size <= (signed)sizeof(struct codec_header) |
257 | || hdr->magic != CODEC_MAGIC | 260 | || (hdr->magic != CODEC_MAGIC |
261 | #ifdef HAVE_RECORDING | ||
262 | && hdr->magic != CODEC_ENC_MAGIC | ||
263 | #endif | ||
264 | ) | ||
258 | || hdr->target_id != TARGET_ID | 265 | || hdr->target_id != TARGET_ID |
259 | || hdr->load_addr != codecbuf | 266 | || hdr->load_addr != codecbuf |
260 | || hdr->end_addr > codecbuf + CODEC_SIZE) | 267 | || hdr->end_addr > codecbuf + CODEC_SIZE) |
diff --git a/apps/codecs.h b/apps/codecs.h index 96804a889b..0b90ef9c19 100644 --- a/apps/codecs.h +++ b/apps/codecs.h | |||
@@ -46,7 +46,7 @@ | |||
46 | #include "profile.h" | 46 | #include "profile.h" |
47 | #endif | 47 | #endif |
48 | #if (CONFIG_CODEC == SWCODEC) | 48 | #if (CONFIG_CODEC == SWCODEC) |
49 | #if !defined(SIMULATOR) | 49 | #if !defined(SIMULATOR) && defined(HAVE_RECORDING) |
50 | #include "pcm_record.h" | 50 | #include "pcm_record.h" |
51 | #endif | 51 | #endif |
52 | #include "dsp.h" | 52 | #include "dsp.h" |
@@ -84,15 +84,18 @@ | |||
84 | #define PREFIX(_x_) _x_ | 84 | #define PREFIX(_x_) _x_ |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | /* magic for normal codecs */ | ||
87 | #define CODEC_MAGIC 0x52434F44 /* RCOD */ | 88 | #define CODEC_MAGIC 0x52434F44 /* RCOD */ |
89 | /* magic for encoder codecs */ | ||
90 | #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ | ||
88 | 91 | ||
89 | /* increase this every time the api struct changes */ | 92 | /* increase this every time the api struct changes */ |
90 | #define CODEC_API_VERSION 9 | 93 | #define CODEC_API_VERSION 10 |
91 | 94 | ||
92 | /* update this to latest version if a change to the api struct breaks | 95 | /* update this to latest version if a change to the api struct breaks |
93 | backwards compatibility (and please take the opportunity to sort in any | 96 | backwards compatibility (and please take the opportunity to sort in any |
94 | new function which are "waiting" at the end of the function table) */ | 97 | new function which are "waiting" at the end of the function table) */ |
95 | #define CODEC_MIN_API_VERSION 8 | 98 | #define CODEC_MIN_API_VERSION 10 |
96 | 99 | ||
97 | /* codec return codes */ | 100 | /* codec return codes */ |
98 | enum codec_status { | 101 | enum codec_status { |
@@ -176,6 +179,7 @@ struct codec_api { | |||
176 | int (*PREFIX(remove))(const char* pathname); | 179 | int (*PREFIX(remove))(const char* pathname); |
177 | int (*PREFIX(rename))(const char* path, const char* newname); | 180 | int (*PREFIX(rename))(const char* path, const char* newname); |
178 | int (*PREFIX(ftruncate))(int fd, off_t length); | 181 | int (*PREFIX(ftruncate))(int fd, off_t length); |
182 | int (*PREFIX(fsync))(int fd); | ||
179 | 183 | ||
180 | int (*fdprintf)(int fd, const char *fmt, ...); | 184 | int (*fdprintf)(int fd, const char *fmt, ...); |
181 | int (*read_line)(int fd, char* buffer, int buffer_size); | 185 | int (*read_line)(int fd, char* buffer, int buffer_size); |
@@ -232,7 +236,8 @@ struct codec_api { | |||
232 | /* sound */ | 236 | /* sound */ |
233 | void (*sound_set)(int setting, int value); | 237 | void (*sound_set)(int setting, int value); |
234 | #ifndef SIMULATOR | 238 | #ifndef SIMULATOR |
235 | void (*mp3_play_data)(const unsigned char* start, int size, void (*get_more)(unsigned char** start, int* size)); | 239 | void (*mp3_play_data)(const unsigned char* start, |
240 | int size, void (*get_more)(unsigned char** start, int* size)); | ||
236 | void (*mp3_play_pause)(bool play); | 241 | void (*mp3_play_pause)(bool play); |
237 | void (*mp3_play_stop)(void); | 242 | void (*mp3_play_stop)(void); |
238 | bool (*mp3_is_playing)(void); | 243 | bool (*mp3_is_playing)(void); |
@@ -263,6 +268,10 @@ struct codec_api { | |||
263 | struct tm* (*get_time)(void); | 268 | struct tm* (*get_time)(void); |
264 | int (*set_time)(const struct tm *tm); | 269 | int (*set_time)(const struct tm *tm); |
265 | void* (*plugin_get_audio_buffer)(int* buffer_size); | 270 | void* (*plugin_get_audio_buffer)(int* buffer_size); |
271 | int (*round_value_to_list32)(unsigned long value, | ||
272 | const unsigned long list[], | ||
273 | int count, | ||
274 | bool signd); | ||
266 | 275 | ||
267 | #if defined(DEBUG) || defined(SIMULATOR) | 276 | #if defined(DEBUG) || defined(SIMULATOR) |
268 | void (*debugf)(const char *fmt, ...); | 277 | void (*debugf)(const char *fmt, ...); |
@@ -291,18 +300,14 @@ struct codec_api { | |||
291 | #endif | 300 | #endif |
292 | 301 | ||
293 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 302 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) |
294 | bool enc_codec_loaded; | 303 | volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */ |
295 | void (*enc_get_inputs)(int *buffer_size, | 304 | void (*enc_get_inputs)(struct enc_inputs *inputs); |
296 | int *channels, int *quality); | 305 | void (*enc_set_parameters)(struct enc_parameters *params); |
297 | void (*enc_set_parameters)(int chunk_size, int num_chunks, | 306 | struct enc_chunk_hdr * (*enc_get_chunk)(void); |
298 | int samp_per_chunk, char *head_ptr, int head_size, | 307 | void (*enc_finish_chunk)(void); |
299 | int enc_id); | 308 | int (*enc_pcm_buf_near_empty)(void); |
300 | unsigned int* (*enc_alloc_chunk)(void); | 309 | unsigned char * (*enc_get_pcm_data)(size_t size); |
301 | void (*enc_free_chunk)(void); | 310 | size_t (*enc_unget_pcm_data)(size_t size); |
302 | int (*enc_wavbuf_near_empty)(void); | ||
303 | char* (*enc_get_wav_data)(int size); | ||
304 | void (**enc_set_header_callback)(void *head_buffer, | ||
305 | int head_size, int num_samples, bool is_file_header); | ||
306 | #endif | 311 | #endif |
307 | 312 | ||
308 | /* new stuff at the end, sort into place next time | 313 | /* new stuff at the end, sort into place next time |
@@ -312,34 +317,49 @@ struct codec_api { | |||
312 | 317 | ||
313 | /* codec header */ | 318 | /* codec header */ |
314 | struct codec_header { | 319 | struct codec_header { |
315 | unsigned long magic; | 320 | unsigned long magic; /* RCOD or RENC */ |
316 | unsigned short target_id; | 321 | unsigned short target_id; |
317 | unsigned short api_version; | 322 | unsigned short api_version; |
318 | unsigned char *load_addr; | 323 | unsigned char *load_addr; |
319 | unsigned char *end_addr; | 324 | unsigned char *end_addr; |
320 | enum codec_status(*entry_point)(struct codec_api*); | 325 | enum codec_status(*entry_point)(struct codec_api*); |
321 | }; | 326 | }; |
327 | |||
322 | #ifdef CODEC | 328 | #ifdef CODEC |
323 | #ifndef SIMULATOR | 329 | #ifndef SIMULATOR |
324 | /* plugin_* is correct, codecs use the plugin linker script */ | 330 | /* plugin_* is correct, codecs use the plugin linker script */ |
325 | extern unsigned char plugin_start_addr[]; | 331 | extern unsigned char plugin_start_addr[]; |
326 | extern unsigned char plugin_end_addr[]; | 332 | extern unsigned char plugin_end_addr[]; |
333 | /* decoders */ | ||
327 | #define CODEC_HEADER \ | 334 | #define CODEC_HEADER \ |
328 | const struct codec_header __header \ | 335 | const struct codec_header __header \ |
329 | __attribute__ ((section (".header")))= { \ | 336 | __attribute__ ((section (".header")))= { \ |
330 | CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ | 337 | CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ |
331 | plugin_start_addr, plugin_end_addr, codec_start }; | 338 | plugin_start_addr, plugin_end_addr, codec_start }; |
332 | #else /* SIMULATOR */ | 339 | /* encoders */ |
340 | #define CODEC_ENC_HEADER \ | ||
341 | const struct codec_header __header \ | ||
342 | __attribute__ ((section (".header")))= { \ | ||
343 | CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ | ||
344 | plugin_start_addr, plugin_end_addr, codec_start }; | ||
345 | |||
346 | #else /* def SIMULATOR */ | ||
347 | /* decoders */ | ||
333 | #define CODEC_HEADER \ | 348 | #define CODEC_HEADER \ |
334 | const struct codec_header __header = { \ | 349 | const struct codec_header __header = { \ |
335 | CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ | 350 | CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ |
336 | NULL, NULL, codec_start }; | 351 | NULL, NULL, codec_start }; |
337 | #endif | 352 | /* encoders */ |
338 | #endif | 353 | #define CODEC_ENC_HEADER \ |
354 | const struct codec_header __header = { \ | ||
355 | CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ | ||
356 | NULL, NULL, codec_start }; | ||
357 | #endif /* SIMULATOR */ | ||
358 | #endif /* CODEC */ | ||
339 | 359 | ||
340 | /* create full codec path from filenames in audio_formats[] | 360 | /* create full codec path from root filenames in audio_formats[] |
341 | assumes buffer size is MAX_PATH */ | 361 | assumes buffer size is MAX_PATH */ |
342 | void codec_get_full_path(char *path, const char *codec_fn); | 362 | void codec_get_full_path(char *path, const char *codec_root_fn); |
343 | 363 | ||
344 | /* defined by the codec loader (codec.c) */ | 364 | /* defined by the codec loader (codec.c) */ |
345 | int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, | 365 | int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, |
diff --git a/apps/codecs/libwavpack/bits.c b/apps/codecs/libwavpack/bits.c index 0a148e123f..0f0e79c292 100644 --- a/apps/codecs/libwavpack/bits.c +++ b/apps/codecs/libwavpack/bits.c | |||
@@ -15,6 +15,7 @@ | |||
15 | // the malloc() system is provided. | 15 | // the malloc() system is provided. |
16 | 16 | ||
17 | #include "wavpack.h" | 17 | #include "wavpack.h" |
18 | #include "system.h" | ||
18 | 19 | ||
19 | #include <string.h> | 20 | #include <string.h> |
20 | 21 | ||
@@ -118,19 +119,16 @@ uint32_t bs_close_write (Bitstream *bs) | |||
118 | void little_endian_to_native (void *data, char *format) | 119 | void little_endian_to_native (void *data, char *format) |
119 | { | 120 | { |
120 | uchar *cp = (uchar *) data; | 121 | uchar *cp = (uchar *) data; |
121 | int32_t temp; | ||
122 | 122 | ||
123 | while (*format) { | 123 | while (*format) { |
124 | switch (*format) { | 124 | switch (*format) { |
125 | case 'L': | 125 | case 'L': |
126 | temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); | 126 | *(long *)cp = letoh32(*(long *)cp); |
127 | * (int32_t *) cp = temp; | ||
128 | cp += 4; | 127 | cp += 4; |
129 | break; | 128 | break; |
130 | 129 | ||
131 | case 'S': | 130 | case 'S': |
132 | temp = cp [0] + (cp [1] << 8); | 131 | *(short *)cp = letoh16(*(short *)cp); |
133 | * (short *) cp = (short) temp; | ||
134 | cp += 2; | 132 | cp += 2; |
135 | break; | 133 | break; |
136 | 134 | ||
@@ -148,28 +146,22 @@ void little_endian_to_native (void *data, char *format) | |||
148 | void native_to_little_endian (void *data, char *format) | 146 | void native_to_little_endian (void *data, char *format) |
149 | { | 147 | { |
150 | uchar *cp = (uchar *) data; | 148 | uchar *cp = (uchar *) data; |
151 | int32_t temp; | ||
152 | 149 | ||
153 | while (*format) { | 150 | while (*format) { |
154 | switch (*format) { | 151 | switch (*format) { |
155 | case 'L': | 152 | case 'L': |
156 | temp = * (int32_t *) cp; | 153 | *(long *)cp = htole32(*(long *)cp); |
157 | *cp++ = (uchar) temp; | 154 | cp += 4; |
158 | *cp++ = (uchar) (temp >> 8); | ||
159 | *cp++ = (uchar) (temp >> 16); | ||
160 | *cp++ = (uchar) (temp >> 24); | ||
161 | break; | 155 | break; |
162 | 156 | ||
163 | case 'S': | 157 | case 'S': |
164 | temp = * (short *) cp; | 158 | *(short *)cp = htole16(*(short *)cp); |
165 | *cp++ = (uchar) temp; | 159 | cp += 2; |
166 | *cp++ = (uchar) (temp >> 8); | ||
167 | break; | 160 | break; |
168 | 161 | ||
169 | default: | 162 | default: |
170 | if (*format >= '0' && *format <= '9') | 163 | if (*format >= '0' && *format <= '9') |
171 | cp += *format - '0'; | 164 | cp += *format - '0'; |
172 | |||
173 | break; | 165 | break; |
174 | } | 166 | } |
175 | 167 | ||
diff --git a/apps/codecs/mp3_enc.c b/apps/codecs/mp3_enc.c index 3caca94f35..cb727ce01e 100644 --- a/apps/codecs/mp3_enc.c +++ b/apps/codecs/mp3_enc.c | |||
@@ -32,20 +32,19 @@ | |||
32 | 32 | ||
33 | #ifndef SIMULATOR | 33 | #ifndef SIMULATOR |
34 | 34 | ||
35 | #include <inttypes.h> | ||
35 | #include "codeclib.h" | 36 | #include "codeclib.h" |
36 | 37 | ||
37 | CODEC_HEADER | 38 | CODEC_ENC_HEADER |
38 | 39 | ||
39 | #ifdef USE_IRAM | 40 | #define ENC_PADDING_FRAMES1 2 |
40 | extern char iramcopy[]; | 41 | #define ENC_PADDING_FRAMES2 4 |
41 | extern char iramstart[]; | 42 | #define ENC_DELAY_SAMP 576 |
42 | extern char iramend[]; | 43 | #define ENC_DELAY_SIZE (ENC_DELAY_SAMP*4) |
43 | extern char iedata[]; | 44 | #define SAMP_PER_FRAME1 1152 |
44 | extern char iend[]; | 45 | #define SAMP_PER_FRAME2 576 |
45 | #endif | 46 | #define PCM_CHUNK_SIZE1 (SAMP_PER_FRAME1*4) |
46 | 47 | #define PCM_CHUNK_SIZE2 (SAMP_PER_FRAME2*4) | |
47 | |||
48 | #define SAMP_PER_FRAME 1152 | ||
49 | #define SAMPL2 576 | 48 | #define SAMPL2 576 |
50 | #define SBLIMIT 32 | 49 | #define SBLIMIT 32 |
51 | #define HTN 16 | 50 | #define HTN 16 |
@@ -54,15 +53,16 @@ extern char iend[]; | |||
54 | #define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ | 53 | #define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ |
55 | else { putbits(cc, sz); cc = c; sz = s; } | 54 | else { putbits(cc, sz); cc = c; sz = s; } |
56 | 55 | ||
57 | enum e_byte_order { order_unknown, order_bigEndian, order_littleEndian }; | 56 | #ifdef USE_IRAM |
58 | 57 | extern char iramcopy[]; | |
59 | typedef unsigned long uint32; | 58 | extern char iramstart[]; |
60 | typedef unsigned short uint16; | 59 | extern char iramend[]; |
61 | typedef unsigned char uint8; | 60 | extern char iedata[]; |
62 | 61 | extern char iend[]; | |
62 | #endif | ||
63 | 63 | ||
64 | typedef struct { | 64 | typedef struct { |
65 | int type; /* 0=(22.05,24,16kHz) 1=(44.1,48,32kHz) */ | 65 | int type; /* 0=(MPEG2 - 22.05,24,16kHz) 1=(MPEG1 - 44.1,48,32kHz) */ |
66 | int mode; /* 0=stereo, 1=jstereo, 2=dual, 3=mono */ | 66 | int mode; /* 0=stereo, 1=jstereo, 2=dual, 3=mono */ |
67 | int bitrate; | 67 | int bitrate; |
68 | int padding; | 68 | int padding; |
@@ -73,21 +73,20 @@ typedef struct { | |||
73 | 73 | ||
74 | /* Side information */ | 74 | /* Side information */ |
75 | typedef struct { | 75 | typedef struct { |
76 | uint32 part2_3_length; | 76 | uint32_t part2_3_length; |
77 | int count1; /* number of 0-1-quadruples */ | 77 | int count1; /* number of 0-1-quadruples */ |
78 | uint32 global_gain; | 78 | uint32_t global_gain; |
79 | uint32 table_select[4]; | 79 | uint32_t table_select[4]; |
80 | uint32 region_0_1; | 80 | uint32_t region_0_1; |
81 | uint32 address1; | 81 | uint32_t address1; |
82 | uint32 address2; | 82 | uint32_t address2; |
83 | uint32 address3; | 83 | uint32_t address3; |
84 | long quantStep; | 84 | long quantStep; |
85 | long additStep; | 85 | long additStep; |
86 | long max_val; | 86 | long max_val; |
87 | } side_info_t; | 87 | } side_info_t; |
88 | 88 | ||
89 | typedef struct { | 89 | typedef struct { |
90 | enum e_byte_order byte_order; | ||
91 | side_info_t cod_info[2][2]; | 90 | side_info_t cod_info[2][2]; |
92 | mpeg_t mpg; | 91 | mpeg_t mpg; |
93 | long frac_per_frame; | 92 | long frac_per_frame; |
@@ -98,19 +97,18 @@ typedef struct { | |||
98 | int ResvSize; | 97 | int ResvSize; |
99 | int channels; | 98 | int channels; |
100 | int granules; | 99 | int granules; |
101 | int resample; | ||
102 | long samplerate; | 100 | long samplerate; |
103 | } config_t; | 101 | } config_t; |
104 | 102 | ||
105 | typedef struct { | 103 | typedef struct { |
106 | int bitpos; /* current bitpos for writing */ | 104 | int bitpos; /* current bitpos for writing */ |
107 | uint32 bbuf[263]; | 105 | uint32_t bbuf[263]; |
108 | } BF_Data; | 106 | } BF_Data; |
109 | 107 | ||
110 | struct huffcodetab { | 108 | struct huffcodetab { |
111 | int len; /* max. index */ | 109 | int len; /* max. index */ |
112 | const uint8 *table; /* pointer to array[len][len] */ | 110 | const uint8_t *table; /* pointer to array[len][len] */ |
113 | const uint8 *hlen; /* pointer to array[len][len] */ | 111 | const uint8_t *hlen; /* pointer to array[len][len] */ |
114 | }; | 112 | }; |
115 | 113 | ||
116 | struct huffcodebig { | 114 | struct huffcodebig { |
@@ -127,102 +125,105 @@ struct huffcodebig { | |||
127 | #define shft_n(x,n) ((x) >> n) | 125 | #define shft_n(x,n) ((x) >> n) |
128 | #define SQRT 724 /* sqrt(2) * 512 */ | 126 | #define SQRT 724 /* sqrt(2) * 512 */ |
129 | 127 | ||
130 | short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ | 128 | static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ |
131 | int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ | 129 | static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ |
132 | int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */ | 130 | static int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */ |
133 | short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */ | 131 | static short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */ |
134 | uint32 scalefac [23] IBSS_ATTR; /* 92 Bytes */ | 132 | static uint32_t scalefac [23] IBSS_ATTR; /* 92 Bytes */ |
135 | BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */ | 133 | static BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */ |
136 | int ca [8] IBSS_ATTR; /* 32 Bytes */ | 134 | static int ca [8] IBSS_ATTR; /* 32 Bytes */ |
137 | int cs [8] IBSS_ATTR; /* 32 Bytes */ | 135 | static int cs [8] IBSS_ATTR; /* 32 Bytes */ |
138 | int cx [9] IBSS_ATTR; /* 36 Bytes */ | 136 | static int cx [9] IBSS_ATTR; /* 36 Bytes */ |
139 | int win [18][4] IBSS_ATTR; /* 288 Bytes */ | 137 | static int win [18][4] IBSS_ATTR; /* 288 Bytes */ |
140 | short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */ | 138 | static short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */ |
141 | short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */ | 139 | static short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */ |
142 | uint8 ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */ | 140 | static uint8_t ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */ |
143 | uint32 tab01 [ 16] IBSS_ATTR; /* 64 Bytes */ | 141 | static uint32_t tab01 [ 16] IBSS_ATTR; /* 64 Bytes */ |
144 | uint32 tab23 [ 9] IBSS_ATTR; /* 36 Bytes */ | 142 | static uint32_t tab23 [ 9] IBSS_ATTR; /* 36 Bytes */ |
145 | uint32 tab56 [ 16] IBSS_ATTR; /* 64 Bytes */ | 143 | static uint32_t tab56 [ 16] IBSS_ATTR; /* 64 Bytes */ |
146 | uint32 tab1315 [256] IBSS_ATTR; /* 1024 Bytes */ | 144 | static uint32_t tab1315 [256] IBSS_ATTR; /* 1024 Bytes */ |
147 | uint32 tab1624 [256] IBSS_ATTR; /* 1024 Bytes */ | 145 | static uint32_t tab1624 [256] IBSS_ATTR; /* 1024 Bytes */ |
148 | uint32 tab789 [ 36] IBSS_ATTR; /* 144 Bytes */ | 146 | static uint32_t tab789 [ 36] IBSS_ATTR; /* 144 Bytes */ |
149 | uint32 tabABC [ 64] IBSS_ATTR; /* 256 Bytes */ | 147 | static uint32_t tabABC [ 64] IBSS_ATTR; /* 256 Bytes */ |
150 | uint8 t1HB [ 4] IBSS_ATTR; | 148 | static uint8_t t1HB [ 4] IBSS_ATTR; |
151 | uint8 t2HB [ 9] IBSS_ATTR; | 149 | static uint8_t t2HB [ 9] IBSS_ATTR; |
152 | uint8 t3HB [ 9] IBSS_ATTR; | 150 | static uint8_t t3HB [ 9] IBSS_ATTR; |
153 | uint8 t5HB [ 16] IBSS_ATTR; | 151 | static uint8_t t5HB [ 16] IBSS_ATTR; |
154 | uint8 t6HB [ 16] IBSS_ATTR; | 152 | static uint8_t t6HB [ 16] IBSS_ATTR; |
155 | uint8 t7HB [ 36] IBSS_ATTR; | 153 | static uint8_t t7HB [ 36] IBSS_ATTR; |
156 | uint8 t8HB [ 36] IBSS_ATTR; | 154 | static uint8_t t8HB [ 36] IBSS_ATTR; |
157 | uint8 t9HB [ 36] IBSS_ATTR; | 155 | static uint8_t t9HB [ 36] IBSS_ATTR; |
158 | uint8 t10HB [ 64] IBSS_ATTR; | 156 | static uint8_t t10HB [ 64] IBSS_ATTR; |
159 | uint8 t11HB [ 64] IBSS_ATTR; | 157 | static uint8_t t11HB [ 64] IBSS_ATTR; |
160 | uint8 t12HB [ 64] IBSS_ATTR; | 158 | static uint8_t t12HB [ 64] IBSS_ATTR; |
161 | uint8 t13HB [256] IBSS_ATTR; | 159 | static uint8_t t13HB [256] IBSS_ATTR; |
162 | uint8 t15HB [256] IBSS_ATTR; | 160 | static uint8_t t15HB [256] IBSS_ATTR; |
163 | uint16 t16HB [256] IBSS_ATTR; | 161 | static uint16_t t16HB [256] IBSS_ATTR; |
164 | uint16 t24HB [256] IBSS_ATTR; | 162 | static uint16_t t24HB [256] IBSS_ATTR; |
165 | uint8 t1l [ 8] IBSS_ATTR; | 163 | static uint8_t t1l [ 8] IBSS_ATTR; |
166 | uint8 t2l [ 9] IBSS_ATTR; | 164 | static uint8_t t2l [ 9] IBSS_ATTR; |
167 | uint8 t3l [ 9] IBSS_ATTR; | 165 | static uint8_t t3l [ 9] IBSS_ATTR; |
168 | uint8 t5l [ 16] IBSS_ATTR; | 166 | static uint8_t t5l [ 16] IBSS_ATTR; |
169 | uint8 t6l [ 16] IBSS_ATTR; | 167 | static uint8_t t6l [ 16] IBSS_ATTR; |
170 | uint8 t7l [ 36] IBSS_ATTR; | 168 | static uint8_t t7l [ 36] IBSS_ATTR; |
171 | uint8 t8l [ 36] IBSS_ATTR; | 169 | static uint8_t t8l [ 36] IBSS_ATTR; |
172 | uint8 t9l [ 36] IBSS_ATTR; | 170 | static uint8_t t9l [ 36] IBSS_ATTR; |
173 | uint8 t10l [ 64] IBSS_ATTR; | 171 | static uint8_t t10l [ 64] IBSS_ATTR; |
174 | uint8 t11l [ 64] IBSS_ATTR; | 172 | static uint8_t t11l [ 64] IBSS_ATTR; |
175 | uint8 t12l [ 64] IBSS_ATTR; | 173 | static uint8_t t12l [ 64] IBSS_ATTR; |
176 | uint8 t13l [256] IBSS_ATTR; | 174 | static uint8_t t13l [256] IBSS_ATTR; |
177 | uint8 t15l [256] IBSS_ATTR; | 175 | static uint8_t t15l [256] IBSS_ATTR; |
178 | uint8 t16l [256] IBSS_ATTR; | 176 | static uint8_t t16l [256] IBSS_ATTR; |
179 | uint8 t24l [256] IBSS_ATTR; | 177 | static uint8_t t24l [256] IBSS_ATTR; |
180 | struct huffcodetab ht [HTN] IBSS_ATTR; | 178 | static struct huffcodetab ht [HTN] IBSS_ATTR; |
181 | 179 | ||
182 | static config_t cfg; | 180 | static unsigned pcm_chunk_size IBSS_ATTR; |
181 | static unsigned samp_per_frame IBSS_ATTR; | ||
182 | |||
183 | static config_t cfg IBSS_ATTR; | ||
183 | static struct codec_api *ci; | 184 | static struct codec_api *ci; |
184 | static int enc_channels; | 185 | static char *res_buffer; |
185 | 186 | ||
186 | static const uint8 ht_count_const[2][2][16] = | 187 | static const uint8_t ht_count_const[2][2][16] = |
187 | { { { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1 }, /* table0 */ | 188 | { { { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1 }, /* table0 */ |
188 | { 1, 5, 5, 7, 5, 8, 7, 9, 5, 7, 7, 9, 7, 9, 9,10 } }, /* hleng0 */ | 189 | { 1, 5, 5, 7, 5, 8, 7, 9, 5, 7, 7, 9, 7, 9, 9,10 } }, /* hleng0 */ |
189 | { {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, /* table1 */ | 190 | { {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, /* table1 */ |
190 | { 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 } } }; /* hleng1 */ | 191 | { 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 } } }; /* hleng1 */ |
191 | 192 | ||
192 | static const uint8 t1HB_const[4] = {1,1,1,0}; | 193 | static const uint8_t t1HB_const[4] = {1,1,1,0}; |
193 | static const uint8 t2HB_const[9] = {1,2,1,3,1,1,3,2,0}; | 194 | static const uint8_t t2HB_const[9] = {1,2,1,3,1,1,3,2,0}; |
194 | static const uint8 t3HB_const[9] = {3,2,1,1,1,1,3,2,0}; | 195 | static const uint8_t t3HB_const[9] = {3,2,1,1,1,1,3,2,0}; |
195 | static const uint8 t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0}; | 196 | static const uint8_t t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0}; |
196 | static const uint8 t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0}; | 197 | static const uint8_t t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0}; |
197 | 198 | ||
198 | static const uint8 t7HB_const[36] = | 199 | static const uint8_t t7HB_const[36] = |
199 | { 1, 2,10,19,16,10, 3, 3, 7,10, 5, 3,11, 4,13,17, 8, 4, | 200 | { 1, 2,10,19,16,10, 3, 3, 7,10, 5, 3,11, 4,13,17, 8, 4, |
200 | 12,11,18,15,11, 2, 7, 6, 9,14, 3, 1, 6, 4, 5, 3, 2, 0 }; | 201 | 12,11,18,15,11, 2, 7, 6, 9,14, 3, 1, 6, 4, 5, 3, 2, 0 }; |
201 | 202 | ||
202 | static const uint8 t8HB_const[36] = | 203 | static const uint8_t t8HB_const[36] = |
203 | { 3, 4, 6,18,12, 5, 5, 1, 2,16, 9, 3, 7, 3, 5,14, 7, 3, | 204 | { 3, 4, 6,18,12, 5, 5, 1, 2,16, 9, 3, 7, 3, 5,14, 7, 3, |
204 | 19,17,15,13,10, 4,13, 5, 8,11, 5, 1,12, 4, 4, 1, 1, 0 }; | 205 | 19,17,15,13,10, 4,13, 5, 8,11, 5, 1,12, 4, 4, 1, 1, 0 }; |
205 | 206 | ||
206 | static const uint8 t9HB_const[36] = | 207 | static const uint8_t t9HB_const[36] = |
207 | { 7, 5, 9,14,15, 7, 6, 4, 5, 5, 6, 7, 7, 6, 8, 8, 8, 5, | 208 | { 7, 5, 9,14,15, 7, 6, 4, 5, 5, 6, 7, 7, 6, 8, 8, 8, 5, |
208 | 15, 6, 9,10, 5, 1,11, 7, 9, 6, 4, 1,14, 4, 6, 2, 6, 0 }; | 209 | 15, 6, 9,10, 5, 1,11, 7, 9, 6, 4, 1,14, 4, 6, 2, 6, 0 }; |
209 | 210 | ||
210 | static const uint8 t10HB_const[64] = | 211 | static const uint8_t t10HB_const[64] = |
211 | {1,2,10,23,35,30,12,17,3,3,8,12,18,21,12,7,11,9,15,21,32, | 212 | {1,2,10,23,35,30,12,17,3,3,8,12,18,21,12,7,11,9,15,21,32, |
212 | 40,19,6,14,13,22,34,46,23,18,7,20,19,33,47,27,22,9,3,31,22, | 213 | 40,19,6,14,13,22,34,46,23,18,7,20,19,33,47,27,22,9,3,31,22, |
213 | 41,26,21,20,5,3,14,13,10,11,16,6,5,1,9,8,7,8,4,4,2,0 }; | 214 | 41,26,21,20,5,3,14,13,10,11,16,6,5,1,9,8,7,8,4,4,2,0 }; |
214 | 215 | ||
215 | static const uint8 t11HB_const[64] = | 216 | static const uint8_t t11HB_const[64] = |
216 | {3,4,10,24,34,33,21,15,5,3,4,10,32,17,11,10,11,7,13,18,30, | 217 | {3,4,10,24,34,33,21,15,5,3,4,10,32,17,11,10,11,7,13,18,30, |
217 | 31,20,5,25,11,19,59,27,18,12,5,35,33,31,58,30,16,7,5,28,26, | 218 | 31,20,5,25,11,19,59,27,18,12,5,35,33,31,58,30,16,7,5,28,26, |
218 | 32,19,17,15,8,14,14,12,9,13,14,9,4,1,11,4,6,6,6,3,2,0 }; | 219 | 32,19,17,15,8,14,14,12,9,13,14,9,4,1,11,4,6,6,6,3,2,0 }; |
219 | 220 | ||
220 | static const uint8 t12HB_const[64] = | 221 | static const uint8_t t12HB_const[64] = |
221 | {9,6,16,33,41,39,38,26,7,5,6,9,23,16,26,11,17,7,11,14,21, | 222 | {9,6,16,33,41,39,38,26,7,5,6,9,23,16,26,11,17,7,11,14,21, |
222 | 30,10,7,17,10,15,12,18,28,14,5,32,13,22,19,18,16,9,5,40,17, | 223 | 30,10,7,17,10,15,12,18,28,14,5,32,13,22,19,18,16,9,5,40,17, |
223 | 31,29,17,13,4,2,27,12,11,15,10,7,4,1,27,12,8,12,6,3,1,0 }; | 224 | 31,29,17,13,4,2,27,12,11,15,10,7,4,1,27,12,8,12,6,3,1,0 }; |
224 | 225 | ||
225 | static const uint8 t13HB_const[256] = | 226 | static const uint8_t t13HB_const[256] = |
226 | {1,5,14,21,34,51,46,71,42,52,68,52,67,44,43,19,3,4,12,19,31,26,44,33,31,24,32, | 227 | {1,5,14,21,34,51,46,71,42,52,68,52,67,44,43,19,3,4,12,19,31,26,44,33,31,24,32, |
227 | 24,31,35,22,14,15,13,23,36,59,49,77,65,29,40,30,40,27,33,42,16,22,20,37,61,56, | 228 | 24,31,35,22,14,15,13,23,36,59,49,77,65,29,40,30,40,27,33,42,16,22,20,37,61,56, |
228 | 79,73,64,43,76,56,37,26,31,25,14,35,16,60,57,97,75,114,91,54,73,55,41,48,53, | 229 | 79,73,64,43,76,56,37,26,31,25,14,35,16,60,57,97,75,114,91,54,73,55,41,48,53, |
@@ -234,7 +235,7 @@ static const uint8 t13HB_const[256] = | |||
234 | 45,21,34,64,56,50,49,45,31,19,12,15,10,7,6,3,48,23,20,39,36,35,53,21,16,23,13, | 235 | 45,21,34,64,56,50,49,45,31,19,12,15,10,7,6,3,48,23,20,39,36,35,53,21,16,23,13, |
235 | 10,6,1,4,2,16,15,17,27,25,20,29,11,17,12,16,8,1,1,0,1 }; | 236 | 10,6,1,4,2,16,15,17,27,25,20,29,11,17,12,16,8,1,1,0,1 }; |
236 | 237 | ||
237 | static const uint8 t15HB_const[256] = | 238 | static const uint8_t t15HB_const[256] = |
238 | {7,12,18,53,47,76,124,108,89,123,108,119,107,81,122,63,13,5,16,27,46,36,61,51, | 239 | {7,12,18,53,47,76,124,108,89,123,108,119,107,81,122,63,13,5,16,27,46,36,61,51, |
239 | 42,70,52,83,65,41,59,36,19,17,15,24,41,34,59,48,40,64,50,78,62,80,56,33,29,28, | 240 | 42,70,52,83,65,41,59,36,19,17,15,24,41,34,59,48,40,64,50,78,62,80,56,33,29,28, |
240 | 25,43,39,63,55,93,76,59,93,72,54,75,50,29,52,22,42,40,67,57,95,79,72,57,89,69, | 241 | 25,43,39,63,55,93,76,59,93,72,54,75,50,29,52,22,42,40,67,57,95,79,72,57,89,69, |
@@ -246,7 +247,7 @@ static const uint8 t15HB_const[256] = | |||
246 | 24,16,22,13,14,7,91,44,39,38,34,63,52,45,31,52,28,19,14,8,9,3,123,60,58,53,47, | 247 | 24,16,22,13,14,7,91,44,39,38,34,63,52,45,31,52,28,19,14,8,9,3,123,60,58,53,47, |
247 | 43,32,22,37,24,17,12,15,10,2,1,71,37,34,30,28,20,17,26,21,16,10,6,8,6,2,0}; | 248 | 43,32,22,37,24,17,12,15,10,2,1,71,37,34,30,28,20,17,26,21,16,10,6,8,6,2,0}; |
248 | 249 | ||
249 | static const uint16 t16HB_const[256] = | 250 | static const uint16_t t16HB_const[256] = |
250 | {1,5,14,44,74,63,110,93,172,149,138,242,225,195,376,17,3,4,12,20,35,62,53,47, | 251 | {1,5,14,44,74,63,110,93,172,149,138,242,225,195,376,17,3,4,12,20,35,62,53,47, |
251 | 83,75,68,119,201,107,207,9,15,13,23,38,67,58,103,90,161,72,127,117,110,209, | 252 | 83,75,68,119,201,107,207,9,15,13,23,38,67,58,103,90,161,72,127,117,110,209, |
252 | 206,16,45,21,39,69,64,114,99,87,158,140,252,212,199,387,365,26,75,36,68,65, | 253 | 206,16,45,21,39,69,64,114,99,87,158,140,252,212,199,387,365,26,75,36,68,65, |
@@ -261,7 +262,7 @@ static const uint16 t16HB_const[256] = | |||
261 | 358,711,709,866,1734,871,3458,870,434,0,12,10,7,11,10,17,11,9,13,12,10,7,5,3, | 262 | 358,711,709,866,1734,871,3458,870,434,0,12,10,7,11,10,17,11,9,13,12,10,7,5,3, |
262 | 1,3}; | 263 | 1,3}; |
263 | 264 | ||
264 | static const uint16 t24HB_const[256] = | 265 | static const uint16_t t24HB_const[256] = |
265 | {15,13,46,80,146,262,248,434,426,669,653,649,621,517,1032,88,14,12,21,38,71, | 266 | {15,13,46,80,146,262,248,434,426,669,653,649,621,517,1032,88,14,12,21,38,71, |
266 | 130,122,216,209,198,327,345,319,297,279,42,47,22,41,74,68,128,120,221,207,194, | 267 | 130,122,216,209,198,327,345,319,297,279,42,47,22,41,74,68,128,120,221,207,194, |
267 | 182,340,315,295,541,18,81,39,75,70,134,125,116,220,204,190,178,325,311,293, | 268 | 182,340,315,295,541,18,81,39,75,70,134,125,116,220,204,190,178,325,311,293, |
@@ -276,7 +277,7 @@ static const uint16 t24HB_const[256] = | |||
276 | 374,369,365,361,357,2,1033,280,278,274,267,264,259,382,378,372,367,363,360, | 277 | 374,369,365,361,357,2,1033,280,278,274,267,264,259,382,378,372,367,363,360, |
277 | 358,356,0,43,20,19,17,15,13,11,9,7,6,4,7,5,3,1,3}; | 278 | 358,356,0,43,20,19,17,15,13,11,9,7,6,4,7,5,3,1,3}; |
278 | 279 | ||
279 | static const uint32 tab1315_const[256] = | 280 | static const uint32_t tab1315_const[256] = |
280 | { 0x010003,0x050005,0x070006,0x080008,0x090008,0x0a0009,0x0a000a,0x0b000a, | 281 | { 0x010003,0x050005,0x070006,0x080008,0x090008,0x0a0009,0x0a000a,0x0b000a, |
281 | 0x0a000a,0x0b000b,0x0c000b,0x0c000c,0x0d000c,0x0d000c,0x0e000d,0x0e000e, | 282 | 0x0a000a,0x0b000b,0x0c000b,0x0c000c,0x0d000c,0x0d000c,0x0e000d,0x0e000e, |
282 | 0x040005,0x060005,0x080007,0x090008,0x0a0009,0x0a0009,0x0b000a,0x0b000a, | 283 | 0x040005,0x060005,0x080007,0x090008,0x0a0009,0x0a0009,0x0b000a,0x0b000a, |
@@ -310,18 +311,18 @@ static const uint32 tab1315_const[256] = | |||
310 | 0x0d000d,0x0e000d,0x0f000d,0x10000d,0x10000d,0x10000d,0x11000d,0x10000e, | 311 | 0x0d000d,0x0e000d,0x0f000d,0x10000d,0x10000d,0x10000d,0x11000d,0x10000e, |
311 | 0x11000e,0x11000e,0x12000e,0x12000e,0x15000f,0x14000f,0x15000f,0x12000f }; | 312 | 0x11000e,0x11000e,0x12000e,0x12000e,0x15000f,0x14000f,0x15000f,0x12000f }; |
312 | 313 | ||
313 | static const uint32 tab01_const[16] = | 314 | static const uint32_t tab01_const[16] = |
314 | { 0x10004,0x50005,0x50005,0x70006,0x50005,0x80006,0x70006,0x90007, | 315 | { 0x10004,0x50005,0x50005,0x70006,0x50005,0x80006,0x70006,0x90007, |
315 | 0x50005,0x70006,0x70006,0x90007,0x70006,0x90007,0x90007,0xa0008 }; | 316 | 0x50005,0x70006,0x70006,0x90007,0x70006,0x90007,0x90007,0xa0008 }; |
316 | 317 | ||
317 | static const uint32 tab23_const[ 9] = | 318 | static const uint32_t tab23_const[ 9] = |
318 | { 0x10002,0x40003,0x70007,0x40004,0x50004,0x70007,0x60006,0x70007,0x80008 }; | 319 | { 0x10002,0x40003,0x70007,0x40004,0x50004,0x70007,0x60006,0x70007,0x80008 }; |
319 | 320 | ||
320 | static const uint32 tab56_const[16] = | 321 | static const uint32_t tab56_const[16] = |
321 | { 0x10003,0x40004,0x70006,0x80008,0x40004,0x50004,0x80006,0x90007, | 322 | { 0x10003,0x40004,0x70006,0x80008,0x40004,0x50004,0x80006,0x90007, |
322 | 0x70005,0x80006,0x90007,0xa0008,0x80007,0x80007,0x90008,0xa0009 }; | 323 | 0x70005,0x80006,0x90007,0xa0008,0x80007,0x80007,0x90008,0xa0009 }; |
323 | 324 | ||
324 | static const uint32 tab789_const[36] = | 325 | static const uint32_t tab789_const[36] = |
325 | {0x00100803,0x00401004,0x00701c06,0x00902407,0x00902409,0x00a0280a,0x00401004, | 326 | {0x00100803,0x00401004,0x00701c06,0x00902407,0x00902409,0x00a0280a,0x00401004, |
326 | 0x00601005,0x00801806,0x00902807,0x00902808,0x00a0280a,0x00701c05,0x00701806, | 327 | 0x00601005,0x00801806,0x00902807,0x00902808,0x00a0280a,0x00701c05,0x00701806, |
327 | 0x00902007,0x00a02808,0x00a02809,0x00b02c0a,0x00802407,0x00902807,0x00a02808, | 328 | 0x00902007,0x00a02808,0x00a02809,0x00b02c0a,0x00802407,0x00902807,0x00a02808, |
@@ -329,7 +330,7 @@ static const uint32 tab789_const[36] = | |||
329 | 0x00b0300a,0x00c0300b,0x00902809,0x00a02809,0x00b02c0a,0x00c02c0a,0x00c0340b, | 330 | 0x00b0300a,0x00c0300b,0x00902809,0x00a02809,0x00b02c0a,0x00c02c0a,0x00c0340b, |
330 | 0x00c0340b}; | 331 | 0x00c0340b}; |
331 | 332 | ||
332 | static const uint32 tabABC_const[64] = | 333 | static const uint32_t tabABC_const[64] = |
333 | {0x00100804,0x00401004,0x00701806,0x00902008,0x00a02409,0x00a0280a,0x00a0240a, | 334 | {0x00100804,0x00401004,0x00701806,0x00902008,0x00a02409,0x00a0280a,0x00a0240a, |
334 | 0x00b0280a,0x00401004,0x00601405,0x00801806,0x00902007,0x00a02809,0x00b02809, | 335 | 0x00b0280a,0x00401004,0x00601405,0x00801806,0x00902007,0x00a02809,0x00b02809, |
335 | 0x00a0240a,0x00a0280a,0x00701806,0x00801c06,0x00902007,0x00a02408,0x00b02809, | 336 | 0x00a0240a,0x00a0280a,0x00701806,0x00801c06,0x00902007,0x00a02408,0x00b02809, |
@@ -341,7 +342,7 @@ static const uint32 tabABC_const[64] = | |||
341 | 0x00a0240a,0x00a0240a,0x00b0280a,0x00c02c0b,0x00c0300b,0x00d0300b,0x00d0300b, | 342 | 0x00a0240a,0x00a0240a,0x00b0280a,0x00c02c0b,0x00c0300b,0x00d0300b,0x00d0300b, |
342 | 0x00d0300c}; | 343 | 0x00d0300c}; |
343 | 344 | ||
344 | static const uint32 tab1624_const[256] = | 345 | static const uint32_t tab1624_const[256] = |
345 | {0x00010004,0x00050005,0x00070007,0x00090008,0x000a0009,0x000a000a,0x000b000a, | 346 | {0x00010004,0x00050005,0x00070007,0x00090008,0x000a0009,0x000a000a,0x000b000a, |
346 | 0x000b000b,0x000c000b,0x000c000c,0x000c000c,0x000d000c,0x000d000c,0x000d000c, | 347 | 0x000b000b,0x000c000b,0x000c000c,0x000c000c,0x000d000c,0x000d000c,0x000d000c, |
347 | 0x000e000d,0x000a000a,0x00040005,0x00060006,0x00080007,0x00090008,0x000a0009, | 348 | 0x000e000d,0x000a000a,0x00040005,0x00060006,0x00080007,0x00090008,0x000a0009, |
@@ -380,34 +381,34 @@ static const uint32 tab1624_const[256] = | |||
380 | 0x000c0009,0x000c0009,0x000c0009,0x000d0009,0x000d0009,0x000d0009,0x000d000a, | 381 | 0x000c0009,0x000c0009,0x000c0009,0x000d0009,0x000d0009,0x000d0009,0x000d000a, |
381 | 0x000d000a,0x000d000a,0x000d000a,0x000a0006}; | 382 | 0x000d000a,0x000d000a,0x000d000a,0x000a0006}; |
382 | 383 | ||
383 | static const uint8 t1l_const[8] = {1,3,2,3,1,4,3,5}; | 384 | static const uint8_t t1l_const[8] = {1,3,2,3,1,4,3,5}; |
384 | static const uint8 t2l_const[9] = {1,3,6,3,3,5,5,5,6}; | 385 | static const uint8_t t2l_const[9] = {1,3,6,3,3,5,5,5,6}; |
385 | static const uint8 t3l_const[9] = {2,2,6,3,2,5,5,5,6}; | 386 | static const uint8_t t3l_const[9] = {2,2,6,3,2,5,5,5,6}; |
386 | static const uint8 t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8}; | 387 | static const uint8_t t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8}; |
387 | static const uint8 t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7}; | 388 | static const uint8_t t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7}; |
388 | 389 | ||
389 | static const uint8 t7l_const[36] = | 390 | static const uint8_t t7l_const[36] = |
390 | {1,3,6,8,8,9,3,4,6,7,7,8,6,5,7,8,8,9,7,7,8,9,9,9,7,7,8,9,9,10,8,8,9,10,10,10}; | 391 | {1,3,6,8,8,9,3,4,6,7,7,8,6,5,7,8,8,9,7,7,8,9,9,9,7,7,8,9,9,10,8,8,9,10,10,10}; |
391 | 392 | ||
392 | static const uint8 t8l_const[36] = | 393 | static const uint8_t t8l_const[36] = |
393 | {2,3,6,8,8,9,3,2,4,8,8,8,6,4,6,8,8,9,8,8,8,9,9,10,8,7,8,9,10,10,9,8,9,9,11,11}; | 394 | {2,3,6,8,8,9,3,2,4,8,8,8,6,4,6,8,8,9,8,8,8,9,9,10,8,7,8,9,10,10,9,8,9,9,11,11}; |
394 | 395 | ||
395 | static const uint8 t9l_const[36] = | 396 | static const uint8_t t9l_const[36] = |
396 | {3,3,5,6,8,9,3,3,4,5,6,8,4,4,5,6,7,8,6,5,6,7,7,8,7,6,7,7,8,9,8,7,8,8,9,9}; | 397 | {3,3,5,6,8,9,3,3,4,5,6,8,4,4,5,6,7,8,6,5,6,7,7,8,7,6,7,7,8,9,8,7,8,8,9,9}; |
397 | 398 | ||
398 | static const uint8 t10l_const[64] = | 399 | static const uint8_t t10l_const[64] = |
399 | {1,3,6,8,9,9,9,10,3,4,6,7,8,9,8,8,6,6,7,8,9,10,9,9,7,7,8,9,10,10,9,10,8,8,9,10, | 400 | {1,3,6,8,9,9,9,10,3,4,6,7,8,9,8,8,6,6,7,8,9,10,9,9,7,7,8,9,10,10,9,10,8,8,9,10, |
400 | 10,10,10,10,9,9,10,10,11,11,10,11,8,8,9,10,10,10,11,11,9,8,9,10,10,11,11,11}; | 401 | 10,10,10,10,9,9,10,10,11,11,10,11,8,8,9,10,10,10,11,11,9,8,9,10,10,11,11,11}; |
401 | 402 | ||
402 | static const uint8 t11l_const[64] = | 403 | static const uint8_t t11l_const[64] = |
403 | {2,3,5,7,8,9,8,9,3,3,4,6,8,8,7,8,5,5,6,7,8,9,8,8,7,6,7,9,8,10,8,9,8,8,8,9,9,10, | 404 | {2,3,5,7,8,9,8,9,3,3,4,6,8,8,7,8,5,5,6,7,8,9,8,8,7,6,7,9,8,10,8,9,8,8,8,9,9,10, |
404 | 9,10,8,8,9,10,10,11,10,11,8,7,7,8,9,10,10,10,8,7,8,9,10,10,10,10}; | 405 | 9,10,8,8,9,10,10,11,10,11,8,7,7,8,9,10,10,10,8,7,8,9,10,10,10,10}; |
405 | 406 | ||
406 | static const uint8 t12l_const[64] = | 407 | static const uint8_t t12l_const[64] = |
407 | {4,3,5,7,8,9,9,9,3,3,4,5,7,7,8,8,5,4,5,6,7,8,7,8,6,5,6,6,7,8,8,8,7,6,7,7,8, | 408 | {4,3,5,7,8,9,9,9,3,3,4,5,7,7,8,8,5,4,5,6,7,8,7,8,6,5,6,6,7,8,8,8,7,6,7,7,8, |
408 | 8,8,9,8,7,8,8,8,9,8,9,8,7,7,8,8,9,9,10,9,8,8,9,9,9,9,10}; | 409 | 8,8,9,8,7,8,8,8,9,8,9,8,7,7,8,8,9,9,10,9,8,8,9,9,9,9,10}; |
409 | 410 | ||
410 | static const uint8 t13l_const[256] = | 411 | static const uint8_t t13l_const[256] = |
411 | {1,4,6,7,8,9,9,10,9,10,11,11,12,12,13,13,3,4,6,7,8,8,9,9,9,9,10,10,11,12,12,12, | 412 | {1,4,6,7,8,9,9,10,9,10,11,11,12,12,13,13,3,4,6,7,8,8,9,9,9,9,10,10,11,12,12,12, |
412 | 6,6,7,8,9,9,10,10,9,10,10,11,11,12,13,13,7,7,8,9,9,10,10,10,10,11,11,11,11,12, | 413 | 6,6,7,8,9,9,10,10,9,10,10,11,11,12,13,13,7,7,8,9,9,10,10,10,10,11,11,11,11,12, |
413 | 13,13,8,7,9,9,10,10,11,11,10,11,11,12,12,13,13,14,9,8,9,10,10,10,11,11,11,11, | 414 | 13,13,8,7,9,9,10,10,11,11,10,11,11,12,12,13,13,14,9,8,9,10,10,10,11,11,11,11, |
@@ -419,7 +420,7 @@ static const uint8 t13l_const[256] = | |||
419 | 16,16,13,12,12,13,13,13,15,14,14,17,15,15,15,17,16,16,12,12,13,14,14,14,15,14, | 420 | 16,16,13,12,12,13,13,13,15,14,14,17,15,15,15,17,16,16,12,12,13,14,14,14,15,14, |
420 | 15,15,16,16,19,18,19,16}; | 421 | 15,15,16,16,19,18,19,16}; |
421 | 422 | ||
422 | static const uint8 t15l_const[256] = | 423 | static const uint8_t t15l_const[256] = |
423 | {3,4,5,7,7,8,9,9,9,10,10,11,11,11,12,13,4,3,5,6,7,7,8,8,8,9,9,10,10,10,11,11,5, | 424 | {3,4,5,7,7,8,9,9,9,10,10,11,11,11,12,13,4,3,5,6,7,7,8,8,8,9,9,10,10,10,11,11,5, |
424 | 5,5,6,7,7,8,8,8,9,9,10,10,11,11,11,6,6,6,7,7,8,8,9,9,9,10,10,10,11,11,11,7,6, | 425 | 5,5,6,7,7,8,8,8,9,9,10,10,11,11,11,6,6,6,7,7,8,8,9,9,9,10,10,10,11,11,11,7,6, |
425 | 7,7,8,8,9,9,9,9,10,10,10,11,11,11,8,7,7,8,8,8,9,9,9,9,10,10,11,11,11,12,9,7,8, | 426 | 7,7,8,8,9,9,9,9,10,10,10,11,11,11,8,7,7,8,8,8,9,9,9,9,10,10,11,11,11,12,9,7,8, |
@@ -430,7 +431,7 @@ static const uint8 t15l_const[256] = | |||
430 | 11,11,11,11,12,12,12,12,12,13,13,12,11,11,11,11,11,11,11,12,12,12,12,13,13,12, | 431 | 11,11,11,11,12,12,12,12,12,13,13,12,11,11,11,11,11,11,11,12,12,12,12,13,13,12, |
431 | 13,12,11,11,11,11,11,11,12,12,12,12,12,13,13,13,13}; | 432 | 13,12,11,11,11,11,11,11,12,12,12,12,12,13,13,13,13}; |
432 | 433 | ||
433 | static const uint8 t16l_const[256] = | 434 | static const uint8_t t16l_const[256] = |
434 | {1,4,6,8,9,9,10,10,11,11,11,12,12,12,13,9,3,4,6,7,8,9,9,9,10,10,10,11,12,11,12, | 435 | {1,4,6,8,9,9,10,10,11,11,11,12,12,12,13,9,3,4,6,7,8,9,9,9,10,10,10,11,12,11,12, |
435 | 8,6,6,7,8,9,9,10,10,11,10,11,11,11,12,12,9,8,7,8,9,9,10,10,10,11,11,12,12,12, | 436 | 8,6,6,7,8,9,9,10,10,11,10,11,11,11,12,12,9,8,7,8,9,9,10,10,10,11,11,12,12,12, |
436 | 13,13,10,9,8,9,9,10,10,11,11,11,12,12,12,13,13,13,9,9,8,9,9,10,11,11,12,11,12, | 437 | 13,13,10,9,8,9,9,10,10,11,11,11,12,12,12,13,13,13,9,9,8,9,9,10,11,11,12,11,12, |
@@ -442,7 +443,7 @@ static const uint8 t16l_const[256] = | |||
442 | 17,15,11,13,13,11,12,14,14,13,14,14,15,16,15,17,15,14,11,9,8,8,9,9,10,10,10, | 443 | 17,15,11,13,13,11,12,14,14,13,14,14,15,16,15,17,15,14,11,9,8,8,9,9,10,10,10, |
443 | 11,11,11,11,11,11,11,8}; | 444 | 11,11,11,11,11,11,11,8}; |
444 | 445 | ||
445 | static const uint8 t24l_const[256] = | 446 | static const uint8_t t24l_const[256] = |
446 | {4,4,6,7,8,9,9,10,10,11,11,11,11,11,12,9,4,4,5,6,7,8,8,9,9,9,10,10,10,10,10,8, | 447 | {4,4,6,7,8,9,9,10,10,11,11,11,11,11,12,9,4,4,5,6,7,8,8,9,9,9,10,10,10,10,10,8, |
447 | 6,5,6,7,7,8,8,9,9,9,9,10,10,10,11,7,7,6,7,7,8,8,8,9,9,9,9,10,10,10,10,7,8,7,7, | 448 | 6,5,6,7,7,8,8,9,9,9,9,10,10,10,11,7,7,6,7,7,8,8,8,9,9,9,9,10,10,10,10,7,8,7,7, |
448 | 8,8,8,8,9,9,9,10,10,10,10,11,7,9,7,8,8,8,8,9,9,9,9,10,10,10,10,10,7,9,8,8,8,8, | 449 | 8,8,8,8,9,9,9,10,10,10,10,11,7,9,7,8,8,8,8,9,9,9,9,10,10,10,10,10,7,9,8,8,8,8, |
@@ -491,8 +492,8 @@ static const struct huffcodebig ht_big[HTN] = | |||
491 | 492 | ||
492 | static const struct | 493 | static const struct |
493 | { | 494 | { |
494 | uint32 region0_cnt; | 495 | uint32_t region0_cnt; |
495 | uint32 region1_cnt; | 496 | uint32_t region1_cnt; |
496 | } subdv_table[23] = | 497 | } subdv_table[23] = |
497 | { {0, 0}, /* 0 bands */ | 498 | { {0, 0}, /* 0 bands */ |
498 | {0, 0}, /* 1 bands */ | 499 | {0, 0}, /* 1 bands */ |
@@ -519,7 +520,7 @@ static const struct | |||
519 | {6, 7}, /* 22 bands */ | 520 | {6, 7}, /* 22 bands */ |
520 | }; | 521 | }; |
521 | 522 | ||
522 | static const uint32 sfBand[6][23] = | 523 | static const uint32_t sfBand[6][23] = |
523 | { | 524 | { |
524 | /* Table B.2.b: 22.05 kHz */ | 525 | /* Table B.2.b: 22.05 kHz */ |
525 | {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, | 526 | {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, |
@@ -747,9 +748,13 @@ static const int order[32] = | |||
747 | { 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, | 748 | { 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, |
748 | 2, 3, 18, 19,10,11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 }; | 749 | 2, 3, 18, 19,10,11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 }; |
749 | 750 | ||
750 | static const int bitr_index[2][15] = | 751 | static const long sampr_index[2][3] = |
751 | { {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160}, | 752 | { { 22050, 24000, 16000 }, /* MPEG 2 */ |
752 | {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} }; | 753 | { 44100, 48000, 32000 } }; /* MPEG 1 */ |
754 | |||
755 | static const long bitr_index[2][15] = | ||
756 | { {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160}, /* MPEG 2 */ | ||
757 | {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} }; /* MPEG 1 */ | ||
753 | 758 | ||
754 | static const int num_bands[3][15] = | 759 | static const int num_bands[3][15] = |
755 | { {0,10,10,10,10,12,14,16, 20, 22, 24, 26, 28, 30, 32}, | 760 | { {0,10,10,10,10,12,14,16, 20, 22, 24, 26, 28, 30, 32}, |
@@ -837,35 +842,55 @@ static const int win_const[18][4] = { | |||
837 | { 134, -146,-3352,-3072 } }; | 842 | { 134, -146,-3352,-3072 } }; |
838 | 843 | ||
839 | /* forward declarations */ | 844 | /* forward declarations */ |
840 | int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table); | 845 | static int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table); |
841 | int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int table); | 846 | static int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int table); |
842 | void putbits(uint32 val, uint32 nbit); | 847 | static void putbits(uint32_t val, uint32_t nbit); |
843 | int find_best_2( short *ix, uint32 start, uint32 end, const uint32 *table, | 848 | static int find_best_2( short *ix, uint32_t start, uint32_t end, const uint32_t *table, |
844 | uint32 len, int *bits); | 849 | uint32_t len, int *bits); |
845 | int find_best_3( short *ix, uint32 start, uint32 end, const uint32 *table, | 850 | static int find_best_3( short *ix, uint32_t start, uint32_t end, const uint32_t *table, |
846 | uint32 len, int *bits); | 851 | uint32_t len, int *bits); |
847 | int count_bit1 ( short *ix, uint32 start, uint32 end, int *bits ); | 852 | static int count_bit1 ( short *ix, uint32_t start, uint32_t end, int *bits ); |
848 | int count_bigv ( short *ix, uint32 start, uint32 end, int table0, int table1, | 853 | static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, |
849 | int *bits); | 854 | int *bits); |
850 | 855 | ||
851 | 856 | ||
852 | void encodeSideInfo( side_info_t si[2][2] ) | 857 | static void encodeSideInfo( side_info_t si[2][2] ) |
853 | { | 858 | { |
854 | int gr, ch, header; | 859 | int gr, ch, header; |
855 | uint32 cc=0, sz=0; | 860 | uint32_t cc=0, sz=0; |
856 | 861 | ||
857 | header = 0xfff00000; | 862 | /* |
858 | header |= cfg.mpg.type << 19; /* mp3 type: 1 */ | 863 | * MPEG header layout: |
859 | header |= 1 << 17; /* mp3 layer: 1 */ | 864 | * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM |
860 | header |= 1 << 16; /* mp3 crc: 0 */ | 865 | * A (31-21) = frame sync |
866 | * B (20-19) = MPEG type | ||
867 | * C (18-17) = MPEG layer | ||
868 | * D (16) = protection bit | ||
869 | * E (15-12) = bitrate index | ||
870 | * F (11-10) = samplerate index | ||
871 | * G (9) = padding bit | ||
872 | * H (8) = private bit | ||
873 | * I (7-6) = channel mode | ||
874 | * J (5-4) = mode extension (jstereo only) | ||
875 | * K (3) = copyright bit | ||
876 | * L (2) = original | ||
877 | * M (1-0) = emphasis | ||
878 | */ | ||
879 | |||
880 | header = (0xfff00000) | /* frame sync (AAAAAAAAA AAA) | ||
881 | mp3 type (upper): 1 (B) */ | ||
882 | (0x01 << 17) | /* mp3 layer: 01 (CC) */ | ||
883 | ( 0x1 << 16) | /* mp3 crc: 1 (D) */ | ||
884 | ( 0x1 << 2); /* mp3 org: 1 (L) */ | ||
885 | header |= cfg.mpg.type << 19; | ||
861 | header |= cfg.mpg.bitr_id << 12; | 886 | header |= cfg.mpg.bitr_id << 12; |
862 | header |= cfg.mpg.smpl_id << 10; | 887 | header |= cfg.mpg.smpl_id << 10; |
863 | header |= cfg.mpg.padding << 9; | 888 | header |= cfg.mpg.padding << 9; |
864 | header |= cfg.mpg.mode << 6; | 889 | header |= cfg.mpg.mode << 6; |
865 | header |= 1 << 2; /* mp3 original: 1 */ | 890 | /* no emphasis (bits 0-1) */ |
866 | putbits( header, 32 ); | 891 | putbits( header, 32 ); |
867 | 892 | ||
868 | if(cfg.mpg.type) | 893 | if(cfg.mpg.type == 1) |
869 | { /* MPEG1 */ | 894 | { /* MPEG1 */ |
870 | if(cfg.channels == 2) { putlong( 0, 20); } | 895 | if(cfg.channels == 2) { putlong( 0, 20); } |
871 | else { putlong( 0, 18); } | 896 | else { putlong( 0, 18); } |
@@ -910,7 +935,7 @@ void encodeSideInfo( side_info_t si[2][2] ) | |||
910 | 935 | ||
911 | /* Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, | 936 | /* Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, |
912 | as well as the definitions of the side information on pages 26 and 27. */ | 937 | as well as the definitions of the side information on pages 26 and 27. */ |
913 | void Huffmancodebits( short *ix, int *xr, side_info_t *gi ) | 938 | static void Huffmancodebits( short *ix, int *xr, side_info_t *gi ) |
914 | { | 939 | { |
915 | int region1 = gi->address1; | 940 | int region1 = gi->address1; |
916 | int region2 = gi->address2; | 941 | int region2 = gi->address2; |
@@ -944,10 +969,10 @@ void Huffmancodebits( short *ix, int *xr, side_info_t *gi ) | |||
944 | } | 969 | } |
945 | } | 970 | } |
946 | 971 | ||
947 | int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int tbl) | 972 | int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int tbl) |
948 | { | 973 | { |
949 | uint32 cc=0, sz=0; | 974 | uint32_t cc=0, sz=0; |
950 | uint32 i, d, p; | 975 | uint32_t i, d, p; |
951 | int sumbit=0, s=0, l=0, v, w, x, y; | 976 | int sumbit=0, s=0, l=0, v, w, x, y; |
952 | #define sgnv (xr[i+0] < 0 ? 1 : 0) | 977 | #define sgnv (xr[i+0] < 0 ? 1 : 0) |
953 | #define sgnw (xr[i+1] < 0 ? 1 : 0) | 978 | #define sgnw (xr[i+1] < 0 ? 1 : 0) |
@@ -995,10 +1020,10 @@ int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int tbl) | |||
995 | } | 1020 | } |
996 | 1021 | ||
997 | /* Implements the pseudocode of page 98 of the IS */ | 1022 | /* Implements the pseudocode of page 98 of the IS */ |
998 | int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table) | 1023 | int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table) |
999 | { | 1024 | { |
1000 | uint32 cc=0, sz=0, code; | 1025 | uint32_t cc=0, sz=0, code; |
1001 | uint32 i, xl=0, yl=0, idx; | 1026 | uint32_t i, xl=0, yl=0, idx; |
1002 | int x, y, bit, sumbit=0; | 1027 | int x, y, bit, sumbit=0; |
1003 | #define sign_x (xr[i+0] < 0 ? 1 : 0) | 1028 | #define sign_x (xr[i+0] < 0 ? 1 : 0) |
1004 | #define sign_y (xr[i+1] < 0 ? 1 : 0) | 1029 | #define sign_y (xr[i+1] < 0 ? 1 : 0) |
@@ -1008,9 +1033,9 @@ int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table) | |||
1008 | 1033 | ||
1009 | if( table > 15 ) | 1034 | if( table > 15 ) |
1010 | { /* ESC-table is used */ | 1035 | { /* ESC-table is used */ |
1011 | uint32 linbits = ht_big[table-16].linbits; | 1036 | uint32_t linbits = ht_big[table-16].linbits; |
1012 | uint16 *hffcode = table < 24 ? t16HB : t24HB; | 1037 | uint16_t *hffcode = table < 24 ? t16HB : t24HB; |
1013 | uint8 *hlen = table < 24 ? t16l : t24l; | 1038 | uint8_t *hlen = table < 24 ? t16l : t24l; |
1014 | 1039 | ||
1015 | for(i=begin; i<end; i+=2) | 1040 | for(i=begin; i<end; i+=2) |
1016 | { | 1041 | { |
@@ -1088,14 +1113,14 @@ int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table) | |||
1088 | return sumbit; | 1113 | return sumbit; |
1089 | } | 1114 | } |
1090 | 1115 | ||
1091 | void putbits(uint32 val, uint32 nbit) | 1116 | void putbits(uint32_t val, uint32_t nbit) |
1092 | { | 1117 | { |
1093 | int new_bitpos = CodedData.bitpos + nbit; | 1118 | int new_bitpos = CodedData.bitpos + nbit; |
1094 | int ptrpos = CodedData.bitpos >> 5; | 1119 | int ptrpos = CodedData.bitpos >> 5; |
1095 | 1120 | ||
1096 | val = val & (0xffffffff >> (32 - nbit)); | 1121 | val = val & (0xffffffff >> (32 - nbit)); |
1097 | 1122 | ||
1098 | /* data fit in one uint32 */ | 1123 | /* data fit in one uint32_t */ |
1099 | if(((new_bitpos - 1) >> 5) == ptrpos) | 1124 | if(((new_bitpos - 1) >> 5) == ptrpos) |
1100 | CodedData.bbuf[ptrpos] |= val << ((32 - new_bitpos) & 31); | 1125 | CodedData.bbuf[ptrpos] |= val << ((32 - new_bitpos) & 31); |
1101 | else | 1126 | else |
@@ -1114,9 +1139,9 @@ void putbits(uint32 val, uint32 nbit) | |||
1114 | /* of the Huffman tables as defined in the IS (Table B.7), and will not */ | 1139 | /* of the Huffman tables as defined in the IS (Table B.7), and will not */ |
1115 | /* work with any arbitrary tables. */ | 1140 | /* work with any arbitrary tables. */ |
1116 | /***************************************************************************/ | 1141 | /***************************************************************************/ |
1117 | int choose_table( short *ix, uint32 begin, uint32 end, int *bits ) | 1142 | int choose_table( short *ix, uint32_t begin, uint32_t end, int *bits ) |
1118 | { | 1143 | { |
1119 | uint32 i; | 1144 | uint32_t i; |
1120 | int max, table0, table1; | 1145 | int max, table0, table1; |
1121 | 1146 | ||
1122 | for(i=begin,max=0; i<end; i++) | 1147 | for(i=begin,max=0; i<end; i++) |
@@ -1158,10 +1183,10 @@ int choose_table( short *ix, uint32 begin, uint32 end, int *bits ) | |||
1158 | } | 1183 | } |
1159 | } | 1184 | } |
1160 | 1185 | ||
1161 | int find_best_2(short *ix, uint32 start, uint32 end, const uint32 *table, | 1186 | int find_best_2(short *ix, uint32_t start, uint32_t end, const uint32_t *table, |
1162 | uint32 len, int *bits) | 1187 | uint32_t len, int *bits) |
1163 | { | 1188 | { |
1164 | uint32 i, sum = 0; | 1189 | uint32_t i, sum = 0; |
1165 | 1190 | ||
1166 | for(i=start; i<end; i+=2) | 1191 | for(i=start; i<end; i+=2) |
1167 | sum += table[ix[i] * len + ix[i+1]]; | 1192 | sum += table[ix[i] * len + ix[i+1]]; |
@@ -1178,10 +1203,10 @@ int find_best_2(short *ix, uint32 start, uint32 end, const uint32 *table, | |||
1178 | } | 1203 | } |
1179 | } | 1204 | } |
1180 | 1205 | ||
1181 | int find_best_3(short *ix, uint32 start, uint32 end, const uint32 *table, | 1206 | int find_best_3(short *ix, uint32_t start, uint32_t end, const uint32_t *table, |
1182 | uint32 len, int *bits) | 1207 | uint32_t len, int *bits) |
1183 | { | 1208 | { |
1184 | uint32 i, j, sum = 0; | 1209 | uint32_t i, j, sum = 0; |
1185 | int sum1 = 0; | 1210 | int sum1 = 0; |
1186 | int sum2 = 0; | 1211 | int sum2 = 0; |
1187 | int sum3 = 0; | 1212 | int sum3 = 0; |
@@ -1211,9 +1236,9 @@ int find_best_3(short *ix, uint32 start, uint32 end, const uint32 *table, | |||
1211 | /*************************************************************************/ | 1236 | /*************************************************************************/ |
1212 | /* Function: Count the number of bits necessary to code the subregion. */ | 1237 | /* Function: Count the number of bits necessary to code the subregion. */ |
1213 | /*************************************************************************/ | 1238 | /*************************************************************************/ |
1214 | int count_bit1(short *ix, uint32 start, uint32 end, int *bits ) | 1239 | int count_bit1(short *ix, uint32_t start, uint32_t end, int *bits ) |
1215 | { | 1240 | { |
1216 | uint32 i, sum = 0; | 1241 | uint32_t i, sum = 0; |
1217 | 1242 | ||
1218 | for(i=start; i<end; i+=2) | 1243 | for(i=start; i<end; i+=2) |
1219 | sum += t1l[4 + ix[i] * 2 + ix[i+1]]; | 1244 | sum += t1l[4 + ix[i] * 2 + ix[i+1]]; |
@@ -1223,10 +1248,10 @@ int count_bit1(short *ix, uint32 start, uint32 end, int *bits ) | |||
1223 | return 1; /* this is table1 */ | 1248 | return 1; /* this is table1 */ |
1224 | } | 1249 | } |
1225 | 1250 | ||
1226 | int count_bigv(short *ix, uint32 start, uint32 end, int table0, | 1251 | int count_bigv(short *ix, uint32_t start, uint32_t end, int table0, |
1227 | int table1, int *bits ) | 1252 | int table1, int *bits ) |
1228 | { | 1253 | { |
1229 | uint32 i, sum0, sum1, sum=0, bigv=0, x, y; | 1254 | uint32_t i, sum0, sum1, sum=0, bigv=0, x, y; |
1230 | 1255 | ||
1231 | /* ESC-table is used */ | 1256 | /* ESC-table is used */ |
1232 | for(i=start; i<end; i+=2) | 1257 | for(i=start; i<end; i+=2) |
@@ -1264,7 +1289,7 @@ int calc_runlen( short *ix, side_info_t *si ) | |||
1264 | int p, i, sum = 0; | 1289 | int p, i, sum = 0; |
1265 | 1290 | ||
1266 | for(i=SAMPL2; i-=2; ) | 1291 | for(i=SAMPL2; i-=2; ) |
1267 | if(*(uint32*)&ix[i-2]) /* !!!! short *ix; !!!!! */ | 1292 | if(*(uint32_t*)&ix[i-2]) /* !!!! short *ix; !!!!! */ |
1268 | break; | 1293 | break; |
1269 | 1294 | ||
1270 | si->count1 = 0; | 1295 | si->count1 = 0; |
@@ -1899,276 +1924,275 @@ void mdct_long(int *out, int *in) | |||
1899 | out[16] = ct - st; | 1924 | out[16] = ct - st; |
1900 | } | 1925 | } |
1901 | 1926 | ||
1902 | static int find_bitrate_index(int type, int bitrate) | 1927 | static int find_bitrate_index(int type, int bitrate, bool stereo) |
1903 | { | 1928 | { |
1904 | int i; | 1929 | if (type == 1 && !stereo && bitrate > 160) |
1930 | bitrate = 160; | ||
1905 | 1931 | ||
1906 | for(i=0;i<14;i++) | 1932 | return ci->round_value_to_list32(bitrate, |
1907 | if(bitrate == bitr_index[type][i]) | 1933 | &bitr_index[type][1], 14, true) + 1; |
1908 | break; | ||
1909 | |||
1910 | return i; | ||
1911 | } | 1934 | } |
1912 | 1935 | ||
1913 | static int find_samplerate_index(long freq, int *mp3_type) | 1936 | static int find_samplerate_index(long freq, int *mp3_type) |
1914 | { /* MPEG 2 */ /* MPEG 1 */ | 1937 | { |
1915 | static long mpeg[2][3] = { {22050, 24000, 16000}, {44100, 48000, 32000} }; | 1938 | int mpeg = freq >= (32000+24000)/2 ? 1 : 0; |
1916 | int mpg, rate; | 1939 | int i = ci->round_value_to_list32(freq, sampr_index[mpeg], 3, true); |
1917 | 1940 | *mp3_type = mpeg; | |
1918 | /* set default values: MPEG1 at 44100/s */ | 1941 | return i; |
1919 | *mp3_type = 1; | ||
1920 | |||
1921 | for(mpg=0; mpg<2; mpg++) | ||
1922 | for(rate=0; rate<3; rate++) | ||
1923 | if(freq == mpeg[mpg][rate]) | ||
1924 | { *mp3_type = mpg; return rate; } | ||
1925 | |||
1926 | return 0; | ||
1927 | } | 1942 | } |
1928 | 1943 | ||
1929 | void init_mp3_encoder_engine(bool stereo, int quality, int sample_rate) | 1944 | bool init_mp3_encoder_engine(int sample_rate, |
1945 | int num_channels, | ||
1946 | struct encoder_config *enc_cfg) | ||
1930 | { | 1947 | { |
1931 | /* keep in sync with rec_quality_info_afmt in id3.h/.c */ | 1948 | const bool stereo = num_channels > 1; |
1932 | static int bitr_s[9] = { 64, 96, 128, 160, 192, 224, 320, 64, 64 }; | 1949 | uint32_t avg_byte_per_frame; |
1933 | static int bitr_m[9] = { 64, 96, 128, 160, 160, 160, 160, 64, 64 }; | 1950 | |
1934 | uint32 avg_byte_per_frame; | 1951 | cfg.channels = stereo ? 2 : 1; |
1935 | 1952 | cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ | |
1936 | if(quality == 0 && stereo && sample_rate >= 32000) | 1953 | cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); |
1937 | { /* use MPEG2 format */ | 1954 | cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; |
1938 | sample_rate >>= 1; | 1955 | cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, |
1939 | cfg.resample = 1; | 1956 | enc_cfg->mp3_enc.bitrate, |
1940 | cfg.granules = 1; | 1957 | stereo); |
1941 | } | 1958 | cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; |
1942 | else | 1959 | cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; |
1943 | { /* use MPEG1 format */ | 1960 | |
1944 | cfg.resample = 0; | 1961 | if (cfg.mpg.type == 1) |
1945 | cfg.granules = 2; | 1962 | { |
1946 | } | 1963 | cfg.granules = 2; |
1964 | pcm_chunk_size = PCM_CHUNK_SIZE1; | ||
1965 | samp_per_frame = SAMP_PER_FRAME1; | ||
1966 | } | ||
1967 | else | ||
1968 | { | ||
1969 | cfg.granules = 1; | ||
1970 | pcm_chunk_size = PCM_CHUNK_SIZE2; | ||
1971 | samp_per_frame = SAMP_PER_FRAME2; | ||
1972 | } | ||
1947 | 1973 | ||
1948 | cfg.byte_order = order_bigEndian; | 1974 | memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); |
1949 | cfg.samplerate = sample_rate; | 1975 | memset(mfbuf , 0 , sizeof(mfbuf )); |
1950 | cfg.channels = stereo ? 2 : 1; | 1976 | memset(mdct_freq , 0 , sizeof(mdct_freq )); |
1951 | cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ | 1977 | memset(enc_data , 0 , sizeof(enc_data )); |
1952 | cfg.mpg.bitrate = stereo ? bitr_s[quality] : bitr_m[quality]; | 1978 | memset(sb_data , 0 , sizeof(sb_data )); |
1953 | cfg.mpg.smpl_id = find_samplerate_index(cfg.samplerate, &cfg.mpg.type); | 1979 | memset(&CodedData, 0 , sizeof(CodedData )); |
1954 | cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, cfg.mpg.bitrate); | 1980 | memcpy(ca , ca_const , sizeof(ca )); |
1955 | cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; | 1981 | memcpy(cs , cs_const , sizeof(cs )); |
1956 | 1982 | memcpy(cx , cx_const , sizeof(cx )); | |
1957 | memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); | 1983 | memcpy(win , win_const , sizeof(win )); |
1958 | memset(mfbuf , 0 , sizeof(mfbuf )); | 1984 | memcpy(enwindow , enwindow_const , sizeof(enwindow )); |
1959 | memset(mdct_freq , 0 , sizeof(mdct_freq )); | 1985 | memcpy(int2idx , int2idx_const , sizeof(int2idx )); |
1960 | memset(enc_data , 0 , sizeof(enc_data )); | 1986 | memcpy(ht_count , ht_count_const , sizeof(ht_count )); |
1961 | memset(sb_data , 0 , sizeof(sb_data )); | 1987 | memcpy( tab01 , tab01_const , sizeof(tab01 )); |
1962 | memset(&CodedData, 0 , sizeof(CodedData )); | 1988 | memcpy( tab23 , tab23_const , sizeof(tab23 )); |
1963 | memcpy(ca , ca_const , sizeof(ca )); | 1989 | memcpy( tab56 , tab56_const , sizeof(tab56 )); |
1964 | memcpy(cs , cs_const , sizeof(cs )); | 1990 | memcpy( tab1315 , tab1315_const , sizeof(tab1315 )); |
1965 | memcpy(cx , cx_const , sizeof(cx )); | 1991 | memcpy( tab1624 , tab1624_const , sizeof(tab1624 )); |
1966 | memcpy(win , win_const , sizeof(win )); | 1992 | memcpy( tab789 , tab789_const , sizeof(tab789 )); |
1967 | memcpy(enwindow , enwindow_const , sizeof(enwindow )); | 1993 | memcpy( tabABC , tabABC_const , sizeof(tabABC )); |
1968 | memcpy(int2idx , int2idx_const , sizeof(int2idx )); | 1994 | memcpy( t1HB , t1HB_const , sizeof(t1HB )); |
1969 | memcpy(ht_count , ht_count_const , sizeof(ht_count )); | 1995 | memcpy( t2HB , t2HB_const , sizeof(t2HB )); |
1970 | memcpy( tab01 , tab01_const , sizeof(tab01 )); | 1996 | memcpy( t3HB , t3HB_const , sizeof(t3HB )); |
1971 | memcpy( tab23 , tab23_const , sizeof(tab23 )); | 1997 | memcpy( t5HB , t5HB_const , sizeof(t5HB )); |
1972 | memcpy( tab56 , tab56_const , sizeof(tab56 )); | 1998 | memcpy( t6HB , t6HB_const , sizeof(t6HB )); |
1973 | memcpy( tab1315 , tab1315_const , sizeof(tab1315 )); | 1999 | memcpy( t7HB , t7HB_const , sizeof(t7HB )); |
1974 | memcpy( tab1624 , tab1624_const , sizeof(tab1624 )); | 2000 | memcpy( t8HB , t8HB_const , sizeof(t8HB )); |
1975 | memcpy( tab789 , tab789_const , sizeof(tab789 )); | 2001 | memcpy( t9HB , t9HB_const , sizeof(t9HB )); |
1976 | memcpy( tabABC , tabABC_const , sizeof(tabABC )); | 2002 | memcpy(t10HB , t10HB_const , sizeof(t10HB )); |
1977 | memcpy( t1HB , t1HB_const , sizeof(t1HB )); | 2003 | memcpy(t11HB , t11HB_const , sizeof(t11HB )); |
1978 | memcpy( t2HB , t2HB_const , sizeof(t2HB )); | 2004 | memcpy(t12HB , t12HB_const , sizeof(t12HB )); |
1979 | memcpy( t3HB , t3HB_const , sizeof(t3HB )); | 2005 | memcpy(t13HB , t13HB_const , sizeof(t13HB )); |
1980 | memcpy( t5HB , t5HB_const , sizeof(t5HB )); | 2006 | memcpy(t15HB , t15HB_const , sizeof(t15HB )); |
1981 | memcpy( t6HB , t6HB_const , sizeof(t6HB )); | 2007 | memcpy(t16HB , t16HB_const , sizeof(t16HB )); |
1982 | memcpy( t7HB , t7HB_const , sizeof(t7HB )); | 2008 | memcpy(t24HB , t24HB_const , sizeof(t24HB )); |
1983 | memcpy( t8HB , t8HB_const , sizeof(t8HB )); | 2009 | memcpy( t1l , t1l_const , sizeof(t1l )); |
1984 | memcpy( t9HB , t9HB_const , sizeof(t9HB )); | 2010 | memcpy( t2l , t2l_const , sizeof(t2l )); |
1985 | memcpy(t10HB , t10HB_const , sizeof(t10HB )); | 2011 | memcpy( t3l , t3l_const , sizeof(t3l )); |
1986 | memcpy(t11HB , t11HB_const , sizeof(t11HB )); | 2012 | memcpy( t5l , t5l_const , sizeof(t5l )); |
1987 | memcpy(t12HB , t12HB_const , sizeof(t12HB )); | 2013 | memcpy( t6l , t6l_const , sizeof(t6l )); |
1988 | memcpy(t13HB , t13HB_const , sizeof(t13HB )); | 2014 | memcpy( t7l , t7l_const , sizeof(t7l )); |
1989 | memcpy(t15HB , t15HB_const , sizeof(t15HB )); | 2015 | memcpy( t8l , t8l_const , sizeof(t8l )); |
1990 | memcpy(t16HB , t16HB_const , sizeof(t16HB )); | 2016 | memcpy( t9l , t9l_const , sizeof(t9l )); |
1991 | memcpy(t24HB , t24HB_const , sizeof(t24HB )); | 2017 | memcpy(t10l , t10l_const , sizeof(t10l )); |
1992 | memcpy( t1l , t1l_const , sizeof(t1l )); | 2018 | memcpy(t11l , t11l_const , sizeof(t11l )); |
1993 | memcpy( t2l , t2l_const , sizeof(t2l )); | 2019 | memcpy(t12l , t12l_const , sizeof(t12l )); |
1994 | memcpy( t3l , t3l_const , sizeof(t3l )); | 2020 | memcpy(t13l , t13l_const , sizeof(t13l )); |
1995 | memcpy( t5l , t5l_const , sizeof(t5l )); | 2021 | memcpy(t15l , t15l_const , sizeof(t15l )); |
1996 | memcpy( t6l , t6l_const , sizeof(t6l )); | 2022 | memcpy(t16l , t16l_const , sizeof(t16l )); |
1997 | memcpy( t7l , t7l_const , sizeof(t7l )); | 2023 | memcpy(t24l , t24l_const , sizeof(t24l )); |
1998 | memcpy( t8l , t8l_const , sizeof(t8l )); | 2024 | memcpy(ht , ht_const , sizeof(ht )); |
1999 | memcpy( t9l , t9l_const , sizeof(t9l )); | 2025 | |
2000 | memcpy(t10l , t10l_const , sizeof(t10l )); | 2026 | ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ |
2001 | memcpy(t11l , t11l_const , sizeof(t11l )); | 2027 | ht[ 1].table = t1HB; ht[ 1].hlen = t1l; |
2002 | memcpy(t12l , t12l_const , sizeof(t12l )); | 2028 | ht[ 2].table = t2HB; ht[ 2].hlen = t2l; |
2003 | memcpy(t13l , t13l_const , sizeof(t13l )); | 2029 | ht[ 3].table = t3HB; ht[ 3].hlen = t3l; |
2004 | memcpy(t15l , t15l_const , sizeof(t15l )); | 2030 | ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */ |
2005 | memcpy(t16l , t16l_const , sizeof(t16l )); | 2031 | ht[ 5].table = t5HB; ht[ 5].hlen = t5l; |
2006 | memcpy(t24l , t24l_const , sizeof(t24l )); | 2032 | ht[ 6].table = t6HB; ht[ 6].hlen = t6l; |
2007 | memcpy(ht , ht_const , sizeof(ht )); | 2033 | ht[ 7].table = t7HB; ht[ 7].hlen = t7l; |
2008 | 2034 | ht[ 8].table = t8HB; ht[ 8].hlen = t8l; | |
2009 | ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ | 2035 | ht[ 9].table = t9HB; ht[ 9].hlen = t9l; |
2010 | ht[ 1].table = t1HB; ht[ 1].hlen = t1l; | 2036 | ht[10].table = t10HB; ht[10].hlen = t10l; |
2011 | ht[ 2].table = t2HB; ht[ 2].hlen = t2l; | 2037 | ht[11].table = t11HB; ht[11].hlen = t11l; |
2012 | ht[ 3].table = t3HB; ht[ 3].hlen = t3l; | 2038 | ht[12].table = t12HB; ht[12].hlen = t12l; |
2013 | ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */ | 2039 | ht[13].table = t13HB; ht[13].hlen = t13l; |
2014 | ht[ 5].table = t5HB; ht[ 5].hlen = t5l; | 2040 | ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */ |
2015 | ht[ 6].table = t6HB; ht[ 6].hlen = t6l; | 2041 | ht[15].table = t15HB; ht[15].hlen = t15l; |
2016 | ht[ 7].table = t7HB; ht[ 7].hlen = t7l; | 2042 | |
2017 | ht[ 8].table = t8HB; ht[ 8].hlen = t8l; | 2043 | /* Figure average number of 'bytes' per frame */ |
2018 | ht[ 9].table = t9HB; ht[ 9].hlen = t9l; | 2044 | avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); |
2019 | ht[10].table = t10HB; ht[10].hlen = t10l; | 2045 | avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; |
2020 | ht[11].table = t11HB; ht[11].hlen = t11l; | 2046 | cfg.byte_per_frame = avg_byte_per_frame / 64; |
2021 | ht[12].table = t12HB; ht[12].hlen = t12l; | 2047 | cfg.frac_per_frame = avg_byte_per_frame & 63; |
2022 | ht[13].table = t13HB; ht[13].hlen = t13l; | 2048 | cfg.slot_lag = 0; |
2023 | ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */ | 2049 | cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) |
2024 | ht[15].table = t15HB; ht[15].hlen = t15l; | 2050 | : (cfg.channels == 1 ? 72 : 136)); |
2025 | 2051 | ||
2026 | /* Figure average number of 'bytes' per frame */ | 2052 | return true; |
2027 | avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); | ||
2028 | avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; | ||
2029 | cfg.byte_per_frame = avg_byte_per_frame / 64; | ||
2030 | cfg.frac_per_frame = avg_byte_per_frame & 63; | ||
2031 | cfg.slot_lag = 0; | ||
2032 | cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) | ||
2033 | : (cfg.channels == 1 ? 72 : 136)); | ||
2034 | } | 2053 | } |
2035 | 2054 | ||
2036 | 2055 | static void to_mono_mm(void) ICODE_ATTR; | |
2037 | enum codec_status codec_start(struct codec_api* api) | 2056 | static void to_mono_mm(void) |
2038 | { | 2057 | { |
2039 | int i, ii, gr, k, ch, shift, gr_cnt; | 2058 | /* |llllllllllllllll|rrrrrrrrrrrrrrrr| => |
2040 | int max, min; | 2059 | * |mmmmmmmmmmmmmmmm|mmmmmmmmmmmmmmmm| |
2041 | long *buffer; | 2060 | */ |
2042 | int chunk_size, num_chunks; | 2061 | uint32_t *samp = (uint32_t *)&mfbuf[2*512]; |
2043 | int enc_buffer_size; | 2062 | uint32_t *samp_end = samp + samp_per_frame; |
2044 | int enc_quality; | ||
2045 | uint32 *mp3_chunk_ptr; | ||
2046 | bool cpu_boosted = true; /* start boosted */ | ||
2047 | 2063 | ||
2048 | /* Generic codec initialisation */ | 2064 | inline void to_mono(uint32_t **samp) |
2049 | ci = api; | 2065 | { |
2050 | 2066 | int32_t lr = **samp; | |
2051 | #ifdef USE_IRAM | 2067 | int32_t m = ((int16_t)lr + (lr >> 16)) >> 1; |
2052 | memcpy(iramstart, iramcopy, iramend - iramstart); | 2068 | *(*samp)++ = (m << 16) | (uint16_t)m; |
2053 | memset(iedata, 0, iend - iedata); | 2069 | } /* to_mono */ |
2054 | #endif | ||
2055 | |||
2056 | if(ci->enc_get_inputs == NULL || | ||
2057 | ci->enc_set_parameters == NULL || | ||
2058 | ci->enc_alloc_chunk == NULL || | ||
2059 | ci->enc_free_chunk == NULL || | ||
2060 | ci->enc_wavbuf_near_empty == NULL || | ||
2061 | ci->enc_get_wav_data == NULL || | ||
2062 | ci->enc_set_header_callback == NULL ) | ||
2063 | return CODEC_ERROR; | ||
2064 | 2070 | ||
2065 | ci->cpu_boost(true); | 2071 | do |
2072 | { | ||
2073 | to_mono(&samp); | ||
2074 | to_mono(&samp); | ||
2075 | to_mono(&samp); | ||
2076 | to_mono(&samp); | ||
2077 | to_mono(&samp); | ||
2078 | to_mono(&samp); | ||
2079 | to_mono(&samp); | ||
2080 | to_mono(&samp); | ||
2081 | } | ||
2082 | while (samp < samp_end); | ||
2083 | } /* to_mono_mm */ | ||
2084 | |||
2085 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
2086 | /* Swaps a frame to big endian */ | ||
2087 | static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, | ||
2088 | size_t size) ICODE_ATTR; | ||
2089 | static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, | ||
2090 | size_t size) | ||
2091 | { | ||
2092 | uint32_t *src_end = SKIPBYTES(src, size); | ||
2066 | 2093 | ||
2067 | *ci->enc_set_header_callback = NULL; | 2094 | do |
2068 | ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); | 2095 | { |
2096 | *dst++ = swap32(*src++); | ||
2097 | *dst++ = swap32(*src++); | ||
2098 | *dst++ = swap32(*src++); | ||
2099 | *dst++ = swap32(*src++); | ||
2100 | *dst++ = swap32(*src++); | ||
2101 | *dst++ = swap32(*src++); | ||
2102 | *dst++ = swap32(*src++); | ||
2103 | *dst++ = swap32(*src++); | ||
2104 | } | ||
2105 | while(src < src_end); | ||
2106 | } /* byte_swap_frame32 */ | ||
2107 | #endif /* ROCKBOX_LITTLE_ENDIAN */ | ||
2069 | 2108 | ||
2070 | init_mp3_encoder_engine(enc_channels == 2, enc_quality, 44100); | 2109 | static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) ICODE_ATTR; |
2110 | static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) | ||
2111 | { | ||
2112 | int gr, gr_cnt; | ||
2113 | int max, min; | ||
2071 | 2114 | ||
2072 | /* must be 4byte aligned */ | 2115 | /* encode one mp3 frame in this loop */ |
2073 | chunk_size = (sizeof(long) + cfg.byte_per_frame + 1 + 3) & ~3; | 2116 | CodedData.bitpos = 0; |
2074 | num_chunks = enc_buffer_size / chunk_size; | 2117 | memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf)); |
2075 | 2118 | ||
2076 | /* inform the main program about the buffer dimensions */ | 2119 | if((cfg.slot_lag += cfg.frac_per_frame) >= 64) |
2077 | ci->enc_set_parameters(chunk_size, num_chunks, SAMP_PER_FRAME, | 2120 | { /* Padding for this frame */ |
2078 | NULL, 0, AFMT_MPA_L3); | 2121 | cfg.slot_lag -= 64; |
2122 | cfg.mpg.padding = 1; | ||
2123 | } | ||
2124 | else | ||
2125 | cfg.mpg.padding = 0; | ||
2079 | 2126 | ||
2080 | #ifdef CPU_COLDFIRE | 2127 | cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding |
2081 | asm volatile ("move.l #0, %macsr"); /* integer mode */ | 2128 | - cfg.sideinfo_len) / cfg.granules / cfg.channels; |
2082 | #endif | ||
2083 | 2129 | ||
2084 | /* main application waits for this flag during encoder loading */ | 2130 | /* shift out old samples */ |
2085 | ci->enc_codec_loaded = true; | 2131 | memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); |
2086 | 2132 | ||
2087 | /* main encoding loop */ | 2133 | if (chunk->flags & CHUNKF_START_FILE) |
2088 | while(!ci->stop_codec) | ||
2089 | { | 2134 | { |
2090 | while((buffer = (long*)ci->enc_get_wav_data(SAMP_PER_FRAME*4)) != NULL) | 2135 | /* prefix silent samples for encoder delay */ |
2091 | { | 2136 | memset(mfbuf + 2*512, 0, ENC_DELAY_SIZE); |
2092 | if(ci->stop_codec) | 2137 | /* read new samples to iram for further processing */ |
2093 | break; | 2138 | memcpy(mfbuf + 2*512 + ENC_DELAY_SIZE/2, |
2094 | 2139 | buffer, pcm_chunk_size - ENC_DELAY_SIZE); | |
2095 | if(ci->enc_wavbuf_near_empty() == 0) | 2140 | chunk->num_pcm = samp_per_frame - ENC_DELAY_SAMP; |
2096 | { | 2141 | } |
2097 | if(!cpu_boosted) | 2142 | else |
2098 | { | 2143 | { |
2099 | ci->cpu_boost(true); | 2144 | /* read new samples to iram for further processing */ |
2100 | cpu_boosted = true; | 2145 | memcpy(mfbuf + 2*512, buffer, pcm_chunk_size); |
2101 | } | 2146 | chunk->num_pcm = samp_per_frame; |
2102 | } | 2147 | } |
2103 | 2148 | ||
2104 | /* encode one mp3 frame in this loop */ | 2149 | if (cfg.channels == 1) |
2105 | CodedData.bitpos = 0; | 2150 | to_mono_mm(); |
2106 | memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf)); | ||
2107 | |||
2108 | if((cfg.slot_lag += cfg.frac_per_frame) >= 64) | ||
2109 | { /* Padding for this frame */ | ||
2110 | cfg.slot_lag -= 64; | ||
2111 | cfg.mpg.padding = 1; | ||
2112 | } | ||
2113 | else | ||
2114 | cfg.mpg.padding = 0; | ||
2115 | 2151 | ||
2116 | cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding | 2152 | cfg.ResvSize = 0; |
2117 | - cfg.sideinfo_len) / cfg.granules / cfg.channels; | 2153 | gr_cnt = cfg.granules * cfg.channels; |
2154 | CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ | ||
2118 | 2155 | ||
2119 | /* shift out old samples */ | 2156 | for(gr=0; gr<cfg.granules; gr++) |
2120 | memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); | 2157 | { |
2121 | /* read new samples to iram for further processing */ | 2158 | short *wk = mfbuf + 2*286 + gr*1152; |
2122 | memcpy((uint32*)(mfbuf + 2*512), buffer, 4*SAMP_PER_FRAME); | 2159 | int ch; |
2123 | 2160 | ||
2124 | if(cfg.resample) /* downsample to half of original */ | 2161 | /* 16bit packed wav data can be windowed efficiently on coldfire */ |
2125 | for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=4) | 2162 | window_subband1(wk, sb_data[0][1-gr][0], sb_data[1][1-gr][0]); |
2126 | { | ||
2127 | mfbuf[i/2+512] = (short)(((int)mfbuf[i+0] + mfbuf[i+2]) >> 1); | ||
2128 | mfbuf[i/2+513] = (short)(((int)mfbuf[i+1] + mfbuf[i+3]) >> 1); | ||
2129 | } | ||
2130 | 2163 | ||
2131 | if(cfg.channels == 1) /* mix left and right channels to mono */ | 2164 | for(ch=0; ch<cfg.channels; ch++) |
2132 | for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=2) | 2165 | { |
2133 | mfbuf[i] = mfbuf[i+1] = (short)(((int)mfbuf[i] + mfbuf[i+1]) >> 1); | 2166 | int ii, k, shift; |
2134 | 2167 | ||
2135 | cfg.ResvSize = 0; | 2168 | wk = mfbuf + 2*286 + gr*1152 + ch; |
2136 | gr_cnt = cfg.granules * cfg.channels; | ||
2137 | CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ | ||
2138 | 2169 | ||
2139 | for(gr=0; gr<cfg.granules; gr++) | 2170 | /* 36864=4*18*16*32 */ |
2171 | for(k=0; k<18; k++, wk+=64) | ||
2140 | { | 2172 | { |
2141 | short *wk = mfbuf + 2*286 + gr*1152; | 2173 | window_subband2(wk, sb_data[ch][1-gr][k]); |
2142 | 2174 | /* Compensate for inversion in the analysis filter */ | |
2143 | /* 16bit packed wav data can be windowed efficiently on coldfire */ | 2175 | if(k & 1) |
2144 | window_subband1(wk, sb_data[0][1-gr][0], sb_data[1][1-gr][0]); | ||
2145 | |||
2146 | for(ch=0; ch<cfg.channels; ch++) | ||
2147 | { | ||
2148 | int band; | ||
2149 | int *mdct; | ||
2150 | |||
2151 | wk = mfbuf + 2*286 + gr*1152 + ch; | ||
2152 | |||
2153 | /* 36864=4*18*16*32 */ | ||
2154 | for(k=0; k<18; k++, wk+=64) | ||
2155 | { | 2176 | { |
2156 | window_subband2(wk, sb_data[ch][1-gr][k]); | 2177 | int band; |
2157 | /* Compensate for inversion in the analysis filter */ | ||
2158 | if(k & 1) | ||
2159 | for(band=1; band<32; band+=2) | 2178 | for(band=1; band<32; band+=2) |
2160 | sb_data[ch][1-gr][k][band] *= -1; | 2179 | sb_data[ch][1-gr][k][band] *= -1; |
2161 | } | 2180 | } |
2181 | } | ||
2162 | 2182 | ||
2163 | /* Perform imdct of 18 previous + 18 current subband samples */ | 2183 | /* Perform imdct of 18 previous + 18 current subband samples |
2164 | /* for integer precision do this loop twice (if neccessary) */ | 2184 | for integer precision do this loop twice (if neccessary) |
2165 | shift = k = 14; | 2185 | */ |
2166 | for(ii=0; ii<2 && k; ii++) | 2186 | shift = k = 14; |
2187 | for(ii=0; ii<2 && k; ii++) | ||
2188 | { | ||
2189 | int *mdct = mdct_freq; | ||
2190 | int band; | ||
2191 | |||
2192 | cfg.cod_info[gr][ch].additStep = 4 * (14 - shift); | ||
2193 | |||
2194 | for(band=0; band<cfg.mpg.num_bands; band++, mdct+=18) | ||
2167 | { | 2195 | { |
2168 | mdct = mdct_freq; | ||
2169 | cfg.cod_info[gr][ch].additStep = 4 * (14 - shift); | ||
2170 | for(band=0; band<cfg.mpg.num_bands; band++, mdct+=18) | ||
2171 | { | ||
2172 | int *band0 = sb_data[ch][ gr][0] + order[band]; | 2196 | int *band0 = sb_data[ch][ gr][0] + order[band]; |
2173 | int *band1 = sb_data[ch][1-gr][0] + order[band]; | 2197 | int *band1 = sb_data[ch][1-gr][0] + order[band]; |
2174 | int work[18]; | 2198 | int work[18]; |
@@ -2176,16 +2200,20 @@ enum codec_status codec_start(struct codec_api* api) | |||
2176 | /* 9216=4*32*9*8 */ | 2200 | /* 9216=4*32*9*8 */ |
2177 | for(k=-9; k<0; k++) | 2201 | for(k=-9; k<0; k++) |
2178 | { | 2202 | { |
2179 | int a = shft_n(band1[(k+9)*32], shift); | 2203 | int a = shft_n(band1[(k+9)*32], shift); |
2180 | int b = shft_n(band1[(8-k)*32], shift); | 2204 | int b = shft_n(band1[(8-k)*32], shift); |
2181 | int c = shft_n(band0[(k+9)*32], shift); | 2205 | int c = shft_n(band0[(k+9)*32], shift); |
2182 | int d = shft_n(band0[(8-k)*32], shift); | 2206 | int d = shft_n(band0[(8-k)*32], shift); |
2183 | 2207 | ||
2184 | work[k+ 9] = shft16(a * win[k+ 9][0] + b * win[k+ 9][1] | 2208 | work[k+ 9] = shft16(a * win[k+ 9][0] + |
2185 | + c * win[k+ 9][2] + d * win[k+ 9][3]); | 2209 | b * win[k+ 9][1] + |
2186 | 2210 | c * win[k+ 9][2] + | |
2187 | work[k+18] = shft16(c * win[k+18][0] + d * win[k+18][1] | 2211 | d * win[k+ 9][3]); |
2188 | + a * win[k+18][2] + b * win[k+18][3]); | 2212 | |
2213 | work[k+18] = shft16(c * win[k+18][0] + | ||
2214 | d * win[k+18][1] + | ||
2215 | a * win[k+18][2] + | ||
2216 | b * win[k+18][3]); | ||
2189 | } | 2217 | } |
2190 | 2218 | ||
2191 | /* 7200=4*18*100 */ | 2219 | /* 7200=4*18*100 */ |
@@ -2193,67 +2221,309 @@ enum codec_status codec_start(struct codec_api* api) | |||
2193 | 2221 | ||
2194 | /* Perform aliasing reduction butterfly */ | 2222 | /* Perform aliasing reduction butterfly */ |
2195 | if(band != 0) | 2223 | if(band != 0) |
2196 | for(k=7; k>=0; --k) | 2224 | { |
2197 | { | 2225 | for(k=7; k>=0; --k) |
2198 | int bu, bd; | 2226 | { |
2199 | bu = shft15(mdct[k]) * ca[k] + shft15(mdct[-1-k]) * cs[k]; | 2227 | int bu, bd; |
2200 | bd = shft15(mdct[k]) * cs[k] - shft15(mdct[-1-k]) * ca[k]; | 2228 | bu = shft15(mdct[k]) * ca[k] + |
2201 | mdct[-1-k] = bu; | 2229 | shft15(mdct[-1-k]) * cs[k]; |
2202 | mdct[ k ] = bd; | 2230 | bd = shft15(mdct[k]) * cs[k] - |
2203 | } | 2231 | shft15(mdct[-1-k]) * ca[k]; |
2204 | } | 2232 | mdct[-1-k] = bu; |
2205 | 2233 | mdct[ k ] = bd; | |
2206 | max = min = 0; | 2234 | } |
2207 | for(k=0; k<576; k++) | 2235 | } |
2208 | { | 2236 | } |
2237 | |||
2238 | max = min = 0; | ||
2239 | for(k=0; k<576; k++) | ||
2240 | { | ||
2209 | mdct_freq[k] = shft13(mdct_freq[k]); | 2241 | mdct_freq[k] = shft13(mdct_freq[k]); |
2210 | if(max < mdct_freq[k]) max = mdct_freq[k]; | 2242 | if(max < mdct_freq[k]) max = mdct_freq[k]; |
2211 | if(min > mdct_freq[k]) min = mdct_freq[k]; | 2243 | if(min > mdct_freq[k]) min = mdct_freq[k]; |
2212 | } | 2244 | } |
2213 | 2245 | ||
2214 | max = (max > -min) ? max : -min; | 2246 | max = (max > -min) ? max : -min; |
2215 | cfg.cod_info[gr][ch].max_val = (long)max; | 2247 | cfg.cod_info[gr][ch].max_val = (long)max; |
2216 | 2248 | ||
2217 | /* calc new shift for higher integer precision */ | 2249 | /* calc new shift for higher integer precision */ |
2218 | for(k=0; max<(0x3c00>>k); k++); | 2250 | for(k=0; max<(0x3c00>>k); k++); |
2219 | shift = 12 - k; | 2251 | shift = 12 - k; |
2220 | } | 2252 | } |
2221 | 2253 | ||
2222 | cfg.cod_info[gr][ch].quantStep += cfg.cod_info[gr][ch].additStep; | 2254 | cfg.cod_info[gr][ch].quantStep += |
2255 | cfg.cod_info[gr][ch].additStep; | ||
2223 | 2256 | ||
2224 | /* bit and noise allocation */ | 2257 | /* bit and noise allocation */ |
2225 | iteration_loop(mdct_freq, &cfg.cod_info[gr][ch], gr_cnt--); | 2258 | iteration_loop(mdct_freq, &cfg.cod_info[gr][ch], |
2226 | /* write the frame to the bitstream */ | 2259 | gr_cnt--); |
2227 | Huffmancodebits(enc_data, mdct_freq, &cfg.cod_info[gr][ch]); | 2260 | /* write the frame to the bitstream */ |
2261 | Huffmancodebits(enc_data, mdct_freq, | ||
2262 | &cfg.cod_info[gr][ch]); | ||
2228 | 2263 | ||
2229 | cfg.cod_info[gr][ch].quantStep -= cfg.cod_info[gr][ch].additStep; | 2264 | cfg.cod_info[gr][ch].quantStep -= |
2265 | cfg.cod_info[gr][ch].additStep; | ||
2230 | 2266 | ||
2231 | if(cfg.granules == 1) | 2267 | if(cfg.granules == 1) |
2232 | memcpy(sb_data[ch][0], sb_data[ch][1], sizeof(sb_data[ch][0])); | 2268 | { |
2233 | } | 2269 | memcpy(sb_data[ch][0], sb_data[ch][1], |
2270 | sizeof(sb_data[ch][0])); | ||
2234 | } | 2271 | } |
2272 | } | ||
2273 | } | ||
2274 | |||
2275 | chunk->enc_size = cfg.byte_per_frame + cfg.mpg.padding; | ||
2235 | 2276 | ||
2236 | mp3_chunk_ptr = (uint32*)ci->enc_alloc_chunk(); | ||
2237 | mp3_chunk_ptr[0] = cfg.byte_per_frame + cfg.mpg.padding; //(CodedData.bitpos + 7) >> 3; | ||
2238 | /* finish this chunk by adding sideinfo header data */ | 2277 | /* finish this chunk by adding sideinfo header data */ |
2239 | CodedData.bitpos = 0; | 2278 | CodedData.bitpos = 0; |
2240 | encodeSideInfo( cfg.cod_info ); | 2279 | encodeSideInfo( cfg.cod_info ); |
2241 | 2280 | ||
2242 | /* allocate mp3 chunk, set chunk size, copy chunk to enc_buffer */ | 2281 | #ifdef ROCKBOX_BIG_ENDIAN |
2243 | memcpy(&mp3_chunk_ptr[1], CodedData.bbuf, mp3_chunk_ptr[0]); | 2282 | /* copy chunk to enc_buffer */ |
2244 | ci->enc_free_chunk(); | 2283 | memcpy(chunk->enc_data, CodedData.bbuf, chunk->enc_size); |
2284 | #else | ||
2285 | /* swap frame to big endian */ | ||
2286 | byte_swap_frame32(chunk->enc_data, CodedData.bbuf, chunk->enc_size); | ||
2287 | #endif | ||
2288 | } /* encode_frame */ | ||
2289 | |||
2290 | /* called very often - inline */ | ||
2291 | static inline bool is_file_data_ok(struct enc_file_event_data *filed) ICODE_ATTR; | ||
2292 | static inline bool is_file_data_ok(struct enc_file_event_data *filed) | ||
2293 | { | ||
2294 | return filed->rec_file >= 0 && (long)filed->chunk->flags >= 0; | ||
2295 | } /* is_event_ok */ | ||
2245 | 2296 | ||
2246 | ci->yield(); | 2297 | /* called very often - inline */ |
2298 | static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; | ||
2299 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
2300 | { | ||
2301 | if (!is_file_data_ok(data)) | ||
2302 | return false; | ||
2303 | |||
2304 | if (data->chunk->enc_data == NULL) | ||
2305 | { | ||
2306 | #ifdef ROCKBOX_HAS_LOGF | ||
2307 | ci->logf("mp3 enc: NULL data"); | ||
2308 | #endif | ||
2309 | return true; | ||
2310 | } | ||
2311 | |||
2312 | if (ci->write(data->rec_file, data->chunk->enc_data, | ||
2313 | data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) | ||
2314 | return false; | ||
2315 | |||
2316 | data->num_pcm_samples += data->chunk->num_pcm; | ||
2317 | return true; | ||
2318 | } /* on_write_chunk */ | ||
2319 | |||
2320 | static bool on_start_file(struct enc_file_event_data *data) | ||
2321 | { | ||
2322 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | ||
2323 | return false; | ||
2324 | |||
2325 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC); | ||
2326 | |||
2327 | if (data->rec_file < 0) | ||
2328 | return false; | ||
2329 | |||
2330 | /* reset sample count */ | ||
2331 | data->num_pcm_samples = 0; | ||
2332 | return true; | ||
2333 | } /* on_start_file */ | ||
2334 | |||
2335 | static bool on_end_file(struct enc_file_event_data *data) | ||
2336 | { | ||
2337 | if (!is_file_data_ok(data)) | ||
2338 | return false; | ||
2339 | |||
2340 | ci->fsync(data->rec_file); | ||
2341 | ci->close(data->rec_file); | ||
2342 | data->rec_file = -1; | ||
2343 | |||
2344 | return true; | ||
2345 | } /* on_end_file */ | ||
2346 | |||
2347 | static void on_rec_new_stream(struct enc_buffer_event_data *data) | ||
2348 | { | ||
2349 | int num_frames = cfg.mpg.type == 1 ? | ||
2350 | ENC_PADDING_FRAMES1 : ENC_PADDING_FRAMES2; | ||
2351 | |||
2352 | if (data->flags & CHUNKF_END_FILE) | ||
2353 | { | ||
2354 | /* add silent frames to end - encoder will also be flushed for start | ||
2355 | of next file if any */ | ||
2356 | memset(res_buffer, 0, pcm_chunk_size); | ||
2357 | |||
2358 | /* the initial chunk given for the end is at enc_wr_index */ | ||
2359 | while (num_frames-- > 0) | ||
2360 | { | ||
2361 | data->chunk->enc_data = ENC_CHUNK_SKIP_HDR(data->chunk->enc_data, | ||
2362 | data->chunk); | ||
2363 | |||
2364 | encode_frame(res_buffer, data->chunk); | ||
2365 | data->chunk->num_pcm = samp_per_frame; | ||
2366 | |||
2367 | ci->enc_finish_chunk(); | ||
2368 | data->chunk = ci->enc_get_chunk(); | ||
2247 | } | 2369 | } |
2370 | } | ||
2371 | else if (data->flags & CHUNKF_PRERECORD) | ||
2372 | { | ||
2373 | /* nothing to add and we cannot change prerecorded data */ | ||
2374 | } | ||
2375 | else if (data->flags & CHUNKF_START_FILE) | ||
2376 | { | ||
2377 | /* starting fresh ... be sure to flush encoder first */ | ||
2378 | struct enc_chunk_hdr *chunk = ENC_CHUNK_HDR(res_buffer); | ||
2248 | 2379 | ||
2249 | if(ci->enc_wavbuf_near_empty()) | 2380 | chunk->flags = 0; |
2381 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | ||
2382 | |||
2383 | while (num_frames-- > 0) | ||
2250 | { | 2384 | { |
2251 | if(cpu_boosted) | 2385 | memset(chunk->enc_data, 0, pcm_chunk_size); |
2386 | encode_frame(chunk->enc_data, chunk); | ||
2387 | } | ||
2388 | } | ||
2389 | } /* on_rec_new_stream */ | ||
2390 | |||
2391 | static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; | ||
2392 | static void enc_events_callback(enum enc_events event, void *data) | ||
2393 | { | ||
2394 | if (event == ENC_WRITE_CHUNK) | ||
2395 | { | ||
2396 | if (on_write_chunk((struct enc_file_event_data *)data)) | ||
2397 | return; | ||
2398 | } | ||
2399 | else if (event == ENC_START_FILE) | ||
2400 | { | ||
2401 | if (on_start_file((struct enc_file_event_data *)data)) | ||
2402 | return; | ||
2403 | } | ||
2404 | else if (event == ENC_END_FILE) | ||
2405 | { | ||
2406 | if (on_end_file((struct enc_file_event_data *)data)) | ||
2407 | return; | ||
2408 | } | ||
2409 | else if (event == ENC_REC_NEW_STREAM) | ||
2410 | { | ||
2411 | on_rec_new_stream((struct enc_buffer_event_data *)data); | ||
2412 | return; | ||
2413 | } | ||
2414 | else | ||
2415 | { | ||
2416 | return; | ||
2417 | } | ||
2418 | |||
2419 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | ||
2420 | } /* enc_events_callback */ | ||
2421 | |||
2422 | static bool enc_init(void) | ||
2423 | { | ||
2424 | struct enc_inputs inputs; | ||
2425 | struct enc_parameters params; | ||
2426 | |||
2427 | if (ci->enc_get_inputs == NULL || | ||
2428 | ci->enc_set_parameters == NULL || | ||
2429 | ci->enc_get_chunk == NULL || | ||
2430 | ci->enc_finish_chunk == NULL || | ||
2431 | ci->enc_pcm_buf_near_empty == NULL || | ||
2432 | ci->enc_get_pcm_data == NULL || | ||
2433 | ci->enc_unget_pcm_data == NULL ) | ||
2434 | return false; | ||
2435 | |||
2436 | ci->enc_get_inputs(&inputs); | ||
2437 | |||
2438 | if (inputs.config->afmt != AFMT_MPA_L3) | ||
2439 | return false; | ||
2440 | |||
2441 | init_mp3_encoder_engine(inputs.sample_rate, inputs.num_channels, | ||
2442 | inputs.config); | ||
2443 | |||
2444 | /* configure the buffer system */ | ||
2445 | params.afmt = AFMT_MPA_L3; | ||
2446 | params.chunk_size = cfg.byte_per_frame + 1; | ||
2447 | params.enc_sample_rate = cfg.samplerate; | ||
2448 | /* need enough reserved bytes to hold one frame of pcm samples + hdr | ||
2449 | for padding and flushing */ | ||
2450 | params.reserve_bytes = ENC_CHUNK_HDR_SIZE + pcm_chunk_size; | ||
2451 | params.events_callback = enc_events_callback; | ||
2452 | ci->enc_set_parameters(¶ms); | ||
2453 | |||
2454 | res_buffer = params.reserve_buffer; | ||
2455 | |||
2456 | #ifdef CPU_COLDFIRE | ||
2457 | asm volatile ("move.l #0, %macsr"); /* integer mode */ | ||
2458 | #endif | ||
2459 | |||
2460 | return true; | ||
2461 | } /* enc_init */ | ||
2462 | |||
2463 | enum codec_status codec_start(struct codec_api* api) | ||
2464 | { | ||
2465 | bool cpu_boosted; | ||
2466 | |||
2467 | /* Generic codec initialisation */ | ||
2468 | ci = api; | ||
2469 | |||
2470 | #ifdef USE_IRAM | ||
2471 | memcpy(iramstart, iramcopy, iramend - iramstart); | ||
2472 | memset(iedata, 0, iend - iedata); | ||
2473 | #endif | ||
2474 | |||
2475 | if (!enc_init()) | ||
2476 | { | ||
2477 | ci->enc_codec_loaded = -1; | ||
2478 | return CODEC_ERROR; | ||
2479 | } | ||
2480 | |||
2481 | /* main application waits for this flag during encoder loading */ | ||
2482 | ci->enc_codec_loaded = 1; | ||
2483 | |||
2484 | ci->cpu_boost(true); | ||
2485 | cpu_boosted = true; | ||
2486 | |||
2487 | /* main encoding loop */ | ||
2488 | while (!ci->stop_codec) | ||
2489 | { | ||
2490 | char *buffer; | ||
2491 | |||
2492 | while ((buffer = ci->enc_get_pcm_data(pcm_chunk_size)) != NULL) | ||
2493 | { | ||
2494 | struct enc_chunk_hdr *chunk; | ||
2495 | |||
2496 | if (ci->stop_codec) | ||
2497 | break; | ||
2498 | |||
2499 | if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0) | ||
2500 | { | ||
2501 | ci->cpu_boost(true); | ||
2502 | cpu_boosted = true; | ||
2503 | } | ||
2504 | |||
2505 | chunk = ci->enc_get_chunk(); | ||
2506 | chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); | ||
2507 | |||
2508 | encode_frame(buffer, chunk); | ||
2509 | |||
2510 | if (chunk->num_pcm < samp_per_frame) | ||
2511 | { | ||
2512 | ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4); | ||
2513 | chunk->num_pcm = samp_per_frame; | ||
2514 | } | ||
2515 | |||
2516 | ci->enc_finish_chunk(); | ||
2517 | |||
2518 | ci->yield(); | ||
2519 | } | ||
2520 | |||
2521 | if (cpu_boosted && ci->enc_pcm_buf_near_empty()) | ||
2252 | { | 2522 | { |
2253 | ci->cpu_boost(false); | 2523 | ci->cpu_boost(false); |
2254 | cpu_boosted = false; | 2524 | cpu_boosted = false; |
2255 | } | 2525 | } |
2256 | } | 2526 | |
2257 | ci->yield(); | 2527 | ci->yield(); |
2258 | } | 2528 | } |
2259 | 2529 | ||
@@ -2261,12 +2531,12 @@ enum codec_status codec_start(struct codec_api* api) | |||
2261 | ci->cpu_boost(false); | 2531 | ci->cpu_boost(false); |
2262 | 2532 | ||
2263 | /* reset parameters to initial state */ | 2533 | /* reset parameters to initial state */ |
2264 | ci->enc_set_parameters(0, 0, 0, 0, 0, 0); | 2534 | ci->enc_set_parameters(NULL); |
2265 | 2535 | ||
2266 | /* main application waits for this flag during encoder removing */ | 2536 | /* main application waits for this flag during encoder removing */ |
2267 | ci->enc_codec_loaded = false; | 2537 | ci->enc_codec_loaded = 0; |
2268 | 2538 | ||
2269 | return CODEC_OK; | 2539 | return CODEC_OK; |
2270 | } | 2540 | } /* codec_start */ |
2271 | 2541 | ||
2272 | #endif | 2542 | #endif /* ndef SIMULATOR */ |
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 | ||
24 | CODEC_HEADER | 25 | CODEC_ENC_HEADER |
26 | |||
27 | #ifdef USE_IRAM | ||
28 | extern char iramcopy[]; | ||
29 | extern char iramstart[]; | ||
30 | extern char iramend[]; | ||
31 | extern char iedata[]; | ||
32 | extern char iend[]; | ||
33 | #endif | ||
34 | |||
35 | struct 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 | ||
26 | static struct codec_api *ci; | 68 | static struct codec_api *ci; |
27 | static int enc_channels; | 69 | static int num_channels; |
70 | uint32_t sample_rate; | ||
71 | uint32_t enc_size; | ||
28 | 72 | ||
29 | #define CHUNK_SIZE 8192 | 73 | static 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 | ||
31 | static 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, | 96 | static 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}; | 97 | static 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 | ||
35 | static 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, | 103 | static 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}; | 104 | static 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) |
40 | void 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 | |||
125 | static 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 | |||
149 | static 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 | |||
192 | static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; | ||
193 | static 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 */ | ||
219 | static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; | ||
220 | static 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 |
60 | enum 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 | |||
290 | static 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(¶ms); | ||
319 | |||
320 | return true; | ||
321 | } /* init_encoder */ | ||
322 | |||
323 | /* main codec entry point */ | ||
324 | enum 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 */ | ||
diff --git a/apps/codecs/wavpack_enc.c b/apps/codecs/wavpack_enc.c index eced7f1f4e..5318abc8fb 100644 --- a/apps/codecs/wavpack_enc.c +++ b/apps/codecs/wavpack_enc.c | |||
@@ -22,201 +22,474 @@ | |||
22 | #include "codeclib.h" | 22 | #include "codeclib.h" |
23 | #include "libwavpack/wavpack.h" | 23 | #include "libwavpack/wavpack.h" |
24 | 24 | ||
25 | CODEC_HEADER | 25 | CODEC_ENC_HEADER |
26 | |||
27 | #ifdef USE_IRAM | ||
28 | extern char iramcopy[]; | ||
29 | extern char iramstart[]; | ||
30 | extern char iramend[]; | ||
31 | extern char iedata[]; | ||
32 | extern char iend[]; | ||
33 | #endif | ||
26 | 34 | ||
27 | typedef unsigned long uint32; | 35 | /** Types **/ |
28 | typedef unsigned short uint16; | 36 | typedef struct |
29 | typedef unsigned char uint8; | 37 | { |
38 | uint8_t type; /* Type of metadata */ | ||
39 | uint8_t word_size; /* Size of metadata in words */ | ||
40 | } WavpackMetadataHeader; | ||
30 | 41 | ||
31 | static unsigned char wav_header_ster [46] = | 42 | struct riff_header |
32 | {33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, | 43 | { |
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}; | 44 | uint8_t riff_id[4]; /* 00h - "RIFF" */ |
45 | uint32_t riff_size; /* 04h - sz following headers + data_size */ | ||
46 | /* format header */ | ||
47 | uint8_t format[4]; /* 08h - "WAVE" */ | ||
48 | uint8_t format_id[4]; /* 0Ch - "fmt " */ | ||
49 | uint32_t format_size; /* 10h - 16 for PCM (sz format data) */ | ||
50 | /* format data */ | ||
51 | uint16_t audio_format; /* 14h - 1=PCM */ | ||
52 | uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */ | ||
53 | uint32_t sample_rate; /* 18h - HZ */ | ||
54 | uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */ | ||
55 | uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ | ||
56 | uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ | ||
57 | /* Not for audio_format=1 (PCM) */ | ||
58 | /* unsigned short extra_param_size; 24h - size of extra data */ | ||
59 | /* unsigned char *extra_params; */ | ||
60 | /* data header */ | ||
61 | uint8_t data_id[4]; /* 24h - "data" */ | ||
62 | uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ | ||
63 | /* unsigned char *data; 2ch - actual sound data */ | ||
64 | }; | ||
65 | |||
66 | #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ | ||
67 | #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ | ||
68 | #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ | ||
69 | |||
70 | #define PCM_DEPTH_BITS 16 | ||
71 | #define PCM_DEPTH_BYTES 2 | ||
72 | #define PCM_SAMP_PER_CHUNK 5000 | ||
73 | #define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK) | ||
74 | |||
75 | /** Data **/ | ||
76 | static struct codec_api *ci; | ||
77 | static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR; | ||
78 | static WavpackConfig config IBSS_ATTR; | ||
79 | static WavpackContext *wpc; | ||
80 | static int32_t data_size, input_size, input_step IBSS_ATTR; | ||
34 | 81 | ||
35 | static unsigned char wav_header_mono [46] = | 82 | static const WavpackMetadataHeader wvpk_mdh = |
36 | {33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, | 83 | { |
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}; | 84 | ID_RIFF_HEADER, |
85 | sizeof (struct riff_header) / sizeof (uint16_t), | ||
86 | }; | ||
38 | 87 | ||
39 | static struct codec_api *ci; | 88 | static const struct riff_header riff_header = |
40 | static int enc_channels; | 89 | { |
90 | /* "RIFF" header */ | ||
91 | { 'R', 'I', 'F', 'F' }, /* riff_id */ | ||
92 | 0, /* riff_size (*) */ | ||
93 | /* format header */ | ||
94 | { 'W', 'A', 'V', 'E' }, /* format */ | ||
95 | { 'f', 'm', 't', ' ' }, /* format_id */ | ||
96 | H_TO_LE32(16), /* format_size */ | ||
97 | /* format data */ | ||
98 | H_TO_LE16(1), /* audio_format */ | ||
99 | 0, /* num_channels (*) */ | ||
100 | 0, /* sample_rate (*) */ | ||
101 | 0, /* byte_rate (*) */ | ||
102 | 0, /* block_align (*) */ | ||
103 | H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */ | ||
104 | /* data header */ | ||
105 | { 'd', 'a', 't', 'a' }, /* data_id */ | ||
106 | 0 /* data_size (*) */ | ||
107 | /* (*) updated during ENC_END_FILE event */ | ||
108 | }; | ||
109 | |||
110 | static void chunk_to_int32(int32_t *src) ICODE_ATTR; | ||
111 | static void chunk_to_int32(int32_t *src) | ||
112 | { | ||
113 | int32_t *dst = (int32_t *)input_buffer + PCM_SAMP_PER_CHUNK; | ||
114 | int32_t *src_end = dst + PCM_SAMP_PER_CHUNK; | ||
41 | 115 | ||
42 | #define CHUNK_SIZE 20000 | 116 | /* copy to IRAM before converting data */ |
117 | memcpy(dst, src, PCM_CHUNK_SIZE); | ||
43 | 118 | ||
44 | static long input_buffer[CHUNK_SIZE/2] IBSS_ATTR; | 119 | src = dst; |
120 | dst = (int32_t *)input_buffer; | ||
45 | 121 | ||
46 | /* update file header info callback function */ | 122 | if (config.num_channels == 1) |
47 | void enc_set_header(void *head_buffer, /* ptr to the file header data */ | ||
48 | int head_size, /* size of this header data */ | ||
49 | int num_pcm_sampl, /* amount of processed pcm samples */ | ||
50 | bool is_file_header) /* update file/chunk header */ | ||
51 | { | ||
52 | if(is_file_header) | ||
53 | { | 123 | { |
54 | /* update file header before file closing */ | 124 | /* |
55 | if(sizeof(WavpackHeader) + sizeof(wav_header_mono) < (unsigned)head_size) | 125 | * |llllllllllllllll|rrrrrrrrrrrrrrrr| => |
126 | * |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm| | ||
127 | */ | ||
128 | inline void to_int32(int32_t **src, int32_t **dst) | ||
56 | { | 129 | { |
57 | char* riff_header = (char*)head_buffer + sizeof(WavpackHeader); | 130 | int32_t t = *(*src)++; |
58 | char* wv_header = (char*)head_buffer + sizeof(wav_header_mono); | 131 | /* endianness irrelevant */ |
59 | int num_file_bytes = num_pcm_sampl * 2 * enc_channels; | 132 | *(*dst)++ = ((int16_t)t + (t >> 16)) >> 1; |
60 | unsigned long ckSize; | 133 | } /* to_int32 */ |
61 | 134 | ||
62 | /* RIFF header and WVPK header have to be swapped */ | 135 | do |
63 | /* copy wavpack header to file start position */ | 136 | { |
64 | ci->memcpy(head_buffer, wv_header, sizeof(WavpackHeader)); | 137 | /* read 10 longs and write 10 longs */ |
65 | wv_header = head_buffer; /* recalc wavpack header position */ | 138 | to_int32(&src, &dst); |
66 | 139 | to_int32(&src, &dst); | |
67 | if(enc_channels == 2) | 140 | to_int32(&src, &dst); |
68 | ci->memcpy(riff_header, wav_header_ster, sizeof(wav_header_ster)); | 141 | to_int32(&src, &dst); |
69 | else | 142 | to_int32(&src, &dst); |
70 | ci->memcpy(riff_header, wav_header_mono, sizeof(wav_header_mono)); | 143 | to_int32(&src, &dst); |
71 | 144 | to_int32(&src, &dst); | |
72 | /* update the Wavpack header first chunk size & total frame count */ | 145 | to_int32(&src, &dst); |
73 | ckSize = htole32(((WavpackHeader*)wv_header)->ckSize) | 146 | to_int32(&src, &dst); |
74 | + sizeof(wav_header_mono); | 147 | to_int32(&src, &dst); |
75 | ((WavpackHeader*)wv_header)->total_samples = htole32(num_pcm_sampl); | ||
76 | ((WavpackHeader*)wv_header)->ckSize = htole32(ckSize); | ||
77 | |||
78 | /* update the RIFF WAV header size entries */ | ||
79 | *(long*)(riff_header+ 6) = htole32(num_file_bytes + 36); | ||
80 | *(long*)(riff_header+42) = htole32(num_file_bytes); | ||
81 | } | 148 | } |
149 | while(src < src_end); | ||
150 | |||
151 | return; | ||
82 | } | 152 | } |
83 | else | 153 | else |
84 | { | 154 | { |
85 | /* update timestamp (block_index) */ | 155 | /* |
86 | ((WavpackHeader*)head_buffer)->block_index = htole32(num_pcm_sampl); | 156 | * |llllllllllllllll|rrrrrrrrrrrrrrrr| => |
157 | * |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr| | ||
158 | */ | ||
159 | inline void to_int32(int32_t **src, int32_t **dst) | ||
160 | { | ||
161 | int32_t t = *(*src)++; | ||
162 | #ifdef ROCKBOX_BIG_ENDIAN | ||
163 | *(*dst)++ = t >> 16, *(*dst)++ = (int16_t)t; | ||
164 | #else | ||
165 | *(*dst)++ = (int16_t)t, *(*dst)++ = t >> 16; | ||
166 | #endif | ||
167 | } /* to_int32 */ | ||
168 | |||
169 | do | ||
170 | { | ||
171 | /* read 10 longs and write 20 longs */ | ||
172 | to_int32(&src, &dst); | ||
173 | to_int32(&src, &dst); | ||
174 | to_int32(&src, &dst); | ||
175 | to_int32(&src, &dst); | ||
176 | to_int32(&src, &dst); | ||
177 | to_int32(&src, &dst); | ||
178 | to_int32(&src, &dst); | ||
179 | to_int32(&src, &dst); | ||
180 | to_int32(&src, &dst); | ||
181 | to_int32(&src, &dst); | ||
182 | } | ||
183 | while (src < src_end); | ||
184 | |||
185 | return; | ||
87 | } | 186 | } |
88 | } | 187 | } /* chunk_to_int32 */ |
89 | 188 | ||
189 | /* called very often - inline */ | ||
190 | static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; | ||
191 | static inline bool is_file_data_ok(struct enc_file_event_data *data) | ||
192 | { | ||
193 | return data->rec_file >= 0 && (long)data->chunk->flags >= 0; | ||
194 | } /* is_file_data_ok */ | ||
90 | 195 | ||
91 | enum codec_status codec_start(struct codec_api* api) | 196 | /* called very often - inline */ |
197 | static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; | ||
198 | static inline bool on_write_chunk(struct enc_file_event_data *data) | ||
199 | { | ||
200 | if (!is_file_data_ok(data)) | ||
201 | return false; | ||
202 | |||
203 | if (data->chunk->enc_data == NULL) | ||
204 | { | ||
205 | #ifdef ROCKBOX_HAS_LOGF | ||
206 | ci->logf("wvpk enc: NULL data"); | ||
207 | #endif | ||
208 | return true; | ||
209 | } | ||
210 | |||
211 | /* update timestamp (block_index) */ | ||
212 | ((WavpackHeader *)data->chunk->enc_data)->block_index = | ||
213 | htole32(data->num_pcm_samples); | ||
214 | |||
215 | if (ci->write(data->rec_file, data->chunk->enc_data, | ||
216 | data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) | ||
217 | return false; | ||
218 | |||
219 | data->num_pcm_samples += data->chunk->num_pcm; | ||
220 | return true; | ||
221 | } /* on_write_chunk */ | ||
222 | |||
223 | static bool on_start_file(struct enc_file_event_data *data) | ||
224 | { | ||
225 | if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') | ||
226 | return false; | ||
227 | |||
228 | data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC); | ||
229 | |||
230 | if (data->rec_file < 0) | ||
231 | return false; | ||
232 | |||
233 | /* reset sample count */ | ||
234 | data->num_pcm_samples = 0; | ||
235 | |||
236 | /* write template headers */ | ||
237 | if (ci->write(data->rec_file, &wvpk_mdh, sizeof (wvpk_mdh)) | ||
238 | != sizeof (wvpk_mdh) || | ||
239 | ci->write(data->rec_file, &riff_header, sizeof (riff_header)) | ||
240 | != sizeof (riff_header)) | ||
241 | { | ||
242 | return false; | ||
243 | } | ||
244 | |||
245 | data->new_enc_size += sizeof(wvpk_mdh) + sizeof(riff_header); | ||
246 | return true; | ||
247 | } /* on_start_file */ | ||
248 | |||
249 | static bool on_end_file(struct enc_file_event_data *data) | ||
250 | { | ||
251 | struct | ||
252 | { | ||
253 | WavpackMetadataHeader wpmdh; | ||
254 | struct riff_header rhdr; | ||
255 | WavpackHeader wph; | ||
256 | } __attribute__ ((packed)) h; | ||
257 | |||
258 | uint32_t data_size; | ||
259 | |||
260 | if (!is_file_data_ok(data)) | ||
261 | return false; | ||
262 | |||
263 | /* read template headers at start */ | ||
264 | if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || | ||
265 | ci->read(data->rec_file, &h, sizeof (h)) != sizeof (h)) | ||
266 | return false; | ||
267 | |||
268 | data_size = data->num_pcm_samples*config.num_channels*PCM_DEPTH_BYTES; | ||
269 | |||
270 | /** "RIFF" header **/ | ||
271 | h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + | ||
272 | RIFF_FMT_DATA_SIZE + RIFF_DATA_HEADER_SIZE + data_size); | ||
273 | |||
274 | /* format data */ | ||
275 | h.rhdr.num_channels = htole16(config.num_channels); | ||
276 | h.rhdr.sample_rate = htole32(config.sample_rate); | ||
277 | h.rhdr.byte_rate = htole32(config.sample_rate*config.num_channels* | ||
278 | PCM_DEPTH_BYTES); | ||
279 | h.rhdr.block_align = htole16(config.num_channels*PCM_DEPTH_BYTES); | ||
280 | |||
281 | /* data header */ | ||
282 | h.rhdr.data_size = htole32(data_size); | ||
283 | |||
284 | /** Wavpack header **/ | ||
285 | h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh) | ||
286 | + sizeof (h.rhdr)); | ||
287 | h.wph.total_samples = htole32(data->num_pcm_samples); | ||
288 | |||
289 | /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */ | ||
290 | if (ci->lseek(data->rec_file, 0, SEEK_SET) | ||
291 | != 0 || | ||
292 | ci->write(data->rec_file, &h.wph, sizeof (h.wph)) | ||
293 | != sizeof (h.wph) || | ||
294 | ci->write(data->rec_file, &h.wpmdh, sizeof (h.wpmdh)) | ||
295 | != sizeof (h.wpmdh) || | ||
296 | ci->write(data->rec_file, &h.rhdr, sizeof (h.rhdr)) | ||
297 | != sizeof (h.rhdr)) | ||
298 | { | ||
299 | return false; | ||
300 | } | ||
301 | |||
302 | ci->fsync(data->rec_file); | ||
303 | ci->close(data->rec_file); | ||
304 | data->rec_file = -1; | ||
305 | |||
306 | return true; | ||
307 | } /* on_end_file */ | ||
308 | |||
309 | static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; | ||
310 | static void enc_events_callback(enum enc_events event, void *data) | ||
92 | { | 311 | { |
93 | int i; | 312 | if (event == ENC_WRITE_CHUNK) |
94 | long t; | 313 | { |
95 | uint32 *src; | 314 | if (on_write_chunk((struct enc_file_event_data *)data)) |
96 | uint32 *dst; | 315 | return; |
97 | int chunk_size, num_chunks, samp_per_chunk; | 316 | } |
98 | int enc_buffer_size; | 317 | else if (event == ENC_START_FILE) |
99 | int enc_quality; | 318 | { |
100 | WavpackConfig config; | 319 | /* write metadata header and RIFF header */ |
101 | WavpackContext *wpc; | 320 | if (on_start_file((struct enc_file_event_data *)data)) |
102 | bool cpu_boosted = true; /* start boosted */ | 321 | return; |
103 | 322 | } | |
104 | ci = api; // copy to global api pointer | 323 | else if (event == ENC_END_FILE) |
324 | { | ||
325 | if (on_end_file((struct enc_file_event_data *)data)) | ||
326 | return; | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | return; | ||
331 | } | ||
332 | |||
333 | ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; | ||
334 | } /* enc_events_callback */ | ||
335 | |||
336 | static bool init_encoder(void) | ||
337 | { | ||
338 | struct enc_inputs inputs; | ||
339 | struct enc_parameters params; | ||
105 | 340 | ||
106 | codec_init(ci); | 341 | codec_init(ci); |
107 | 342 | ||
108 | if(ci->enc_get_inputs == NULL || | 343 | if (ci->enc_get_inputs == NULL || |
109 | ci->enc_set_parameters == NULL || | 344 | ci->enc_set_parameters == NULL || |
110 | ci->enc_alloc_chunk == NULL || | 345 | ci->enc_get_chunk == NULL || |
111 | ci->enc_free_chunk == NULL || | 346 | ci->enc_finish_chunk == NULL || |
112 | ci->enc_wavbuf_near_empty == NULL || | 347 | ci->enc_pcm_buf_near_empty == NULL || |
113 | ci->enc_get_wav_data == NULL || | 348 | ci->enc_get_pcm_data == NULL || |
114 | ci->enc_set_header_callback == NULL ) | 349 | ci->enc_unget_pcm_data == NULL ) |
115 | return CODEC_ERROR; | 350 | return false; |
116 | 351 | ||
117 | ci->cpu_boost(true); | 352 | ci->enc_get_inputs(&inputs); |
353 | |||
354 | if (inputs.config->afmt != AFMT_WAVPACK) | ||
355 | return false; | ||
118 | 356 | ||
119 | *ci->enc_set_header_callback = enc_set_header; | 357 | memset(&config, 0, sizeof (config)); |
120 | ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); | 358 | config.bits_per_sample = PCM_DEPTH_BITS; |
359 | config.bytes_per_sample = PCM_DEPTH_BYTES; | ||
360 | config.sample_rate = inputs.sample_rate; | ||
361 | config.num_channels = inputs.num_channels; | ||
362 | |||
363 | wpc = WavpackOpenFileOutput (); | ||
364 | |||
365 | if (!WavpackSetConfiguration(wpc, &config, -1)) | ||
366 | return false; | ||
121 | 367 | ||
122 | /* configure the buffer system */ | 368 | /* configure the buffer system */ |
123 | chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; | 369 | params.afmt = AFMT_WAVPACK; |
124 | num_chunks = enc_buffer_size / chunk_size; | 370 | input_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; |
125 | samp_per_chunk = CHUNK_SIZE / 4; | 371 | data_size = 105*input_size / 100; |
372 | input_size *= 2; | ||
373 | input_step = input_size / 4; | ||
374 | params.chunk_size = data_size; | ||
375 | params.enc_sample_rate = inputs.sample_rate; | ||
376 | params.reserve_bytes = 0; | ||
377 | params.events_callback = enc_events_callback; | ||
126 | 378 | ||
127 | /* inform the main program about buffer dimensions and other params */ | 379 | ci->enc_set_parameters(¶ms); |
128 | /* add wav_header_mono as place holder to file start position */ | ||
129 | /* wav header and wvpk header have to be reordered later */ | ||
130 | ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk, | ||
131 | wav_header_mono, sizeof(wav_header_mono), | ||
132 | AFMT_WAVPACK); | ||
133 | 380 | ||
134 | wpc = WavpackOpenFileOutput (); | 381 | return true; |
382 | } /* init_encoder */ | ||
383 | |||
384 | enum codec_status codec_start(struct codec_api* api) | ||
385 | { | ||
386 | bool cpu_boosted; | ||
387 | |||
388 | ci = api; /* copy to global api pointer */ | ||
135 | 389 | ||
136 | memset (&config, 0, sizeof (config)); | 390 | #ifdef USE_IRAM |
137 | config.bits_per_sample = 16; | 391 | ci->memcpy(iramstart, iramcopy, iramend - iramstart); |
138 | config.bytes_per_sample = 2; | 392 | ci->memset(iedata, 0, iend - iedata); |
139 | config.sample_rate = 44100; | 393 | #endif |
140 | config.num_channels = enc_channels; | ||
141 | 394 | ||
142 | if (!WavpackSetConfiguration (wpc, &config, 1)) | 395 | /* initialize params and config */ |
396 | if (!init_encoder()) | ||
397 | { | ||
398 | ci->enc_codec_loaded = -1; | ||
143 | return CODEC_ERROR; | 399 | return CODEC_ERROR; |
400 | } | ||
144 | 401 | ||
145 | /* main application waits for this flag during encoder loading */ | 402 | /* main application waits for this flag during encoder loading */ |
146 | ci->enc_codec_loaded = true; | 403 | ci->enc_codec_loaded = 1; |
404 | |||
405 | ci->cpu_boost(true); | ||
406 | cpu_boosted = true; | ||
147 | 407 | ||
148 | /* main encoding loop */ | 408 | /* main encoding loop */ |
149 | while(!ci->stop_codec) | 409 | while(!ci->stop_codec) |
150 | { | 410 | { |
151 | while((src = (uint32*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) | 411 | uint8_t *src; |
412 | |||
413 | while ((src = ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) | ||
152 | { | 414 | { |
415 | struct enc_chunk_hdr *chunk; | ||
416 | bool abort_chunk; | ||
417 | uint8_t *dst; | ||
418 | uint8_t *src_end; | ||
419 | |||
153 | if(ci->stop_codec) | 420 | if(ci->stop_codec) |
154 | break; | 421 | break; |
155 | 422 | ||
156 | if(ci->enc_wavbuf_near_empty() == 0) | 423 | abort_chunk = true; |
424 | |||
425 | if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0) | ||
157 | { | 426 | { |
158 | if(!cpu_boosted) | 427 | ci->cpu_boost(true); |
159 | { | 428 | cpu_boosted = true; |
160 | ci->cpu_boost(true); | ||
161 | cpu_boosted = true; | ||
162 | } | ||
163 | } | 429 | } |
164 | 430 | ||
165 | dst = (uint32*)ci->enc_alloc_chunk() + 1; | 431 | chunk = ci->enc_get_chunk(); |
166 | 432 | ||
167 | WavpackStartBlock (wpc, (uint8*)dst, (uint8*)dst + CHUNK_SIZE); | 433 | /* reset counts and pointer */ |
434 | chunk->enc_size = 0; | ||
435 | chunk->num_pcm = 0; | ||
436 | chunk->enc_data = NULL; | ||
168 | 437 | ||
169 | if(enc_channels == 2) | 438 | dst = ENC_CHUNK_SKIP_HDR(dst, chunk); |
170 | { | ||
171 | for (i=0; i<CHUNK_SIZE/4; i++) | ||
172 | { | ||
173 | t = (long)*src++; | ||
174 | 439 | ||
175 | input_buffer[2*i + 0] = t >> 16; | 440 | WavpackStartBlock(wpc, dst, dst + data_size); |
176 | input_buffer[2*i + 1] = (short)t; | 441 | |
177 | } | 442 | chunk_to_int32((uint32_t*)src); |
178 | } | 443 | src = input_buffer; |
179 | else | 444 | src_end = src + input_size; |
445 | |||
446 | /* encode chunk in four steps yielding between each */ | ||
447 | do | ||
180 | { | 448 | { |
181 | for (i=0; i<CHUNK_SIZE/4; i++) | 449 | if (WavpackPackSamples(wpc, (int32_t *)src, |
450 | PCM_SAMP_PER_CHUNK/4)) | ||
182 | { | 451 | { |
183 | t = (long)*src++; | 452 | chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; |
184 | t = (((t<<16)>>16) + (t>>16)) >> 1; /* left+right */ | 453 | ci->yield(); |
185 | 454 | /* could've been stopped in some way */ | |
186 | input_buffer[i] = t; | 455 | abort_chunk = ci->stop_codec || |
456 | (chunk->flags & CHUNKF_ABORT); | ||
187 | } | 457 | } |
188 | } | ||
189 | 458 | ||
190 | if (!WavpackPackSamples (wpc, input_buffer, CHUNK_SIZE/4)) | 459 | src += input_step; |
191 | return CODEC_ERROR; | 460 | } |
461 | while (!abort_chunk && src < src_end); | ||
192 | 462 | ||
463 | if (!abort_chunk) | ||
464 | { | ||
465 | chunk->enc_data = dst; | ||
466 | if (chunk->num_pcm < PCM_SAMP_PER_CHUNK) | ||
467 | ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4); | ||
193 | /* finish the chunk and store chunk size info */ | 468 | /* finish the chunk and store chunk size info */ |
194 | dst[-1] = WavpackFinishBlock (wpc); | 469 | chunk->enc_size = WavpackFinishBlock(wpc); |
195 | 470 | ci->enc_finish_chunk(); | |
196 | ci->enc_free_chunk(); | 471 | } |
197 | ci->yield(); | ||
198 | } | 472 | } |
199 | 473 | ||
200 | if(ci->enc_wavbuf_near_empty()) | 474 | if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0) |
201 | { | 475 | { |
202 | if(cpu_boosted) | 476 | ci->cpu_boost(false); |
203 | { | 477 | cpu_boosted = false; |
204 | ci->cpu_boost(false); | ||
205 | cpu_boosted = false; | ||
206 | } | ||
207 | } | 478 | } |
479 | |||
208 | ci->yield(); | 480 | ci->yield(); |
209 | } | 481 | } |
210 | 482 | ||
211 | if(cpu_boosted) /* set initial boost state */ | 483 | if (cpu_boosted) /* set initial boost state */ |
212 | ci->cpu_boost(false); | 484 | ci->cpu_boost(false); |
213 | 485 | ||
214 | /* reset parameters to initial state */ | 486 | /* reset parameters to initial state */ |
215 | ci->enc_set_parameters(0, 0, 0, 0, 0, 0); | 487 | ci->enc_set_parameters(NULL); |
216 | 488 | ||
217 | /* main application waits for this flag during encoder removing */ | 489 | /* main application waits for this flag during encoder removing */ |
218 | ci->enc_codec_loaded = false; | 490 | ci->enc_codec_loaded = 0; |
219 | 491 | ||
220 | return CODEC_OK; | 492 | return CODEC_OK; |
221 | } | 493 | } /* codec_start */ |
222 | #endif | 494 | |
495 | #endif /* ndef SIMULATOR */ | ||
diff --git a/apps/eq_menu.c b/apps/eq_menu.c index 6c4dde4a78..9939ee77fe 100644 --- a/apps/eq_menu.c +++ b/apps/eq_menu.c | |||
@@ -710,7 +710,8 @@ static bool eq_save_preset(void) | |||
710 | char filename[MAX_PATH]; | 710 | char filename[MAX_PATH]; |
711 | int *setting; | 711 | int *setting; |
712 | 712 | ||
713 | create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2); | 713 | create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2 |
714 | IF_CNFN_NUM_(, NULL)); | ||
714 | 715 | ||
715 | /* allow user to modify filename */ | 716 | /* allow user to modify filename */ |
716 | while (true) { | 717 | while (true) { |
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c index a8b8c5061b..ae8bba0538 100644 --- a/apps/gui/statusbar.c +++ b/apps/gui/statusbar.c | |||
@@ -124,19 +124,6 @@ | |||
124 | #endif | 124 | #endif |
125 | #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ | 125 | #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ |
126 | STATUSBAR_DISK_WIDTH | 126 | STATUSBAR_DISK_WIDTH |
127 | #if defined(HAVE_RECORDING) | ||
128 | /* analogue frequency numbers taken from the order of frequencies in sample_rate */ | ||
129 | #define FREQ_44 7 | ||
130 | #define FREQ_48 8 | ||
131 | #define FREQ_32 6 | ||
132 | #define FREQ_22 4 | ||
133 | #define FREQ_24 5 | ||
134 | #define FREQ_16 3 | ||
135 | #ifdef HAVE_SPDIF_IN | ||
136 | #define SOURCE_SPDIF 2 | ||
137 | #endif | ||
138 | #endif | ||
139 | |||
140 | struct gui_syncstatusbar statusbars; | 127 | struct gui_syncstatusbar statusbars; |
141 | 128 | ||
142 | void gui_statusbar_init(struct gui_statusbar * bar) | 129 | void gui_statusbar_init(struct gui_statusbar * bar) |
@@ -600,41 +587,113 @@ void gui_statusbar_time(struct screen * display, int hour, int minute) | |||
600 | #endif | 587 | #endif |
601 | 588 | ||
602 | #ifdef HAVE_RECORDING | 589 | #ifdef HAVE_RECORDING |
603 | void gui_statusbar_icon_recording_info(struct screen * display) | 590 | #if CONFIG_CODEC == SWCODEC |
591 | /** | ||
592 | * Write a number to the display using bitmaps and return new position | ||
593 | */ | ||
594 | static int write_bitmap_number(struct screen * display, int value, | ||
595 | int x, int y) | ||
604 | { | 596 | { |
605 | #if (CONFIG_CODEC != SWCODEC) || (defined(SIMULATOR) && defined(HAVE_SPDIF_IN)) | 597 | char buf[12], *ptr; |
606 | char buffer[3]; | 598 | snprintf(buf, sizeof(buf), "%d", value); |
599 | |||
600 | for (ptr = buf; *ptr != '\0'; ptr++, x += BM_GLYPH_WIDTH) | ||
601 | display->mono_bitmap(bitmap_glyphs_4x8[*ptr - '0'], x, y, | ||
602 | BM_GLYPH_WIDTH, STATUSBAR_HEIGHT); | ||
603 | return x; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Write format info bitmaps - right justified | ||
608 | */ | ||
609 | static void gui_statusbar_write_format_info(struct screen * display) | ||
610 | { | ||
611 | /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED | ||
612 | so must use icons */ | ||
613 | int rec_format = global_settings.rec_format; | ||
614 | unsigned bitrk = 0; /* compiler warns about unitialized use !! */ | ||
615 | int xpos = STATUSBAR_ENCODER_X_POS; | ||
616 | int width = STATUSBAR_ENCODER_WIDTH; | ||
617 | const unsigned char *bm = bitmap_formats_18x8[rec_format]; | ||
618 | |||
619 | if (rec_format == REC_FORMAT_MPA_L3) | ||
620 | { | ||
621 | /* Special handling for mp3 */ | ||
622 | bitrk = global_settings.mp3_enc_config.bitrate; | ||
623 | bitrk = mp3_enc_bitr[bitrk]; | ||
624 | |||
625 | width = BM_MPA_L3_M_WIDTH; | ||
626 | |||
627 | /* Slide 'M' to right if fewer than three digits used */ | ||
628 | if (bitrk > 999) | ||
629 | bitrk = 999; /* neurotic safety check if corrupted */ | ||
630 | else | ||
631 | { | ||
632 | if (bitrk < 100) | ||
633 | xpos += BM_GLYPH_WIDTH; | ||
634 | if (bitrk < 10) | ||
635 | xpos += BM_GLYPH_WIDTH; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | |||
640 | /* Show bitmap - clipping right edge if needed */ | ||
641 | display->mono_bitmap_part(bm, 0, 0, STATUSBAR_ENCODER_WIDTH, | ||
642 | xpos, STATUSBAR_Y_POS, width, STATUSBAR_HEIGHT); | ||
643 | |||
644 | if (rec_format == REC_FORMAT_MPA_L3) | ||
645 | { | ||
646 | xpos += BM_MPA_L3_M_WIDTH; /* to right of 'M' */ | ||
647 | write_bitmap_number(display, bitrk, xpos, STATUSBAR_Y_POS); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | /** | ||
652 | * Write sample rate using bitmaps - left justified | ||
653 | */ | ||
654 | static void gui_statusbar_write_samplerate_info(struct screen * display) | ||
655 | { | ||
656 | unsigned long samprk; | ||
657 | int xpos; | ||
658 | |||
659 | #ifdef SIMULATOR | ||
660 | samprk = 44100; | ||
661 | #else | ||
662 | #ifdef HAVE_SPDIF_IN | ||
663 | if (global_settings.rec_source == AUDIO_SRC_SPDIF) | ||
664 | /* Use rate in use, not current measured rate if it changed */ | ||
665 | samprk = pcm_rec_sample_rate(); | ||
666 | else | ||
607 | #endif | 667 | #endif |
668 | samprk = rec_freq_sampr[global_settings.rec_frequency]; | ||
669 | #endif /* SIMULATOR */ | ||
670 | |||
671 | samprk /= 1000; | ||
672 | if (samprk > 99) | ||
673 | samprk = 99; /* Limit to 3 glyphs */ | ||
674 | |||
675 | xpos = write_bitmap_number(display, (unsigned)samprk, | ||
676 | STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS); | ||
677 | |||
678 | /* write the 'k' */ | ||
679 | display->mono_bitmap(bitmap_glyphs_4x8[Glyph_4x8_k], xpos, | ||
680 | STATUSBAR_Y_POS, BM_GLYPH_WIDTH, | ||
681 | STATUSBAR_HEIGHT); | ||
682 | } | ||
683 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
684 | |||
685 | void gui_statusbar_icon_recording_info(struct screen * display) | ||
686 | { | ||
608 | #if CONFIG_CODEC != SWCODEC | 687 | #if CONFIG_CODEC != SWCODEC |
688 | char buffer[3]; | ||
609 | int width, height; | 689 | int width, height; |
610 | static char* const sample_rate[12] = | ||
611 | { | ||
612 | "8", | ||
613 | "11", | ||
614 | "12", | ||
615 | "16", | ||
616 | "22", | ||
617 | "24", | ||
618 | "32", | ||
619 | "44", | ||
620 | "48", | ||
621 | "64", | ||
622 | "88", | ||
623 | "96" | ||
624 | }; | ||
625 | |||
626 | display->setfont(FONT_SYSFIXED); | 690 | display->setfont(FONT_SYSFIXED); |
627 | #endif | 691 | #endif /* CONFIG_CODEC != SWCODEC */ |
628 | 692 | ||
629 | /* Display Codec info in statusbar */ | 693 | /* Display Codec info in statusbar */ |
630 | #if CONFIG_CODEC == SWCODEC | 694 | #if CONFIG_CODEC == SWCODEC |
631 | /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED | 695 | gui_statusbar_write_format_info(display); |
632 | so must use icons */ | 696 | #else /* !SWCODEC */ |
633 | display->mono_bitmap(bitmap_icons_18x8[global_settings.rec_quality], | ||
634 | STATUSBAR_ENCODER_X_POS, STATUSBAR_Y_POS, | ||
635 | STATUSBAR_ENCODER_WIDTH, STATUSBAR_HEIGHT); | ||
636 | #else | ||
637 | |||
638 | display->mono_bitmap(bitmap_icons_5x8[Icon_q], | 697 | display->mono_bitmap(bitmap_icons_5x8[Icon_q], |
639 | STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS, | 698 | STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS, |
640 | 5, STATUSBAR_HEIGHT); | 699 | 5, STATUSBAR_HEIGHT); |
@@ -643,56 +702,37 @@ void gui_statusbar_icon_recording_info(struct screen * display) | |||
643 | display->getstringsize(buffer, &width, &height); | 702 | display->getstringsize(buffer, &width, &height); |
644 | if (height <= STATUSBAR_HEIGHT) | 703 | if (height <= STATUSBAR_HEIGHT) |
645 | display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer); | 704 | display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer); |
646 | #endif | 705 | #endif /* CONFIG_CODEC == SWCODEC */ |
647 | 706 | ||
648 | /* Display Samplerate info in statusbar */ | 707 | /* Display Samplerate info in statusbar */ |
649 | #if defined(HAVE_SPDIF_IN) | 708 | #if CONFIG_CODEC == SWCODEC |
650 | if (global_settings.rec_source == SOURCE_SPDIF) | 709 | /* SWCODEC targets use bitmaps for glyphs */ |
710 | gui_statusbar_write_samplerate_info(display); | ||
711 | #else /* !SWCODEC */ | ||
712 | /* hwcodec targets have sysfont characters */ | ||
713 | #ifdef HAVE_SPDIF_IN | ||
714 | if (global_settings.rec_source == AUDIO_SRC_SPDIF) | ||
651 | { | 715 | { |
652 | #if (CONFIG_CODEC != MAS3587F) && !defined(SIMULATOR) | ||
653 | display->mono_bitmap(bitmap_icons_12x8[audio_get_spdif_sample_rate()], | ||
654 | STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, | ||
655 | STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT); | ||
656 | #else | ||
657 | /* Can't measure S/PDIF sample rate on Archos/Sim yet */ | 716 | /* Can't measure S/PDIF sample rate on Archos/Sim yet */ |
658 | snprintf(buffer, sizeof(buffer), "--"); | 717 | snprintf(buffer, sizeof(buffer), "--"); |
659 | #endif | ||
660 | } | 718 | } |
661 | else | 719 | else |
662 | #endif /* HAVE_SPDIF_IN */ | 720 | #endif /* HAVE_SPDIF_IN */ |
663 | { | 721 | { |
664 | /* Analogue frequency in wrong order so remap settings numbers */ | 722 | static char const * const freq_strings[12] = |
665 | int freq = global_settings.rec_frequency; | 723 | { "44", "48", "32", "22", "24", "16" }; |
666 | if (freq == 0) | 724 | snprintf(buffer, sizeof(buffer), "%s", |
667 | freq = FREQ_44; | 725 | freq_strings[global_settings.rec_frequency]); |
668 | else if (freq == 1) | ||
669 | freq = FREQ_48; | ||
670 | else if (freq == 2) | ||
671 | freq = FREQ_32; | ||
672 | else if (freq == 3) | ||
673 | freq = FREQ_22; | ||
674 | else if (freq == 4) | ||
675 | freq = FREQ_24; | ||
676 | else if (freq == 5) | ||
677 | freq = FREQ_16; | ||
678 | |||
679 | #if CONFIG_CODEC == SWCODEC | ||
680 | /* samplerate icons for swcodec targets*/ | ||
681 | display->mono_bitmap(bitmap_icons_12x8[freq], | ||
682 | STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, | ||
683 | STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT); | ||
684 | } | ||
685 | #else | ||
686 | /* hwcodec targets have sysfont characters */ | ||
687 | snprintf(buffer, sizeof(buffer), "%s", sample_rate[freq]); | ||
688 | display->getstringsize(buffer, &width, &height); | ||
689 | } | 726 | } |
690 | 727 | ||
691 | if (height <= STATUSBAR_HEIGHT) | 728 | display->getstringsize(buffer, &width, &height); |
692 | display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer); | 729 | |
730 | if (height <= STATUSBAR_HEIGHT) | ||
731 | display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer); | ||
732 | |||
733 | display->setfont(FONT_UI); | ||
734 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
693 | 735 | ||
694 | display->setfont(FONT_UI); | ||
695 | #endif | ||
696 | /* Display Channel status in status bar */ | 736 | /* Display Channel status in status bar */ |
697 | if(global_settings.rec_channels) | 737 | if(global_settings.rec_channels) |
698 | { | 738 | { |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 40d7bb7b19..8f7deb78a9 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -9802,7 +9802,7 @@ | |||
9802 | </phrase> | 9802 | </phrase> |
9803 | <phrase> | 9803 | <phrase> |
9804 | id: VOICE_KBIT_PER_SEC | 9804 | id: VOICE_KBIT_PER_SEC |
9805 | desc: spoken only, for file extension | 9805 | desc: spoken only, a unit postfix |
9806 | user: | 9806 | user: |
9807 | <source> | 9807 | <source> |
9808 | *: "" | 9808 | *: "" |
@@ -10032,3 +10032,115 @@ | |||
10032 | *: "" | 10032 | *: "" |
10033 | </voice> | 10033 | </voice> |
10034 | </phrase> | 10034 | </phrase> |
10035 | <phrase> | ||
10036 | id: LANG_RECORDING_FORMAT | ||
10037 | desc: audio format item in recording menu | ||
10038 | user: | ||
10039 | <source> | ||
10040 | *: "Format" | ||
10041 | </source> | ||
10042 | <dest> | ||
10043 | *: "Format" | ||
10044 | </dest> | ||
10045 | <voice> | ||
10046 | *: "Format" | ||
10047 | </voice> | ||
10048 | </phrase> | ||
10049 | <phrase> | ||
10050 | id: LANG_AFMT_MPA_L3 | ||
10051 | desc: audio format description | ||
10052 | user: | ||
10053 | <source> | ||
10054 | *: "MPEG Layer 3" | ||
10055 | </source> | ||
10056 | <dest> | ||
10057 | *: "MPEG Layer 3" | ||
10058 | </dest> | ||
10059 | <voice> | ||
10060 | *: "MPEG Layer 3" | ||
10061 | </voice> | ||
10062 | </phrase> | ||
10063 | <phrase> | ||
10064 | id: LANG_AFMT_PCM_WAV | ||
10065 | desc: audio format description | ||
10066 | user: | ||
10067 | <source> | ||
10068 | *: "PCM Wave" | ||
10069 | </source> | ||
10070 | <dest> | ||
10071 | *: "PCM Wave" | ||
10072 | </dest> | ||
10073 | <voice> | ||
10074 | *: "PCM Wave" | ||
10075 | </voice> | ||
10076 | </phrase> | ||
10077 | <phrase> | ||
10078 | id: LANG_AFMT_WAVPACK | ||
10079 | desc: audio format description | ||
10080 | user: | ||
10081 | <source> | ||
10082 | *: "WavPack" | ||
10083 | </source> | ||
10084 | <dest> | ||
10085 | *: "WavPack" | ||
10086 | </dest> | ||
10087 | <voice> | ||
10088 | *: "WavPack" | ||
10089 | </voice> | ||
10090 | </phrase> | ||
10091 | <phrase> | ||
10092 | id: LANG_ENCODER_SETTINGS | ||
10093 | desc: encoder settings | ||
10094 | user: | ||
10095 | <source> | ||
10096 | *: "Encoder Settings" | ||
10097 | </source> | ||
10098 | <dest> | ||
10099 | *: "Encoder Settings" | ||
10100 | </dest> | ||
10101 | <voice> | ||
10102 | *: "Encoder Settings" | ||
10103 | </voice> | ||
10104 | </phrase> | ||
10105 | <phrase> | ||
10106 | id: LANG_NO_SETTINGS | ||
10107 | desc: when something has settings in a certain context | ||
10108 | user: | ||
10109 | <source> | ||
10110 | *: "(No Settings)" | ||
10111 | </source> | ||
10112 | <dest> | ||
10113 | *: "(No Settings)" | ||
10114 | </dest> | ||
10115 | <voice> | ||
10116 | *: "No settings available" | ||
10117 | </voice> | ||
10118 | </phrase> | ||
10119 | <phrase> | ||
10120 | id: LANG_SOURCE_FREQUENCY | ||
10121 | desc: when recording source frequency setting must follow source | ||
10122 | user: | ||
10123 | <source> | ||
10124 | *: "(Same As Source)" | ||
10125 | </source> | ||
10126 | <dest> | ||
10127 | *: "(Same As Source)" | ||
10128 | </dest> | ||
10129 | <voice> | ||
10130 | *: "Same As Source" | ||
10131 | </voice> | ||
10132 | </phrase> | ||
10133 | <phrase> | ||
10134 | id: LANG_BITRATE | ||
10135 | desc: bits-kilobits per unit time | ||
10136 | user: | ||
10137 | <source> | ||
10138 | *: "Bitrate" | ||
10139 | </source> | ||
10140 | <dest> | ||
10141 | *: "Bitrate" | ||
10142 | </dest> | ||
10143 | <voice> | ||
10144 | *: "Bitrate" | ||
10145 | </voice> | ||
10146 | </phrase> | ||
diff --git a/apps/main.c b/apps/main.c index c4ee45cb89..05b4ab54a3 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -286,6 +286,9 @@ void init(void) | |||
286 | 286 | ||
287 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 287 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
288 | set_cpu_frequency(CPUFREQ_NORMAL); | 288 | set_cpu_frequency(CPUFREQ_NORMAL); |
289 | #ifdef CPU_COLDFIRE | ||
290 | coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); | ||
291 | #endif | ||
289 | cpu_boost_id(true, CPUBOOSTID_MAININIT); | 292 | cpu_boost_id(true, CPUBOOSTID_MAININIT); |
290 | #endif | 293 | #endif |
291 | 294 | ||
diff --git a/apps/metadata.c b/apps/metadata.c index ee0100ecf7..845536877c 100644 --- a/apps/metadata.c +++ b/apps/metadata.c | |||
@@ -88,36 +88,6 @@ struct apetag_item_header | |||
88 | long flags; | 88 | long flags; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | struct format_list | ||
92 | { | ||
93 | char format; | ||
94 | char extension[5]; | ||
95 | }; | ||
96 | |||
97 | static const struct format_list formats[] = | ||
98 | { | ||
99 | { AFMT_MPA_L1, "mp1" }, | ||
100 | { AFMT_MPA_L2, "mp2" }, | ||
101 | { AFMT_MPA_L2, "mpa" }, | ||
102 | { AFMT_MPA_L3, "mp3" }, | ||
103 | #if CONFIG_CODEC == SWCODEC | ||
104 | { AFMT_OGG_VORBIS, "ogg" }, | ||
105 | { AFMT_PCM_WAV, "wav" }, | ||
106 | { AFMT_FLAC, "flac" }, | ||
107 | { AFMT_MPC, "mpc" }, | ||
108 | { AFMT_A52, "a52" }, | ||
109 | { AFMT_A52, "ac3" }, | ||
110 | { AFMT_WAVPACK, "wv" }, | ||
111 | { AFMT_ALAC, "m4a" }, | ||
112 | { AFMT_AAC, "mp4" }, | ||
113 | { AFMT_SHN, "shn" }, | ||
114 | { AFMT_AIFF, "aif" }, | ||
115 | { AFMT_AIFF, "aiff" }, | ||
116 | { AFMT_SID, "sid" }, | ||
117 | { AFMT_ADX, "adx" }, | ||
118 | #endif | ||
119 | }; | ||
120 | |||
121 | #if CONFIG_CODEC == SWCODEC | 91 | #if CONFIG_CODEC == SWCODEC |
122 | static const unsigned short a52_bitrates[] = | 92 | static const unsigned short a52_bitrates[] = |
123 | { | 93 | { |
@@ -1691,14 +1661,24 @@ unsigned int probe_file_format(const char *filename) | |||
1691 | return AFMT_UNKNOWN; | 1661 | return AFMT_UNKNOWN; |
1692 | } | 1662 | } |
1693 | 1663 | ||
1694 | suffix += 1; | 1664 | /* skip '.' */ |
1665 | suffix++; | ||
1666 | |||
1667 | for (i = 1; i < AFMT_NUM_CODECS; i++) | ||
1668 | { | ||
1669 | /* search extension list for type */ | ||
1670 | const char *ext = audio_formats[i].ext_list; | ||
1695 | 1671 | ||
1696 | for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) | 1672 | do |
1697 | { | 1673 | { |
1698 | if (strcasecmp(suffix, formats[i].extension) == 0) | 1674 | if (strcasecmp(suffix, ext) == 0) |
1699 | { | 1675 | { |
1700 | return formats[i].format; | 1676 | return i; |
1677 | } | ||
1678 | |||
1679 | ext += strlen(ext) + 1; | ||
1701 | } | 1680 | } |
1681 | while (*ext != '\0'); | ||
1702 | } | 1682 | } |
1703 | 1683 | ||
1704 | return AFMT_UNKNOWN; | 1684 | return AFMT_UNKNOWN; |
diff --git a/apps/misc.c b/apps/misc.c index c36d61914b..01463851be 100644 --- a/apps/misc.c +++ b/apps/misc.c | |||
@@ -58,6 +58,8 @@ | |||
58 | #endif /* End HAVE_LCD_BITMAP */ | 58 | #endif /* End HAVE_LCD_BITMAP */ |
59 | #include "gui/gwps-common.h" | 59 | #include "gui/gwps-common.h" |
60 | 60 | ||
61 | #include "misc.h" | ||
62 | |||
61 | /* Format a large-range value for output, using the appropriate unit so that | 63 | /* Format a large-range value for output, using the appropriate unit so that |
62 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" | 64 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" |
63 | * units) if possible, and 3 significant digits are shown. If a buffer is | 65 | * units) if possible, and 3 significant digits are shown. If a buffer is |
@@ -114,16 +116,20 @@ char *output_dyn_value(char *buf, int buf_size, int value, | |||
114 | } | 116 | } |
115 | 117 | ||
116 | /* Create a filename with a number part in a way that the number is 1 | 118 | /* Create a filename with a number part in a way that the number is 1 |
117 | higher than the highest numbered file matching the same pattern. | 119 | * higher than the highest numbered file matching the same pattern. |
118 | It is allowed that buffer and path point to the same memory location, | 120 | * It is allowed that buffer and path point to the same memory location, |
119 | saving a strcpy(). Path must always be given without trailing slash,. */ | 121 | * saving a strcpy(). Path must always be given without trailing slash. |
122 | * "num" can point to an int specifying the number to use or NULL or a value | ||
123 | * less than zero to number automatically. The final number used will also | ||
124 | * be returned in *num. If *num is >= 0 then *num will be incremented by | ||
125 | * one. */ | ||
120 | char *create_numbered_filename(char *buffer, const char *path, | 126 | char *create_numbered_filename(char *buffer, const char *path, |
121 | const char *prefix, const char *suffix, | 127 | const char *prefix, const char *suffix, |
122 | int numberlen) | 128 | int numberlen IF_CNFN_NUM_(, int *num)) |
123 | { | 129 | { |
124 | DIR *dir; | 130 | DIR *dir; |
125 | struct dirent *entry; | 131 | struct dirent *entry; |
126 | int max_num = 0; | 132 | int max_num; |
127 | int pathlen; | 133 | int pathlen; |
128 | int prefixlen = strlen(prefix); | 134 | int prefixlen = strlen(prefix); |
129 | char fmtstring[12]; | 135 | char fmtstring[12]; |
@@ -133,6 +139,18 @@ char *create_numbered_filename(char *buffer, const char *path, | |||
133 | 139 | ||
134 | pathlen = strlen(buffer); | 140 | pathlen = strlen(buffer); |
135 | 141 | ||
142 | #ifdef IF_CNFN_NUM | ||
143 | if (num && *num >= 0) | ||
144 | { | ||
145 | /* number specified */ | ||
146 | max_num = *num; | ||
147 | } | ||
148 | else | ||
149 | #endif | ||
150 | { | ||
151 | /* automatic numbering */ | ||
152 | max_num = 0; | ||
153 | |||
136 | dir = opendir(pathlen ? buffer : "/"); | 154 | dir = opendir(pathlen ? buffer : "/"); |
137 | if (!dir) | 155 | if (!dir) |
138 | return NULL; | 156 | return NULL; |
@@ -149,11 +167,20 @@ char *create_numbered_filename(char *buffer, const char *path, | |||
149 | if (curr_num > max_num) | 167 | if (curr_num > max_num) |
150 | max_num = curr_num; | 168 | max_num = curr_num; |
151 | } | 169 | } |
170 | |||
152 | closedir(dir); | 171 | closedir(dir); |
172 | } | ||
173 | |||
174 | max_num++; | ||
153 | 175 | ||
154 | snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen); | 176 | snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen); |
155 | snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix, | 177 | snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix, |
156 | max_num + 1, suffix); | 178 | max_num, suffix); |
179 | |||
180 | #ifdef IF_CNFN_NUM | ||
181 | if (num) | ||
182 | *num = max_num; | ||
183 | #endif | ||
157 | 184 | ||
158 | return buffer; | 185 | return buffer; |
159 | } | 186 | } |
@@ -161,13 +188,22 @@ char *create_numbered_filename(char *buffer, const char *path, | |||
161 | #ifdef CONFIG_RTC | 188 | #ifdef CONFIG_RTC |
162 | /* Create a filename with a date+time part. | 189 | /* Create a filename with a date+time part. |
163 | It is allowed that buffer and path point to the same memory location, | 190 | It is allowed that buffer and path point to the same memory location, |
164 | saving a strcpy(). Path must always be given without trailing slash. */ | 191 | saving a strcpy(). Path must always be given without trailing slash. |
192 | unique_time as true makes the function wait until the current time has | ||
193 | changed. */ | ||
165 | char *create_datetime_filename(char *buffer, const char *path, | 194 | char *create_datetime_filename(char *buffer, const char *path, |
166 | const char *prefix, const char *suffix) | 195 | const char *prefix, const char *suffix, |
196 | bool unique_time) | ||
167 | { | 197 | { |
168 | struct tm *tm = get_time(); | 198 | struct tm *tm = get_time(); |
199 | static struct tm last_tm; | ||
169 | int pathlen; | 200 | int pathlen; |
170 | 201 | ||
202 | while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm))) | ||
203 | sleep(HZ/10); | ||
204 | |||
205 | last_tm = *tm; | ||
206 | |||
171 | if (buffer != path) | 207 | if (buffer != path) |
172 | strncpy(buffer, path, MAX_PATH); | 208 | strncpy(buffer, path, MAX_PATH); |
173 | 209 | ||
@@ -356,9 +392,10 @@ void screen_dump(void) | |||
356 | #endif | 392 | #endif |
357 | 393 | ||
358 | #ifdef CONFIG_RTC | 394 | #ifdef CONFIG_RTC |
359 | create_datetime_filename(filename, "", "dump ", ".bmp"); | 395 | create_datetime_filename(filename, "", "dump ", ".bmp", false); |
360 | #else | 396 | #else |
361 | create_numbered_filename(filename, "", "dump_", ".bmp", 4); | 397 | create_numbered_filename(filename, "", "dump_", ".bmp", 4 |
398 | IF_CNFN_NUM_(, NULL)); | ||
362 | #endif | 399 | #endif |
363 | 400 | ||
364 | fh = creat(filename, O_WRONLY); | 401 | fh = creat(filename, O_WRONLY); |
diff --git a/apps/misc.h b/apps/misc.h index 1bc9a23447..6c660e0a5e 100644 --- a/apps/misc.h +++ b/apps/misc.h | |||
@@ -19,21 +19,46 @@ | |||
19 | #ifndef MISC_H | 19 | #ifndef MISC_H |
20 | #define MISC_H | 20 | #define MISC_H |
21 | 21 | ||
22 | #include <stdbool.h> | ||
23 | |||
22 | /* Format a large-range value for output, using the appropriate unit so that | 24 | /* Format a large-range value for output, using the appropriate unit so that |
23 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" | 25 | * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" |
24 | * units) if possible, and 3 significant digits are shown. If a buffer is | 26 | * units) if possible, and 3 significant digits are shown. If a buffer is |
25 | * given, the result is snprintf()'d into that buffer, otherwise the result is | 27 | * given, the result is snprintf()'d into that buffer, otherwise the result is |
26 | * voiced.*/ | 28 | * voiced.*/ |
27 | void output_dyn_value(char *buf, int buf_size, int value, | 29 | char *output_dyn_value(char *buf, int buf_size, int value, |
28 | const unsigned char **units, bool bin_scale); | 30 | const unsigned char **units, bool bin_scale); |
29 | 31 | ||
32 | /* Create a filename with a number part in a way that the number is 1 | ||
33 | * higher than the highest numbered file matching the same pattern. | ||
34 | * It is allowed that buffer and path point to the same memory location, | ||
35 | * saving a strcpy(). Path must always be given without trailing slash. | ||
36 | * | ||
37 | * "num" can point to an int specifying the number to use or NULL or a value | ||
38 | * less than zero to number automatically. The final number used will also | ||
39 | * be returned in *num. If *num is >= 0 then *num will be incremented by | ||
40 | * one. */ | ||
41 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(CONFIG_RTC) | ||
42 | /* this feature is needed by SWCODEC recording without a RTC to prevent | ||
43 | disk access when changing files */ | ||
44 | #define IF_CNFN_NUM_(...) __VA_ARGS__ | ||
45 | #define IF_CNFN_NUM | ||
46 | #else | ||
47 | #define IF_CNFN_NUM_(...) | ||
48 | #endif | ||
30 | char *create_numbered_filename(char *buffer, const char *path, | 49 | char *create_numbered_filename(char *buffer, const char *path, |
31 | const char *prefix, const char *suffix, | 50 | const char *prefix, const char *suffix, |
32 | int numberlen); | 51 | int numberlen IF_CNFN_NUM_(, int *num)); |
33 | #ifdef CONFIG_RTC | 52 | #ifdef CONFIG_RTC |
53 | /* Create a filename with a date+time part. | ||
54 | It is allowed that buffer and path point to the same memory location, | ||
55 | saving a strcpy(). Path must always be given without trailing slash. | ||
56 | unique_time as true makes the function wait until the current time has | ||
57 | changed. */ | ||
34 | char *create_datetime_filename(char *buffer, const char *path, | 58 | char *create_datetime_filename(char *buffer, const char *path, |
35 | const char *prefix, const char *suffix); | 59 | const char *prefix, const char *suffix, |
36 | #endif | 60 | bool unique_time); |
61 | #endif /* CONFIG_RTC */ | ||
37 | 62 | ||
38 | /* Read (up to) a line of text from fd into buffer and return number of bytes | 63 | /* Read (up to) a line of text from fd into buffer and return number of bytes |
39 | * read (which may be larger than the number of bytes stored in buffer). If | 64 | * read (which may be larger than the number of bytes stored in buffer). If |
@@ -57,4 +82,4 @@ long default_event_handler(long event); | |||
57 | void car_adapter_mode_init(void); | 82 | void car_adapter_mode_init(void); |
58 | extern int show_logo(void); | 83 | extern int show_logo(void); |
59 | 84 | ||
60 | #endif | 85 | #endif /* MISC_H */ |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 44f175c67d..5119d20ebd 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -51,9 +51,11 @@ struct pcmbufdesc | |||
51 | void (*callback)(void); | 51 | void (*callback)(void); |
52 | }; | 52 | }; |
53 | 53 | ||
54 | #define PCMBUF_DESCS(bufsize) ((bufsize) / PCMBUF_MINAVG_CHUNK) | ||
55 | |||
54 | /* Size of the PCM buffer. */ | 56 | /* Size of the PCM buffer. */ |
55 | static size_t pcmbuf_size IDATA_ATTR = 0; | 57 | static size_t pcmbuf_size IDATA_ATTR = 0; |
56 | 58 | static char *pcmbuf_bufend IDATA_ATTR; | |
57 | static char *audiobuffer IDATA_ATTR; | 59 | static char *audiobuffer IDATA_ATTR; |
58 | /* Current audio buffer write index. */ | 60 | /* Current audio buffer write index. */ |
59 | static size_t audiobuffer_pos IDATA_ATTR; | 61 | static size_t audiobuffer_pos IDATA_ATTR; |
@@ -360,7 +362,7 @@ int pcmbuf_used_descs(void) { | |||
360 | } | 362 | } |
361 | 363 | ||
362 | int pcmbuf_descs(void) { | 364 | int pcmbuf_descs(void) { |
363 | return pcmbuf_size / PCMBUF_MINAVG_CHUNK; | 365 | return PCMBUF_DESCS(pcmbuf_size); |
364 | } | 366 | } |
365 | 367 | ||
366 | size_t get_pcmbuf_descsize(void) { | 368 | size_t get_pcmbuf_descsize(void) { |
@@ -371,28 +373,37 @@ static void pcmbuf_init_pcmbuffers(void) { | |||
371 | struct pcmbufdesc *next = pcmbuf_write; | 373 | struct pcmbufdesc *next = pcmbuf_write; |
372 | next++; | 374 | next++; |
373 | pcmbuf_write_end = pcmbuf_write; | 375 | pcmbuf_write_end = pcmbuf_write; |
374 | while ((void *)next < (void *)audiobufend) { | 376 | while ((void *)next < (void *)pcmbuf_bufend) { |
375 | pcmbuf_write_end->link=next; | 377 | pcmbuf_write_end->link=next; |
376 | pcmbuf_write_end=next; | 378 | pcmbuf_write_end=next; |
377 | next++; | 379 | next++; |
378 | } | 380 | } |
379 | } | 381 | } |
380 | 382 | ||
383 | bool pcmbuf_is_same_size(size_t bufsize) | ||
384 | { | ||
385 | /* keep calculations synced with pcmbuf_init */ | ||
386 | bufsize += PCMBUF_MIX_CHUNK * 2 + PCMBUF_DESCS(bufsize); | ||
387 | return bufsize == (size_t)(pcmbuf_bufend - audiobuffer); | ||
388 | } | ||
389 | |||
381 | /* Initialize the pcmbuffer the structure looks like this: | 390 | /* Initialize the pcmbuffer the structure looks like this: |
382 | * ...CODECBUFFER|---------PCMBUF---------|GUARDBUF|DESCS| */ | 391 | * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */ |
383 | void pcmbuf_init(size_t bufsize) | 392 | size_t pcmbuf_init(size_t bufsize, char *bufend) |
384 | { | 393 | { |
385 | pcmbuf_size = bufsize; | 394 | pcmbuf_size = bufsize; |
395 | pcmbuf_bufend = bufend; | ||
386 | pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc); | 396 | pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc); |
387 | audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - | 397 | audiobuffer = pcmbuf_bufend - (pcmbuf_size + PCMBUF_MIX_CHUNK * 2 |
388 | (pcmbuf_size + PCMBUF_MIX_CHUNK * 2 + pcmbuf_descsize)]; | 398 | + pcmbuf_descsize); |
389 | fadebuf = &audiobuffer[pcmbuf_size]; | 399 | fadebuf = &audiobuffer[pcmbuf_size]; |
390 | voicebuf = &fadebuf[PCMBUF_MIX_CHUNK]; | 400 | voicebuf = &fadebuf[PCMBUF_MIX_CHUNK]; |
391 | pcmbuf_write = (struct pcmbufdesc *)(&voicebuf[PCMBUF_MIX_CHUNK]); | 401 | pcmbuf_write = (struct pcmbufdesc *)&voicebuf[PCMBUF_MIX_CHUNK]; |
392 | pcmbuf_init_pcmbuffers(); | 402 | pcmbuf_init_pcmbuffers(); |
393 | position_callback = NULL; | 403 | position_callback = NULL; |
394 | pcmbuf_event_handler = NULL; | 404 | pcmbuf_event_handler = NULL; |
395 | pcmbuf_play_stop(); | 405 | pcmbuf_play_stop(); |
406 | return pcmbuf_bufend - audiobuffer; | ||
396 | } | 407 | } |
397 | 408 | ||
398 | size_t pcmbuf_get_bufsize(void) | 409 | size_t pcmbuf_get_bufsize(void) |
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index b5035f4405..a408cdae42 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h | |||
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | /* Returns true if the buffer needs to change size */ | 39 | /* Returns true if the buffer needs to change size */ |
40 | bool pcmbuf_is_same_size(size_t bufsize); | 40 | bool pcmbuf_is_same_size(size_t bufsize); |
41 | void pcmbuf_init(size_t bufsize); | 41 | size_t pcmbuf_init(size_t bufsize, char *bufend); |
42 | /* Size in bytes used by the pcmbuffer */ | 42 | /* Size in bytes used by the pcmbuffer */ |
43 | size_t pcmbuf_get_bufsize(void); | 43 | size_t pcmbuf_get_bufsize(void); |
44 | size_t get_pcmbuf_descsize(void); | 44 | size_t get_pcmbuf_descsize(void); |
diff --git a/apps/playback.c b/apps/playback.c index f8372665a4..af6b573f1d 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -54,8 +54,6 @@ | |||
54 | #include "playlist.h" | 54 | #include "playlist.h" |
55 | #include "playback.h" | 55 | #include "playback.h" |
56 | #include "pcmbuf.h" | 56 | #include "pcmbuf.h" |
57 | #include "pcm_playback.h" | ||
58 | #include "pcm_record.h" | ||
59 | #include "buffer.h" | 57 | #include "buffer.h" |
60 | #include "dsp.h" | 58 | #include "dsp.h" |
61 | #include "abrepeat.h" | 59 | #include "abrepeat.h" |
@@ -78,6 +76,7 @@ | |||
78 | 76 | ||
79 | #ifdef HAVE_RECORDING | 77 | #ifdef HAVE_RECORDING |
80 | #include "recording.h" | 78 | #include "recording.h" |
79 | #include "talk.h" | ||
81 | #endif | 80 | #endif |
82 | 81 | ||
83 | #define PLAYBACK_VOICE | 82 | #define PLAYBACK_VOICE |
@@ -93,9 +92,13 @@ | |||
93 | * for their correct seeek target, 32k seems a good size */ | 92 | * for their correct seeek target, 32k seems a good size */ |
94 | #define AUDIO_REBUFFER_GUESS_SIZE (1024*32) | 93 | #define AUDIO_REBUFFER_GUESS_SIZE (1024*32) |
95 | 94 | ||
96 | /* macros to enable logf for queues */ | 95 | /* macros to enable logf for queues |
96 | logging on SYS_TIMEOUT can be disabled */ | ||
97 | #ifdef SIMULATOR | 97 | #ifdef SIMULATOR |
98 | #define PLAYBACK_LOGQUEUES /* Define this for logf output of all queuing */ | 98 | /* Define this for logf output of all queuing except SYS_TIMEOUT */ |
99 | #define PLAYBACK_LOGQUEUES | ||
100 | /* Define this to logf SYS_TIMEOUT messages */ | ||
101 | #define PLAYBACK_LOGQUEUES_SYS_TIMEOUT | ||
99 | #endif | 102 | #endif |
100 | 103 | ||
101 | #ifdef PLAYBACK_LOGQUEUES | 104 | #ifdef PLAYBACK_LOGQUEUES |
@@ -104,6 +107,18 @@ | |||
104 | #define LOGFQUEUE(s) | 107 | #define LOGFQUEUE(s) |
105 | #endif | 108 | #endif |
106 | 109 | ||
110 | #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT | ||
111 | #define LOGFQUEUE_SYS_TIMEOUT(s) logf("%s", s) | ||
112 | #else | ||
113 | #define LOGFQUEUE_SYS_TIMEOUT(s) | ||
114 | #endif | ||
115 | |||
116 | |||
117 | /* Define one constant that includes recording related functionality */ | ||
118 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
119 | #define AUDIO_HAVE_RECORDING | ||
120 | #endif | ||
121 | |||
107 | enum { | 122 | enum { |
108 | Q_AUDIO_PLAY = 1, | 123 | Q_AUDIO_PLAY = 1, |
109 | Q_AUDIO_STOP, | 124 | Q_AUDIO_STOP, |
@@ -122,6 +137,9 @@ enum { | |||
122 | #if MEM > 8 | 137 | #if MEM > 8 |
123 | Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, | 138 | Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, |
124 | #endif | 139 | #endif |
140 | #ifdef AUDIO_HAVE_RECORDING | ||
141 | Q_AUDIO_LOAD_ENCODER, | ||
142 | #endif | ||
125 | 143 | ||
126 | Q_CODEC_REQUEST_PENDING, | 144 | Q_CODEC_REQUEST_PENDING, |
127 | Q_CODEC_REQUEST_COMPLETE, | 145 | Q_CODEC_REQUEST_COMPLETE, |
@@ -133,7 +151,7 @@ enum { | |||
133 | Q_CODEC_LOAD, | 151 | Q_CODEC_LOAD, |
134 | Q_CODEC_LOAD_DISK, | 152 | Q_CODEC_LOAD_DISK, |
135 | 153 | ||
136 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 154 | #ifdef AUDIO_HAVE_RECORDING |
137 | Q_ENCODER_LOAD_DISK, | 155 | Q_ENCODER_LOAD_DISK, |
138 | Q_ENCODER_RECORD, | 156 | Q_ENCODER_RECORD, |
139 | #endif | 157 | #endif |
@@ -178,11 +196,16 @@ static volatile bool paused; /* Is audio paused? (A/C-) */ | |||
178 | static volatile bool filling IDATA_ATTR; /* Is file buffer currently being refilled? (A/C-) */ | 196 | static volatile bool filling IDATA_ATTR; /* Is file buffer currently being refilled? (A/C-) */ |
179 | 197 | ||
180 | /* Ring buffer where tracks and codecs are loaded */ | 198 | /* Ring buffer where tracks and codecs are loaded */ |
181 | static char *filebuf; /* Pointer to start of ring buffer (A/C-) */ | 199 | static unsigned char *filebuf; /* Pointer to start of ring buffer (A/C-) */ |
182 | size_t filebuflen; /* Total size of the ring buffer FIXME: make static (A/C-)*/ | 200 | size_t filebuflen; /* Total size of the ring buffer FIXME: make static (A/C-)*/ |
183 | static volatile size_t buf_ridx IDATA_ATTR; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */ | 201 | static volatile size_t buf_ridx IDATA_ATTR; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */ |
184 | static volatile size_t buf_widx IDATA_ATTR; /* Ring buffer read position (A/C-) */ | 202 | static volatile size_t buf_widx IDATA_ATTR; /* Ring buffer read position (A/C-) */ |
185 | 203 | ||
204 | #define BUFFER_STATE_TRASHED -1 /* Buffer is in a trashed state and must be reset */ | ||
205 | #define BUFFER_STATE_NORMAL 0 /* Buffer is arranged for voice and audio */ | ||
206 | #define BUFFER_STATE_VOICED_ONLY 1 /* Buffer is arranged for voice-only use */ | ||
207 | static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */ | ||
208 | |||
186 | #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen) | 209 | #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen) |
187 | #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v) | 210 | #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v) |
188 | #define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen) | 211 | #define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen) |
@@ -235,7 +258,7 @@ static const char audio_thread_name[] = "audio"; | |||
235 | static void audio_thread(void); | 258 | static void audio_thread(void); |
236 | static void audio_initiate_track_change(long direction); | 259 | static void audio_initiate_track_change(long direction); |
237 | static bool audio_have_tracks(void); | 260 | static bool audio_have_tracks(void); |
238 | static void audio_reset_buffer(void); | 261 | static void audio_reset_buffer(size_t pcmbufsize); |
239 | 262 | ||
240 | /* Codec thread */ | 263 | /* Codec thread */ |
241 | extern struct codec_api ci; | 264 | extern struct codec_api ci; |
@@ -294,6 +317,10 @@ static void voice_thread(void); | |||
294 | void mp3_play_data(const unsigned char* start, int size, | 317 | void mp3_play_data(const unsigned char* start, int size, |
295 | void (*get_more)(unsigned char** start, int* size)) | 318 | void (*get_more)(unsigned char** start, int* size)) |
296 | { | 319 | { |
320 | /* must reset the buffer before any playback begins if needed */ | ||
321 | if (buffer_state == BUFFER_STATE_TRASHED) | ||
322 | audio_reset_buffer(pcmbuf_get_bufsize()); | ||
323 | |||
297 | #ifdef PLAYBACK_VOICE | 324 | #ifdef PLAYBACK_VOICE |
298 | static struct voice_info voice_clip; | 325 | static struct voice_info voice_clip; |
299 | voice_clip.callback = get_more; | 326 | voice_clip.callback = get_more; |
@@ -330,38 +357,95 @@ void mpeg_id3_options(bool _v1first) | |||
330 | v1first = _v1first; | 357 | v1first = _v1first; |
331 | } | 358 | } |
332 | 359 | ||
333 | void audio_load_encoder(int enc_id) | 360 | unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) |
334 | { | 361 | { |
335 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 362 | unsigned char *buf = audiobuf; |
336 | const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER); | 363 | unsigned char *end = audiobufend; |
364 | |||
365 | audio_stop(); | ||
366 | |||
367 | if (talk_buf || !talk_voice_required() | ||
368 | || buffer_state == BUFFER_STATE_TRASHED) | ||
369 | { | ||
370 | logf("get buffer: talk_buf"); | ||
371 | /* ok to use everything from audiobuf to audiobufend */ | ||
372 | if (buffer_state != BUFFER_STATE_TRASHED) | ||
373 | talk_buffer_steal(); | ||
374 | buffer_state = BUFFER_STATE_TRASHED; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | /* skip talk buffer and move pcm buffer to end */ | ||
379 | logf("get buffer: voice"); | ||
380 | mp3_play_stop(); | ||
381 | buf += talk_get_bufsize(); | ||
382 | end -= pcmbuf_init(pcmbuf_get_bufsize(), audiobufend); | ||
383 | buffer_state = BUFFER_STATE_VOICED_ONLY; | ||
384 | } | ||
385 | |||
386 | *buffer_size = end - buf; | ||
387 | |||
388 | return buf; | ||
389 | } | ||
390 | |||
391 | #ifdef HAVE_RECORDING | ||
392 | unsigned char *audio_get_recording_buffer(size_t *buffer_size) | ||
393 | { | ||
394 | /* don't allow overwrite of voice swap area or we'll trash the | ||
395 | swapped-out voice codec but can use whole thing if none */ | ||
396 | unsigned char *end = iram_buf[CODEC_IDX_VOICE] ? | ||
397 | iram_buf[CODEC_IDX_VOICE] : audiobufend; | ||
398 | |||
399 | audio_stop(); | ||
400 | talk_buffer_steal(); | ||
401 | |||
402 | buffer_state = BUFFER_STATE_TRASHED; | ||
403 | |||
404 | *buffer_size = end - audiobuf; | ||
405 | |||
406 | return (unsigned char *)audiobuf; | ||
407 | } | ||
408 | |||
409 | bool audio_load_encoder(int afmt) | ||
410 | { | ||
411 | #ifndef SIMULATOR | ||
412 | const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER); | ||
337 | if (!enc_fn) | 413 | if (!enc_fn) |
338 | return; | 414 | return false; |
339 | 415 | ||
340 | audio_remove_encoder(); | 416 | audio_remove_encoder(); |
417 | ci.enc_codec_loaded = 0; /* clear any previous error condition */ | ||
341 | 418 | ||
342 | LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK"); | 419 | LOGFQUEUE("audio > Q_AUDIO_LOAD_ENCODER"); |
343 | queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn); | 420 | queue_post(&audio_queue, Q_AUDIO_LOAD_ENCODER, (void *)enc_fn); |
344 | 421 | ||
345 | while (!ci.enc_codec_loaded) | 422 | while (ci.enc_codec_loaded == 0) |
346 | yield(); | 423 | yield(); |
424 | |||
425 | logf("codec loaded: %d", ci.enc_codec_loaded); | ||
426 | |||
427 | return ci.enc_codec_loaded > 0; | ||
428 | #else | ||
429 | (void)afmt; | ||
430 | return true; | ||
347 | #endif | 431 | #endif |
348 | return; | ||
349 | (void)enc_id; | ||
350 | } /* audio_load_encoder */ | 432 | } /* audio_load_encoder */ |
351 | 433 | ||
352 | void audio_remove_encoder(void) | 434 | void audio_remove_encoder(void) |
353 | { | 435 | { |
354 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 436 | #ifndef SIMULATOR |
355 | /* force encoder codec unload (if previously loaded) */ | 437 | /* force encoder codec unload (if currently loaded) */ |
356 | if (!ci.enc_codec_loaded) | 438 | if (ci.enc_codec_loaded <= 0) |
357 | return; | 439 | return; |
358 | 440 | ||
359 | ci.stop_codec = true; | 441 | ci.stop_codec = true; |
360 | while (ci.enc_codec_loaded) | 442 | while (ci.enc_codec_loaded > 0) |
361 | yield(); | 443 | yield(); |
362 | #endif | 444 | #endif |
363 | } /* audio_remove_encoder */ | 445 | } /* audio_remove_encoder */ |
364 | 446 | ||
447 | #endif /* HAVE_RECORDING */ | ||
448 | |||
365 | struct mp3entry* audio_current_track(void) | 449 | struct mp3entry* audio_current_track(void) |
366 | { | 450 | { |
367 | const char *filename; | 451 | const char *filename; |
@@ -553,6 +637,9 @@ void audio_flush_and_reload_tracks(void) | |||
553 | 637 | ||
554 | void audio_error_clear(void) | 638 | void audio_error_clear(void) |
555 | { | 639 | { |
640 | #ifdef AUDIO_HAVE_RECORDING | ||
641 | pcm_rec_error_clear(); | ||
642 | #endif | ||
556 | } | 643 | } |
557 | 644 | ||
558 | int audio_status(void) | 645 | int audio_status(void) |
@@ -573,11 +660,6 @@ int audio_status(void) | |||
573 | return ret; | 660 | return ret; |
574 | } | 661 | } |
575 | 662 | ||
576 | bool audio_query_poweroff(void) | ||
577 | { | ||
578 | return !(playing && paused); | ||
579 | } | ||
580 | |||
581 | int audio_get_file_pos(void) | 663 | int audio_get_file_pos(void) |
582 | { | 664 | { |
583 | return 0; | 665 | return 0; |
@@ -617,7 +699,7 @@ void audio_set_crossfade(int enable) | |||
617 | enable = 0; | 699 | enable = 0; |
618 | size = NATIVE_FREQUENCY*2; | 700 | size = NATIVE_FREQUENCY*2; |
619 | #endif | 701 | #endif |
620 | if (pcmbuf_get_bufsize() == size) | 702 | if (buffer_state == BUFFER_STATE_NORMAL && pcmbuf_is_same_size(size)) |
621 | return ; | 703 | return ; |
622 | 704 | ||
623 | if (was_playing) | 705 | if (was_playing) |
@@ -633,9 +715,8 @@ void audio_set_crossfade(int enable) | |||
633 | voice_stop(); | 715 | voice_stop(); |
634 | 716 | ||
635 | /* Re-initialize audio system. */ | 717 | /* Re-initialize audio system. */ |
636 | pcmbuf_init(size); | 718 | audio_reset_buffer(size); |
637 | pcmbuf_crossfade_enable(enable); | 719 | pcmbuf_crossfade_enable(enable); |
638 | audio_reset_buffer(); | ||
639 | logf("abuf:%dB", pcmbuf_get_bufsize()); | 720 | logf("abuf:%dB", pcmbuf_get_bufsize()); |
640 | logf("fbuf:%dB", filebuflen); | 721 | logf("fbuf:%dB", filebuflen); |
641 | 722 | ||
@@ -714,8 +795,7 @@ void voice_stop(void) | |||
714 | { | 795 | { |
715 | #ifdef PLAYBACK_VOICE | 796 | #ifdef PLAYBACK_VOICE |
716 | /* Messages should not be posted to voice codec queue unless it is the | 797 | /* Messages should not be posted to voice codec queue unless it is the |
717 | current codec or deadlocks happen. | 798 | current codec or deadlocks happen. */ |
718 | -- jhMikeS */ | ||
719 | if (current_codec != CODEC_IDX_VOICE) | 799 | if (current_codec != CODEC_IDX_VOICE) |
720 | return; | 800 | return; |
721 | 801 | ||
@@ -784,21 +864,32 @@ static void set_filebuf_watermark(int seconds) | |||
784 | conf_watermark = bytes; | 864 | conf_watermark = bytes; |
785 | } | 865 | } |
786 | 866 | ||
787 | static const char * get_codec_filename(int enc_spec) | 867 | static const char * get_codec_filename(int cod_spec) |
788 | { | 868 | { |
789 | const char *fname; | 869 | const char *fname; |
790 | int type = enc_spec & CODEC_TYPE_MASK; | 870 | |
791 | int afmt = enc_spec & CODEC_AFMT_MASK; | 871 | #ifdef HAVE_RECORDING |
872 | /* Can choose decoder or encoder if one available */ | ||
873 | int type = cod_spec & CODEC_TYPE_MASK; | ||
874 | int afmt = cod_spec & CODEC_AFMT_MASK; | ||
792 | 875 | ||
793 | if ((unsigned)afmt >= AFMT_NUM_CODECS) | 876 | if ((unsigned)afmt >= AFMT_NUM_CODECS) |
794 | type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK); | 877 | type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK); |
795 | 878 | ||
796 | fname = (type == CODEC_TYPE_DECODER) ? | 879 | fname = (type == CODEC_TYPE_ENCODER) ? |
797 | audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn; | 880 | audio_formats[afmt].codec_enc_root_fn : |
881 | audio_formats[afmt].codec_root_fn; | ||
798 | 882 | ||
799 | logf("%s: %d - %s", | 883 | logf("%s: %d - %s", |
800 | (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder", | 884 | (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder", |
801 | afmt, fname ? fname : "<unknown>"); | 885 | afmt, fname ? fname : "<unknown>"); |
886 | #else /* !HAVE_RECORDING */ | ||
887 | /* Always decoder */ | ||
888 | if ((unsigned)cod_spec >= AFMT_NUM_CODECS) | ||
889 | cod_spec = AFMT_UNKNOWN; | ||
890 | fname = audio_formats[cod_spec].codec_root_fn; | ||
891 | logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>"); | ||
892 | #endif /* HAVE_RECORDING */ | ||
802 | 893 | ||
803 | return fname; | 894 | return fname; |
804 | } /* get_codec_filename */ | 895 | } /* get_codec_filename */ |
@@ -940,7 +1031,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
940 | } | 1031 | } |
941 | break; | 1032 | break; |
942 | 1033 | ||
943 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 1034 | #ifdef AUDIO_HAVE_RECORDING |
944 | case Q_ENCODER_RECORD: | 1035 | case Q_ENCODER_RECORD: |
945 | LOGFQUEUE("voice < Q_ENCODER_RECORD"); | 1036 | LOGFQUEUE("voice < Q_ENCODER_RECORD"); |
946 | swap_codec(); | 1037 | swap_codec(); |
@@ -995,7 +1086,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
995 | goto voice_play_clip; | 1086 | goto voice_play_clip; |
996 | 1087 | ||
997 | case SYS_TIMEOUT: | 1088 | case SYS_TIMEOUT: |
998 | LOGFQUEUE("voice < SYS_TIMEOUT"); | 1089 | LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT"); |
999 | goto voice_play_clip; | 1090 | goto voice_play_clip; |
1000 | 1091 | ||
1001 | default: | 1092 | default: |
@@ -1773,7 +1864,7 @@ static void codec_thread(void) | |||
1773 | #endif | 1864 | #endif |
1774 | break ; | 1865 | break ; |
1775 | 1866 | ||
1776 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 1867 | #ifdef AUDIO_HAVE_RECORDING |
1777 | case Q_ENCODER_LOAD_DISK: | 1868 | case Q_ENCODER_LOAD_DISK: |
1778 | LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); | 1869 | LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); |
1779 | audio_codec_loaded = false; /* Not audio codec! */ | 1870 | audio_codec_loaded = false; /* Not audio codec! */ |
@@ -1785,12 +1876,14 @@ static void codec_thread(void) | |||
1785 | } | 1876 | } |
1786 | #endif | 1877 | #endif |
1787 | mutex_lock(&mutex_codecthread); | 1878 | mutex_lock(&mutex_codecthread); |
1879 | logf("loading encoder"); | ||
1788 | current_codec = CODEC_IDX_AUDIO; | 1880 | current_codec = CODEC_IDX_AUDIO; |
1789 | ci.stop_codec = false; | 1881 | ci.stop_codec = false; |
1790 | status = codec_load_file((const char *)ev.data, &ci); | 1882 | status = codec_load_file((const char *)ev.data, &ci); |
1791 | mutex_unlock(&mutex_codecthread); | 1883 | mutex_unlock(&mutex_codecthread); |
1884 | logf("encoder stopped"); | ||
1792 | break; | 1885 | break; |
1793 | #endif | 1886 | #endif /* AUDIO_HAVE_RECORDING */ |
1794 | 1887 | ||
1795 | #ifndef SIMULATOR | 1888 | #ifndef SIMULATOR |
1796 | case SYS_USB_CONNECTED: | 1889 | case SYS_USB_CONNECTED: |
@@ -1872,6 +1965,24 @@ static void codec_thread(void) | |||
1872 | } | 1965 | } |
1873 | break; | 1966 | break; |
1874 | 1967 | ||
1968 | #ifdef AUDIO_HAVE_RECORDING | ||
1969 | case Q_ENCODER_LOAD_DISK: | ||
1970 | LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); | ||
1971 | |||
1972 | if (status == CODEC_OK) | ||
1973 | break; | ||
1974 | |||
1975 | logf("Encoder failure"); | ||
1976 | gui_syncsplash(HZ*2, true, "Encoder failure"); | ||
1977 | |||
1978 | if (ci.enc_codec_loaded < 0) | ||
1979 | break; | ||
1980 | |||
1981 | logf("Encoder failed to load"); | ||
1982 | ci.enc_codec_loaded = -1; | ||
1983 | break; | ||
1984 | #endif /* AUDIO_HAVE_RECORDING */ | ||
1985 | |||
1875 | default: | 1986 | default: |
1876 | LOGFQUEUE("codec < default"); | 1987 | LOGFQUEUE("codec < default"); |
1877 | 1988 | ||
@@ -2992,6 +3103,10 @@ static void audio_play_start(size_t offset) | |||
2992 | /* Wait for any previously playing audio to flush - TODO: Not necessary? */ | 3103 | /* Wait for any previously playing audio to flush - TODO: Not necessary? */ |
2993 | audio_stop_codec_flush(); | 3104 | audio_stop_codec_flush(); |
2994 | 3105 | ||
3106 | /* must reset the buffer before any playback begins if needed */ | ||
3107 | if (buffer_state != BUFFER_STATE_NORMAL) | ||
3108 | audio_reset_buffer(pcmbuf_get_bufsize()); | ||
3109 | |||
2995 | track_changed = true; | 3110 | track_changed = true; |
2996 | playlist_end = false; | 3111 | playlist_end = false; |
2997 | 3112 | ||
@@ -3084,51 +3199,60 @@ static void audio_initiate_dir_change(long direction) | |||
3084 | ci.new_track = direction; | 3199 | ci.new_track = direction; |
3085 | } | 3200 | } |
3086 | 3201 | ||
3087 | static void audio_reset_buffer(void) | 3202 | /* |
3203 | * Layout audio buffer as follows: | ||
3204 | * [|TALK]|MALLOC|FILE|GUARD|PCM|AUDIOCODEC|[VOICECODEC|] | ||
3205 | */ | ||
3206 | static void audio_reset_buffer(size_t pcmbufsize) | ||
3088 | { | 3207 | { |
3208 | /* see audio_get_recording_buffer if this is modified */ | ||
3089 | size_t offset; | 3209 | size_t offset; |
3090 | 3210 | ||
3091 | /* Set up file buffer as all space available */ | 3211 | logf("audio_reset_buffer"); |
3092 | filebuf = (char *)&audiobuf[talk_get_bufsize()+MALLOC_BUFSIZE]; | 3212 | logf(" size:%08X", pcmbufsize); |
3093 | filebuflen = audiobufend - (unsigned char *) filebuf - GUARD_BUFSIZE - | 3213 | |
3094 | (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_MIX_CHUNK * 2); | 3214 | /* Initially set up file buffer as all space available */ |
3215 | filebuf = audiobuf + MALLOC_BUFSIZE + talk_get_bufsize(); | ||
3216 | filebuflen = audiobufend - filebuf; | ||
3095 | 3217 | ||
3096 | /* Allow for codec(s) at end of file buffer */ | 3218 | /* Allow for codec(s) at end of audio buffer */ |
3097 | if (talk_voice_required()) | 3219 | if (talk_voice_required()) |
3098 | { | 3220 | { |
3099 | /* Allow 2 codecs at end of file buffer */ | 3221 | #ifdef PLAYBACK_VOICE |
3222 | /* Allow 2 codecs at end of audio buffer */ | ||
3100 | filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE); | 3223 | filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE); |
3101 | 3224 | ||
3102 | #ifdef PLAYBACK_VOICE | 3225 | iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen; |
3103 | iram_buf[0] = &filebuf[filebuflen]; | 3226 | dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE; |
3104 | iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE]; | 3227 | iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE; |
3105 | dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2]; | 3228 | dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE; |
3106 | dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE]; | ||
3107 | #endif | 3229 | #endif |
3108 | } | 3230 | } |
3109 | else | 3231 | else |
3110 | { | 3232 | { |
3111 | /* Allow for 1 codec at end of file buffer */ | 3233 | #ifdef PLAYBACK_VOICE |
3234 | /* Allow for 1 codec at end of audio buffer */ | ||
3112 | filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE; | 3235 | filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE; |
3113 | 3236 | ||
3114 | #ifdef PLAYBACK_VOICE | 3237 | iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen; |
3115 | iram_buf[0] = &filebuf[filebuflen]; | 3238 | dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE; |
3116 | iram_buf[1] = NULL; | 3239 | iram_buf[CODEC_IDX_VOICE] = NULL; |
3117 | dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE]; | 3240 | dram_buf[CODEC_IDX_VOICE] = NULL; |
3118 | dram_buf[1] = NULL; | ||
3119 | #endif | 3241 | #endif |
3120 | } | 3242 | } |
3121 | 3243 | ||
3244 | filebuflen -= pcmbuf_init(pcmbufsize, filebuf + filebuflen) + GUARD_BUFSIZE; | ||
3245 | |||
3122 | /* Ensure that file buffer is aligned */ | 3246 | /* Ensure that file buffer is aligned */ |
3123 | offset = (-(size_t)filebuf) & 3; | 3247 | offset = -(size_t)filebuf & 3; |
3124 | filebuf += offset; | 3248 | filebuf += offset; |
3125 | filebuflen -= offset; | 3249 | filebuflen -= offset; |
3126 | filebuflen &= ~3; | 3250 | filebuflen &= ~3; |
3127 | 3251 | ||
3128 | /* Clear any references to the file buffer */ | 3252 | /* Clear any references to the file buffer */ |
3253 | buffer_state = BUFFER_STATE_NORMAL; | ||
3129 | } | 3254 | } |
3130 | 3255 | ||
3131 | |||
3132 | #ifdef ROCKBOX_HAS_LOGF | 3256 | #ifdef ROCKBOX_HAS_LOGF |
3133 | static void audio_test_track_changed_event(struct mp3entry *id3) | 3257 | static void audio_test_track_changed_event(struct mp3entry *id3) |
3134 | { | 3258 | { |
@@ -3149,9 +3273,8 @@ static void audio_playback_init(void) | |||
3149 | logf("playback api init"); | 3273 | logf("playback api init"); |
3150 | pcm_init(); | 3274 | pcm_init(); |
3151 | 3275 | ||
3152 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 3276 | #ifdef AUDIO_HAVE_RECORDING |
3153 | /* Set the input multiplexer to Line In */ | 3277 | rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); |
3154 | pcm_rec_mux(0); | ||
3155 | #endif | 3278 | #endif |
3156 | 3279 | ||
3157 | #ifdef ROCKBOX_HAS_LOGF | 3280 | #ifdef ROCKBOX_HAS_LOGF |
@@ -3219,8 +3342,9 @@ static void audio_playback_init(void) | |||
3219 | #endif | 3342 | #endif |
3220 | } | 3343 | } |
3221 | 3344 | ||
3222 | filebuf = (char *)&audiobuf[MALLOC_BUFSIZE]; /* Will be reset by reset_buffer */ | 3345 | /* initialize the buffer */ |
3223 | 3346 | filebuf = audiobuf; /* must be non-NULL for audio_set_crossfade */ | |
3347 | buffer_state = BUFFER_STATE_TRASHED; /* force it */ | ||
3224 | audio_set_crossfade(global_settings.crossfade); | 3348 | audio_set_crossfade(global_settings.crossfade); |
3225 | 3349 | ||
3226 | audio_is_initialized = true; | 3350 | audio_is_initialized = true; |
@@ -3358,6 +3482,14 @@ static void audio_thread(void) | |||
3358 | playlist_update_resume_info(audio_current_track()); | 3482 | playlist_update_resume_info(audio_current_track()); |
3359 | break ; | 3483 | break ; |
3360 | 3484 | ||
3485 | #ifdef AUDIO_HAVE_RECORDING | ||
3486 | case Q_AUDIO_LOAD_ENCODER: | ||
3487 | LOGFQUEUE("audio < Q_AUDIO_LOAD_ENCODER"); | ||
3488 | LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK"); | ||
3489 | queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, ev.data); | ||
3490 | break; | ||
3491 | #endif | ||
3492 | |||
3361 | #ifndef SIMULATOR | 3493 | #ifndef SIMULATOR |
3362 | case SYS_USB_CONNECTED: | 3494 | case SYS_USB_CONNECTED: |
3363 | LOGFQUEUE("audio < SYS_USB_CONNECTED"); | 3495 | LOGFQUEUE("audio < SYS_USB_CONNECTED"); |
@@ -3368,7 +3500,7 @@ static void audio_thread(void) | |||
3368 | #endif | 3500 | #endif |
3369 | 3501 | ||
3370 | case SYS_TIMEOUT: | 3502 | case SYS_TIMEOUT: |
3371 | LOGFQUEUE("audio < SYS_TIMEOUT"); | 3503 | LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT"); |
3372 | break; | 3504 | break; |
3373 | 3505 | ||
3374 | default: | 3506 | default: |
diff --git a/apps/playlist.c b/apps/playlist.c index 5a5313b736..134b52ea8b 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -155,7 +155,7 @@ static int recreate_control(struct playlist_info* playlist); | |||
155 | static void update_playlist_filename(struct playlist_info* playlist, | 155 | static void update_playlist_filename(struct playlist_info* playlist, |
156 | const char *dir, const char *file); | 156 | const char *dir, const char *file); |
157 | static int add_indices_to_playlist(struct playlist_info* playlist, | 157 | static int add_indices_to_playlist(struct playlist_info* playlist, |
158 | char* buffer, int buflen); | 158 | char* buffer, size_t buflen); |
159 | static int add_track_to_playlist(struct playlist_info* playlist, | 159 | static int add_track_to_playlist(struct playlist_info* playlist, |
160 | const char *filename, int position, | 160 | const char *filename, int position, |
161 | bool queue, int seek_pos); | 161 | bool queue, int seek_pos); |
@@ -457,7 +457,7 @@ static void update_playlist_filename(struct playlist_info* playlist, | |||
457 | * calculate track offsets within a playlist file | 457 | * calculate track offsets within a playlist file |
458 | */ | 458 | */ |
459 | static int add_indices_to_playlist(struct playlist_info* playlist, | 459 | static int add_indices_to_playlist(struct playlist_info* playlist, |
460 | char* buffer, int buflen) | 460 | char* buffer, size_t buflen) |
461 | { | 461 | { |
462 | unsigned int nread; | 462 | unsigned int nread; |
463 | unsigned int i = 0; | 463 | unsigned int i = 0; |
@@ -489,8 +489,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, | |||
489 | buflen = (audiobufend - audiobuf); | 489 | buflen = (audiobufend - audiobuf); |
490 | buffer = (char *)audiobuf; | 490 | buffer = (char *)audiobuf; |
491 | #else | 491 | #else |
492 | buflen = (audiobufend - audiobuf - talk_get_bufsize()); | 492 | buffer = (char *)audio_get_buffer(false, &buflen); |
493 | buffer = (char *)&audiobuf[talk_get_bufsize()]; | ||
494 | #endif | 493 | #endif |
495 | } | 494 | } |
496 | 495 | ||
@@ -1853,7 +1852,7 @@ int playlist_resume(void) | |||
1853 | { | 1852 | { |
1854 | struct playlist_info* playlist = ¤t_playlist; | 1853 | struct playlist_info* playlist = ¤t_playlist; |
1855 | char *buffer; | 1854 | char *buffer; |
1856 | int buflen; | 1855 | size_t buflen; |
1857 | int nread; | 1856 | int nread; |
1858 | int total_read = 0; | 1857 | int total_read = 0; |
1859 | int control_file_size = 0; | 1858 | int control_file_size = 0; |
@@ -1866,8 +1865,7 @@ int playlist_resume(void) | |||
1866 | buflen = (audiobufend - audiobuf); | 1865 | buflen = (audiobufend - audiobuf); |
1867 | buffer = (char *)audiobuf; | 1866 | buffer = (char *)audiobuf; |
1868 | #else | 1867 | #else |
1869 | buflen = (audiobufend - audiobuf - talk_get_bufsize()); | 1868 | buffer = (char *)audio_get_buffer(false, &buflen); |
1870 | buffer = (char *)&audiobuf[talk_get_bufsize()]; | ||
1871 | #endif | 1869 | #endif |
1872 | 1870 | ||
1873 | empty_playlist(playlist, true); | 1871 | empty_playlist(playlist, true); |
diff --git a/apps/plugin.c b/apps/plugin.c index 25f1865c9e..3a893fc537 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -674,12 +674,18 @@ void* plugin_get_buffer(int* buffer_size) | |||
674 | } | 674 | } |
675 | 675 | ||
676 | /* Returns a pointer to the mp3 buffer. | 676 | /* Returns a pointer to the mp3 buffer. |
677 | Playback gets stopped, to avoid conflicts. */ | 677 | Playback gets stopped, to avoid conflicts. |
678 | Talk buffer is stolen as well. | ||
679 | */ | ||
678 | void* plugin_get_audio_buffer(int* buffer_size) | 680 | void* plugin_get_audio_buffer(int* buffer_size) |
679 | { | 681 | { |
682 | #if CONFIG_CODEC == SWCODEC | ||
683 | return audio_get_buffer(true, (size_t *)buffer_size); | ||
684 | #else | ||
680 | audio_stop(); | 685 | audio_stop(); |
681 | talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ | 686 | talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ |
682 | *buffer_size = audiobufend - audiobuf; | 687 | *buffer_size = audiobufend - audiobuf; |
688 | #endif | ||
683 | return audiobuf; | 689 | return audiobuf; |
684 | } | 690 | } |
685 | 691 | ||
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c index 46d628e780..ba22bb5a2c 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c | |||
@@ -30,12 +30,17 @@ | |||
30 | 30 | ||
31 | const unsigned char bitmap_icons_5x8[][5] = | 31 | const unsigned char bitmap_icons_5x8[][5] = |
32 | { | 32 | { |
33 | [Icon_Lock_Main] ={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Main */ | 33 | [Icon_Lock_Main] = |
34 | [Icon_Lock_Remote]={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Remote */ | 34 | {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Main */ |
35 | [Icon_Stereo]={0x7f, 0x1c, 0x00, 0x1c, 0x7f}, /* Stereo recording */ | 35 | [Icon_Lock_Remote] = |
36 | [Icon_Mono]={0x00, 0x1c, 0x7f, 0x00, 0x00}, /* Mono recording */ | 36 | {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Remote */ |
37 | [Icon_Stereo] = | ||
38 | {0x7f, 0x22, 0x1c, 0x22, 0x7f}, /* Stereo recording */ | ||
39 | [Icon_Mono] = | ||
40 | {0x00, 0x1c, 0x22, 0x7f, 0x00}, /* Mono recording */ | ||
37 | #if CONFIG_CODEC != SWCODEC | 41 | #if CONFIG_CODEC != SWCODEC |
38 | [Icon_q]={0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */ | 42 | [Icon_q] = |
43 | {0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */ | ||
39 | #endif | 44 | #endif |
40 | }; | 45 | }; |
41 | 46 | ||
@@ -81,45 +86,52 @@ const unsigned char bitmap_icons_7x8[][7] = | |||
81 | {0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */ | 86 | {0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */ |
82 | }; | 87 | }; |
83 | 88 | ||
84 | #if CONFIG_CODEC == SWCODEC | 89 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) |
85 | const unsigned char bitmap_icons_18x8[][18] = | 90 | const unsigned char bitmap_glyphs_4x8[][4] = |
86 | { | 91 | { |
87 | {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3e, 0x2a, | 92 | /* Keep digits together and first! */ |
88 | 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 64kbps */ | 93 | [0] = |
89 | {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x0e, 0x0a, | 94 | {0x00, 0x3e, 0x22, 0x3e}, /* 0 */ |
90 | 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00}, /* mp3 96kbps */ | 95 | [1] = |
91 | {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, | 96 | {0x00, 0x24, 0x3e, 0x20}, /* 1 */ |
92 | 0x2e, 0x00, 0x3e, 0x2a, 0x3e, 0x00}, /* mp3 128kbps */ | 97 | [2] = |
93 | {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, | 98 | {0x00, 0x3a, 0x2a, 0x2e}, /* 2 */ |
94 | 0x3a, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 160kbps */ | 99 | [3] = |
95 | {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x0e, 0x0a, | 100 | {0x00, 0x22, 0x2a, 0x36}, /* 3 */ |
96 | 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00}, /* mp3 192kbps */ | 101 | [4] = |
97 | {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, | 102 | {0x00, 0x0e, 0x08, 0x3e}, /* 4 */ |
98 | 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 224kbps */ | 103 | [5] = |
99 | {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, | 104 | {0x00, 0x2e, 0x2a, 0x3a}, /* 5 */ |
100 | 0x2e, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 320kbps */ | 105 | [6] = |
101 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x1e, 0x20, 0x18, 0x20, 0x1e, | 106 | {0x00, 0x3e, 0x2a, 0x3a}, /* 6 */ |
102 | 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00}, /* wv */ | 107 | [7] = |
103 | {0x00, 0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x12, 0x12, 0x3c, | 108 | {0x00, 0x02, 0x02, 0x3e}, /* 7 */ |
104 | 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00} /* wav */ | 109 | [8] = |
110 | {0x00, 0x3e, 0x2a, 0x3e}, /* 8 */ | ||
111 | [9] = | ||
112 | {0x00, 0x0e, 0x0a, 0x3e}, /* 9 */ | ||
113 | [10 ... Glyph_4x8Last-1] = | ||
114 | {0x00, 0x00, 0x00, 0x00}, /* auto-blank */ | ||
115 | [Glyph_4x8_k] = | ||
116 | {0x00, 0x3e, 0x10, 0x28}, /* k */ | ||
105 | }; | 117 | }; |
106 | 118 | ||
107 | const unsigned char bitmap_icons_12x8[][12] = | 119 | const unsigned char bitmap_formats_18x8[Format_18x8Last][18]= |
108 | { | 120 | { |
109 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 8khz */ | 121 | [0 ... Format_18x8Last-1] = /* auto-blank */ |
110 | {0x00, 0x24, 0x3e, 0x20, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x10, 0x28}, /* 11khz */ | 122 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
111 | {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 12khz */ | 123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ___ */ |
112 | {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28}, /* 16khz */ | 124 | [Format_18x8_MPA_L3] = |
113 | {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 22khz */ | 125 | {0x00, 0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, |
114 | {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 24khz */ | 126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* M__ */ |
115 | {0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 32khz */ | 127 | [Format_18x8_WAVPACK] = |
116 | {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 44.1khz */ | 128 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20, |
117 | {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 48khz */ | 129 | 0x18, 0x20, 0x1e, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* _WV */ |
118 | {0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 64khz */ | 130 | [Format_18x8_PCM_WAV] = |
119 | {0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 88.2khz */ | 131 | {0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x0a, |
120 | {0x00, 0x0e, 0x0a, 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28} /* 96khz */ | 132 | 0x0a, 0x0a, 0x3c, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* WAV */ |
121 | }; | 133 | }; |
122 | #endif | 134 | #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ |
123 | 135 | ||
124 | /* Disk/MMC activity */ | 136 | /* Disk/MMC activity */ |
125 | const unsigned char bitmap_icon_disk[12] = | 137 | const unsigned char bitmap_icon_disk[12] = |
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index 75401f6f0b..1e7b8dba1e 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h | |||
@@ -89,44 +89,40 @@ enum icons_7x8 { | |||
89 | Icon7x8Last | 89 | Icon7x8Last |
90 | }; | 90 | }; |
91 | 91 | ||
92 | #if CONFIG_CODEC == SWCODEC | 92 | #if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) |
93 | enum icons_12x8 { | 93 | #define BM_GLYPH_WIDTH 4 |
94 | Icon_8000, | 94 | enum Glyphs_4x8 { |
95 | Icon_11025, | 95 | Glyph_4x8_0 = 0, |
96 | Icon_12000, | 96 | Glyph_4x8_1, |
97 | Icon_16000, | 97 | Glyph_4x8_2, |
98 | Icon_22050, | 98 | Glyph_4x8_3, |
99 | Icon_24000, | 99 | Glyph_4x8_4, |
100 | Icon_32000, | 100 | Glyph_4x8_5, |
101 | Icon_44100, | 101 | Glyph_4x8_6, |
102 | Icon_48000, | 102 | Glyph_4x8_7, |
103 | Icon_64000, | 103 | Glyph_4x8_8, |
104 | Icon_88200, | 104 | Glyph_4x8_9, |
105 | Icon_96000, | 105 | Glyph_4x8_k, |
106 | Icon12x8Last | 106 | Glyph_4x8Last |
107 | }; | 107 | }; |
108 | 108 | extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4]; | |
109 | enum icons_18x8 { | 109 | |
110 | Icon_mp364, | 110 | #define BM_MPA_L3_M_WIDTH 6 |
111 | Icon_mp396, | 111 | #ifdef ID3_H |
112 | Icon_mp3128, | 112 | /* This enum is redundant but sort of in keeping with the style */ |
113 | Icon_mp3160, | 113 | enum rec_format_18x8 { |
114 | Icon_mp3192, | 114 | Format_18x8_MPA_L3 = REC_FORMAT_MPA_L3, |
115 | Icon_mp3224, | 115 | Format_18x8_WAVPACK = REC_FORMAT_WAVPACK, |
116 | Icon_mp3320, | 116 | Format_18x8_PCM_WAV = REC_FORMAT_PCM_WAV, |
117 | Icon_wv, | 117 | Format_18x8Last = REC_NUM_FORMATS |
118 | Icon_wav, | ||
119 | Icon18x8Last | ||
120 | }; | 118 | }; |
121 | #endif | 119 | extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18]; |
120 | #endif /* ID3_H */ | ||
121 | #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ | ||
122 | 122 | ||
123 | extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; | 123 | extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; |
124 | extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; | 124 | extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; |
125 | extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; | 125 | extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; |
126 | #if CONFIG_CODEC == SWCODEC | ||
127 | extern const unsigned char bitmap_icons_12x8[Icon12x8Last][12]; | ||
128 | extern const unsigned char bitmap_icons_18x8[Icon18x8Last][18]; | ||
129 | #endif | ||
130 | extern const unsigned char bitmap_icon_disk[]; | 126 | extern const unsigned char bitmap_icon_disk[]; |
131 | 127 | ||
132 | #define STATUSBAR_X_POS 0 | 128 | #define STATUSBAR_X_POS 0 |
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c index 0370f4deea..44be43124a 100644 --- a/apps/recorder/peakmeter.c +++ b/apps/recorder/peakmeter.c | |||
@@ -540,10 +540,8 @@ void peak_meter_peek(void) | |||
540 | if (pm_playback) | 540 | if (pm_playback) |
541 | pcm_calculate_peaks(&pm_cur_left, &pm_cur_right); | 541 | pcm_calculate_peaks(&pm_cur_left, &pm_cur_right); |
542 | #ifdef HAVE_RECORDING | 542 | #ifdef HAVE_RECORDING |
543 | if (!pm_playback) | 543 | else |
544 | { | 544 | pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right); |
545 | pcm_rec_get_peaks(&pm_cur_left, &pm_cur_right); | ||
546 | } | ||
547 | #endif | 545 | #endif |
548 | left = pm_cur_left; | 546 | left = pm_cur_left; |
549 | right = pm_cur_right; | 547 | right = pm_cur_right; |
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index d74437a8c9..7a0cc6543e 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c | |||
@@ -386,6 +386,7 @@ bool radio_screen(void) | |||
386 | unsigned int last_seconds = 0; | 386 | unsigned int last_seconds = 0; |
387 | #if CONFIG_CODEC != SWCODEC | 387 | #if CONFIG_CODEC != SWCODEC |
388 | int hours, minutes; | 388 | int hours, minutes; |
389 | struct audio_recording_options rec_options; | ||
389 | #endif | 390 | #endif |
390 | bool keep_playing = false; | 391 | bool keep_playing = false; |
391 | bool statusbar = global_settings.statusbar; | 392 | bool statusbar = global_settings.statusbar; |
@@ -436,12 +437,9 @@ bool radio_screen(void) | |||
436 | 437 | ||
437 | peak_meter_enabled = true; | 438 | peak_meter_enabled = true; |
438 | 439 | ||
439 | rec_set_recording_options(global_settings.rec_frequency, | 440 | rec_init_recording_options(&rec_options); |
440 | global_settings.rec_quality, | 441 | rec_options.rec_source = AUDIO_SRC_LINEIN; |
441 | AUDIO_SRC_LINEIN, 0, | 442 | rec_set_recording_options(&rec_options); |
442 | global_settings.rec_channels, | ||
443 | global_settings.rec_editable, | ||
444 | global_settings.rec_prerecord_time); | ||
445 | 443 | ||
446 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | 444 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), |
447 | sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); | 445 | sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); |
@@ -881,7 +879,7 @@ bool radio_screen(void) | |||
881 | } | 879 | } |
882 | else | 880 | else |
883 | { | 881 | { |
884 | if(global_settings.rec_prerecord_time) | 882 | if(rec_options.rec_prerecord_time) |
885 | { | 883 | { |
886 | snprintf(buf, 32, "%s %02d", | 884 | snprintf(buf, 32, "%s %02d", |
887 | str(LANG_RECORD_PRERECORD), seconds%60); | 885 | str(LANG_RECORD_PRERECORD), seconds%60); |
@@ -1173,7 +1171,8 @@ bool save_preset_list(void) | |||
1173 | if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */ | 1171 | if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */ |
1174 | mkdir(FMPRESET_PATH, 0); | 1172 | mkdir(FMPRESET_PATH, 0); |
1175 | 1173 | ||
1176 | create_numbered_filename(filepreset,FMPRESET_PATH,"preset",".fmr",2); | 1174 | create_numbered_filename(filepreset, FMPRESET_PATH, "preset", |
1175 | ".fmr", 2 IF_CNFN_NUM_(, NULL)); | ||
1177 | 1176 | ||
1178 | while(bad_file_name) | 1177 | while(bad_file_name) |
1179 | { | 1178 | { |
@@ -1534,12 +1533,10 @@ static bool fm_recording_settings(void) | |||
1534 | #if CONFIG_CODEC != SWCODEC | 1533 | #if CONFIG_CODEC != SWCODEC |
1535 | if (!ret) | 1534 | if (!ret) |
1536 | { | 1535 | { |
1537 | rec_set_recording_options(global_settings.rec_frequency, | 1536 | struct audio_recording_options rec_options; |
1538 | global_settings.rec_quality, | 1537 | rec_init_recording_options(&rec_options); |
1539 | AUDIO_SRC_LINEIN, 0, | 1538 | rec_options.rec_source = AUDIO_SRC_LINEIN; |
1540 | global_settings.rec_channels, | 1539 | rec_set_recording_options(&rec_options); |
1541 | global_settings.rec_editable, | ||
1542 | global_settings.rec_prerecord_time); | ||
1543 | } | 1540 | } |
1544 | #endif | 1541 | #endif |
1545 | 1542 | ||
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 0a21d96566..6a053cd12e 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c | |||
@@ -30,8 +30,10 @@ | |||
30 | #include "mpeg.h" | 30 | #include "mpeg.h" |
31 | #include "audio.h" | 31 | #include "audio.h" |
32 | #if CONFIG_CODEC == SWCODEC | 32 | #if CONFIG_CODEC == SWCODEC |
33 | #include "pcm_record.h" | 33 | #include "thread.h" |
34 | #include "pcm_playback.h" | ||
34 | #include "playback.h" | 35 | #include "playback.h" |
36 | #include "enc_config.h" | ||
35 | #endif | 37 | #endif |
36 | #ifdef HAVE_UDA1380 | 38 | #ifdef HAVE_UDA1380 |
37 | #include "uda1380.h" | 39 | #include "uda1380.h" |
@@ -73,36 +75,40 @@ | |||
73 | 75 | ||
74 | #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) | 76 | #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) |
75 | 77 | ||
78 | #if CONFIG_KEYPAD == RECORDER_PAD | ||
76 | bool f2_rec_screen(void); | 79 | bool f2_rec_screen(void); |
77 | bool f3_rec_screen(void); | 80 | bool f3_rec_screen(void); |
81 | #endif | ||
78 | 82 | ||
79 | #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ | 83 | #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ |
80 | 84 | ||
81 | int screen_update = NB_SCREENS; | 85 | int screen_update = NB_SCREENS; |
82 | bool remote_display_on = true; | 86 | bool remote_display_on = true; |
83 | const char* const freq_str[6] = | ||
84 | { | ||
85 | "44.1kHz", | ||
86 | "48kHz", | ||
87 | "32kHz", | ||
88 | "22.05kHz", | ||
89 | "24kHz", | ||
90 | "16kHz" | ||
91 | }; | ||
92 | 87 | ||
88 | /** File name creation **/ | ||
93 | #if CONFIG_CODEC == SWCODEC | 89 | #if CONFIG_CODEC == SWCODEC |
94 | #define REC_ENCODER_ID(q) \ | 90 | |
95 | rec_quality_info_afmt[q] | 91 | #ifdef IF_CNFN_NUM |
96 | #define REC_QUALITY_LABEL(q) \ | 92 | /* current file number to assist in creating unique numbered filenames |
97 | (audio_formats[REC_ENCODER_ID(q)].label) | 93 | without actually having to create the file on disk */ |
98 | #define REC_FILE_ENDING(q) \ | 94 | static int file_number = -1; |
99 | (audio_formats[REC_ENCODER_ID(q)].ext) | 95 | #endif /* IF_CNFN_NUM */ |
100 | #else | 96 | |
97 | #define REC_FILE_ENDING(rec_format) \ | ||
98 | (audio_formats[rec_format_afmt[rec_format]].ext_list) | ||
99 | |||
100 | #else /* CONFIG_CODEC != SWCODEC */ | ||
101 | |||
101 | /* default record file extension for HWCODEC */ | 102 | /* default record file extension for HWCODEC */ |
102 | #define REC_QUALITY_LABEL(q) "MP3" | 103 | #define REC_FILE_ENDING(rec_format) \ |
103 | #define REC_FILE_ENDING(q) ".mp3" | 104 | (audio_formats[AFMT_MPA_L3].ext_list) |
104 | #endif | ||
105 | 105 | ||
106 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
107 | |||
108 | /* path for current file */ | ||
109 | static char path_buffer[MAX_PATH]; | ||
110 | |||
111 | /** Automatic Gain Control (AGC) **/ | ||
106 | #ifdef HAVE_AGC | 112 | #ifdef HAVE_AGC |
107 | /* Timing counters: | 113 | /* Timing counters: |
108 | * peak_time is incremented every 0.2s, every 2nd run of record screen loop. | 114 | * peak_time is incremented every 0.2s, every 2nd run of record screen loop. |
@@ -496,20 +502,24 @@ void adjust_cursor(void) | |||
496 | 502 | ||
497 | char *rec_create_filename(char *buffer) | 503 | char *rec_create_filename(char *buffer) |
498 | { | 504 | { |
505 | char ext[16]; | ||
506 | |||
499 | if(global_settings.rec_directory) | 507 | if(global_settings.rec_directory) |
500 | getcwd(buffer, MAX_PATH); | 508 | getcwd(buffer, MAX_PATH); |
501 | else | 509 | else |
502 | strncpy(buffer, rec_base_directory, MAX_PATH); | 510 | strncpy(buffer, rec_base_directory, MAX_PATH); |
503 | 511 | ||
512 | snprintf(ext, sizeof(ext), ".%s", | ||
513 | REC_FILE_ENDING(global_settings.rec_format)); | ||
504 | 514 | ||
505 | #ifdef CONFIG_RTC | 515 | #ifdef CONFIG_RTC |
506 | create_datetime_filename(buffer, buffer, "R", | 516 | /* We'll wait at least up to the start of the next second so no duplicate |
507 | REC_FILE_ENDING(global_settings.rec_quality)); | 517 | names are created */ |
518 | return create_datetime_filename(buffer, buffer, "R", ext, true); | ||
508 | #else | 519 | #else |
509 | create_numbered_filename(buffer, buffer, "rec_", | 520 | return create_numbered_filename(buffer, buffer, "rec_", ext, 4 |
510 | REC_FILE_ENDING(global_settings.rec_quality), 4); | 521 | IF_CNFN_NUM_(, &file_number)); |
511 | #endif | 522 | #endif |
512 | return buffer; | ||
513 | } | 523 | } |
514 | 524 | ||
515 | int rec_create_directory(void) | 525 | int rec_create_directory(void) |
@@ -557,9 +567,15 @@ static void rec_boost(bool state) | |||
557 | 567 | ||
558 | /** | 568 | /** |
559 | * Selects an audio source for recording or playback | 569 | * Selects an audio source for recording or playback |
560 | * powers/unpowers related devices. | 570 | * powers/unpowers related devices and sets up monitoring. |
561 | * Here because it calls app code and used only for HAVE_RECORDING atm. | 571 | * Here because it calls app code and used only for HAVE_RECORDING atm. |
562 | * Would like it in pcm_record.c. | 572 | * Would like it in pcm_record.c. |
573 | * | ||
574 | * Behaves like a firmware function in that it does not use global settings | ||
575 | * to determine the state. | ||
576 | * | ||
577 | * The order of setting monitoring may need tweaking dependent upon the | ||
578 | * selected source to get the smoothest transition. | ||
563 | */ | 579 | */ |
564 | #if defined(HAVE_UDA1380) | 580 | #if defined(HAVE_UDA1380) |
565 | #define ac_disable_recording uda1380_disable_recording | 581 | #define ac_disable_recording uda1380_disable_recording |
@@ -571,7 +587,13 @@ static void rec_boost(bool state) | |||
571 | #define ac_set_monitor tlv320_set_monitor | 587 | #define ac_set_monitor tlv320_set_monitor |
572 | #endif | 588 | #endif |
573 | 589 | ||
574 | void rec_set_source(int source, int flags) | 590 | #ifdef HAVE_SPDIF_IN |
591 | #define rec_spdif_set_monitor(m) audio_spdif_set_monitor(m) | ||
592 | #else | ||
593 | #define rec_spdif_set_monitor(m) | ||
594 | #endif | ||
595 | |||
596 | void rec_set_source(int source, unsigned flags) | ||
575 | { | 597 | { |
576 | /* Prevent pops from unneeded switching */ | 598 | /* Prevent pops from unneeded switching */ |
577 | static int last_source = AUDIO_SRC_PLAYBACK; | 599 | static int last_source = AUDIO_SRC_PLAYBACK; |
@@ -586,7 +608,9 @@ void rec_set_source(int source, int flags) | |||
586 | 608 | ||
587 | /** Do power up/down of associated device(s) **/ | 609 | /** Do power up/down of associated device(s) **/ |
588 | 610 | ||
611 | /** SPDIF **/ | ||
589 | #ifdef HAVE_SPDIF_IN | 612 | #ifdef HAVE_SPDIF_IN |
613 | /* Always boost for SPDIF */ | ||
590 | if ((source == AUDIO_SRC_SPDIF) != (source == last_source)) | 614 | if ((source == AUDIO_SRC_SPDIF) != (source == last_source)) |
591 | rec_boost(source == AUDIO_SRC_SPDIF); | 615 | rec_boost(source == AUDIO_SRC_SPDIF); |
592 | 616 | ||
@@ -595,10 +619,11 @@ void rec_set_source(int source, int flags) | |||
595 | both optical in and out is controlled by the same power source, which is | 619 | both optical in and out is controlled by the same power source, which is |
596 | the case on H1x0. */ | 620 | the case on H1x0. */ |
597 | spdif_power_enable((source == AUDIO_SRC_SPDIF) || | 621 | spdif_power_enable((source == AUDIO_SRC_SPDIF) || |
598 | global_settings.spdif_enable); | 622 | audio_get_spdif_power_setting()); |
599 | #endif | 623 | #endif |
600 | #endif | 624 | #endif |
601 | 625 | ||
626 | /** Tuner **/ | ||
602 | #ifdef CONFIG_TUNER | 627 | #ifdef CONFIG_TUNER |
603 | /* Switch radio off or on per source and flags. */ | 628 | /* Switch radio off or on per source and flags. */ |
604 | if (source != AUDIO_SRC_FMRADIO) | 629 | if (source != AUDIO_SRC_FMRADIO) |
@@ -612,12 +637,15 @@ void rec_set_source(int source, int flags) | |||
612 | switch (source) | 637 | switch (source) |
613 | { | 638 | { |
614 | default: /* playback - no recording */ | 639 | default: /* playback - no recording */ |
640 | source = AUDIO_SRC_PLAYBACK; | ||
641 | case AUDIO_SRC_PLAYBACK: | ||
615 | pm_playback = true; | 642 | pm_playback = true; |
616 | if (source == last_source) | 643 | if (source == last_source) |
617 | break; | 644 | break; |
618 | ac_disable_recording(); | 645 | ac_disable_recording(); |
619 | ac_set_monitor(false); | 646 | ac_set_monitor(false); |
620 | pcm_rec_mux(0); /* line in */ | 647 | pcm_rec_mux(0); /* line in */ |
648 | rec_spdif_set_monitor(-1); /* silence it */ | ||
621 | break; | 649 | break; |
622 | 650 | ||
623 | case AUDIO_SRC_MIC: /* recording only */ | 651 | case AUDIO_SRC_MIC: /* recording only */ |
@@ -625,6 +653,7 @@ void rec_set_source(int source, int flags) | |||
625 | break; | 653 | break; |
626 | ac_enable_recording(true); /* source mic */ | 654 | ac_enable_recording(true); /* source mic */ |
627 | pcm_rec_mux(0); /* line in */ | 655 | pcm_rec_mux(0); /* line in */ |
656 | rec_spdif_set_monitor(0); | ||
628 | break; | 657 | break; |
629 | 658 | ||
630 | case AUDIO_SRC_LINEIN: /* recording only */ | 659 | case AUDIO_SRC_LINEIN: /* recording only */ |
@@ -632,29 +661,20 @@ void rec_set_source(int source, int flags) | |||
632 | break; | 661 | break; |
633 | pcm_rec_mux(0); /* line in */ | 662 | pcm_rec_mux(0); /* line in */ |
634 | ac_enable_recording(false); /* source line */ | 663 | ac_enable_recording(false); /* source line */ |
664 | rec_spdif_set_monitor(0); | ||
635 | break; | 665 | break; |
636 | 666 | ||
637 | #ifdef HAVE_SPDIF_IN | 667 | #ifdef HAVE_SPDIF_IN |
638 | case AUDIO_SRC_SPDIF: /* recording only */ | 668 | case AUDIO_SRC_SPDIF: /* recording only */ |
639 | if (recording) | 669 | if (source == last_source) |
640 | { | 670 | break; |
641 | /* This was originally done in audio_set_recording_options only */ | 671 | ac_disable_recording(); |
642 | #ifdef HAVE_SPDIF_POWER | 672 | audio_spdif_set_monitor(1); |
643 | EBU1CONFIG = global_settings.spdif_enable ? (1 << 2) : 0; | ||
644 | /* Input source is EBUin1, Feed-through monitoring if desired */ | ||
645 | #else | ||
646 | EBU1CONFIG = (1 << 2); | ||
647 | /* Input source is EBUin1, Feed-through monitoring */ | ||
648 | #endif | ||
649 | } | ||
650 | |||
651 | if (source != last_source) | ||
652 | uda1380_disable_recording(); | ||
653 | break; | 673 | break; |
654 | #endif /* HAVE_SPDIF_IN */ | 674 | #endif /* HAVE_SPDIF_IN */ |
655 | 675 | ||
656 | #ifdef HAVE_FMRADIO_IN | 676 | #ifdef HAVE_FMRADIO_IN |
657 | case AUDIO_SRC_FMRADIO: | 677 | case AUDIO_SRC_FMRADIO: /* recording and playback */ |
658 | if (!recording) | 678 | if (!recording) |
659 | { | 679 | { |
660 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | 680 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), |
@@ -687,6 +707,8 @@ void rec_set_source(int source, int flags) | |||
687 | tlv320_set_monitor(true); /* analog bypass */ | 707 | tlv320_set_monitor(true); /* analog bypass */ |
688 | } | 708 | } |
689 | #endif | 709 | #endif |
710 | |||
711 | rec_spdif_set_monitor(0); | ||
690 | break; | 712 | break; |
691 | /* #elif defined(CONFIG_TUNER) */ | 713 | /* #elif defined(CONFIG_TUNER) */ |
692 | /* Have radio but cannot record it */ | 714 | /* Have radio but cannot record it */ |
@@ -702,33 +724,50 @@ void rec_set_source(int source, int flags) | |||
702 | } /* rec_set_source */ | 724 | } /* rec_set_source */ |
703 | #endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */ | 725 | #endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */ |
704 | 726 | ||
705 | /* steal the mp3 buffer then actually set options */ | 727 | void rec_init_recording_options(struct audio_recording_options *options) |
706 | void rec_set_recording_options(int frequency, int quality, | 728 | { |
707 | int source, int source_flags, | 729 | options->rec_source = global_settings.rec_source; |
708 | int channel_mode, bool editable, | 730 | options->rec_frequency = global_settings.rec_frequency; |
709 | int prerecord_time) | 731 | options->rec_channels = global_settings.rec_channels; |
732 | options->rec_prerecord_time = global_settings.rec_prerecord_time; | ||
733 | #if CONFIG_CODEC == SWCODEC | ||
734 | options->rec_source_flags = 0; | ||
735 | options->enc_config.rec_format = global_settings.rec_format; | ||
736 | global_to_encoder_config(&options->enc_config); | ||
737 | #else | ||
738 | options->rec_quality = global_settings.rec_quality; | ||
739 | options->rec_editable = global_settings.rec_editable; | ||
740 | #endif | ||
741 | } | ||
742 | |||
743 | void rec_set_recording_options(struct audio_recording_options *options) | ||
710 | { | 744 | { |
711 | #if CONFIG_CODEC != SWCODEC | 745 | #if CONFIG_CODEC != SWCODEC |
712 | if (global_settings.rec_prerecord_time) | 746 | if (global_settings.rec_prerecord_time) |
713 | #endif | ||
714 | talk_buffer_steal(); /* will use the mp3 buffer */ | 747 | talk_buffer_steal(); /* will use the mp3 buffer */ |
748 | #endif | ||
749 | |||
750 | #ifdef HAVE_SPDIF_IN | ||
751 | #ifdef HAVE_SPDIF_POWER | ||
752 | audio_set_spdif_power_setting(global_settings.spdif_enable); | ||
753 | #endif | ||
754 | #endif | ||
715 | 755 | ||
716 | #if CONFIG_CODEC == SWCODEC | 756 | #if CONFIG_CODEC == SWCODEC |
717 | rec_set_source(source, source_flags | SRCF_RECORDING); | 757 | rec_set_source(options->rec_source, |
718 | #else | 758 | options->rec_source_flags | SRCF_RECORDING); |
719 | (void)source_flags; | ||
720 | #endif | 759 | #endif |
721 | 760 | ||
722 | audio_set_recording_options(frequency, quality, source, | 761 | audio_set_recording_options(options); |
723 | channel_mode, editable, prerecord_time); | ||
724 | } | 762 | } |
725 | 763 | ||
726 | static char path_buffer[MAX_PATH]; | ||
727 | |||
728 | /* steals mp3 buffer, creates unique filename and starts recording */ | 764 | /* steals mp3 buffer, creates unique filename and starts recording */ |
729 | void rec_record(void) | 765 | void rec_record(void) |
730 | { | 766 | { |
767 | #if CONFIG_CODEC != SWCODEC | ||
731 | talk_buffer_steal(); /* we use the mp3 buffer */ | 768 | talk_buffer_steal(); /* we use the mp3 buffer */ |
769 | #endif | ||
770 | IF_CNFN_NUM_(file_number = -1;) /* Hit disk for number */ | ||
732 | audio_record(rec_create_filename(path_buffer)); | 771 | audio_record(rec_create_filename(path_buffer)); |
733 | } | 772 | } |
734 | 773 | ||
@@ -753,7 +792,6 @@ static void trigger_listener(int trigger_status) | |||
753 | case TRIG_GO: | 792 | case TRIG_GO: |
754 | if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD) | 793 | if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD) |
755 | { | 794 | { |
756 | talk_buffer_steal(); /* we use the mp3 buffer */ | ||
757 | rec_record(); | 795 | rec_record(); |
758 | /* give control to mpeg thread so that it can start | 796 | /* give control to mpeg thread so that it can start |
759 | recording */ | 797 | recording */ |
@@ -831,6 +869,8 @@ bool recording_screen(bool no_source) | |||
831 | ID2P(LANG_GIGABYTE) | 869 | ID2P(LANG_GIGABYTE) |
832 | }; | 870 | }; |
833 | 871 | ||
872 | struct audio_recording_options rec_options; | ||
873 | |||
834 | global_settings.recscreen_on = true; | 874 | global_settings.recscreen_on = true; |
835 | cursor = 0; | 875 | cursor = 0; |
836 | #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) | 876 | #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) |
@@ -838,35 +878,26 @@ bool recording_screen(bool no_source) | |||
838 | #endif | 878 | #endif |
839 | 879 | ||
840 | #if CONFIG_CODEC == SWCODEC | 880 | #if CONFIG_CODEC == SWCODEC |
841 | audio_stop(); | ||
842 | voice_stop(); | ||
843 | /* recording_menu gets messed up: so reset talk_menu */ | 881 | /* recording_menu gets messed up: so reset talk_menu */ |
844 | talk_menu = global_settings.talk_menu; | 882 | talk_menu = global_settings.talk_menu; |
845 | global_settings.talk_menu = 0; | 883 | global_settings.talk_menu = 0; |
884 | /* audio_init_recording stops anything playing when it takes the audio | ||
885 | buffer */ | ||
846 | #else | 886 | #else |
847 | /* Yes, we use the D/A for monitoring */ | 887 | /* Yes, we use the D/A for monitoring */ |
848 | peak_meter_enabled = true; | 888 | peak_meter_enabled = true; |
849 | peak_meter_playback(true); | 889 | peak_meter_playback(true); |
850 | #endif | 890 | #endif |
851 | 891 | ||
852 | #if CONFIG_CODEC == SWCODEC | ||
853 | audio_init_recording(talk_get_bufsize()); | ||
854 | #else | ||
855 | audio_init_recording(0); | 892 | audio_init_recording(0); |
856 | #endif | ||
857 | sound_set_volume(global_settings.volume); | 893 | sound_set_volume(global_settings.volume); |
858 | 894 | ||
859 | #ifdef HAVE_AGC | 895 | #ifdef HAVE_AGC |
860 | peak_meter_get_peakhold(&peak_l, &peak_r); | 896 | peak_meter_get_peakhold(&peak_l, &peak_r); |
861 | #endif | 897 | #endif |
862 | 898 | ||
863 | rec_set_recording_options(global_settings.rec_frequency, | 899 | rec_init_recording_options(&rec_options); |
864 | global_settings.rec_quality, | 900 | rec_set_recording_options(&rec_options); |
865 | global_settings.rec_source, | ||
866 | 0, | ||
867 | global_settings.rec_channels, | ||
868 | global_settings.rec_editable, | ||
869 | global_settings.rec_prerecord_time); | ||
870 | 901 | ||
871 | set_gain(); | 902 | set_gain(); |
872 | settings_apply_trigger(); | 903 | settings_apply_trigger(); |
@@ -1025,7 +1056,6 @@ bool recording_screen(bool no_source) | |||
1025 | { | 1056 | { |
1026 | /* manual recording */ | 1057 | /* manual recording */ |
1027 | have_recorded = true; | 1058 | have_recorded = true; |
1028 | talk_buffer_steal(); /* we use the mp3 buffer */ | ||
1029 | rec_record(); | 1059 | rec_record(); |
1030 | last_seconds = 0; | 1060 | last_seconds = 0; |
1031 | if (talk_menu) | 1061 | if (talk_menu) |
@@ -1253,16 +1283,10 @@ bool recording_screen(bool no_source) | |||
1253 | #if CONFIG_CODEC == SWCODEC | 1283 | #if CONFIG_CODEC == SWCODEC |
1254 | /* reinit after submenu exit */ | 1284 | /* reinit after submenu exit */ |
1255 | audio_close_recording(); | 1285 | audio_close_recording(); |
1256 | audio_init_recording(talk_get_bufsize()); | 1286 | audio_init_recording(0); |
1257 | #endif | 1287 | #endif |
1258 | rec_set_recording_options( | 1288 | rec_init_recording_options(&rec_options); |
1259 | global_settings.rec_frequency, | 1289 | rec_set_recording_options(&rec_options); |
1260 | global_settings.rec_quality, | ||
1261 | global_settings.rec_source, | ||
1262 | 0, | ||
1263 | global_settings.rec_channels, | ||
1264 | global_settings.rec_editable, | ||
1265 | global_settings.rec_prerecord_time); | ||
1266 | 1290 | ||
1267 | if(rec_create_directory() > 0) | 1291 | if(rec_create_directory() > 0) |
1268 | have_recorded = true; | 1292 | have_recorded = true; |
@@ -1739,11 +1763,7 @@ bool recording_screen(bool no_source) | |||
1739 | } | 1763 | } |
1740 | } /* end while(!done) */ | 1764 | } /* end while(!done) */ |
1741 | 1765 | ||
1742 | #if CONFIG_CODEC == SWCODEC | ||
1743 | audio_stat = pcm_rec_status(); | ||
1744 | #else | ||
1745 | audio_stat = audio_status(); | 1766 | audio_stat = audio_status(); |
1746 | #endif | ||
1747 | if (audio_stat & AUDIO_STATUS_ERROR) | 1767 | if (audio_stat & AUDIO_STATUS_ERROR) |
1748 | { | 1768 | { |
1749 | gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL)); | 1769 | gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL)); |
@@ -1804,11 +1824,22 @@ bool recording_screen(bool no_source) | |||
1804 | #if CONFIG_KEYPAD == RECORDER_PAD | 1824 | #if CONFIG_KEYPAD == RECORDER_PAD |
1805 | bool f2_rec_screen(void) | 1825 | bool f2_rec_screen(void) |
1806 | { | 1826 | { |
1827 | static const char* const freq_str[6] = | ||
1828 | { | ||
1829 | "44.1kHz", | ||
1830 | "48kHz", | ||
1831 | "32kHz", | ||
1832 | "22.05kHz", | ||
1833 | "24kHz", | ||
1834 | "16kHz" | ||
1835 | }; | ||
1836 | |||
1807 | bool exit = false; | 1837 | bool exit = false; |
1808 | bool used = false; | 1838 | bool used = false; |
1809 | int w, h, i; | 1839 | int w, h, i; |
1810 | char buf[32]; | 1840 | char buf[32]; |
1811 | int button; | 1841 | int button; |
1842 | struct audio_recording_options rec_options; | ||
1812 | 1843 | ||
1813 | FOR_NB_SCREENS(i) | 1844 | FOR_NB_SCREENS(i) |
1814 | { | 1845 | { |
@@ -1919,13 +1950,8 @@ bool f2_rec_screen(void) | |||
1919 | } | 1950 | } |
1920 | } | 1951 | } |
1921 | 1952 | ||
1922 | rec_set_recording_options(global_settings.rec_frequency, | 1953 | rec_init_recording_options(&rec_options); |
1923 | global_settings.rec_quality, | 1954 | rec_set_recording_options(&rec_options); |
1924 | global_settings.rec_source, | ||
1925 | 0, | ||
1926 | global_settings.rec_channels, | ||
1927 | global_settings.rec_editable, | ||
1928 | global_settings.rec_prerecord_time); | ||
1929 | 1955 | ||
1930 | set_gain(); | 1956 | set_gain(); |
1931 | 1957 | ||
@@ -1948,6 +1974,8 @@ bool f3_rec_screen(void) | |||
1948 | str(LANG_SYSFONT_RECORDING_SRC_LINE), | 1974 | str(LANG_SYSFONT_RECORDING_SRC_LINE), |
1949 | str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) | 1975 | str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) |
1950 | }; | 1976 | }; |
1977 | struct audio_recording_options rec_options; | ||
1978 | |||
1951 | FOR_NB_SCREENS(i) | 1979 | FOR_NB_SCREENS(i) |
1952 | { | 1980 | { |
1953 | screens[i].setfont(FONT_SYSFIXED); | 1981 | screens[i].setfont(FONT_SYSFIXED); |
@@ -2019,13 +2047,8 @@ bool f3_rec_screen(void) | |||
2019 | } | 2047 | } |
2020 | } | 2048 | } |
2021 | 2049 | ||
2022 | rec_set_recording_options(global_settings.rec_frequency, | 2050 | rec_init_recording_options(&rec_options); |
2023 | global_settings.rec_quality, | 2051 | rec_set_recording_options(&rec_options); |
2024 | global_settings.rec_source, | ||
2025 | 0, | ||
2026 | global_settings.rec_channels, | ||
2027 | global_settings.rec_editable, | ||
2028 | global_settings.rec_prerecord_time); | ||
2029 | 2052 | ||
2030 | set_gain(); | 2053 | set_gain(); |
2031 | 2054 | ||
@@ -2066,23 +2089,30 @@ unsigned long audio_num_recorded_bytes(void) | |||
2066 | } | 2089 | } |
2067 | 2090 | ||
2068 | #if CONFIG_CODEC == SWCODEC | 2091 | #if CONFIG_CODEC == SWCODEC |
2069 | void rec_set_source(int source, int flags) | 2092 | void rec_set_source(int source, unsigned flags) |
2070 | { | 2093 | { |
2071 | source = source; | 2094 | source = source; |
2072 | flags = flags; | 2095 | flags = flags; |
2073 | } | 2096 | } |
2074 | #endif | ||
2075 | 2097 | ||
2076 | void audio_set_recording_options(int frequency, int quality, | 2098 | #ifdef HAVE_SPDIF_IN |
2077 | int source, int channel_mode, | 2099 | #ifdef HAVE_SPDIF_POWER |
2078 | bool editable, int prerecord_time) | 2100 | void audio_set_spdif_power_setting(bool on) |
2079 | { | 2101 | { |
2080 | frequency = frequency; | 2102 | on = on; |
2081 | quality = quality; | 2103 | } |
2082 | source = source; | 2104 | |
2083 | channel_mode = channel_mode; | 2105 | bool audio_get_spdif_power_setting(void) |
2084 | editable = editable; | 2106 | { |
2085 | prerecord_time = prerecord_time; | 2107 | return true; |
2108 | } | ||
2109 | #endif /* HAVE_SPDIF_POWER */ | ||
2110 | #endif /* HAVE_SPDIF_IN */ | ||
2111 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
2112 | |||
2113 | void audio_set_recording_options(struct audio_recording_options *options) | ||
2114 | { | ||
2115 | options = options; | ||
2086 | } | 2116 | } |
2087 | 2117 | ||
2088 | void audio_set_recording_gain(int left, int right, int type) | 2118 | void audio_set_recording_gain(int left, int right, int type) |
@@ -2104,7 +2134,7 @@ void audio_resume_recording(void) | |||
2104 | { | 2134 | { |
2105 | } | 2135 | } |
2106 | 2136 | ||
2107 | void pcm_rec_get_peaks(int *left, int *right) | 2137 | void pcm_calculate_rec_peaks(int *left, int *right) |
2108 | { | 2138 | { |
2109 | if (left) | 2139 | if (left) |
2110 | *left = 0; | 2140 | *left = 0; |
diff --git a/apps/recorder/recording.h b/apps/recorder/recording.h index aa216e757f..a977efa749 100644 --- a/apps/recorder/recording.h +++ b/apps/recorder/recording.h | |||
@@ -32,15 +32,16 @@ int rec_create_directory(void); | |||
32 | #define SRCF_FMRADIO_PLAYING 0x0000 /* default */ | 32 | #define SRCF_FMRADIO_PLAYING 0x0000 /* default */ |
33 | #define SRCF_FMRADIO_PAUSED 0x2000 | 33 | #define SRCF_FMRADIO_PAUSED 0x2000 |
34 | #endif | 34 | #endif |
35 | void rec_set_source(int source, int flags); | 35 | void rec_set_source(int source, unsigned flags); |
36 | #endif /* CONFIG_CODEC == SW_CODEC */ | 36 | #endif /* CONFIG_CODEC == SW_CODEC */ |
37 | 37 | ||
38 | /* Initializes a recording_options structure with global settings. | ||
39 | pass returned data to audio_set_recording_options or | ||
40 | rec_set_recording_options */ | ||
41 | void rec_init_recording_options(struct audio_recording_options *options); | ||
38 | /* steals mp3 buffer, sets source and then options */ | 42 | /* steals mp3 buffer, sets source and then options */ |
39 | /* SRCF_RECORDING is implied */ | 43 | /* SRCF_RECORDING is implied for SWCODEC */ |
40 | void rec_set_recording_options(int frequency, int quality, | 44 | void rec_set_recording_options(struct audio_recording_options *options); |
41 | int source, int source_flags, | ||
42 | int channel_mode, bool editable, | ||
43 | int prerecord_time); | ||
44 | 45 | ||
45 | /* steals mp3 buffer, creates unique filename and starts recording */ | 46 | /* steals mp3 buffer, creates unique filename and starts recording */ |
46 | void rec_record(void); | 47 | void rec_record(void); |
diff --git a/apps/settings.c b/apps/settings.c index a4320eda7b..ec96cc760b 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -90,13 +90,16 @@ const char rec_base_directory[] = REC_BASE_DIR; | |||
90 | #include "pcmbuf.h" | 90 | #include "pcmbuf.h" |
91 | #include "pcm_playback.h" | 91 | #include "pcm_playback.h" |
92 | #include "dsp.h" | 92 | #include "dsp.h" |
93 | #ifdef HAVE_RECORDING | ||
94 | #include "enc_config.h" | ||
93 | #endif | 95 | #endif |
96 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
94 | 97 | ||
95 | #ifdef HAVE_WM8758 | 98 | #ifdef HAVE_WM8758 |
96 | #include "eq_menu.h" | 99 | #include "eq_menu.h" |
97 | #endif | 100 | #endif |
98 | 101 | ||
99 | #define CONFIG_BLOCK_VERSION 55 | 102 | #define CONFIG_BLOCK_VERSION 56 |
100 | #define CONFIG_BLOCK_SIZE 512 | 103 | #define CONFIG_BLOCK_SIZE 512 |
101 | #define RTC_BLOCK_SIZE 44 | 104 | #define RTC_BLOCK_SIZE 44 |
102 | 105 | ||
@@ -514,7 +517,7 @@ static const struct bit_entry hd_bits[] = | |||
514 | {1, S_O(rec_editable), false, "editable recordings", off_on }, | 517 | {1, S_O(rec_editable), false, "editable recordings", off_on }, |
515 | #endif /* CONFIG_CODEC == MAS3587F */ | 518 | #endif /* CONFIG_CODEC == MAS3587F */ |
516 | 519 | ||
517 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) | 520 | #if CONFIG_CODEC == SWCODEC |
518 | #ifdef HAVE_UDA1380 | 521 | #ifdef HAVE_UDA1380 |
519 | {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ | 522 | {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ |
520 | #endif | 523 | #endif |
@@ -524,16 +527,20 @@ static const struct bit_entry hd_bits[] = | |||
524 | #endif | 527 | #endif |
525 | {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ | 528 | {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ |
526 | {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ | 529 | {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ |
527 | #if 0 /* Till samplerates are added for SWCODEC */ | 530 | {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT, |
528 | {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ | 531 | "rec frequency", REC_FREQ_CFG_VAL_LIST }, |
529 | "rec frequency", "44,48,32,22,24,16" }, | 532 | {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT, |
530 | #else | 533 | "rec format", REC_FORMAT_CFG_VAL_LIST }, |
531 | {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ | 534 | /** Encoder settings start - keep these together **/ |
532 | "rec frequency", "44" }, | 535 | /* mp3_enc */ |
533 | #endif | 536 | {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT, |
534 | 537 | "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST }, | |
535 | {4, S_O(rec_quality), 4 /* MP3 L3 192 kBit/s */, "rec quality", NULL }, | 538 | /* wav_enc */ |
536 | #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ | 539 | /* (no settings yet) */ |
540 | /* wavpack_enc */ | ||
541 | /* (no settings yet) */ | ||
542 | /** Encoder settings end **/ | ||
543 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
537 | 544 | ||
538 | /* values for the trigger */ | 545 | /* values for the trigger */ |
539 | {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, | 546 | {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, |
@@ -1301,6 +1308,11 @@ void settings_apply(void) | |||
1301 | lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); | 1308 | lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); |
1302 | #endif | 1309 | #endif |
1303 | #endif /* CONFIG_BACKLIGHT */ | 1310 | #endif /* CONFIG_BACKLIGHT */ |
1311 | |||
1312 | /* This should stay last */ | ||
1313 | #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC | ||
1314 | enc_global_settings_apply(); | ||
1315 | #endif | ||
1304 | } | 1316 | } |
1305 | 1317 | ||
1306 | 1318 | ||
@@ -1727,13 +1739,13 @@ static void save_cfg_table(const struct bit_entry* p_table, int count, int fd) | |||
1727 | } | 1739 | } |
1728 | } | 1740 | } |
1729 | 1741 | ||
1730 | |||
1731 | bool settings_save_config(void) | 1742 | bool settings_save_config(void) |
1732 | { | 1743 | { |
1733 | int fd; | 1744 | int fd; |
1734 | char filename[MAX_PATH]; | 1745 | char filename[MAX_PATH]; |
1735 | 1746 | ||
1736 | create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2); | 1747 | create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2 |
1748 | IF_CNFN_NUM_(, NULL)); | ||
1737 | 1749 | ||
1738 | /* allow user to modify filename */ | 1750 | /* allow user to modify filename */ |
1739 | while (true) { | 1751 | while (true) { |
@@ -1887,6 +1899,10 @@ void settings_reset(void) { | |||
1887 | global_settings.kbd_file[0] = '\0'; | 1899 | global_settings.kbd_file[0] = '\0'; |
1888 | #endif | 1900 | #endif |
1889 | global_settings.hold_lr_for_scroll_in_list = true; | 1901 | global_settings.hold_lr_for_scroll_in_list = true; |
1902 | |||
1903 | #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC | ||
1904 | enc_global_settings_reset(); | ||
1905 | #endif | ||
1890 | } | 1906 | } |
1891 | 1907 | ||
1892 | bool set_bool(const char* string, bool* variable ) | 1908 | bool set_bool(const char* string, bool* variable ) |
diff --git a/apps/settings.h b/apps/settings.h index 435d8e9ce2..09d4974eee 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -29,6 +29,10 @@ | |||
29 | #include "tagcache.h" | 29 | #include "tagcache.h" |
30 | #include "button.h" | 30 | #include "button.h" |
31 | 31 | ||
32 | #if CONFIG_CODEC == SWCODEC | ||
33 | #include "audio.h" | ||
34 | #endif | ||
35 | |||
32 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS | 36 | #ifdef HAVE_BACKLIGHT_BRIGHTNESS |
33 | #include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */ | 37 | #include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */ |
34 | #endif | 38 | #endif |
@@ -142,18 +146,22 @@ struct user_settings | |||
142 | int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */ | 146 | int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */ |
143 | #endif | 147 | #endif |
144 | 148 | ||
149 | #if CONFIG_CODEC == SWCODEC | ||
150 | int rec_format; /* record format index */ | ||
151 | #else | ||
145 | int rec_quality; /* 0-7 */ | 152 | int rec_quality; /* 0-7 */ |
146 | int rec_source; /* 0=mic, 1=line, 2=S/PDIF */ | 153 | #endif /* CONFIG_CODEC == SWCODEC */ |
147 | int rec_frequency; /* 0 = 44.1kHz | 154 | int rec_source; /* 0=mic, 1=line, 2=S/PDIF, 2 or 3=FM Radio */ |
155 | int rec_frequency; /* 0 = 44.1kHz (depends on target) | ||
148 | 1 = 48kHz | 156 | 1 = 48kHz |
149 | 2 = 32kHz | 157 | 2 = 32kHz |
150 | 3 = 22.05kHz | 158 | 3 = 22.05kHz |
151 | 4 = 24kHz | 159 | 4 = 24kHz |
152 | 5 = 16kHz */ | 160 | 5 = 16kHz */ |
153 | int rec_channels; /* 0=Stereo, 1=Mono */ | 161 | int rec_channels; /* 0=Stereo, 1=Mono */ |
154 | int rec_mic_gain; /* 0-15 */ | 162 | int rec_mic_gain; /* depends on target */ |
155 | int rec_left_gain; /* 0-15 */ | 163 | int rec_left_gain; /* depends on target */ |
156 | int rec_right_gain; /* 0-15 */ | 164 | int rec_right_gain; /* depands on target */ |
157 | bool rec_editable; /* true means that the bit reservoir is off */ | 165 | bool rec_editable; /* true means that the bit reservoir is off */ |
158 | bool recscreen_on; /* true if using the recording screen */ | 166 | bool recscreen_on; /* true if using the recording screen */ |
159 | 167 | ||
@@ -504,6 +512,20 @@ struct user_settings | |||
504 | #endif | 512 | #endif |
505 | bool audioscrobbler; /* Audioscrobbler logging */ | 513 | bool audioscrobbler; /* Audioscrobbler logging */ |
506 | 514 | ||
515 | /* If values are just added to the end, no need to bump plugin API | ||
516 | version. */ | ||
517 | /* new stuff to be added at the end */ | ||
518 | |||
519 | #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC | ||
520 | /* Encoder Settings Start - keep these together */ | ||
521 | struct mp3_enc_config mp3_enc_config; | ||
522 | #if 0 /* These currently contain no members but their places in line | ||
523 | should be held */ | ||
524 | struct wav_enc_config wav_enc_config; | ||
525 | struct wavpack_enc_config wavpack_enc_config; | ||
526 | #endif | ||
527 | /* Encoder Settings End */ | ||
528 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
507 | }; | 529 | }; |
508 | 530 | ||
509 | enum optiontype { INT, BOOL }; | 531 | enum optiontype { INT, BOOL }; |
@@ -584,7 +606,7 @@ extern const char rec_base_directory[]; | |||
584 | 606 | ||
585 | /* argument bits for settings_load() */ | 607 | /* argument bits for settings_load() */ |
586 | #define SETTINGS_RTC 1 /* only the settings from the RTC nonvolatile RAM */ | 608 | #define SETTINGS_RTC 1 /* only the settings from the RTC nonvolatile RAM */ |
587 | #define SETTINGS_HD 2 /* only the settings fron the disk sector */ | 609 | #define SETTINGS_HD 2 /* only the settings from the disk sector */ |
588 | #define SETTINGS_ALL 3 /* both */ | 610 | #define SETTINGS_ALL 3 /* both */ |
589 | 611 | ||
590 | /* repeat mode options */ | 612 | /* repeat mode options */ |
diff --git a/apps/sound_menu.c b/apps/sound_menu.c index c10ba9417e..fb766d604c 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c | |||
@@ -54,6 +54,10 @@ | |||
54 | #include "dsp.h" | 54 | #include "dsp.h" |
55 | #include "eq_menu.h" | 55 | #include "eq_menu.h" |
56 | #include "pcmbuf.h" | 56 | #include "pcmbuf.h" |
57 | #ifdef HAVE_RECORDING | ||
58 | #include "enc_config.h" | ||
59 | #endif | ||
60 | #include "general.h" | ||
57 | #endif | 61 | #endif |
58 | #include "action.h" | 62 | #include "action.h" |
59 | 63 | ||
@@ -308,22 +312,20 @@ static bool recsource(void) | |||
308 | { | 312 | { |
309 | int n_opts = AUDIO_NUM_SOURCES; | 313 | int n_opts = AUDIO_NUM_SOURCES; |
310 | 314 | ||
311 | struct opt_items names[AUDIO_NUM_SOURCES] = { | 315 | static const struct opt_items names[AUDIO_NUM_SOURCES] = { |
312 | { STR(LANG_RECORDING_SRC_MIC) }, | 316 | [AUDIO_SRC_MIC] = { STR(LANG_RECORDING_SRC_MIC) }, |
313 | { STR(LANG_RECORDING_SRC_LINE) }, | 317 | [AUDIO_SRC_LINEIN] = { STR(LANG_RECORDING_SRC_LINE) }, |
314 | #ifdef HAVE_SPDIF_IN | 318 | #ifdef HAVE_SPDIF_IN |
315 | { STR(LANG_RECORDING_SRC_DIGITAL) }, | 319 | [AUDIO_SRC_SPDIF] = { STR(LANG_RECORDING_SRC_DIGITAL) }, |
320 | #endif | ||
321 | #ifdef HAVE_FMRADIO_IN | ||
322 | [AUDIO_SRC_FMRADIO] = { STR(LANG_FM_RADIO) } | ||
316 | #endif | 323 | #endif |
317 | }; | 324 | }; |
318 | 325 | ||
319 | /* caveat: assumes it's the last item! */ | 326 | /* caveat: assumes it's the last item! */ |
320 | #ifdef HAVE_FMRADIO_IN | 327 | #ifdef HAVE_FMRADIO_IN |
321 | if (radio_hardware_present()) | 328 | if (!radio_hardware_present()) |
322 | { | ||
323 | names[AUDIO_SRC_FMRADIO].string = ID2P(LANG_FM_RADIO); | ||
324 | names[AUDIO_SRC_FMRADIO].voice_id = LANG_FM_RADIO; | ||
325 | } | ||
326 | else | ||
327 | n_opts--; | 329 | n_opts--; |
328 | #endif | 330 | #endif |
329 | 331 | ||
@@ -332,28 +334,7 @@ static bool recsource(void) | |||
332 | n_opts, NULL ); | 334 | n_opts, NULL ); |
333 | } | 335 | } |
334 | 336 | ||
335 | /* To be removed when we add support for sample rates and channel settings */ | 337 | #if CONFIG_CODEC == MAS3587F |
336 | #if CONFIG_CODEC == SWCODEC | ||
337 | static bool recquality(void) | ||
338 | { | ||
339 | static const struct opt_items names[] = { | ||
340 | { "MP3 64 kBit/s", TALK_ID( 64, UNIT_KBIT) }, | ||
341 | { "MP3 96 kBit/s", TALK_ID( 96, UNIT_KBIT) }, | ||
342 | { "MP3 128 kBit/s", TALK_ID( 128, UNIT_KBIT) }, | ||
343 | { "MP3 160 kBit/s", TALK_ID( 160, UNIT_KBIT) }, | ||
344 | { "MP3 192 kBit/s", TALK_ID( 192, UNIT_KBIT) }, | ||
345 | { "MP3 224 kBit/s", TALK_ID( 224, UNIT_KBIT) }, | ||
346 | { "MP3 320 kBit/s", TALK_ID( 320, UNIT_KBIT) }, | ||
347 | { "WV 900 kBit/s", TALK_ID( 900, UNIT_KBIT) }, | ||
348 | { "WAV 1411 kBit/s", TALK_ID(1411, UNIT_KBIT) } | ||
349 | }; | ||
350 | |||
351 | return set_option(str(LANG_RECORDING_QUALITY), | ||
352 | &global_settings.rec_quality, INT, | ||
353 | names, sizeof (names)/sizeof(struct opt_items), | ||
354 | NULL ); | ||
355 | } | ||
356 | #elif CONFIG_CODEC == MAS3587F | ||
357 | static bool recquality(void) | 338 | static bool recquality(void) |
358 | { | 339 | { |
359 | return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT, | 340 | return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT, |
@@ -368,32 +349,182 @@ static bool receditable(void) | |||
368 | } | 349 | } |
369 | #endif /* CONFIG_CODEC == MAS3587F */ | 350 | #endif /* CONFIG_CODEC == MAS3587F */ |
370 | 351 | ||
352 | #if CONFIG_CODEC == SWCODEC | ||
353 | /* Makes an options list from a source list of options and indexes */ | ||
354 | void make_options_from_indexes(const struct opt_items *src_names, | ||
355 | const long *src_indexes, | ||
356 | int n_indexes, | ||
357 | struct opt_items *dst_names) | ||
358 | { | ||
359 | while (--n_indexes >= 0) | ||
360 | dst_names[n_indexes] = src_names[src_indexes[n_indexes]]; | ||
361 | } /* make_options_from_indexes */ | ||
362 | |||
363 | static bool recformat(void) | ||
364 | { | ||
365 | static const struct opt_items names[REC_NUM_FORMATS] = { | ||
366 | [REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) }, | ||
367 | [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) }, | ||
368 | [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) }, | ||
369 | }; | ||
370 | |||
371 | int rec_format = global_settings.rec_format; | ||
372 | bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT, | ||
373 | names, REC_NUM_FORMATS, NULL ); | ||
374 | |||
375 | if (rec_format != global_settings.rec_format) | ||
376 | { | ||
377 | global_settings.rec_format = rec_format; | ||
378 | enc_global_settings_apply(); | ||
379 | } | ||
380 | |||
381 | return res; | ||
382 | } /* recformat */ | ||
383 | |||
384 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
385 | |||
371 | static bool recfrequency(void) | 386 | static bool recfrequency(void) |
372 | { | 387 | { |
373 | static const struct opt_items names[] = { | 388 | #if CONFIG_CODEC == MAS3587F |
389 | static const struct opt_items names[6] = { | ||
374 | { "44.1kHz", TALK_ID(44, UNIT_KHZ) }, | 390 | { "44.1kHz", TALK_ID(44, UNIT_KHZ) }, |
375 | #if CONFIG_CODEC != SWCODEC /* This is temporary */ | ||
376 | { "48kHz", TALK_ID(48, UNIT_KHZ) }, | 391 | { "48kHz", TALK_ID(48, UNIT_KHZ) }, |
377 | { "32kHz", TALK_ID(32, UNIT_KHZ) }, | 392 | { "32kHz", TALK_ID(32, UNIT_KHZ) }, |
378 | { "22.05kHz", TALK_ID(22, UNIT_KHZ) }, | 393 | { "22.05kHz", TALK_ID(22, UNIT_KHZ) }, |
379 | { "24kHz", TALK_ID(24, UNIT_KHZ) }, | 394 | { "24kHz", TALK_ID(24, UNIT_KHZ) }, |
380 | { "16kHz", TALK_ID(16, UNIT_KHZ) } | 395 | { "16kHz", TALK_ID(16, UNIT_KHZ) } |
381 | #endif | ||
382 | }; | 396 | }; |
383 | return set_option(str(LANG_RECORDING_FREQUENCY), | 397 | return set_option(str(LANG_RECORDING_FREQUENCY), |
384 | &global_settings.rec_frequency, INT, | 398 | &global_settings.rec_frequency, INT, |
385 | names, sizeof(names)/sizeof(*names), NULL ); | 399 | names, 6, NULL ); |
400 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
401 | |||
402 | #if CONFIG_CODEC == SWCODEC | ||
403 | static const struct opt_items names[REC_NUM_FREQ] = { | ||
404 | REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },) | ||
405 | REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },) | ||
406 | REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },) | ||
407 | REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },) | ||
408 | REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },) | ||
409 | REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },) | ||
410 | REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },) | ||
411 | REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },) | ||
412 | REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },) | ||
413 | REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },) | ||
414 | REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },) | ||
415 | REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },) | ||
416 | }; | ||
417 | |||
418 | struct opt_items opts[REC_NUM_FREQ]; | ||
419 | unsigned long table[REC_NUM_FREQ]; | ||
420 | int n_opts; | ||
421 | int rec_frequency; | ||
422 | bool ret; | ||
423 | |||
424 | #ifdef HAVE_SPDIF_IN | ||
425 | if (global_settings.rec_source == AUDIO_SRC_SPDIF) | ||
426 | { | ||
427 | /* Inform user that frequency follows the source's frequency */ | ||
428 | opts[0].string = ID2P(LANG_SOURCE_FREQUENCY); | ||
429 | opts[0].voice_id = LANG_SOURCE_FREQUENCY; | ||
430 | n_opts = 1; | ||
431 | rec_frequency = 0; | ||
386 | } | 432 | } |
433 | else | ||
434 | #endif | ||
435 | { | ||
436 | struct encoder_caps caps; | ||
437 | struct encoder_config cfg; | ||
438 | |||
439 | cfg.rec_format = global_settings.rec_format; | ||
440 | global_to_encoder_config(&cfg); | ||
441 | |||
442 | if (!enc_get_caps(&cfg, &caps, true)) | ||
443 | return false; | ||
444 | |||
445 | /* Construct samplerate menu based upon encoder settings */ | ||
446 | n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL, | ||
447 | caps.samplerate_caps, table); | ||
448 | |||
449 | if (n_opts == 0) | ||
450 | return false; /* No common flags...?? */ | ||
451 | |||
452 | make_options_from_indexes(names, table, n_opts, opts); | ||
453 | |||
454 | /* Find closest rate that the potentially restricted list | ||
455 | comes to */ | ||
456 | make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr, | ||
457 | caps.samplerate_caps, table); | ||
458 | |||
459 | rec_frequency = round_value_to_list32( | ||
460 | rec_freq_sampr[global_settings.rec_frequency], | ||
461 | table, n_opts, false); | ||
462 | } | ||
463 | |||
464 | ret = set_option(str(LANG_RECORDING_FREQUENCY), | ||
465 | &rec_frequency, INT, opts, n_opts, NULL ); | ||
466 | |||
467 | if (!ret | ||
468 | #ifdef HAVE_SPDIF_IN | ||
469 | && global_settings.rec_source != AUDIO_SRC_SPDIF | ||
470 | #endif | ||
471 | ) | ||
472 | { | ||
473 | /* Translate back to full index */ | ||
474 | global_settings.rec_frequency = | ||
475 | round_value_to_list32(table[rec_frequency], | ||
476 | rec_freq_sampr, | ||
477 | REC_NUM_FREQ, | ||
478 | false); | ||
479 | } | ||
480 | |||
481 | return ret; | ||
482 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
483 | } /* recfrequency */ | ||
387 | 484 | ||
388 | static bool recchannels(void) | 485 | static bool recchannels(void) |
389 | { | 486 | { |
390 | static const struct opt_items names[] = { | 487 | static const struct opt_items names[CHN_NUM_MODES] = { |
391 | { STR(LANG_CHANNEL_STEREO) }, | 488 | [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) }, |
392 | { STR(LANG_CHANNEL_MONO) } | 489 | [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) } |
393 | }; | 490 | }; |
491 | #if CONFIG_CODEC == MAS3587F | ||
394 | return set_option(str(LANG_RECORDING_CHANNELS), | 492 | return set_option(str(LANG_RECORDING_CHANNELS), |
395 | &global_settings.rec_channels, INT, | 493 | &global_settings.rec_channels, INT, |
396 | names, 2, NULL ); | 494 | names, CHN_NUM_MODES, NULL ); |
495 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
496 | |||
497 | #if CONFIG_CODEC == SWCODEC | ||
498 | struct opt_items opts[CHN_NUM_MODES]; | ||
499 | long table[CHN_NUM_MODES]; | ||
500 | struct encoder_caps caps; | ||
501 | struct encoder_config cfg; | ||
502 | int n_opts; | ||
503 | int rec_channels; | ||
504 | bool ret; | ||
505 | |||
506 | cfg.rec_format = global_settings.rec_format; | ||
507 | global_to_encoder_config(&cfg); | ||
508 | |||
509 | if (!enc_get_caps(&cfg, &caps, true)) | ||
510 | return false; | ||
511 | |||
512 | n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL, | ||
513 | caps.channel_caps, table); | ||
514 | |||
515 | rec_channels = round_value_to_list32(global_settings.rec_channels, | ||
516 | table, n_opts, false); | ||
517 | |||
518 | make_options_from_indexes(names, table, n_opts, opts); | ||
519 | |||
520 | ret = set_option(str(LANG_RECORDING_CHANNELS), &rec_channels, | ||
521 | INT, opts, n_opts, NULL ); | ||
522 | |||
523 | if (!ret) | ||
524 | global_settings.rec_channels = table[rec_channels]; | ||
525 | |||
526 | return ret; | ||
527 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
397 | } | 528 | } |
398 | 529 | ||
399 | static bool rectimesplit(void) | 530 | static bool rectimesplit(void) |
@@ -1049,58 +1180,59 @@ bool rectrigger(void) | |||
1049 | action_signalscreenchange(); | 1180 | action_signalscreenchange(); |
1050 | return retval; | 1181 | return retval; |
1051 | } | 1182 | } |
1052 | #endif | 1183 | #endif /* !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F */ |
1053 | 1184 | ||
1054 | bool recording_menu(bool no_source) | 1185 | bool recording_menu(bool no_source) |
1055 | { | 1186 | { |
1056 | int m; | 1187 | static const struct menu_item static_items[] = { |
1057 | int i = 0; | 1188 | #if CONFIG_CODEC == MAS3587F |
1058 | struct menu_item items[13]; | 1189 | { ID2P(LANG_RECORDING_QUALITY), recquality }, |
1059 | bool result; | ||
1060 | |||
1061 | #if CONFIG_CODEC == MAS3587F || CONFIG_CODEC == SWCODEC | ||
1062 | items[i].desc = ID2P(LANG_RECORDING_QUALITY); | ||
1063 | items[i++].function = recquality; | ||
1064 | #endif | 1190 | #endif |
1065 | items[i].desc = ID2P(LANG_RECORDING_FREQUENCY); | 1191 | #if CONFIG_CODEC == SWCODEC |
1066 | items[i++].function = recfrequency; | 1192 | { ID2P(LANG_RECORDING_FORMAT), recformat }, |
1067 | if(!no_source) { | 1193 | { ID2P(LANG_ENCODER_SETTINGS), enc_global_config_menu }, |
1068 | items[i].desc = ID2P(LANG_RECORDING_SOURCE); | 1194 | #endif |
1069 | items[i++].function = recsource; | 1195 | { ID2P(LANG_RECORDING_FREQUENCY), recfrequency }, |
1070 | } | 1196 | { ID2P(LANG_RECORDING_SOURCE), recsource }, /* not shown if no_source */ |
1071 | items[i].desc = ID2P(LANG_RECORDING_CHANNELS); | 1197 | { ID2P(LANG_RECORDING_CHANNELS), recchannels }, |
1072 | items[i++].function = recchannels; | ||
1073 | #if CONFIG_CODEC == MAS3587F | 1198 | #if CONFIG_CODEC == MAS3587F |
1074 | items[i].desc = ID2P(LANG_RECORDING_EDITABLE); | 1199 | { ID2P(LANG_RECORDING_EDITABLE), receditable }, |
1075 | items[i++].function = receditable; | ||
1076 | #endif | 1200 | #endif |
1077 | items[i].desc = ID2P(LANG_RECORD_TIMESPLIT); | 1201 | { ID2P(LANG_RECORD_TIMESPLIT), filesplitoptionsmenu }, |
1078 | items[i++].function = filesplitoptionsmenu; | 1202 | { ID2P(LANG_RECORD_PRERECORD_TIME), recprerecord }, |
1079 | items[i].desc = ID2P(LANG_RECORD_PRERECORD_TIME); | 1203 | { ID2P(LANG_RECORD_DIRECTORY), recdirectory }, |
1080 | items[i++].function = recprerecord; | 1204 | { ID2P(LANG_RECORD_STARTUP), reconstartup }, |
1081 | items[i].desc = ID2P(LANG_RECORD_DIRECTORY); | ||
1082 | items[i++].function = recdirectory; | ||
1083 | items[i].desc = ID2P(LANG_RECORD_STARTUP); | ||
1084 | items[i++].function = reconstartup; | ||
1085 | #ifdef CONFIG_BACKLIGHT | 1205 | #ifdef CONFIG_BACKLIGHT |
1086 | items[i].desc = ID2P(LANG_CLIP_LIGHT); | 1206 | { ID2P(LANG_CLIP_LIGHT), cliplight }, |
1087 | items[i++].function = cliplight; | ||
1088 | #endif | 1207 | #endif |
1089 | #if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F | 1208 | #if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F |
1090 | items[i].desc = ID2P(LANG_RECORD_TRIGGER); | 1209 | { ID2P(LANG_RECORD_TRIGGER), rectrigger }, |
1091 | items[i++].function = rectrigger; | ||
1092 | #endif | 1210 | #endif |
1093 | #ifdef HAVE_AGC | 1211 | #ifdef HAVE_AGC |
1094 | items[i].desc = ID2P(LANG_RECORD_AGC_PRESET); | 1212 | { ID2P(LANG_RECORD_AGC_PRESET), agc_preset }, |
1095 | items[i++].function = agc_preset; | 1213 | { ID2P(LANG_RECORD_AGC_CLIPTIME), agc_cliptime }, |
1096 | items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME); | ||
1097 | items[i++].function = agc_cliptime; | ||
1098 | #endif | 1214 | #endif |
1215 | }; | ||
1099 | 1216 | ||
1100 | m=menu_init( items, i, NULL, NULL, NULL, NULL); | 1217 | struct menu_item items[ARRAYLEN(static_items)]; |
1218 | int i, n_items; | ||
1219 | int m; | ||
1220 | |||
1221 | bool result; | ||
1222 | |||
1223 | for (i = 0, n_items = 0; i < (int)ARRAYLEN(items); i++) | ||
1224 | { | ||
1225 | const struct menu_item *mi = &static_items[i]; | ||
1226 | if (no_source && mi->function == recsource) | ||
1227 | continue; | ||
1228 | items[n_items++] = *mi; | ||
1229 | } | ||
1230 | |||
1231 | m = menu_init(items, n_items, NULL, NULL, NULL, NULL); | ||
1101 | result = menu_run(m); | 1232 | result = menu_run(m); |
1102 | menu_exit(m); | 1233 | menu_exit(m); |
1103 | 1234 | ||
1104 | return result; | 1235 | return result; |
1105 | } | 1236 | } /* recording_menu */ |
1106 | #endif | 1237 | |
1238 | #endif /* HAVE_RECORDING */ | ||
diff --git a/apps/status.c b/apps/status.c index 2a57db0f89..75219d604c 100644 --- a/apps/status.c +++ b/apps/status.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #ifdef CONFIG_TUNER | 46 | #ifdef CONFIG_TUNER |
47 | #include "radio.h" | 47 | #include "radio.h" |
48 | #endif | 48 | #endif |
49 | #if CONFIG_CODEC == SWCODEC | 49 | #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC |
50 | #include "pcm_record.h" | 50 | #include "pcm_record.h" |
51 | #endif | 51 | #endif |
52 | 52 | ||
@@ -87,10 +87,6 @@ int current_playmode(void) | |||
87 | } | 87 | } |
88 | 88 | ||
89 | #ifdef HAVE_RECORDING | 89 | #ifdef HAVE_RECORDING |
90 | #if CONFIG_CODEC == SWCODEC | ||
91 | audio_stat = pcm_rec_status(); | ||
92 | #endif | ||
93 | |||
94 | if(audio_stat & AUDIO_STATUS_RECORD) | 90 | if(audio_stat & AUDIO_STATUS_RECORD) |
95 | { | 91 | { |
96 | if(audio_stat & AUDIO_STATUS_PAUSE) | 92 | if(audio_stat & AUDIO_STATUS_PAUSE) |
diff --git a/apps/talk.c b/apps/talk.c index d81aa082c9..018f6ed5ab 100644 --- a/apps/talk.c +++ b/apps/talk.c | |||
@@ -46,13 +46,17 @@ | |||
46 | 46 | ||
47 | MASCODEC | MASCODEC | SWCODEC | 47 | MASCODEC | MASCODEC | SWCODEC |
48 | (playing) | (stopped) | | 48 | (playing) | (stopped) | |
49 | audiobuf-----------+-----------+----------- | 49 | audiobuf-----------+-----------+------------ |
50 | audio | voice | thumbnail | 50 | audio | voice | thumbnail |
51 | |-----------|----------- filebuf | 51 | |-----------|------------ |
52 | | thumbnail | voice | 52 | | thumbnail | voice |
53 | | |----------- | 53 | | |------------ |
54 | | | filebuf | ||
55 | | |------------ | ||
54 | | | audio | 56 | | | audio |
55 | audiobufend----------+-----------+----------- | 57 | | |------------ |
58 | | | codec swap | ||
59 | audiobufend----------+-----------+------------ | ||
56 | 60 | ||
57 | SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */ | 61 | SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */ |
58 | 62 | ||
@@ -102,7 +106,7 @@ struct queue_entry /* one entry of the internal queue */ | |||
102 | 106 | ||
103 | /***************** Globals *****************/ | 107 | /***************** Globals *****************/ |
104 | 108 | ||
105 | static unsigned char* p_thumbnail; /* buffer for thumbnail */ | 109 | static unsigned char* p_thumbnail = NULL; /* buffer for thumbnail */ |
106 | static long size_for_thumbnail; /* leftover buffer size for it */ | 110 | static long size_for_thumbnail; /* leftover buffer size for it */ |
107 | static struct voicefile* p_voicefile; /* loaded voicefile */ | 111 | static struct voicefile* p_voicefile; /* loaded voicefile */ |
108 | static bool has_voicefile; /* a voicefile file is present */ | 112 | static bool has_voicefile; /* a voicefile file is present */ |
@@ -479,11 +483,14 @@ static void reset_state(void) | |||
479 | queue_write = queue_read = 0; /* reset the queue */ | 483 | queue_write = queue_read = 0; /* reset the queue */ |
480 | p_voicefile = NULL; /* indicate no voicefile (trashed) */ | 484 | p_voicefile = NULL; /* indicate no voicefile (trashed) */ |
481 | #if CONFIG_CODEC == SWCODEC | 485 | #if CONFIG_CODEC == SWCODEC |
482 | /* Allocate a dedicated thumbnail buffer */ | 486 | /* Allocate a dedicated thumbnail buffer - once */ |
483 | size_for_thumbnail = audiobufend - audiobuf; | 487 | if (p_thumbnail == NULL) |
484 | if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE) | 488 | { |
485 | size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE; | 489 | size_for_thumbnail = audiobufend - audiobuf; |
486 | p_thumbnail = buffer_alloc(size_for_thumbnail); | 490 | if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE) |
491 | size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE; | ||
492 | p_thumbnail = buffer_alloc(size_for_thumbnail); | ||
493 | } | ||
487 | #else | 494 | #else |
488 | /* Just use the audiobuf, without allocating anything */ | 495 | /* Just use the audiobuf, without allocating anything */ |
489 | p_thumbnail = audiobuf; | 496 | p_thumbnail = audiobuf; |
diff --git a/apps/tree.c b/apps/tree.c index 653da791a8..6465b50e6f 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -58,7 +58,9 @@ | |||
58 | #include "misc.h" | 58 | #include "misc.h" |
59 | #include "filetree.h" | 59 | #include "filetree.h" |
60 | #include "tagtree.h" | 60 | #include "tagtree.h" |
61 | #ifdef HAVE_RECORDING | ||
61 | #include "recorder/recording.h" | 62 | #include "recorder/recording.h" |
63 | #endif | ||
62 | #include "rtc.h" | 64 | #include "rtc.h" |
63 | #include "dircache.h" | 65 | #include "dircache.h" |
64 | #ifdef HAVE_TAGCACHE | 66 | #ifdef HAVE_TAGCACHE |
diff --git a/bootloader/main.c b/bootloader/main.c index 99eb449151..0f3d706d7b 100644 --- a/bootloader/main.c +++ b/bootloader/main.c | |||
@@ -204,6 +204,7 @@ void main(void) | |||
204 | kernel_init(); | 204 | kernel_init(); |
205 | 205 | ||
206 | set_cpu_frequency(CPUFREQ_NORMAL); | 206 | set_cpu_frequency(CPUFREQ_NORMAL); |
207 | coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); | ||
207 | 208 | ||
208 | set_irq_level(0); | 209 | set_irq_level(0); |
209 | lcd_init(); | 210 | lcd_init(); |
@@ -311,6 +312,9 @@ void main(void) | |||
311 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 312 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
312 | /* Set up waitstates for the peripherals */ | 313 | /* Set up waitstates for the peripherals */ |
313 | set_cpu_frequency(0); /* PLL off */ | 314 | set_cpu_frequency(0); /* PLL off */ |
315 | #ifdef CPU_COLDFIRE | ||
316 | coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); | ||
317 | #endif | ||
314 | #endif | 318 | #endif |
315 | 319 | ||
316 | #ifdef HAVE_UDA1380 | 320 | #ifdef HAVE_UDA1380 |
diff --git a/firmware/SOURCES b/firmware/SOURCES index 1ec3c82616..df38169be3 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -4,6 +4,7 @@ logf.c | |||
4 | #endif | 4 | #endif |
5 | backlight.c | 5 | backlight.c |
6 | buffer.c | 6 | buffer.c |
7 | general.c | ||
7 | common/atoi.c | 8 | common/atoi.c |
8 | common/crc32.c | 9 | common/crc32.c |
9 | common/ctype.c | 10 | common/ctype.c |
@@ -45,7 +46,12 @@ target/coldfire/memcpy-coldfire.S | |||
45 | target/coldfire/memmove-coldfire.S | 46 | target/coldfire/memmove-coldfire.S |
46 | target/coldfire/memset-coldfire.S | 47 | target/coldfire/memset-coldfire.S |
47 | target/coldfire/memset16-coldfire.S | 48 | target/coldfire/memset16-coldfire.S |
49 | #ifndef SIMULATOR | ||
50 | #ifndef BOOTLOADER | ||
51 | target/coldfire/pcm-coldfire.c | ||
52 | #endif | ||
48 | target/coldfire/system-coldfire.c | 53 | target/coldfire/system-coldfire.c |
54 | #endif | ||
49 | #elif (CONFIG_CPU == SH7034) | 55 | #elif (CONFIG_CPU == SH7034) |
50 | target/sh/memcpy-sh.S | 56 | target/sh/memcpy-sh.S |
51 | target/sh/memmove-sh.S | 57 | target/sh/memmove-sh.S |
@@ -207,15 +213,21 @@ drivers/wm8731l.c | |||
207 | #elif defined(HAVE_TLV320) && !defined(SIMULATOR) | 213 | #elif defined(HAVE_TLV320) && !defined(SIMULATOR) |
208 | drivers/tlv320.c | 214 | drivers/tlv320.c |
209 | #endif | 215 | #endif |
210 | #if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) | 216 | #if (CONFIG_CODEC == SWCODEC) && !defined(BOOTLOADER) |
211 | pcm_playback.c | 217 | pcm_sampr.c |
212 | #endif | ||
213 | #if CONFIG_CODEC == SWCODEC | ||
214 | replaygain.c | 218 | replaygain.c |
215 | #endif | 219 | #ifndef SIMULATOR |
216 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 220 | pcm_playback.c |
221 | #endif /* SIMULATOR */ | ||
222 | #ifdef HAVE_RECORDING | ||
223 | enc_base.c | ||
224 | #if defined(CPU_COLDFIRE) | ||
225 | #ifndef SIMULATOR | ||
217 | pcm_record.c | 226 | pcm_record.c |
218 | #endif | 227 | #endif /* SIMULATOR */ |
228 | #endif /* CPU_COLDFIRE */ | ||
229 | #endif /* HAVE_RECORDING */ | ||
230 | #endif /* SWCODEC && !BOOTLOADER */ | ||
219 | sound.c | 231 | sound.c |
220 | #if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) | 232 | #if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) |
221 | common/sscanf.c | 233 | common/sscanf.c |
diff --git a/firmware/drivers/tlv320.c b/firmware/drivers/tlv320.c index abce31ef81..7c4bbbd1ee 100644 --- a/firmware/drivers/tlv320.c +++ b/firmware/drivers/tlv320.c | |||
@@ -82,7 +82,7 @@ void tlv320_init(void) | |||
82 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ | 82 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ |
83 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); | 83 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); |
84 | tlv320_write_reg(REG_DIA, DIA_ACT); | 84 | tlv320_write_reg(REG_DIA, DIA_ACT); |
85 | tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ | 85 | tlv320_set_frequency(-1); /* default */ |
86 | /* All ON except ADC, MIC and LINE */ | 86 | /* All ON except ADC, MIC and LINE */ |
87 | tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); | 87 | tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); |
88 | } | 88 | } |
@@ -96,6 +96,32 @@ void tlv320_reset(void) | |||
96 | } | 96 | } |
97 | 97 | ||
98 | /** | 98 | /** |
99 | * Sets internal sample rate for DAC and ADC relative to MCLK | ||
100 | * Selection for frequency: | ||
101 | * Fs: tlv: with: | ||
102 | * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
103 | * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 | ||
104 | * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
105 | * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 | ||
106 | */ | ||
107 | void tlv320_set_frequency(unsigned fsel) | ||
108 | { | ||
109 | /* All rates available for 11.2896MHz besides 8.021 */ | ||
110 | unsigned char values_src[3] = | ||
111 | { | ||
112 | /* Fs: */ | ||
113 | (0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */ | ||
114 | (0x8 << 2), /* 44100 */ | ||
115 | (0xf << 2), /* 88200 */ | ||
116 | }; | ||
117 | |||
118 | if (fsel >= ARRAYLEN(values_src)) | ||
119 | fsel = 1; | ||
120 | |||
121 | tlv320_write_reg(REG_SRC, values_src[fsel]); | ||
122 | } | ||
123 | |||
124 | /** | ||
99 | * Sets left and right headphone volume | 125 | * Sets left and right headphone volume |
100 | * | 126 | * |
101 | * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB | 127 | * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB |
@@ -142,7 +168,6 @@ void tlv320_set_recvol(int left, int right, int type) | |||
142 | value_aap &= ~AAP_MICB; | 168 | value_aap &= ~AAP_MICB; |
143 | 169 | ||
144 | tlv320_write_reg(REG_AAP, value_aap); | 170 | tlv320_write_reg(REG_AAP, value_aap); |
145 | |||
146 | } | 171 | } |
147 | else if (type == AUDIO_GAIN_LINEIN) | 172 | else if (type == AUDIO_GAIN_LINEIN) |
148 | { | 173 | { |
@@ -180,15 +205,17 @@ void tlv320_mute(bool mute) | |||
180 | } | 205 | } |
181 | 206 | ||
182 | /* Nice shutdown of TLV320 codec */ | 207 | /* Nice shutdown of TLV320 codec */ |
183 | void tlv320_close() | 208 | void tlv320_close(void) |
184 | { | 209 | { |
210 | tlv320_mute(true); | ||
211 | sleep(HZ/8); | ||
212 | |||
185 | tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | | 213 | tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | |
186 | PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ | 214 | PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ |
187 | } | 215 | } |
188 | 216 | ||
189 | void tlv320_enable_recording(bool source_mic) | 217 | void tlv320_enable_recording(bool source_mic) |
190 | { | 218 | { |
191 | unsigned value_daif = tlv320_regs[REG_DAIF]; | ||
192 | unsigned value_aap, value_pc; | 219 | unsigned value_aap, value_pc; |
193 | 220 | ||
194 | if (source_mic) | 221 | if (source_mic) |
@@ -205,20 +232,12 @@ void tlv320_enable_recording(bool source_mic) | |||
205 | 232 | ||
206 | tlv320_write_reg(REG_PC, value_pc); | 233 | tlv320_write_reg(REG_PC, value_pc); |
207 | tlv320_write_reg(REG_AAP, value_aap); | 234 | tlv320_write_reg(REG_AAP, value_aap); |
208 | |||
209 | /* Enable MASTER mode (start sending I2S data to the CPU) */ | ||
210 | value_daif |= DAIF_MS; | ||
211 | tlv320_write_reg(REG_DAIF, value_daif); | ||
212 | } | 235 | } |
213 | 236 | ||
214 | void tlv320_disable_recording() | 237 | void tlv320_disable_recording(void) |
215 | { | 238 | { |
216 | unsigned value_pc = tlv320_regs[REG_PC]; | 239 | unsigned value_pc = tlv320_regs[REG_PC]; |
217 | unsigned value_aap = tlv320_regs[REG_AAP]; | 240 | unsigned value_aap = tlv320_regs[REG_AAP]; |
218 | unsigned value_daif = tlv320_regs[REG_DAIF]; | ||
219 | |||
220 | value_daif &= ~DAIF_MS; /* disable MASTER mode */ | ||
221 | tlv320_write_reg(REG_DAIF, value_daif); | ||
222 | 241 | ||
223 | value_aap |= AAP_MICM; /* mute MIC */ | 242 | value_aap |= AAP_MICM; /* mute MIC */ |
224 | tlv320_write_reg(REG_PC, value_aap); | 243 | tlv320_write_reg(REG_PC, value_aap); |
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index 241a117385..d6dfe6623b 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c | |||
@@ -49,9 +49,10 @@ short recgain_line; | |||
49 | #define NUM_DEFAULT_REGS 13 | 49 | #define NUM_DEFAULT_REGS 13 |
50 | unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = | 50 | unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = |
51 | { | 51 | { |
52 | REG_0, EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50, | 52 | REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK | |
53 | SYSCLK_256FS | WSPLL_25_50, | ||
53 | REG_I2S, I2S_IFMT_IIS, | 54 | REG_I2S, I2S_IFMT_IIS, |
54 | REG_PWR, PON_BIAS, | 55 | REG_PWR, PON_PLL | PON_BIAS, |
55 | /* PON_HP & PON_DAC is enabled later */ | 56 | /* PON_HP & PON_DAC is enabled later */ |
56 | REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), | 57 | REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), |
57 | /* 00=max, 3f=mute */ | 58 | /* 00=max, 3f=mute */ |
@@ -60,7 +61,7 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = | |||
60 | REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), | 61 | REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), |
61 | /* 00=max, ff=mute */ | 62 | /* 00=max, ff=mute */ |
62 | REG_EQ, EQ_MODE_MAX, | 63 | REG_EQ, EQ_MODE_MAX, |
63 | /* Bass and tremble = 0 dB */ | 64 | /* Bass and treble = 0 dB */ |
64 | REG_MUTE, MUTE_MASTER | MUTE_CH2, | 65 | REG_MUTE, MUTE_MASTER | MUTE_CH2, |
65 | /* Mute everything to start with */ | 66 | /* Mute everything to start with */ |
66 | REG_MIX_CTL, MIX_CTL_MIX, | 67 | REG_MIX_CTL, MIX_CTL_MIX, |
@@ -192,6 +193,43 @@ void uda1380_reset(void) | |||
192 | #endif | 193 | #endif |
193 | } | 194 | } |
194 | 195 | ||
196 | /** | ||
197 | * Sets frequency settings for DAC and ADC relative to MCLK | ||
198 | * | ||
199 | * Selection for frequency ranges: | ||
200 | * Fs: range: with: | ||
201 | * 11025: 0 = 6.25 to 12.5 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
202 | * 22050: 1 = 12.5 to 25 MCLK/2 SCLK, LRCK: Audio Clk / 8 | ||
203 | * 44100: 2 = 25 to 50 MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
204 | * 88200: 3 = 50 to 100 MCLK SCLK, LRCK: Audio Clk / 2 <= TODO: Needs WSPLL | ||
205 | */ | ||
206 | void uda1380_set_frequency(unsigned fsel) | ||
207 | { | ||
208 | static const unsigned short values_reg[4][2] = | ||
209 | { | ||
210 | /* Fs: */ | ||
211 | { 0, WSPLL_625_125 | SYSCLK_512FS }, /* 11025 */ | ||
212 | { 0, WSPLL_125_25 | SYSCLK_256FS }, /* 22050 */ | ||
213 | { MIX_CTL_SEL_NS, WSPLL_25_50 | SYSCLK_256FS }, /* 44100 */ | ||
214 | { MIX_CTL_SEL_NS, WSPLL_50_100 | SYSCLK_256FS }, /* 88200 */ | ||
215 | }; | ||
216 | |||
217 | const unsigned short *ent; | ||
218 | |||
219 | if (fsel >= ARRAYLEN(values_reg)) | ||
220 | fsel = 2; | ||
221 | |||
222 | ent = values_reg[fsel]; | ||
223 | |||
224 | /* Set WSPLL input frequency range or SYSCLK divider */ | ||
225 | uda1380_regs[REG_0] &= ~0xf; | ||
226 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]); | ||
227 | |||
228 | /* Choose 3rd order or 5th order noise shaper */ | ||
229 | uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS; | ||
230 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]); | ||
231 | } | ||
232 | |||
195 | /* Initialize UDA1380 codec with default register values (uda1380_defaults) */ | 233 | /* Initialize UDA1380 codec with default register values (uda1380_defaults) */ |
196 | int uda1380_init(void) | 234 | int uda1380_init(void) |
197 | { | 235 | { |
@@ -227,30 +265,34 @@ void uda1380_close(void) | |||
227 | */ | 265 | */ |
228 | void uda1380_enable_recording(bool source_mic) | 266 | void uda1380_enable_recording(bool source_mic) |
229 | { | 267 | { |
268 | uda1380_regs[REG_0] &= ~(ADC_CLK | DAC_CLK); | ||
230 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); | 269 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); |
231 | 270 | ||
232 | if (source_mic) | 271 | if (source_mic) |
233 | { | 272 | { |
234 | /* VGA_GAIN: 0=0 dB, F=30dB */ | 273 | /* VGA_GAIN: 0=0 dB, F=30dB */ |
274 | /* Output of left ADC is fed into right bitstream */ | ||
275 | uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_PGAR | PON_ADCR); | ||
235 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); | 276 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); |
277 | uda1380_regs[REG_ADC] &= ~SKIP_DCFIL; | ||
236 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) | 278 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) |
237 | | SEL_LNA | SEL_MIC | EN_DCFIL); | 279 | | SEL_LNA | SEL_MIC | EN_DCFIL); |
238 | uda1380_write_reg(REG_PGA, 0); | 280 | uda1380_write_reg(REG_PGA, 0); |
239 | } else | 281 | } |
282 | else | ||
240 | { | 283 | { |
241 | /* PGA_GAIN: 0=0 dB, F=24dB */ | 284 | /* PGA_GAIN: 0=0 dB, F=24dB */ |
285 | uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_LNA); | ||
242 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL | 286 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL |
243 | | PON_PGAR | PON_ADCR); | 287 | | PON_PGAR | PON_ADCR); |
244 | uda1380_write_reg(REG_ADC, EN_DCFIL); | 288 | uda1380_write_reg(REG_ADC, EN_DCFIL); |
245 | uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & PGA_GAIN_MASK) | 289 | uda1380_write_reg(REG_PGA, uda1380_regs[REG_PGA] & PGA_GAIN_MASK); |
246 | | PGA_GAINL(0) | PGA_GAINR(0)); | ||
247 | } | 290 | } |
248 | 291 | ||
249 | sleep(HZ/8); | 292 | sleep(HZ/8); |
250 | 293 | ||
251 | uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); | 294 | uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); |
252 | uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); | 295 | uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); |
253 | |||
254 | } | 296 | } |
255 | 297 | ||
256 | /** | 298 | /** |
@@ -262,10 +304,13 @@ void uda1380_disable_recording(void) | |||
262 | sleep(HZ/8); | 304 | sleep(HZ/8); |
263 | 305 | ||
264 | uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); | 306 | uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); |
265 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] & ~(PON_LNA | PON_ADCL | 307 | |
266 | | PON_ADCR | PON_PGAL | 308 | uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | PON_PGAL | PON_PGAR); |
267 | | PON_PGAR)); | 309 | uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PLL); |
268 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] & ~EN_ADC); | 310 | |
311 | uda1380_regs[REG_0] &= ~EN_ADC; | ||
312 | uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ADC_CLK | DAC_CLK); | ||
313 | |||
269 | uda1380_write_reg(REG_ADC, SKIP_DCFIL); | 314 | uda1380_write_reg(REG_ADC, SKIP_DCFIL); |
270 | } | 315 | } |
271 | 316 | ||
@@ -373,20 +418,3 @@ void uda1380_set_monitor(int enable) | |||
373 | else /* mute channel 2 */ | 418 | else /* mute channel 2 */ |
374 | uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); | 419 | uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); |
375 | } | 420 | } |
376 | |||
377 | /* Change the order of the noise chaper, | ||
378 | 5th order is recommended above 32kHz */ | ||
379 | void uda1380_set_nsorder(int order) | ||
380 | { | ||
381 | switch(order) | ||
382 | { | ||
383 | case 5: | ||
384 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ||
385 | | MIX_CTL_SEL_NS); | ||
386 | break; | ||
387 | case 3: | ||
388 | default: | ||
389 | uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ||
390 | & ~MIX_CTL_SEL_NS); | ||
391 | } | ||
392 | } | ||
diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 9099cb3765..d3f544de94 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h | |||
@@ -20,6 +20,20 @@ | |||
20 | #define AUDIO_H | 20 | #define AUDIO_H |
21 | 21 | ||
22 | #include <stdbool.h> | 22 | #include <stdbool.h> |
23 | #include <sys/types.h> | ||
24 | /* These must always be included with audio.h for this to compile under | ||
25 | cetain conditions. Do it here or else spread the complication around to | ||
26 | many files. */ | ||
27 | #if CONFIG_CODEC == SWCODEC | ||
28 | #include "pcm_sampr.h" | ||
29 | #include "pcm_playback.h" | ||
30 | #ifdef HAVE_RECORDING | ||
31 | #include "pcm_record.h" | ||
32 | #include "id3.h" | ||
33 | #include "enc_base.h" | ||
34 | #endif /* HAVE_RECORDING */ | ||
35 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
36 | |||
23 | 37 | ||
24 | #ifdef SIMULATOR | 38 | #ifdef SIMULATOR |
25 | #define audio_play(x) sim_audio_play(x) | 39 | #define audio_play(x) sim_audio_play(x) |
@@ -31,9 +45,6 @@ | |||
31 | #define AUDIO_STATUS_PRERECORD 8 | 45 | #define AUDIO_STATUS_PRERECORD 8 |
32 | #define AUDIO_STATUS_ERROR 16 | 46 | #define AUDIO_STATUS_ERROR 16 |
33 | 47 | ||
34 | #define AUDIO_STATUS_STAYON_FLAGS \ | ||
35 | (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE | AUDIO_STATUS_RECORD | AUDIO_) | ||
36 | |||
37 | #define AUDIOERR_DISK_FULL 1 | 48 | #define AUDIOERR_DISK_FULL 1 |
38 | 49 | ||
39 | #define AUDIO_GAIN_LINEIN 0 | 50 | #define AUDIO_GAIN_LINEIN 0 |
@@ -72,10 +83,11 @@ void audio_resume(void); | |||
72 | void audio_next(void); | 83 | void audio_next(void); |
73 | void audio_prev(void); | 84 | void audio_prev(void); |
74 | int audio_status(void); | 85 | int audio_status(void); |
75 | bool audio_query_poweroff(void); | 86 | #if CONFIG_CODEC == SWCODEC |
76 | int audio_track_count(void); /* SWCODEC only */ | 87 | int audio_track_count(void); /* SWCODEC only */ |
77 | long audio_filebufused(void); /* SWCODEC only */ | 88 | long audio_filebufused(void); /* SWCODEC only */ |
78 | void audio_pre_ff_rewind(void); /* SWCODEC only */ | 89 | void audio_pre_ff_rewind(void); /* SWCODEC only */ |
90 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
79 | void audio_ff_rewind(long newtime); | 91 | void audio_ff_rewind(long newtime); |
80 | void audio_flush_and_reload_tracks(void); | 92 | void audio_flush_and_reload_tracks(void); |
81 | struct mp3entry* audio_current_track(void); | 93 | struct mp3entry* audio_current_track(void); |
@@ -89,18 +101,28 @@ void audio_error_clear(void); | |||
89 | int audio_get_file_pos(void); | 101 | int audio_get_file_pos(void); |
90 | void audio_beep(int duration); | 102 | void audio_beep(int duration); |
91 | void audio_init_playback(void); | 103 | void audio_init_playback(void); |
104 | unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size); | ||
92 | 105 | ||
93 | /* audio recording functions */ | 106 | /* channel modes */ |
94 | void audio_init_recording(unsigned int buffer_offset); | 107 | enum rec_channel_modes |
95 | void audio_close_recording(void); | 108 | { |
96 | void audio_record(const char *filename); | 109 | __CHN_MODE_START_INDEX = -1, |
97 | void audio_stop_recording(void); | 110 | |
98 | void audio_pause_recording(void); | 111 | CHN_MODE_STEREO, |
99 | void audio_resume_recording(void); | 112 | CHN_MODE_MONO, |
100 | void audio_new_file(const char *filename); | 113 | |
114 | CHN_NUM_MODES | ||
115 | }; | ||
116 | |||
117 | #if CONFIG_CODEC == SWCODEC | ||
118 | /* channel mode capability bits */ | ||
119 | #define CHN_CAP_STEREO (1 << CHN_MODE_STEREO) | ||
120 | #define CHN_CAP_MONO (1 << CHN_MODE_MONO) | ||
121 | #define CHN_CAP_ALL (CHN_CAP_STEREO | CHN_CAP_MONO) | ||
122 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
101 | 123 | ||
102 | /* audio sources */ | 124 | /* audio sources */ |
103 | enum | 125 | enum audio_sources |
104 | { | 126 | { |
105 | AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ | 127 | AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ |
106 | AUDIO_SRC_MIC, /* monitor mic */ | 128 | AUDIO_SRC_MIC, /* monitor mic */ |
@@ -123,33 +145,57 @@ enum | |||
123 | AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 | 145 | AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 |
124 | }; | 146 | }; |
125 | 147 | ||
126 | /* channel modes */ | 148 | #ifdef HAVE_RECORDING |
127 | enum | 149 | /* parameters for audio_set_recording_options */ |
150 | struct audio_recording_options | ||
128 | { | 151 | { |
129 | CHN_MODE_MONO = 1, | 152 | int rec_source; |
130 | CHN_MODE_STEREO, | 153 | int rec_frequency; |
154 | int rec_channels; | ||
155 | int rec_prerecord_time; | ||
156 | #if CONFIG_CODEC == SWCODEC | ||
157 | int rec_source_flags; /* for rec_set_source */ | ||
158 | struct encoder_config enc_config; | ||
159 | #else | ||
160 | int rec_quality; | ||
161 | bool rec_editable; | ||
162 | #endif | ||
131 | }; | 163 | }; |
132 | void audio_set_recording_options(int frequency, int quality, | 164 | |
133 | int source, int channel_mode, | 165 | /* audio recording functions */ |
134 | bool editable, int prerecord_time); | 166 | void audio_init_recording(unsigned int buffer_offset); |
167 | void audio_close_recording(void); | ||
168 | void audio_record(const char *filename); | ||
169 | void audio_stop_recording(void); | ||
170 | void audio_pause_recording(void); | ||
171 | void audio_resume_recording(void); | ||
172 | void audio_new_file(const char *filename); | ||
173 | void audio_set_recording_options(struct audio_recording_options *options); | ||
135 | void audio_set_recording_gain(int left, int right, int type); | 174 | void audio_set_recording_gain(int left, int right, int type); |
136 | unsigned long audio_recorded_time(void); | 175 | unsigned long audio_recorded_time(void); |
137 | unsigned long audio_num_recorded_bytes(void); | 176 | unsigned long audio_num_recorded_bytes(void); |
138 | #if 0 | 177 | |
139 | #ifdef HAVE_SPDIF_POWER | ||
140 | void audio_set_spdif_power_setting(bool on); | ||
141 | #endif | ||
142 | #endif | ||
143 | unsigned long audio_get_spdif_sample_rate(void); | ||
144 | unsigned long audio_prev_elapsed(void); | ||
145 | #if CONFIG_CODEC == SWCODEC | 178 | #if CONFIG_CODEC == SWCODEC |
146 | /* audio encoder functions (defined in playback.c) */ | 179 | /* SWCODEC recoring functions */ |
147 | int audio_get_encoder_id(void); | 180 | /* playback.c */ |
148 | void audio_load_encoder(int enc_id); | 181 | bool audio_load_encoder(int afmt); |
149 | void audio_remove_encoder(void); | 182 | void audio_remove_encoder(void); |
183 | unsigned char *audio_get_recording_buffer(size_t *buffer_size); | ||
150 | #endif /* CONFIG_CODEC == SWCODEC */ | 184 | #endif /* CONFIG_CODEC == SWCODEC */ |
185 | #endif /* HAVE_RECORDING */ | ||
151 | 186 | ||
187 | #ifdef HAVE_SPDIF_IN | ||
188 | #ifdef HAVE_SPDIF_POWER | ||
189 | void audio_set_spdif_power_setting(bool on); | ||
190 | bool audio_get_spdif_power_setting(void); | ||
191 | #endif | ||
192 | /* returns index into rec_master_sampr_list */ | ||
193 | int audio_get_spdif_sample_rate(void); | ||
194 | /* > 0: monitor EBUin, 0: Monitor IISrecv, <0: reset only */ | ||
195 | void audio_spdif_set_monitor(int monitor_spdif); | ||
196 | #endif /* HAVE_SPDIF_IN */ | ||
152 | 197 | ||
198 | unsigned long audio_prev_elapsed(void); | ||
153 | 199 | ||
154 | 200 | ||
155 | /***********************************************************************/ | 201 | /***********************************************************************/ |
diff --git a/firmware/export/config-h100.h b/firmware/export/config-h100.h index 6f74078e1e..285ab88930 100644 --- a/firmware/export/config-h100.h +++ b/firmware/export/config-h100.h | |||
@@ -84,6 +84,12 @@ | |||
84 | /* define this if you have recording possibility */ | 84 | /* define this if you have recording possibility */ |
85 | #define HAVE_RECORDING 1 | 85 | #define HAVE_RECORDING 1 |
86 | 86 | ||
87 | /* define hardware samples rate caps mask */ | ||
88 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
89 | |||
90 | /* define the bitmask of recording sample rates */ | ||
91 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
92 | |||
87 | #define HAVE_AGC | 93 | #define HAVE_AGC |
88 | 94 | ||
89 | #ifndef SIMULATOR | 95 | #ifndef SIMULATOR |
diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index 1476102100..b22ff0eb22 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h | |||
@@ -77,6 +77,12 @@ | |||
77 | /* define this if you have recording possibility */ | 77 | /* define this if you have recording possibility */ |
78 | #define HAVE_RECORDING 1 | 78 | #define HAVE_RECORDING 1 |
79 | 79 | ||
80 | /* define hardware samples rate caps mask */ | ||
81 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
82 | |||
83 | /* define the bitmask of recording sample rates */ | ||
84 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
85 | |||
80 | #define HAVE_AGC | 86 | #define HAVE_AGC |
81 | 87 | ||
82 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ | 88 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ |
diff --git a/firmware/export/config-h300.h b/firmware/export/config-h300.h index 31f0f6729f..748635dcb4 100644 --- a/firmware/export/config-h300.h +++ b/firmware/export/config-h300.h | |||
@@ -72,6 +72,12 @@ | |||
72 | /* define this if you have recording possibility */ | 72 | /* define this if you have recording possibility */ |
73 | #define HAVE_RECORDING 1 | 73 | #define HAVE_RECORDING 1 |
74 | 74 | ||
75 | /* define hardware samples rate caps mask */ | ||
76 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
77 | |||
78 | /* define the bitmask of recording sample rates */ | ||
79 | #define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
80 | |||
75 | #define HAVE_AGC | 81 | #define HAVE_AGC |
76 | 82 | ||
77 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ | 83 | #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ |
@@ -157,4 +163,3 @@ | |||
157 | 163 | ||
158 | /* Define this for FM radio input available */ | 164 | /* Define this for FM radio input available */ |
159 | #define HAVE_FMRADIO_IN | 165 | #define HAVE_FMRADIO_IN |
160 | |||
diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index 80b010a6b0..d4c904ed23 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h | |||
@@ -9,6 +9,12 @@ | |||
9 | /* define this if you have recording possibility */ | 9 | /* define this if you have recording possibility */ |
10 | #define HAVE_RECORDING 1 | 10 | #define HAVE_RECORDING 1 |
11 | 11 | ||
12 | /* define the bitmask of hardware sample rates */ | ||
13 | #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
14 | |||
15 | /* define the bitmask of recording sample rates */ | ||
16 | #define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) | ||
17 | |||
12 | /* define this if you have a bitmap LCD display */ | 18 | /* define this if you have a bitmap LCD display */ |
13 | #define HAVE_LCD_BITMAP 1 | 19 | #define HAVE_LCD_BITMAP 1 |
14 | 20 | ||
diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 1d07affbfa..dd099e0204 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h | |||
@@ -24,13 +24,19 @@ | |||
24 | #include "file.h" | 24 | #include "file.h" |
25 | 25 | ||
26 | /* Audio file types. */ | 26 | /* Audio file types. */ |
27 | enum { | 27 | enum |
28 | { | ||
28 | AFMT_UNKNOWN = 0, /* Unknown file format */ | 29 | AFMT_UNKNOWN = 0, /* Unknown file format */ |
29 | 30 | ||
31 | /* start formats */ | ||
32 | |||
30 | AFMT_MPA_L1, /* MPEG Audio layer 1 */ | 33 | AFMT_MPA_L1, /* MPEG Audio layer 1 */ |
31 | AFMT_MPA_L2, /* MPEG Audio layer 2 */ | 34 | AFMT_MPA_L2, /* MPEG Audio layer 2 */ |
32 | AFMT_MPA_L3, /* MPEG Audio layer 3 */ | 35 | AFMT_MPA_L3, /* MPEG Audio layer 3 */ |
33 | 36 | ||
37 | AFMT_AIFF, /* Audio Interchange File Format */ | ||
38 | |||
39 | #if CONFIG_CODEC == SWCODEC | ||
34 | AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ | 40 | AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ |
35 | AFMT_OGG_VORBIS, /* Ogg Vorbis */ | 41 | AFMT_OGG_VORBIS, /* Ogg Vorbis */ |
36 | AFMT_FLAC, /* FLAC */ | 42 | AFMT_FLAC, /* FLAC */ |
@@ -40,54 +46,91 @@ enum { | |||
40 | AFMT_ALAC, /* Apple Lossless Audio Codec */ | 46 | AFMT_ALAC, /* Apple Lossless Audio Codec */ |
41 | AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ | 47 | AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ |
42 | AFMT_SHN, /* Shorten */ | 48 | AFMT_SHN, /* Shorten */ |
43 | AFMT_AIFF, /* Audio Interchange File Format */ | ||
44 | AFMT_SID, /* SID File Format */ | 49 | AFMT_SID, /* SID File Format */ |
45 | AFMT_ADX, /* ADX */ | 50 | AFMT_ADX, /* ADX File Format */ |
51 | #endif | ||
46 | 52 | ||
47 | /* New formats must be added to the end of this list */ | 53 | /* add new formats at any index above this line to have a sensible order - |
54 | specified array index inits are used */ | ||
55 | /* format arrays defined in id3.c */ | ||
48 | 56 | ||
49 | AFMT_NUM_CODECS, | 57 | AFMT_NUM_CODECS, |
50 | 58 | ||
51 | #if CONFIG_CODEC == SWCODEC | 59 | #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) |
52 | /* masks to decompose parts */ | 60 | /* masks to decompose parts */ |
53 | CODEC_AFMT_MASK = 0x0fff, | 61 | CODEC_AFMT_MASK = 0x0fff, |
54 | CODEC_TYPE_MASK = 0x7000, | 62 | CODEC_TYPE_MASK = 0x7000, |
55 | 63 | ||
56 | /* switch for specifying codec type when requesting a filename */ | 64 | /* switch for specifying codec type when requesting a filename */ |
57 | CODEC_TYPE_DECODER = (0 << 12), /* default */ | 65 | CODEC_TYPE_DECODER = (0 << 12), /* default */ |
58 | CODEC_TYPE_ENCODER = (1 << 12) | 66 | CODEC_TYPE_ENCODER = (1 << 12), |
59 | #endif | 67 | #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ |
60 | }; | 68 | }; |
61 | 69 | ||
62 | #if CONFIG_CODEC == SWCODEC | 70 | #if CONFIG_CODEC == SWCODEC |
63 | #define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ | 71 | #define CODEC_EXTENSION "codec" |
64 | { label, codec_fname, codec_enc_fname, enc_ext } | 72 | |
65 | #else | 73 | #ifdef HAVE_RECORDING |
66 | #define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ | 74 | #define ENCODER_SUFFIX "_enc" |
67 | { label } | 75 | enum rec_format_indexes |
68 | #endif | 76 | { |
77 | __REC_FORMAT_START_INDEX = -1, | ||
78 | |||
79 | /* start formats */ | ||
80 | |||
81 | REC_FORMAT_PCM_WAV, | ||
82 | REC_FORMAT_WAVPACK, | ||
83 | REC_FORMAT_MPA_L3, | ||
84 | |||
85 | /* add new formats at any index above this line to have a sensible order - | ||
86 | specified array index inits are used | ||
87 | REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range | ||
88 | REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes | ||
89 | */ | ||
90 | |||
91 | REC_NUM_FORMATS, | ||
92 | |||
93 | REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV, | ||
94 | REC_FORMAT_CFG_NUM_BITS = 2 | ||
95 | }; | ||
96 | |||
97 | #define REC_FORMAT_CFG_VAL_LIST "wave,wvpk,mpa3" | ||
98 | |||
99 | /* get REC_FORMAT_* corresponding AFMT_* */ | ||
100 | extern const int rec_format_afmt[REC_NUM_FORMATS]; | ||
101 | /* get AFMT_* corresponding REC_FORMAT_* */ | ||
102 | extern const int afmt_rec_format[AFMT_NUM_CODECS]; | ||
103 | |||
104 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
105 | { label, root_fname, enc_root_fname, ext_list } | ||
106 | #else /* !HAVE_RECORDING */ | ||
107 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
108 | { label, root_fname, ext_list } | ||
109 | #endif /* HAVE_RECORDING */ | ||
110 | #else /* !SWCODEC */ | ||
111 | |||
112 | #define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ | ||
113 | { label, ext_list } | ||
114 | #endif /* CONFIG_CODEC == SWCODEC */ | ||
69 | 115 | ||
70 | /* record describing the audio format */ | 116 | /* record describing the audio format */ |
71 | struct afmt_entry | 117 | struct afmt_entry |
72 | { | 118 | { |
73 | #if CONFIG_CODEC == SWCODEC | ||
74 | char label[8]; /* format label */ | 119 | char label[8]; /* format label */ |
75 | char *codec_fn; /* filename of decoder codec */ | 120 | #if CONFIG_CODEC == SWCODEC |
76 | char *codec_enc_fn; /* filename of encoder codec */ | 121 | char *codec_root_fn; /* root codec filename (sans _enc and .codec) */ |
77 | char *ext; /* default extension for file (enc only for now) */ | 122 | #ifdef HAVE_RECORDING |
78 | #else | 123 | char *codec_enc_root_fn; /* filename of encoder codec */ |
79 | char label[4]; | 124 | #endif |
80 | #endif | 125 | #endif |
126 | char *ext_list; /* double NULL terminated extension | ||
127 | list for type with the first as | ||
128 | the default for recording */ | ||
81 | }; | 129 | }; |
82 | 130 | ||
83 | /* database of labels and codecs. add formats per above enum */ | 131 | /* database of labels and codecs. add formats per above enum */ |
84 | extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; | 132 | extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; |
85 | 133 | ||
86 | #if CONFIG_CODEC == SWCODEC | ||
87 | /* recording quality to AFMT_* */ | ||
88 | extern const int rec_quality_info_afmt[9]; | ||
89 | #endif | ||
90 | |||
91 | struct mp3entry { | 134 | struct mp3entry { |
92 | char path[MAX_PATH]; | 135 | char path[MAX_PATH]; |
93 | char* title; | 136 | char* title; |
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index a4cd93969b..9c3e96ba63 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h | |||
@@ -19,11 +19,23 @@ | |||
19 | #ifndef PCM_PLAYBACK_H | 19 | #ifndef PCM_PLAYBACK_H |
20 | #define PCM_PLAYBACK_H | 20 | #define PCM_PLAYBACK_H |
21 | 21 | ||
22 | #include <sys/types.h> | ||
23 | |||
24 | /* Typedef for registered callback (play and record) */ | ||
25 | typedef void (*pcm_more_callback_type)(unsigned char **start, | ||
26 | size_t *size); | ||
27 | |||
22 | void pcm_init(void); | 28 | void pcm_init(void); |
29 | |||
30 | /* set the pcm frequency - use values in hw_sampr_list | ||
31 | * use -1 for the default frequency | ||
32 | */ | ||
23 | void pcm_set_frequency(unsigned int frequency); | 33 | void pcm_set_frequency(unsigned int frequency); |
34 | /* apply settings to hardware immediately */ | ||
35 | void pcm_apply_settings(bool reset); | ||
24 | 36 | ||
25 | /* This is for playing "raw" PCM data */ | 37 | /* This is for playing "raw" PCM data */ |
26 | void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), | 38 | void pcm_play_data(pcm_more_callback_type get_more, |
27 | unsigned char* start, size_t size); | 39 | unsigned char* start, size_t size); |
28 | 40 | ||
29 | void pcm_calculate_peaks(int *left, int *right); | 41 | void pcm_calculate_peaks(int *left, int *right); |
@@ -35,4 +47,4 @@ void pcm_play_pause(bool play); | |||
35 | bool pcm_is_paused(void); | 47 | bool pcm_is_paused(void); |
36 | bool pcm_is_playing(void); | 48 | bool pcm_is_playing(void); |
37 | 49 | ||
38 | #endif | 50 | #endif /* PCM_PLAYBACK_H */ |
diff --git a/firmware/export/pcm_record.h b/firmware/export/pcm_record.h index b217335340..c1187a4c6c 100644 --- a/firmware/export/pcm_record.h +++ b/firmware/export/pcm_record.h | |||
@@ -20,24 +20,44 @@ | |||
20 | #ifndef PCM_RECORD_H | 20 | #ifndef PCM_RECORD_H |
21 | #define PCM_RECORD_H | 21 | #define PCM_RECORD_H |
22 | 22 | ||
23 | void enc_set_parameters(int chunk_size, int num_chunks, | 23 | #define DMA_REC_ERROR_DMA ((size_t)-1) |
24 | int samp_per_chunk, char *head_ptr, int head_size, | 24 | #ifdef HAVE_SPDIF_IN |
25 | int enc_id); | 25 | #define DMA_REC_ERROR_SPDIF ((size_t)-2) |
26 | void enc_get_inputs(int *buffer_size, int *channels, int *quality); | 26 | #endif |
27 | unsigned int* enc_alloc_chunk(void); | 27 | /* Use AUDIO_SRC_* enumeration values */ |
28 | void enc_free_chunk(void); | 28 | void pcm_set_monitor(int monitor); |
29 | int enc_wavbuf_near_empty(void); | 29 | void pcm_set_rec_source(int source); |
30 | char* enc_get_wav_data(int size); | 30 | |
31 | extern void (*enc_set_header_callback)(void *head_buffer, int head_size, | 31 | /** |
32 | int num_pcm_samples, bool is_file_header); | 32 | * RAW pcm data recording |
33 | * These calls are nescessary only when using the raw pcm apis directly. | ||
34 | */ | ||
35 | |||
36 | /* Initialize pcm recording interface */ | ||
37 | void pcm_init_recording(void); | ||
38 | /* Uninitialze pcm recording interface */ | ||
39 | void pcm_close_recording(void); | ||
40 | |||
41 | /* Start recording "raw" PCM data */ | ||
42 | void pcm_record_data(pcm_more_callback_type more_ready, | ||
43 | unsigned char *start, size_t size); | ||
33 | 44 | ||
45 | /* Stop tranferring data into supplied buffer */ | ||
46 | void pcm_stop_recording(void); | ||
47 | |||
48 | void pcm_calculate_rec_peaks(int *left, int *right); | ||
49 | |||
50 | /** General functions for high level codec recording **/ | ||
51 | void pcm_rec_error_clear(void); | ||
34 | unsigned long pcm_rec_status(void); | 52 | unsigned long pcm_rec_status(void); |
35 | void pcm_rec_init(void); | 53 | void pcm_rec_init(void); |
36 | void pcm_rec_mux(int source); | 54 | void pcm_rec_mux(int source); |
37 | int pcm_rec_current_bitrate(void); | 55 | int pcm_rec_current_bitrate(void); |
56 | int pcm_rec_encoder_afmt(void); /* AFMT_* value, AFMT_UNKNOWN if none */ | ||
57 | int pcm_rec_rec_format(void); /* Format index or -1 otherwise */ | ||
58 | unsigned long pcm_rec_sample_rate(void); | ||
38 | int pcm_get_num_unprocessed(void); | 59 | int pcm_get_num_unprocessed(void); |
39 | void pcm_rec_get_peaks(int *left, int *right); | ||
40 | 60 | ||
41 | /* audio.h contains audio recording functions */ | 61 | /* audio.h contains audio_* recording functions */ |
42 | 62 | ||
43 | #endif | 63 | #endif /* PCM_RECORD_H */ |
diff --git a/firmware/export/system.h b/firmware/export/system.h index 4a33d80466..9b90a6e80c 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h | |||
@@ -21,7 +21,6 @@ | |||
21 | #define __SYSTEM_H__ | 21 | #define __SYSTEM_H__ |
22 | 22 | ||
23 | #include "cpu.h" | 23 | #include "cpu.h" |
24 | #include "config.h" | ||
25 | #include "stdbool.h" | 24 | #include "stdbool.h" |
26 | 25 | ||
27 | extern void system_reboot (void); | 26 | extern void system_reboot (void); |
@@ -111,6 +110,23 @@ const char *get_cpu_boost_tracker(void); | |||
111 | #define MAX(a, b) (((a)>(b))?(a):(b)) | 110 | #define MAX(a, b) (((a)>(b))?(a):(b)) |
112 | #endif | 111 | #endif |
113 | 112 | ||
113 | /* return number of elements in array a */ | ||
114 | #define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0])) | ||
115 | |||
116 | /* return p incremented by specified number of bytes */ | ||
117 | #define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count))) | ||
118 | |||
119 | #define P2_M1(p2) ((1 << (p2))-1) | ||
120 | |||
121 | /* align up or down to nearest 2^p2 */ | ||
122 | #define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2)) | ||
123 | #define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2) | ||
124 | |||
125 | /* align up or down to nearest integer multiple of a */ | ||
126 | #define ALIGN_DOWN(n, a) ((n)/(a)*(a)) | ||
127 | #define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a) | ||
128 | |||
129 | /* live endianness conversion */ | ||
114 | #ifdef ROCKBOX_LITTLE_ENDIAN | 130 | #ifdef ROCKBOX_LITTLE_ENDIAN |
115 | #define letoh16(x) (x) | 131 | #define letoh16(x) (x) |
116 | #define letoh32(x) (x) | 132 | #define letoh32(x) (x) |
@@ -120,6 +136,8 @@ const char *get_cpu_boost_tracker(void); | |||
120 | #define betoh32(x) swap32(x) | 136 | #define betoh32(x) swap32(x) |
121 | #define htobe16(x) swap16(x) | 137 | #define htobe16(x) swap16(x) |
122 | #define htobe32(x) swap32(x) | 138 | #define htobe32(x) swap32(x) |
139 | #define swap_odd_even_be32(x) (x) | ||
140 | #define swap_odd_even_le32(x) swap_odd_even32(x) | ||
123 | #else | 141 | #else |
124 | #define letoh16(x) swap16(x) | 142 | #define letoh16(x) swap16(x) |
125 | #define letoh32(x) swap32(x) | 143 | #define letoh32(x) swap32(x) |
@@ -129,6 +147,37 @@ const char *get_cpu_boost_tracker(void); | |||
129 | #define betoh32(x) (x) | 147 | #define betoh32(x) (x) |
130 | #define htobe16(x) (x) | 148 | #define htobe16(x) (x) |
131 | #define htobe32(x) (x) | 149 | #define htobe32(x) (x) |
150 | #define swap_odd_even_be32(x) swap_odd_even32(x) | ||
151 | #define swap_odd_even_le32(x) (x) | ||
152 | #endif | ||
153 | |||
154 | /* static endianness conversion */ | ||
155 | #define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \ | ||
156 | ((unsigned short)(x) << 8))) | ||
157 | |||
158 | #define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \ | ||
159 | (((unsigned long)(x) & 0xff0000ul) >> 8) | \ | ||
160 | (((unsigned long)(x) & 0xff00ul) << 8) | \ | ||
161 | ((unsigned long)(x) << 24))) | ||
162 | |||
163 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
164 | #define LE_TO_H16(x) (x) | ||
165 | #define LE_TO_H32(x) (x) | ||
166 | #define H_TO_LE16(x) (x) | ||
167 | #define H_TO_LE32(x) (x) | ||
168 | #define BE_TO_H16(x) SWAP_16(x) | ||
169 | #define BE_TO_H32(x) SWAP_32(x) | ||
170 | #define H_TO_BE16(x) SWAP_16(x) | ||
171 | #define H_TO_BE32(x) SWAP_32(x) | ||
172 | #else | ||
173 | #define LE_TO_H16(x) SWAP_16(x) | ||
174 | #define LE_TO_H32(x) SWAP_32(x) | ||
175 | #define H_TO_LE16(x) SWAP_16(x) | ||
176 | #define H_TO_LE32(x) SWAP_32(x) | ||
177 | #define BE_TO_H16(x) (x) | ||
178 | #define BE_TO_H32(x) (x) | ||
179 | #define H_TO_BE16(x) (x) | ||
180 | #define H_TO_BE32(x) (x) | ||
132 | #endif | 181 | #endif |
133 | 182 | ||
134 | 183 | ||
@@ -181,6 +230,7 @@ enum { | |||
181 | : /* %0 */ I_CONSTRAINT((char)(mask)), \ | 230 | : /* %0 */ I_CONSTRAINT((char)(mask)), \ |
182 | /* %1 */ "z"(address-GBR)) | 231 | /* %1 */ "z"(address-GBR)) |
183 | 232 | ||
233 | |||
184 | #endif /* CONFIG_CPU == SH7034 */ | 234 | #endif /* CONFIG_CPU == SH7034 */ |
185 | 235 | ||
186 | #ifndef SIMULATOR | 236 | #ifndef SIMULATOR |
@@ -388,7 +438,20 @@ static inline unsigned long swap32(unsigned long value) | |||
388 | #define invalidate_icache() | 438 | #define invalidate_icache() |
389 | 439 | ||
390 | #endif | 440 | #endif |
391 | #else | 441 | |
442 | #ifndef CPU_COLDFIRE | ||
443 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
444 | { | ||
445 | /* | ||
446 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
447 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
448 | */ | ||
449 | unsigned long t = value & 0xff00ff00; | ||
450 | return (t >> 8) | ((t ^ value) << 8); | ||
451 | } | ||
452 | #endif | ||
453 | |||
454 | #else /* SIMULATOR */ | ||
392 | 455 | ||
393 | static inline unsigned short swap16(unsigned short value) | 456 | static inline unsigned short swap16(unsigned short value) |
394 | /* | 457 | /* |
@@ -412,8 +475,18 @@ static inline unsigned long swap32(unsigned long value) | |||
412 | return (lo << 16) | hi; | 475 | return (lo << 16) | hi; |
413 | } | 476 | } |
414 | 477 | ||
478 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
479 | { | ||
480 | /* | ||
481 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
482 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
483 | */ | ||
484 | unsigned long t = value & 0xff00ff00; | ||
485 | return (t >> 8) | ((t ^ value) << 8); | ||
486 | } | ||
487 | |||
415 | #define invalidate_icache() | 488 | #define invalidate_icache() |
416 | 489 | ||
417 | #endif | 490 | #endif /* !SIMULATOR */ |
418 | 491 | ||
419 | #endif | 492 | #endif /* __SYSTEM_H__ */ |
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index 17e6e3aa88..72c692ec3b 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -142,7 +142,10 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list); | |||
142 | void sleep_thread(int ticks); | 142 | void sleep_thread(int ticks); |
143 | void block_thread(struct thread_entry **thread, int timeout); | 143 | void block_thread(struct thread_entry **thread, int timeout); |
144 | void wakeup_thread(struct thread_entry **thread); | 144 | void wakeup_thread(struct thread_entry **thread); |
145 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
145 | int thread_set_priority(struct thread_entry *thread, int priority); | 146 | int thread_set_priority(struct thread_entry *thread, int priority); |
147 | int thread_get_priority(struct thread_entry *thread); | ||
148 | #endif | ||
146 | void init_threads(void); | 149 | void init_threads(void); |
147 | int thread_stack_usage(const struct thread_entry *thread); | 150 | int thread_stack_usage(const struct thread_entry *thread); |
148 | int thread_get_status(const struct thread_entry *thread); | 151 | int thread_get_status(const struct thread_entry *thread); |
diff --git a/firmware/export/tlv320.h b/firmware/export/tlv320.h index dfcbec4373..023ec9d874 100644 --- a/firmware/export/tlv320.h +++ b/firmware/export/tlv320.h | |||
@@ -24,6 +24,16 @@ | |||
24 | 24 | ||
25 | extern void tlv320_init(void); | 25 | extern void tlv320_init(void); |
26 | extern void tlv320_reset(void); | 26 | extern void tlv320_reset(void); |
27 | /** | ||
28 | * Sets internal sample rate for DAC and ADC relative to MCLK | ||
29 | * Selection for frequency: | ||
30 | * Fs: tlv: with: | ||
31 | * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 | ||
32 | * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 | ||
33 | * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) | ||
34 | * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 | ||
35 | */ | ||
36 | extern void tlv320_set_frequency(unsigned fsel); | ||
27 | extern void tlv320_enable_output(bool enable); | 37 | extern void tlv320_enable_output(bool enable); |
28 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); | 38 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); |
29 | extern void tlv320_set_recvol(int left, int right, int type); | 39 | extern void tlv320_set_recvol(int left, int right, int type); |
diff --git a/firmware/export/uda1380.h b/firmware/export/uda1380.h index 9c761c6a7d..639ca8aa5c 100644 --- a/firmware/export/uda1380.h +++ b/firmware/export/uda1380.h | |||
@@ -28,8 +28,17 @@ extern void uda1380_set_bass(int value); | |||
28 | extern void uda1380_set_treble(int value); | 28 | extern void uda1380_set_treble(int value); |
29 | extern int uda1380_mute(int mute); | 29 | extern int uda1380_mute(int mute); |
30 | extern void uda1380_close(void); | 30 | extern void uda1380_close(void); |
31 | extern void uda1380_set_nsorder(int order); | 31 | /** |
32 | 32 | * Sets frequency settings for DAC and ADC relative to MCLK | |
33 | * | ||
34 | * Selection for frequency ranges: | ||
35 | * Fs: range: with: | ||
36 | * 11025: 0 = 6.25 to 12.5 SCLK, LRCK: Audio Clk / 16 | ||
37 | * 22050: 1 = 12.5 to 25 SCLK, LRCK: Audio Clk / 8 | ||
38 | * 44100: 2 = 25 to 50 SCLK, LRCK: Audio Clk / 4 (default) | ||
39 | * 88200: 3 = 50 to 100 SCLK, LRCK: Audio Clk / 2 | ||
40 | */ | ||
41 | extern void uda1380_set_frequency(unsigned fsel); | ||
33 | extern void uda1380_enable_recording(bool source_mic); | 42 | extern void uda1380_enable_recording(bool source_mic); |
34 | extern void uda1380_disable_recording(void); | 43 | extern void uda1380_disable_recording(void); |
35 | extern void uda1380_set_recvol(int left, int right, int type); | 44 | extern void uda1380_set_recvol(int left, int right, int type); |
diff --git a/firmware/id3.c b/firmware/id3.c index 92f60a2095..7d03c75331 100644 --- a/firmware/id3.c +++ b/firmware/id3.c | |||
@@ -44,6 +44,89 @@ | |||
44 | #include "replaygain.h" | 44 | #include "replaygain.h" |
45 | #include "rbunicode.h" | 45 | #include "rbunicode.h" |
46 | 46 | ||
47 | /** Database of audio formats **/ | ||
48 | const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | ||
49 | { | ||
50 | /* Unknown file format */ | ||
51 | [AFMT_UNKNOWN] = | ||
52 | AFMT_ENTRY("???", NULL, NULL, NULL ), | ||
53 | |||
54 | /* MPEG Audio layer 1 */ | ||
55 | [AFMT_MPA_L1] = | ||
56 | AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), | ||
57 | /* MPEG Audio layer 2 */ | ||
58 | [AFMT_MPA_L2] = | ||
59 | AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), | ||
60 | /* MPEG Audio layer 3 */ | ||
61 | [AFMT_MPA_L3] = | ||
62 | AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), | ||
63 | |||
64 | /* Audio Interchange File Format */ | ||
65 | [AFMT_AIFF] = | ||
66 | AFMT_ENTRY("AIFF", "aiff", NULL, "aiff\0aif\0"), | ||
67 | |||
68 | #if CONFIG_CODEC == SWCODEC | ||
69 | /* Uncompressed PCM in a WAV file */ | ||
70 | [AFMT_PCM_WAV] = | ||
71 | AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), | ||
72 | /* Ogg Vorbis */ | ||
73 | [AFMT_OGG_VORBIS] = | ||
74 | AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), | ||
75 | /* FLAC */ | ||
76 | [AFMT_FLAC] = | ||
77 | AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), | ||
78 | /* Musepack */ | ||
79 | [AFMT_MPC] = | ||
80 | AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), | ||
81 | /* A/52 (aka AC3) audio */ | ||
82 | [AFMT_A52] = | ||
83 | AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), | ||
84 | /* WavPack */ | ||
85 | [AFMT_WAVPACK] = | ||
86 | AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), | ||
87 | /* Apple Lossless Audio Codec */ | ||
88 | [AFMT_ALAC] = | ||
89 | AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0" ), | ||
90 | /* Advanced Audio Coding in M4A container */ | ||
91 | [AFMT_AAC] = | ||
92 | AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), | ||
93 | /* Shorten */ | ||
94 | [AFMT_SHN] = | ||
95 | AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), | ||
96 | /* SID File Format */ | ||
97 | [AFMT_SID] = | ||
98 | AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), | ||
99 | /* ADX File Format */ | ||
100 | [AFMT_ADX] = | ||
101 | AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), | ||
102 | #endif | ||
103 | }; | ||
104 | |||
105 | #if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) | ||
106 | /* get REC_FORMAT_* corresponding AFMT_* */ | ||
107 | const int rec_format_afmt[REC_NUM_FORMATS] = | ||
108 | { | ||
109 | /* give AFMT_UNKNOWN by default */ | ||
110 | [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, | ||
111 | /* add new entries below this line */ | ||
112 | [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, | ||
113 | [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, | ||
114 | [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, | ||
115 | }; | ||
116 | |||
117 | /* get AFMT_* corresponding REC_FORMAT_* */ | ||
118 | const int afmt_rec_format[AFMT_NUM_CODECS] = | ||
119 | { | ||
120 | /* give -1 by default */ | ||
121 | [0 ... AFMT_NUM_CODECS-1] = -1, | ||
122 | /* add new entries below this line */ | ||
123 | [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, | ||
124 | [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, | ||
125 | [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, | ||
126 | }; | ||
127 | #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ | ||
128 | /****/ | ||
129 | |||
47 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ | 130 | #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ |
48 | ((long)(b1 & 0x7F) << (2*7)) | \ | 131 | ((long)(b1 & 0x7F) << (2*7)) | \ |
49 | ((long)(b2 & 0x7F) << (1*7)) | \ | 132 | ((long)(b2 & 0x7F) << (1*7)) | \ |
@@ -85,61 +168,6 @@ static const char* const genres[] = { | |||
85 | "Synthpop" | 168 | "Synthpop" |
86 | }; | 169 | }; |
87 | 170 | ||
88 | /* database of audio formats */ | ||
89 | const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | ||
90 | { | ||
91 | /* Unknown file format */ | ||
92 | AFMT_ENTRY("???", NULL, NULL, NULL ), | ||
93 | /* MPEG Audio layer 1 */ | ||
94 | AFMT_ENTRY("MP1", "mpa.codec", NULL, NULL ), | ||
95 | /* MPEG Audio layer 2 */ | ||
96 | AFMT_ENTRY("MP2", "mpa.codec", NULL, NULL ), | ||
97 | /* MPEG Audio layer 3 */ | ||
98 | AFMT_ENTRY("MP3", "mpa.codec", "mp3_enc.codec", ".mp3"), | ||
99 | #if CONFIG_CODEC == SWCODEC | ||
100 | /* Uncompressed PCM in a WAV file */ | ||
101 | AFMT_ENTRY("WAV", "wav.codec", "wav_enc.codec", ".wav"), | ||
102 | /* Ogg Vorbis */ | ||
103 | AFMT_ENTRY("Ogg", "vorbis.codec", NULL, NULL ), | ||
104 | /* FLAC */ | ||
105 | AFMT_ENTRY("FLAC", "flac.codec", NULL, NULL ), | ||
106 | /* Musepack */ | ||
107 | AFMT_ENTRY("MPC", "mpc.codec", NULL, NULL ), | ||
108 | /* A/52 (aka AC3) audio */ | ||
109 | AFMT_ENTRY("AC3", "a52.codec", NULL, NULL ), | ||
110 | /* WavPack */ | ||
111 | AFMT_ENTRY("WV", "wavpack.codec", "wavpack_enc.codec", ".wv" ), | ||
112 | /* Apple Lossless Audio Codec */ | ||
113 | AFMT_ENTRY("ALAC", "alac.codec", NULL, NULL ), | ||
114 | /* Advanced Audio Coding in M4A container */ | ||
115 | AFMT_ENTRY("AAC", "aac.codec", NULL, NULL ), | ||
116 | /* Shorten */ | ||
117 | AFMT_ENTRY("SHN", "shorten.codec", NULL, NULL ), | ||
118 | /* Audio Interchange File Format */ | ||
119 | AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ), | ||
120 | /* SID File Format */ | ||
121 | AFMT_ENTRY("SID", "sid.codec", NULL, NULL ), | ||
122 | /* ADX File Format */ | ||
123 | AFMT_ENTRY("ADX", "adx.codec", NULL, NULL ), | ||
124 | #endif | ||
125 | }; | ||
126 | |||
127 | #if CONFIG_CODEC == SWCODEC | ||
128 | /* recording quality to AFMT_* */ | ||
129 | const int rec_quality_info_afmt[9] = | ||
130 | { | ||
131 | AFMT_MPA_L3, /* MPEG L3 64 kBit/s */ | ||
132 | AFMT_MPA_L3, /* MPEG L3 96 kBit/s */ | ||
133 | AFMT_MPA_L3, /* MPEG L3 128 kBit/s */ | ||
134 | AFMT_MPA_L3, /* MPEG L3 160 kBit/s */ | ||
135 | AFMT_MPA_L3, /* MPEG L3 192 kBit/s */ | ||
136 | AFMT_MPA_L3, /* MPEG L3 224 kBit/s */ | ||
137 | AFMT_MPA_L3, /* MPEG L3 320 kBit/s */ | ||
138 | AFMT_WAVPACK, /* WavPack 909 kBit/s */ | ||
139 | AFMT_PCM_WAV, /* PCM Wav 1411 kBit/s */ | ||
140 | }; | ||
141 | #endif /* SWCODEC */ | ||
142 | |||
143 | char* id3_get_genre(const struct mp3entry* id3) | 171 | char* id3_get_genre(const struct mp3entry* id3) |
144 | { | 172 | { |
145 | if( id3->genre_string ) | 173 | if( id3->genre_string ) |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index ce1d995461..bb438a3ab4 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -2453,34 +2453,32 @@ static void stop_recording(void) | |||
2453 | resume_recording(); | 2453 | resume_recording(); |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | void audio_set_recording_options(int frequency, int quality, | 2456 | void audio_set_recording_options(struct audio_recording_options *options) |
2457 | int source, int channel_mode, | ||
2458 | bool editable, int prerecord_time) | ||
2459 | { | 2457 | { |
2460 | bool is_mpeg1; | 2458 | bool is_mpeg1; |
2461 | 2459 | ||
2462 | is_mpeg1 = (frequency < 3)?true:false; | 2460 | is_mpeg1 = (options->rec_frequency < 3)?true:false; |
2463 | 2461 | ||
2464 | rec_version_index = is_mpeg1?3:2; | 2462 | rec_version_index = is_mpeg1?3:2; |
2465 | rec_frequency_index = frequency % 3; | 2463 | rec_frequency_index = options->rec_frequency % 3; |
2466 | 2464 | ||
2467 | shadow_encoder_control = (quality << 17) | | 2465 | shadow_encoder_control = (options->rec_quality << 17) | |
2468 | (rec_frequency_index << 10) | | 2466 | (rec_frequency_index << 10) | |
2469 | ((is_mpeg1?1:0) << 9) | | 2467 | ((is_mpeg1?1:0) << 9) | |
2470 | (((channel_mode * 2 + 1) & 3) << 6) | | 2468 | (((options->rec_channels * 2 + 1) & 3) << 6) | |
2471 | (1 << 5) /* MS-stereo */ | | 2469 | (1 << 5) /* MS-stereo */ | |
2472 | (1 << 2) /* Is an original */; | 2470 | (1 << 2) /* Is an original */; |
2473 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); | 2471 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); |
2474 | 2472 | ||
2475 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); | 2473 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); |
2476 | 2474 | ||
2477 | shadow_soft_mute = editable?4:0; | 2475 | shadow_soft_mute = options->rec_editable?4:0; |
2478 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); | 2476 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); |
2479 | 2477 | ||
2480 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); | 2478 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); |
2481 | 2479 | ||
2482 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ | 2480 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ |
2483 | ((source < 2)?1:2) << 8) | /* Input select */ | 2481 | ((options->rec_source < 2)?1:2) << 8) | /* Input select */ |
2484 | (1 << 5) | /* SDO strobe invert */ | 2482 | (1 << 5) | /* SDO strobe invert */ |
2485 | ((is_mpeg1?0:1) << 3) | | 2483 | ((is_mpeg1?0:1) << 3) | |
2486 | (1 << 2) | /* Inverted SIBC clock signal */ | 2484 | (1 << 2) | /* Inverted SIBC clock signal */ |
@@ -2489,7 +2487,7 @@ void audio_set_recording_options(int frequency, int quality, | |||
2489 | 2487 | ||
2490 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | 2488 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); |
2491 | 2489 | ||
2492 | if(source == AUDIO_SRC_MIC) | 2490 | if(options->rec_source == AUDIO_SRC_MIC) |
2493 | { | 2491 | { |
2494 | /* Copy left channel to right (mono mode) */ | 2492 | /* Copy left channel to right (mono mode) */ |
2495 | mas_codec_writereg(8, 0x8000); | 2493 | mas_codec_writereg(8, 0x8000); |
@@ -2500,7 +2498,7 @@ void audio_set_recording_options(int frequency, int quality, | |||
2500 | mas_codec_writereg(8, 0); | 2498 | mas_codec_writereg(8, 0); |
2501 | } | 2499 | } |
2502 | 2500 | ||
2503 | prerecording_max_seconds = prerecord_time; | 2501 | prerecording_max_seconds = options->rec_prerecord_time; |
2504 | if(prerecording_max_seconds) | 2502 | if(prerecording_max_seconds) |
2505 | { | 2503 | { |
2506 | prerecording = true; | 2504 | prerecording = true; |
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index cd14f123d1..b7ea96f3d3 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -16,259 +16,86 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include <stdbool.h> | 19 | #include "system.h" |
20 | #include "config.h" | 20 | #include "kernel.h" |
21 | #include "debug.h" | 21 | #include "logf.h" |
22 | #include "panic.h" | 22 | #include "audio.h" |
23 | #include <kernel.h> | 23 | #if defined(HAVE_WM8975) |
24 | #include "cpu.h" | ||
25 | #include "i2c.h" | ||
26 | #if defined(HAVE_UDA1380) | ||
27 | #include "uda1380.h" | ||
28 | #elif defined(HAVE_WM8975) | ||
29 | #include "wm8975.h" | 24 | #include "wm8975.h" |
30 | #elif defined(HAVE_WM8758) | 25 | #elif defined(HAVE_WM8758) |
31 | #include "wm8758.h" | 26 | #include "wm8758.h" |
32 | #elif defined(HAVE_TLV320) | ||
33 | #include "tlv320.h" | ||
34 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) | 27 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) |
35 | #include "wm8731l.h" | 28 | #include "wm8731l.h" |
36 | #elif CONFIG_CPU == PNX0101 | 29 | #elif CONFIG_CPU == PNX0101 |
30 | #include "string.h" | ||
37 | #include "pnx0101.h" | 31 | #include "pnx0101.h" |
38 | #endif | 32 | #endif |
39 | #include "system.h" | ||
40 | #include "logf.h" | ||
41 | 33 | ||
42 | #include <stdio.h> | 34 | /** |
43 | #include <string.h> | 35 | * APIs implemented in the target-specific portion: |
44 | #include <stdarg.h> | 36 | * Public - |
45 | #include "pcm_playback.h" | 37 | * pcm_init |
46 | #include "lcd.h" | 38 | * pcm_get_bytes_waiting |
47 | #include "button.h" | 39 | * pcm_calculate_peaks |
48 | #include "file.h" | 40 | * Semi-private - |
49 | #include "buffer.h" | 41 | * pcm_play_dma_start |
50 | #include "sprintf.h" | 42 | * pcm_play_dma_stop |
51 | #include "button.h" | 43 | * pcm_play_pause_pause |
52 | #include <string.h> | 44 | * pcm_play_pause_unpause |
53 | 45 | */ | |
54 | static bool pcm_playing; | 46 | |
55 | static bool pcm_paused; | 47 | /** These items may be implemented target specifically or need to |
48 | be shared semi-privately **/ | ||
56 | 49 | ||
57 | /* the registered callback function to ask for more mp3 data */ | 50 | /* the registered callback function to ask for more mp3 data */ |
58 | static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL; | 51 | pcm_more_callback_type pcm_callback_for_more = NULL; |
52 | bool pcm_playing = false; | ||
53 | bool pcm_paused = false; | ||
54 | |||
55 | void pcm_play_dma_start(const void *addr, size_t size); | ||
56 | void pcm_play_dma_stop(void); | ||
57 | void pcm_play_pause_pause(void); | ||
58 | void pcm_play_pause_unpause(void); | ||
59 | |||
60 | /** Functions that require targeted implementation **/ | ||
61 | |||
62 | #ifndef CPU_COLDFIRE | ||
59 | 63 | ||
60 | #if (CONFIG_CPU == S3C2440) | 64 | #if (CONFIG_CPU == S3C2440) |
61 | 65 | ||
62 | /* TODO: Implement for Gigabeat | 66 | /* TODO: Implement for Gigabeat |
63 | For now, just implement some dummy functions. | 67 | For now, just implement some dummy functions. |
64 | */ | 68 | */ |
65 | |||
66 | void pcm_init(void) | 69 | void pcm_init(void) |
67 | { | 70 | { |
68 | |||
69 | } | 71 | } |
70 | 72 | ||
71 | static void dma_start(const void *addr, size_t size) | 73 | void pcm_play_dma_start(const void *addr, size_t size) |
72 | { | 74 | { |
73 | (void)addr; | 75 | (void)addr; |
74 | (void)size; | 76 | (void)size; |
75 | } | 77 | } |
76 | 78 | ||
77 | void pcm_set_frequency(unsigned int frequency) | 79 | void pcm_play_dma_stop(void) |
78 | { | ||
79 | (void)frequency; | ||
80 | } | ||
81 | |||
82 | void pcm_play_stop(void) | ||
83 | { | 80 | { |
84 | } | 81 | } |
85 | 82 | ||
86 | size_t pcm_get_bytes_waiting(void) | 83 | void pcm_play_pause_pause(void) |
87 | { | 84 | { |
88 | return 0; | ||
89 | } | 85 | } |
90 | #else | ||
91 | #ifdef CPU_COLDFIRE | ||
92 | 86 | ||
93 | #ifdef HAVE_SPDIF_OUT | 87 | void pcm_play_pause_unpause(void) |
94 | #define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2)) | ||
95 | #endif | ||
96 | #define IIS_DEFPARM(freq) ((freq << 12) | 0x300 | 4 << 2) | ||
97 | #define IIS_RESET 0x800 | ||
98 | |||
99 | #ifdef IAUDIO_X5 | ||
100 | #define SET_IIS_CONFIG(x) IIS1CONFIG = (x); | ||
101 | #else | ||
102 | #define SET_IIS_CONFIG(x) IIS2CONFIG = (x); | ||
103 | #endif | ||
104 | |||
105 | static int pcm_freq = 0x6; /* 44.1 is default */ | ||
106 | |||
107 | int peak_left = 0, peak_right = 0; | ||
108 | |||
109 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | ||
110 | static void dma_start(const void *addr, size_t size) | ||
111 | { | 88 | { |
112 | pcm_playing = true; | ||
113 | |||
114 | addr = (void *)((unsigned long)addr & ~3); /* Align data */ | ||
115 | size &= ~3; /* Size must be multiple of 4 */ | ||
116 | |||
117 | /* Reset the audio FIFO */ | ||
118 | #ifdef HAVE_SPDIF_OUT | ||
119 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
120 | #endif | ||
121 | |||
122 | /* Set up DMA transfer */ | ||
123 | SAR0 = (unsigned long)addr; /* Source address */ | ||
124 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ | ||
125 | BCR0 = size; /* Bytes to transfer */ | ||
126 | |||
127 | /* Enable the FIFO and force one write to it */ | ||
128 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); | ||
129 | /* Also send the audio to S/PDIF */ | ||
130 | #ifdef HAVE_SPDIF_OUT | ||
131 | EBU1CONFIG = EBU_DEFPARM; | ||
132 | #endif | ||
133 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | (3 << 20) | DMA_START; | ||
134 | } | 89 | } |
135 | 90 | ||
136 | /* Stops the DMA transfer and interrupt */ | ||
137 | static void dma_stop(void) | ||
138 | { | ||
139 | pcm_playing = false; | ||
140 | |||
141 | DCR0 = 0; | ||
142 | DSR0 = 1; | ||
143 | /* Reset the FIFO */ | ||
144 | SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); | ||
145 | #ifdef HAVE_SPDIF_OUT | ||
146 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
147 | #endif | ||
148 | } | ||
149 | |||
150 | /* sets frequency of input to DAC */ | ||
151 | void pcm_set_frequency(unsigned int frequency) | 91 | void pcm_set_frequency(unsigned int frequency) |
152 | { | 92 | { |
153 | switch(frequency) | 93 | (void)frequency; |
154 | { | ||
155 | case 11025: | ||
156 | pcm_freq = 0x2; | ||
157 | #ifdef HAVE_UDA1380 | ||
158 | uda1380_set_nsorder(3); | ||
159 | #endif | ||
160 | break; | ||
161 | case 22050: | ||
162 | pcm_freq = 0x4; | ||
163 | #ifdef HAVE_UDA1380 | ||
164 | uda1380_set_nsorder(3); | ||
165 | #endif | ||
166 | break; | ||
167 | case 44100: | ||
168 | default: | ||
169 | pcm_freq = 0x6; | ||
170 | #ifdef HAVE_UDA1380 | ||
171 | uda1380_set_nsorder(5); | ||
172 | #endif | ||
173 | break; | ||
174 | } | ||
175 | } | 94 | } |
176 | 95 | ||
177 | size_t pcm_get_bytes_waiting(void) | 96 | size_t pcm_get_bytes_waiting(void) |
178 | { | 97 | { |
179 | return (BCR0 & 0xffffff); | 98 | return 0; |
180 | } | ||
181 | |||
182 | /* DMA0 Interrupt is called when the DMA has finished transfering a chunk */ | ||
183 | void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); | ||
184 | void DMA0(void) | ||
185 | { | ||
186 | int res = DSR0; | ||
187 | |||
188 | DSR0 = 1; /* Clear interrupt */ | ||
189 | DCR0 &= ~DMA_EEXT; | ||
190 | |||
191 | /* Stop on error */ | ||
192 | if(res & 0x70) | ||
193 | { | ||
194 | dma_stop(); | ||
195 | logf("DMA Error:0x%04x", res); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | size_t next_size; | ||
200 | unsigned char *next_start; | ||
201 | { | ||
202 | void (*get_more)(unsigned char**, size_t*) = callback_for_more; | ||
203 | if (get_more) | ||
204 | get_more(&next_start, &next_size); | ||
205 | else | ||
206 | { | ||
207 | next_size = 0; | ||
208 | next_start = NULL; | ||
209 | } | ||
210 | } | ||
211 | if(next_size) | ||
212 | { | ||
213 | SAR0 = (unsigned long)next_start; /* Source address */ | ||
214 | BCR0 = next_size; /* Bytes to transfer */ | ||
215 | DCR0 |= DMA_EEXT; | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | /* Finished playing */ | ||
220 | dma_stop(); | ||
221 | logf("DMA No Data:0x%04x", res); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | IPR |= (1<<14); /* Clear pending interrupt request */ | ||
226 | } | ||
227 | |||
228 | void pcm_init(void) | ||
229 | { | ||
230 | pcm_playing = false; | ||
231 | pcm_paused = false; | ||
232 | |||
233 | MPARK = 0x81; /* PARK[1,0]=10 + BCR24BIT */ | ||
234 | DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */ | ||
235 | DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1; | ||
236 | DMACONFIG = 1; /* DMA0Req = PDOR3 */ | ||
237 | |||
238 | /* Reset the audio FIFO */ | ||
239 | SET_IIS_CONFIG(IIS_RESET); | ||
240 | |||
241 | /* Enable interrupt at level 7, priority 0 */ | ||
242 | ICR6 = 0x1c; | ||
243 | IMR &= ~(1<<14); /* bit 14 is DMA0 */ | ||
244 | |||
245 | pcm_set_frequency(44100); | ||
246 | |||
247 | /* Prevent pops (resets DAC to zero point) */ | ||
248 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq) | IIS_RESET); | ||
249 | |||
250 | #if defined(HAVE_UDA1380) | ||
251 | /* Initialize default register values. */ | ||
252 | uda1380_init(); | ||
253 | |||
254 | /* Sleep a while so the power can stabilize (especially a long | ||
255 | delay is needed for the line out connector). */ | ||
256 | sleep(HZ); | ||
257 | |||
258 | /* Power on FSDAC and HP amp. */ | ||
259 | uda1380_enable_output(true); | ||
260 | |||
261 | /* Unmute the master channel (DAC should be at zero point now). */ | ||
262 | uda1380_mute(false); | ||
263 | |||
264 | #elif defined(HAVE_TLV320) | ||
265 | tlv320_init(); | ||
266 | sleep(HZ/4); | ||
267 | tlv320_mute(false); | ||
268 | #endif | ||
269 | |||
270 | /* Call dma_stop to initialize everything. */ | ||
271 | dma_stop(); | ||
272 | } | 99 | } |
273 | 100 | ||
274 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | 101 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
@@ -286,14 +113,14 @@ void pcm_init(void) | |||
286 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ | 113 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ |
287 | #endif | 114 | #endif |
288 | 115 | ||
289 | static int pcm_freq = 44100; /* 44.1 is default */ | 116 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
290 | 117 | ||
291 | /* NOTE: The order of these two variables is important if you use the iPod | 118 | /* NOTE: The order of these two variables is important if you use the iPod |
292 | assembler optimised fiq handler, so don't change it. */ | 119 | assembler optimised fiq handler, so don't change it. */ |
293 | unsigned short* p IBSS_ATTR; | 120 | unsigned short* p IBSS_ATTR; |
294 | size_t p_size IBSS_ATTR; | 121 | size_t p_size IBSS_ATTR; |
295 | 122 | ||
296 | static void dma_start(const void *addr, size_t size) | 123 | void pcm_play_dma_start(const void *addr, size_t size) |
297 | { | 124 | { |
298 | p=(unsigned short*)addr; | 125 | p=(unsigned short*)addr; |
299 | p_size=size; | 126 | p_size=size; |
@@ -341,7 +168,7 @@ static void dma_start(const void *addr, size_t size) | |||
341 | } | 168 | } |
342 | 169 | ||
343 | /* Stops the DMA transfer and interrupt */ | 170 | /* Stops the DMA transfer and interrupt */ |
344 | static void dma_stop(void) | 171 | void pcm_play_dma_stop(void) |
345 | { | 172 | { |
346 | pcm_playing = false; | 173 | pcm_playing = false; |
347 | 174 | ||
@@ -365,9 +192,58 @@ static void dma_stop(void) | |||
365 | disable_fiq(); | 192 | disable_fiq(); |
366 | } | 193 | } |
367 | 194 | ||
195 | void pcm_play_pause_pause(void) | ||
196 | { | ||
197 | #if CONFIG_CPU == PP5020 | ||
198 | /* Disable the interrupt */ | ||
199 | IISCONFIG &= ~0x2; | ||
200 | /* Disable playback FIFO */ | ||
201 | IISCONFIG &= ~0x20000000; | ||
202 | #elif CONFIG_CPU == PP5002 | ||
203 | /* Disable the interrupt */ | ||
204 | IISFIFO_CFG &= ~(1<<9); | ||
205 | /* Disable playback FIFO */ | ||
206 | IISCONFIG &= ~0x4; | ||
207 | #endif | ||
208 | disable_fiq(); | ||
209 | } | ||
210 | |||
211 | void pcm_play_pause_unpause(void) | ||
212 | { | ||
213 | /* Enable the FIFO and fill it */ | ||
214 | |||
215 | enable_fiq(); | ||
216 | |||
217 | /* Enable playback FIFO */ | ||
218 | #if CONFIG_CPU == PP5020 | ||
219 | IISCONFIG |= 0x20000000; | ||
220 | #elif CONFIG_CPU == PP5002 | ||
221 | IISCONFIG |= 0x4; | ||
222 | #endif | ||
223 | |||
224 | /* Fill the FIFO - we assume there are enough bytes in the | ||
225 | pcm buffer to fill the 32-byte FIFO. */ | ||
226 | while (p_size > 0) { | ||
227 | if (FIFO_FREE_COUNT < 2) { | ||
228 | /* Enable interrupt */ | ||
229 | #if CONFIG_CPU == PP5020 | ||
230 | IISCONFIG |= 0x2; | ||
231 | #elif CONFIG_CPU == PP5002 | ||
232 | IISFIFO_CFG |= (1<<9); | ||
233 | #endif | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | IISFIFO_WR = (*(p++))<<16; | ||
238 | IISFIFO_WR = (*(p++))<<16; | ||
239 | p_size-=4; | ||
240 | } | ||
241 | } | ||
242 | |||
368 | void pcm_set_frequency(unsigned int frequency) | 243 | void pcm_set_frequency(unsigned int frequency) |
369 | { | 244 | { |
370 | pcm_freq=frequency; | 245 | (void)frequency; |
246 | pcm_freq = HW_SAMPR_DEFAULT; | ||
371 | } | 247 | } |
372 | 248 | ||
373 | size_t pcm_get_bytes_waiting(void) | 249 | size_t pcm_get_bytes_waiting(void) |
@@ -378,8 +254,8 @@ size_t pcm_get_bytes_waiting(void) | |||
378 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode | 254 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode |
379 | has registers r8-r14 banked, and so does not need to be saved. This routine | 255 | has registers r8-r14 banked, and so does not need to be saved. This routine |
380 | uses only these registers, and so will never touch the stack unless it | 256 | uses only these registers, and so will never touch the stack unless it |
381 | actually needs to do so when calling callback_for_more. C version is still | 257 | actually needs to do so when calling pcm_callback_for_more. C version is |
382 | included below for reference. | 258 | still included below for reference. |
383 | */ | 259 | */ |
384 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 | 260 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 |
385 | void fiq(void) ICODE_ATTR __attribute__((naked)); | 261 | void fiq(void) ICODE_ATTR __attribute__((naked)); |
@@ -433,10 +309,10 @@ void fiq(void) | |||
433 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ | 309 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ |
434 | "str r9, [r0] \n\t" /* save internal copies of variables back */ | 310 | "str r9, [r0] \n\t" /* save internal copies of variables back */ |
435 | "str r8, [r1] \n\t" | 311 | "str r8, [r1] \n\t" |
436 | "ldr r2, =callback_for_more\n\t" | 312 | "ldr r2, =pcm_callback_for_more\n\t" |
437 | "ldr r2, [r2] \n\t" /* get callback address */ | 313 | "ldr r2, [r2] \n\t" /* get callback address */ |
438 | "cmp r2, #0 \n\t" /* check for null pointer */ | 314 | "cmp r2, #0 \n\t" /* check for null pointer */ |
439 | "movne lr, pc \n\t" /* call callback_for_more */ | 315 | "movne lr, pc \n\t" /* call pcm_callback_for_more */ |
440 | "bxne r2 \n\t" | 316 | "bxne r2 \n\t" |
441 | "ldmia sp!, { r0-r3, r12, lr}\n\t" | 317 | "ldmia sp!, { r0-r3, r12, lr}\n\t" |
442 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ | 318 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ |
@@ -477,7 +353,7 @@ void fiq(void) | |||
477 | "b .exit \n\t" | 353 | "b .exit \n\t" |
478 | ); | 354 | ); |
479 | } | 355 | } |
480 | #else | 356 | #else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */ |
481 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | 357 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); |
482 | void fiq(void) | 358 | void fiq(void) |
483 | { | 359 | { |
@@ -507,20 +383,21 @@ void fiq(void) | |||
507 | } | 383 | } |
508 | 384 | ||
509 | /* p is empty, get some more data */ | 385 | /* p is empty, get some more data */ |
510 | if (callback_for_more) { | 386 | if (pcm_callback_for_more) { |
511 | callback_for_more((unsigned char**)&p,&p_size); | 387 | pcm_callback_for_more((unsigned char**)&p,&p_size); |
512 | } | 388 | } |
513 | } while (p_size); | 389 | } while (p_size); |
514 | 390 | ||
515 | /* No more data, so disable the FIFO/FIQ */ | 391 | /* No more data, so disable the FIFO/FIQ */ |
516 | dma_stop(); | 392 | pcm_play_dma_stop(); |
517 | } | 393 | } |
518 | #endif | 394 | #endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */ |
519 | 395 | ||
520 | void pcm_init(void) | 396 | void pcm_init(void) |
521 | { | 397 | { |
522 | pcm_playing = false; | 398 | pcm_playing = false; |
523 | pcm_paused = false; | 399 | pcm_paused = false; |
400 | pcm_callback_for_more = NULL; | ||
524 | 401 | ||
525 | /* Initialize default register values. */ | 402 | /* Initialize default register values. */ |
526 | wmcodec_init(); | 403 | wmcodec_init(); |
@@ -531,8 +408,8 @@ void pcm_init(void) | |||
531 | /* Unmute the master channel (DAC should be at zero point now). */ | 408 | /* Unmute the master channel (DAC should be at zero point now). */ |
532 | wmcodec_mute(false); | 409 | wmcodec_mute(false); |
533 | 410 | ||
534 | /* Call dma_stop to initialize everything. */ | 411 | /* Call pcm_play_dma_stop to initialize everything. */ |
535 | dma_stop(); | 412 | pcm_play_dma_stop(); |
536 | } | 413 | } |
537 | 414 | ||
538 | #elif (CONFIG_CPU == PNX0101) | 415 | #elif (CONFIG_CPU == PNX0101) |
@@ -542,12 +419,16 @@ void pcm_init(void) | |||
542 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; | 419 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; |
543 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; | 420 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; |
544 | 421 | ||
545 | static int pcm_freq = 44100; /* 44.1 is default */ | 422 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
546 | 423 | ||
547 | unsigned short* p IBSS_ATTR; | 424 | unsigned short* p IBSS_ATTR; |
548 | size_t p_size IBSS_ATTR; | 425 | size_t p_size IBSS_ATTR; |
549 | 426 | ||
550 | static void dma_start(const void *addr, size_t size) | 427 | void pcm_init(void) |
428 | { | ||
429 | } | ||
430 | |||
431 | void pcm_play_dma_start(const void *addr, size_t size) | ||
551 | { | 432 | { |
552 | p = (unsigned short*)addr; | 433 | p = (unsigned short*)addr; |
553 | p_size = size; | 434 | p_size = size; |
@@ -555,11 +436,19 @@ static void dma_start(const void *addr, size_t size) | |||
555 | pcm_playing = true; | 436 | pcm_playing = true; |
556 | } | 437 | } |
557 | 438 | ||
558 | static void dma_stop(void) | 439 | void pcm_play_dma_stop(void) |
559 | { | 440 | { |
560 | pcm_playing = false; | 441 | pcm_playing = false; |
561 | } | 442 | } |
562 | 443 | ||
444 | void pcm_play_pause_pause(void) | ||
445 | { | ||
446 | } | ||
447 | |||
448 | void pcm_play_pause_unpause(void) | ||
449 | { | ||
450 | } | ||
451 | |||
563 | static inline void fill_dma_buf(int offset) | 452 | static inline void fill_dma_buf(int offset) |
564 | { | 453 | { |
565 | short *l, *r, *lend; | 454 | short *l, *r, *lend; |
@@ -611,8 +500,8 @@ static inline void fill_dma_buf(int offset) | |||
611 | p = tmp_p; | 500 | p = tmp_p; |
612 | if (l >= lend) | 501 | if (l >= lend) |
613 | return; | 502 | return; |
614 | else if (callback_for_more) | 503 | else if (pcm_callback_for_more) |
615 | callback_for_more((unsigned char**)&p, | 504 | pcm_callback_for_more((unsigned char**)&p, |
616 | &p_size); | 505 | &p_size); |
617 | } | 506 | } |
618 | while (p_size); | 507 | while (p_size); |
@@ -647,9 +536,10 @@ unsigned long physical_address(void *p) | |||
647 | void pcm_init(void) | 536 | void pcm_init(void) |
648 | { | 537 | { |
649 | int i; | 538 | int i; |
650 | callback_for_more = NULL; | 539 | |
651 | pcm_playing = false; | 540 | pcm_playing = false; |
652 | pcm_paused = false; | 541 | pcm_paused = false; |
542 | pcm_callback_for_more = NULL; | ||
653 | 543 | ||
654 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); | 544 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); |
655 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); | 545 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); |
@@ -691,271 +581,37 @@ void pcm_init(void) | |||
691 | 581 | ||
692 | void pcm_set_frequency(unsigned int frequency) | 582 | void pcm_set_frequency(unsigned int frequency) |
693 | { | 583 | { |
694 | pcm_freq=frequency; | 584 | (void)frequency; |
585 | pcm_freq = HW_SAMPR_DEFAULT; | ||
695 | } | 586 | } |
696 | size_t pcm_get_bytes_waiting(void) | 587 | size_t pcm_get_bytes_waiting(void) |
697 | { | 588 | { |
698 | return p_size; | 589 | return p_size; |
699 | } | 590 | } |
700 | #endif | 591 | #endif /* CONFIG_CPU == */ |
701 | 592 | ||
702 | void pcm_play_stop(void) | 593 | /* dummy functions for those not actually supporting all this yet */ |
594 | void pcm_apply_settings(bool reset) | ||
703 | { | 595 | { |
704 | if (pcm_playing) { | 596 | (void)reset; |
705 | dma_stop(); | ||
706 | } | ||
707 | } | 597 | } |
708 | 598 | ||
709 | #endif | 599 | void pcm_set_monitor(int monitor) |
710 | |||
711 | void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), | ||
712 | unsigned char* start, size_t size) | ||
713 | { | 600 | { |
714 | callback_for_more = get_more; | 601 | (void)monitor; |
715 | |||
716 | if (!(start && size)) | ||
717 | { | ||
718 | if (get_more) | ||
719 | get_more(&start, &size); | ||
720 | else | ||
721 | return; | ||
722 | } | ||
723 | if (start && size) | ||
724 | { | ||
725 | dma_start(start, size); | ||
726 | if (pcm_paused) { | ||
727 | pcm_paused = false; | ||
728 | pcm_play_pause(false); | ||
729 | } | ||
730 | } | ||
731 | } | 602 | } |
603 | /** **/ | ||
732 | 604 | ||
733 | void pcm_mute(bool mute) | 605 | void pcm_mute(bool mute) |
734 | { | 606 | { |
735 | #ifdef HAVE_UDA1380 | 607 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
736 | uda1380_mute(mute); | ||
737 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
738 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | 608 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) |
739 | wmcodec_mute(mute); | 609 | wmcodec_mute(mute); |
740 | #elif defined(HAVE_TLV320) | ||
741 | tlv320_mute(mute); | ||
742 | #endif | 610 | #endif |
743 | if (mute) | 611 | if (mute) |
744 | sleep(HZ/16); | 612 | sleep(HZ/16); |
745 | } | 613 | } |
746 | 614 | ||
747 | void pcm_play_pause(bool play) | ||
748 | { | ||
749 | bool needs_change = pcm_paused == play; | ||
750 | |||
751 | /* This needs to be done ahead of the rest to prevent infinite | ||
752 | * recursion from dma_start */ | ||
753 | pcm_paused = !play; | ||
754 | if (pcm_playing && needs_change) { | ||
755 | if(play) { | ||
756 | if (pcm_get_bytes_waiting()) { | ||
757 | logf("unpause"); | ||
758 | |||
759 | #ifdef CPU_COLDFIRE | ||
760 | /* Enable the FIFO and force one write to it */ | ||
761 | SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); | ||
762 | #ifdef HAVE_SPDIF_OUT | ||
763 | EBU1CONFIG = EBU_DEFPARM; | ||
764 | #endif | ||
765 | DCR0 |= DMA_EEXT | DMA_START; | ||
766 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
767 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | ||
768 | /* Enable the FIFO and fill it */ | ||
769 | |||
770 | enable_fiq(); | ||
771 | |||
772 | /* Enable playback FIFO */ | ||
773 | #if CONFIG_CPU == PP5020 | ||
774 | IISCONFIG |= 0x20000000; | ||
775 | #elif CONFIG_CPU == PP5002 | ||
776 | IISCONFIG |= 0x4; | ||
777 | #endif | ||
778 | |||
779 | /* Fill the FIFO - we assume there are enough bytes in the | ||
780 | pcm buffer to fill the 32-byte FIFO. */ | ||
781 | while (p_size > 0) { | ||
782 | if (FIFO_FREE_COUNT < 2) { | ||
783 | /* Enable interrupt */ | ||
784 | #if CONFIG_CPU == PP5020 | ||
785 | IISCONFIG |= 0x2; | ||
786 | #elif CONFIG_CPU == PP5002 | ||
787 | IISFIFO_CFG |= (1<<9); | ||
788 | #endif | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | IISFIFO_WR = (*(p++))<<16; | ||
793 | IISFIFO_WR = (*(p++))<<16; | ||
794 | p_size-=4; | ||
795 | } | ||
796 | #elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */ | ||
797 | /* nothing yet */ | ||
798 | #endif | ||
799 | } else { | ||
800 | #if (CONFIG_CPU != PNX0101 && CONFIG_CPU != S3C2440) | ||
801 | size_t next_size; | ||
802 | unsigned char *next_start; | ||
803 | void (*get_more)(unsigned char**, size_t*) = callback_for_more; | ||
804 | logf("unpause, no data waiting"); | ||
805 | if (get_more) | ||
806 | get_more(&next_start, &next_size); | ||
807 | if (next_start && next_size) | ||
808 | dma_start(next_start, next_size); | ||
809 | else | ||
810 | { | ||
811 | dma_stop(); | ||
812 | logf("unpause attempted, no data"); | ||
813 | } | ||
814 | #endif | ||
815 | } | ||
816 | } else { | ||
817 | logf("pause"); | ||
818 | |||
819 | #ifdef CPU_COLDFIRE | ||
820 | /* Disable DMA peripheral request. */ | ||
821 | DCR0 &= ~DMA_EEXT; | ||
822 | SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); | ||
823 | #ifdef HAVE_SPDIF_OUT | ||
824 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | ||
825 | #endif | ||
826 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
827 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) | ||
828 | #if CONFIG_CPU == PP5020 | ||
829 | /* Disable the interrupt */ | ||
830 | IISCONFIG &= ~0x2; | ||
831 | /* Disable playback FIFO */ | ||
832 | IISCONFIG &= ~0x20000000; | ||
833 | #elif CONFIG_CPU == PP5002 | ||
834 | /* Disable the interrupt */ | ||
835 | IISFIFO_CFG &= ~(1<<9); | ||
836 | /* Disable playback FIFO */ | ||
837 | IISCONFIG &= ~0x4; | ||
838 | #endif | ||
839 | |||
840 | disable_fiq(); | ||
841 | #elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */ | ||
842 | /* nothing yet */ | ||
843 | #endif | ||
844 | } | ||
845 | } /* pcm_playing && needs_change */ | ||
846 | } | ||
847 | |||
848 | bool pcm_is_playing(void) { | ||
849 | return pcm_playing; | ||
850 | } | ||
851 | |||
852 | bool pcm_is_paused(void) { | ||
853 | return pcm_paused; | ||
854 | } | ||
855 | |||
856 | |||
857 | #if defined(CPU_COLDFIRE) | ||
858 | /* Peaks ahead in the DMA buffer based upon the calling period to | ||
859 | attempt to compensate for the delay. Keeps a moving average of | ||
860 | length four. */ | ||
861 | void pcm_calculate_peaks(int *left, int *right) | ||
862 | { | ||
863 | unsigned long samples; | ||
864 | unsigned long *addr, *end; | ||
865 | long peak_p, peak_n; | ||
866 | |||
867 | static unsigned long last_peak_tick = 0; | ||
868 | static unsigned long frame_period = 0; | ||
869 | |||
870 | /* Throttled peak ahead based on calling period */ | ||
871 | unsigned long period = current_tick - last_peak_tick; | ||
872 | |||
873 | /* Keep reasonable limits on period */ | ||
874 | if (period < 1) | ||
875 | period = 1; | ||
876 | else if (period > HZ/5) | ||
877 | period = HZ/5; | ||
878 | |||
879 | frame_period = (3*frame_period + period) >> 2; | ||
880 | |||
881 | last_peak_tick = current_tick; | ||
882 | |||
883 | if (!pcm_playing || pcm_paused) | ||
884 | { | ||
885 | peak_left = peak_right = 0; | ||
886 | goto peak_done; | ||
887 | } | ||
888 | |||
889 | samples = (BCR0 & 0xffffff) >> 2; | ||
890 | addr = (long *)(SAR0 & ~3); | ||
891 | samples = MIN(frame_period*44100/HZ, samples); | ||
892 | end = addr + samples; | ||
893 | peak_p = peak_n = 0; | ||
894 | |||
895 | if (left && right) | ||
896 | { | ||
897 | if (samples > 0) | ||
898 | { | ||
899 | long peak_rp = 0, peak_rn = 0; | ||
900 | |||
901 | do | ||
902 | { | ||
903 | long value = *addr; | ||
904 | long ch; | ||
905 | |||
906 | ch = value >> 16; | ||
907 | if (ch > peak_p) peak_p = ch; | ||
908 | else if (ch < peak_n) peak_n = ch; | ||
909 | |||
910 | ch = (short)value; | ||
911 | if (ch > peak_rp) peak_rp = ch; | ||
912 | else if (ch < peak_rn) peak_rn = ch; | ||
913 | |||
914 | addr += 4; | ||
915 | } | ||
916 | while (addr < end); | ||
917 | |||
918 | peak_left = MAX(peak_p, -peak_n); | ||
919 | peak_right = MAX(peak_rp, -peak_rn); | ||
920 | } | ||
921 | } | ||
922 | else if (left || right) | ||
923 | { | ||
924 | if (samples > 0) | ||
925 | { | ||
926 | if (left) | ||
927 | { | ||
928 | /* Put left channel in low word */ | ||
929 | addr = (long *)((short *)addr - 1); | ||
930 | end = (long *)((short *)end - 1); | ||
931 | } | ||
932 | |||
933 | do | ||
934 | { | ||
935 | long value = *(short *)addr; | ||
936 | |||
937 | if (value > peak_p) peak_p = value; | ||
938 | else if (value < peak_n) peak_n = value; | ||
939 | |||
940 | addr += 4; | ||
941 | } | ||
942 | while (addr < end); | ||
943 | |||
944 | if (left) | ||
945 | peak_left = MAX(peak_p, -peak_n); | ||
946 | else | ||
947 | peak_right = MAX(peak_p, -peak_n); | ||
948 | } | ||
949 | } | ||
950 | |||
951 | peak_done: | ||
952 | if (left) | ||
953 | *left = peak_left; | ||
954 | |||
955 | if (right) | ||
956 | *right = peak_right; | ||
957 | } | ||
958 | #else | ||
959 | /* | 615 | /* |
960 | * This function goes directly into the DMA buffer to calculate the left and | 616 | * This function goes directly into the DMA buffer to calculate the left and |
961 | * right peak values. To avoid missing peaks it tries to look forward two full | 617 | * right peak values. To avoid missing peaks it tries to look forward two full |
@@ -1037,4 +693,94 @@ void pcm_calculate_peaks(int *left, int *right) | |||
1037 | } | 693 | } |
1038 | #endif | 694 | #endif |
1039 | } | 695 | } |
696 | |||
1040 | #endif /* CPU_COLDFIRE */ | 697 | #endif /* CPU_COLDFIRE */ |
698 | |||
699 | /**************************************************************************** | ||
700 | * Functions that do not require targeted implementation but only a targeted | ||
701 | * interface | ||
702 | */ | ||
703 | |||
704 | /* Common code to pcm_play_data and pcm_play_pause | ||
705 | Returns true if DMA playback was started, else false. */ | ||
706 | bool pcm_play_data_start(pcm_more_callback_type get_more, | ||
707 | unsigned char *start, size_t size) | ||
708 | { | ||
709 | if (!(start && size)) | ||
710 | { | ||
711 | size = 0; | ||
712 | if (get_more) | ||
713 | get_more(&start, &size); | ||
714 | } | ||
715 | |||
716 | if (start && size) | ||
717 | { | ||
718 | pcm_play_dma_start(start, size); | ||
719 | return true; | ||
720 | } | ||
721 | |||
722 | return false; | ||
723 | } | ||
724 | |||
725 | void pcm_play_data(pcm_more_callback_type get_more, | ||
726 | unsigned char *start, size_t size) | ||
727 | { | ||
728 | pcm_callback_for_more = get_more; | ||
729 | |||
730 | if (pcm_play_data_start(get_more, start, size) && pcm_paused) | ||
731 | { | ||
732 | pcm_paused = false; | ||
733 | pcm_play_pause(false); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | void pcm_play_pause(bool play) | ||
738 | { | ||
739 | bool needs_change = pcm_paused == play; | ||
740 | |||
741 | /* This needs to be done ahead of the rest to prevent infinite | ||
742 | recursion from pcm_play_data */ | ||
743 | pcm_paused = !play; | ||
744 | |||
745 | if (pcm_playing && needs_change) | ||
746 | { | ||
747 | if (play) | ||
748 | { | ||
749 | if (pcm_get_bytes_waiting()) | ||
750 | { | ||
751 | logf("unpause"); | ||
752 | pcm_play_pause_unpause(); | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | logf("unpause, no data waiting"); | ||
757 | if (!pcm_play_data_start(pcm_callback_for_more, NULL, 0)) | ||
758 | { | ||
759 | pcm_play_dma_stop(); | ||
760 | logf("unpause attempted, no data"); | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | logf("pause"); | ||
767 | pcm_play_pause_pause(); | ||
768 | } | ||
769 | } /* pcm_playing && needs_change */ | ||
770 | } | ||
771 | |||
772 | void pcm_play_stop(void) | ||
773 | { | ||
774 | if (pcm_playing) | ||
775 | pcm_play_dma_stop(); | ||
776 | } | ||
777 | |||
778 | bool pcm_is_playing(void) | ||
779 | { | ||
780 | return pcm_playing; | ||
781 | } | ||
782 | |||
783 | bool pcm_is_paused(void) | ||
784 | { | ||
785 | return pcm_paused; | ||
786 | } | ||
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 2785d4b1b1..25f1f1ef64 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -16,199 +16,238 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | #include "system.h" | |
20 | #include "config.h" | 20 | #include "kernel.h" |
21 | #include "debug.h" | 21 | #include "logf.h" |
22 | #include "panic.h" | 22 | #include "panic.h" |
23 | #include "thread.h" | 23 | #include "thread.h" |
24 | |||
25 | #include <kernel.h> | ||
26 | #include <stdio.h> | ||
27 | #include <string.h> | ||
28 | #include <stdarg.h> | ||
29 | #include <string.h> | 24 | #include <string.h> |
30 | 25 | #include "ata.h" | |
31 | #include "cpu.h" | 26 | #include "usb.h" |
32 | #include "i2c.h" | 27 | #if defined(HAVE_UDA1380) |
33 | #include "power.h" | ||
34 | #ifdef HAVE_UDA1380 | ||
35 | #include "uda1380.h" | 28 | #include "uda1380.h" |
36 | #endif | 29 | #include "general.h" |
37 | #ifdef HAVE_TLV320 | 30 | #elif defined(HAVE_TLV320) |
38 | #include "tlv320.h" | 31 | #include "tlv320.h" |
39 | #endif | 32 | #endif |
40 | #include "system.h" | ||
41 | #include "usb.h" | ||
42 | |||
43 | #include "buffer.h" | 33 | #include "buffer.h" |
44 | #include "audio.h" | 34 | #include "audio.h" |
45 | #include "button.h" | ||
46 | #include "file.h" | ||
47 | #include "sprintf.h" | ||
48 | #include "logf.h" | ||
49 | #include "button.h" | ||
50 | #include "lcd.h" | ||
51 | #include "lcd-remote.h" | ||
52 | #include "pcm_playback.h" | ||
53 | #include "sound.h" | 35 | #include "sound.h" |
54 | #include "id3.h" | 36 | #include "id3.h" |
55 | #include "pcm_record.h" | ||
56 | |||
57 | extern int boost_counter; /* used for boost check */ | ||
58 | 37 | ||
59 | /***************************************************************************/ | 38 | /***************************************************************************/ |
60 | 39 | ||
40 | /** | ||
41 | * APIs implemented in the target tree portion: | ||
42 | * Public - | ||
43 | * pcm_init_recording | ||
44 | * pcm_close_recording | ||
45 | * pcm_rec_mux | ||
46 | * Semi-private - | ||
47 | * pcm_rec_dma_start | ||
48 | * pcm_rec_dma_stop | ||
49 | */ | ||
50 | |||
51 | /** These items may be implemented target specifically or need to | ||
52 | be shared semi-privately **/ | ||
53 | |||
54 | /* the registered callback function for when more data is available */ | ||
55 | pcm_more_callback_type pcm_callback_more_ready = NULL; | ||
56 | /* DMA transfer in is currently active */ | ||
57 | bool pcm_recording = false; | ||
58 | |||
59 | /* APIs implemented in the target-specific portion */ | ||
60 | void pcm_rec_dma_start(const void *addr, size_t size); | ||
61 | void pcm_rec_dma_stop(void); | ||
62 | |||
63 | /** General recording state **/ | ||
61 | static bool is_recording; /* We are recording */ | 64 | static bool is_recording; /* We are recording */ |
62 | static bool is_paused; /* We have paused */ | 65 | static bool is_paused; /* We have paused */ |
66 | static bool is_stopping; /* We are currently stopping */ | ||
63 | static bool is_error; /* An error has occured */ | 67 | static bool is_error; /* An error has occured */ |
64 | 68 | ||
65 | static unsigned long num_rec_bytes; /* Num bytes recorded */ | 69 | /** Stats on encoded data for current file **/ |
66 | static unsigned long num_file_bytes; /* Num bytes written to current file */ | 70 | static size_t num_rec_bytes; /* Num bytes recorded */ |
67 | static int error_count; /* Number of DMA errors */ | 71 | static unsigned long num_rec_samples; /* Number of PCM samples recorded */ |
68 | static unsigned long num_pcm_samples; /* Num pcm samples written to current file */ | ||
69 | |||
70 | static long record_start_time; /* current_tick when recording was started */ | ||
71 | static long pause_start_time; /* current_tick when pause was started */ | ||
72 | static unsigned int sample_rate; /* Sample rate at time of recording start */ | ||
73 | static int rec_source; /* Current recording source */ | ||
74 | 72 | ||
75 | static int wav_file; | 73 | /** Stats on encoded data for all files from start to stop **/ |
76 | static char recording_filename[MAX_PATH]; | 74 | static unsigned long long accum_rec_bytes; /* total size written to chunks */ |
75 | static unsigned long long accum_pcm_samples; /* total pcm count processed */ | ||
77 | 76 | ||
78 | static volatile bool init_done, close_done, record_done; | 77 | /* Keeps data about current file and is sent as event data for codec */ |
79 | static volatile bool stop_done, pause_done, resume_done, new_file_done; | 78 | static struct enc_file_event_data rec_fdata IDATA_ATTR = |
80 | 79 | { | |
81 | static int peak_left, peak_right; | 80 | .chunk = NULL, |
81 | .new_enc_size = 0, | ||
82 | .new_num_pcm = 0, | ||
83 | .rec_file = -1, | ||
84 | .num_pcm_samples = 0 | ||
85 | }; | ||
82 | 86 | ||
83 | #ifdef IAUDIO_X5 | 87 | /** These apply to current settings **/ |
84 | #define SET_IIS_PLAY(x) IIS1CONFIG = (x); | 88 | static int rec_source; /* current rec_source setting */ |
85 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | 89 | static int rec_frequency; /* current frequency setting */ |
86 | #else | 90 | static unsigned long sample_rate; /* Sample rate in HZ */ |
87 | #define SET_IIS_PLAY(x) IIS2CONFIG = (x); | 91 | static int num_channels; /* Current number of channels */ |
88 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | 92 | static struct encoder_config enc_config; /* Current encoder configuration */ |
89 | #endif | ||
90 | 93 | ||
91 | /**************************************************************************** | 94 | /**************************************************************************** |
92 | use 2 circular buffers of same size: | 95 | use 2 circular buffers: |
93 | rec_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data | 96 | pcm_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data |
94 | enc_buffer=encoded audio buffer: storage for encoder output data | 97 | enc_buffer=encoded audio buffer: storage for encoder output data |
95 | 98 | ||
96 | Flow: | 99 | Flow: |
97 | 1. when entering recording_screen DMA feeds the ringbuffer rec_buffer | 100 | 1. when entering recording_screen DMA feeds the ringbuffer pcm_buffer |
98 | 2. if enough pcm data are available the encoder codec does encoding of pcm | 101 | 2. if enough pcm data are available the encoder codec does encoding of pcm |
99 | chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread | 102 | chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread |
100 | 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk | 103 | 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk |
101 | 104 | ||
102 | Functions calls: | 105 | Functions calls (basic encoder steps): |
103 | 1.main: codec_load_encoder(); start the encoder | 106 | 1.main: audio_load_encoder(); start the encoder |
104 | 2.encoder: enc_get_inputs(); get encoder buffsize, mono/stereo, quality | 107 | 2.encoder: enc_get_inputs(); get encoder recording settings |
105 | 3.encoder: enc_set_parameters(); set the encoder parameters (max.chunksize) | 108 | 3.encoder: enc_set_parameters(); set the encoder parameters |
106 | 4.encoder: enc_get_wav_data(); get n bytes of unprocessed pcm data | 109 | 4.encoder: enc_get_pcm_data(); get n bytes of unprocessed pcm data |
107 | 5.encoder: enc_wavbuf_near_empty();if true: reduce cpu_boost | 110 | 5.encoder: enc_pcm_buf_near_empty(); if 1: reduce cpu_boost |
108 | 6.encoder: enc_alloc_chunk(); get a ptr to next enc chunk | 111 | 6.encoder: enc_alloc_chunk(); get a ptr to next enc chunk |
109 | 7.encoder: <process enc chunk> compress and store data to enc chunk | 112 | 7.encoder: <process enc chunk> compress and store data to enc chunk |
110 | 8.encoder: enc_free_chunk(); inform main about chunk process finished | 113 | 8.encoder: enc_free_chunk(); inform main about chunk process finished |
111 | 9.encoder: repeat 4. to 8. | 114 | 9.encoder: repeat 4. to 8. |
112 | A.main: enc_set_header_callback(); create the current format header (file) | 115 | A.pcmrec: enc_events_callback(); called for certain events |
113 | ****************************************************************************/ | 116 | ****************************************************************************/ |
114 | #define NUM_CHUNKS 256 /* Power of 2 */ | 117 | |
115 | #define CHUNK_SIZE 8192 /* Power of 2 */ | 118 | /** buffer parameters where incoming PCM data is placed **/ |
116 | #define MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ | 119 | #define PCM_NUM_CHUNKS 256 /* Power of 2 */ |
117 | #define CHUNK_MASK (NUM_CHUNKS * CHUNK_SIZE - 1) | 120 | #define PCM_CHUNK_SIZE 8192 /* Power of 2 */ |
118 | #define WRITE_THRESHOLD (44100 * 5 / enc_samp_per_chunk) /* 5sec */ | 121 | #define PCM_CHUNK_MASK (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE - 1) |
119 | #define GET_CHUNK(x) (long*)(&rec_buffer[x]) | 122 | |
120 | #define GET_ENC_CHUNK(x) (long*)(&enc_buffer[enc_chunk_size*(x)]) | 123 | #define GET_PCM_CHUNK(offset) ((long *)(pcm_buffer + (offset))) |
121 | 124 | #define GET_ENC_CHUNK(index) ENC_CHUNK_HDR(enc_buffer + enc_chunk_size*(index)) | |
122 | static int audio_enc_id; /* current encoder id */ | 125 | |
123 | static unsigned char *rec_buffer; /* Circular recording buffer */ | 126 | #define INC_ENC_INDEX(index) \ |
124 | static unsigned char *enc_buffer; /* Circular encoding buffer */ | 127 | { if (++index >= enc_num_chunks) index = 0; } |
125 | static unsigned char *enc_head_buffer; /* encoder header buffer */ | 128 | #define DEC_ENC_INDEX(index) \ |
126 | static int enc_head_size; /* used size in header buffer */ | 129 | { if (--index < 0) index = enc_num_chunks - 1; } |
127 | static int write_pos; /* Current chunk pos for DMA writing */ | 130 | |
128 | static int read_pos; /* Current chunk pos for encoding */ | 131 | static size_t rec_buffer_size; /* size of available buffer */ |
129 | static long pre_record_ticks;/* pre-record time expressed in ticks */ | 132 | static unsigned char *pcm_buffer; /* circular recording buffer */ |
130 | static int enc_wr_index; /* Current encoding chunk write index */ | 133 | static unsigned char *enc_buffer; /* circular encoding buffer */ |
131 | static int enc_rd_index; /* Current encoding chunk read index */ | 134 | static volatile int dma_wr_pos; /* current DMA write pos */ |
132 | static int enc_chunk_size; /* maximum encoder chunk size */ | 135 | static int pcm_rd_pos; /* current PCM read pos */ |
136 | static volatile bool dma_lock; /* lock DMA write position */ | ||
137 | static unsigned long pre_record_ticks;/* pre-record time in ticks */ | ||
138 | static int enc_wr_index; /* encoder chunk write index */ | ||
139 | static int enc_rd_index; /* encoder chunk read index */ | ||
133 | static int enc_num_chunks; /* number of chunks in ringbuffer */ | 140 | static int enc_num_chunks; /* number of chunks in ringbuffer */ |
134 | static int enc_buffer_size; /* encode buffer size */ | 141 | static size_t enc_chunk_size; /* maximum encoder chunk size */ |
135 | static int enc_channels; /* 1=mono 2=stereo */ | 142 | static size_t enc_data_size; /* maximum data size for encoder */ |
136 | static int enc_quality; /* mp3: 64,96,128,160,192,320 kBit */ | 143 | static unsigned long enc_sample_rate; /* sample rate used by encoder */ |
137 | static int enc_samp_per_chunk;/* pcm samples per encoder chunk */ | ||
138 | static bool wav_queue_empty; /* all wav chunks processed? */ | 144 | static bool wav_queue_empty; /* all wav chunks processed? */ |
139 | static unsigned long avrg_bit_rate; /* average bit rates from chunks */ | ||
140 | static unsigned long curr_bit_rate; /* cumulated bit rates from chunks */ | ||
141 | static unsigned long curr_chunk_cnt; /* number of processed chunks */ | ||
142 | 145 | ||
143 | void (*enc_set_header_callback)(void *head_buffer, int head_size, | 146 | /** file flushing **/ |
144 | int num_pcm_samples, bool is_file_header); | 147 | static int write_threshold; /* max chunk limit for data flush */ |
148 | static int panic_threshold; /* boost thread prio when here */ | ||
149 | static int spinup_time = -1;/* last ata_spinup_time */ | ||
150 | |||
151 | /** encoder events **/ | ||
152 | static void (*enc_events_callback)(enum enc_events event, void *data); | ||
153 | |||
154 | /** Path queue for files to write **/ | ||
155 | #define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */ | ||
156 | static unsigned char *fn_queue; /* pointer to first filename */ | ||
157 | static ssize_t fnq_size; /* capacity of queue in bytes */ | ||
158 | static int fnq_rd_pos; /* current read position */ | ||
159 | static int fnq_wr_pos; /* current write position */ | ||
145 | 160 | ||
146 | /***************************************************************************/ | 161 | /***************************************************************************/ |
147 | 162 | ||
148 | static struct event_queue pcmrec_queue; | 163 | static struct event_queue pcmrec_queue; |
149 | static long pcmrec_stack[2*DEFAULT_STACK_SIZE/sizeof(long)]; | 164 | static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; |
150 | static const char pcmrec_thread_name[] = "pcmrec"; | 165 | static const char pcmrec_thread_name[] = "pcmrec"; |
151 | 166 | ||
152 | static void pcmrec_thread(void); | 167 | static void pcmrec_thread(void); |
153 | static void pcmrec_dma_start(void); | ||
154 | static void pcmrec_dma_stop(void); | ||
155 | static void close_wave(void); | ||
156 | 168 | ||
157 | /* Event IDs */ | 169 | /* Event values which are also single-bit flags */ |
158 | #define PCMREC_INIT 1 /* Enable recording */ | 170 | #define PCMREC_INIT 0x00000001 /* enable recording */ |
159 | #define PCMREC_CLOSE 2 | 171 | #define PCMREC_CLOSE 0x00000002 |
160 | 172 | ||
161 | #define PCMREC_START 3 /* Start a new recording */ | 173 | #define PCMREC_START 0x00000004 /* start recording (when stopped) */ |
162 | #define PCMREC_STOP 4 /* Stop the current recording */ | 174 | #define PCMREC_STOP 0x00000008 /* stop the current recording */ |
163 | #define PCMREC_PAUSE 10 | 175 | #define PCMREC_PAUSE 0x00000010 /* pause the current recording */ |
164 | #define PCMREC_RESUME 11 | 176 | #define PCMREC_RESUME 0x00000020 /* resume the current recording */ |
165 | #define PCMREC_NEW_FILE 12 | 177 | #define PCMREC_NEW_FILE 0x00000040 /* start new file (when recording) */ |
166 | #define PCMREC_SET_GAIN 13 | 178 | #define PCMREC_SET_GAIN 0x00000080 |
179 | #define PCMREC_FLUSH_NUM 0x00000100 /* flush a number of files out */ | ||
180 | #define PCMREC_FINISH_STOP 0x00000200 /* finish the stopping recording */ | ||
167 | 181 | ||
168 | /*******************************************************************/ | 182 | /* mask for signaling events */ |
169 | /* Functions that are not executing in the pcmrec_thread first */ | 183 | static volatile long pcm_thread_event_mask; |
170 | /*******************************************************************/ | ||
171 | 184 | ||
172 | /* Creates pcmrec_thread */ | 185 | static void pcm_thread_sync_post(long event, void *data) |
173 | void pcm_rec_init(void) | ||
174 | { | 186 | { |
175 | queue_init(&pcmrec_queue, true); | 187 | pcm_thread_event_mask &= ~event; |
176 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | 188 | queue_post(&pcmrec_queue, event, data); |
177 | pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); | 189 | while(!(event & pcm_thread_event_mask)) |
178 | } | 190 | yield(); |
191 | } /* pcm_thread_sync_post */ | ||
179 | 192 | ||
193 | static inline void pcm_thread_signal_event(long event) | ||
194 | { | ||
195 | pcm_thread_event_mask |= event; | ||
196 | } /* pcm_thread_signal_event */ | ||
180 | 197 | ||
181 | int audio_get_encoder_id(void) | 198 | static inline void pcm_thread_unsignal_event(long event) |
182 | { | 199 | { |
183 | return audio_enc_id; | 200 | pcm_thread_event_mask &= ~event; |
184 | } | 201 | } /* pcm_thread_unsignal_event */ |
185 | 202 | ||
186 | /* Initializes recording: | 203 | static inline bool pcm_thread_event_state(long signaled, long unsignaled) |
187 | * - Set up the UDA1380/TLV320 for recording | 204 | { |
188 | * - Prepare for DMA transfers | 205 | return ((signaled | unsignaled) & pcm_thread_event_mask) == signaled; |
189 | */ | 206 | } /* pcm_thread_event_state */ |
190 | 207 | ||
191 | void audio_init_recording(unsigned int buffer_offset) | 208 | static void pcm_thread_wait_for_stop(void) |
192 | { | 209 | { |
193 | (void)buffer_offset; | 210 | if (is_stopping) |
211 | { | ||
212 | logf("waiting for stop to finish"); | ||
213 | while (is_stopping) | ||
214 | yield(); | ||
215 | } | ||
216 | } /* pcm_thread_wait_for_stop */ | ||
194 | 217 | ||
195 | init_done = false; | 218 | /*******************************************************************/ |
196 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); | 219 | /* Functions that are not executing in the pcmrec_thread first */ |
220 | /*******************************************************************/ | ||
197 | 221 | ||
198 | while(!init_done) | 222 | /* Callback for when more data is ready */ |
199 | sleep_thread(1); | 223 | static void pcm_rec_have_more(unsigned char **data, size_t *size) |
200 | } | ||
201 | |||
202 | void audio_close_recording(void) | ||
203 | { | 224 | { |
204 | close_done = false; | 225 | if (*size != 0) |
205 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); | 226 | { |
227 | /* some error condition */ | ||
228 | if (*size == DMA_REC_ERROR_DMA) | ||
229 | { | ||
230 | /* Flush recorded data to disk and stop recording */ | ||
231 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
232 | return; | ||
233 | } | ||
234 | /* else try again next transmission */ | ||
235 | } | ||
236 | else if (!dma_lock) | ||
237 | { | ||
238 | /* advance write position */ | ||
239 | dma_wr_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; | ||
240 | } | ||
206 | 241 | ||
207 | while(!close_done) | 242 | *data = (unsigned char *)GET_PCM_CHUNK(dma_wr_pos); |
208 | sleep_thread(1); | 243 | *size = PCM_CHUNK_SIZE; |
244 | } /* pcm_rec_have_more */ | ||
209 | 245 | ||
210 | audio_remove_encoder(); | 246 | /** pcm_rec_* group **/ |
211 | } | 247 | void pcm_rec_error_clear(void) |
248 | { | ||
249 | is_error = false; | ||
250 | } /* pcm_rec_error_clear */ | ||
212 | 251 | ||
213 | unsigned long pcm_rec_status(void) | 252 | unsigned long pcm_rec_status(void) |
214 | { | 253 | { |
@@ -216,165 +255,223 @@ unsigned long pcm_rec_status(void) | |||
216 | 255 | ||
217 | if (is_recording) | 256 | if (is_recording) |
218 | ret |= AUDIO_STATUS_RECORD; | 257 | ret |= AUDIO_STATUS_RECORD; |
258 | |||
219 | if (is_paused) | 259 | if (is_paused) |
220 | ret |= AUDIO_STATUS_PAUSE; | 260 | ret |= AUDIO_STATUS_PAUSE; |
261 | |||
221 | if (is_error) | 262 | if (is_error) |
222 | ret |= AUDIO_STATUS_ERROR; | 263 | ret |= AUDIO_STATUS_ERROR; |
223 | if (!is_recording && pre_record_ticks && init_done && !close_done) | 264 | |
265 | if (!is_recording && pre_record_ticks && | ||
266 | pcm_thread_event_state(PCMREC_INIT, PCMREC_CLOSE)) | ||
224 | ret |= AUDIO_STATUS_PRERECORD; | 267 | ret |= AUDIO_STATUS_PRERECORD; |
225 | 268 | ||
226 | return ret; | 269 | return ret; |
227 | } | 270 | } /* pcm_rec_status */ |
228 | 271 | ||
229 | int pcm_rec_current_bitrate(void) | 272 | int pcm_rec_current_bitrate(void) |
230 | { | 273 | { |
231 | return avrg_bit_rate; | 274 | if (accum_pcm_samples == 0) |
232 | } | 275 | return 0; |
233 | 276 | ||
234 | unsigned long audio_recorded_time(void) | 277 | return (int)(8*accum_rec_bytes*enc_sample_rate / (1000*accum_pcm_samples)); |
278 | } /* pcm_rec_current_bitrate */ | ||
279 | |||
280 | int pcm_rec_encoder_afmt(void) | ||
235 | { | 281 | { |
236 | if (is_recording) | 282 | return enc_config.afmt; |
283 | } /* pcm_rec_encoder_afmt */ | ||
284 | |||
285 | int pcm_rec_rec_format(void) | ||
237 | { | 286 | { |
238 | if (is_paused) | 287 | return afmt_rec_format[enc_config.afmt]; |
239 | return pause_start_time - record_start_time; | 288 | } /* pcm_rec_rec_format */ |
240 | else | ||
241 | return current_tick - record_start_time; | ||
242 | } | ||
243 | 289 | ||
244 | return 0; | 290 | unsigned long pcm_rec_sample_rate(void) |
245 | } | 291 | { |
292 | /* Which is better ?? */ | ||
293 | #if 0 | ||
294 | return enc_sample_rate; | ||
295 | #endif | ||
296 | return sample_rate; | ||
297 | } /* audio_get_sample_rate */ | ||
246 | 298 | ||
247 | unsigned long audio_num_recorded_bytes(void) | 299 | /** |
300 | * Creates pcmrec_thread | ||
301 | */ | ||
302 | void pcm_rec_init(void) | ||
248 | { | 303 | { |
249 | if (is_recording) | 304 | queue_init(&pcmrec_queue, true); |
250 | return num_rec_bytes; | 305 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), |
306 | pcmrec_thread_name, PRIORITY_RECORDING); | ||
307 | } /* pcm_rec_init */ | ||
251 | 308 | ||
309 | /** audio_* group **/ | ||
310 | |||
311 | void audio_init_recording(unsigned int buffer_offset) | ||
312 | { | ||
313 | (void)buffer_offset; | ||
314 | pcm_thread_wait_for_stop(); | ||
315 | pcm_thread_sync_post(PCMREC_INIT, NULL); | ||
316 | } /* audio_init_recording */ | ||
317 | |||
318 | void audio_close_recording(void) | ||
319 | { | ||
320 | pcm_thread_wait_for_stop(); | ||
321 | pcm_thread_sync_post(PCMREC_CLOSE, NULL); | ||
322 | /* reset pcm to defaults (playback only) */ | ||
323 | pcm_set_frequency(-1); | ||
324 | pcm_set_monitor(-1); | ||
325 | pcm_set_rec_source(-1); | ||
326 | #ifdef HAVE_TLV320 | ||
327 | /* tlv320 screeches if left at 88.2 with no inputs */ | ||
328 | pcm_apply_settings(true); | ||
329 | #endif | ||
330 | audio_remove_encoder(); | ||
331 | } /* audio_close_recording */ | ||
332 | |||
333 | unsigned long audio_recorded_time(void) | ||
334 | { | ||
335 | if (!is_recording || enc_sample_rate == 0) | ||
252 | return 0; | 336 | return 0; |
253 | } | ||
254 | 337 | ||
255 | #ifdef HAVE_SPDIF_IN | 338 | /* return actual recorded time a la encoded data even if encoder rate |
256 | /* Only the last six of these are standard rates, but all sample rates are | 339 | doesn't match the pcm rate */ |
257 | * possible, so we support some other common ones as well. | 340 | return (long)(HZ*(unsigned long long)num_rec_samples / enc_sample_rate); |
258 | */ | 341 | } /* audio_recorded_time */ |
259 | static unsigned long spdif_sample_rates[] = { | ||
260 | 8000, 11025, 12000, 16000, 22050, 24000, | ||
261 | 32000, 44100, 48000, 64000, 88200, 96000 | ||
262 | }; | ||
263 | 342 | ||
264 | /* Return SPDIF sample rate. Since we base our reading on the actual SPDIF | 343 | unsigned long audio_num_recorded_bytes(void) |
265 | * sample rate (which might be a bit inaccurate), we round off to the closest | ||
266 | * sample rate that is supported by SPDIF. | ||
267 | */ | ||
268 | unsigned long audio_get_spdif_sample_rate(void) | ||
269 | { | 344 | { |
270 | int i = 0; | 345 | if (!is_recording) |
271 | unsigned long measured_rate; | 346 | return 0; |
272 | const int upper_bound = sizeof(spdif_sample_rates)/sizeof(long) - 1; | 347 | |
348 | return num_rec_bytes; | ||
349 | } /* audio_num_recorded_bytes */ | ||
273 | 350 | ||
351 | #ifdef HAVE_SPDIF_IN | ||
352 | /* Return current SPDIF sample rate */ | ||
353 | static unsigned long measure_spdif_sample_rate(void) | ||
354 | { | ||
274 | /* The following formula is specified in MCF5249 user's manual section | 355 | /* The following formula is specified in MCF5249 user's manual section |
275 | * 17.6.1. The 3*(1 << 13) part will need changing if the setup of the | 356 | * 17.6.1. The 128 divide is because of the fact that the SPDIF clock is |
276 | * PHASECONFIG register is ever changed. The 128 divide is because of the | 357 | * the sample rate times 128. Keep "3*(1 << 13)" part in sync with |
277 | * fact that the SPDIF clock is the sample rate times 128. | 358 | * PHASECONFIG setup in pcm_init_recording in pcm-coldfire.c. |
278 | */ | 359 | */ |
279 | measured_rate = (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ/ | 360 | return (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ / |
280 | ((1 << 15)*3*(1 << 13))/128); | 361 | ((1 << 15)*3*(1 << 13))/128); |
281 | /* Find which SPDIF sample rate we're closest to. */ | 362 | } /* measure_spdif_sample_rate */ |
282 | while (spdif_sample_rates[i] < measured_rate && i < upper_bound) ++i; | ||
283 | if (i > 0 && i < upper_bound) | ||
284 | { | ||
285 | long diff1 = measured_rate - spdif_sample_rates[i - 1]; | ||
286 | long diff2 = spdif_sample_rates[i] - measured_rate; | ||
287 | 363 | ||
288 | if (diff2 > diff1) --i; | 364 | /** |
289 | } | 365 | * Return SPDIF sample rate index in audio_master_sampr_list. Since we base |
290 | return i; | 366 | * our reading on the actual SPDIF sample rate (which might be a bit |
291 | } | 367 | * inaccurate), we round off to the closest sample rate that is supported by |
292 | #endif | 368 | * SPDIF. |
369 | */ | ||
370 | int audio_get_spdif_sample_rate(void) | ||
371 | { | ||
372 | unsigned long measured_rate = measure_spdif_sample_rate(); | ||
373 | /* Find which SPDIF sample rate we're closest to. */ | ||
374 | return round_value_to_list32(measured_rate, audio_master_sampr_list, | ||
375 | SAMPR_NUM_FREQ, false); | ||
376 | } /* audio_get_spdif_sample_rate */ | ||
293 | 377 | ||
294 | #if 0 | ||
295 | /* not needed atm */ | ||
296 | #ifdef HAVE_SPDIF_POWER | 378 | #ifdef HAVE_SPDIF_POWER |
297 | static bool spdif_power_setting; | 379 | static bool spdif_power_setting; |
298 | 380 | ||
299 | void audio_set_spdif_power_setting(bool on) | 381 | void audio_set_spdif_power_setting(bool on) |
300 | { | 382 | { |
301 | spdif_power_setting = on; | 383 | spdif_power_setting = on; |
302 | } | 384 | } /* audio_set_spdif_power_setting */ |
385 | |||
386 | bool audio_get_spdif_power_setting(void) | ||
387 | { | ||
388 | return spdif_power_setting; | ||
389 | } /* audio_get_spdif_power_setting */ | ||
303 | #endif | 390 | #endif |
391 | |||
392 | void audio_spdif_set_monitor(int monitor_spdif) | ||
393 | { | ||
394 | EBU1CONFIG = 0x800; /* Reset before reprogram */ | ||
395 | |||
396 | if (monitor_spdif > 0) | ||
397 | { | ||
398 | #ifdef HAVE_SPDIF_POWER | ||
399 | EBU1CONFIG = spdif_power_setting ? (1 << 2) : 0; | ||
400 | /* Input source is EBUin1, Feed-through monitoring if desired */ | ||
401 | #else | ||
402 | EBU1CONFIG = (1 << 2); | ||
403 | /* Input source is EBUin1, Feed-through monitoring */ | ||
304 | #endif | 404 | #endif |
405 | } | ||
406 | else if (monitor_spdif == 0) | ||
407 | { | ||
408 | /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ | ||
409 | EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); | ||
410 | } | ||
411 | } /* audio_spdif_set_monitor */ | ||
412 | |||
413 | #endif /* HAVE_SPDIF_IN */ | ||
305 | 414 | ||
306 | /** | 415 | /** |
307 | * Sets recording parameters | 416 | * Sets recording parameters |
308 | * | ||
309 | * This functions starts feeding the CPU with audio data over the I2S bus | ||
310 | */ | 417 | */ |
311 | void audio_set_recording_options(int frequency, int quality, | 418 | void audio_set_recording_options(struct audio_recording_options *options) |
312 | int source, int channel_mode, | ||
313 | bool editable, int prerecord_time) | ||
314 | { | 419 | { |
315 | /* TODO: */ | 420 | pcm_thread_wait_for_stop(); |
316 | (void)editable; | ||
317 | 421 | ||
318 | /* NOTE: Coldfire UDA based recording does not yet support anything other | 422 | /* stop DMA transfer */ |
319 | * than 44.1kHz sampling rate, so we limit it to that case here now. SPDIF | 423 | dma_lock = true; |
320 | * based recording will overwrite this value with the proper sample rate in | 424 | pcm_stop_recording(); |
321 | * audio_record(), and will not be affected by this. | ||
322 | */ | ||
323 | frequency = 44100; | ||
324 | enc_quality = quality; | ||
325 | rec_source = source; | ||
326 | enc_channels = channel_mode == CHN_MODE_MONO ? 1 : 2; | ||
327 | pre_record_ticks = prerecord_time * HZ; | ||
328 | 425 | ||
329 | switch (source) | 426 | rec_frequency = options->rec_frequency; |
330 | { | 427 | rec_source = options->rec_source; |
331 | case AUDIO_SRC_MIC: | 428 | num_channels = options->rec_channels == 1 ? 1 : 2; |
332 | case AUDIO_SRC_LINEIN: | 429 | pre_record_ticks = options->rec_prerecord_time * HZ; |
333 | #ifdef HAVE_FMRADIO_IN | 430 | enc_config = options->enc_config; |
334 | case AUDIO_SRC_FMRADIO: | 431 | enc_config.afmt = rec_format_afmt[enc_config.rec_format]; |
335 | #endif | ||
336 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | ||
337 | DATAINCONTROL = 0xc020; | ||
338 | break; | ||
339 | 432 | ||
340 | #ifdef HAVE_SPDIF_IN | 433 | #ifdef HAVE_SPDIF_IN |
341 | case AUDIO_SRC_SPDIF: | 434 | if (rec_source == AUDIO_SRC_SPDIF) |
342 | /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ | 435 | { |
343 | DATAINCONTROL = 0xc038; | 436 | /* must measure SPDIF sample rate before configuring codecs */ |
344 | break; | 437 | unsigned long sr = measure_spdif_sample_rate(); |
345 | #endif /* HAVE_SPDIF_IN */ | 438 | /* round to master list for SPDIF rate */ |
439 | int index = round_value_to_list32(sr, audio_master_sampr_list, | ||
440 | SAMPR_NUM_FREQ, false); | ||
441 | sample_rate = audio_master_sampr_list[index]; | ||
442 | /* round to HW playback rates for monitoring */ | ||
443 | index = round_value_to_list32(sr, hw_freq_sampr, | ||
444 | HW_NUM_FREQ, false); | ||
445 | pcm_set_frequency(hw_freq_sampr[index]); | ||
446 | /* encoders with a limited number of rates do their own rounding */ | ||
447 | } | ||
448 | else | ||
449 | #endif | ||
450 | { | ||
451 | /* set sample rate from frequency selection */ | ||
452 | sample_rate = rec_freq_sampr[rec_frequency]; | ||
453 | pcm_set_frequency(sample_rate); | ||
346 | } | 454 | } |
347 | 455 | ||
348 | sample_rate = frequency; | 456 | pcm_set_monitor(rec_source); |
349 | 457 | pcm_set_rec_source(rec_source); | |
350 | /* Monitoring: route the signals through the coldfire audio interface. */ | ||
351 | 458 | ||
352 | SET_IIS_PLAY(0x800); /* Reset before reprogram */ | 459 | /* apply pcm settings to hardware */ |
460 | pcm_apply_settings(true); | ||
353 | 461 | ||
354 | #ifdef HAVE_SPDIF_IN | 462 | if (audio_load_encoder(enc_config.afmt)) |
355 | if (source == AUDIO_SRC_SPDIF) | ||
356 | { | 463 | { |
357 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ | 464 | /* start DMA transfer */ |
358 | IIS2CONFIG = (6 << 12) | (7 << 8) | (4 << 2); | 465 | pcm_record_data(pcm_rec_have_more, NULL, 0); |
359 | /* S/PDIF feed-through already configured */ | 466 | /* do unlock after starting to prevent preincrement of dma_wr_pos */ |
467 | dma_lock = pre_record_ticks == 0; | ||
360 | } | 468 | } |
361 | else | 469 | else |
362 | { | 470 | { |
363 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | 471 | logf("set rec opt: enc load failed"); |
364 | IIS2CONFIG = (8 << 12) | (4 << 8) | (4 << 2); | 472 | is_error = true; |
365 | |||
366 | EBU1CONFIG = 0x800; /* Reset before reprogram */ | ||
367 | /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ | ||
368 | EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); | ||
369 | } | ||
370 | #else | ||
371 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | ||
372 | SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); | ||
373 | #endif | ||
374 | |||
375 | audio_load_encoder(rec_quality_info_afmt[quality]); | ||
376 | } | 473 | } |
377 | 474 | } /* audio_set_recording_options */ | |
378 | 475 | ||
379 | /** | 476 | /** |
380 | * Note that microphone is mono, only left value is used | 477 | * Note that microphone is mono, only left value is used |
@@ -391,8 +488,7 @@ void audio_set_recording_gain(int left, int right, int type) | |||
391 | #elif defined (HAVE_TLV320) | 488 | #elif defined (HAVE_TLV320) |
392 | tlv320_set_recvol(left, right, type); | 489 | tlv320_set_recvol(left, right, type); |
393 | #endif | 490 | #endif |
394 | } | 491 | } /* audio_set_recording_gain */ |
395 | |||
396 | 492 | ||
397 | /** | 493 | /** |
398 | * Start recording | 494 | * Start recording |
@@ -401,585 +497,882 @@ void audio_set_recording_gain(int left, int right, int type) | |||
401 | */ | 497 | */ |
402 | void audio_record(const char *filename) | 498 | void audio_record(const char *filename) |
403 | { | 499 | { |
500 | logf("audio_record: %s", filename); | ||
501 | |||
502 | pcm_thread_wait_for_stop(); | ||
503 | pcm_thread_sync_post(PCMREC_START, (void *)filename); | ||
504 | |||
505 | logf("audio_record_done"); | ||
506 | } /* audio_record */ | ||
507 | |||
508 | void audio_new_file(const char *filename) | ||
509 | { | ||
510 | logf("audio_new_file: %s", filename); | ||
511 | |||
512 | pcm_thread_wait_for_stop(); | ||
513 | pcm_thread_sync_post(PCMREC_NEW_FILE, (void *)filename); | ||
514 | |||
515 | logf("audio_new_file done"); | ||
516 | } /* audio_new_file */ | ||
517 | |||
518 | void audio_stop_recording(void) | ||
519 | { | ||
520 | logf("audio_stop_recording"); | ||
521 | |||
522 | pcm_thread_wait_for_stop(); | ||
523 | |||
404 | if (is_recording) | 524 | if (is_recording) |
405 | { | 525 | dma_lock = true; /* fix DMA write ptr at current position */ |
406 | logf("record while recording"); | 526 | |
407 | return; | 527 | pcm_thread_sync_post(PCMREC_STOP, NULL); |
408 | } | 528 | |
529 | logf("audio_stop_recording done"); | ||
530 | } /* audio_stop_recording */ | ||
531 | |||
532 | void audio_pause_recording(void) | ||
533 | { | ||
534 | logf("audio_pause_recording"); | ||
409 | 535 | ||
410 | strncpy(recording_filename, filename, MAX_PATH - 1); | 536 | pcm_thread_wait_for_stop(); |
411 | recording_filename[MAX_PATH - 1] = 0; | ||
412 | 537 | ||
413 | #ifdef HAVE_SPDIF_IN | 538 | if (is_recording) |
414 | if (rec_source == AUDIO_SRC_SPDIF) | 539 | dma_lock = true; /* fix DMA write ptr at current position */ |
415 | sample_rate = audio_get_spdif_sample_rate(); | ||
416 | #endif | ||
417 | 540 | ||
418 | record_done = false; | 541 | pcm_thread_sync_post(PCMREC_PAUSE, NULL); |
419 | queue_post(&pcmrec_queue, PCMREC_START, 0); | 542 | logf("audio_pause_recording done"); |
543 | } /* audio_pause_recording */ | ||
420 | 544 | ||
421 | while(!record_done) | 545 | void audio_resume_recording(void) |
422 | sleep_thread(1); | 546 | { |
423 | } | 547 | logf("audio_resume_recording"); |
424 | 548 | ||
549 | pcm_thread_wait_for_stop(); | ||
550 | pcm_thread_sync_post(PCMREC_RESUME, NULL); | ||
425 | 551 | ||
426 | void audio_new_file(const char *filename) | 552 | logf("audio_resume_recording done"); |
553 | } /* audio_resume_recording */ | ||
554 | |||
555 | /***************************************************************************/ | ||
556 | /* */ | ||
557 | /* Functions that execute in the context of pcmrec_thread */ | ||
558 | /* */ | ||
559 | /***************************************************************************/ | ||
560 | |||
561 | /** Filename Queue **/ | ||
562 | |||
563 | /* returns true if the queue is empty */ | ||
564 | static inline bool pcmrec_fnq_is_empty(void) | ||
427 | { | 565 | { |
428 | logf("pcm_new_file"); | 566 | return fnq_rd_pos == fnq_wr_pos; |
567 | } /* pcmrec_fnq_is_empty */ | ||
568 | |||
569 | /* empties the filename queue */ | ||
570 | static inline void pcmrec_fnq_set_empty(void) | ||
571 | { | ||
572 | fnq_rd_pos = fnq_wr_pos; | ||
573 | } /* pcmrec_fnq_set_empty */ | ||
429 | 574 | ||
430 | new_file_done = false; | 575 | /* returns true if the queue is full */ |
576 | static bool pcmrec_fnq_is_full(void) | ||
577 | { | ||
578 | ssize_t size = fnq_wr_pos - fnq_rd_pos; | ||
579 | if (size < 0) | ||
580 | size += fnq_size; | ||
431 | 581 | ||
432 | strncpy(recording_filename, filename, MAX_PATH - 1); | 582 | return size >= fnq_size - MAX_PATH; |
433 | recording_filename[MAX_PATH - 1] = 0; | 583 | } /* pcmrec_fnq_is_full */ |
434 | 584 | ||
435 | queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); | 585 | /* queue another filename - will overwrite oldest one if full */ |
586 | static bool pcmrec_fnq_add_filename(const char *filename) | ||
587 | { | ||
588 | strncpy(fn_queue + fnq_wr_pos, filename, MAX_PATH); | ||
436 | 589 | ||
437 | while(!new_file_done) | 590 | if ((fnq_wr_pos += MAX_PATH) >= fnq_size) |
438 | sleep_thread(1); | 591 | fnq_wr_pos = 0; |
439 | 592 | ||
440 | logf("pcm_new_file done"); | 593 | if (fnq_rd_pos != fnq_wr_pos) |
441 | } | 594 | return true; |
442 | 595 | ||
443 | /** | 596 | /* queue full */ |
444 | * | 597 | if ((fnq_rd_pos += MAX_PATH) >= fnq_size) |
445 | */ | 598 | fnq_rd_pos = 0; |
446 | void audio_stop_recording(void) | 599 | |
600 | return true; | ||
601 | } /* pcmrec_fnq_add_filename */ | ||
602 | |||
603 | /* replace the last filename added */ | ||
604 | static bool pcmrec_fnq_replace_tail(const char *filename) | ||
447 | { | 605 | { |
448 | if (!is_recording) | 606 | int pos; |
449 | return; | 607 | |
608 | if (pcmrec_fnq_is_empty()) | ||
609 | return false; | ||
610 | |||
611 | pos = fnq_wr_pos - MAX_PATH; | ||
612 | if (pos < 0) | ||
613 | pos = fnq_size - MAX_PATH; | ||
614 | |||
615 | strncpy(fn_queue + pos, filename, MAX_PATH); | ||
616 | |||
617 | return true; | ||
618 | } /* pcmrec_fnq_replace_tail */ | ||
450 | 619 | ||
451 | logf("pcm_stop"); | 620 | /* pulls the next filename from the queue */ |
621 | static bool pcmrec_fnq_get_filename(char *filename) | ||
622 | { | ||
623 | if (pcmrec_fnq_is_empty()) | ||
624 | return false; | ||
625 | |||
626 | if (filename) | ||
627 | strncpy(filename, fn_queue + fnq_rd_pos, MAX_PATH); | ||
452 | 628 | ||
453 | is_paused = true; /* fix pcm write ptr at current position */ | 629 | if ((fnq_rd_pos += MAX_PATH) >= fnq_size) |
454 | stop_done = false; | 630 | fnq_rd_pos = 0; |
455 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | ||
456 | 631 | ||
457 | while(!stop_done) | 632 | return true; |
458 | sleep_thread(1); | 633 | } /* pcmrec_fnq_get_filename */ |
459 | 634 | ||
460 | logf("pcm_stop done"); | 635 | /* close the file number pointed to by fd_p */ |
461 | } | 636 | static void pcmrec_close_file(int *fd_p) |
637 | { | ||
638 | if (*fd_p < 0) | ||
639 | return; /* preserve error */ | ||
462 | 640 | ||
463 | void audio_pause_recording(void) | 641 | close(*fd_p); |
642 | *fd_p = -1; | ||
643 | } /* pcmrec_close_file */ | ||
644 | |||
645 | /** Data Flushing **/ | ||
646 | |||
647 | /** | ||
648 | * called after callback to update sizes if codec changed the amount of data | ||
649 | * a chunk represents | ||
650 | */ | ||
651 | static inline void pcmrec_update_sizes_inl(size_t prev_enc_size, | ||
652 | unsigned long prev_num_pcm) | ||
464 | { | 653 | { |
465 | if (!is_recording) | 654 | if (rec_fdata.new_enc_size != prev_enc_size) |
466 | { | 655 | { |
467 | logf("pause when not recording"); | 656 | ssize_t size_diff = rec_fdata.new_enc_size - prev_enc_size; |
468 | return; | 657 | num_rec_bytes += size_diff; |
658 | accum_rec_bytes += size_diff; | ||
469 | } | 659 | } |
470 | if (is_paused) | 660 | |
661 | if (rec_fdata.new_num_pcm != prev_num_pcm) | ||
471 | { | 662 | { |
472 | logf("pause when paused"); | 663 | unsigned long pcm_diff = rec_fdata.new_num_pcm - prev_num_pcm; |
473 | return; | 664 | num_rec_samples += pcm_diff; |
665 | accum_pcm_samples += pcm_diff; | ||
474 | } | 666 | } |
475 | 667 | } /* pcmrec_update_sizes_inl */ | |
476 | pause_done = false; | ||
477 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | ||
478 | 668 | ||
479 | while(!pause_done) | 669 | /* don't need to inline every instance */ |
480 | sleep_thread(1); | 670 | static void pcmrec_update_sizes(size_t prev_enc_size, |
481 | } | 671 | unsigned long prev_num_pcm) |
672 | { | ||
673 | pcmrec_update_sizes_inl(prev_enc_size, prev_num_pcm); | ||
674 | } /* pcmrec_update_sizes */ | ||
482 | 675 | ||
483 | void audio_resume_recording(void) | 676 | static void pcmrec_start_file(void) |
484 | { | 677 | { |
485 | if (!is_paused) | 678 | size_t enc_size = rec_fdata.new_enc_size; |
679 | unsigned long num_pcm = rec_fdata.new_num_pcm; | ||
680 | int curr_rec_file = rec_fdata.rec_file; | ||
681 | char filename[MAX_PATH]; | ||
682 | |||
683 | /* must always pull the filename that matches with this queue */ | ||
684 | if (!pcmrec_fnq_get_filename(filename)) | ||
486 | { | 685 | { |
487 | logf("resume when not paused"); | 686 | logf("start file: fnq empty"); |
488 | return; | 687 | *filename = '\0'; |
688 | is_error = true; | ||
689 | } | ||
690 | else if (is_error) | ||
691 | { | ||
692 | logf("start file: is_error already"); | ||
693 | } | ||
694 | else if (curr_rec_file >= 0) | ||
695 | { | ||
696 | /* Any previous file should have been closed */ | ||
697 | logf("start file: file already open"); | ||
698 | is_error = true; | ||
489 | } | 699 | } |
490 | 700 | ||
491 | resume_done = false; | 701 | if (is_error) |
492 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | 702 | rec_fdata.chunk->flags |= CHUNKF_ERROR; |
493 | 703 | ||
494 | while(!resume_done) | 704 | /* encoder can set error flag here and should increase |
495 | sleep_thread(1); | 705 | enc_new_size and pcm_new_size to reflect additional |
496 | } | 706 | data written if any */ |
707 | rec_fdata.filename = filename; | ||
708 | enc_events_callback(ENC_START_FILE, &rec_fdata); | ||
709 | |||
710 | if (!is_error && (rec_fdata.chunk->flags & CHUNKF_ERROR)) | ||
711 | { | ||
712 | logf("start file: enc error"); | ||
713 | is_error = true; | ||
714 | } | ||
497 | 715 | ||
498 | /* return peaks as int, so convert from short first | 716 | if (is_error) |
499 | note that peak values are always positive */ | 717 | { |
500 | void pcm_rec_get_peaks(int *left, int *right) | 718 | pcmrec_close_file(&curr_rec_file); |
719 | /* Write no more to this file */ | ||
720 | rec_fdata.chunk->flags |= CHUNKF_END_FILE; | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | pcmrec_update_sizes(enc_size, num_pcm); | ||
725 | } | ||
726 | |||
727 | rec_fdata.chunk->flags &= ~CHUNKF_START_FILE; | ||
728 | } /* pcmrec_start_file */ | ||
729 | |||
730 | static inline void pcmrec_write_chunk(void) | ||
501 | { | 731 | { |
502 | if (left) | 732 | size_t enc_size = rec_fdata.new_enc_size; |
503 | *left = peak_left; | 733 | unsigned long num_pcm = rec_fdata.new_num_pcm; |
504 | if (right) | ||
505 | *right = peak_right; | ||
506 | peak_left = 0; | ||
507 | peak_right = 0; | ||
508 | } | ||
509 | 734 | ||
510 | /***************************************************************************/ | 735 | if (is_error) |
511 | /* Functions that executes in the context of pcmrec_thread */ | 736 | rec_fdata.chunk->flags |= CHUNKF_ERROR; |
512 | /***************************************************************************/ | 737 | |
738 | enc_events_callback(ENC_WRITE_CHUNK, &rec_fdata); | ||
739 | |||
740 | if ((long)rec_fdata.chunk->flags >= 0) | ||
741 | { | ||
742 | pcmrec_update_sizes_inl(enc_size, num_pcm); | ||
743 | } | ||
744 | else if (!is_error) | ||
745 | { | ||
746 | logf("wr chk enc error %d %d", | ||
747 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); | ||
748 | is_error = true; | ||
749 | } | ||
750 | } /* pcmrec_write_chunk */ | ||
751 | |||
752 | static void pcmrec_end_file(void) | ||
753 | { | ||
754 | /* all data in output buffer for current file will have been | ||
755 | written and encoder can now do any nescessary steps to | ||
756 | finalize the written file */ | ||
757 | size_t enc_size = rec_fdata.new_enc_size; | ||
758 | unsigned long num_pcm = rec_fdata.new_num_pcm; | ||
759 | |||
760 | enc_events_callback(ENC_END_FILE, &rec_fdata); | ||
761 | |||
762 | if (!is_error) | ||
763 | { | ||
764 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) | ||
765 | { | ||
766 | logf("end file: enc error"); | ||
767 | is_error = true; | ||
768 | } | ||
769 | else | ||
770 | { | ||
771 | pcmrec_update_sizes(enc_size, num_pcm); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /* Force file close if error */ | ||
776 | if (is_error) | ||
777 | pcmrec_close_file(&rec_fdata.rec_file); | ||
778 | |||
779 | rec_fdata.chunk->flags &= ~CHUNKF_END_FILE; | ||
780 | } /* pcmrec_end_file */ | ||
513 | 781 | ||
514 | /** | 782 | /** |
515 | * Process the chunks | 783 | * Process the chunks |
516 | * | 784 | * |
517 | * This function is called when queue_get_w_tmo times out. | 785 | * This function is called when queue_get_w_tmo times out. |
518 | * | 786 | * |
519 | * Other functions can also call this function with flush = true when | 787 | * Set flush_num to the number of files to flush to disk. |
520 | * they want to save everything in the buffers to disk. | 788 | * flush_num = -1 to flush all available chunks to disk. |
789 | * flush_num = 0 normal write thresholding | ||
790 | * flush_num = 1 or greater - all available chunks of current file plus | ||
791 | * flush_num file starts if first chunk has been processed. | ||
521 | * | 792 | * |
522 | */ | 793 | */ |
523 | static void pcmrec_callback(bool flush) | 794 | static void pcmrec_flush(unsigned flush_num) |
524 | { | 795 | { |
525 | int i, num_ready, size_yield; | 796 | static unsigned long last_flush_tick = 0; |
526 | long *enc_chunk, chunk_size; | 797 | unsigned long start_tick; |
527 | 798 | int num_ready, num; | |
528 | if (!is_recording && !flush) | 799 | int prio; |
529 | return; | 800 | int i; |
530 | 801 | ||
531 | num_ready = enc_wr_index - enc_rd_index; | 802 | num_ready = enc_wr_index - enc_rd_index; |
532 | if (num_ready < 0) | 803 | if (num_ready < 0) |
533 | num_ready += enc_num_chunks; | 804 | num_ready += enc_num_chunks; |
534 | 805 | ||
535 | /* calculate an estimate of recorded bytes */ | 806 | num = num_ready; |
536 | num_rec_bytes = num_file_bytes + num_ready * /* enc_chunk_size */ | ||
537 | ((avrg_bit_rate * 1000 / 8 * enc_samp_per_chunk + 22050) / 44100); | ||
538 | 807 | ||
539 | /* near full state reached: less than 5sec remaining space */ | 808 | if (flush_num == 0) |
540 | if (enc_num_chunks - num_ready < WRITE_THRESHOLD || flush) | ||
541 | { | 809 | { |
542 | logf("writing: %d (%d)", num_ready, flush); | 810 | if (!is_recording) |
543 | 811 | return; | |
544 | cpu_boost_id(true, CPUBOOSTID_PCMRECORD); | ||
545 | 812 | ||
546 | size_yield = 0; | 813 | if (ata_spinup_time != spinup_time) |
547 | for (i=0; i<num_ready; i++) | ||
548 | { | 814 | { |
549 | enc_chunk = GET_ENC_CHUNK(enc_rd_index); | 815 | /* spinup time has changed, calculate new write threshold */ |
550 | chunk_size = *enc_chunk++; | 816 | logf("new t spinup : %d", ata_spinup_time); |
551 | 817 | unsigned long st = spinup_time = ata_spinup_time; | |
552 | /* safety net: if size entry got corrupted => limit */ | 818 | |
553 | if (chunk_size > (long)(enc_chunk_size - sizeof(long))) | 819 | /* write at 5s + st remaining in enc_buffer */ |
554 | chunk_size = enc_chunk_size - sizeof(long); | 820 | if (st < 2*HZ) |
821 | st = 2*HZ; /* my drive is usually < 250 ticks :) */ | ||
822 | else if (st > 10*HZ) | ||
823 | st = 10*HZ; | ||
824 | |||
825 | write_threshold = enc_num_chunks - | ||
826 | (int)(((5ull*HZ + st)*4ull*sample_rate + (enc_chunk_size-1)) / | ||
827 | (enc_chunk_size*HZ)); | ||
828 | |||
829 | if (write_threshold < 0) | ||
830 | write_threshold = 0; | ||
831 | else if (write_threshold > panic_threshold) | ||
832 | write_threshold = panic_threshold; | ||
833 | |||
834 | logf("new wr thresh: %d", write_threshold); | ||
835 | } | ||
555 | 836 | ||
556 | if (enc_set_header_callback != NULL) | 837 | if (num_ready < write_threshold) |
557 | enc_set_header_callback(enc_chunk, enc_chunk_size, | 838 | return; |
558 | num_pcm_samples, false); | ||
559 | 839 | ||
560 | if (write(wav_file, enc_chunk, chunk_size) != chunk_size) | 840 | /* if we're getting called too much and this isn't forced, |
561 | { | 841 | boost stat */ |
562 | close_wave(); | 842 | if (current_tick - last_flush_tick < HZ/2) |
563 | logf("pcmrec: write err"); | 843 | num = panic_threshold; |
564 | is_error = true; | 844 | } |
565 | break; | ||
566 | } | ||
567 | 845 | ||
568 | num_file_bytes += chunk_size; | 846 | start_tick = current_tick; |
569 | num_pcm_samples += enc_samp_per_chunk; | 847 | prio = -1; |
570 | size_yield += chunk_size; | ||
571 | 848 | ||
572 | if (size_yield >= 32768) | 849 | logf("writing: %d (%d)", num_ready, flush_num); |
573 | { /* yield when 32kB written */ | 850 | |
574 | size_yield = 0; | 851 | cpu_boost_id(true, CPUBOOSTID_PCMRECORD); |
575 | yield(); | ||
576 | } | ||
577 | 852 | ||
578 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | 853 | for (i=0; i<num_ready; i++) |
854 | { | ||
855 | if (prio == -1 && (num >= panic_threshold || | ||
856 | current_tick - start_tick > 10*HZ)) | ||
857 | { | ||
858 | /* losing ground - boost priority until finished */ | ||
859 | logf("pcmrec: boost priority"); | ||
860 | prio = thread_set_priority(NULL, thread_get_priority(NULL)-1); | ||
579 | } | 861 | } |
580 | 862 | ||
581 | /* sync file */ | 863 | rec_fdata.chunk = GET_ENC_CHUNK(enc_rd_index); |
582 | fsync(wav_file); | 864 | rec_fdata.new_enc_size = rec_fdata.chunk->enc_size; |
865 | rec_fdata.new_num_pcm = rec_fdata.chunk->num_pcm; | ||
583 | 866 | ||
584 | cpu_boost_id(false, CPUBOOSTID_PCMRECORD); | 867 | if (rec_fdata.chunk->flags & CHUNKF_START_FILE) |
868 | { | ||
869 | pcmrec_start_file(); | ||
870 | if (--flush_num == 0) | ||
871 | i = num_ready; /* stop on next loop - must write this | ||
872 | chunk if it has data */ | ||
873 | } | ||
585 | 874 | ||
586 | logf("done"); | 875 | pcmrec_write_chunk(); |
587 | } | ||
588 | } | ||
589 | 876 | ||
590 | /* Abort dma transfer */ | 877 | if (rec_fdata.chunk->flags & CHUNKF_END_FILE) |
591 | static void pcmrec_dma_stop(void) | 878 | pcmrec_end_file(); |
592 | { | ||
593 | DCR1 = 0; | ||
594 | 879 | ||
595 | error_count++; | 880 | INC_ENC_INDEX(enc_rd_index); |
596 | 881 | ||
597 | DSR1 = 1; /* Clear interrupt */ | 882 | if (is_error) |
598 | IPR |= (1<<15); /* Clear pending interrupt request */ | 883 | break; |
599 | 884 | ||
600 | logf("dma1 stopped"); | 885 | if (prio == -1) |
601 | } | 886 | { |
887 | num = enc_wr_index - enc_rd_index; | ||
888 | if (num < 0) | ||
889 | num += enc_num_chunks; | ||
890 | } | ||
602 | 891 | ||
603 | static void pcmrec_dma_start(void) | 892 | /* no yielding, the file apis called in the codecs do that */ |
604 | { | 893 | } /* end for */ |
605 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | ||
606 | SAR1 = (unsigned long)&PDIR2; /* Source address */ | ||
607 | BCR1 = CHUNK_SIZE; /* Bytes to transfer */ | ||
608 | 894 | ||
609 | /* Start the DMA transfer.. */ | 895 | /* sync file */ |
610 | #ifdef HAVE_SPDIF_IN | 896 | if (rec_fdata.rec_file >= 0) |
611 | INTERRUPTCLEAR = 0x03c00000; | 897 | fsync(rec_fdata.rec_file); |
612 | #endif | 898 | |
899 | cpu_boost_id(false, CPUBOOSTID_PCMRECORD); | ||
613 | 900 | ||
614 | /* 16Byte transfers prevents from sporadic errors during cpu_boost() */ | 901 | if (prio != -1) |
615 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_DSIZE(3) | DMA_START; | 902 | { |
903 | /* return to original priority */ | ||
904 | logf("pcmrec: unboost priority"); | ||
905 | thread_set_priority(NULL, prio); | ||
906 | } | ||
616 | 907 | ||
617 | logf("dma1 started"); | 908 | last_flush_tick = current_tick; /* save tick when we left */ |
618 | } | 909 | logf("done"); |
910 | } /* pcmrec_flush */ | ||
619 | 911 | ||
620 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */ | 912 | /** |
621 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); | 913 | * Marks a new stream in the buffer and gives the encoder a chance for special |
622 | void DMA1(void) | 914 | * handling of transition from one to the next. The encoder may change the |
915 | * chunk that ends the old stream by requesting more chunks and similiarly for | ||
916 | * the new but must always advance the position though the interface. It can | ||
917 | * later reject any data it cares to when writing the file but should mark the | ||
918 | * chunk so it can recognize this. ENC_WRITE_CHUNK event must be able to accept | ||
919 | * a NULL data pointer without error as well. | ||
920 | */ | ||
921 | static void pcmrec_new_stream(const char *filename, /* next file name */ | ||
922 | unsigned long flags, /* CHUNKF_* flags */ | ||
923 | int pre_index) /* index for prerecorded data */ | ||
623 | { | 924 | { |
624 | int res = DSR1; | 925 | logf("pcmrec_new_stream"); |
625 | 926 | ||
626 | DSR1 = 1; /* Clear interrupt */ | 927 | struct enc_buffer_event_data data; |
928 | bool (*fnq_add_fn)(const char *) = NULL; | ||
929 | struct enc_chunk_hdr *start = NULL; | ||
627 | 930 | ||
628 | if (res & 0x70) | 931 | int get_chunk_index(struct enc_chunk_hdr *chunk) |
629 | { | 932 | { |
630 | DCR1 = 0; /* Stop DMA transfer */ | 933 | return ((char *)chunk - (char *)enc_buffer) / enc_chunk_size; |
631 | error_count++; | 934 | } |
632 | |||
633 | logf("dma1 err: 0x%x", res); | ||
634 | |||
635 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | ||
636 | BCR1 = CHUNK_SIZE; | ||
637 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; | ||
638 | 935 | ||
639 | /* Flush recorded data to disk and stop recording */ | 936 | struct enc_chunk_hdr * get_prev_chunk(int index) |
640 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
641 | } | ||
642 | #ifdef HAVE_SPDIF_IN | ||
643 | else if ((rec_source == AUDIO_SRC_SPDIF) && | ||
644 | (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ | ||
645 | { | 937 | { |
646 | INTERRUPTCLEAR = 0x03c00000; | 938 | DEC_ENC_INDEX(index); |
647 | error_count++; | 939 | return GET_ENC_CHUNK(index); |
940 | } | ||
648 | 941 | ||
649 | logf("spdif err"); | 942 | data.pre_chunk = NULL; |
943 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | ||
650 | 944 | ||
651 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | 945 | /* end chunk */ |
652 | BCR1 = CHUNK_SIZE; | 946 | if (flags & CHUNKF_END_FILE) |
653 | } | ||
654 | #endif | ||
655 | else | ||
656 | { | 947 | { |
657 | long peak_l, peak_r; | 948 | data.chunk->flags &= CHUNKF_START_FILE | CHUNKF_END_FILE; |
658 | long *ptr, j; | ||
659 | |||
660 | ptr = GET_CHUNK(write_pos); | ||
661 | 949 | ||
662 | if (!is_paused) /* advance write position */ | 950 | if (data.chunk->flags & CHUNKF_START_FILE) |
663 | write_pos = (write_pos + CHUNK_SIZE) & CHUNK_MASK; | 951 | { |
952 | /* cannot start and end on same unprocessed chunk */ | ||
953 | logf("file end on start"); | ||
954 | flags &= ~CHUNKF_END_FILE; | ||
955 | } | ||
956 | else if (enc_rd_index == enc_wr_index) | ||
957 | { | ||
958 | /* all data flushed but file not ended - chunk will be left | ||
959 | empty */ | ||
960 | logf("end on dead end"); | ||
961 | data.chunk->flags = 0; | ||
962 | data.chunk->enc_size = 0; | ||
963 | data.chunk->num_pcm = 0; | ||
964 | data.chunk->enc_data = NULL; | ||
965 | INC_ENC_INDEX(enc_wr_index); | ||
966 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | ||
967 | } | ||
968 | else | ||
969 | { | ||
970 | struct enc_chunk_hdr *last = get_prev_chunk(enc_wr_index); | ||
664 | 971 | ||
665 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ | 972 | if (last->flags & CHUNKF_END_FILE) |
666 | BCR1 = CHUNK_SIZE; | 973 | { |
974 | /* end already processed and marked - can't end twice */ | ||
975 | logf("file end again"); | ||
976 | flags &= ~CHUNKF_END_FILE; | ||
977 | } | ||
978 | } | ||
979 | } | ||
667 | 980 | ||
668 | peak_l = peak_r = 0; | 981 | /* start chunk */ |
982 | if (flags & CHUNKF_START_FILE) | ||
983 | { | ||
984 | bool pre = flags & CHUNKF_PRERECORD; | ||
669 | 985 | ||
670 | /* only peak every 4th sample */ | 986 | if (pre) |
671 | for (j=0; j<CHUNK_SIZE/4; j+=4) | ||
672 | { | 987 | { |
673 | long value = ptr[j]; | 988 | logf("stream prerecord start"); |
674 | #ifdef ROCKBOX_BIG_ENDIAN | 989 | start = data.pre_chunk = GET_ENC_CHUNK(pre_index); |
675 | if (value > peak_l) peak_l = value; | 990 | start->flags &= CHUNKF_START_FILE | CHUNKF_PRERECORD; |
676 | else if (-value > peak_l) peak_l = -value; | 991 | } |
677 | 992 | else | |
678 | value <<= 16; | 993 | { |
679 | if (value > peak_r) peak_r = value; | 994 | logf("stream normal start"); |
680 | else if (-value > peak_r) peak_r = -value; | 995 | start = data.chunk; |
681 | #else | 996 | start->flags &= CHUNKF_START_FILE; |
682 | if (value > peak_r) peak_r = value; | ||
683 | else if (-value > peak_r) peak_r = -value; | ||
684 | |||
685 | value <<= 16; | ||
686 | if (value > peak_l) peak_l = value; | ||
687 | else if (-value > peak_l) peak_l = -value; | ||
688 | #endif | ||
689 | } | 997 | } |
690 | 998 | ||
691 | peak_left = (int)(peak_l >> 16); | 999 | /* if encoder hasn't yet processed the last start - abort the start |
692 | peak_right = (int)(peak_r >> 16); | 1000 | of the previous file queued or else it will be empty and invalid */ |
1001 | if (start->flags & CHUNKF_START_FILE) | ||
1002 | { | ||
1003 | logf("replacing fnq tail: %s", filename); | ||
1004 | fnq_add_fn = pcmrec_fnq_replace_tail; | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | logf("adding filename: %s", filename); | ||
1009 | fnq_add_fn = pcmrec_fnq_add_filename; | ||
1010 | } | ||
693 | } | 1011 | } |
694 | 1012 | ||
695 | IPR |= (1<<15); /* Clear pending interrupt request */ | 1013 | data.flags = flags; |
696 | } | 1014 | enc_events_callback(ENC_REC_NEW_STREAM, &data); |
697 | |||
698 | /* Create WAVE file and write header */ | ||
699 | /* Sets returns 0 if success, -1 on failure */ | ||
700 | static int start_wave(void) | ||
701 | { | ||
702 | wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC); | ||
703 | 1015 | ||
704 | if (wav_file < 0) | 1016 | if (flags & CHUNKF_END_FILE) |
705 | { | 1017 | { |
706 | wav_file = -1; | 1018 | int i = get_chunk_index(data.chunk); |
707 | logf("rec: create failed: %d", wav_file); | 1019 | get_prev_chunk(i)->flags |= CHUNKF_END_FILE; |
708 | is_error = true; | ||
709 | return -1; | ||
710 | } | 1020 | } |
711 | 1021 | ||
712 | /* add main file header (enc_head_size=0 for encoders without) */ | 1022 | if (start) |
713 | if (enc_head_size != write(wav_file, enc_head_buffer, enc_head_size)) | ||
714 | { | 1023 | { |
715 | close(wav_file); | 1024 | if (!(flags & CHUNKF_PRERECORD)) |
716 | wav_file = -1; | 1025 | { |
717 | logf("rec: write failed"); | 1026 | /* get stats on data added to start - sort of a prerecord operation */ |
718 | is_error = true; | 1027 | int i = get_chunk_index(data.chunk); |
719 | return -1; | 1028 | struct enc_chunk_hdr *chunk = data.chunk; |
720 | } | ||
721 | 1029 | ||
722 | return 0; | 1030 | logf("start data: %d %d", i, enc_wr_index); |
723 | } | ||
724 | 1031 | ||
725 | /* Update header and set correct length values */ | 1032 | num_rec_bytes = 0; |
726 | static void close_wave(void) | 1033 | num_rec_samples = 0; |
727 | { | ||
728 | unsigned char head[100]; /* assume maximum 100 bytes for file header */ | ||
729 | int size_read; | ||
730 | 1034 | ||
731 | if (wav_file != -1) | 1035 | while (i != enc_wr_index) |
732 | { | 1036 | { |
733 | /* update header before closing the file (wav+wv encoder will do) */ | 1037 | num_rec_bytes += chunk->enc_size; |
734 | if (enc_set_header_callback != NULL) | 1038 | num_rec_samples += chunk->num_pcm; |
735 | { | 1039 | INC_ENC_INDEX(i); |
736 | lseek(wav_file, 0, SEEK_SET); | 1040 | chunk = GET_ENC_CHUNK(i); |
737 | /* try to read the head size (but we'll accept less) */ | 1041 | } |
738 | size_read = read(wav_file, head, sizeof(head)); | 1042 | |
1043 | start->flags &= ~CHUNKF_START_FILE; | ||
1044 | start = data.chunk; | ||
1045 | } | ||
1046 | |||
1047 | start->flags |= CHUNKF_START_FILE; | ||
739 | 1048 | ||
740 | enc_set_header_callback(head, size_read, num_pcm_samples, true); | 1049 | /* flush one file out if full and adding */ |
741 | lseek(wav_file, 0, SEEK_SET); | 1050 | if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full()) |
742 | write(wav_file, head, size_read); | 1051 | { |
1052 | logf("fnq full: flushing 1"); | ||
1053 | pcmrec_flush(1); | ||
743 | } | 1054 | } |
744 | close(wav_file); | 1055 | |
745 | wav_file = -1; | 1056 | fnq_add_fn(filename); |
746 | } | 1057 | } |
747 | } | 1058 | } /* pcmrec_new_stream */ |
748 | 1059 | ||
749 | static void pcmrec_start(void) | 1060 | /** event handlers for pcmrec thread */ |
1061 | |||
1062 | /* PCMREC_INIT */ | ||
1063 | static void pcmrec_init(void) | ||
750 | { | 1064 | { |
751 | long max_pre_chunks, pre_ticks, max_pre_ticks; | 1065 | rec_fdata.rec_file = -1; |
1066 | |||
1067 | /* pcm FIFO */ | ||
1068 | dma_lock = true; | ||
1069 | pcm_rd_pos = 0; | ||
1070 | dma_wr_pos = 0; | ||
1071 | |||
1072 | /* encoder FIFO */ | ||
1073 | enc_wr_index = 0; | ||
1074 | enc_rd_index = 0; | ||
1075 | |||
1076 | /* filename queue */ | ||
1077 | fnq_rd_pos = 0; | ||
1078 | fnq_wr_pos = 0; | ||
1079 | |||
1080 | /* stats */ | ||
1081 | num_rec_bytes = 0; | ||
1082 | num_rec_samples = 0; | ||
1083 | accum_rec_bytes = 0; | ||
1084 | accum_pcm_samples = 0; | ||
1085 | |||
1086 | pcm_thread_unsignal_event(PCMREC_CLOSE); | ||
1087 | is_recording = false; | ||
1088 | is_paused = false; | ||
1089 | is_stopping = false; | ||
1090 | is_error = false; | ||
1091 | |||
1092 | pcm_buffer = audio_get_recording_buffer(&rec_buffer_size); | ||
1093 | /* Line align pcm_buffer 2^4=16 bytes */ | ||
1094 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned)pcm_buffer, 4); | ||
1095 | enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + | ||
1096 | PCM_MAX_FEED_SIZE, 2); | ||
1097 | |||
1098 | pcm_init_recording(); | ||
1099 | pcm_thread_signal_event(PCMREC_INIT); | ||
1100 | } /* pcmrec_init */ | ||
1101 | |||
1102 | /* PCMREC_CLOSE */ | ||
1103 | static void pcmrec_close(void) | ||
1104 | { | ||
1105 | dma_lock = true; | ||
1106 | pcm_close_recording(); | ||
1107 | pcm_thread_unsignal_event(PCMREC_INIT); | ||
1108 | pcm_thread_signal_event(PCMREC_CLOSE); | ||
1109 | } /* pcmrec_close */ | ||
1110 | |||
1111 | /* PCMREC_START */ | ||
1112 | static void pcmrec_start(const char *filename) | ||
1113 | { | ||
1114 | unsigned long pre_sample_ticks; | ||
1115 | int rd_start; | ||
752 | 1116 | ||
753 | logf("pcmrec_start"); | 1117 | logf("pcmrec_start: %s", filename); |
754 | 1118 | ||
755 | if (is_recording) | 1119 | if (is_recording) |
756 | { | 1120 | { |
757 | logf("already recording"); | 1121 | logf("already recording"); |
758 | record_done = true; | 1122 | goto already_recording; |
759 | return; | ||
760 | } | 1123 | } |
761 | 1124 | ||
762 | if (wav_file != -1) | 1125 | /* reset stats */ |
763 | close_wave(); | 1126 | num_rec_bytes = 0; |
1127 | num_rec_samples = 0; | ||
1128 | accum_rec_bytes = 0; | ||
1129 | accum_pcm_samples = 0; | ||
1130 | spinup_time = -1; | ||
1131 | |||
1132 | rd_start = enc_wr_index; | ||
1133 | pre_sample_ticks = 0; | ||
764 | 1134 | ||
765 | if (start_wave() != 0) | 1135 | if (pre_record_ticks) |
766 | { | 1136 | { |
767 | /* failed to create the file */ | 1137 | int i; |
768 | record_done = true; | ||
769 | return; | ||
770 | } | ||
771 | 1138 | ||
772 | /* calculate maximum available chunks & resulting ticks */ | 1139 | /* calculate number of available chunks */ |
773 | max_pre_chunks = (enc_wr_index - enc_rd_index + | 1140 | unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index + |
774 | enc_num_chunks) % enc_num_chunks; | ||
775 | if (max_pre_chunks > enc_num_chunks - WRITE_THRESHOLD) | ||
776 | max_pre_chunks = enc_num_chunks - WRITE_THRESHOLD; | ||
777 | max_pre_ticks = max_pre_chunks * HZ * enc_samp_per_chunk / 44100; | ||
778 | |||
779 | /* limit prerecord if not enough data available */ | ||
780 | pre_ticks = pre_record_ticks > max_pre_ticks ? | ||
781 | max_pre_ticks : pre_record_ticks; | ||
782 | max_pre_chunks = 44100 * pre_ticks / HZ / enc_samp_per_chunk; | ||
783 | enc_rd_index = (enc_wr_index - max_pre_chunks + | ||
784 | enc_num_chunks) % enc_num_chunks; | 1141 | enc_num_chunks) % enc_num_chunks; |
1142 | /* overflow at 974 seconds of prerecording at 44.1kHz */ | ||
1143 | unsigned long pre_record_sample_ticks = enc_sample_rate*pre_record_ticks; | ||
1144 | |||
1145 | /* Get exact measure of recorded data as number of samples aren't | ||
1146 | nescessarily going to be the max for each chunk */ | ||
1147 | for (i = rd_start; avail_pre_chunks-- > 0;) | ||
1148 | { | ||
1149 | struct enc_chunk_hdr *chunk; | ||
1150 | unsigned long chunk_sample_ticks; | ||
1151 | |||
1152 | DEC_ENC_INDEX(i); | ||
1153 | |||
1154 | chunk = GET_ENC_CHUNK(i); | ||
1155 | |||
1156 | /* must have data to be counted */ | ||
1157 | if (chunk->enc_data == NULL) | ||
1158 | continue; | ||
785 | 1159 | ||
786 | record_start_time = current_tick - pre_ticks; | 1160 | chunk_sample_ticks = chunk->num_pcm*HZ; |
787 | 1161 | ||
788 | num_rec_bytes = enc_num_chunks * CHUNK_SIZE; | 1162 | rd_start = i; |
789 | num_file_bytes = 0; | 1163 | pre_sample_ticks += chunk_sample_ticks; |
790 | num_pcm_samples = 0; | 1164 | num_rec_bytes += chunk->enc_size; |
791 | pause_start_time = 0; | 1165 | num_rec_samples += chunk->num_pcm; |
1166 | |||
1167 | /* stop here if enough already */ | ||
1168 | if (pre_sample_ticks >= pre_record_sample_ticks) | ||
1169 | break; | ||
1170 | } | ||
1171 | |||
1172 | accum_rec_bytes = num_rec_bytes; | ||
1173 | accum_pcm_samples = num_rec_samples; | ||
1174 | } | ||
1175 | |||
1176 | enc_rd_index = rd_start; | ||
1177 | |||
1178 | /* filename queue should be empty */ | ||
1179 | if (!pcmrec_fnq_is_empty()) | ||
1180 | { | ||
1181 | logf("fnq: not empty!"); | ||
1182 | pcmrec_fnq_set_empty(); | ||
1183 | } | ||
792 | 1184 | ||
1185 | dma_lock = false; | ||
793 | is_paused = false; | 1186 | is_paused = false; |
794 | is_recording = true; | 1187 | is_recording = true; |
795 | record_done = true; | ||
796 | } | ||
797 | 1188 | ||
1189 | pcmrec_new_stream(filename, | ||
1190 | CHUNKF_START_FILE | | ||
1191 | (pre_sample_ticks > 0 ? CHUNKF_PRERECORD : 0), | ||
1192 | enc_rd_index); | ||
1193 | |||
1194 | already_recording: | ||
1195 | pcm_thread_signal_event(PCMREC_START); | ||
1196 | logf("pcmrec_start done"); | ||
1197 | } /* pcmrec_start */ | ||
1198 | |||
1199 | /* PCMREC_STOP */ | ||
798 | static void pcmrec_stop(void) | 1200 | static void pcmrec_stop(void) |
799 | { | 1201 | { |
800 | logf("pcmrec_stop"); | 1202 | logf("pcmrec_stop"); |
801 | 1203 | ||
802 | if (is_recording) | 1204 | if (!is_recording) |
803 | { | 1205 | { |
804 | /* wait for encoding finish */ | 1206 | logf("not recording"); |
805 | is_paused = true; | 1207 | goto not_recording_or_stopping; |
806 | while(!wav_queue_empty) | 1208 | } |
807 | sleep_thread(1); | 1209 | else if (is_stopping) |
808 | 1210 | { | |
809 | is_recording = false; | 1211 | logf("already stopping"); |
810 | 1212 | goto not_recording_or_stopping; | |
811 | /* Flush buffers to file */ | ||
812 | pcmrec_callback(true); | ||
813 | close_wave(); | ||
814 | } | 1213 | } |
815 | 1214 | ||
816 | is_paused = false; | 1215 | is_stopping = true; |
817 | stop_done = true; | 1216 | dma_lock = true; /* lock dma write position */ |
1217 | queue_post(&pcmrec_queue, PCMREC_FINISH_STOP, NULL); | ||
818 | 1218 | ||
1219 | not_recording_or_stopping: | ||
1220 | pcm_thread_signal_event(PCMREC_STOP); | ||
819 | logf("pcmrec_stop done"); | 1221 | logf("pcmrec_stop done"); |
820 | } | 1222 | } /* pcmrec_stop */ |
821 | 1223 | ||
822 | static void pcmrec_new_file(void) | 1224 | /* PCMREC_FINISH_STOP */ |
1225 | static void pcmrec_finish_stop(void) | ||
823 | { | 1226 | { |
824 | logf("pcmrec_new_file"); | 1227 | logf("pcmrec_finish_stop"); |
825 | 1228 | ||
826 | if (!is_recording) | 1229 | if (!is_stopping) |
827 | { | 1230 | { |
828 | logf("not recording"); | 1231 | logf("not stopping"); |
829 | new_file_done = true; | 1232 | goto not_stopping; |
830 | return; | ||
831 | } | 1233 | } |
832 | 1234 | ||
833 | /* Since pcmrec_callback() blocks until the data has been written, | 1235 | /* flush all available data first to avoid overflow while waiting |
834 | here is a good approximation when recording to the new file starts | 1236 | for encoding to finish */ |
835 | */ | 1237 | pcmrec_flush(-1); |
836 | record_start_time = current_tick; | ||
837 | 1238 | ||
838 | if (is_paused) | 1239 | /* wait for encoder to finish remaining data */ |
839 | pause_start_time = record_start_time; | 1240 | if (!is_error) |
1241 | { | ||
1242 | while (!wav_queue_empty) | ||
1243 | yield(); | ||
1244 | } | ||
840 | 1245 | ||
841 | /* Flush what we got in buffers to file */ | 1246 | /* end stream at last data */ |
842 | pcmrec_callback(true); | 1247 | pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0); |
843 | 1248 | ||
844 | close_wave(); | 1249 | /* flush anything else encoder added */ |
845 | 1250 | pcmrec_flush(-1); | |
846 | num_rec_bytes = 0; | 1251 | |
847 | num_file_bytes = 0; | 1252 | /* remove any pending file start not yet processed - should be at |
848 | num_pcm_samples = 0; | 1253 | most one at enc_wr_index */ |
1254 | pcmrec_fnq_get_filename(NULL); | ||
1255 | /* encoder should abort any chunk it was in midst of processing */ | ||
1256 | GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT; | ||
849 | 1257 | ||
850 | /* start the new file */ | 1258 | /* filename queue should be empty */ |
851 | if (start_wave() != 0) | 1259 | if (!pcmrec_fnq_is_empty()) |
852 | { | 1260 | { |
853 | logf("new_file failed"); | 1261 | logf("fnq: not empty!"); |
854 | pcmrec_stop(); | 1262 | pcmrec_fnq_set_empty(); |
855 | } | 1263 | } |
856 | 1264 | ||
857 | new_file_done = true; | 1265 | /* be absolutely sure the file is closed */ |
858 | logf("pcmrec_new_file done"); | 1266 | if (is_error) |
859 | } | 1267 | pcmrec_close_file(&rec_fdata.rec_file); |
1268 | rec_fdata.rec_file = -1; | ||
1269 | |||
1270 | is_recording = false; | ||
1271 | is_paused = false; | ||
1272 | is_stopping = false; | ||
1273 | dma_lock = pre_record_ticks == 0; | ||
1274 | |||
1275 | not_stopping: | ||
1276 | logf("pcmrec_finish_stop done"); | ||
1277 | } /* pcmrec_finish_stop */ | ||
860 | 1278 | ||
1279 | /* PCMREC_PAUSE */ | ||
861 | static void pcmrec_pause(void) | 1280 | static void pcmrec_pause(void) |
862 | { | 1281 | { |
863 | logf("pcmrec_pause"); | 1282 | logf("pcmrec_pause"); |
864 | 1283 | ||
865 | if (!is_recording) | 1284 | if (!is_recording) |
866 | { | 1285 | { |
867 | logf("pause: not recording"); | 1286 | logf("not recording"); |
868 | pause_done = true; | 1287 | goto not_recording_or_paused; |
869 | return; | 1288 | } |
1289 | else if (is_paused) | ||
1290 | { | ||
1291 | logf("already paused"); | ||
1292 | goto not_recording_or_paused; | ||
870 | } | 1293 | } |
871 | 1294 | ||
872 | pause_start_time = current_tick; | 1295 | dma_lock = true; /* fix DMA write pointer at current position */ |
873 | is_paused = true; | 1296 | is_paused = true; |
874 | pause_done = true; | ||
875 | 1297 | ||
1298 | not_recording_or_paused: | ||
1299 | pcm_thread_signal_event(PCMREC_PAUSE); | ||
876 | logf("pcmrec_pause done"); | 1300 | logf("pcmrec_pause done"); |
877 | } | 1301 | } /* pcmrec_pause */ |
878 | |||
879 | 1302 | ||
1303 | /* PCMREC_RESUME */ | ||
880 | static void pcmrec_resume(void) | 1304 | static void pcmrec_resume(void) |
881 | { | 1305 | { |
882 | logf("pcmrec_resume"); | 1306 | logf("pcmrec_resume"); |
883 | 1307 | ||
884 | if (!is_paused) | 1308 | if (!is_recording) |
885 | { | 1309 | { |
886 | logf("resume: not paused"); | 1310 | logf("not recording"); |
887 | resume_done = true; | 1311 | goto not_recording_or_not_paused; |
888 | return; | 1312 | } |
1313 | else if (!is_paused) | ||
1314 | { | ||
1315 | logf("not paused"); | ||
1316 | goto not_recording_or_not_paused; | ||
889 | } | 1317 | } |
890 | 1318 | ||
891 | is_paused = false; | 1319 | is_paused = false; |
892 | is_recording = true; | 1320 | is_recording = true; |
1321 | dma_lock = false; | ||
893 | 1322 | ||
894 | /* Compensate for the time we have been paused */ | 1323 | not_recording_or_not_paused: |
895 | if (pause_start_time) | 1324 | pcm_thread_signal_event(PCMREC_RESUME); |
896 | { | ||
897 | record_start_time += current_tick - pause_start_time; | ||
898 | pause_start_time = 0; | ||
899 | } | ||
900 | |||
901 | resume_done = true; | ||
902 | logf("pcmrec_resume done"); | 1325 | logf("pcmrec_resume done"); |
903 | } | 1326 | } /* pcmrec_resume */ |
904 | 1327 | ||
905 | /** | 1328 | /* PCMREC_NEW_FILE */ |
906 | * audio_init_recording calls this function using PCMREC_INIT | 1329 | static void pcmrec_new_file(const char *filename) |
907 | * | ||
908 | */ | ||
909 | static void pcmrec_init(void) | ||
910 | { | 1330 | { |
911 | wav_file = -1; | 1331 | logf("pcmrec_new_file: %s", filename); |
912 | read_pos = 0; | ||
913 | write_pos = 0; | ||
914 | enc_wr_index = 0; | ||
915 | enc_rd_index = 0; | ||
916 | 1332 | ||
917 | avrg_bit_rate = 0; | 1333 | if (!is_recording) |
918 | curr_bit_rate = 0; | 1334 | { |
919 | curr_chunk_cnt = 0; | 1335 | logf("not recording"); |
920 | 1336 | goto not_recording; | |
921 | peak_left = 0; | 1337 | } |
922 | peak_right = 0; | ||
923 | 1338 | ||
924 | num_rec_bytes = 0; | 1339 | num_rec_bytes = 0; |
925 | num_file_bytes = 0; | 1340 | num_rec_samples = 0; |
926 | num_pcm_samples = 0; | ||
927 | record_start_time = 0; | ||
928 | pause_start_time = 0; | ||
929 | |||
930 | close_done = false; | ||
931 | is_recording = false; | ||
932 | is_paused = false; | ||
933 | is_error = false; | ||
934 | |||
935 | rec_buffer = (unsigned char*)(((long)audiobuf + 15) & ~15); | ||
936 | enc_buffer = rec_buffer + NUM_CHUNKS * CHUNK_SIZE + MAX_FEED_SIZE; | ||
937 | /* 8000Bytes at audiobufend */ | ||
938 | enc_buffer_size = audiobufend - enc_buffer - 8000; | ||
939 | |||
940 | SET_IIS_PLAY(0x800); /* Stop any playback */ | ||
941 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ | ||
942 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ | ||
943 | |||
944 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ | ||
945 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ | ||
946 | DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; | ||
947 | ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ | ||
948 | IMR &= ~(1<<15); /* bit 15 is DMA1 */ | ||
949 | |||
950 | #ifdef HAVE_SPDIF_IN | ||
951 | PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ | ||
952 | #endif | ||
953 | pcmrec_dma_start(); | ||
954 | |||
955 | init_done = 1; | ||
956 | } | ||
957 | 1341 | ||
958 | static void pcmrec_close(void) | 1342 | pcmrec_new_stream(filename, |
959 | { | 1343 | CHUNKF_START_FILE | CHUNKF_END_FILE, |
960 | DMAROUTE = (DMAROUTE & 0xffff00ff); | 1344 | 0); |
961 | ICR7 = 0x00; /* Disable interrupt */ | ||
962 | IMR |= (1<<15); /* bit 15 is DMA1 */ | ||
963 | 1345 | ||
964 | pcmrec_dma_stop(); | 1346 | not_recording: |
965 | 1347 | pcm_thread_signal_event(PCMREC_NEW_FILE); | |
966 | /* Reset PDIR2 data flow */ | 1348 | logf("pcmrec_new_file done"); |
967 | DATAINCONTROL = 0x200; | 1349 | } /* pcmrec_new_file */ |
968 | close_done = true; | ||
969 | init_done = false; | ||
970 | } | ||
971 | 1350 | ||
1351 | static void pcmrec_thread(void) __attribute__((noreturn)); | ||
972 | static void pcmrec_thread(void) | 1352 | static void pcmrec_thread(void) |
973 | { | 1353 | { |
974 | struct event ev; | 1354 | struct event ev; |
975 | 1355 | ||
976 | logf("thread pcmrec start"); | 1356 | logf("thread pcmrec start"); |
977 | 1357 | ||
978 | error_count = 0; | ||
979 | |||
980 | while(1) | 1358 | while(1) |
981 | { | 1359 | { |
982 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 4); | 1360 | if (is_recording) |
1361 | { | ||
1362 | /* Poll periodically to flush data */ | ||
1363 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); | ||
1364 | |||
1365 | if (ev.id == SYS_TIMEOUT) | ||
1366 | { | ||
1367 | pcmrec_flush(0); /* flush if getting full */ | ||
1368 | continue; | ||
1369 | } | ||
1370 | } | ||
1371 | else | ||
1372 | { | ||
1373 | /* Not doing anything - sit and wait for commands */ | ||
1374 | queue_wait(&pcmrec_queue, &ev); | ||
1375 | } | ||
983 | 1376 | ||
984 | switch (ev.id) | 1377 | switch (ev.id) |
985 | { | 1378 | { |
@@ -992,13 +1385,17 @@ static void pcmrec_thread(void) | |||
992 | break; | 1385 | break; |
993 | 1386 | ||
994 | case PCMREC_START: | 1387 | case PCMREC_START: |
995 | pcmrec_start(); | 1388 | pcmrec_start((const char *)ev.data); |
996 | break; | 1389 | break; |
997 | 1390 | ||
998 | case PCMREC_STOP: | 1391 | case PCMREC_STOP: |
999 | pcmrec_stop(); | 1392 | pcmrec_stop(); |
1000 | break; | 1393 | break; |
1001 | 1394 | ||
1395 | case PCMREC_FINISH_STOP: | ||
1396 | pcmrec_finish_stop(); | ||
1397 | break; | ||
1398 | |||
1002 | case PCMREC_PAUSE: | 1399 | case PCMREC_PAUSE: |
1003 | pcmrec_pause(); | 1400 | pcmrec_pause(); |
1004 | break; | 1401 | break; |
@@ -1008,11 +1405,11 @@ static void pcmrec_thread(void) | |||
1008 | break; | 1405 | break; |
1009 | 1406 | ||
1010 | case PCMREC_NEW_FILE: | 1407 | case PCMREC_NEW_FILE: |
1011 | pcmrec_new_file(); | 1408 | pcmrec_new_file((const char *)ev.data); |
1012 | break; | 1409 | break; |
1013 | 1410 | ||
1014 | case SYS_TIMEOUT: | 1411 | case PCMREC_FLUSH_NUM: |
1015 | pcmrec_callback(false); | 1412 | pcmrec_flush((unsigned)ev.data); |
1016 | break; | 1413 | break; |
1017 | 1414 | ||
1018 | case SYS_USB_CONNECTED: | 1415 | case SYS_USB_CONNECTED: |
@@ -1023,140 +1420,267 @@ static void pcmrec_thread(void) | |||
1023 | usb_wait_for_disconnect(&pcmrec_queue); | 1420 | usb_wait_for_disconnect(&pcmrec_queue); |
1024 | } | 1421 | } |
1025 | break; | 1422 | break; |
1026 | } | 1423 | } /* end switch */ |
1027 | } | 1424 | } /* end while */ |
1425 | } /* pcmrec_thread */ | ||
1028 | 1426 | ||
1029 | logf("thread pcmrec done"); | 1427 | /****************************************************************************/ |
1030 | } | 1428 | /* */ |
1429 | /* following functions will be called by the encoder codec */ | ||
1430 | /* */ | ||
1431 | /****************************************************************************/ | ||
1031 | 1432 | ||
1032 | /* Select VINL & VINR source: 0=Line-in, 1=FM Radio */ | 1433 | /* pass the encoder settings to the encoder */ |
1033 | void pcm_rec_mux(int source) | 1434 | void enc_get_inputs(struct enc_inputs *inputs) |
1034 | { | 1435 | { |
1035 | #ifdef IRIVER_H300_SERIES | 1436 | inputs->sample_rate = sample_rate; |
1036 | if(source == 0) | 1437 | inputs->num_channels = num_channels; |
1037 | and_l(~0x40000000, &GPIO_OUT); /* Line In */ | 1438 | inputs->config = &enc_config; |
1038 | else | 1439 | } /* enc_get_inputs */ |
1039 | or_l(0x40000000, &GPIO_OUT); /* FM radio */ | ||
1040 | 1440 | ||
1041 | or_l(0x40000000, &GPIO_ENABLE); | 1441 | /* set the encoder dimensions (called by encoder codec at initialization and |
1042 | or_l(0x40000000, &GPIO_FUNCTION); | 1442 | termination) */ |
1043 | #elif defined(IRIVER_H100_SERIES) | 1443 | void enc_set_parameters(struct enc_parameters *params) |
1044 | if(source == 0) | 1444 | { |
1045 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ | 1445 | size_t bufsize, resbytes; |
1046 | else | ||
1047 | or_l(0x00800000, &GPIO_OUT); /* FM radio */ | ||
1048 | 1446 | ||
1049 | or_l(0x00800000, &GPIO_ENABLE); | 1447 | logf("enc_set_parameters"); |
1050 | or_l(0x00800000, &GPIO_FUNCTION); | ||
1051 | 1448 | ||
1052 | #elif defined(IAUDIO_X5) | 1449 | if (!params) |
1053 | if(source == 0) | 1450 | { |
1054 | or_l((1<<29), &GPIO_OUT); /* Line In */ | 1451 | logf("reset"); |
1055 | else | 1452 | /* Encoder is terminating */ |
1056 | and_l(~(1<<29), &GPIO_OUT); /* FM radio */ | 1453 | memset(&enc_config, 0, sizeof (enc_config)); |
1454 | enc_sample_rate = 0; | ||
1455 | return; | ||
1456 | } | ||
1457 | |||
1458 | enc_sample_rate = params->enc_sample_rate; | ||
1459 | logf("enc sampr:%d", enc_sample_rate); | ||
1460 | |||
1461 | pcm_rd_pos = dma_wr_pos; | ||
1462 | |||
1463 | enc_config.afmt = params->afmt; | ||
1464 | /* addition of the header is always implied - chunk size 4-byte aligned */ | ||
1465 | enc_chunk_size = | ||
1466 | ALIGN_UP_P2(ENC_CHUNK_HDR_SIZE + params->chunk_size, 2); | ||
1467 | enc_data_size = enc_chunk_size - ENC_CHUNK_HDR_SIZE; | ||
1468 | enc_events_callback = params->events_callback; | ||
1469 | |||
1470 | logf("chunk size:%d", enc_chunk_size); | ||
1471 | |||
1472 | /*** Configure the buffers ***/ | ||
1473 | |||
1474 | /* Layout of recording buffer: | ||
1475 | * [ax] = possible alignment x multiple | ||
1476 | * [sx] = possible size alignment of x multiple | ||
1477 | * |[a16]|[s4]:PCM Buffer+PCM Guard|[s4 each]:Encoder Chunks|-> | ||
1478 | * |[[s4]:Reserved Bytes]|Filename Queue->|[space]| | ||
1479 | */ | ||
1480 | resbytes = ALIGN_UP_P2(params->reserve_bytes, 2); | ||
1481 | logf("resbytes:%d", resbytes); | ||
1482 | |||
1483 | bufsize = rec_buffer_size - (enc_buffer - pcm_buffer) - | ||
1484 | resbytes - FNQ_MIN_NUM_PATHS*MAX_PATH; | ||
1485 | |||
1486 | enc_num_chunks = bufsize / enc_chunk_size; | ||
1487 | logf("num chunks:%d", enc_num_chunks); | ||
1057 | 1488 | ||
1058 | or_l((1<<29), &GPIO_ENABLE); | 1489 | /* get real amount used by encoder chunks */ |
1059 | or_l((1<<29), &GPIO_FUNCTION); | 1490 | bufsize = enc_num_chunks*enc_chunk_size; |
1491 | logf("enc size:%d", bufsize); | ||
1492 | |||
1493 | /* panic boost thread priority at 1 second remaining */ | ||
1494 | panic_threshold = enc_num_chunks - | ||
1495 | (4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size; | ||
1496 | if (panic_threshold < 0) | ||
1497 | panic_threshold = 0; | ||
1498 | |||
1499 | logf("panic thr:%d", panic_threshold); | ||
1500 | |||
1501 | /** set OUT parameters **/ | ||
1502 | params->enc_buffer = enc_buffer; | ||
1503 | params->buf_chunk_size = enc_chunk_size; | ||
1504 | params->num_chunks = enc_num_chunks; | ||
1505 | |||
1506 | /* calculate reserve buffer start and return pointer to encoder */ | ||
1507 | params->reserve_buffer = NULL; | ||
1508 | if (resbytes > 0) | ||
1509 | { | ||
1510 | params->reserve_buffer = enc_buffer + bufsize; | ||
1511 | bufsize += resbytes; | ||
1512 | } | ||
1060 | 1513 | ||
1061 | /* iAudio x5 */ | 1514 | /* place filename queue at end of buffer using up whatever remains */ |
1515 | fnq_rd_pos = 0; /* reset */ | ||
1516 | fnq_wr_pos = 0; /* reset */ | ||
1517 | fn_queue = enc_buffer + bufsize; | ||
1518 | fnq_size = pcm_buffer + rec_buffer_size - fn_queue; | ||
1519 | fnq_size = ALIGN_DOWN(fnq_size, MAX_PATH); | ||
1520 | logf("fnq files: %d", fnq_size / MAX_PATH); | ||
1521 | |||
1522 | #if 0 | ||
1523 | logf("ab :%08X", (unsigned long)audiobuf); | ||
1524 | logf("pcm:%08X", (unsigned long)pcm_buffer); | ||
1525 | logf("enc:%08X", (unsigned long)enc_buffer); | ||
1526 | logf("res:%08X", (unsigned long)params->reserve_buffer); | ||
1527 | logf("fnq:%08X", (unsigned long)fn_queue); | ||
1528 | logf("end:%08X", (unsigned long)fn_queue + fnq_size); | ||
1529 | logf("abe:%08X", (unsigned long)audiobufend); | ||
1062 | #endif | 1530 | #endif |
1063 | } | ||
1064 | 1531 | ||
1532 | /* init all chunk headers and reset indexes */ | ||
1533 | enc_rd_index = 0; | ||
1534 | for (enc_wr_index = enc_num_chunks; enc_wr_index > 0; ) | ||
1535 | GET_ENC_CHUNK(--enc_wr_index)->flags = 0; | ||
1065 | 1536 | ||
1066 | /****************************************************************************/ | 1537 | logf("enc_set_parameters done"); |
1067 | /* */ | 1538 | } /* enc_set_parameters */ |
1068 | /* following functions will be called by the encoder codec */ | ||
1069 | /* */ | ||
1070 | /****************************************************************************/ | ||
1071 | 1539 | ||
1072 | /* pass the encoder buffer pointer/size, mono/stereo, quality to the encoder */ | 1540 | /* return encoder chunk at current write position */ |
1073 | void enc_get_inputs(int *buffer_size, int *channels, int *quality) | 1541 | struct enc_chunk_hdr * enc_get_chunk(void) |
1074 | { | 1542 | { |
1075 | *buffer_size = enc_buffer_size; | 1543 | struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); |
1076 | *channels = enc_channels; | 1544 | chunk->flags &= CHUNKF_START_FILE; |
1077 | *quality = enc_quality; | ||
1078 | } | ||
1079 | 1545 | ||
1080 | /* set the encoder dimensions (called by encoder codec at initialization) */ | 1546 | if (!is_recording) |
1081 | void enc_set_parameters(int chunk_size, int num_chunks, int samp_per_chunk, | 1547 | chunk->flags |= CHUNKF_PRERECORD; |
1082 | char *head_ptr, int head_size, int enc_id) | ||
1083 | { | ||
1084 | /* set read_pos just in front of current write_pos */ | ||
1085 | read_pos = (write_pos - CHUNK_SIZE) & CHUNK_MASK; | ||
1086 | |||
1087 | enc_rd_index = 0; /* reset */ | ||
1088 | enc_wr_index = 0; /* reset */ | ||
1089 | enc_chunk_size = chunk_size; /* max chunk size */ | ||
1090 | enc_num_chunks = num_chunks; /* total number of chunks */ | ||
1091 | enc_samp_per_chunk = samp_per_chunk; /* pcm samples / encoderchunk */ | ||
1092 | enc_head_buffer = head_ptr; /* optional file header data (wav) */ | ||
1093 | enc_head_size = head_size; /* optional file header data (wav) */ | ||
1094 | audio_enc_id = enc_id; /* AFMT_* id */ | ||
1095 | } | ||
1096 | 1548 | ||
1097 | /* allocate encoder chunk */ | 1549 | return chunk; |
1098 | unsigned int *enc_alloc_chunk(void) | 1550 | } /* enc_get_chunk */ |
1099 | { | ||
1100 | return (unsigned int*)(enc_buffer + enc_wr_index * enc_chunk_size); | ||
1101 | } | ||
1102 | 1551 | ||
1103 | /* free previously allocated encoder chunk */ | 1552 | /* releases the current chunk into the available chunks */ |
1104 | void enc_free_chunk(void) | 1553 | void enc_finish_chunk(void) |
1105 | { | 1554 | { |
1106 | unsigned long *enc_chunk; | 1555 | struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); |
1107 | 1556 | ||
1108 | enc_chunk = GET_ENC_CHUNK(enc_wr_index); | 1557 | /* encoder may have set error flag or written too much data */ |
1109 | curr_chunk_cnt++; | 1558 | if ((long)chunk->flags < 0 || chunk->enc_size > enc_data_size) |
1110 | /* curr_bit_rate += *enc_chunk * 44100 * 8 / (enc_samp_per_chunk * 1000); */ | 1559 | { |
1111 | curr_bit_rate += *enc_chunk * 441 * 8 / (enc_samp_per_chunk * 10 ); | 1560 | is_error = true; |
1112 | avrg_bit_rate = (curr_bit_rate + curr_chunk_cnt / 2) / curr_chunk_cnt; | ||
1113 | 1561 | ||
1114 | /* advance enc_wr_index to the next chunk */ | 1562 | #ifdef ROCKBOX_HAS_LOGF |
1115 | enc_wr_index = (enc_wr_index + 1) % enc_num_chunks; | 1563 | if (chunk->enc_size > enc_data_size) |
1564 | { | ||
1565 | /* illegal to scribble over next chunk */ | ||
1566 | logf("finish chk ovf: %d>%d", chunk->enc_size, enc_data_size); | ||
1567 | } | ||
1568 | else | ||
1569 | { | ||
1570 | /* encoder set error flag */ | ||
1571 | logf("finish chk enc error"); | ||
1572 | } | ||
1573 | #endif | ||
1574 | } | ||
1575 | |||
1576 | /* advance enc_wr_index to the next encoder chunk */ | ||
1577 | INC_ENC_INDEX(enc_wr_index); | ||
1116 | 1578 | ||
1117 | /* buffer full: advance enc_rd_index (for prerecording purpose) */ | 1579 | if (enc_rd_index != enc_wr_index) |
1118 | if (enc_rd_index == enc_wr_index) | ||
1119 | { | 1580 | { |
1120 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | 1581 | num_rec_bytes += chunk->enc_size; |
1582 | accum_rec_bytes += chunk->enc_size; | ||
1583 | num_rec_samples += chunk->num_pcm; | ||
1584 | accum_pcm_samples += chunk->num_pcm; | ||
1121 | } | 1585 | } |
1122 | } | 1586 | else if (is_recording) /* buffer full */ |
1587 | { | ||
1588 | /* keep current position */ | ||
1589 | logf("enc_buffer ovf"); | ||
1590 | DEC_ENC_INDEX(enc_wr_index); | ||
1591 | } | ||
1592 | else | ||
1593 | { | ||
1594 | /* advance enc_rd_index for prerecording */ | ||
1595 | INC_ENC_INDEX(enc_rd_index); | ||
1596 | } | ||
1597 | } /* enc_finish_chunk */ | ||
1123 | 1598 | ||
1124 | /* checks near empty state on wav input buffer */ | 1599 | /* checks near empty state on pcm input buffer */ |
1125 | int enc_wavbuf_near_empty(void) | 1600 | int enc_pcm_buf_near_empty(void) |
1126 | { | 1601 | { |
1127 | /* less than 1sec raw data? => unboost encoder */ | 1602 | /* less than 1sec raw data? => unboost encoder */ |
1128 | if (((write_pos - read_pos) & CHUNK_MASK) < 44100*4) | 1603 | size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; |
1129 | return 1; | 1604 | return avail < (sample_rate << 2) ? 1 : 0; |
1130 | else | 1605 | } /* enc_pcm_buf_near_empty */ |
1131 | return 0; | ||
1132 | } | ||
1133 | 1606 | ||
1134 | /* passes a pointer to next chunk of unprocessed wav data */ | 1607 | /* passes a pointer to next chunk of unprocessed wav data */ |
1135 | char *enc_get_wav_data(int size) | 1608 | /* TODO: this really should give the actual size returned */ |
1609 | unsigned char * enc_get_pcm_data(size_t size) | ||
1136 | { | 1610 | { |
1137 | char *ptr; | 1611 | size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; |
1138 | int avail; | ||
1139 | 1612 | ||
1140 | /* limit the requested pcm data size */ | 1613 | /* limit the requested pcm data size */ |
1141 | if(size > MAX_FEED_SIZE) | 1614 | if (size > PCM_MAX_FEED_SIZE) |
1142 | size = MAX_FEED_SIZE; | 1615 | size = PCM_MAX_FEED_SIZE; |
1143 | |||
1144 | avail = (write_pos - read_pos) & CHUNK_MASK; | ||
1145 | 1616 | ||
1146 | if (avail >= size) | 1617 | if (avail >= size) |
1147 | { | 1618 | { |
1148 | ptr = rec_buffer + read_pos; | 1619 | unsigned char *ptr = pcm_buffer + pcm_rd_pos; |
1149 | read_pos = (read_pos + size) & CHUNK_MASK; | 1620 | pcm_rd_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; |
1150 | 1621 | ||
1151 | /* ptr must point to continous data at wraparound position */ | 1622 | /* ptr must point to continous data at wraparound position */ |
1152 | if (read_pos < size) | 1623 | if ((size_t)pcm_rd_pos < size) |
1153 | memcpy(rec_buffer + NUM_CHUNKS * CHUNK_SIZE, | 1624 | memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE, |
1154 | rec_buffer, read_pos); | 1625 | pcm_buffer, pcm_rd_pos); |
1155 | 1626 | ||
1156 | wav_queue_empty = false; | 1627 | wav_queue_empty = false; |
1157 | return ptr; | 1628 | return ptr; |
1158 | } | 1629 | } |
1159 | 1630 | ||
1631 | /* not enough data available - encoder should idle */ | ||
1160 | wav_queue_empty = true; | 1632 | wav_queue_empty = true; |
1161 | return NULL; | 1633 | return NULL; |
1162 | } | 1634 | } /* enc_get_pcm_data */ |
1635 | |||
1636 | /* puts some pcm data back in the queue */ | ||
1637 | size_t enc_unget_pcm_data(size_t size) | ||
1638 | { | ||
1639 | /* can't let DMA advance write position when doing this */ | ||
1640 | int level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
1641 | |||
1642 | if (pcm_rd_pos != dma_wr_pos) | ||
1643 | { | ||
1644 | /* disallow backing up into current DMA write chunk */ | ||
1645 | size_t old_avail = (pcm_rd_pos - dma_wr_pos - PCM_CHUNK_SIZE) | ||
1646 | & PCM_CHUNK_MASK; | ||
1647 | |||
1648 | /* limit size to amount of old data remaining */ | ||
1649 | if (size > old_avail) | ||
1650 | size = old_avail; | ||
1651 | |||
1652 | pcm_rd_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; | ||
1653 | } | ||
1654 | |||
1655 | set_irq_level(level); | ||
1656 | |||
1657 | return size; | ||
1658 | } /* enc_unget_pcm_data */ | ||
1659 | |||
1660 | /** Low level pcm recording apis **/ | ||
1661 | |||
1662 | /**************************************************************************** | ||
1663 | * Functions that do not require targeted implementation but only a targeted | ||
1664 | * interface | ||
1665 | */ | ||
1666 | void pcm_record_data(pcm_more_callback_type more_ready, | ||
1667 | unsigned char *start, size_t size) | ||
1668 | { | ||
1669 | pcm_callback_more_ready = more_ready; | ||
1670 | |||
1671 | if (!(start && size)) | ||
1672 | { | ||
1673 | size = 0; | ||
1674 | if (more_ready) | ||
1675 | more_ready(&start, &size); | ||
1676 | } | ||
1677 | |||
1678 | if (start && size) | ||
1679 | pcm_rec_dma_start(start, size); | ||
1680 | } /* pcm_record_data */ | ||
1681 | |||
1682 | void pcm_stop_recording(void) | ||
1683 | { | ||
1684 | if (pcm_recording) | ||
1685 | pcm_rec_dma_stop(); | ||
1686 | } /* pcm_stop_recording */ | ||
diff --git a/firmware/system.c b/firmware/system.c index 242d84d16c..96d5f96602 100644 --- a/firmware/system.c +++ b/firmware/system.c | |||
@@ -390,8 +390,7 @@ int system_memory_guard(int newmode) | |||
390 | (void)newmode; | 390 | (void)newmode; |
391 | return 0; | 391 | return 0; |
392 | } | 392 | } |
393 | #elif defined(CPU_COLDFIRE) | 393 | |
394 | /* system code is in target tree for all coldfire targets */ | ||
395 | #elif CONFIG_CPU == SH7034 | 394 | #elif CONFIG_CPU == SH7034 |
396 | #include "led.h" | 395 | #include "led.h" |
397 | #include "system.h" | 396 | #include "system.h" |
diff --git a/firmware/target/coldfire/iaudio/x5/system-x5.c b/firmware/target/coldfire/iaudio/x5/system-x5.c index 6be6d25ce0..30a4f6e71b 100644 --- a/firmware/target/coldfire/iaudio/x5/system-x5.c +++ b/firmware/target/coldfire/iaudio/x5/system-x5.c | |||
@@ -42,7 +42,7 @@ void set_cpu_frequency(long frequency) | |||
42 | PLLCR &= ~1; /* Bypass mode */ | 42 | PLLCR &= ~1; /* Bypass mode */ |
43 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 43 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
44 | RECALC_DELAYS(CPUFREQ_MAX); | 44 | RECALC_DELAYS(CPUFREQ_MAX); |
45 | PLLCR = 0x13442045; | 45 | PLLCR = 0x03042045 | (PLLCR & 0x70C00000); |
46 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ | 46 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ |
47 | CSCR1 = 0x00000980; /* LCD: 2 wait states */ | 47 | CSCR1 = 0x00000980; /* LCD: 2 wait states */ |
48 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. | 48 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. |
@@ -60,7 +60,7 @@ void set_cpu_frequency(long frequency) | |||
60 | PLLCR &= ~1; /* Bypass mode */ | 60 | PLLCR &= ~1; /* Bypass mode */ |
61 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 61 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
62 | RECALC_DELAYS(CPUFREQ_NORMAL); | 62 | RECALC_DELAYS(CPUFREQ_NORMAL); |
63 | PLLCR = 0x16430045; | 63 | PLLCR = 0x06030045 | (PLLCR & 0x70C00000); |
64 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ | 64 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ |
65 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 65 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
66 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. | 66 | while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. |
@@ -77,7 +77,8 @@ void set_cpu_frequency(long frequency) | |||
77 | PLLCR &= ~1; /* Bypass mode */ | 77 | PLLCR &= ~1; /* Bypass mode */ |
78 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); | 78 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); |
79 | RECALC_DELAYS(CPUFREQ_DEFAULT); | 79 | RECALC_DELAYS(CPUFREQ_DEFAULT); |
80 | PLLCR = 0x10400200; /* Power down PLL, but keep CLSEL and CRSEL */ | 80 | /* Power down PLL, but keep CLSEL and CRSEL */ |
81 | PLLCR = 0x00000200 | (PLLCR & 0x70C00000); | ||
81 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ | 82 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ |
82 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 83 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
83 | DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ | 84 | DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ |
diff --git a/firmware/target/coldfire/iriver/system-iriver.c b/firmware/target/coldfire/iriver/system-iriver.c index 3517788641..43ba4eeed4 100644 --- a/firmware/target/coldfire/iriver/system-iriver.c +++ b/firmware/target/coldfire/iriver/system-iriver.c | |||
@@ -81,7 +81,7 @@ void set_cpu_frequency(long frequency) | |||
81 | PLLCR &= ~1; /* Bypass mode */ | 81 | PLLCR &= ~1; /* Bypass mode */ |
82 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 82 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
83 | RECALC_DELAYS(CPUFREQ_MAX); | 83 | RECALC_DELAYS(CPUFREQ_MAX); |
84 | PLLCR = 0x11c56005; | 84 | PLLCR = 0x01056005 | (PLLCR & 0x70c00000); |
85 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ | 85 | CSCR0 = 0x00001180; /* Flash: 4 wait states */ |
86 | CSCR1 = 0x00001580; /* LCD: 5 wait states */ | 86 | CSCR1 = 0x00001580; /* LCD: 5 wait states */ |
87 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 87 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
@@ -108,7 +108,7 @@ void set_cpu_frequency(long frequency) | |||
108 | PLLCR &= ~1; /* Bypass mode */ | 108 | PLLCR &= ~1; /* Bypass mode */ |
109 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); | 109 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); |
110 | RECALC_DELAYS(CPUFREQ_NORMAL); | 110 | RECALC_DELAYS(CPUFREQ_NORMAL); |
111 | PLLCR = 0x13c5e005; | 111 | PLLCR = 0x0305e005 | (PLLCR & 0x70c00000); |
112 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ | 112 | CSCR0 = 0x00000580; /* Flash: 1 wait state */ |
113 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 113 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
114 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 114 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
@@ -134,7 +134,8 @@ void set_cpu_frequency(long frequency) | |||
134 | PLLCR &= ~1; /* Bypass mode */ | 134 | PLLCR &= ~1; /* Bypass mode */ |
135 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); | 135 | timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); |
136 | RECALC_DELAYS(CPUFREQ_DEFAULT); | 136 | RECALC_DELAYS(CPUFREQ_DEFAULT); |
137 | PLLCR = 0x10c00200; /* Power down PLL, but keep CLSEL and CRSEL */ | 137 | /* Power down PLL, but keep CLSEL and CRSEL */ |
138 | PLLCR = 0x00000200 | (PLLCR & 0x70c00000); | ||
138 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ | 139 | CSCR0 = 0x00000180; /* Flash: 0 wait states */ |
139 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ | 140 | CSCR1 = 0x00000180; /* LCD: 0 wait states */ |
140 | #if CONFIG_USBOTG == USBOTG_ISP1362 | 141 | #if CONFIG_USBOTG == USBOTG_ISP1362 |
diff --git a/firmware/target/coldfire/system-coldfire.c b/firmware/target/coldfire/system-coldfire.c index 66e4feb154..2fc81496db 100644 --- a/firmware/target/coldfire/system-coldfire.c +++ b/firmware/target/coldfire/system-coldfire.c | |||
@@ -310,3 +310,10 @@ int system_memory_guard(int newmode) | |||
310 | 310 | ||
311 | return oldmode; | 311 | return oldmode; |
312 | } | 312 | } |
313 | |||
314 | /* allow setting of audio clock related bits */ | ||
315 | void coldfire_set_pllcr_audio_bits(long bits) | ||
316 | { | ||
317 | PLLCR = (PLLCR & ~0x70c00000) | (bits & 0x70c00000); | ||
318 | } | ||
319 | |||
diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h index 03852115ad..24e3fb8705 100644 --- a/firmware/target/coldfire/system-target.h +++ b/firmware/target/coldfire/system-target.h | |||
@@ -110,6 +110,28 @@ static inline unsigned long swap32(unsigned long value) | |||
110 | return value; | 110 | return value; |
111 | } | 111 | } |
112 | 112 | ||
113 | static inline unsigned long swap_odd_even32(unsigned long value) | ||
114 | { | ||
115 | /* | ||
116 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
117 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
118 | */ | ||
119 | unsigned long mask = 0x00FF00FF; | ||
120 | |||
121 | asm ( /* val = ABCD */ | ||
122 | "and.l %[val],%[mask] \n" /* mask = .B.D */ | ||
123 | "eor.l %[mask],%[val] \n" /* val = A.C. */ | ||
124 | "lsl.l #8,%[mask] \n" /* mask = B.D. */ | ||
125 | "lsr.l #8,%[val] \n" /* val = .A.C */ | ||
126 | "or.l %[mask],%[val] \n" /* val = BADC */ | ||
127 | : /* outputs */ | ||
128 | [val] "+d"(value), | ||
129 | [mask]"+d"(mask) | ||
130 | ); | ||
131 | |||
132 | return value; | ||
133 | } | ||
134 | |||
113 | static inline void invalidate_icache(void) | 135 | static inline void invalidate_icache(void) |
114 | { | 136 | { |
115 | asm volatile ("move.l #0x01000000,%d0\n" | 137 | asm volatile ("move.l #0x01000000,%d0\n" |
@@ -118,6 +140,13 @@ static inline void invalidate_icache(void) | |||
118 | "movec.l %d0,%cacr"); | 140 | "movec.l %d0,%cacr"); |
119 | } | 141 | } |
120 | 142 | ||
143 | #ifdef IAUDIO_X5 | ||
144 | #define DEFAULT_PLLCR_AUDIO_BITS 0x10400000 | ||
145 | #else | ||
146 | #define DEFAULT_PLLCR_AUDIO_BITS 0x10c00000 | ||
147 | #endif | ||
148 | void coldfire_set_pllcr_audio_bits(long bits); | ||
149 | |||
121 | /* 11.2896 MHz */ | 150 | /* 11.2896 MHz */ |
122 | #define CPUFREQ_DEFAULT_MULT 1 | 151 | #define CPUFREQ_DEFAULT_MULT 1 |
123 | #define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ) | 152 | #define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ) |
diff --git a/firmware/thread.c b/firmware/thread.c index 6a94a52333..4094877742 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -711,6 +711,14 @@ int thread_set_priority(struct thread_entry *thread, int priority) | |||
711 | 711 | ||
712 | return old_priority; | 712 | return old_priority; |
713 | } | 713 | } |
714 | |||
715 | int thread_get_priority(struct thread_entry *thread) | ||
716 | { | ||
717 | if (thread == NULL) | ||
718 | thread = cores[CURRENT_CORE].running; | ||
719 | |||
720 | return thread->priority; | ||
721 | } | ||
714 | #endif | 722 | #endif |
715 | 723 | ||
716 | void init_threads(void) | 724 | void init_threads(void) |
diff --git a/uisimulator/sdl/lcd-charcell.c b/uisimulator/sdl/lcd-charcell.c index 8b93653a19..eb94ebf67f 100644 --- a/uisimulator/sdl/lcd-charcell.c +++ b/uisimulator/sdl/lcd-charcell.c | |||
@@ -181,7 +181,8 @@ void screen_dump(void) | |||
181 | int x, y; | 181 | int x, y; |
182 | static unsigned char line[BMP_LINESIZE]; | 182 | static unsigned char line[BMP_LINESIZE]; |
183 | 183 | ||
184 | create_numbered_filename(filename, "", "dump_", ".bmp", 4); | 184 | create_numbered_filename(filename, "", "dump_", ".bmp", 4, |
185 | IF_CNFN_NUM_(, NULL)); | ||
185 | DEBUGF("screen_dump\n"); | 186 | DEBUGF("screen_dump\n"); |
186 | 187 | ||
187 | fd = sim_creat(filename, O_WRONLY); | 188 | fd = sim_creat(filename, O_WRONLY); |