diff options
Diffstat (limited to 'firmware/pcm_record.c')
-rw-r--r-- | firmware/pcm_record.c | 736 |
1 files changed, 381 insertions, 355 deletions
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index fee2bbd35b..4e4d5f25a0 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -50,6 +50,8 @@ | |||
50 | #include "lcd.h" | 50 | #include "lcd.h" |
51 | #include "lcd-remote.h" | 51 | #include "lcd-remote.h" |
52 | #include "pcm_playback.h" | 52 | #include "pcm_playback.h" |
53 | #include "sound.h" | ||
54 | #include "id3.h" | ||
53 | #include "pcm_record.h" | 55 | #include "pcm_record.h" |
54 | 56 | ||
55 | extern int boost_counter; /* used for boost check */ | 57 | extern int boost_counter; /* used for boost check */ |
@@ -57,43 +59,26 @@ extern int boost_counter; /* used for boost check */ | |||
57 | /***************************************************************************/ | 59 | /***************************************************************************/ |
58 | 60 | ||
59 | static bool is_recording; /* We are recording */ | 61 | static bool is_recording; /* We are recording */ |
60 | static bool is_stopping; /* Are we going to stop */ | ||
61 | static bool is_paused; /* We have paused */ | 62 | static bool is_paused; /* We have paused */ |
62 | static bool is_error; /* An error has occured */ | 63 | static bool is_error; /* An error has occured */ |
63 | 64 | ||
64 | static unsigned long num_rec_bytes; /* Num bytes recorded */ | 65 | static unsigned long num_rec_bytes; /* Num bytes recorded */ |
65 | static unsigned long num_file_bytes; /* Num bytes written to current file */ | 66 | static unsigned long num_file_bytes; /* Num bytes written to current file */ |
66 | static int error_count; /* Number of DMA errors */ | 67 | static int error_count; /* Number of DMA errors */ |
68 | static unsigned long num_pcm_samples; /* Num pcm samples written to current file */ | ||
67 | 69 | ||
68 | static long record_start_time; /* Value of current_tick when recording was started */ | 70 | static long record_start_time; /* current_tick when recording was started */ |
69 | static long pause_start_time; /* Value of current_tick when pause was started */ | 71 | static long pause_start_time; /* current_tick when pause was started */ |
70 | static volatile int buffered_chunks; /* number of valid chunks in buffer */ | 72 | static unsigned int sample_rate; /* Sample rate at time of recording start */ |
71 | static unsigned int sample_rate; /* Sample rate at time of recording start */ | 73 | static int rec_source; /* Current recording source */ |
72 | static int rec_source; /* Current recording source */ | ||
73 | 74 | ||
74 | static int wav_file; | 75 | static int wav_file; |
75 | static char recording_filename[MAX_PATH]; | 76 | static char recording_filename[MAX_PATH]; |
76 | 77 | ||
77 | static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; | 78 | static volatile bool init_done, close_done, record_done; |
79 | static volatile bool stop_done, pause_done, resume_done, new_file_done; | ||
78 | 80 | ||
79 | static short peak_left, peak_right; | 81 | static int peak_left, peak_right; |
80 | |||
81 | /***************************************************************************/ | ||
82 | |||
83 | /* | ||
84 | Some estimates: | ||
85 | Normal recording rate: 44100 HZ * 4 = 176 KB/s | ||
86 | Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk | ||
87 | */ | ||
88 | |||
89 | #define CHUNK_SIZE 8192 /* Multiple of 4 */ | ||
90 | #define WRITE_THRESHOLD 250 /* (2 MB) Write when this many chunks (or less) until buffer full */ | ||
91 | |||
92 | #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)]) | ||
93 | |||
94 | static unsigned int rec_buffer_offset; | ||
95 | static unsigned char *rec_buffer; /* Circular recording buffer */ | ||
96 | static int num_chunks; /* Number of chunks available in rec_buffer */ | ||
97 | 82 | ||
98 | #ifdef IAUDIO_X5 | 83 | #ifdef IAUDIO_X5 |
99 | #define SET_IIS_PLAY(x) IIS1CONFIG = (x); | 84 | #define SET_IIS_PLAY(x) IIS1CONFIG = (x); |
@@ -103,27 +88,71 @@ static int num_chunks; /* Number of chunks available in rec_buffer * | |||
103 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | 88 | #define SET_IIS_REC(x) IIS1CONFIG = (x); |
104 | #endif | 89 | #endif |
105 | 90 | ||
106 | /* | 91 | /**************************************************************************** |
107 | Overrun occures when DMA needs to write a new chunk and write_index == read_index | 92 | use 2 circular buffers of same size: |
108 | Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk | 93 | rec_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data |
109 | more often. | 94 | enc_buffer=encoded audio buffer: storage for encoder output data |
110 | */ | 95 | |
111 | 96 | Flow: | |
112 | static int write_index; /* Current chunk the DMA is writing to */ | 97 | 1. when entering recording_screen DMA feeds the ringbuffer rec_buffer |
113 | static int read_index; /* Oldest chunk that is not written to disk */ | 98 | 2. if enough pcm data are available the encoder codec does encoding of pcm |
114 | static int read2_index; /* Latest chunk that has not been converted to little endian */ | 99 | chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread |
115 | static long pre_record_ticks; /* pre-record time expressed in ticks */ | 100 | 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk |
116 | static int pre_record_chunks; /* pre-record time expressed in chunks */ | 101 | |
102 | Functions calls: | ||
103 | 1.main: codec_load_encoder(); start the encoder | ||
104 | 2.encoder: enc_get_inputs(); get encoder buffsize, mono/stereo, quality | ||
105 | 3.encoder: enc_set_parameters(); set the encoder parameters (max.chunksize) | ||
106 | 4.encoder: enc_get_wav_data(); get n bytes of unprocessed pcm data | ||
107 | 5.encoder: enc_wavbuf_near_empty();if true: reduce cpu_boost | ||
108 | 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 | ||
110 | 8.encoder: enc_free_chunk(); inform main about chunk process finished | ||
111 | 9.encoder: repeat 4. to 8. | ||
112 | A.main: enc_set_header_callback(); create the current format header (file) | ||
113 | ****************************************************************************/ | ||
114 | #define NUM_CHUNKS 256 /* Power of 2 */ | ||
115 | #define CHUNK_SIZE 8192 /* Power of 2 */ | ||
116 | #define MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ | ||
117 | #define CHUNK_MASK (NUM_CHUNKS * CHUNK_SIZE - 1) | ||
118 | #define WRITE_THRESHOLD (44100 * 5 / enc_samp_per_chunk) /* 5sec */ | ||
119 | #define GET_CHUNK(x) (long*)(&rec_buffer[x]) | ||
120 | #define GET_ENC_CHUNK(x) (long*)(&enc_buffer[enc_chunk_size*(x)]) | ||
121 | |||
122 | static int audio_enc_id; /* current encoder id */ | ||
123 | static unsigned char *rec_buffer; /* Circular recording buffer */ | ||
124 | static unsigned char *enc_buffer; /* Circular encoding buffer */ | ||
125 | static unsigned char *enc_head_buffer; /* encoder header buffer */ | ||
126 | static int enc_head_size; /* used size in header buffer */ | ||
127 | static int write_pos; /* Current chunk pos for DMA writing */ | ||
128 | static int read_pos; /* Current chunk pos for encoding */ | ||
129 | static long pre_record_ticks;/* pre-record time expressed in ticks */ | ||
130 | static int enc_wr_index; /* Current encoding chunk write index */ | ||
131 | static int enc_rd_index; /* Current encoding chunk read index */ | ||
132 | static int enc_chunk_size; /* maximum encoder chunk size */ | ||
133 | static int enc_num_chunks; /* number of chunks in ringbuffer */ | ||
134 | static int enc_buffer_size; /* encode buffer size */ | ||
135 | static int enc_channels; /* 1=mono 2=stereo */ | ||
136 | static int enc_quality; /* mp3: 64,96,128,160,192,320 kBit */ | ||
137 | static int enc_samp_per_chunk;/* pcm samples per encoder chunk */ | ||
138 | 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 | |||
143 | void (*enc_set_header_callback)(void *head_buffer, int head_size, | ||
144 | int num_pcm_samples, bool is_file_header); | ||
117 | 145 | ||
118 | /***************************************************************************/ | 146 | /***************************************************************************/ |
119 | 147 | ||
120 | static struct event_queue pcmrec_queue; | 148 | static struct event_queue pcmrec_queue; |
121 | static long pcmrec_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | 149 | static long pcmrec_stack[2*DEFAULT_STACK_SIZE/sizeof(long)]; |
122 | static const char pcmrec_thread_name[] = "pcmrec"; | 150 | static const char pcmrec_thread_name[] = "pcmrec"; |
123 | 151 | ||
124 | static void pcmrec_thread(void); | 152 | static void pcmrec_thread(void); |
125 | static void pcmrec_dma_start(void); | 153 | static void pcmrec_dma_start(void); |
126 | static void pcmrec_dma_stop(void); | 154 | static void pcmrec_dma_stop(void); |
155 | static void close_wave(void); | ||
127 | 156 | ||
128 | /* Event IDs */ | 157 | /* Event IDs */ |
129 | #define PCMREC_INIT 1 /* Enable recording */ | 158 | #define PCMREC_INIT 1 /* Enable recording */ |
@@ -144,10 +173,16 @@ static void pcmrec_dma_stop(void); | |||
144 | void pcm_rec_init(void) | 173 | void pcm_rec_init(void) |
145 | { | 174 | { |
146 | queue_init(&pcmrec_queue); | 175 | queue_init(&pcmrec_queue); |
147 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name); | 176 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), |
177 | pcmrec_thread_name); | ||
148 | } | 178 | } |
149 | 179 | ||
150 | 180 | ||
181 | int audio_get_encoder_id(void) | ||
182 | { | ||
183 | return audio_enc_id; | ||
184 | } | ||
185 | |||
151 | /* Initializes recording: | 186 | /* Initializes recording: |
152 | * - Set up the UDA1380/TLV320 for recording | 187 | * - Set up the UDA1380/TLV320 for recording |
153 | * - Prepare for DMA transfers | 188 | * - Prepare for DMA transfers |
@@ -155,13 +190,14 @@ void pcm_rec_init(void) | |||
155 | 190 | ||
156 | void audio_init_recording(unsigned int buffer_offset) | 191 | void audio_init_recording(unsigned int buffer_offset) |
157 | { | 192 | { |
158 | rec_buffer_offset = buffer_offset; | 193 | (void)buffer_offset; |
194 | |||
159 | init_done = false; | 195 | init_done = false; |
160 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); | 196 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); |
161 | 197 | ||
162 | while(!init_done) | 198 | while(!init_done) |
163 | sleep_thread(); | 199 | sleep_thread(); |
164 | wake_up_thread(); | 200 | wake_up_thread(); |
165 | } | 201 | } |
166 | 202 | ||
167 | void audio_close_recording(void) | 203 | void audio_close_recording(void) |
@@ -171,7 +207,9 @@ void audio_close_recording(void) | |||
171 | 207 | ||
172 | while(!close_done) | 208 | while(!close_done) |
173 | sleep_thread(); | 209 | sleep_thread(); |
174 | wake_up_thread(); | 210 | wake_up_thread(); |
211 | |||
212 | audio_remove_encoder(); | ||
175 | } | 213 | } |
176 | 214 | ||
177 | unsigned long pcm_rec_status(void) | 215 | unsigned long pcm_rec_status(void) |
@@ -184,10 +222,17 @@ unsigned long pcm_rec_status(void) | |||
184 | ret |= AUDIO_STATUS_PAUSE; | 222 | ret |= AUDIO_STATUS_PAUSE; |
185 | if (is_error) | 223 | if (is_error) |
186 | ret |= AUDIO_STATUS_ERROR; | 224 | ret |= AUDIO_STATUS_ERROR; |
225 | if (!is_recording && pre_record_ticks && init_done && !close_done) | ||
226 | ret |= AUDIO_STATUS_PRERECORD; | ||
187 | 227 | ||
188 | return ret; | 228 | return ret; |
189 | } | 229 | } |
190 | 230 | ||
231 | int pcm_rec_current_bitrate(void) | ||
232 | { | ||
233 | return avrg_bit_rate; | ||
234 | } | ||
235 | |||
191 | unsigned long audio_recorded_time(void) | 236 | unsigned long audio_recorded_time(void) |
192 | { | 237 | { |
193 | if (is_recording) | 238 | if (is_recording) |
@@ -248,6 +293,8 @@ unsigned long audio_get_spdif_sample_rate(void) | |||
248 | } | 293 | } |
249 | #endif | 294 | #endif |
250 | 295 | ||
296 | #if 0 | ||
297 | /* not needed atm */ | ||
251 | #ifdef HAVE_SPDIF_POWER | 298 | #ifdef HAVE_SPDIF_POWER |
252 | static bool spdif_power_setting; | 299 | static bool spdif_power_setting; |
253 | 300 | ||
@@ -256,21 +303,18 @@ void audio_set_spdif_power_setting(bool on) | |||
256 | spdif_power_setting = on; | 303 | spdif_power_setting = on; |
257 | } | 304 | } |
258 | #endif | 305 | #endif |
306 | #endif | ||
259 | 307 | ||
260 | /** | 308 | /** |
261 | * Sets the audio source | 309 | * Sets recording parameters |
262 | * | 310 | * |
263 | * This functions starts feeding the CPU with audio data over the I2S bus | 311 | * This functions starts feeding the CPU with audio data over the I2S bus |
264 | * | ||
265 | * @param source 0=mic, 1=line-in, 2=spdif | ||
266 | */ | 312 | */ |
267 | void audio_set_recording_options(int frequency, int quality, | 313 | void audio_set_recording_options(int frequency, int quality, |
268 | int source, int channel_mode, | 314 | int source, int channel_mode, |
269 | bool editable, int prerecord_time) | 315 | bool editable, int prerecord_time) |
270 | { | 316 | { |
271 | /* TODO: */ | 317 | /* TODO: */ |
272 | (void)quality; | ||
273 | (void)channel_mode; | ||
274 | (void)editable; | 318 | (void)editable; |
275 | 319 | ||
276 | /* NOTE: Coldfire UDA based recording does not yet support anything other | 320 | /* NOTE: Coldfire UDA based recording does not yet support anything other |
@@ -278,69 +322,30 @@ void audio_set_recording_options(int frequency, int quality, | |||
278 | * based recording will overwrite this value with the proper sample rate in | 322 | * based recording will overwrite this value with the proper sample rate in |
279 | * audio_record(), and will not be affected by this. | 323 | * audio_record(), and will not be affected by this. |
280 | */ | 324 | */ |
281 | frequency = 44100; | 325 | frequency = 44100; |
326 | enc_quality = quality; | ||
327 | rec_source = source; | ||
328 | enc_channels = channel_mode == CHN_MODE_MONO ? 1 : 2; | ||
282 | pre_record_ticks = prerecord_time * HZ; | 329 | pre_record_ticks = prerecord_time * HZ; |
283 | pre_record_chunks = ((frequency * prerecord_time * 4)/CHUNK_SIZE)+1; | ||
284 | if(pre_record_chunks >= (num_chunks-250)) | ||
285 | { | ||
286 | /* we can't prerecord more than our buffersize minus treshold to write to disk! */ | ||
287 | pre_record_chunks = num_chunks-250; | ||
288 | /* don't forget to recalculate that time! */ | ||
289 | pre_record_ticks = ((pre_record_chunks * CHUNK_SIZE)/(4*frequency)) * HZ; | ||
290 | } | ||
291 | |||
292 | //logf("pcmrec: src=%d", source); | ||
293 | 330 | ||
294 | rec_source = source; | ||
295 | #ifdef HAVE_SPDIF_POWER | ||
296 | /* Check if S/PDIF output power should be switched off or on. NOTE: assumes | ||
297 | both optical in and out is controlled by the same power source, which is | ||
298 | the case on H1x0. */ | ||
299 | spdif_power_enable((source == 2) || spdif_power_setting); | ||
300 | #endif | ||
301 | switch (source) | 331 | switch (source) |
302 | { | 332 | { |
303 | /* mic */ | 333 | case AUDIO_SRC_MIC: |
304 | case 0: | 334 | case AUDIO_SRC_LINEIN: |
305 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | 335 | #ifdef HAVE_FMRADIO_IN |
306 | DATAINCONTROL = 0xc020; | 336 | case AUDIO_SRC_FMRADIO: |
307 | |||
308 | #ifdef HAVE_UDA1380 | ||
309 | uda1380_enable_recording(true); | ||
310 | #endif | 337 | #endif |
311 | #ifdef HAVE_TLV320 | ||
312 | tlv320_enable_recording(true); | ||
313 | #endif | ||
314 | break; | ||
315 | |||
316 | /* line-in */ | ||
317 | case 1: | ||
318 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | 338 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ |
319 | DATAINCONTROL = 0xc020; | 339 | DATAINCONTROL = 0xc020; |
320 | |||
321 | #ifdef HAVE_UDA1380 | ||
322 | uda1380_enable_recording(false); | ||
323 | #endif | ||
324 | #ifdef HAVE_TLV320 | ||
325 | tlv320_enable_recording(false); | ||
326 | #endif | ||
327 | break; | 340 | break; |
328 | #ifdef HAVE_SPDIF_IN | 341 | |
329 | /* SPDIF */ | 342 | #ifdef HAVE_SPDIF_IN |
330 | case 2: | 343 | case AUDIO_SRC_SPDIF: |
331 | /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ | 344 | /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ |
332 | DATAINCONTROL = 0xc038; | 345 | DATAINCONTROL = 0xc038; |
333 | #ifdef HAVE_SPDIF_POWER | ||
334 | EBU1CONFIG = spdif_power_setting ? (1 << 2) : 0; | ||
335 | /* Input source is EBUin1, Feed-through monitoring if desired */ | ||
336 | #else | ||
337 | EBU1CONFIG = (1 << 2); | ||
338 | /* Input source is EBUin1, Feed-through monitoring */ | ||
339 | #endif | ||
340 | uda1380_disable_recording(); | ||
341 | break; | 346 | break; |
342 | #endif | 347 | #endif /* HAVE_SPDIF_IN */ |
343 | } | 348 | } |
344 | 349 | ||
345 | sample_rate = frequency; | 350 | sample_rate = frequency; |
346 | 351 | ||
@@ -349,7 +354,8 @@ void audio_set_recording_options(int frequency, int quality, | |||
349 | SET_IIS_PLAY(0x800); /* Reset before reprogram */ | 354 | SET_IIS_PLAY(0x800); /* Reset before reprogram */ |
350 | 355 | ||
351 | #ifdef HAVE_SPDIF_IN | 356 | #ifdef HAVE_SPDIF_IN |
352 | if (source == 2) { | 357 | if (source == AUDIO_SRC_SPDIF) |
358 | { | ||
353 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ | 359 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ |
354 | IIS2CONFIG = (6 << 12) | (7 << 8) | (4 << 2); | 360 | IIS2CONFIG = (6 << 12) | (7 << 8) | (4 << 2); |
355 | /* S/PDIF feed-through already configured */ | 361 | /* S/PDIF feed-through already configured */ |
@@ -367,6 +373,8 @@ void audio_set_recording_options(int frequency, int quality, | |||
367 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | 373 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ |
368 | SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); | 374 | SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); |
369 | #endif | 375 | #endif |
376 | |||
377 | audio_load_encoder(rec_quality_info_afmt[quality]); | ||
370 | } | 378 | } |
371 | 379 | ||
372 | 380 | ||
@@ -380,10 +388,9 @@ void audio_set_recording_options(int frequency, int quality, | |||
380 | void audio_set_recording_gain(int left, int right, int type) | 388 | void audio_set_recording_gain(int left, int right, int type) |
381 | { | 389 | { |
382 | //logf("rcmrec: t=%d l=%d r=%d", type, left, right); | 390 | //logf("rcmrec: t=%d l=%d r=%d", type, left, right); |
383 | #ifdef HAVE_UDA1380 | 391 | #if defined(HAVE_UDA1380) |
384 | uda1380_set_recvol(left, right, type); | 392 | uda1380_set_recvol(left, right, type); |
385 | #endif | 393 | #elif defined (HAVE_TLV320) |
386 | #ifdef HAVE_TLV320 | ||
387 | tlv320_set_recvol(left, right, type); | 394 | tlv320_set_recvol(left, right, type); |
388 | #endif | 395 | #endif |
389 | } | 396 | } |
@@ -406,7 +413,7 @@ void audio_record(const char *filename) | |||
406 | recording_filename[MAX_PATH - 1] = 0; | 413 | recording_filename[MAX_PATH - 1] = 0; |
407 | 414 | ||
408 | #ifdef HAVE_SPDIF_IN | 415 | #ifdef HAVE_SPDIF_IN |
409 | if (rec_source == 2) | 416 | if (rec_source == AUDIO_SRC_SPDIF) |
410 | sample_rate = audio_get_spdif_sample_rate(); | 417 | sample_rate = audio_get_spdif_sample_rate(); |
411 | #endif | 418 | #endif |
412 | 419 | ||
@@ -447,6 +454,7 @@ void audio_stop_recording(void) | |||
447 | 454 | ||
448 | logf("pcm_stop"); | 455 | logf("pcm_stop"); |
449 | 456 | ||
457 | is_paused = true; /* fix pcm write ptr at current position */ | ||
450 | stop_done = false; | 458 | stop_done = false; |
451 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 459 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); |
452 | 460 | ||
@@ -499,9 +507,9 @@ void audio_resume_recording(void) | |||
499 | void pcm_rec_get_peaks(int *left, int *right) | 507 | void pcm_rec_get_peaks(int *left, int *right) |
500 | { | 508 | { |
501 | if (left) | 509 | if (left) |
502 | *left = (int)peak_left; | 510 | *left = peak_left; |
503 | if (right) | 511 | if (right) |
504 | *right = (int)peak_right; | 512 | *right = peak_right; |
505 | peak_left = 0; | 513 | peak_left = 0; |
506 | peak_right = 0; | 514 | peak_right = 0; |
507 | } | 515 | } |
@@ -511,7 +519,7 @@ void pcm_rec_get_peaks(int *left, int *right) | |||
511 | /***************************************************************************/ | 519 | /***************************************************************************/ |
512 | 520 | ||
513 | /** | 521 | /** |
514 | * Process the chunks using read_index and write_index. | 522 | * Process the chunks |
515 | * | 523 | * |
516 | * This function is called when queue_get_w_tmo times out. | 524 | * This function is called when queue_get_w_tmo times out. |
517 | * | 525 | * |
@@ -519,70 +527,24 @@ void pcm_rec_get_peaks(int *left, int *right) | |||
519 | * they want to save everything in the buffers to disk. | 527 | * they want to save everything in the buffers to disk. |
520 | * | 528 | * |
521 | */ | 529 | */ |
522 | |||
523 | static void pcmrec_callback(bool flush) ICODE_ATTR; | ||
524 | static void pcmrec_callback(bool flush) | 530 | static void pcmrec_callback(bool flush) |
525 | { | 531 | { |
526 | int num_ready, num_free, num_new; | 532 | int i, num_ready, size_yield; |
527 | short *ptr; | 533 | long *enc_chunk, chunk_size; |
528 | short value; | ||
529 | int i, j, w; | ||
530 | |||
531 | w = write_index; | ||
532 | |||
533 | num_new = w - read2_index; | ||
534 | if (num_new < 0) | ||
535 | num_new += num_chunks; | ||
536 | |||
537 | for (i=0; i<num_new; i++) | ||
538 | { | ||
539 | /* Convert the samples to little-endian so we only have to write later | ||
540 | (Less hd-spinning time), also do peak detection while we're at it | ||
541 | */ | ||
542 | ptr = GET_CHUNK(read2_index); | ||
543 | for (j=0; j<CHUNK_SIZE/4; j++) | ||
544 | { | ||
545 | value = *ptr; | ||
546 | if(value > peak_left) | ||
547 | peak_left = value; | ||
548 | else if (-value > peak_left) | ||
549 | peak_left = -value; | ||
550 | |||
551 | *ptr = htole16(value); | ||
552 | ptr++; | ||
553 | |||
554 | value = *ptr; | ||
555 | if(value > peak_right) | ||
556 | peak_right = value; | ||
557 | else if (-value > peak_right) | ||
558 | peak_right = -value; | ||
559 | |||
560 | *ptr = htole16(value); | ||
561 | ptr++; | ||
562 | } | ||
563 | 534 | ||
564 | if(is_recording && !is_paused) | 535 | if (!is_recording && !flush) |
565 | num_rec_bytes += CHUNK_SIZE; | ||
566 | |||
567 | read2_index++; | ||
568 | if (read2_index >= num_chunks) | ||
569 | read2_index = 0; | ||
570 | } | ||
571 | |||
572 | if ((!is_recording || is_paused) && !flush) | ||
573 | { | ||
574 | /* not recording = no saving to disk, fake buffer clearing */ | ||
575 | read_index = write_index; | ||
576 | return; | 536 | return; |
577 | } | ||
578 | 537 | ||
579 | num_ready = w - read_index; | 538 | num_ready = enc_wr_index - enc_rd_index; |
580 | if (num_ready < 0) | 539 | if (num_ready < 0) |
581 | num_ready += num_chunks; | 540 | num_ready += enc_num_chunks; |
582 | 541 | ||
583 | num_free = num_chunks - num_ready; | 542 | /* calculate an estimate of recorded bytes */ |
584 | 543 | num_rec_bytes = num_file_bytes + num_ready * /* enc_chunk_size */ | |
585 | if (num_free <= WRITE_THRESHOLD || flush) | 544 | ((avrg_bit_rate * 1000 / 8 * enc_samp_per_chunk + 22050) / 44100); |
545 | |||
546 | /* near full state reached: less than 5sec remaining space */ | ||
547 | if (enc_num_chunks - num_ready < WRITE_THRESHOLD || flush) | ||
586 | { | 548 | { |
587 | bool must_boost = (boost_counter ? false : true); | 549 | bool must_boost = (boost_counter ? false : true); |
588 | 550 | ||
@@ -591,23 +553,41 @@ static void pcmrec_callback(bool flush) | |||
591 | if(must_boost) | 553 | if(must_boost) |
592 | cpu_boost(true); | 554 | cpu_boost(true); |
593 | 555 | ||
556 | size_yield = 0; | ||
594 | for (i=0; i<num_ready; i++) | 557 | for (i=0; i<num_ready; i++) |
595 | { | 558 | { |
596 | if (write(wav_file, GET_CHUNK(read_index), CHUNK_SIZE) != CHUNK_SIZE) | 559 | enc_chunk = GET_ENC_CHUNK(enc_rd_index); |
560 | chunk_size = *enc_chunk++; | ||
561 | |||
562 | /* safety net: if size entry got corrupted => limit */ | ||
563 | if (chunk_size > (long)(enc_chunk_size - sizeof(long))) | ||
564 | chunk_size = enc_chunk_size - sizeof(long); | ||
565 | |||
566 | if (enc_set_header_callback != NULL) | ||
567 | enc_set_header_callback(enc_chunk, enc_chunk_size, | ||
568 | num_pcm_samples, false); | ||
569 | |||
570 | if (write(wav_file, enc_chunk, chunk_size) != chunk_size) | ||
597 | { | 571 | { |
572 | close_wave(); | ||
598 | if(must_boost) | 573 | if(must_boost) |
599 | cpu_boost(false); | 574 | cpu_boost(false); |
600 | logf("pcmrec: write err"); | 575 | logf("pcmrec: write err"); |
601 | pcmrec_dma_stop(); | 576 | is_error = true; |
602 | return; | 577 | break; |
603 | } | 578 | } |
604 | 579 | ||
605 | num_file_bytes += CHUNK_SIZE; | 580 | num_file_bytes += chunk_size; |
606 | 581 | num_pcm_samples += enc_samp_per_chunk; | |
607 | read_index++; | 582 | size_yield += chunk_size; |
608 | if (read_index >= num_chunks) | 583 | |
609 | read_index = 0; | 584 | if (size_yield >= 32768) |
610 | yield(); | 585 | { /* yield when 32kB written */ |
586 | size_yield = 0; | ||
587 | yield(); | ||
588 | } | ||
589 | |||
590 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | ||
611 | } | 591 | } |
612 | 592 | ||
613 | if(must_boost) | 593 | if(must_boost) |
@@ -623,36 +603,33 @@ static void pcmrec_callback(bool flush) | |||
623 | /* Abort dma transfer */ | 603 | /* Abort dma transfer */ |
624 | static void pcmrec_dma_stop(void) | 604 | static void pcmrec_dma_stop(void) |
625 | { | 605 | { |
626 | DCR1 = 0; | 606 | DCR1 = 0; |
627 | 607 | ||
628 | is_error = true; | ||
629 | is_recording = false; | ||
630 | |||
631 | error_count++; | 608 | error_count++; |
632 | 609 | ||
610 | DSR1 = 1; /* Clear interrupt */ | ||
611 | IPR |= (1<<15); /* Clear pending interrupt request */ | ||
612 | |||
633 | logf("dma1 stopped"); | 613 | logf("dma1 stopped"); |
634 | } | 614 | } |
635 | 615 | ||
636 | static void pcmrec_dma_start(void) | 616 | static void pcmrec_dma_start(void) |
637 | { | 617 | { |
638 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ | 618 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ |
639 | SAR1 = (unsigned long)&PDIR2; /* Source address */ | 619 | SAR1 = (unsigned long)&PDIR2; /* Source address */ |
640 | BCR1 = CHUNK_SIZE; /* Bytes to transfer */ | 620 | BCR1 = CHUNK_SIZE; /* Bytes to transfer */ |
641 | 621 | ||
642 | /* Start the DMA transfer.. */ | 622 | /* Start the DMA transfer.. */ |
643 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; | ||
644 | |||
645 | #ifdef HAVE_SPDIF_IN | 623 | #ifdef HAVE_SPDIF_IN |
646 | INTERRUPTCLEAR = 0x03c00000; | 624 | INTERRUPTCLEAR = 0x03c00000; |
647 | #endif | 625 | #endif |
648 | 626 | ||
649 | /* pre-recording: buffer count */ | 627 | /* 16Byte transfers prevents from sporadic errors during cpu_boost() */ |
650 | buffered_chunks = 0; | 628 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_DSIZE(3) | DMA_START; |
651 | 629 | ||
652 | logf("dma1 started"); | 630 | logf("dma1 started"); |
653 | } | 631 | } |
654 | 632 | ||
655 | |||
656 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */ | 633 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */ |
657 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); | 634 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); |
658 | void DMA1(void) | 635 | void DMA1(void) |
@@ -668,62 +645,64 @@ void DMA1(void) | |||
668 | 645 | ||
669 | logf("dma1 err: 0x%x", res); | 646 | logf("dma1 err: 0x%x", res); |
670 | 647 | ||
671 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ | 648 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ |
672 | BCR1 = CHUNK_SIZE; | 649 | BCR1 = CHUNK_SIZE; |
673 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; | 650 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; |
651 | |||
652 | /* Flush recorded data to disk and stop recording */ | ||
653 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
674 | } | 654 | } |
675 | #ifdef HAVE_SPDIF_IN | 655 | #ifdef HAVE_SPDIF_IN |
676 | else if ((rec_source == 2) && (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ | 656 | else if ((rec_source == AUDIO_SRC_SPDIF) && |
657 | (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ | ||
677 | { | 658 | { |
678 | INTERRUPTCLEAR = 0x03c00000; | 659 | INTERRUPTCLEAR = 0x03c00000; |
679 | error_count++; | 660 | error_count++; |
680 | 661 | ||
681 | logf("spdif err"); | 662 | logf("spdif err"); |
682 | 663 | ||
683 | if (is_stopping) | 664 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ |
684 | { | 665 | BCR1 = CHUNK_SIZE; |
685 | DCR1 = 0; /* Stop DMA transfer */ | ||
686 | is_stopping = false; | ||
687 | |||
688 | logf("dma1 stopping"); | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ | ||
693 | BCR1 = CHUNK_SIZE; | ||
694 | } | ||
695 | } | 666 | } |
696 | #endif | 667 | #endif |
697 | else | 668 | else |
698 | { | 669 | { |
699 | write_index++; | 670 | long peak_l, peak_r; |
700 | if (write_index >= num_chunks) | 671 | long *ptr, j; |
701 | write_index = 0; | ||
702 | 672 | ||
703 | /* update number of valid chunks for pre-recording */ | 673 | ptr = GET_CHUNK(write_pos); |
704 | if(buffered_chunks < num_chunks) | ||
705 | buffered_chunks++; | ||
706 | 674 | ||
707 | if (is_stopping) | 675 | if (!is_paused) /* advance write position */ |
708 | { | 676 | write_pos = (write_pos + CHUNK_SIZE) & CHUNK_MASK; |
709 | DCR1 = 0; /* Stop DMA transfer */ | ||
710 | is_stopping = false; | ||
711 | 677 | ||
712 | logf("dma1 stopping"); | 678 | DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ |
713 | } | 679 | BCR1 = CHUNK_SIZE; |
714 | else if (write_index == read_index) | ||
715 | { | ||
716 | DCR1 = 0; /* Stop DMA transfer */ | ||
717 | is_recording = false; | ||
718 | 680 | ||
719 | logf("dma1 overrun"); | 681 | peak_l = peak_r = 0; |
720 | 682 | ||
721 | } | 683 | /* only peak every 4th sample */ |
722 | else | 684 | for (j=0; j<CHUNK_SIZE/4; j+=4) |
723 | { | 685 | { |
724 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ | 686 | long value = ptr[j]; |
725 | BCR1 = CHUNK_SIZE; | 687 | #ifdef ROCKBOX_BIG_ENDIAN |
688 | if (value > peak_l) peak_l = value; | ||
689 | else if (-value > peak_l) peak_l = -value; | ||
690 | |||
691 | value <<= 16; | ||
692 | if (value > peak_r) peak_r = value; | ||
693 | else if (-value > peak_r) peak_r = -value; | ||
694 | #else | ||
695 | if (value > peak_r) peak_r = value; | ||
696 | else if (-value > peak_r) peak_r = -value; | ||
697 | |||
698 | value <<= 16; | ||
699 | if (value > peak_l) peak_l = value; | ||
700 | else if (-value > peak_l) peak_l = -value; | ||
701 | #endif | ||
726 | } | 702 | } |
703 | |||
704 | peak_left = (int)(peak_l >> 16); | ||
705 | peak_right = (int)(peak_r >> 16); | ||
727 | } | 706 | } |
728 | 707 | ||
729 | IPR |= (1<<15); /* Clear pending interrupt request */ | 708 | IPR |= (1<<15); /* Clear pending interrupt request */ |
@@ -733,15 +712,8 @@ void DMA1(void) | |||
733 | /* Sets returns 0 if success, -1 on failure */ | 712 | /* Sets returns 0 if success, -1 on failure */ |
734 | static int start_wave(void) | 713 | static int start_wave(void) |
735 | { | 714 | { |
736 | unsigned char header[44] = | ||
737 | { | ||
738 | 'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ', | ||
739 | 0x10,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0, | ||
740 | 4,0,0x10,0,'d','a','t','a',0,0,0,0 | ||
741 | }; | ||
742 | unsigned long avg_bytes_per_sec; | ||
743 | |||
744 | wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC); | 715 | wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC); |
716 | |||
745 | if (wav_file < 0) | 717 | if (wav_file < 0) |
746 | { | 718 | { |
747 | wav_file = -1; | 719 | wav_file = -1; |
@@ -749,19 +721,9 @@ static int start_wave(void) | |||
749 | is_error = true; | 721 | is_error = true; |
750 | return -1; | 722 | return -1; |
751 | } | 723 | } |
752 | /* Now set the sample rate field of the WAV header to what it should be */ | ||
753 | header[24] = (unsigned char)(sample_rate & 0xff); | ||
754 | header[25] = (unsigned char)(sample_rate >> 8); | ||
755 | header[26] = (unsigned char)(sample_rate >> 16); | ||
756 | header[27] = (unsigned char)(sample_rate >> 24); | ||
757 | /* And then the average bytes per second field */ | ||
758 | avg_bytes_per_sec = sample_rate*4; /* Hard coded to 16 bit stereo */ | ||
759 | header[28] = (unsigned char)(avg_bytes_per_sec & 0xff); | ||
760 | header[29] = (unsigned char)(avg_bytes_per_sec >> 8); | ||
761 | header[30] = (unsigned char)(avg_bytes_per_sec >> 16); | ||
762 | header[31] = (unsigned char)(avg_bytes_per_sec >> 24); | ||
763 | 724 | ||
764 | if (sizeof(header) != write(wav_file, header, sizeof(header))) | 725 | /* add main file header (enc_head_size=0 for encoders without) */ |
726 | if (enc_head_size != write(wav_file, enc_head_buffer, enc_head_size)) | ||
765 | { | 727 | { |
766 | close(wav_file); | 728 | close(wav_file); |
767 | wav_file = -1; | 729 | wav_file = -1; |
@@ -776,18 +738,22 @@ static int start_wave(void) | |||
776 | /* Update header and set correct length values */ | 738 | /* Update header and set correct length values */ |
777 | static void close_wave(void) | 739 | static void close_wave(void) |
778 | { | 740 | { |
779 | long l; | 741 | unsigned char head[100]; /* assume maximum 100 bytes for file header */ |
742 | int size_read; | ||
780 | 743 | ||
781 | if (wav_file != -1) | 744 | if (wav_file != -1) |
782 | { | 745 | { |
783 | l = htole32(num_file_bytes + 36); | 746 | /* update header before closing the file (wav+wv encoder will do) */ |
784 | lseek(wav_file, 4, SEEK_SET); | 747 | if (enc_set_header_callback != NULL) |
785 | write(wav_file, &l, 4); | 748 | { |
786 | 749 | lseek(wav_file, 0, SEEK_SET); | |
787 | l = htole32(num_file_bytes); | 750 | /* try to read the head size (but we'll accept less) */ |
788 | lseek(wav_file, 40, SEEK_SET); | 751 | size_read = read(wav_file, head, sizeof(head)); |
789 | write(wav_file, &l, 4); | 752 | |
790 | 753 | enc_set_header_callback(head, size_read, num_pcm_samples, true); | |
754 | lseek(wav_file, 0, SEEK_SET); | ||
755 | write(wav_file, head, size_read); | ||
756 | } | ||
791 | close(wav_file); | 757 | close(wav_file); |
792 | wav_file = -1; | 758 | wav_file = -1; |
793 | } | 759 | } |
@@ -795,8 +761,7 @@ static void close_wave(void) | |||
795 | 761 | ||
796 | static void pcmrec_start(void) | 762 | static void pcmrec_start(void) |
797 | { | 763 | { |
798 | int pre_chunks = pre_record_chunks; /* recalculate every time! */ | 764 | long max_pre_chunks, pre_ticks, max_pre_ticks; |
799 | long pre_ticks = pre_record_ticks; /* recalculate every time! */ | ||
800 | 765 | ||
801 | logf("pcmrec_start"); | 766 | logf("pcmrec_start"); |
802 | 767 | ||
@@ -808,7 +773,7 @@ static void pcmrec_start(void) | |||
808 | } | 773 | } |
809 | 774 | ||
810 | if (wav_file != -1) | 775 | if (wav_file != -1) |
811 | close(wav_file); | 776 | close_wave(); |
812 | 777 | ||
813 | if (start_wave() != 0) | 778 | if (start_wave() != 0) |
814 | { | 779 | { |
@@ -817,32 +782,29 @@ static void pcmrec_start(void) | |||
817 | return; | 782 | return; |
818 | } | 783 | } |
819 | 784 | ||
820 | /* pre-recording calculation */ | 785 | /* calculate maximum available chunks & resulting ticks */ |
821 | if(buffered_chunks < pre_chunks) | 786 | max_pre_chunks = (enc_wr_index - enc_rd_index + |
822 | { | 787 | enc_num_chunks) % enc_num_chunks; |
823 | /* not enough good chunks available - limit pre-record time */ | 788 | if (max_pre_chunks > enc_num_chunks - WRITE_THRESHOLD) |
824 | pre_chunks = buffered_chunks; | 789 | max_pre_chunks = enc_num_chunks - WRITE_THRESHOLD; |
825 | pre_ticks = ((buffered_chunks * CHUNK_SIZE)/(4*sample_rate)) * HZ; | 790 | max_pre_ticks = max_pre_chunks * HZ * enc_samp_per_chunk / 44100; |
826 | } | ||
827 | record_start_time = current_tick - pre_ticks; | ||
828 | 791 | ||
829 | read_index = write_index - pre_chunks; | 792 | /* limit prerecord if not enough data available */ |
830 | if(read_index < 0) | 793 | pre_ticks = pre_record_ticks > max_pre_ticks ? |
831 | { | 794 | max_pre_ticks : pre_record_ticks; |
832 | read_index += num_chunks; | 795 | max_pre_chunks = 44100 * pre_ticks / HZ / enc_samp_per_chunk; |
833 | } | 796 | enc_rd_index = (enc_wr_index - max_pre_chunks + |
797 | enc_num_chunks) % enc_num_chunks; | ||
834 | 798 | ||
835 | peak_left = 0; | 799 | record_start_time = current_tick - pre_ticks; |
836 | peak_right = 0; | 800 | |
837 | 801 | num_rec_bytes = enc_num_chunks * CHUNK_SIZE; | |
838 | num_rec_bytes = pre_chunks * CHUNK_SIZE; | ||
839 | num_file_bytes = 0; | 802 | num_file_bytes = 0; |
803 | num_pcm_samples = 0; | ||
840 | pause_start_time = 0; | 804 | pause_start_time = 0; |
841 | 805 | ||
842 | is_stopping = false; | ||
843 | is_paused = false; | 806 | is_paused = false; |
844 | is_recording = true; | 807 | is_recording = true; |
845 | |||
846 | record_done = true; | 808 | record_done = true; |
847 | } | 809 | } |
848 | 810 | ||
@@ -850,36 +812,24 @@ static void pcmrec_stop(void) | |||
850 | { | 812 | { |
851 | logf("pcmrec_stop"); | 813 | logf("pcmrec_stop"); |
852 | 814 | ||
853 | if (!is_recording) | 815 | if (is_recording) |
854 | { | 816 | { |
855 | stop_done = true; | 817 | /* wait for encoding finish */ |
856 | return; | 818 | is_paused = true; |
857 | } | 819 | while(!wav_queue_empty) |
858 | |||
859 | if (!is_paused) | ||
860 | { | ||
861 | /* wait for recording to finish */ | ||
862 | is_stopping = true; | ||
863 | |||
864 | while (is_stopping && is_recording) | ||
865 | sleep_thread(); | 820 | sleep_thread(); |
866 | wake_up_thread(); | ||
867 | |||
868 | is_stopping = false; | ||
869 | } | ||
870 | |||
871 | is_recording = false; | ||
872 | |||
873 | /* Flush buffers to file */ | ||
874 | pcmrec_callback(true); | ||
875 | 821 | ||
876 | close_wave(); | 822 | wake_up_thread(); |
823 | is_recording = false; | ||
877 | 824 | ||
825 | /* Flush buffers to file */ | ||
826 | pcmrec_callback(true); | ||
827 | close_wave(); | ||
828 | } | ||
829 | |||
830 | is_paused = false; | ||
878 | stop_done = true; | 831 | stop_done = true; |
879 | 832 | ||
880 | /* Finally start dma again for peakmeters and pre-recoding to work. */ | ||
881 | pcmrec_dma_start(); | ||
882 | |||
883 | logf("pcmrec_stop done"); | 833 | logf("pcmrec_stop done"); |
884 | } | 834 | } |
885 | 835 | ||
@@ -898,7 +848,6 @@ static void pcmrec_new_file(void) | |||
898 | here is a good approximation when recording to the new file starts | 848 | here is a good approximation when recording to the new file starts |
899 | */ | 849 | */ |
900 | record_start_time = current_tick; | 850 | record_start_time = current_tick; |
901 | num_rec_bytes = 0; | ||
902 | 851 | ||
903 | if (is_paused) | 852 | if (is_paused) |
904 | pause_start_time = record_start_time; | 853 | pause_start_time = record_start_time; |
@@ -908,7 +857,9 @@ static void pcmrec_new_file(void) | |||
908 | 857 | ||
909 | close_wave(); | 858 | close_wave(); |
910 | 859 | ||
860 | num_rec_bytes = 0; | ||
911 | num_file_bytes = 0; | 861 | num_file_bytes = 0; |
862 | num_pcm_samples = 0; | ||
912 | 863 | ||
913 | /* start the new file */ | 864 | /* start the new file */ |
914 | if (start_wave() != 0) | 865 | if (start_wave() != 0) |
@@ -932,20 +883,8 @@ static void pcmrec_pause(void) | |||
932 | return; | 883 | return; |
933 | } | 884 | } |
934 | 885 | ||
935 | /* Abort DMA transfer and flush to file? */ | ||
936 | |||
937 | is_stopping = true; | ||
938 | |||
939 | while (is_stopping && is_recording) | ||
940 | sleep_thread(); | ||
941 | wake_up_thread(); | ||
942 | |||
943 | pause_start_time = current_tick; | 886 | pause_start_time = current_tick; |
944 | is_paused = true; | 887 | is_paused = true; |
945 | |||
946 | /* Flush what we got in buffers to file */ | ||
947 | pcmrec_callback(true); | ||
948 | |||
949 | pause_done = true; | 888 | pause_done = true; |
950 | 889 | ||
951 | logf("pcmrec_pause done"); | 890 | logf("pcmrec_pause done"); |
@@ -973,10 +912,7 @@ static void pcmrec_resume(void) | |||
973 | pause_start_time = 0; | 912 | pause_start_time = 0; |
974 | } | 913 | } |
975 | 914 | ||
976 | pcmrec_dma_start(); | ||
977 | |||
978 | resume_done = true; | 915 | resume_done = true; |
979 | |||
980 | logf("pcmrec_resume done"); | 916 | logf("pcmrec_resume done"); |
981 | } | 917 | } |
982 | 918 | ||
@@ -986,50 +922,47 @@ static void pcmrec_resume(void) | |||
986 | */ | 922 | */ |
987 | static void pcmrec_init(void) | 923 | static void pcmrec_init(void) |
988 | { | 924 | { |
989 | unsigned long buffer_size; | ||
990 | |||
991 | wav_file = -1; | 925 | wav_file = -1; |
992 | read_index = 0; | 926 | read_pos = 0; |
993 | read2_index = 0; | 927 | write_pos = 0; |
994 | write_index = 0; | 928 | enc_wr_index = 0; |
995 | pre_record_chunks = 0; | 929 | enc_rd_index = 0; |
996 | pre_record_ticks = 0; | 930 | |
931 | avrg_bit_rate = 0; | ||
932 | curr_bit_rate = 0; | ||
933 | curr_chunk_cnt = 0; | ||
997 | 934 | ||
998 | peak_left = 0; | 935 | peak_left = 0; |
999 | peak_right = 0; | 936 | peak_right = 0; |
1000 | 937 | ||
1001 | num_rec_bytes = 0; | 938 | num_rec_bytes = 0; |
1002 | num_file_bytes = 0; | 939 | num_file_bytes = 0; |
940 | num_pcm_samples = 0; | ||
1003 | record_start_time = 0; | 941 | record_start_time = 0; |
1004 | pause_start_time = 0; | 942 | pause_start_time = 0; |
1005 | buffered_chunks = 0; | 943 | |
1006 | 944 | close_done = false; | |
1007 | is_recording = false; | 945 | is_recording = false; |
1008 | is_stopping = false; | ||
1009 | is_paused = false; | 946 | is_paused = false; |
1010 | is_error = false; | 947 | is_error = false; |
1011 | 948 | ||
1012 | rec_buffer = (unsigned char*)(((unsigned long)audiobuf + rec_buffer_offset) & ~3); | 949 | rec_buffer = (unsigned char*)(((long)audiobuf + 15) & ~15); |
1013 | buffer_size = (long)audiobufend - (long)audiobuf - rec_buffer_offset - 16; | 950 | enc_buffer = rec_buffer + NUM_CHUNKS * CHUNK_SIZE + MAX_FEED_SIZE; |
1014 | 951 | /* 8000Bytes at audiobufend */ | |
1015 | logf("buf size: %d kb", buffer_size/1024); | 952 | enc_buffer_size = audiobufend - enc_buffer - 8000; |
1016 | |||
1017 | num_chunks = buffer_size / CHUNK_SIZE; | ||
1018 | |||
1019 | logf("num_chunks: %d", num_chunks); | ||
1020 | 953 | ||
1021 | SET_IIS_PLAY(0x800); /* Stop any playback */ | 954 | SET_IIS_PLAY(0x800); /* Stop any playback */ |
1022 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ | 955 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ |
1023 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ | 956 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ |
1024 | 957 | ||
1025 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ | 958 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ |
1026 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ | 959 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ |
1027 | DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; | 960 | DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; |
1028 | ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ | 961 | ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ |
1029 | IMR &= ~(1<<15); /* bit 15 is DMA1 */ | 962 | IMR &= ~(1<<15); /* bit 15 is DMA1 */ |
1030 | 963 | ||
1031 | #ifdef HAVE_SPDIF_IN | 964 | #ifdef HAVE_SPDIF_IN |
1032 | PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ | 965 | PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ |
1033 | #endif | 966 | #endif |
1034 | pcmrec_dma_start(); | 967 | pcmrec_dma_start(); |
1035 | 968 | ||
@@ -1038,23 +971,16 @@ static void pcmrec_init(void) | |||
1038 | 971 | ||
1039 | static void pcmrec_close(void) | 972 | static void pcmrec_close(void) |
1040 | { | 973 | { |
1041 | #ifdef HAVE_UDA1380 | ||
1042 | uda1380_disable_recording(); | ||
1043 | #endif | ||
1044 | #ifdef HAVE_TLV320 | ||
1045 | tlv320_disable_recording(); | ||
1046 | #endif | ||
1047 | |||
1048 | #ifdef HAVE_SPDIF_POWER | ||
1049 | spdif_power_enable(spdif_power_setting); | ||
1050 | #endif | ||
1051 | DMAROUTE = (DMAROUTE & 0xffff00ff); | 974 | DMAROUTE = (DMAROUTE & 0xffff00ff); |
1052 | ICR7 = 0x00; /* Disable interrupt */ | 975 | ICR7 = 0x00; /* Disable interrupt */ |
1053 | IMR |= (1<<15); /* bit 15 is DMA1 */ | 976 | IMR |= (1<<15); /* bit 15 is DMA1 */ |
1054 | 977 | ||
978 | pcmrec_dma_stop(); | ||
979 | |||
1055 | /* Reset PDIR2 data flow */ | 980 | /* Reset PDIR2 data flow */ |
1056 | DATAINCONTROL = 0x200; | 981 | DATAINCONTROL = 0x200; |
1057 | close_done = true; | 982 | close_done = true; |
983 | init_done = false; | ||
1058 | } | 984 | } |
1059 | 985 | ||
1060 | static void pcmrec_thread(void) | 986 | static void pcmrec_thread(void) |
@@ -1064,10 +990,10 @@ static void pcmrec_thread(void) | |||
1064 | logf("thread pcmrec start"); | 990 | logf("thread pcmrec start"); |
1065 | 991 | ||
1066 | error_count = 0; | 992 | error_count = 0; |
1067 | 993 | ||
1068 | while (1) | 994 | while(1) |
1069 | { | 995 | { |
1070 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 40); | 996 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 4); |
1071 | 997 | ||
1072 | switch (ev.id) | 998 | switch (ev.id) |
1073 | { | 999 | { |
@@ -1104,8 +1030,9 @@ static void pcmrec_thread(void) | |||
1104 | break; | 1030 | break; |
1105 | 1031 | ||
1106 | case SYS_USB_CONNECTED: | 1032 | case SYS_USB_CONNECTED: |
1107 | if (!is_recording && !is_stopping) | 1033 | if (!is_recording) |
1108 | { | 1034 | { |
1035 | pcmrec_close(); | ||
1109 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 1036 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
1110 | usb_wait_for_disconnect(&pcmrec_queue); | 1037 | usb_wait_for_disconnect(&pcmrec_queue); |
1111 | } | 1038 | } |
@@ -1148,3 +1075,102 @@ void pcm_rec_mux(int source) | |||
1148 | /* iAudio x5 */ | 1075 | /* iAudio x5 */ |
1149 | #endif | 1076 | #endif |
1150 | } | 1077 | } |
1078 | |||
1079 | |||
1080 | /****************************************************************************/ | ||
1081 | /* */ | ||
1082 | /* following functions will be called by the encoder codec */ | ||
1083 | /* */ | ||
1084 | /****************************************************************************/ | ||
1085 | |||
1086 | /* pass the encoder buffer pointer/size, mono/stereo, quality to the encoder */ | ||
1087 | void enc_get_inputs(int *buffer_size, int *channels, int *quality) | ||
1088 | { | ||
1089 | *buffer_size = enc_buffer_size; | ||
1090 | *channels = enc_channels; | ||
1091 | *quality = enc_quality; | ||
1092 | } | ||
1093 | |||
1094 | /* set the encoder dimensions (called by encoder codec at initialization) */ | ||
1095 | void enc_set_parameters(int chunk_size, int num_chunks, int samp_per_chunk, | ||
1096 | char *head_ptr, int head_size, int enc_id) | ||
1097 | { | ||
1098 | /* set read_pos just in front of current write_pos */ | ||
1099 | read_pos = (write_pos - CHUNK_SIZE) & CHUNK_MASK; | ||
1100 | |||
1101 | enc_rd_index = 0; /* reset */ | ||
1102 | enc_wr_index = 0; /* reset */ | ||
1103 | enc_chunk_size = chunk_size; /* max chunk size */ | ||
1104 | enc_num_chunks = num_chunks; /* total number of chunks */ | ||
1105 | enc_samp_per_chunk = samp_per_chunk; /* pcm samples / encoderchunk */ | ||
1106 | enc_head_buffer = head_ptr; /* optional file header data (wav) */ | ||
1107 | enc_head_size = head_size; /* optional file header data (wav) */ | ||
1108 | audio_enc_id = enc_id; /* AFMT_* id */ | ||
1109 | } | ||
1110 | |||
1111 | /* allocate encoder chunk */ | ||
1112 | unsigned int *enc_alloc_chunk(void) | ||
1113 | { | ||
1114 | return (unsigned int*)(enc_buffer + enc_wr_index * enc_chunk_size); | ||
1115 | } | ||
1116 | |||
1117 | /* free previously allocated encoder chunk */ | ||
1118 | void enc_free_chunk(void) | ||
1119 | { | ||
1120 | unsigned long *enc_chunk; | ||
1121 | |||
1122 | enc_chunk = GET_ENC_CHUNK(enc_wr_index); | ||
1123 | curr_chunk_cnt++; | ||
1124 | /* curr_bit_rate += *enc_chunk * 44100 * 8 / (enc_samp_per_chunk * 1000); */ | ||
1125 | curr_bit_rate += *enc_chunk * 441 * 8 / (enc_samp_per_chunk * 10 ); | ||
1126 | avrg_bit_rate = (curr_bit_rate + curr_chunk_cnt / 2) / curr_chunk_cnt; | ||
1127 | |||
1128 | /* advance enc_wr_index to the next chunk */ | ||
1129 | enc_wr_index = (enc_wr_index + 1) % enc_num_chunks; | ||
1130 | |||
1131 | /* buffer full: advance enc_rd_index (for prerecording purpose) */ | ||
1132 | if (enc_rd_index == enc_wr_index) | ||
1133 | { | ||
1134 | enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | /* checks near empty state on wav input buffer */ | ||
1139 | int enc_wavbuf_near_empty(void) | ||
1140 | { | ||
1141 | /* less than 1sec raw data? => unboost encoder */ | ||
1142 | if (((write_pos - read_pos) & CHUNK_MASK) < 44100*4) | ||
1143 | return 1; | ||
1144 | else | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | /* passes a pointer to next chunk of unprocessed wav data */ | ||
1149 | char *enc_get_wav_data(int size) | ||
1150 | { | ||
1151 | char *ptr; | ||
1152 | int avail; | ||
1153 | |||
1154 | /* limit the requested pcm data size */ | ||
1155 | if(size > MAX_FEED_SIZE) | ||
1156 | size = MAX_FEED_SIZE; | ||
1157 | |||
1158 | avail = (write_pos - read_pos) & CHUNK_MASK; | ||
1159 | |||
1160 | if (avail >= size) | ||
1161 | { | ||
1162 | ptr = rec_buffer + read_pos; | ||
1163 | read_pos = (read_pos + size) & CHUNK_MASK; | ||
1164 | |||
1165 | /* ptr must point to continous data at wraparound position */ | ||
1166 | if (read_pos < size) | ||
1167 | memcpy(rec_buffer + NUM_CHUNKS * CHUNK_SIZE, | ||
1168 | rec_buffer, read_pos); | ||
1169 | |||
1170 | wav_queue_empty = false; | ||
1171 | return ptr; | ||
1172 | } | ||
1173 | |||
1174 | wav_queue_empty = true; | ||
1175 | return NULL; | ||
1176 | } | ||