diff options
-rw-r--r-- | apps/SOURCES | 3 | ||||
-rw-r--r-- | apps/debug_menu.c | 4 | ||||
-rw-r--r-- | apps/lang/english.lang | 22 | ||||
-rw-r--r-- | apps/main.c | 2 | ||||
-rw-r--r-- | apps/recorder/radio.c | 32 | ||||
-rw-r--r-- | apps/recorder/recording.c | 114 | ||||
-rw-r--r-- | apps/settings.c | 23 | ||||
-rw-r--r-- | apps/settings.h | 5 | ||||
-rw-r--r-- | apps/sound_menu.c | 34 | ||||
-rw-r--r-- | firmware/drivers/uda1380.c | 33 | ||||
-rw-r--r-- | firmware/export/audio.h | 23 | ||||
-rw-r--r-- | firmware/export/config-h120.h | 2 | ||||
-rw-r--r-- | firmware/export/mpeg.h | 13 | ||||
-rw-r--r-- | firmware/export/pcm_record.h | 32 | ||||
-rw-r--r-- | firmware/export/sound.h | 6 | ||||
-rw-r--r-- | firmware/export/uda1380.h | 2 | ||||
-rw-r--r-- | firmware/mpeg.c | 51 | ||||
-rw-r--r-- | firmware/pcm_record.c | 717 | ||||
-rw-r--r-- | firmware/sound.c | 30 |
19 files changed, 770 insertions, 378 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 8b2184baca..6b2b68236b 100644 --- a/apps/SOURCES +++ b/apps/SOURCES | |||
@@ -65,7 +65,4 @@ playback.c | |||
65 | metadata.c | 65 | metadata.c |
66 | codecs.c | 66 | codecs.c |
67 | dsp.c | 67 | dsp.c |
68 | #ifndef SIMULATOR | ||
69 | pcm_recording.c | ||
70 | #endif | ||
71 | #endif | 68 | #endif |
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index cd395cc9f3..dd6a2d76a5 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -58,9 +58,6 @@ | |||
58 | #include "ata_mmc.h" | 58 | #include "ata_mmc.h" |
59 | #endif | 59 | #endif |
60 | #include "logfdisp.h" | 60 | #include "logfdisp.h" |
61 | #if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) | ||
62 | extern bool pcm_rec_screen(void); | ||
63 | #endif | ||
64 | #if CONFIG_CODEC == SWCODEC | 61 | #if CONFIG_CODEC == SWCODEC |
65 | #include "pcmbuf.h" | 62 | #include "pcmbuf.h" |
66 | #include "pcm_playback.h" | 63 | #include "pcm_playback.h" |
@@ -1781,7 +1778,6 @@ bool debug_menu(void) | |||
1781 | { "CPU frequency", dbg_cpufreq }, | 1778 | { "CPU frequency", dbg_cpufreq }, |
1782 | #endif | 1779 | #endif |
1783 | #if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) | 1780 | #if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) |
1784 | { "PCM recording", pcm_rec_screen }, | ||
1785 | { "S/PDIF analyzer", dbg_spdif }, | 1781 | { "S/PDIF analyzer", dbg_spdif }, |
1786 | #endif | 1782 | #endif |
1787 | #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE) | 1783 | #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE) |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 9d547173c7..9123066627 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -939,13 +939,13 @@ new: | |||
939 | 939 | ||
940 | id: LANG_RECORDING_LEFT | 940 | id: LANG_RECORDING_LEFT |
941 | desc: in the recording screen | 941 | desc: in the recording screen |
942 | eng: "Left" | 942 | eng: "Gain Left" |
943 | voice: "" | 943 | voice: "" |
944 | new: | 944 | new: |
945 | 945 | ||
946 | id: LANG_RECORDING_RIGHT | 946 | id: LANG_RECORDING_RIGHT |
947 | desc: in the recording screen | 947 | desc: in the recording screen |
948 | eng: "Right" | 948 | eng: "Gain Right" |
949 | voice: "" | 949 | voice: "" |
950 | new: | 950 | new: |
951 | 951 | ||
@@ -3352,3 +3352,21 @@ desc: in crossfade settings menu | |||
3352 | eng: "Fade out mode" | 3352 | eng: "Fade out mode" |
3353 | voice: "Fade out mode" | 3353 | voice: "Fade out mode" |
3354 | new: | 3354 | new: |
3355 | |||
3356 | id: LANG_RECORDING_ADC_RIGHT | ||
3357 | desc: in the recording settings | ||
3358 | eng: "ADC Gain Right" | ||
3359 | voice: "ADC Gain Right" | ||
3360 | new: | ||
3361 | |||
3362 | id: LANG_RECORDING_ADC_LEFT | ||
3363 | desc: in the recording settings | ||
3364 | eng: "ADC Gain Left" | ||
3365 | voice: "ADC Gain Left" | ||
3366 | new: | ||
3367 | |||
3368 | id: LANG_RECORDING_MONITOR | ||
3369 | desc: in the recording settings | ||
3370 | eng: "Monitor Mode" | ||
3371 | voice: "Monitor Mode" | ||
3372 | new: | ||
diff --git a/apps/main.c b/apps/main.c index 296b3fc351..ab802d5e24 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -323,7 +323,7 @@ void init(void) | |||
323 | sound_settings_apply(); | 323 | sound_settings_apply(); |
324 | #endif | 324 | #endif |
325 | #if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) | 325 | #if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) |
326 | pcm_init_recording(); | 326 | pcm_rec_init(); |
327 | #endif | 327 | #endif |
328 | talk_init(); | 328 | talk_init(); |
329 | /* runtime database has to be initialized after audio_init() */ | 329 | /* runtime database has to be initialized after audio_init() */ |
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index 443bb3192f..6be6d04e72 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c | |||
@@ -226,7 +226,7 @@ bool radio_screen(void) | |||
226 | audio_stop(); | 226 | audio_stop(); |
227 | 227 | ||
228 | #if CONFIG_CODEC != SWCODEC | 228 | #if CONFIG_CODEC != SWCODEC |
229 | mpeg_init_recording(); | 229 | audio_init_recording(); |
230 | 230 | ||
231 | sound_settings_apply(); | 231 | sound_settings_apply(); |
232 | 232 | ||
@@ -238,23 +238,24 @@ bool radio_screen(void) | |||
238 | if (global_settings.rec_prerecord_time) | 238 | if (global_settings.rec_prerecord_time) |
239 | talk_buffer_steal(); /* will use the mp3 buffer */ | 239 | talk_buffer_steal(); /* will use the mp3 buffer */ |
240 | 240 | ||
241 | mpeg_set_recording_options(global_settings.rec_frequency, | 241 | audio_set_recording_options(global_settings.rec_frequency, |
242 | global_settings.rec_quality, | 242 | global_settings.rec_quality, |
243 | 1, /* Line In */ | 243 | 1, /* Line In */ |
244 | global_settings.rec_channels, | 244 | global_settings.rec_channels, |
245 | global_settings.rec_editable, | 245 | global_settings.rec_editable, |
246 | global_settings.rec_prerecord_time); | 246 | global_settings.rec_prerecord_time, |
247 | global_settings.rec_monitor); | ||
247 | 248 | ||
248 | 249 | ||
249 | mpeg_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | 250 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), |
250 | sound_default(SOUND_RIGHT_GAIN), false); | 251 | sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); |
251 | #else | 252 | #else |
252 | uda1380_enable_recording(false); | 253 | uda1380_enable_recording(false); |
253 | uda1380_set_recvol(0, 0, 10); | 254 | uda1380_set_recvol(10, 10, AUDIO_GAIN_LINEIN); |
254 | uda1380_set_monitor(true); | 255 | uda1380_set_monitor(true); |
255 | 256 | ||
256 | /* Set the input multiplexer to FM */ | 257 | /* Set the input multiplexer to FM */ |
257 | pcmrec_set_mux(1); | 258 | pcm_rec_mux(1); |
258 | #endif | 259 | #endif |
259 | #endif | 260 | #endif |
260 | 261 | ||
@@ -345,14 +346,14 @@ bool radio_screen(void) | |||
345 | #ifndef SIMULATOR | 346 | #ifndef SIMULATOR |
346 | if(audio_status() == AUDIO_STATUS_RECORD) | 347 | if(audio_status() == AUDIO_STATUS_RECORD) |
347 | { | 348 | { |
348 | mpeg_new_file(rec_create_filename(buf)); | 349 | audio_new_file(rec_create_filename(buf)); |
349 | update_screen = true; | 350 | update_screen = true; |
350 | } | 351 | } |
351 | else | 352 | else |
352 | { | 353 | { |
353 | have_recorded = true; | 354 | have_recorded = true; |
354 | talk_buffer_steal(); /* we use the mp3 buffer */ | 355 | talk_buffer_steal(); /* we use the mp3 buffer */ |
355 | mpeg_record(rec_create_filename(buf)); | 356 | audio_record(rec_create_filename(buf)); |
356 | update_screen = true; | 357 | update_screen = true; |
357 | } | 358 | } |
358 | #endif | 359 | #endif |
@@ -517,7 +518,7 @@ bool radio_screen(void) | |||
517 | 518 | ||
518 | #ifndef SIMULATOR | 519 | #ifndef SIMULATOR |
519 | #if CONFIG_CODEC != SWCODEC | 520 | #if CONFIG_CODEC != SWCODEC |
520 | seconds = mpeg_recorded_time() / HZ; | 521 | seconds = audio_recorded_time() / HZ; |
521 | #endif | 522 | #endif |
522 | #endif | 523 | #endif |
523 | if(update_screen || seconds > last_seconds) | 524 | if(update_screen || seconds > last_seconds) |
@@ -609,8 +610,8 @@ bool radio_screen(void) | |||
609 | { | 610 | { |
610 | #if CONFIG_CODEC != SWCODEC | 611 | #if CONFIG_CODEC != SWCODEC |
611 | /* Enable the Left and right A/D Converter */ | 612 | /* Enable the Left and right A/D Converter */ |
612 | mpeg_set_recording_gain(sound_default(SOUND_LEFT_GAIN), | 613 | audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), |
613 | sound_default(SOUND_RIGHT_GAIN), false); | 614 | sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); |
614 | mas_codec_writereg(6, 0x4000); | 615 | mas_codec_writereg(6, 0x4000); |
615 | #endif | 616 | #endif |
616 | radio_set_status(FMRADIO_POWERED); /* leave it powered */ | 617 | radio_set_status(FMRADIO_POWERED); /* leave it powered */ |
@@ -619,7 +620,7 @@ bool radio_screen(void) | |||
619 | { | 620 | { |
620 | radio_stop(); | 621 | radio_stop(); |
621 | #if CONFIG_CODEC == SWCODEC | 622 | #if CONFIG_CODEC == SWCODEC |
622 | pcmrec_set_mux(0); /* Line In */ | 623 | pcm_rec_mux(0); /* Line In */ |
623 | #endif | 624 | #endif |
624 | } | 625 | } |
625 | 626 | ||
@@ -913,12 +914,13 @@ static bool fm_recording_settings(void) | |||
913 | if (global_settings.rec_prerecord_time) | 914 | if (global_settings.rec_prerecord_time) |
914 | talk_buffer_steal(); /* will use the mp3 buffer */ | 915 | talk_buffer_steal(); /* will use the mp3 buffer */ |
915 | 916 | ||
916 | mpeg_set_recording_options(global_settings.rec_frequency, | 917 | audio_set_recording_options(global_settings.rec_frequency, |
917 | global_settings.rec_quality, | 918 | global_settings.rec_quality, |
918 | 1, /* Line In */ | 919 | 1, /* Line In */ |
919 | global_settings.rec_channels, | 920 | global_settings.rec_channels, |
920 | global_settings.rec_editable, | 921 | global_settings.rec_editable, |
921 | global_settings.rec_prerecord_time); | 922 | global_settings.rec_prerecord_time, |
923 | global_settings.rec_monitor); | ||
922 | } | 924 | } |
923 | return ret; | 925 | return ret; |
924 | } | 926 | } |
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index b70e7b64ed..ebd92178c5 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c | |||
@@ -28,6 +28,13 @@ | |||
28 | #include "led.h" | 28 | #include "led.h" |
29 | #include "mpeg.h" | 29 | #include "mpeg.h" |
30 | #include "audio.h" | 30 | #include "audio.h" |
31 | #if CONFIG_CODEC == SWCODEC | ||
32 | #include "pcm_record.h" | ||
33 | #endif | ||
34 | #ifdef HAVE_UDA1380 | ||
35 | #include "uda1380.h" | ||
36 | #endif | ||
37 | |||
31 | #include "mp3_playback.h" | 38 | #include "mp3_playback.h" |
32 | #include "mas.h" | 39 | #include "mas.h" |
33 | #include "button.h" | 40 | #include "button.h" |
@@ -79,9 +86,12 @@ | |||
79 | 86 | ||
80 | #elif CONFIG_KEYPAD == IRIVER_H100_PAD | 87 | #elif CONFIG_KEYPAD == IRIVER_H100_PAD |
81 | #define REC_STOPEXIT BUTTON_OFF | 88 | #define REC_STOPEXIT BUTTON_OFF |
82 | #define REC_RECPAUSE BUTTON_ON | 89 | #define REC_RECPAUSE BUTTON_REC |
83 | #define REC_INC BUTTON_RIGHT | 90 | #define REC_INC BUTTON_RIGHT |
84 | #define REC_DEC BUTTON_LEFT | 91 | #define REC_DEC BUTTON_LEFT |
92 | #define REC_NEXT BUTTON_DOWN | ||
93 | #define REC_PREV BUTTON_UP | ||
94 | #define REC_SETTINGS BUTTON_MODE | ||
85 | 95 | ||
86 | #elif CONFIG_KEYPAD == GMINI100_PAD | 96 | #elif CONFIG_KEYPAD == GMINI100_PAD |
87 | #define REC_STOPEXIT BUTTON_OFF | 97 | #define REC_STOPEXIT BUTTON_OFF |
@@ -102,6 +112,12 @@ bool f3_rec_screen(void); | |||
102 | #define MAX_SOURCE SOURCE_LINE | 112 | #define MAX_SOURCE SOURCE_LINE |
103 | #endif | 113 | #endif |
104 | 114 | ||
115 | #if CONFIG_CODEC == SWCODEC | ||
116 | #define REC_FILE_ENDING ".wav" | ||
117 | #else | ||
118 | #define REC_FILE_ENDING ".mp3" | ||
119 | #endif | ||
120 | |||
105 | #define MAX_FILE_SIZE 0x7FF00000 /* 2 GB - 1 MB */ | 121 | #define MAX_FILE_SIZE 0x7FF00000 /* 2 GB - 1 MB */ |
106 | 122 | ||
107 | const char* const freq_str[6] = | 123 | const char* const freq_str[6] = |
@@ -118,13 +134,18 @@ static void set_gain(void) | |||
118 | { | 134 | { |
119 | if(global_settings.rec_source == SOURCE_MIC) | 135 | if(global_settings.rec_source == SOURCE_MIC) |
120 | { | 136 | { |
121 | mpeg_set_recording_gain(global_settings.rec_mic_gain, 0, true); | 137 | audio_set_recording_gain(global_settings.rec_mic_gain, 0, AUDIO_GAIN_MIC); |
122 | } | 138 | } |
123 | else | 139 | else |
124 | { | 140 | { |
125 | mpeg_set_recording_gain(global_settings.rec_left_gain, | 141 | audio_set_recording_gain(global_settings.rec_left_gain, |
126 | global_settings.rec_right_gain, false); | 142 | global_settings.rec_right_gain, AUDIO_GAIN_LINEIN); |
127 | } | 143 | } |
144 | #ifdef HAVE_UDA1380 | ||
145 | audio_set_recording_gain(global_settings.rec_adc_left_gain, | ||
146 | global_settings.rec_adc_right_gain, | ||
147 | AUDIO_GAIN_ADC); | ||
148 | #endif | ||
128 | } | 149 | } |
129 | 150 | ||
130 | static const char* const fmtstr[] = | 151 | static const char* const fmtstr[] = |
@@ -176,9 +197,9 @@ char *rec_create_filename(char *buffer) | |||
176 | strncpy(buffer, rec_base_directory, MAX_PATH); | 197 | strncpy(buffer, rec_base_directory, MAX_PATH); |
177 | 198 | ||
178 | #ifdef HAVE_RTC | 199 | #ifdef HAVE_RTC |
179 | create_datetime_filename(buffer, buffer, "R", ".mp3"); | 200 | create_datetime_filename(buffer, buffer, "R", REC_FILE_ENDING); |
180 | #else | 201 | #else |
181 | create_numbered_filename(buffer, buffer, "rec_", ".mp3", 4); | 202 | create_numbered_filename(buffer, buffer, "rec_", REC_FILE_ENDING, 4); |
182 | #endif | 203 | #endif |
183 | return buffer; | 204 | return buffer; |
184 | } | 205 | } |
@@ -227,7 +248,7 @@ static void trigger_listener(int trigger_status) | |||
227 | if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD) | 248 | if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD) |
228 | { | 249 | { |
229 | talk_buffer_steal(); /* we use the mp3 buffer */ | 250 | talk_buffer_steal(); /* we use the mp3 buffer */ |
230 | mpeg_record(rec_create_filename(path_buffer)); | 251 | audio_record(rec_create_filename(path_buffer)); |
231 | 252 | ||
232 | /* give control to mpeg thread so that it can start recording */ | 253 | /* give control to mpeg thread so that it can start recording */ |
233 | yield(); yield(); yield(); | 254 | yield(); yield(); yield(); |
@@ -236,7 +257,7 @@ static void trigger_listener(int trigger_status) | |||
236 | /* if we're already recording this is a retrigger */ | 257 | /* if we're already recording this is a retrigger */ |
237 | else | 258 | else |
238 | { | 259 | { |
239 | mpeg_new_file(rec_create_filename(path_buffer)); | 260 | audio_new_file(rec_create_filename(path_buffer)); |
240 | /* tell recording_screen to reset the time */ | 261 | /* tell recording_screen to reset the time */ |
241 | last_seconds = 0; | 262 | last_seconds = 0; |
242 | } | 263 | } |
@@ -273,6 +294,7 @@ bool recording_screen(void) | |||
273 | char path_buffer[MAX_PATH]; | 294 | char path_buffer[MAX_PATH]; |
274 | bool been_in_usb_mode = false; | 295 | bool been_in_usb_mode = false; |
275 | int last_audio_stat = -1; | 296 | int last_audio_stat = -1; |
297 | int audio_stat; | ||
276 | #if CONFIG_LED == LED_REAL | 298 | #if CONFIG_LED == LED_REAL |
277 | bool led_state = false; | 299 | bool led_state = false; |
278 | int led_countdown = 2; | 300 | int led_countdown = 2; |
@@ -289,7 +311,7 @@ bool recording_screen(void) | |||
289 | #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) | 311 | #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) |
290 | ata_set_led_enabled(false); | 312 | ata_set_led_enabled(false); |
291 | #endif | 313 | #endif |
292 | mpeg_init_recording(); | 314 | audio_init_recording(); |
293 | 315 | ||
294 | sound_set_volume(global_settings.volume); | 316 | sound_set_volume(global_settings.volume); |
295 | 317 | ||
@@ -298,15 +320,20 @@ bool recording_screen(void) | |||
298 | 320 | ||
299 | peak_meter_enabled = true; | 321 | peak_meter_enabled = true; |
300 | 322 | ||
323 | #if CONFIG_CODEC == SWCODEC | ||
324 | audio_stop(); | ||
325 | #endif | ||
326 | |||
301 | if (global_settings.rec_prerecord_time) | 327 | if (global_settings.rec_prerecord_time) |
302 | talk_buffer_steal(); /* will use the mp3 buffer */ | 328 | talk_buffer_steal(); /* will use the mp3 buffer */ |
303 | 329 | ||
304 | mpeg_set_recording_options(global_settings.rec_frequency, | 330 | audio_set_recording_options(global_settings.rec_frequency, |
305 | global_settings.rec_quality, | 331 | global_settings.rec_quality, |
306 | global_settings.rec_source, | 332 | global_settings.rec_source, |
307 | global_settings.rec_channels, | 333 | global_settings.rec_channels, |
308 | global_settings.rec_editable, | 334 | global_settings.rec_editable, |
309 | global_settings.rec_prerecord_time); | 335 | global_settings.rec_prerecord_time, |
336 | global_settings.rec_monitor); | ||
310 | 337 | ||
311 | set_gain(); | 338 | set_gain(); |
312 | 339 | ||
@@ -321,7 +348,12 @@ bool recording_screen(void) | |||
321 | 348 | ||
322 | while(!done) | 349 | while(!done) |
323 | { | 350 | { |
324 | int audio_stat = audio_status(); | 351 | #if CONFIG_CODEC == SWCODEC |
352 | audio_stat = pcm_rec_status(); | ||
353 | #else | ||
354 | audio_stat = audio_status(); | ||
355 | #endif | ||
356 | |||
325 | #if CONFIG_LED == LED_REAL | 357 | #if CONFIG_LED == LED_REAL |
326 | 358 | ||
327 | /* | 359 | /* |
@@ -390,7 +422,7 @@ bool recording_screen(void) | |||
390 | 422 | ||
391 | if(audio_stat & AUDIO_STATUS_RECORD) | 423 | if(audio_stat & AUDIO_STATUS_RECORD) |
392 | { | 424 | { |
393 | audio_stop(); | 425 | audio_stop_recording(); |
394 | } | 426 | } |
395 | else | 427 | else |
396 | { | 428 | { |
@@ -416,7 +448,7 @@ bool recording_screen(void) | |||
416 | /* manual recording */ | 448 | /* manual recording */ |
417 | have_recorded = true; | 449 | have_recorded = true; |
418 | talk_buffer_steal(); /* we use the mp3 buffer */ | 450 | talk_buffer_steal(); /* we use the mp3 buffer */ |
419 | mpeg_record(rec_create_filename(path_buffer)); | 451 | audio_record(rec_create_filename(path_buffer)); |
420 | last_seconds = 0; | 452 | last_seconds = 0; |
421 | if (global_settings.talk_menu) | 453 | if (global_settings.talk_menu) |
422 | { /* no voice possible here, but a beep */ | 454 | { /* no voice possible here, but a beep */ |
@@ -438,7 +470,7 @@ bool recording_screen(void) | |||
438 | { | 470 | { |
439 | if(audio_stat & AUDIO_STATUS_PAUSE) | 471 | if(audio_stat & AUDIO_STATUS_PAUSE) |
440 | { | 472 | { |
441 | mpeg_resume_recording(); | 473 | audio_resume_recording(); |
442 | if (global_settings.talk_menu) | 474 | if (global_settings.talk_menu) |
443 | { /* no voice possible here, but a beep */ | 475 | { /* no voice possible here, but a beep */ |
444 | audio_beep(HZ/4); /* short beep on resume */ | 476 | audio_beep(HZ/4); /* short beep on resume */ |
@@ -446,7 +478,7 @@ bool recording_screen(void) | |||
446 | } | 478 | } |
447 | else | 479 | else |
448 | { | 480 | { |
449 | mpeg_pause_recording(); | 481 | audio_pause_recording(); |
450 | } | 482 | } |
451 | } | 483 | } |
452 | update_countdown = 1; /* Update immediately */ | 484 | update_countdown = 1; /* Update immediately */ |
@@ -535,7 +567,7 @@ bool recording_screen(void) | |||
535 | sound_min(SOUND_RIGHT_GAIN)) | 567 | sound_min(SOUND_RIGHT_GAIN)) |
536 | global_settings.rec_right_gain--; | 568 | global_settings.rec_right_gain--; |
537 | break; | 569 | break; |
538 | } | 570 | } |
539 | set_gain(); | 571 | set_gain(); |
540 | update_countdown = 1; /* Update immediately */ | 572 | update_countdown = 1; /* Update immediately */ |
541 | break; | 573 | break; |
@@ -557,12 +589,13 @@ bool recording_screen(void) | |||
557 | if (global_settings.rec_prerecord_time) | 589 | if (global_settings.rec_prerecord_time) |
558 | talk_buffer_steal(); /* will use the mp3 buffer */ | 590 | talk_buffer_steal(); /* will use the mp3 buffer */ |
559 | 591 | ||
560 | mpeg_set_recording_options(global_settings.rec_frequency, | 592 | audio_set_recording_options(global_settings.rec_frequency, |
561 | global_settings.rec_quality, | 593 | global_settings.rec_quality, |
562 | global_settings.rec_source, | 594 | global_settings.rec_source, |
563 | global_settings.rec_channels, | 595 | global_settings.rec_channels, |
564 | global_settings.rec_editable, | 596 | global_settings.rec_editable, |
565 | global_settings.rec_prerecord_time); | 597 | global_settings.rec_prerecord_time, |
598 | global_settings.rec_monitor); | ||
566 | 599 | ||
567 | set_gain(); | 600 | set_gain(); |
568 | update_countdown = 1; /* Update immediately */ | 601 | update_countdown = 1; /* Update immediately */ |
@@ -596,7 +629,7 @@ bool recording_screen(void) | |||
596 | case REC_F3: | 629 | case REC_F3: |
597 | if(audio_stat & AUDIO_STATUS_RECORD) | 630 | if(audio_stat & AUDIO_STATUS_RECORD) |
598 | { | 631 | { |
599 | mpeg_new_file(rec_create_filename(path_buffer)); | 632 | audio_new_file(rec_create_filename(path_buffer)); |
600 | last_seconds = 0; | 633 | last_seconds = 0; |
601 | } | 634 | } |
602 | else | 635 | else |
@@ -638,8 +671,8 @@ bool recording_screen(void) | |||
638 | 671 | ||
639 | lcd_setfont(FONT_SYSFIXED); | 672 | lcd_setfont(FONT_SYSFIXED); |
640 | 673 | ||
641 | seconds = mpeg_recorded_time() / HZ; | 674 | seconds = audio_recorded_time() / HZ; |
642 | 675 | ||
643 | update_countdown--; | 676 | update_countdown--; |
644 | if(update_countdown == 0 || seconds > last_seconds) | 677 | if(update_countdown == 0 || seconds > last_seconds) |
645 | { | 678 | { |
@@ -660,7 +693,7 @@ bool recording_screen(void) | |||
660 | lcd_puts(0, 0, buf); | 693 | lcd_puts(0, 0, buf); |
661 | 694 | ||
662 | dseconds = rec_timesplit_seconds(); | 695 | dseconds = rec_timesplit_seconds(); |
663 | num_recorded_bytes = mpeg_num_recorded_bytes(); | 696 | num_recorded_bytes = audio_num_recorded_bytes(); |
664 | 697 | ||
665 | if(audio_stat & AUDIO_STATUS_PRERECORD) | 698 | if(audio_stat & AUDIO_STATUS_PRERECORD) |
666 | { | 699 | { |
@@ -699,7 +732,7 @@ bool recording_screen(void) | |||
699 | ((global_settings.rec_timesplit && (seconds >= dseconds)) | 732 | ((global_settings.rec_timesplit && (seconds >= dseconds)) |
700 | || (num_recorded_bytes >= MAX_FILE_SIZE))) | 733 | || (num_recorded_bytes >= MAX_FILE_SIZE))) |
701 | { | 734 | { |
702 | mpeg_new_file(rec_create_filename(path_buffer)); | 735 | audio_new_file(rec_create_filename(path_buffer)); |
703 | update_countdown = 1; | 736 | update_countdown = 1; |
704 | last_seconds = 0; | 737 | last_seconds = 0; |
705 | } | 738 | } |
@@ -784,7 +817,13 @@ bool recording_screen(void) | |||
784 | } | 817 | } |
785 | } | 818 | } |
786 | 819 | ||
787 | if(audio_status() & AUDIO_STATUS_ERROR) | 820 | |
821 | #if CONFIG_CODEC == SWCODEC | ||
822 | audio_stat = pcm_rec_status(); | ||
823 | #else | ||
824 | audio_stat = audio_status(); | ||
825 | #endif | ||
826 | if (audio_stat & AUDIO_STATUS_ERROR) | ||
788 | { | 827 | { |
789 | splash(0, true, str(LANG_DISK_FULL)); | 828 | splash(0, true, str(LANG_DISK_FULL)); |
790 | status_draw(true); | 829 | status_draw(true); |
@@ -799,7 +838,12 @@ bool recording_screen(void) | |||
799 | } | 838 | } |
800 | } | 839 | } |
801 | 840 | ||
841 | #if CONFIG_CODEC == SWCODEC | ||
842 | audio_stop_recording(); | ||
843 | audio_close_recording(); | ||
844 | #else | ||
802 | audio_init_playback(); | 845 | audio_init_playback(); |
846 | #endif | ||
803 | 847 | ||
804 | /* make sure the trigger is really turned off */ | 848 | /* make sure the trigger is really turned off */ |
805 | peak_meter_trigger(false); | 849 | peak_meter_trigger(false); |
@@ -924,12 +968,13 @@ bool f2_rec_screen(void) | |||
924 | if (global_settings.rec_prerecord_time) | 968 | if (global_settings.rec_prerecord_time) |
925 | talk_buffer_steal(); /* will use the mp3 buffer */ | 969 | talk_buffer_steal(); /* will use the mp3 buffer */ |
926 | 970 | ||
927 | mpeg_set_recording_options(global_settings.rec_frequency, | 971 | audio_set_recording_options(global_settings.rec_frequency, |
928 | global_settings.rec_quality, | 972 | global_settings.rec_quality, |
929 | global_settings.rec_source, | 973 | global_settings.rec_source, |
930 | global_settings.rec_channels, | 974 | global_settings.rec_channels, |
931 | global_settings.rec_editable, | 975 | global_settings.rec_editable, |
932 | global_settings.rec_prerecord_time); | 976 | global_settings.rec_prerecord_time, |
977 | global_settings.rec_monitor); | ||
933 | 978 | ||
934 | set_gain(); | 979 | set_gain(); |
935 | 980 | ||
@@ -1018,12 +1063,14 @@ bool f3_rec_screen(void) | |||
1018 | if (global_settings.rec_prerecord_time) | 1063 | if (global_settings.rec_prerecord_time) |
1019 | talk_buffer_steal(); /* will use the mp3 buffer */ | 1064 | talk_buffer_steal(); /* will use the mp3 buffer */ |
1020 | 1065 | ||
1021 | mpeg_set_recording_options(global_settings.rec_frequency, | 1066 | audio_set_recording_options(global_settings.rec_frequency, |
1022 | global_settings.rec_quality, | 1067 | global_settings.rec_quality, |
1023 | global_settings.rec_source, | 1068 | global_settings.rec_source, |
1024 | global_settings.rec_channels, | 1069 | global_settings.rec_channels, |
1025 | global_settings.rec_editable, | 1070 | global_settings.rec_editable, |
1026 | global_settings.rec_prerecord_time); | 1071 | global_settings.rec_prerecord_time, |
1072 | global_settings.rec_monitor); | ||
1073 | |||
1027 | 1074 | ||
1028 | set_gain(); | 1075 | set_gain(); |
1029 | 1076 | ||
@@ -1034,4 +1081,13 @@ bool f3_rec_screen(void) | |||
1034 | } | 1081 | } |
1035 | #endif /* #ifdef REC_F3 */ | 1082 | #endif /* #ifdef REC_F3 */ |
1036 | 1083 | ||
1084 | #if CONFIG_CODEC == SWCODEC | ||
1085 | void audio_beep(int duration) | ||
1086 | { | ||
1087 | /* dummy */ | ||
1088 | (void)duration; | ||
1089 | } | ||
1090 | #endif | ||
1091 | |||
1092 | |||
1037 | #endif /* HAVE_RECORDING */ | 1093 | #endif /* HAVE_RECORDING */ |
diff --git a/apps/settings.c b/apps/settings.c index b573d72c97..d44fec1f0b 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -85,7 +85,7 @@ const char rec_base_directory[] = REC_BASE_DIR; | |||
85 | #include "dsp.h" | 85 | #include "dsp.h" |
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | #define CONFIG_BLOCK_VERSION 29 | 88 | #define CONFIG_BLOCK_VERSION 30 |
89 | #define CONFIG_BLOCK_SIZE 512 | 89 | #define CONFIG_BLOCK_SIZE 512 |
90 | #define RTC_BLOCK_SIZE 44 | 90 | #define RTC_BLOCK_SIZE 44 |
91 | 91 | ||
@@ -407,6 +407,7 @@ static const struct bit_entry hd_bits[] = | |||
407 | 407 | ||
408 | #ifdef HAVE_RECORDING | 408 | #ifdef HAVE_RECORDING |
409 | {1, S_O(rec_startup), false, "rec screen on startup", off_on }, | 409 | {1, S_O(rec_startup), false, "rec screen on startup", off_on }, |
410 | {1, S_O(rec_monitor), true, "monitor recording", off_on }, | ||
410 | 411 | ||
411 | /* values for the trigger */ | 412 | /* values for the trigger */ |
412 | {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, | 413 | {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, |
@@ -450,6 +451,26 @@ static const struct bit_entry hd_bits[] = | |||
450 | {22, S_O(dircache_size), 0, NULL, NULL }, | 451 | {22, S_O(dircache_size), 0, NULL, NULL }, |
451 | #endif | 452 | #endif |
452 | 453 | ||
454 | #if defined(HAVE_UDA1380) | ||
455 | /* recording settings for iriver */ | ||
456 | {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */ | ||
457 | "off,00:05,00:10,00:15,00:30,01:00,01:14,01:20,02:00,04:00,06:00,08:00,10:00,12:00,18:00,24:00" }, | ||
458 | {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" }, | ||
459 | {4, S_O(rec_mic_gain), 4, "rec mic gain", NULL }, | ||
460 | {1, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line" }, | ||
461 | {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ | ||
462 | "rec frequency", "44,48,32,22,24,16" }, | ||
463 | {4, S_O(rec_left_gain), 2, /* 0dB */ | ||
464 | "rec left gain", NULL }, /* 0...15 */ | ||
465 | {4, S_O(rec_right_gain), 2, /* 0dB */ | ||
466 | "rec right gain", NULL }, /* 0...15 */ | ||
467 | {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */ | ||
468 | {1, S_O(rec_directory), 0, /* rec_base_directory */ | ||
469 | "rec directory", REC_BASE_DIR ",current" }, | ||
470 | {8|SIGNED, S_O(rec_adc_left_gain), 0, /* 0dB */ "adc left gain", NULL }, /* -128...48 */ | ||
471 | {8|SIGNED, S_O(rec_adc_right_gain), 0, /* 0dB */ "adc right gain", NULL }, /* -128...48 */ | ||
472 | #endif | ||
473 | |||
453 | /* If values are just added to the end, no need to bump the version. */ | 474 | /* If values are just added to the end, no need to bump the version. */ |
454 | /* new stuff to be added at the end */ | 475 | /* new stuff to be added at the end */ |
455 | 476 | ||
diff --git a/apps/settings.h b/apps/settings.h index 63349c646e..18c566b980 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -176,7 +176,12 @@ struct user_settings | |||
176 | int rec_mic_gain; /* 0-15 */ | 176 | int rec_mic_gain; /* 0-15 */ |
177 | int rec_left_gain; /* 0-15 */ | 177 | int rec_left_gain; /* 0-15 */ |
178 | int rec_right_gain; /* 0-15 */ | 178 | int rec_right_gain; /* 0-15 */ |
179 | #ifdef HAVE_UDA1380 | ||
180 | int rec_adc_left_gain; /* -128 .. 48 */ | ||
181 | int rec_adc_right_gain; /* -128 .. 48 */ | ||
182 | #endif | ||
179 | bool rec_editable; /* true means that the bit reservoir is off */ | 183 | bool rec_editable; /* true means that the bit reservoir is off */ |
184 | bool rec_monitor; /* true means that one can listen to what is being recorded */ | ||
180 | 185 | ||
181 | /* note: timesplit setting is not saved */ | 186 | /* note: timesplit setting is not saved */ |
182 | int rec_timesplit; /* 0 = off, | 187 | int rec_timesplit; /* 0 = off, |
diff --git a/apps/sound_menu.c b/apps/sound_menu.c index 766372471e..c429920143 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c | |||
@@ -228,6 +228,28 @@ static bool receditable(void) | |||
228 | &global_settings.rec_editable); | 228 | &global_settings.rec_editable); |
229 | } | 229 | } |
230 | 230 | ||
231 | static bool recmonitor(void) | ||
232 | { | ||
233 | return set_bool(str(LANG_RECORDING_MONITOR), | ||
234 | &global_settings.rec_monitor); | ||
235 | } | ||
236 | |||
237 | #ifdef HAVE_UDA1380 | ||
238 | static bool recadcleft(void) | ||
239 | { | ||
240 | return set_sound(str(LANG_RECORDING_ADC_LEFT), | ||
241 | &global_settings.rec_adc_left_gain, | ||
242 | SOUND_ADC_LEFT_GAIN); | ||
243 | } | ||
244 | |||
245 | static bool recadcright(void) | ||
246 | { | ||
247 | return set_sound(str(LANG_RECORDING_ADC_RIGHT), | ||
248 | &global_settings.rec_adc_right_gain, | ||
249 | SOUND_ADC_RIGHT_GAIN); | ||
250 | } | ||
251 | #endif | ||
252 | |||
231 | static bool rectimesplit(void) | 253 | static bool rectimesplit(void) |
232 | { | 254 | { |
233 | static const struct opt_items names[] = { | 255 | static const struct opt_items names[] = { |
@@ -740,7 +762,7 @@ bool recording_menu(bool no_source) | |||
740 | { | 762 | { |
741 | int m; | 763 | int m; |
742 | int i = 0; | 764 | int i = 0; |
743 | struct menu_item items[10]; | 765 | struct menu_item items[13]; |
744 | bool result; | 766 | bool result; |
745 | 767 | ||
746 | items[i].desc = ID2P(LANG_RECORDING_QUALITY); | 768 | items[i].desc = ID2P(LANG_RECORDING_QUALITY); |
@@ -753,6 +775,16 @@ bool recording_menu(bool no_source) | |||
753 | } | 775 | } |
754 | items[i].desc = ID2P(LANG_RECORDING_CHANNELS); | 776 | items[i].desc = ID2P(LANG_RECORDING_CHANNELS); |
755 | items[i++].function = recchannels; | 777 | items[i++].function = recchannels; |
778 | |||
779 | #ifdef HAVE_UDA1380 | ||
780 | items[i].desc = ID2P(LANG_RECORDING_ADC_LEFT); | ||
781 | items[i++].function = recadcleft; | ||
782 | items[i].desc = ID2P(LANG_RECORDING_ADC_RIGHT); | ||
783 | items[i++].function = recadcright; | ||
784 | #endif | ||
785 | |||
786 | items[i].desc = ID2P(LANG_RECORDING_MONITOR); | ||
787 | items[i++].function = recmonitor; | ||
756 | items[i].desc = ID2P(LANG_RECORDING_EDITABLE); | 788 | items[i].desc = ID2P(LANG_RECORDING_EDITABLE); |
757 | items[i++].function = receditable; | 789 | items[i++].function = receditable; |
758 | items[i].desc = ID2P(LANG_RECORD_TIMESPLIT); | 790 | items[i].desc = ID2P(LANG_RECORD_TIMESPLIT); |
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index e89f9bb684..6a5bd078c0 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "string.h" | 28 | #include "string.h" |
29 | #include "file.h" | 29 | #include "file.h" |
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "audio.h" | ||
31 | 32 | ||
32 | #include "i2c-coldfire.h" | 33 | #include "i2c-coldfire.h" |
33 | #include "uda1380.h" | 34 | #include "uda1380.h" |
@@ -204,7 +205,7 @@ void uda1380_close(void) | |||
204 | * sound samples over the I2S bus, which is connected | 205 | * sound samples over the I2S bus, which is connected |
205 | * to the processor's IIS1 interface. | 206 | * to the processor's IIS1 interface. |
206 | * | 207 | * |
207 | * source_mic: true=record from microphone, false=record from line-in | 208 | * source_mic: true=record from microphone, false=record from line-in (or radio) |
208 | */ | 209 | */ |
209 | void uda1380_enable_recording(bool source_mic) | 210 | void uda1380_enable_recording(bool source_mic) |
210 | { | 211 | { |
@@ -246,17 +247,29 @@ void uda1380_disable_recording(void) | |||
246 | /** | 247 | /** |
247 | * Set recording gain and volume | 248 | * Set recording gain and volume |
248 | * | 249 | * |
249 | * mic_gain : range 0 .. 15 -> 0 .. 30 dB gain | 250 | * type: params: ranges: |
250 | * linein_gain : range 0 .. 15 -> 0 .. 24 dB gain | 251 | * AUDIO_GAIN_MIC left 0 .. 15 -> 0 .. 30 dB gain |
251 | * | 252 | * AUDIO_GAIN_LINEIN left & right 0 .. 8 -> 0 .. 24 dB gain |
252 | * adc_volume : range -127 .. 48 -> -63 .. 24 dB gain | 253 | * AUDIO_GAIN_ADC left & right -128 .. 48 -> -64 .. 24 dB gain |
253 | * note that 0 -> 0 dB gain.. | 254 | * |
255 | * Note: For all types the value 0 gives 0 dB gain. | ||
254 | */ | 256 | */ |
255 | void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume) | 257 | void uda1380_set_recvol(int left, int right, int type) |
256 | { | 258 | { |
257 | uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(adc_volume) | DEC_VOLR(adc_volume)); | 259 | switch (type) |
258 | uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(linein_gain) | PGA_GAINR(linein_gain)); | 260 | { |
259 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & ~VGA_GAIN_MASK) | VGA_GAIN(mic_gain)); | 261 | case AUDIO_GAIN_MIC: |
262 | uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & ~VGA_GAIN_MASK) | VGA_GAIN(left)); | ||
263 | break; | ||
264 | |||
265 | case AUDIO_GAIN_LINEIN: | ||
266 | uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(left) | PGA_GAINR(right)); | ||
267 | break; | ||
268 | |||
269 | case AUDIO_GAIN_ADC: | ||
270 | uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) | DEC_VOLR(right)); | ||
271 | break; | ||
272 | } | ||
260 | } | 273 | } |
261 | 274 | ||
262 | 275 | ||
diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 67ed052f2b..ab6f41c81f 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h | |||
@@ -33,6 +33,11 @@ | |||
33 | 33 | ||
34 | #define AUDIOERR_DISK_FULL 1 | 34 | #define AUDIOERR_DISK_FULL 1 |
35 | 35 | ||
36 | #define AUDIO_GAIN_LINEIN 0 | ||
37 | #define AUDIO_GAIN_MIC 1 | ||
38 | #define AUDIO_GAIN_ADC 2 /* for UDA1380 */ | ||
39 | |||
40 | |||
36 | struct audio_debug | 41 | struct audio_debug |
37 | { | 42 | { |
38 | int audiobuflen; | 43 | int audiobuflen; |
@@ -79,6 +84,24 @@ int audio_get_file_pos(void); | |||
79 | void audio_beep(int duration); | 84 | void audio_beep(int duration); |
80 | void audio_init_playback(void); | 85 | void audio_init_playback(void); |
81 | 86 | ||
87 | /* audio recording functions */ | ||
88 | void audio_init_recording(void); | ||
89 | void audio_close_recording(void); | ||
90 | void audio_record(const char *filename); | ||
91 | void audio_stop_recording(void); | ||
92 | void audio_pause_recording(void); | ||
93 | void audio_resume_recording(void); | ||
94 | void audio_new_file(const char *filename); | ||
95 | void audio_set_recording_options(int frequency, int quality, | ||
96 | int source, int channel_mode, | ||
97 | bool editable, int prerecord_time, | ||
98 | bool monitor); | ||
99 | void audio_set_recording_gain(int left, int right, int type); | ||
100 | unsigned long audio_recorded_time(void); | ||
101 | unsigned long audio_num_recorded_bytes(void); | ||
102 | |||
103 | |||
104 | |||
82 | /***********************************************************************/ | 105 | /***********************************************************************/ |
83 | /* audio event handling */ | 106 | /* audio event handling */ |
84 | 107 | ||
diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index 72bc770bde..653dbc0bee 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #define MODEL_NUMBER 0 | 7 | #define MODEL_NUMBER 0 |
8 | 8 | ||
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 this if you have a bitmap LCD display */ | 12 | /* define this if you have a bitmap LCD display */ |
13 | #define HAVE_LCD_BITMAP 1 | 13 | #define HAVE_LCD_BITMAP 1 |
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index a7c9cac321..d62ac14ade 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -44,20 +44,11 @@ | |||
44 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 576) | 44 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 576) |
45 | 45 | ||
46 | #if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR) | 46 | #if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR) |
47 | void mpeg_init_recording(void); | 47 | |
48 | void mpeg_record(const char *filename); | ||
49 | void mpeg_new_file(const char *filename); | ||
50 | void mpeg_set_recording_options(int frequency, int quality, | ||
51 | int source, int channel_mode, | ||
52 | bool editable, int prerecord_time); | ||
53 | void mpeg_set_recording_gain(int left, int right, bool use_mic); | ||
54 | #if CONFIG_TUNER & S1A0903X01 | 48 | #if CONFIG_TUNER & S1A0903X01 |
55 | int mpeg_get_mas_pllfreq(void); | 49 | int mpeg_get_mas_pllfreq(void); |
56 | #endif | 50 | #endif |
57 | unsigned long mpeg_recorded_time(void); | 51 | |
58 | unsigned long mpeg_num_recorded_bytes(void); | ||
59 | void mpeg_pause_recording(void); | ||
60 | void mpeg_resume_recording(void); | ||
61 | #endif | 52 | #endif |
62 | unsigned long mpeg_get_last_header(void); | 53 | unsigned long mpeg_get_last_header(void); |
63 | 54 | ||
diff --git a/firmware/export/pcm_record.h b/firmware/export/pcm_record.h index af73108d86..304a67f577 100644 --- a/firmware/export/pcm_record.h +++ b/firmware/export/pcm_record.h | |||
@@ -17,37 +17,13 @@ | |||
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | ||
20 | /* | ||
21 | * Function names are taken from apps/recorder/recording.c to | ||
22 | * make the integration later easier.. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef PCM_RECORD_H | 20 | #ifndef PCM_RECORD_H |
27 | #define PCM_RECORD_H | 21 | #define PCM_RECORD_H |
28 | 22 | ||
29 | unsigned long pcm_status(void); | 23 | unsigned long pcm_rec_status(void); |
30 | 24 | void pcm_rec_init(void); | |
31 | void pcm_init_recording(void); | 25 | void pcm_rec_mux(int source); |
32 | |||
33 | void pcm_open_recording(void); | ||
34 | void pcm_close_recording(void); | ||
35 | |||
36 | |||
37 | void pcm_set_recording_options(int source, bool enable_waveform); | ||
38 | void pcm_set_recording_gain(int gain, int volume); | ||
39 | |||
40 | void pcm_record(const char *filename); | ||
41 | void pcm_stop_recording(void); | ||
42 | |||
43 | //void pcm_new_file(const char *filename); | ||
44 | |||
45 | |||
46 | unsigned long pcm_recorded_time(void); | ||
47 | unsigned long pcm_num_recorded_bytes(void); | ||
48 | void pcm_pause_recording(void); | ||
49 | void pcm_resume_recording(void); | ||
50 | 26 | ||
51 | void pcmrec_set_mux(int source); | 27 | /* audio.h contains audio recording functions */ |
52 | 28 | ||
53 | #endif | 29 | #endif |
diff --git a/firmware/export/sound.h b/firmware/export/sound.h index 9907462dc8..2c002063db 100644 --- a/firmware/export/sound.h +++ b/firmware/export/sound.h | |||
@@ -36,11 +36,15 @@ enum { | |||
36 | SOUND_MDB_ENABLE, | 36 | SOUND_MDB_ENABLE, |
37 | SOUND_SUPERBASS, | 37 | SOUND_SUPERBASS, |
38 | #endif | 38 | #endif |
39 | #if CONFIG_CODEC == MAS3587F | 39 | #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) |
40 | SOUND_LEFT_GAIN, | 40 | SOUND_LEFT_GAIN, |
41 | SOUND_RIGHT_GAIN, | 41 | SOUND_RIGHT_GAIN, |
42 | SOUND_MIC_GAIN, | 42 | SOUND_MIC_GAIN, |
43 | #endif | 43 | #endif |
44 | #if defined(HAVE_UDA1380) | ||
45 | SOUND_ADC_LEFT_GAIN, | ||
46 | SOUND_ADC_RIGHT_GAIN, | ||
47 | #endif | ||
44 | }; | 48 | }; |
45 | 49 | ||
46 | enum { | 50 | enum { |
diff --git a/firmware/export/uda1380.h b/firmware/export/uda1380.h index 3bef5439b5..90a6d44e04 100644 --- a/firmware/export/uda1380.h +++ b/firmware/export/uda1380.h | |||
@@ -32,7 +32,7 @@ extern void uda1380_set_nsorder(int order); | |||
32 | 32 | ||
33 | extern void uda1380_enable_recording(bool source_mic); | 33 | extern void uda1380_enable_recording(bool source_mic); |
34 | extern void uda1380_disable_recording(void); | 34 | extern void uda1380_disable_recording(void); |
35 | extern void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume); | 35 | extern void uda1380_set_recvol(int left, int right, int type); |
36 | extern void uda1380_set_monitor(int enable); | 36 | extern void uda1380_set_monitor(int enable); |
37 | 37 | ||
38 | #define UDA1380_ADDR 0x30 | 38 | #define UDA1380_ADDR 0x30 |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 022a321602..caeb3b96b6 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -2115,7 +2115,7 @@ void audio_init_playback(void) | |||
2115 | /**************************************************************************** | 2115 | /**************************************************************************** |
2116 | * Recording functions | 2116 | * Recording functions |
2117 | ***************************************************************************/ | 2117 | ***************************************************************************/ |
2118 | void mpeg_init_recording(void) | 2118 | void audio_init_recording(void) |
2119 | { | 2119 | { |
2120 | init_recording_done = false; | 2120 | init_recording_done = false; |
2121 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); | 2121 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); |
@@ -2224,7 +2224,7 @@ static void init_recording(void) | |||
2224 | call mpeg_set_recording_options(). */ | 2224 | call mpeg_set_recording_options(). */ |
2225 | } | 2225 | } |
2226 | 2226 | ||
2227 | void mpeg_record(const char *filename) | 2227 | void audio_record(const char *filename) |
2228 | { | 2228 | { |
2229 | mpeg_errno = 0; | 2229 | mpeg_errno = 0; |
2230 | 2230 | ||
@@ -2234,12 +2234,12 @@ void mpeg_record(const char *filename) | |||
2234 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); | 2234 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); |
2235 | } | 2235 | } |
2236 | 2236 | ||
2237 | void mpeg_pause_recording(void) | 2237 | void audio_pause_recording(void) |
2238 | { | 2238 | { |
2239 | queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, NULL); | 2239 | queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, NULL); |
2240 | } | 2240 | } |
2241 | 2241 | ||
2242 | void mpeg_resume_recording(void) | 2242 | void audio_resume_recording(void) |
2243 | { | 2243 | { |
2244 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL); | 2244 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL); |
2245 | } | 2245 | } |
@@ -2435,9 +2435,10 @@ static void stop_recording(void) | |||
2435 | resume_recording(); | 2435 | resume_recording(); |
2436 | } | 2436 | } |
2437 | 2437 | ||
2438 | void mpeg_set_recording_options(int frequency, int quality, | 2438 | void audio_set_recording_options(int frequency, int quality, |
2439 | int source, int channel_mode, | 2439 | int source, int channel_mode, |
2440 | bool editable, int prerecord_time) | 2440 | bool editable, int prerecord_time, |
2441 | bool monitor) | ||
2441 | { | 2442 | { |
2442 | bool is_mpeg1; | 2443 | bool is_mpeg1; |
2443 | 2444 | ||
@@ -2461,7 +2462,7 @@ void mpeg_set_recording_options(int frequency, int quality, | |||
2461 | 2462 | ||
2462 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); | 2463 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); |
2463 | 2464 | ||
2464 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ | 2465 | shadow_io_control_main = ((monitor?(1 << 10):0) | /* Monitoring ON */ |
2465 | ((source < 2)?1:2) << 8) | /* Input select */ | 2466 | ((source < 2)?1:2) << 8) | /* Input select */ |
2466 | (1 << 5) | /* SDO strobe invert */ | 2467 | (1 << 5) | /* SDO strobe invert */ |
2467 | ((is_mpeg1?0:1) << 3) | | 2468 | ((is_mpeg1?0:1) << 3) | |
@@ -2497,13 +2498,13 @@ void mpeg_set_recording_options(int frequency, int quality, | |||
2497 | } | 2498 | } |
2498 | 2499 | ||
2499 | /* If use_mic is true, the left gain is used */ | 2500 | /* If use_mic is true, the left gain is used */ |
2500 | void mpeg_set_recording_gain(int left, int right, bool use_mic) | 2501 | void audio_set_recording_gain(int left, int right, int type) |
2501 | { | 2502 | { |
2502 | /* Enable both left and right A/D */ | 2503 | /* Enable both left and right A/D */ |
2503 | shadow_codec_reg0 = (left << 12) | | 2504 | shadow_codec_reg0 = (left << 12) | |
2504 | (right << 8) | | 2505 | (right << 8) | |
2505 | (left << 4) | | 2506 | (left << 4) | |
2506 | (use_mic?0x0008:0) | /* Connect left A/D to mic */ | 2507 | (type==AUDIO_GAIN_MIC?0x0008:0) | /* Connect left A/D to mic */ |
2507 | 0x0007; | 2508 | 0x0007; |
2508 | mas_codec_writereg(0x0, shadow_codec_reg0); | 2509 | mas_codec_writereg(0x0, shadow_codec_reg0); |
2509 | } | 2510 | } |
@@ -2539,7 +2540,7 @@ void audio_beep(int duration) | |||
2539 | while (current_tick - starttick < duration); | 2540 | while (current_tick - starttick < duration); |
2540 | } | 2541 | } |
2541 | 2542 | ||
2542 | void mpeg_new_file(const char *filename) | 2543 | void audio_new_file(const char *filename) |
2543 | { | 2544 | { |
2544 | mpeg_errno = 0; | 2545 | mpeg_errno = 0; |
2545 | 2546 | ||
@@ -2549,7 +2550,7 @@ void mpeg_new_file(const char *filename) | |||
2549 | queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL); | 2550 | queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL); |
2550 | } | 2551 | } |
2551 | 2552 | ||
2552 | unsigned long mpeg_recorded_time(void) | 2553 | unsigned long audio_recorded_time(void) |
2553 | { | 2554 | { |
2554 | if(is_prerecording) | 2555 | if(is_prerecording) |
2555 | return prerecord_count * HZ; | 2556 | return prerecord_count * HZ; |
@@ -2565,7 +2566,7 @@ unsigned long mpeg_recorded_time(void) | |||
2565 | return 0; | 2566 | return 0; |
2566 | } | 2567 | } |
2567 | 2568 | ||
2568 | unsigned long mpeg_num_recorded_bytes(void) | 2569 | unsigned long audio_num_recorded_bytes(void) |
2569 | { | 2570 | { |
2570 | int num_bytes; | 2571 | int num_bytes; |
2571 | int index; | 2572 | int index; |
@@ -2599,7 +2600,7 @@ void audio_init_playback(void) | |||
2599 | { | 2600 | { |
2600 | /* a dummy */ | 2601 | /* a dummy */ |
2601 | } | 2602 | } |
2602 | unsigned long mpeg_recorded_time(void) | 2603 | unsigned long audio_recorded_time(void) |
2603 | { | 2604 | { |
2604 | /* a dummy */ | 2605 | /* a dummy */ |
2605 | return 0; | 2606 | return 0; |
@@ -2609,42 +2610,42 @@ void audio_beep(int duration) | |||
2609 | /* a dummy */ | 2610 | /* a dummy */ |
2610 | (void)duration; | 2611 | (void)duration; |
2611 | } | 2612 | } |
2612 | void mpeg_pause_recording(void) | 2613 | void audio_pause_recording(void) |
2613 | { | 2614 | { |
2614 | /* a dummy */ | 2615 | /* a dummy */ |
2615 | } | 2616 | } |
2616 | void mpeg_resume_recording(void) | 2617 | void audio_resume_recording(void) |
2617 | { | 2618 | { |
2618 | /* a dummy */ | 2619 | /* a dummy */ |
2619 | } | 2620 | } |
2620 | unsigned long mpeg_num_recorded_bytes(void) | 2621 | unsigned long audio_num_recorded_bytes(void) |
2621 | { | 2622 | { |
2622 | /* a dummy */ | 2623 | /* a dummy */ |
2623 | return 0; | 2624 | return 0; |
2624 | } | 2625 | } |
2625 | void mpeg_record(const char *filename) | 2626 | void audio_record(const char *filename) |
2626 | { | 2627 | { |
2627 | /* a dummy */ | 2628 | /* a dummy */ |
2628 | (void)filename; | 2629 | (void)filename; |
2629 | } | 2630 | } |
2630 | void mpeg_new_file(const char *filename) | 2631 | void audio_new_file(const char *filename) |
2631 | { | 2632 | { |
2632 | /* a dummy */ | 2633 | /* a dummy */ |
2633 | (void)filename; | 2634 | (void)filename; |
2634 | } | 2635 | } |
2635 | 2636 | ||
2636 | void mpeg_set_recording_gain(int left, int right, bool use_mic) | 2637 | void audio_set_recording_gain(int left, int right, int type) |
2637 | { | 2638 | { |
2638 | /* a dummy */ | 2639 | /* a dummy */ |
2639 | (void)left; | 2640 | (void)left; |
2640 | (void)right; | 2641 | (void)right; |
2641 | (void)use_mic; | 2642 | (void)type; |
2642 | } | 2643 | } |
2643 | void mpeg_init_recording(void) | 2644 | void audio_init_recording(void) |
2644 | { | 2645 | { |
2645 | /* a dummy */ | 2646 | /* a dummy */ |
2646 | } | 2647 | } |
2647 | void mpeg_set_recording_options(int frequency, int quality, | 2648 | void audio_set_recording_options(int frequency, int quality, |
2648 | int source, int channel_mode, | 2649 | int source, int channel_mode, |
2649 | bool editable, int prerecord_time) | 2650 | bool editable, int prerecord_time) |
2650 | { | 2651 | { |
@@ -2710,6 +2711,12 @@ void audio_stop(void) | |||
2710 | #endif /* SIMULATOR */ | 2711 | #endif /* SIMULATOR */ |
2711 | } | 2712 | } |
2712 | 2713 | ||
2714 | /* dummy */ | ||
2715 | void audio_stop_recording(void) | ||
2716 | { | ||
2717 | audio_stop(); | ||
2718 | } | ||
2719 | |||
2713 | void audio_pause(void) | 2720 | void audio_pause(void) |
2714 | { | 2721 | { |
2715 | #ifndef SIMULATOR | 2722 | #ifndef SIMULATOR |
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 8b46a09ed3..b167d6a562 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -30,11 +30,7 @@ | |||
30 | 30 | ||
31 | #include "cpu.h" | 31 | #include "cpu.h" |
32 | #include "i2c.h" | 32 | #include "i2c.h" |
33 | #if defined(HAVE_UDA1380) | ||
34 | #include "uda1380.h" | 33 | #include "uda1380.h" |
35 | #elif defined(HAVE_TLV320) | ||
36 | #include "tlv320.h" | ||
37 | #endif | ||
38 | #include "system.h" | 34 | #include "system.h" |
39 | #include "usb.h" | 35 | #include "usb.h" |
40 | 36 | ||
@@ -56,47 +52,56 @@ | |||
56 | static volatile bool is_recording; /* We are recording */ | 52 | static volatile bool is_recording; /* We are recording */ |
57 | static volatile bool is_stopping; /* Are we going to stop */ | 53 | static volatile bool is_stopping; /* Are we going to stop */ |
58 | static volatile bool is_paused; /* We have paused */ | 54 | static volatile bool is_paused; /* We have paused */ |
55 | static volatile bool is_error; /* An error has occured */ | ||
59 | 56 | ||
60 | static volatile int num_rec_bytes; | 57 | static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ |
58 | static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ | ||
61 | static volatile int int_count; /* Number of DMA completed interrupts */ | 59 | static volatile int int_count; /* Number of DMA completed interrupts */ |
62 | static volatile int error_count; /* Number of DMA errors */ | 60 | static volatile int error_count; /* Number of DMA errors */ |
63 | 61 | ||
64 | static unsigned long record_start_time; /* Value of current_tick when recording was started */ | 62 | static unsigned long record_start_time; /* Value of current_tick when recording was started */ |
65 | static unsigned long pause_start_time; /* Value of current_tick when pause was started */ | 63 | static unsigned long pause_start_time; /* Value of current_tick when pause was started */ |
66 | 64 | ||
67 | static int rec_gain, rec_volume; | ||
68 | static bool show_waveform; | 65 | static bool show_waveform; |
69 | static int init_done = 0; | 66 | |
70 | static int wav_file; | 67 | static int wav_file; |
71 | static char recording_filename[MAX_PATH]; | 68 | static char recording_filename[MAX_PATH]; |
72 | 69 | ||
70 | static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; | ||
71 | |||
73 | /***************************************************************************/ | 72 | /***************************************************************************/ |
74 | 73 | ||
75 | /* | 74 | /* |
76 | Some estimates: | 75 | Some estimates: |
77 | 44100 HZ * 4 = 176400 bytes/s | 76 | Normal recording rate: 44100 HZ * 4 = 176 KB/s |
78 | Refresh LCD 10 HZ = 176400 / 10 = 17640 bytes ~=~ 1024*16 bytes | 77 | Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk |
78 | CHUNK_SIZE: 65536 | ||
79 | Chunks/s: 176 KB / 65536 = ~3 chunks / s | ||
80 | |||
81 | WRITE_THRESHOLD: 30 | ||
82 | - Should gives us < 10s to start writing to disk before we run out | ||
83 | of buffer space.. | ||
79 | 84 | ||
80 | If NUM_BUFFERS is 80 we can hold ~8 sec of data in memory | ||
81 | ALL_BUFFER_SIZE will be 1024*16 * 80 = 1310720 bytes | ||
82 | */ | 85 | */ |
83 | 86 | ||
84 | #define NUM_BUFFERS 80 | 87 | #define CHUNK_SIZE 65536 /* Multiple of 4 */ |
85 | #define EACH_BUFFER_SIZE (1024*16) /* Multiple of 4. Use small value to get responsive waveform */ | 88 | #define WRITE_THRESHOLD 30 /* Write when this many chunks (or less) until buffer full */ |
86 | #define ALL_BUFFERS_SIZE (NUM_BUFFERS * EACH_BUFFER_SIZE) | 89 | |
90 | #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)]) | ||
87 | 91 | ||
88 | #define WRITE_THRESHOLD 40 /* Minimum number of buffers before write to file */ | 92 | static unsigned char *rec_buffer; /* Circular recording buffer */ |
93 | static int num_chunks; /* Number of chunks available in rec_buffer */ | ||
89 | 94 | ||
90 | static unsigned char *rec_buffers[NUM_BUFFERS]; | ||
91 | 95 | ||
92 | /* | 96 | /* |
93 | Overrun occures when DMA needs to write a new buffer and write_index == read_index | 97 | Overrun occures when DMA needs to write a new chunk and write_index == read_index |
94 | Solution to this is to optimize pcmrec_callback, use cpu_boost somewhere or increase | 98 | Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk |
95 | the total buffer size (or WRITE_THRESHOLD) | 99 | more often. |
96 | */ | 100 | */ |
97 | 101 | ||
98 | static int write_index; /* Which buffer the DMA is currently recording */ | 102 | static volatile int write_index; /* Current chunk the DMA is writing to */ |
99 | static int read_index; /* The oldest buffer that the pcmrec_callback has not read */ | 103 | static volatile int read_index; /* Oldest chunk that is not written to disk */ |
104 | static volatile int read2_index; /* Latest chunk that has not been converted to little endian */ | ||
100 | 105 | ||
101 | /***************************************************************************/ | 106 | /***************************************************************************/ |
102 | 107 | ||
@@ -105,10 +110,13 @@ static long pcmrec_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(lon | |||
105 | static const char pcmrec_thread_name[] = "pcmrec"; | 110 | static const char pcmrec_thread_name[] = "pcmrec"; |
106 | 111 | ||
107 | static void pcmrec_thread(void); | 112 | static void pcmrec_thread(void); |
113 | static void pcmrec_dma_start(void); | ||
114 | static void pcmrec_dma_stop(void); | ||
108 | 115 | ||
109 | /* Event IDs */ | 116 | /* Event IDs */ |
110 | #define PCMREC_OPEN 1 /* Enable recording */ | 117 | #define PCMREC_INIT 1 /* Enable recording */ |
111 | #define PCMREC_CLOSE 2 /* Disable recording */ | 118 | #define PCMREC_CLOSE 2 |
119 | |||
112 | #define PCMREC_START 3 /* Start a new recording */ | 120 | #define PCMREC_START 3 /* Start a new recording */ |
113 | #define PCMREC_STOP 4 /* Stop the current recording */ | 121 | #define PCMREC_STOP 4 /* Stop the current recording */ |
114 | #define PCMREC_PAUSE 10 | 122 | #define PCMREC_PAUSE 10 |
@@ -122,71 +130,58 @@ static void pcmrec_thread(void); | |||
122 | /* Functions that are not executing in the pcmrec_thread first */ | 130 | /* Functions that are not executing in the pcmrec_thread first */ |
123 | /*******************************************************************/ | 131 | /*******************************************************************/ |
124 | 132 | ||
125 | void pcm_init_recording(void) | 133 | /* Creates pcmrec_thread */ |
134 | void pcm_rec_init(void) | ||
126 | { | 135 | { |
127 | int_count = 0; | ||
128 | error_count = 0; | ||
129 | |||
130 | show_waveform = 0; | ||
131 | is_recording = 0; | ||
132 | is_stopping = 0; | ||
133 | num_rec_bytes = 0; | ||
134 | wav_file = -1; | ||
135 | read_index = 0; | ||
136 | write_index = 0; | ||
137 | |||
138 | queue_init(&pcmrec_queue); | 136 | queue_init(&pcmrec_queue); |
139 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name); | 137 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name); |
140 | } | 138 | } |
141 | 139 | ||
142 | void pcm_open_recording(void) | ||
143 | { | ||
144 | init_done = 0; | ||
145 | |||
146 | logf("pcm_open_rec"); | ||
147 | |||
148 | queue_post(&pcmrec_queue, PCMREC_OPEN, 0); | ||
149 | 140 | ||
150 | while (init_done) | 141 | /* Initializes recording: |
151 | { | 142 | * - Set up the UDA1380 for recording |
152 | sleep(HZ >> 8); | 143 | * - Prepare for DMA transfers |
153 | } | 144 | */ |
154 | 145 | ||
155 | logf("pcm_open_rec done"); | 146 | void audio_init_recording(void) |
147 | { | ||
148 | init_done = false; | ||
149 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); | ||
150 | |||
151 | while(!init_done) | ||
152 | sleep_thread(); | ||
153 | wake_up_thread(); | ||
156 | } | 154 | } |
157 | 155 | ||
158 | void pcm_close_recording(void) | 156 | void audio_close_recording(void) |
159 | { | 157 | { |
160 | /* todo: synchronize completion with pcmrec thread */ | 158 | close_done = false; |
161 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); | 159 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); |
160 | |||
161 | while(!close_done) | ||
162 | sleep_thread(); | ||
163 | wake_up_thread(); | ||
162 | } | 164 | } |
163 | 165 | ||
164 | 166 | unsigned long pcm_rec_status(void) | |
165 | |||
166 | unsigned long pcm_status(void) | ||
167 | { | 167 | { |
168 | unsigned long ret = 0; | 168 | unsigned long ret = 0; |
169 | 169 | ||
170 | if (is_recording) | 170 | if (is_recording) |
171 | ret |= AUDIO_STATUS_RECORD; | 171 | ret |= AUDIO_STATUS_RECORD; |
172 | if (is_paused) | ||
173 | ret |= AUDIO_STATUS_PAUSE; | ||
174 | if (is_error) | ||
175 | ret |= AUDIO_STATUS_ERROR; | ||
172 | 176 | ||
173 | return ret; | 177 | return ret; |
174 | } | 178 | } |
175 | 179 | ||
176 | 180 | unsigned long audio_recorded_time(void) | |
177 | |||
178 | void pcm_new_file(const char *filename) | ||
179 | { | ||
180 | /* todo */ | ||
181 | filename = filename; | ||
182 | |||
183 | } | ||
184 | |||
185 | unsigned long pcm_recorded_time(void) | ||
186 | { | 181 | { |
187 | if (is_recording) | 182 | if (is_recording) |
188 | { | 183 | { |
189 | if(is_paused) | 184 | if (is_paused) |
190 | return pause_start_time - record_start_time; | 185 | return pause_start_time - record_start_time; |
191 | else | 186 | else |
192 | return current_tick - record_start_time; | 187 | return current_tick - record_start_time; |
@@ -195,92 +190,168 @@ unsigned long pcm_recorded_time(void) | |||
195 | return 0; | 190 | return 0; |
196 | } | 191 | } |
197 | 192 | ||
198 | unsigned long pcm_num_recorded_bytes(void) | 193 | unsigned long audio_num_recorded_bytes(void) |
199 | { | 194 | { |
200 | |||
201 | if (is_recording) | 195 | if (is_recording) |
202 | { | ||
203 | return num_rec_bytes; | 196 | return num_rec_bytes; |
204 | } | ||
205 | else | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | void pcm_pause_recording(void) | ||
210 | { | ||
211 | /* todo */ | ||
212 | } | ||
213 | 197 | ||
214 | void pcm_resume_recording(void) | 198 | return 0; |
215 | { | ||
216 | /* todo */ | ||
217 | } | 199 | } |
218 | 200 | ||
219 | 201 | ||
220 | /** | 202 | /** |
221 | * Sets the audio source | 203 | * Sets the audio source |
222 | * | 204 | * |
223 | * Side effect: This functions starts feeding the CPU with audio data over the I2S bus | 205 | * This functions starts feeding the CPU with audio data over the I2S bus |
224 | * | 206 | * |
225 | * @param source 0=line-in, 1=mic | 207 | * @param source 0=mic, 1=line-in, (todo: 2=spdif) |
226 | */ | 208 | */ |
227 | void pcm_set_recording_options(int source, bool enable_waveform) | 209 | void audio_set_recording_options(int frequency, int quality, |
210 | int source, int channel_mode, | ||
211 | bool editable, int prerecord_time, | ||
212 | bool monitor) | ||
228 | { | 213 | { |
229 | #if defined(HAVE_UDA1380) | 214 | /* TODO: */ |
230 | uda1380_enable_recording(source); | 215 | (void)frequency; |
231 | #elif defined(HAVE_TLV320) | 216 | (void)quality; |
232 | tlv320_enable_recording(source); | 217 | (void)channel_mode; |
233 | #endif | 218 | (void)editable; |
234 | show_waveform = enable_waveform; | 219 | (void)prerecord_time; |
220 | |||
221 | //logf("pcmrec: src=%d", source); | ||
222 | |||
223 | switch (source) | ||
224 | { | ||
225 | /* mic */ | ||
226 | case 0: | ||
227 | uda1380_enable_recording(true); | ||
228 | break; | ||
229 | |||
230 | /* line-in */ | ||
231 | case 1: | ||
232 | uda1380_enable_recording(false); | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | uda1380_set_monitor(monitor); | ||
235 | } | 237 | } |
236 | 238 | ||
237 | 239 | ||
238 | /** | 240 | /** |
241 | * Note that microphone is mono, only left value is used | ||
242 | * See uda1380_set_recvol() for exact ranges. | ||
239 | * | 243 | * |
240 | * @param gain line-in and microphone gain (0-15) | 244 | * @param type 0=line-in (radio), 1=mic, 2=ADC |
241 | * @param volume ADC volume (0-255) | 245 | * |
242 | */ | 246 | */ |
243 | void pcm_set_recording_gain(int gain, int volume) | 247 | void audio_set_recording_gain(int left, int right, int type) |
244 | { | 248 | { |
245 | rec_gain = gain; | 249 | //logf("rcmrec: t=%d l=%d r=%d", type, left, right); |
246 | rec_volume = volume; | 250 | uda1380_set_recvol(left, right, type); |
247 | |||
248 | queue_post(&pcmrec_queue, PCMREC_SET_GAIN, 0); | ||
249 | } | 251 | } |
250 | 252 | ||
253 | |||
251 | /** | 254 | /** |
252 | * Start recording | 255 | * Start recording |
253 | * | 256 | * |
254 | * Use pcm_set_recording_options before calling record | 257 | * Use audio_set_recording_options first to select recording options |
255 | */ | 258 | */ |
256 | void pcm_record(const char *filename) | 259 | void audio_record(const char *filename) |
257 | { | 260 | { |
261 | if (is_recording) | ||
262 | { | ||
263 | logf("record while recording"); | ||
264 | return; | ||
265 | } | ||
266 | |||
258 | strncpy(recording_filename, filename, MAX_PATH - 1); | 267 | strncpy(recording_filename, filename, MAX_PATH - 1); |
259 | recording_filename[MAX_PATH - 1] = 0; | 268 | recording_filename[MAX_PATH - 1] = 0; |
260 | 269 | ||
270 | record_done = false; | ||
261 | queue_post(&pcmrec_queue, PCMREC_START, 0); | 271 | queue_post(&pcmrec_queue, PCMREC_START, 0); |
272 | |||
273 | while(!record_done) | ||
274 | sleep_thread(); | ||
275 | wake_up_thread(); | ||
276 | } | ||
277 | |||
278 | |||
279 | void audio_new_file(const char *filename) | ||
280 | { | ||
281 | logf("pcm_new_file"); | ||
282 | |||
283 | new_file_done = false; | ||
284 | |||
285 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
286 | recording_filename[MAX_PATH - 1] = 0; | ||
287 | |||
288 | queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); | ||
289 | |||
290 | while(!new_file_done) | ||
291 | sleep_thread(); | ||
292 | wake_up_thread(); | ||
293 | |||
294 | logf("pcm_new_file done"); | ||
262 | } | 295 | } |
263 | 296 | ||
264 | /** | 297 | /** |
265 | * | 298 | * |
266 | */ | 299 | */ |
267 | void pcm_stop_recording(void) | 300 | void audio_stop_recording(void) |
268 | { | 301 | { |
269 | if (is_recording) | 302 | if (!is_recording) |
270 | is_stopping = 1; | 303 | return; |
271 | 304 | ||
305 | logf("pcm_stop"); | ||
306 | |||
307 | stop_done = false; | ||
272 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 308 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); |
273 | 309 | ||
274 | logf("pcm_stop_recording"); | 310 | while(!stop_done) |
311 | sleep_thread(); | ||
312 | wake_up_thread(); | ||
313 | |||
314 | logf("pcm_stop done"); | ||
315 | } | ||
275 | 316 | ||
276 | while (is_stopping) | 317 | void audio_pause_recording(void) |
318 | { | ||
319 | if (!is_recording) | ||
320 | { | ||
321 | logf("pause when not recording"); | ||
322 | return; | ||
323 | } | ||
324 | if (is_paused) | ||
277 | { | 325 | { |
278 | sleep(HZ >> 4); | 326 | logf("pause when paused"); |
327 | return; | ||
279 | } | 328 | } |
329 | |||
330 | pause_done = false; | ||
331 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | ||
280 | 332 | ||
281 | logf("pcm_stop_recording done"); | 333 | while(!pause_done) |
334 | sleep_thread(); | ||
335 | wake_up_thread(); | ||
282 | } | 336 | } |
283 | 337 | ||
338 | void audio_resume_recording(void) | ||
339 | { | ||
340 | if (!is_paused) | ||
341 | { | ||
342 | logf("resume when not paused"); | ||
343 | return; | ||
344 | } | ||
345 | |||
346 | resume_done = false; | ||
347 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | ||
348 | |||
349 | while(!resume_done) | ||
350 | sleep_thread(); | ||
351 | wake_up_thread(); | ||
352 | } | ||
353 | |||
354 | |||
284 | 355 | ||
285 | /***************************************************************************/ | 356 | /***************************************************************************/ |
286 | /* Functions that executes in the context of pcmrec_thread */ | 357 | /* Functions that executes in the context of pcmrec_thread */ |
@@ -288,100 +359,116 @@ void pcm_stop_recording(void) | |||
288 | 359 | ||
289 | 360 | ||
290 | /** | 361 | /** |
291 | * Process the buffers using read_index and write_index. | 362 | * Process the chunks using read_index and write_index. |
292 | * | 363 | * |
293 | * DMA1 handler posts to pcmrec_queue so that pcmrec_thread calls this | 364 | * DMA1 handler posts to pcmrec_queue and pcmrec_thread calls this |
294 | * function. Also pcmrec_stop will call this function when the recording | 365 | * function. |
295 | * is stopping, and that call will have flush = true. | 366 | * |
367 | * Other function can also call this function with flush = true when | ||
368 | * they want to save everything recorded sofar to disk. | ||
296 | * | 369 | * |
297 | */ | 370 | */ |
298 | 371 | ||
299 | void pcmrec_callback(bool flush) __attribute__ ((section (".icode"))); | 372 | static void pcmrec_callback(bool flush) __attribute__ ((section (".icode"))); |
300 | void pcmrec_callback(bool flush) | 373 | static void pcmrec_callback(bool flush) |
301 | { | 374 | { |
302 | int num_ready; | 375 | int num_ready, num_free, num_new; |
376 | unsigned short *ptr; | ||
377 | int i, j, w; | ||
378 | |||
379 | w = write_index; | ||
380 | |||
381 | num_new = w - read2_index; | ||
382 | if (num_new < 0) | ||
383 | num_new += num_chunks; | ||
384 | |||
385 | for (i=0; i<num_new; i++) | ||
386 | { | ||
387 | /* Convert the samples to little-endian so we only have to write later | ||
388 | (Less hd-spinning time) | ||
389 | */ | ||
390 | ptr = GET_CHUNK(read2_index); | ||
391 | for (j=0; j<CHUNK_SIZE/2; j++) | ||
392 | { | ||
393 | /* TODO: might be a good place to add the peak-meter.. */ | ||
394 | |||
395 | *ptr = htole16(*ptr); | ||
396 | ptr++; | ||
397 | } | ||
398 | |||
399 | num_rec_bytes += CHUNK_SIZE; | ||
400 | |||
401 | read2_index++; | ||
402 | if (read2_index >= num_chunks) | ||
403 | read2_index = 0; | ||
404 | } | ||
303 | 405 | ||
304 | num_ready = write_index - read_index; | 406 | num_ready = w - read_index; |
305 | if (num_ready < 0) | 407 | if (num_ready < 0) |
306 | num_ready += NUM_BUFFERS; | 408 | num_ready += num_chunks; |
307 | |||
308 | /* we can consume up to num_ready buffers */ | ||
309 | 409 | ||
310 | #ifdef HAVE_REMOTE_LCD | 410 | if (num_ready >= num_chunks) |
311 | /* Draw waveform on remote LCD */ | ||
312 | if (show_waveform && num_ready>0) | ||
313 | { | 411 | { |
314 | short *buf; | 412 | logf("num_ready overflow?"); |
315 | long x,y,offset; | 413 | num_ready = num_chunks-1; |
316 | int show_index; | 414 | } |
317 | |||
318 | /* Just display the last buffer (most recent one) */ | ||
319 | show_index = read_index + num_ready - 1; | ||
320 | buf = (short*)rec_buffers[show_index]; | ||
321 | |||
322 | lcd_remote_clear_display(); | ||
323 | |||
324 | offset = 0; | ||
325 | for (x=0; x<LCD_REMOTE_WIDTH-1; x++) | ||
326 | { | ||
327 | y = buf[offset] * (LCD_REMOTE_HEIGHT / 2) *5; /* The 5 is just 'zooming' */ | ||
328 | y = y >> 15; /* Divide with SHRT_MAX */ | ||
329 | y += LCD_REMOTE_HEIGHT/2; | ||
330 | 415 | ||
331 | if (y < 2) y=2; | 416 | num_free = num_chunks - num_ready; |
332 | if (y >= LCD_REMOTE_HEIGHT-2) y = LCD_REMOTE_HEIGHT-2; | ||
333 | 417 | ||
334 | lcd_remote_drawpixel(x,y); | 418 | if (wav_file == -1 || (!is_recording && !flush)) |
419 | { | ||
420 | /* In this case we should consume the buffers to avoid */ | ||
421 | /* getting 'dma1 overrun' */ | ||
335 | 422 | ||
336 | offset += (EACH_BUFFER_SIZE/2) / LCD_REMOTE_WIDTH; | 423 | read_index+=num_ready; |
337 | } | 424 | if (read_index >= num_chunks) |
425 | read_index -= num_chunks; | ||
338 | 426 | ||
339 | lcd_remote_update(); | 427 | return; |
340 | } | 428 | } |
341 | 429 | ||
342 | #endif | 430 | if (num_free <= WRITE_THRESHOLD || flush) |
343 | |||
344 | /* Note: This might be a good place to call the 'codec' later */ | ||
345 | |||
346 | /* Check that we have the minimum amount of data to save or */ | ||
347 | /* that if it's closing time which mean we have to save.. */ | ||
348 | if (wav_file != -1) | ||
349 | { | 431 | { |
350 | if (num_ready >= WRITE_THRESHOLD || flush) | 432 | logf("writing: %d (%d)", num_ready, flush); |
433 | |||
434 | for (i=0; i<num_ready; i++) | ||
351 | { | 435 | { |
352 | unsigned short *ptr = (unsigned short*)rec_buffers[read_index]; | 436 | if (write(wav_file, GET_CHUNK(read_index), CHUNK_SIZE) != CHUNK_SIZE) |
353 | int i; | ||
354 | |||
355 | for (i=0; i<EACH_BUFFER_SIZE * num_ready / 2; i++) | ||
356 | { | 437 | { |
357 | *ptr = htole16(*ptr); | 438 | logf("pcmrec: write err"); |
358 | ptr++; | 439 | pcmrec_dma_stop(); |
440 | return; | ||
359 | } | 441 | } |
360 | 442 | ||
361 | write(wav_file, rec_buffers[read_index], EACH_BUFFER_SIZE * num_ready); | 443 | num_file_bytes += CHUNK_SIZE; |
362 | 444 | ||
363 | read_index+=num_ready; | 445 | read_index++; |
364 | if (read_index >= NUM_BUFFERS) | 446 | if (read_index >= num_chunks) |
365 | read_index -= NUM_BUFFERS; | 447 | read_index = 0; |
366 | } | 448 | } |
367 | 449 | ||
368 | } else | 450 | logf("done"); |
369 | { | ||
370 | /* In this case we must consume the buffers otherwise we will */ | ||
371 | /* get 'dma1 overrun' pretty fast */ | ||
372 | |||
373 | read_index+=num_ready; | ||
374 | if (read_index >= NUM_BUFFERS) | ||
375 | read_index -= NUM_BUFFERS; | ||
376 | } | 451 | } |
377 | } | 452 | } |
378 | 453 | ||
454 | /* Abort dma transfer */ | ||
455 | static void pcmrec_dma_stop(void) | ||
456 | { | ||
457 | DCR1 = 0; | ||
458 | |||
459 | is_error = true; | ||
460 | is_recording = false; | ||
461 | |||
462 | error_count++; | ||
463 | |||
464 | logf("dma1 stopped"); | ||
465 | } | ||
379 | 466 | ||
380 | void pcmrec_dma_start(void) | 467 | static void pcmrec_dma_start(void) |
381 | { | 468 | { |
382 | DAR1 = (unsigned long)rec_buffers[write_index++]; /* Destination address */ | 469 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ |
383 | SAR1 = (unsigned long)&PDIR2; /* Source address */ | 470 | SAR1 = (unsigned long)&PDIR2; /* Source address */ |
384 | BCR1 = EACH_BUFFER_SIZE; /* Bytes to transfer */ | 471 | BCR1 = CHUNK_SIZE; /* Bytes to transfer */ |
385 | 472 | ||
386 | /* Start the DMA transfer.. */ | 473 | /* Start the DMA transfer.. */ |
387 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; | 474 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; |
@@ -404,36 +491,37 @@ void DMA1(void) | |||
404 | { | 491 | { |
405 | DCR1 = 0; /* Stop DMA transfer */ | 492 | DCR1 = 0; /* Stop DMA transfer */ |
406 | error_count++; | 493 | error_count++; |
407 | is_recording = 0; | 494 | is_recording = false; |
408 | 495 | ||
409 | logf("dma1 err 0x%x", res); | 496 | logf("dma1 err 0x%x", res); |
497 | |||
498 | /* Flush recorded data to disk and stop recording */ | ||
499 | queue_post(&pcmrec_queue, PCMREC_STOP, NULL); | ||
410 | 500 | ||
411 | } else | 501 | } else |
412 | { | 502 | { |
413 | num_rec_bytes += EACH_BUFFER_SIZE; | ||
414 | |||
415 | write_index++; | 503 | write_index++; |
416 | if (write_index >= NUM_BUFFERS) | 504 | if (write_index >= num_chunks) |
417 | write_index = 0; | 505 | write_index = 0; |
418 | 506 | ||
419 | if (is_stopping || !is_recording) | 507 | if (is_stopping || !is_recording) |
420 | { | 508 | { |
421 | DCR1 = 0; /* Stop DMA transfer */ | 509 | DCR1 = 0; /* Stop DMA transfer */ |
422 | is_recording = 0; | 510 | is_stopping = false; |
423 | 511 | ||
424 | logf("dma1 stopping"); | 512 | logf("dma1 stopping"); |
425 | 513 | ||
426 | } else if (write_index == read_index) | 514 | } else if (write_index == read_index) |
427 | { | 515 | { |
428 | DCR1 = 0; /* Stop DMA transfer */ | 516 | DCR1 = 0; /* Stop DMA transfer */ |
429 | is_recording = 0; | 517 | is_recording = false; |
430 | 518 | ||
431 | logf("dma1 overrun"); | 519 | logf("dma1 overrun"); |
432 | 520 | ||
433 | } else | 521 | } else |
434 | { | 522 | { |
435 | DAR1 = (unsigned long)rec_buffers[write_index]; /* Destination address */ | 523 | DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ |
436 | BCR1 = EACH_BUFFER_SIZE; | 524 | BCR1 = CHUNK_SIZE; |
437 | 525 | ||
438 | queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL); | 526 | queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL); |
439 | 527 | ||
@@ -443,6 +531,8 @@ void DMA1(void) | |||
443 | IPR |= (1<<15); /* Clear pending interrupt request */ | 531 | IPR |= (1<<15); /* Clear pending interrupt request */ |
444 | } | 532 | } |
445 | 533 | ||
534 | /* Create WAVE file and write header */ | ||
535 | /* Sets returns 0 if success, -1 on failure */ | ||
446 | static int start_wave(void) | 536 | static int start_wave(void) |
447 | { | 537 | { |
448 | unsigned char header[44] = | 538 | unsigned char header[44] = |
@@ -456,7 +546,8 @@ static int start_wave(void) | |||
456 | if (wav_file < 0) | 546 | if (wav_file < 0) |
457 | { | 547 | { |
458 | wav_file = -1; | 548 | wav_file = -1; |
459 | logf("create failed: %d", wav_file); | 549 | logf("rec: create failed: %d", wav_file); |
550 | is_error = true; | ||
460 | return -1; | 551 | return -1; |
461 | } | 552 | } |
462 | 553 | ||
@@ -464,8 +555,9 @@ static int start_wave(void) | |||
464 | { | 555 | { |
465 | close(wav_file); | 556 | close(wav_file); |
466 | wav_file = -1; | 557 | wav_file = -1; |
467 | logf("write failed"); | 558 | logf("rec: write failed"); |
468 | return -2; | 559 | is_error = true; |
560 | return -1; | ||
469 | } | 561 | } |
470 | 562 | ||
471 | return 0; | 563 | return 0; |
@@ -476,16 +568,19 @@ static void close_wave(void) | |||
476 | { | 568 | { |
477 | long l; | 569 | long l; |
478 | 570 | ||
479 | l = htole32(num_rec_bytes + 36); | 571 | if (wav_file != -1) |
480 | lseek(wav_file, 4, SEEK_SET); | 572 | { |
481 | write(wav_file, &l, 4); | 573 | l = htole32(num_file_bytes + 36); |
482 | 574 | lseek(wav_file, 4, SEEK_SET); | |
483 | l = htole32(num_rec_bytes); | 575 | write(wav_file, &l, 4); |
484 | lseek(wav_file, 40, SEEK_SET); | 576 | |
485 | write(wav_file, &l, 4); | 577 | l = htole32(num_file_bytes); |
486 | 578 | lseek(wav_file, 40, SEEK_SET); | |
487 | close(wav_file); | 579 | write(wav_file, &l, 4); |
488 | wav_file = -1; | 580 | |
581 | close(wav_file); | ||
582 | wav_file = -1; | ||
583 | } | ||
489 | } | 584 | } |
490 | 585 | ||
491 | static void pcmrec_start(void) | 586 | static void pcmrec_start(void) |
@@ -493,74 +588,206 @@ static void pcmrec_start(void) | |||
493 | logf("pcmrec_start"); | 588 | logf("pcmrec_start"); |
494 | 589 | ||
495 | if (is_recording) | 590 | if (is_recording) |
591 | { | ||
592 | logf("already recording"); | ||
593 | record_done = true; | ||
496 | return; | 594 | return; |
497 | 595 | } | |
596 | |||
498 | if (wav_file != -1) | 597 | if (wav_file != -1) |
499 | close(wav_file); | 598 | close(wav_file); |
500 | 599 | ||
501 | logf("rec: %s", recording_filename); | 600 | if (start_wave() != 0) |
502 | 601 | { | |
503 | start_wave(); /* todo: send signal to pcm_record if we have failed */ | 602 | /* failed to create the file */ |
504 | 603 | record_done = true; | |
604 | return; | ||
605 | } | ||
606 | |||
505 | num_rec_bytes = 0; | 607 | num_rec_bytes = 0; |
506 | 608 | num_file_bytes = 0; | |
507 | /* Store the current time */ | ||
508 | record_start_time = current_tick; | 609 | record_start_time = current_tick; |
509 | 610 | pause_start_time = 0; | |
611 | |||
510 | write_index = 0; | 612 | write_index = 0; |
511 | read_index = 0; | 613 | read_index = 0; |
614 | read2_index = 0; | ||
512 | 615 | ||
513 | is_stopping = 0; | 616 | is_stopping = false; |
514 | is_paused = 0; | 617 | is_paused = false; |
515 | is_recording = 1; | 618 | is_recording = true; |
516 | 619 | ||
517 | pcmrec_dma_start(); | 620 | pcmrec_dma_start(); |
518 | 621 | ||
622 | record_done = true; | ||
519 | } | 623 | } |
520 | 624 | ||
521 | static void pcmrec_stop(void) | 625 | static void pcmrec_stop(void) |
522 | { | 626 | { |
523 | /* wait for recording to finish */ | 627 | logf("pcmrec_stop"); |
628 | |||
629 | if (!is_recording) | ||
630 | { | ||
631 | stop_done = true; | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | if (!is_paused) | ||
636 | { | ||
637 | /* wait for recording to finish */ | ||
638 | is_stopping = true; | ||
639 | |||
640 | while (is_stopping && is_recording) | ||
641 | sleep_thread(); | ||
642 | wake_up_thread(); | ||
643 | |||
644 | is_stopping = false; | ||
645 | } | ||
646 | |||
647 | is_recording = false; | ||
648 | |||
649 | /* Flush buffers to file */ | ||
650 | pcmrec_callback(true); | ||
524 | 651 | ||
525 | /* todo: Abort current DMA transfer using DCR1.. */ | 652 | close_wave(); |
526 | 653 | ||
527 | logf("pcmrec_stop"); | 654 | stop_done = true; |
655 | |||
656 | logf("pcmrec_stop done"); | ||
657 | } | ||
528 | 658 | ||
529 | while (is_recording) | 659 | static void pcmrec_new_file(void) |
660 | { | ||
661 | logf("pcmrec_new_file"); | ||
662 | |||
663 | if (!is_recording) | ||
530 | { | 664 | { |
531 | sleep(HZ >> 4); | 665 | logf("not recording"); |
666 | new_file_done = true; | ||
667 | return; | ||
532 | } | 668 | } |
669 | |||
670 | /* Since pcmrec_callback() blocks until the data has been written, | ||
671 | here is a good approximation when recording to the new file starts | ||
672 | */ | ||
673 | record_start_time = current_tick; | ||
674 | num_rec_bytes = 0; | ||
675 | |||
676 | if (is_paused) | ||
677 | pause_start_time = record_start_time; | ||
678 | |||
679 | /* Flush what we got in buffers to file */ | ||
680 | pcmrec_callback(true); | ||
681 | |||
682 | close_wave(); | ||
533 | 683 | ||
534 | logf("pcmrec_stop done"); | 684 | num_file_bytes = 0; |
685 | |||
686 | /* start the new file */ | ||
687 | if (start_wave() != 0) | ||
688 | { | ||
689 | logf("new_file failed"); | ||
690 | pcmrec_stop(); | ||
691 | } | ||
535 | 692 | ||
536 | /* Write unfinished buffers to file */ | 693 | new_file_done = true; |
694 | logf("pcmrec_new_file done"); | ||
695 | } | ||
696 | |||
697 | static void pcmrec_pause(void) | ||
698 | { | ||
699 | logf("pcmrec_pause"); | ||
700 | |||
701 | if (!is_recording) | ||
702 | { | ||
703 | logf("pause: not recording"); | ||
704 | pause_done = true; | ||
705 | return; | ||
706 | } | ||
707 | |||
708 | /* Abort DMA transfer and flush to file? */ | ||
709 | |||
710 | is_stopping = true; | ||
711 | |||
712 | while (is_stopping && is_recording) | ||
713 | sleep_thread(); | ||
714 | wake_up_thread(); | ||
715 | |||
716 | pause_start_time = current_tick; | ||
717 | is_paused = true; | ||
718 | |||
719 | /* Flush what we got in buffers to file */ | ||
537 | pcmrec_callback(true); | 720 | pcmrec_callback(true); |
721 | |||
722 | pause_done = true; | ||
723 | |||
724 | logf("pcmrec_pause done"); | ||
725 | } | ||
538 | 726 | ||
539 | close_wave(); | ||
540 | 727 | ||
541 | is_stopping = 0; | 728 | static void pcmrec_resume(void) |
729 | { | ||
730 | logf("pcmrec_resume"); | ||
731 | |||
732 | if (!is_paused) | ||
733 | { | ||
734 | logf("resume: not paused"); | ||
735 | resume_done = true; | ||
736 | return; | ||
737 | } | ||
738 | |||
739 | is_paused = false; | ||
740 | is_recording = true; | ||
741 | |||
742 | /* Compensate for the time we have been paused */ | ||
743 | if (pause_start_time) | ||
744 | { | ||
745 | record_start_time += current_tick - pause_start_time; | ||
746 | pause_start_time = 0; | ||
747 | } | ||
748 | |||
749 | pcmrec_dma_start(); | ||
750 | |||
751 | resume_done = true; | ||
752 | |||
753 | logf("pcmrec_resume done"); | ||
542 | } | 754 | } |
543 | 755 | ||
544 | static void pcmrec_open(void) | 756 | |
757 | /** | ||
758 | * audio_init_recording calls this function using PCMREC_INIT | ||
759 | * | ||
760 | */ | ||
761 | static void pcmrec_init(void) | ||
545 | { | 762 | { |
546 | unsigned long buffer_start; | 763 | unsigned long buffer_size; |
547 | int i; | ||
548 | 764 | ||
549 | show_waveform = 0; | 765 | show_waveform = 0; |
550 | is_recording = 0; | ||
551 | is_stopping = 0; | ||
552 | num_rec_bytes = 0; | ||
553 | wav_file = -1; | 766 | wav_file = -1; |
554 | read_index = 0; | 767 | read_index = 0; |
768 | read2_index = 0; | ||
555 | write_index = 0; | 769 | write_index = 0; |
556 | 770 | ||
557 | buffer_start = (unsigned long)(&audiobuf[(audiobufend - audiobuf) - (ALL_BUFFERS_SIZE + 16)]); | 771 | num_rec_bytes = 0; |
558 | buffer_start &= ~3; | 772 | num_file_bytes = 0; |
559 | 773 | record_start_time = 0; | |
560 | for (i=0; i<NUM_BUFFERS; i++) | 774 | pause_start_time = 0; |
561 | { | 775 | |
562 | rec_buffers[i] = (unsigned char*)(buffer_start + EACH_BUFFER_SIZE * i); | 776 | is_recording = false; |
563 | } | 777 | is_stopping = false; |
778 | is_paused = false; | ||
779 | is_error = false; | ||
780 | |||
781 | rec_buffer = (unsigned char*)(((unsigned long)audiobuf) & ~3); | ||
782 | buffer_size = (long)audiobufend - (long)audiobuf - 16; | ||
783 | |||
784 | //buffer_size = 1024*1024*5; | ||
785 | |||
786 | logf("buf size: %d kb", buffer_size/1024); | ||
787 | |||
788 | num_chunks = buffer_size / CHUNK_SIZE; | ||
789 | |||
790 | logf("num_chunks: %d", num_chunks); | ||
564 | 791 | ||
565 | IIS1CONFIG = 0x800; /* Stop any playback */ | 792 | IIS1CONFIG = 0x800; /* Stop any playback */ |
566 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ | 793 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ |
@@ -578,16 +805,13 @@ static void pcmrec_open(void) | |||
578 | 805 | ||
579 | static void pcmrec_close(void) | 806 | static void pcmrec_close(void) |
580 | { | 807 | { |
581 | #if defined(HAVE_UDA1380) | ||
582 | uda1380_disable_recording(); | 808 | uda1380_disable_recording(); |
583 | #elif defined(HAVE_TLV320) | ||
584 | tlv320_disable_recording(); | ||
585 | #endif | ||
586 | 809 | ||
587 | DMAROUTE = (DMAROUTE & 0xffff00ff); | 810 | DMAROUTE = (DMAROUTE & 0xffff00ff); |
588 | ICR7 = 0x00; /* Disable interrupt */ | 811 | ICR7 = 0x00; /* Disable interrupt */ |
589 | IMR |= (1<<15); /* bit 15 is DMA1 */ | 812 | IMR |= (1<<15); /* bit 15 is DMA1 */ |
590 | 813 | ||
814 | close_done = true; | ||
591 | } | 815 | } |
592 | 816 | ||
593 | static void pcmrec_thread(void) | 817 | static void pcmrec_thread(void) |
@@ -596,14 +820,17 @@ static void pcmrec_thread(void) | |||
596 | 820 | ||
597 | logf("thread pcmrec start"); | 821 | logf("thread pcmrec start"); |
598 | 822 | ||
823 | int_count = 0; | ||
824 | error_count = 0; | ||
825 | |||
599 | while (1) | 826 | while (1) |
600 | { | 827 | { |
601 | queue_wait(&pcmrec_queue, &ev); | 828 | queue_wait(&pcmrec_queue, &ev); |
602 | 829 | ||
603 | switch (ev.id) | 830 | switch (ev.id) |
604 | { | 831 | { |
605 | case PCMREC_OPEN: | 832 | case PCMREC_INIT: |
606 | pcmrec_open(); | 833 | pcmrec_init(); |
607 | break; | 834 | break; |
608 | 835 | ||
609 | case PCMREC_CLOSE: | 836 | case PCMREC_CLOSE: |
@@ -619,25 +846,18 @@ static void pcmrec_thread(void) | |||
619 | break; | 846 | break; |
620 | 847 | ||
621 | case PCMREC_PAUSE: | 848 | case PCMREC_PAUSE: |
622 | /* todo */ | 849 | pcmrec_pause(); |
623 | break; | 850 | break; |
624 | 851 | ||
625 | case PCMREC_RESUME: | 852 | case PCMREC_RESUME: |
626 | /* todo */ | 853 | pcmrec_resume(); |
627 | break; | 854 | break; |
628 | 855 | ||
629 | case PCMREC_NEW_FILE: | 856 | case PCMREC_NEW_FILE: |
630 | /* todo */ | 857 | pcmrec_new_file(); |
631 | break; | ||
632 | |||
633 | case PCMREC_SET_GAIN: | ||
634 | #if defined(HAVE_UDA1380) | ||
635 | uda1380_set_recvol(rec_gain, rec_gain, rec_volume); | ||
636 | #elif defined(HAVE_TLV320) | ||
637 | /* ToDo */ | ||
638 | #endif | ||
639 | break; | 858 | break; |
640 | 859 | ||
860 | /* Notification by DMA interrupt */ | ||
641 | case PCMREC_GOT_DATA: | 861 | case PCMREC_GOT_DATA: |
642 | pcmrec_callback(false); | 862 | pcmrec_callback(false); |
643 | break; | 863 | break; |
@@ -655,7 +875,8 @@ static void pcmrec_thread(void) | |||
655 | logf("thread pcmrec done"); | 875 | logf("thread pcmrec done"); |
656 | } | 876 | } |
657 | 877 | ||
658 | void pcmrec_set_mux(int source) | 878 | /* Select VINL & VINR source: 0=Line-in, 1=FM Radio */ |
879 | void pcm_rec_mux(int source) | ||
659 | { | 880 | { |
660 | if(source == 0) | 881 | if(source == 0) |
661 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ | 882 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ |
diff --git a/firmware/sound.c b/firmware/sound.c index 332cca02e8..9ab545f51d 100644 --- a/firmware/sound.c +++ b/firmware/sound.c | |||
@@ -84,6 +84,12 @@ static const struct sound_settings_info sound_settings_table[] = { | |||
84 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL}, | 84 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL}, |
85 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL}, | 85 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL}, |
86 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 15, 2, NULL}, | 86 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 15, 2, NULL}, |
87 | #elif defined(HAVE_UDA1380) | ||
88 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 8, 8, NULL}, | ||
89 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 8, 8, NULL}, | ||
90 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 15, 2, NULL}, | ||
91 | [SOUND_ADC_LEFT_GAIN] = {"dB", 1, 1,-128, 48, 0, NULL}, | ||
92 | [SOUND_ADC_RIGHT_GAIN]= {"dB", 1, 1,-128, 48, 0, NULL}, | ||
87 | #endif | 93 | #endif |
88 | }; | 94 | }; |
89 | 95 | ||
@@ -668,6 +674,30 @@ int sound_val2phys(int setting, int value) | |||
668 | break; | 674 | break; |
669 | } | 675 | } |
670 | return result; | 676 | return result; |
677 | #elif defined(HAVE_UDA1380) | ||
678 | int result = 0; | ||
679 | |||
680 | switch(setting) | ||
681 | { | ||
682 | case SOUND_LEFT_GAIN: | ||
683 | case SOUND_RIGHT_GAIN: | ||
684 | result = value * 30; /* (24/8) *10 */ | ||
685 | break; | ||
686 | |||
687 | case SOUND_MIC_GAIN: | ||
688 | result = value * 20; /* (30/15) *10 */ | ||
689 | break; | ||
690 | |||
691 | case SOUND_ADC_LEFT_GAIN: | ||
692 | case SOUND_ADC_RIGHT_GAIN: | ||
693 | result = value * 5; /* (1/2) *10 */ | ||
694 | break; | ||
695 | |||
696 | default: | ||
697 | result = value; | ||
698 | break; | ||
699 | } | ||
700 | return result; | ||
671 | #else | 701 | #else |
672 | (void)setting; | 702 | (void)setting; |
673 | return value; | 703 | return value; |