summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy <andy@rockbox.org>2005-11-12 04:00:56 +0000
committerAndy <andy@rockbox.org>2005-11-12 04:00:56 +0000
commite6e5496535a6fa45ee5cb63fb80886514ae72231 (patch)
treeebd73be009933c4c7eaf224ccec308aa56dd7b99
parent663fba13996c32e13d4cca89ffda86de8d536c7f (diff)
downloadrockbox-e6e5496535a6fa45ee5cb63fb80886514ae72231.tar.gz
rockbox-e6e5496535a6fa45ee5cb63fb80886514ae72231.zip
iRiver: Initial support for wav-recording in recording menu. Supports mic/line-in (and radio), monitor mode, time-splitting (and byte-splitting), pause/resume etc. Things todo: Prerecording, peakmeter (should be simple), frequency other than 44.1 kHz, etc..
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7818 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/debug_menu.c4
-rw-r--r--apps/lang/english.lang22
-rw-r--r--apps/main.c2
-rw-r--r--apps/recorder/radio.c32
-rw-r--r--apps/recorder/recording.c114
-rw-r--r--apps/settings.c23
-rw-r--r--apps/settings.h5
-rw-r--r--apps/sound_menu.c34
-rw-r--r--firmware/drivers/uda1380.c33
-rw-r--r--firmware/export/audio.h23
-rw-r--r--firmware/export/config-h120.h2
-rw-r--r--firmware/export/mpeg.h13
-rw-r--r--firmware/export/pcm_record.h32
-rw-r--r--firmware/export/sound.h6
-rw-r--r--firmware/export/uda1380.h2
-rw-r--r--firmware/mpeg.c51
-rw-r--r--firmware/pcm_record.c717
-rw-r--r--firmware/sound.c30
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
65metadata.c 65metadata.c
66codecs.c 66codecs.c
67dsp.c 67dsp.c
68#ifndef SIMULATOR
69pcm_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)
62extern 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
940id: LANG_RECORDING_LEFT 940id: LANG_RECORDING_LEFT
941desc: in the recording screen 941desc: in the recording screen
942eng: "Left" 942eng: "Gain Left"
943voice: "" 943voice: ""
944new: 944new:
945 945
946id: LANG_RECORDING_RIGHT 946id: LANG_RECORDING_RIGHT
947desc: in the recording screen 947desc: in the recording screen
948eng: "Right" 948eng: "Gain Right"
949voice: "" 949voice: ""
950new: 950new:
951 951
@@ -3352,3 +3352,21 @@ desc: in crossfade settings menu
3352eng: "Fade out mode" 3352eng: "Fade out mode"
3353voice: "Fade out mode" 3353voice: "Fade out mode"
3354new: 3354new:
3355
3356id: LANG_RECORDING_ADC_RIGHT
3357desc: in the recording settings
3358eng: "ADC Gain Right"
3359voice: "ADC Gain Right"
3360new:
3361
3362id: LANG_RECORDING_ADC_LEFT
3363desc: in the recording settings
3364eng: "ADC Gain Left"
3365voice: "ADC Gain Left"
3366new:
3367
3368id: LANG_RECORDING_MONITOR
3369desc: in the recording settings
3370eng: "Monitor Mode"
3371voice: "Monitor Mode"
3372new:
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
107const char* const freq_str[6] = 123const 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
130static const char* const fmtstr[] = 151static 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
1085void 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
231static bool recmonitor(void)
232{
233 return set_bool(str(LANG_RECORDING_MONITOR),
234 &global_settings.rec_monitor);
235}
236
237#ifdef HAVE_UDA1380
238static 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
245static 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
231static bool rectimesplit(void) 253static 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 */
209void uda1380_enable_recording(bool source_mic) 210void 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 */
255void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume) 257void 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
36struct audio_debug 41struct audio_debug
37{ 42{
38 int audiobuflen; 43 int audiobuflen;
@@ -79,6 +84,24 @@ int audio_get_file_pos(void);
79void audio_beep(int duration); 84void audio_beep(int duration);
80void audio_init_playback(void); 85void audio_init_playback(void);
81 86
87/* audio recording functions */
88void audio_init_recording(void);
89void audio_close_recording(void);
90void audio_record(const char *filename);
91void audio_stop_recording(void);
92void audio_pause_recording(void);
93void audio_resume_recording(void);
94void audio_new_file(const char *filename);
95void audio_set_recording_options(int frequency, int quality,
96 int source, int channel_mode,
97 bool editable, int prerecord_time,
98 bool monitor);
99void audio_set_recording_gain(int left, int right, int type);
100unsigned long audio_recorded_time(void);
101unsigned 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)
47void mpeg_init_recording(void); 47
48void mpeg_record(const char *filename);
49void mpeg_new_file(const char *filename);
50void mpeg_set_recording_options(int frequency, int quality,
51 int source, int channel_mode,
52 bool editable, int prerecord_time);
53void mpeg_set_recording_gain(int left, int right, bool use_mic);
54#if CONFIG_TUNER & S1A0903X01 48#if CONFIG_TUNER & S1A0903X01
55int mpeg_get_mas_pllfreq(void); 49int mpeg_get_mas_pllfreq(void);
56#endif 50#endif
57unsigned long mpeg_recorded_time(void); 51
58unsigned long mpeg_num_recorded_bytes(void);
59void mpeg_pause_recording(void);
60void mpeg_resume_recording(void);
61#endif 52#endif
62unsigned long mpeg_get_last_header(void); 53unsigned 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
29unsigned long pcm_status(void); 23unsigned long pcm_rec_status(void);
30 24void pcm_rec_init(void);
31void pcm_init_recording(void); 25void pcm_rec_mux(int source);
32
33void pcm_open_recording(void);
34void pcm_close_recording(void);
35
36
37void pcm_set_recording_options(int source, bool enable_waveform);
38void pcm_set_recording_gain(int gain, int volume);
39
40void pcm_record(const char *filename);
41void pcm_stop_recording(void);
42
43//void pcm_new_file(const char *filename);
44
45
46unsigned long pcm_recorded_time(void);
47unsigned long pcm_num_recorded_bytes(void);
48void pcm_pause_recording(void);
49void pcm_resume_recording(void);
50 26
51void 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
46enum { 50enum {
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
33extern void uda1380_enable_recording(bool source_mic); 33extern void uda1380_enable_recording(bool source_mic);
34extern void uda1380_disable_recording(void); 34extern void uda1380_disable_recording(void);
35extern void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume); 35extern void uda1380_set_recvol(int left, int right, int type);
36extern void uda1380_set_monitor(int enable); 36extern 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 ***************************************************************************/
2118void mpeg_init_recording(void) 2118void 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
2227void mpeg_record(const char *filename) 2227void 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
2237void mpeg_pause_recording(void) 2237void 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
2242void mpeg_resume_recording(void) 2242void 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
2438void mpeg_set_recording_options(int frequency, int quality, 2438void 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 */
2500void mpeg_set_recording_gain(int left, int right, bool use_mic) 2501void 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
2542void mpeg_new_file(const char *filename) 2543void 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
2552unsigned long mpeg_recorded_time(void) 2553unsigned 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
2568unsigned long mpeg_num_recorded_bytes(void) 2569unsigned 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}
2602unsigned long mpeg_recorded_time(void) 2603unsigned 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}
2612void mpeg_pause_recording(void) 2613void audio_pause_recording(void)
2613{ 2614{
2614 /* a dummy */ 2615 /* a dummy */
2615} 2616}
2616void mpeg_resume_recording(void) 2617void audio_resume_recording(void)
2617{ 2618{
2618 /* a dummy */ 2619 /* a dummy */
2619} 2620}
2620unsigned long mpeg_num_recorded_bytes(void) 2621unsigned long audio_num_recorded_bytes(void)
2621{ 2622{
2622 /* a dummy */ 2623 /* a dummy */
2623 return 0; 2624 return 0;
2624} 2625}
2625void mpeg_record(const char *filename) 2626void audio_record(const char *filename)
2626{ 2627{
2627 /* a dummy */ 2628 /* a dummy */
2628 (void)filename; 2629 (void)filename;
2629} 2630}
2630void mpeg_new_file(const char *filename) 2631void audio_new_file(const char *filename)
2631{ 2632{
2632 /* a dummy */ 2633 /* a dummy */
2633 (void)filename; 2634 (void)filename;
2634} 2635}
2635 2636
2636void mpeg_set_recording_gain(int left, int right, bool use_mic) 2637void 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}
2643void mpeg_init_recording(void) 2644void audio_init_recording(void)
2644{ 2645{
2645 /* a dummy */ 2646 /* a dummy */
2646} 2647}
2647void mpeg_set_recording_options(int frequency, int quality, 2648void 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 */
2715void audio_stop_recording(void)
2716{
2717 audio_stop();
2718}
2719
2713void audio_pause(void) 2720void 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 @@
56static volatile bool is_recording; /* We are recording */ 52static volatile bool is_recording; /* We are recording */
57static volatile bool is_stopping; /* Are we going to stop */ 53static volatile bool is_stopping; /* Are we going to stop */
58static volatile bool is_paused; /* We have paused */ 54static volatile bool is_paused; /* We have paused */
55static volatile bool is_error; /* An error has occured */
59 56
60static volatile int num_rec_bytes; 57static volatile unsigned long num_rec_bytes; /* Num bytes recorded */
58static volatile unsigned long num_file_bytes; /* Num bytes written to current file */
61static volatile int int_count; /* Number of DMA completed interrupts */ 59static volatile int int_count; /* Number of DMA completed interrupts */
62static volatile int error_count; /* Number of DMA errors */ 60static volatile int error_count; /* Number of DMA errors */
63 61
64static unsigned long record_start_time; /* Value of current_tick when recording was started */ 62static unsigned long record_start_time; /* Value of current_tick when recording was started */
65static unsigned long pause_start_time; /* Value of current_tick when pause was started */ 63static unsigned long pause_start_time; /* Value of current_tick when pause was started */
66 64
67static int rec_gain, rec_volume;
68static bool show_waveform; 65static bool show_waveform;
69static int init_done = 0; 66
70static int wav_file; 67static int wav_file;
71static char recording_filename[MAX_PATH]; 68static char recording_filename[MAX_PATH];
72 69
70static 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 */ 92static unsigned char *rec_buffer; /* Circular recording buffer */
93static int num_chunks; /* Number of chunks available in rec_buffer */
89 94
90static 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
98static int write_index; /* Which buffer the DMA is currently recording */ 102static volatile int write_index; /* Current chunk the DMA is writing to */
99static int read_index; /* The oldest buffer that the pcmrec_callback has not read */ 103static volatile int read_index; /* Oldest chunk that is not written to disk */
104static 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
105static const char pcmrec_thread_name[] = "pcmrec"; 110static const char pcmrec_thread_name[] = "pcmrec";
106 111
107static void pcmrec_thread(void); 112static void pcmrec_thread(void);
113static void pcmrec_dma_start(void);
114static 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
125void pcm_init_recording(void) 133/* Creates pcmrec_thread */
134void 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
142void 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"); 146void 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
158void pcm_close_recording(void) 156void 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 166unsigned long pcm_rec_status(void)
165
166unsigned 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 180unsigned long audio_recorded_time(void)
177
178void pcm_new_file(const char *filename)
179{
180 /* todo */
181 filename = filename;
182
183}
184
185unsigned 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
198unsigned long pcm_num_recorded_bytes(void) 193unsigned 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
209void pcm_pause_recording(void)
210{
211 /* todo */
212}
213 197
214void 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 */
227void pcm_set_recording_options(int source, bool enable_waveform) 209void 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 */
243void pcm_set_recording_gain(int gain, int volume) 247void 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 */
256void pcm_record(const char *filename) 259void 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
279void 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 */
267void pcm_stop_recording(void) 300void 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) 317void 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
338void 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
299void pcmrec_callback(bool flush) __attribute__ ((section (".icode"))); 372static void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
300void pcmrec_callback(bool flush) 373static 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 */
455static 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
380void pcmrec_dma_start(void) 467static 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 */
446static int start_wave(void) 536static 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
491static void pcmrec_start(void) 586static 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
521static void pcmrec_stop(void) 625static 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) 659static 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
697static 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; 728static 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
544static void pcmrec_open(void) 756
757/**
758 * audio_init_recording calls this function using PCMREC_INIT
759 *
760 */
761static 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
579static void pcmrec_close(void) 806static 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
593static void pcmrec_thread(void) 817static 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
658void pcmrec_set_mux(int source) 878/* Select VINL & VINR source: 0=Line-in, 1=FM Radio */
879void 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;