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.zip
rockbox-e6e5496535a6fa45ee5cb63fb80886514ae72231.tar.gz
rockbox-e6e5496535a6fa45ee5cb63fb80886514ae72231.tar.bz2
rockbox-e6e5496535a6fa45ee5cb63fb80886514ae72231.tar.xz
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 8b2184b..6b2b682 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -65,7 +65,4 @@ playback.c
metadata.c
codecs.c
dsp.c
-#ifndef SIMULATOR
-pcm_recording.c
-#endif
#endif
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index cd395cc..dd6a2d7 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -58,9 +58,6 @@
#include "ata_mmc.h"
#endif
#include "logfdisp.h"
-#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
-extern bool pcm_rec_screen(void);
-#endif
#if CONFIG_CODEC == SWCODEC
#include "pcmbuf.h"
#include "pcm_playback.h"
@@ -1781,7 +1778,6 @@ bool debug_menu(void)
{ "CPU frequency", dbg_cpufreq },
#endif
#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
- { "PCM recording", pcm_rec_screen },
{ "S/PDIF analyzer", dbg_spdif },
#endif
#if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 9d54717..9123066 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -939,13 +939,13 @@ new:
id: LANG_RECORDING_LEFT
desc: in the recording screen
-eng: "Left"
+eng: "Gain Left"
voice: ""
new:
id: LANG_RECORDING_RIGHT
desc: in the recording screen
-eng: "Right"
+eng: "Gain Right"
voice: ""
new:
@@ -3352,3 +3352,21 @@ desc: in crossfade settings menu
eng: "Fade out mode"
voice: "Fade out mode"
new:
+
+id: LANG_RECORDING_ADC_RIGHT
+desc: in the recording settings
+eng: "ADC Gain Right"
+voice: "ADC Gain Right"
+new:
+
+id: LANG_RECORDING_ADC_LEFT
+desc: in the recording settings
+eng: "ADC Gain Left"
+voice: "ADC Gain Left"
+new:
+
+id: LANG_RECORDING_MONITOR
+desc: in the recording settings
+eng: "Monitor Mode"
+voice: "Monitor Mode"
+new:
diff --git a/apps/main.c b/apps/main.c
index 296b3fc..ab802d5 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -323,7 +323,7 @@ void init(void)
sound_settings_apply();
#endif
#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
- pcm_init_recording();
+ pcm_rec_init();
#endif
talk_init();
/* runtime database has to be initialized after audio_init() */
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 443bb31..6be6d04 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -226,7 +226,7 @@ bool radio_screen(void)
audio_stop();
#if CONFIG_CODEC != SWCODEC
- mpeg_init_recording();
+ audio_init_recording();
sound_settings_apply();
@@ -238,23 +238,24 @@ bool radio_screen(void)
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
1, /* Line In */
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
- mpeg_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
- sound_default(SOUND_RIGHT_GAIN), false);
+ audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
+ sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
#else
uda1380_enable_recording(false);
- uda1380_set_recvol(0, 0, 10);
+ uda1380_set_recvol(10, 10, AUDIO_GAIN_LINEIN);
uda1380_set_monitor(true);
/* Set the input multiplexer to FM */
- pcmrec_set_mux(1);
+ pcm_rec_mux(1);
#endif
#endif
@@ -345,14 +346,14 @@ bool radio_screen(void)
#ifndef SIMULATOR
if(audio_status() == AUDIO_STATUS_RECORD)
{
- mpeg_new_file(rec_create_filename(buf));
+ audio_new_file(rec_create_filename(buf));
update_screen = true;
}
else
{
have_recorded = true;
talk_buffer_steal(); /* we use the mp3 buffer */
- mpeg_record(rec_create_filename(buf));
+ audio_record(rec_create_filename(buf));
update_screen = true;
}
#endif
@@ -517,7 +518,7 @@ bool radio_screen(void)
#ifndef SIMULATOR
#if CONFIG_CODEC != SWCODEC
- seconds = mpeg_recorded_time() / HZ;
+ seconds = audio_recorded_time() / HZ;
#endif
#endif
if(update_screen || seconds > last_seconds)
@@ -609,8 +610,8 @@ bool radio_screen(void)
{
#if CONFIG_CODEC != SWCODEC
/* Enable the Left and right A/D Converter */
- mpeg_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
- sound_default(SOUND_RIGHT_GAIN), false);
+ audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
+ sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
mas_codec_writereg(6, 0x4000);
#endif
radio_set_status(FMRADIO_POWERED); /* leave it powered */
@@ -619,7 +620,7 @@ bool radio_screen(void)
{
radio_stop();
#if CONFIG_CODEC == SWCODEC
- pcmrec_set_mux(0); /* Line In */
+ pcm_rec_mux(0); /* Line In */
#endif
}
@@ -913,12 +914,13 @@ static bool fm_recording_settings(void)
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
1, /* Line In */
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
}
return ret;
}
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index b70e7b6..ebd9217 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -28,6 +28,13 @@
#include "led.h"
#include "mpeg.h"
#include "audio.h"
+#if CONFIG_CODEC == SWCODEC
+#include "pcm_record.h"
+#endif
+#ifdef HAVE_UDA1380
+#include "uda1380.h"
+#endif
+
#include "mp3_playback.h"
#include "mas.h"
#include "button.h"
@@ -79,9 +86,12 @@
#elif CONFIG_KEYPAD == IRIVER_H100_PAD
#define REC_STOPEXIT BUTTON_OFF
-#define REC_RECPAUSE BUTTON_ON
+#define REC_RECPAUSE BUTTON_REC
#define REC_INC BUTTON_RIGHT
#define REC_DEC BUTTON_LEFT
+#define REC_NEXT BUTTON_DOWN
+#define REC_PREV BUTTON_UP
+#define REC_SETTINGS BUTTON_MODE
#elif CONFIG_KEYPAD == GMINI100_PAD
#define REC_STOPEXIT BUTTON_OFF
@@ -102,6 +112,12 @@ bool f3_rec_screen(void);
#define MAX_SOURCE SOURCE_LINE
#endif
+#if CONFIG_CODEC == SWCODEC
+#define REC_FILE_ENDING ".wav"
+#else
+#define REC_FILE_ENDING ".mp3"
+#endif
+
#define MAX_FILE_SIZE 0x7FF00000 /* 2 GB - 1 MB */
const char* const freq_str[6] =
@@ -118,13 +134,18 @@ static void set_gain(void)
{
if(global_settings.rec_source == SOURCE_MIC)
{
- mpeg_set_recording_gain(global_settings.rec_mic_gain, 0, true);
+ audio_set_recording_gain(global_settings.rec_mic_gain, 0, AUDIO_GAIN_MIC);
}
else
{
- mpeg_set_recording_gain(global_settings.rec_left_gain,
- global_settings.rec_right_gain, false);
+ audio_set_recording_gain(global_settings.rec_left_gain,
+ global_settings.rec_right_gain, AUDIO_GAIN_LINEIN);
}
+#ifdef HAVE_UDA1380
+ audio_set_recording_gain(global_settings.rec_adc_left_gain,
+ global_settings.rec_adc_right_gain,
+ AUDIO_GAIN_ADC);
+#endif
}
static const char* const fmtstr[] =
@@ -176,9 +197,9 @@ char *rec_create_filename(char *buffer)
strncpy(buffer, rec_base_directory, MAX_PATH);
#ifdef HAVE_RTC
- create_datetime_filename(buffer, buffer, "R", ".mp3");
+ create_datetime_filename(buffer, buffer, "R", REC_FILE_ENDING);
#else
- create_numbered_filename(buffer, buffer, "rec_", ".mp3", 4);
+ create_numbered_filename(buffer, buffer, "rec_", REC_FILE_ENDING, 4);
#endif
return buffer;
}
@@ -227,7 +248,7 @@ static void trigger_listener(int trigger_status)
if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD)
{
talk_buffer_steal(); /* we use the mp3 buffer */
- mpeg_record(rec_create_filename(path_buffer));
+ audio_record(rec_create_filename(path_buffer));
/* give control to mpeg thread so that it can start recording */
yield(); yield(); yield();
@@ -236,7 +257,7 @@ static void trigger_listener(int trigger_status)
/* if we're already recording this is a retrigger */
else
{
- mpeg_new_file(rec_create_filename(path_buffer));
+ audio_new_file(rec_create_filename(path_buffer));
/* tell recording_screen to reset the time */
last_seconds = 0;
}
@@ -273,6 +294,7 @@ bool recording_screen(void)
char path_buffer[MAX_PATH];
bool been_in_usb_mode = false;
int last_audio_stat = -1;
+ int audio_stat;
#if CONFIG_LED == LED_REAL
bool led_state = false;
int led_countdown = 2;
@@ -289,7 +311,7 @@ bool recording_screen(void)
#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
ata_set_led_enabled(false);
#endif
- mpeg_init_recording();
+ audio_init_recording();
sound_set_volume(global_settings.volume);
@@ -298,15 +320,20 @@ bool recording_screen(void)
peak_meter_enabled = true;
+#if CONFIG_CODEC == SWCODEC
+ audio_stop();
+#endif
+
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
global_settings.rec_source,
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
set_gain();
@@ -321,7 +348,12 @@ bool recording_screen(void)
while(!done)
{
- int audio_stat = audio_status();
+#if CONFIG_CODEC == SWCODEC
+ audio_stat = pcm_rec_status();
+#else
+ audio_stat = audio_status();
+#endif
+
#if CONFIG_LED == LED_REAL
/*
@@ -390,7 +422,7 @@ bool recording_screen(void)
if(audio_stat & AUDIO_STATUS_RECORD)
{
- audio_stop();
+ audio_stop_recording();
}
else
{
@@ -416,7 +448,7 @@ bool recording_screen(void)
/* manual recording */
have_recorded = true;
talk_buffer_steal(); /* we use the mp3 buffer */
- mpeg_record(rec_create_filename(path_buffer));
+ audio_record(rec_create_filename(path_buffer));
last_seconds = 0;
if (global_settings.talk_menu)
{ /* no voice possible here, but a beep */
@@ -438,7 +470,7 @@ bool recording_screen(void)
{
if(audio_stat & AUDIO_STATUS_PAUSE)
{
- mpeg_resume_recording();
+ audio_resume_recording();
if (global_settings.talk_menu)
{ /* no voice possible here, but a beep */
audio_beep(HZ/4); /* short beep on resume */
@@ -446,7 +478,7 @@ bool recording_screen(void)
}
else
{
- mpeg_pause_recording();
+ audio_pause_recording();
}
}
update_countdown = 1; /* Update immediately */
@@ -535,7 +567,7 @@ bool recording_screen(void)
sound_min(SOUND_RIGHT_GAIN))
global_settings.rec_right_gain--;
break;
- }
+ }
set_gain();
update_countdown = 1; /* Update immediately */
break;
@@ -557,12 +589,13 @@ bool recording_screen(void)
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
global_settings.rec_source,
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
set_gain();
update_countdown = 1; /* Update immediately */
@@ -596,7 +629,7 @@ bool recording_screen(void)
case REC_F3:
if(audio_stat & AUDIO_STATUS_RECORD)
{
- mpeg_new_file(rec_create_filename(path_buffer));
+ audio_new_file(rec_create_filename(path_buffer));
last_seconds = 0;
}
else
@@ -638,8 +671,8 @@ bool recording_screen(void)
lcd_setfont(FONT_SYSFIXED);
- seconds = mpeg_recorded_time() / HZ;
-
+ seconds = audio_recorded_time() / HZ;
+
update_countdown--;
if(update_countdown == 0 || seconds > last_seconds)
{
@@ -660,7 +693,7 @@ bool recording_screen(void)
lcd_puts(0, 0, buf);
dseconds = rec_timesplit_seconds();
- num_recorded_bytes = mpeg_num_recorded_bytes();
+ num_recorded_bytes = audio_num_recorded_bytes();
if(audio_stat & AUDIO_STATUS_PRERECORD)
{
@@ -699,7 +732,7 @@ bool recording_screen(void)
((global_settings.rec_timesplit && (seconds >= dseconds))
|| (num_recorded_bytes >= MAX_FILE_SIZE)))
{
- mpeg_new_file(rec_create_filename(path_buffer));
+ audio_new_file(rec_create_filename(path_buffer));
update_countdown = 1;
last_seconds = 0;
}
@@ -784,7 +817,13 @@ bool recording_screen(void)
}
}
- if(audio_status() & AUDIO_STATUS_ERROR)
+
+#if CONFIG_CODEC == SWCODEC
+ audio_stat = pcm_rec_status();
+#else
+ audio_stat = audio_status();
+#endif
+ if (audio_stat & AUDIO_STATUS_ERROR)
{
splash(0, true, str(LANG_DISK_FULL));
status_draw(true);
@@ -799,7 +838,12 @@ bool recording_screen(void)
}
}
+#if CONFIG_CODEC == SWCODEC
+ audio_stop_recording();
+ audio_close_recording();
+#else
audio_init_playback();
+#endif
/* make sure the trigger is really turned off */
peak_meter_trigger(false);
@@ -924,12 +968,13 @@ bool f2_rec_screen(void)
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
global_settings.rec_source,
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
set_gain();
@@ -1018,12 +1063,14 @@ bool f3_rec_screen(void)
if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */
- mpeg_set_recording_options(global_settings.rec_frequency,
+ audio_set_recording_options(global_settings.rec_frequency,
global_settings.rec_quality,
global_settings.rec_source,
global_settings.rec_channels,
global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ global_settings.rec_prerecord_time,
+ global_settings.rec_monitor);
+
set_gain();
@@ -1034,4 +1081,13 @@ bool f3_rec_screen(void)
}
#endif /* #ifdef REC_F3 */
+#if CONFIG_CODEC == SWCODEC
+void audio_beep(int duration)
+{
+ /* dummy */
+ (void)duration;
+}
+#endif
+
+
#endif /* HAVE_RECORDING */
diff --git a/apps/settings.c b/apps/settings.c
index b573d72..d44fec1 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -85,7 +85,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "dsp.h"
#endif
-#define CONFIG_BLOCK_VERSION 29
+#define CONFIG_BLOCK_VERSION 30
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@@ -407,6 +407,7 @@ static const struct bit_entry hd_bits[] =
#ifdef HAVE_RECORDING
{1, S_O(rec_startup), false, "rec screen on startup", off_on },
+ {1, S_O(rec_monitor), true, "monitor recording", off_on },
/* values for the trigger */
{8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
@@ -450,6 +451,26 @@ static const struct bit_entry hd_bits[] =
{22, S_O(dircache_size), 0, NULL, NULL },
#endif
+#if defined(HAVE_UDA1380)
+ /* recording settings for iriver */
+ {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */
+ "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" },
+ {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" },
+ {4, S_O(rec_mic_gain), 4, "rec mic gain", NULL },
+ {1, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line" },
+ {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
+ "rec frequency", "44,48,32,22,24,16" },
+ {4, S_O(rec_left_gain), 2, /* 0dB */
+ "rec left gain", NULL }, /* 0...15 */
+ {4, S_O(rec_right_gain), 2, /* 0dB */
+ "rec right gain", NULL }, /* 0...15 */
+ {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */
+ {1, S_O(rec_directory), 0, /* rec_base_directory */
+ "rec directory", REC_BASE_DIR ",current" },
+ {8|SIGNED, S_O(rec_adc_left_gain), 0, /* 0dB */ "adc left gain", NULL }, /* -128...48 */
+ {8|SIGNED, S_O(rec_adc_right_gain), 0, /* 0dB */ "adc right gain", NULL }, /* -128...48 */
+#endif
+
/* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */
diff --git a/apps/settings.h b/apps/settings.h
index 63349c6..18c566b 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -176,7 +176,12 @@ struct user_settings
int rec_mic_gain; /* 0-15 */
int rec_left_gain; /* 0-15 */
int rec_right_gain; /* 0-15 */
+#ifdef HAVE_UDA1380
+ int rec_adc_left_gain; /* -128 .. 48 */
+ int rec_adc_right_gain; /* -128 .. 48 */
+#endif
bool rec_editable; /* true means that the bit reservoir is off */
+ bool rec_monitor; /* true means that one can listen to what is being recorded */
/* note: timesplit setting is not saved */
int rec_timesplit; /* 0 = off,
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 7663724..c429920 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -228,6 +228,28 @@ static bool receditable(void)
&global_settings.rec_editable);
}
+static bool recmonitor(void)
+{
+ return set_bool(str(LANG_RECORDING_MONITOR),
+ &global_settings.rec_monitor);
+}
+
+#ifdef HAVE_UDA1380
+static bool recadcleft(void)
+{
+ return set_sound(str(LANG_RECORDING_ADC_LEFT),
+ &global_settings.rec_adc_left_gain,
+ SOUND_ADC_LEFT_GAIN);
+}
+
+static bool recadcright(void)
+{
+ return set_sound(str(LANG_RECORDING_ADC_RIGHT),
+ &global_settings.rec_adc_right_gain,
+ SOUND_ADC_RIGHT_GAIN);
+}
+#endif
+
static bool rectimesplit(void)
{
static const struct opt_items names[] = {
@@ -740,7 +762,7 @@ bool recording_menu(bool no_source)
{
int m;
int i = 0;
- struct menu_item items[10];
+ struct menu_item items[13];
bool result;
items[i].desc = ID2P(LANG_RECORDING_QUALITY);
@@ -753,6 +775,16 @@ bool recording_menu(bool no_source)
}
items[i].desc = ID2P(LANG_RECORDING_CHANNELS);
items[i++].function = recchannels;
+
+#ifdef HAVE_UDA1380
+ items[i].desc = ID2P(LANG_RECORDING_ADC_LEFT);
+ items[i++].function = recadcleft;
+ items[i].desc = ID2P(LANG_RECORDING_ADC_RIGHT);
+ items[i++].function = recadcright;
+#endif
+
+ items[i].desc = ID2P(LANG_RECORDING_MONITOR);
+ items[i++].function = recmonitor;
items[i].desc = ID2P(LANG_RECORDING_EDITABLE);
items[i++].function = receditable;
items[i].desc = ID2P(LANG_RECORD_TIMESPLIT);
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c
index e89f9bb..6a5bd07 100644
--- a/firmware/drivers/uda1380.c
+++ b/firmware/drivers/uda1380.c
@@ -28,6 +28,7 @@
#include "string.h"
#include "file.h"
#include "buffer.h"
+#include "audio.h"
#include "i2c-coldfire.h"
#include "uda1380.h"
@@ -204,7 +205,7 @@ void uda1380_close(void)
* sound samples over the I2S bus, which is connected
* to the processor's IIS1 interface.
*
- * source_mic: true=record from microphone, false=record from line-in
+ * source_mic: true=record from microphone, false=record from line-in (or radio)
*/
void uda1380_enable_recording(bool source_mic)
{
@@ -246,17 +247,29 @@ void uda1380_disable_recording(void)
/**
* Set recording gain and volume
*
- * mic_gain : range 0 .. 15 -> 0 .. 30 dB gain
- * linein_gain : range 0 .. 15 -> 0 .. 24 dB gain
- *
- * adc_volume : range -127 .. 48 -> -63 .. 24 dB gain
- * note that 0 -> 0 dB gain..
+ * type: params: ranges:
+ * AUDIO_GAIN_MIC left 0 .. 15 -> 0 .. 30 dB gain
+ * AUDIO_GAIN_LINEIN left & right 0 .. 8 -> 0 .. 24 dB gain
+ * AUDIO_GAIN_ADC left & right -128 .. 48 -> -64 .. 24 dB gain
+ *
+ * Note: For all types the value 0 gives 0 dB gain.
*/
-void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume)
+void uda1380_set_recvol(int left, int right, int type)
{
- uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(adc_volume) | DEC_VOLR(adc_volume));
- uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(linein_gain) | PGA_GAINR(linein_gain));
- uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & ~VGA_GAIN_MASK) | VGA_GAIN(mic_gain));
+ switch (type)
+ {
+ case AUDIO_GAIN_MIC:
+ uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & ~VGA_GAIN_MASK) | VGA_GAIN(left));
+ break;
+
+ case AUDIO_GAIN_LINEIN:
+ uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(left) | PGA_GAINR(right));
+ break;
+
+ case AUDIO_GAIN_ADC:
+ uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) | DEC_VOLR(right));
+ break;
+ }
}
diff --git a/firmware/export/audio.h b/firmware/export/audio.h
index 67ed052..ab6f41c 100644
--- a/firmware/export/audio.h
+++ b/firmware/export/audio.h
@@ -33,6 +33,11 @@
#define AUDIOERR_DISK_FULL 1
+#define AUDIO_GAIN_LINEIN 0
+#define AUDIO_GAIN_MIC 1
+#define AUDIO_GAIN_ADC 2 /* for UDA1380 */
+
+
struct audio_debug
{
int audiobuflen;
@@ -79,6 +84,24 @@ int audio_get_file_pos(void);
void audio_beep(int duration);
void audio_init_playback(void);
+/* audio recording functions */
+void audio_init_recording(void);
+void audio_close_recording(void);
+void audio_record(const char *filename);
+void audio_stop_recording(void);
+void audio_pause_recording(void);
+void audio_resume_recording(void);
+void audio_new_file(const char *filename);
+void audio_set_recording_options(int frequency, int quality,
+ int source, int channel_mode,
+ bool editable, int prerecord_time,
+ bool monitor);
+void audio_set_recording_gain(int left, int right, int type);
+unsigned long audio_recorded_time(void);
+unsigned long audio_num_recorded_bytes(void);
+
+
+
/***********************************************************************/
/* audio event handling */
diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h
index 72bc770..653dbc0 100644
--- a/firmware/export/config-h120.h
+++ b/firmware/export/config-h120.h
@@ -7,7 +7,7 @@
#define MODEL_NUMBER 0
/* define this if you have recording possibility */
-/*#define HAVE_RECORDING 1*/
+#define HAVE_RECORDING 1
/* define this if you have a bitmap LCD display */
#define HAVE_LCD_BITMAP 1
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h
index a7c9cac..d62ac14 100644
--- a/firmware/export/mpeg.h
+++ b/firmware/export/mpeg.h
@@ -44,20 +44,11 @@
#define MPEG_RESERVED_HEADER_SPACE (4096 + 576)
#if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR)
-void mpeg_init_recording(void);
-void mpeg_record(const char *filename);
-void mpeg_new_file(const char *filename);
-void mpeg_set_recording_options(int frequency, int quality,
- int source, int channel_mode,
- bool editable, int prerecord_time);
-void mpeg_set_recording_gain(int left, int right, bool use_mic);
+
#if CONFIG_TUNER & S1A0903X01
int mpeg_get_mas_pllfreq(void);
#endif
-unsigned long mpeg_recorded_time(void);
-unsigned long mpeg_num_recorded_bytes(void);
-void mpeg_pause_recording(void);
-void mpeg_resume_recording(void);
+
#endif
unsigned long mpeg_get_last_header(void);
diff --git a/firmware/export/pcm_record.h b/firmware/export/pcm_record.h
index af73108..304a67f 100644
--- a/firmware/export/pcm_record.h
+++ b/firmware/export/pcm_record.h
@@ -17,37 +17,13 @@
*
****************************************************************************/
-/*
- * Function names are taken from apps/recorder/recording.c to
- * make the integration later easier..
- *
- */
-
#ifndef PCM_RECORD_H
#define PCM_RECORD_H
-unsigned long pcm_status(void);
-
-void pcm_init_recording(void);
-
-void pcm_open_recording(void);
-void pcm_close_recording(void);
-
-
-void pcm_set_recording_options(int source, bool enable_waveform);
-void pcm_set_recording_gain(int gain, int volume);
-
-void pcm_record(const char *filename);
-void pcm_stop_recording(void);
-
-//void pcm_new_file(const char *filename);
-
-
-unsigned long pcm_recorded_time(void);
-unsigned long pcm_num_recorded_bytes(void);
-void pcm_pause_recording(void);
-void pcm_resume_recording(void);
+unsigned long pcm_rec_status(void);
+void pcm_rec_init(void);
+void pcm_rec_mux(int source);
-void pcmrec_set_mux(int source);
+/* audio.h contains audio recording functions */
#endif
diff --git a/firmware/export/sound.h b/firmware/export/sound.h
index 9907462..2c00206 100644
--- a/firmware/export/sound.h
+++ b/firmware/export/sound.h
@@ -36,11 +36,15 @@ enum {
SOUND_MDB_ENABLE,
SOUND_SUPERBASS,
#endif
-#if CONFIG_CODEC == MAS3587F
+#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380)
SOUND_LEFT_GAIN,
SOUND_RIGHT_GAIN,
SOUND_MIC_GAIN,
#endif
+#if defined(HAVE_UDA1380)
+ SOUND_ADC_LEFT_GAIN,
+ SOUND_ADC_RIGHT_GAIN,
+#endif
};
enum {
diff --git a/firmware/export/uda1380.h b/firmware/export/uda1380.h
index 3bef543..90a6d44 100644
--- a/firmware/export/uda1380.h
+++ b/firmware/export/uda1380.h
@@ -32,7 +32,7 @@ extern void uda1380_set_nsorder(int order);
extern void uda1380_enable_recording(bool source_mic);
extern void uda1380_disable_recording(void);
-extern void uda1380_set_recvol(int mic_gain, int linein_gain, int adc_volume);
+extern void uda1380_set_recvol(int left, int right, int type);
extern void uda1380_set_monitor(int enable);
#define UDA1380_ADDR 0x30
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 022a321..caeb3b9 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2115,7 +2115,7 @@ void audio_init_playback(void)
/****************************************************************************
* Recording functions
***************************************************************************/
-void mpeg_init_recording(void)
+void audio_init_recording(void)
{
init_recording_done = false;
queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
@@ -2224,7 +2224,7 @@ static void init_recording(void)
call mpeg_set_recording_options(). */
}
-void mpeg_record(const char *filename)
+void audio_record(const char *filename)
{
mpeg_errno = 0;
@@ -2234,12 +2234,12 @@ void mpeg_record(const char *filename)
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
}
-void mpeg_pause_recording(void)
+void audio_pause_recording(void)
{
queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, NULL);
}
-void mpeg_resume_recording(void)
+void audio_resume_recording(void)
{
queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL);
}
@@ -2435,9 +2435,10 @@ static void stop_recording(void)
resume_recording();
}
-void mpeg_set_recording_options(int frequency, int quality,
+void audio_set_recording_options(int frequency, int quality,
int source, int channel_mode,
- bool editable, int prerecord_time)
+ bool editable, int prerecord_time,
+ bool monitor)
{
bool is_mpeg1;
@@ -2461,7 +2462,7 @@ void mpeg_set_recording_options(int frequency, int quality,
DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute);
- shadow_io_control_main = ((1 << 10) | /* Monitoring ON */
+ shadow_io_control_main = ((monitor?(1 << 10):0) | /* Monitoring ON */
((source < 2)?1:2) << 8) | /* Input select */
(1 << 5) | /* SDO strobe invert */
((is_mpeg1?0:1) << 3) |
@@ -2497,13 +2498,13 @@ void mpeg_set_recording_options(int frequency, int quality,
}
/* If use_mic is true, the left gain is used */
-void mpeg_set_recording_gain(int left, int right, bool use_mic)
+void audio_set_recording_gain(int left, int right, int type)
{
/* Enable both left and right A/D */
shadow_codec_reg0 = (left << 12) |
(right << 8) |
(left << 4) |
- (use_mic?0x0008:0) | /* Connect left A/D to mic */
+ (type==AUDIO_GAIN_MIC?0x0008:0) | /* Connect left A/D to mic */
0x0007;
mas_codec_writereg(0x0, shadow_codec_reg0);
}
@@ -2539,7 +2540,7 @@ void audio_beep(int duration)
while (current_tick - starttick < duration);
}
-void mpeg_new_file(const char *filename)
+void audio_new_file(const char *filename)
{
mpeg_errno = 0;
@@ -2549,7 +2550,7 @@ void mpeg_new_file(const char *filename)
queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL);
}
-unsigned long mpeg_recorded_time(void)
+unsigned long audio_recorded_time(void)
{
if(is_prerecording)
return prerecord_count * HZ;
@@ -2565,7 +2566,7 @@ unsigned long mpeg_recorded_time(void)
return 0;
}
-unsigned long mpeg_num_recorded_bytes(void)
+unsigned long audio_num_recorded_bytes(void)
{
int num_bytes;
int index;
@@ -2599,7 +2600,7 @@ void audio_init_playback(void)
{
/* a dummy */
}
-unsigned long mpeg_recorded_time(void)
+unsigned long audio_recorded_time(void)
{
/* a dummy */
return 0;
@@ -2609,42 +2610,42 @@ void audio_beep(int duration)
/* a dummy */
(void)duration;
}
-void mpeg_pause_recording(void)
+void audio_pause_recording(void)
{
/* a dummy */
}
-void mpeg_resume_recording(void)
+void audio_resume_recording(void)
{
/* a dummy */
}
-unsigned long mpeg_num_recorded_bytes(void)
+unsigned long audio_num_recorded_bytes(void)
{
/* a dummy */
return 0;
}
-void mpeg_record(const char *filename)
+void audio_record(const char *filename)
{
/* a dummy */
(void)filename;
}
-void mpeg_new_file(const char *filename)
+void audio_new_file(const char *filename)
{
/* a dummy */
(void)filename;
}
-void mpeg_set_recording_gain(int left, int right, bool use_mic)
+void audio_set_recording_gain(int left, int right, int type)
{
/* a dummy */
(void)left;
(void)right;
- (void)use_mic;
+ (void)type;
}
-void mpeg_init_recording(void)
+void audio_init_recording(void)
{
/* a dummy */
}
-void mpeg_set_recording_options(int frequency, int quality,
+void audio_set_recording_options(int frequency, int quality,
int source, int channel_mode,
bool editable, int prerecord_time)
{
@@ -2710,6 +2711,12 @@ void audio_stop(void)
#endif /* SIMULATOR */
}
+/* dummy */
+void audio_stop_recording(void)
+{
+ audio_stop();
+}
+
void audio_pause(void)
{
#ifndef SIMULATOR
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 8b46a09..b167d6a 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -30,11 +30,7 @@
#include "cpu.h"
#include "i2c.h"
-#if defined(HAVE_UDA1380)
#include "uda1380.h"
-#elif defined(HAVE_TLV320)
-#include "tlv320.h"
-#endif
#include "system.h"
#include "usb.h"
@@ -56,47 +52,56 @@
static volatile bool is_recording; /* We are recording */
static volatile bool is_stopping; /* Are we going to stop */
static volatile bool is_paused; /* We have paused */
+static volatile bool is_error; /* An error has occured */
-static volatile int num_rec_bytes;
+static volatile unsigned long num_rec_bytes; /* Num bytes recorded */
+static volatile unsigned long num_file_bytes; /* Num bytes written to current file */
static volatile int int_count; /* Number of DMA completed interrupts */
static volatile int error_count; /* Number of DMA errors */
static unsigned long record_start_time; /* Value of current_tick when recording was started */
static unsigned long pause_start_time; /* Value of current_tick when pause was started */
-static int rec_gain, rec_volume;
static bool show_waveform;
-static int init_done = 0;
+
static int wav_file;
static char recording_filename[MAX_PATH];
+static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done;
+
/***************************************************************************/
/*
- Some estimates:
- 44100 HZ * 4 = 176400 bytes/s
- Refresh LCD 10 HZ = 176400 / 10 = 17640 bytes ~=~ 1024*16 bytes
+ Some estimates:
+ Normal recording rate: 44100 HZ * 4 = 176 KB/s
+ Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk
+ CHUNK_SIZE: 65536
+ Chunks/s: 176 KB / 65536 = ~3 chunks / s
+
+ WRITE_THRESHOLD: 30
+ - Should gives us < 10s to start writing to disk before we run out
+ of buffer space..
- If NUM_BUFFERS is 80 we can hold ~8 sec of data in memory
- ALL_BUFFER_SIZE will be 1024*16 * 80 = 1310720 bytes
*/
-#define NUM_BUFFERS 80
-#define EACH_BUFFER_SIZE (1024*16) /* Multiple of 4. Use small value to get responsive waveform */
-#define ALL_BUFFERS_SIZE (NUM_BUFFERS * EACH_BUFFER_SIZE)
+#define CHUNK_SIZE 65536 /* Multiple of 4 */
+#define WRITE_THRESHOLD 30 /* Write when this many chunks (or less) until buffer full */
+
+#define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)])
-#define WRITE_THRESHOLD 40 /* Minimum number of buffers before write to file */
+static unsigned char *rec_buffer; /* Circular recording buffer */
+static int num_chunks; /* Number of chunks available in rec_buffer */
-static unsigned char *rec_buffers[NUM_BUFFERS];
/*
- Overrun occures when DMA needs to write a new buffer and write_index == read_index
- Solution to this is to optimize pcmrec_callback, use cpu_boost somewhere or increase
- the total buffer size (or WRITE_THRESHOLD)
+ Overrun occures when DMA needs to write a new chunk and write_index == read_index
+ Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk
+ more often.
*/
-static int write_index; /* Which buffer the DMA is currently recording */
-static int read_index; /* The oldest buffer that the pcmrec_callback has not read */
+static volatile int write_index; /* Current chunk the DMA is writing to */
+static volatile int read_index; /* Oldest chunk that is not written to disk */
+static volatile int read2_index; /* Latest chunk that has not been converted to little endian */
/***************************************************************************/
@@ -105,10 +110,13 @@ static long pcmrec_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(lon
static const char pcmrec_thread_name[] = "pcmrec";
static void pcmrec_thread(void);
+static void pcmrec_dma_start(void);
+static void pcmrec_dma_stop(void);
/* Event IDs */
-#define PCMREC_OPEN 1 /* Enable recording */
-#define PCMREC_CLOSE 2 /* Disable recording */
+#define PCMREC_INIT 1 /* Enable recording */
+#define PCMREC_CLOSE 2
+
#define PCMREC_START 3 /* Start a new recording */
#define PCMREC_STOP 4 /* Stop the current recording */
#define PCMREC_PAUSE 10
@@ -122,71 +130,58 @@ static void pcmrec_thread(void);
/* Functions that are not executing in the pcmrec_thread first */
/*******************************************************************/
-void pcm_init_recording(void)
+/* Creates pcmrec_thread */
+void pcm_rec_init(void)
{
- int_count = 0;
- error_count = 0;
-
- show_waveform = 0;
- is_recording = 0;
- is_stopping = 0;
- num_rec_bytes = 0;
- wav_file = -1;
- read_index = 0;
- write_index = 0;
-
queue_init(&pcmrec_queue);
create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), pcmrec_thread_name);
}
-void pcm_open_recording(void)
-{
- init_done = 0;
-
- logf("pcm_open_rec");
-
- queue_post(&pcmrec_queue, PCMREC_OPEN, 0);
- while (init_done)
- {
- sleep(HZ >> 8);
- }
-
- logf("pcm_open_rec done");
+/* Initializes recording:
+ * - Set up the UDA1380 for recording
+ * - Prepare for DMA transfers
+ */
+
+void audio_init_recording(void)
+{
+ init_done = false;
+ queue_post(&pcmrec_queue, PCMREC_INIT, 0);
+
+ while(!init_done)
+ sleep_thread();
+ wake_up_thread();
}
-void pcm_close_recording(void)
+void audio_close_recording(void)
{
- /* todo: synchronize completion with pcmrec thread */
+ close_done = false;
queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
+
+ while(!close_done)
+ sleep_thread();
+ wake_up_thread();
}
-
-
-unsigned long pcm_status(void)
+unsigned long pcm_rec_status(void)
{
unsigned long ret = 0;
if (is_recording)
ret |= AUDIO_STATUS_RECORD;
+ if (is_paused)
+ ret |= AUDIO_STATUS_PAUSE;
+ if (is_error)
+ ret |= AUDIO_STATUS_ERROR;
return ret;
}
-
-
-void pcm_new_file(const char *filename)
-{
- /* todo */
- filename = filename;
-
-}
-
-unsigned long pcm_recorded_time(void)
+unsigned long audio_recorded_time(void)
{
if (is_recording)
{
- if(is_paused)
+ if (is_paused)
return pause_start_time - record_start_time;
else
return current_tick - record_start_time;
@@ -195,92 +190,168 @@ unsigned long pcm_recorded_time(void)
return 0;
}
-unsigned long pcm_num_recorded_bytes(void)
+unsigned long audio_num_recorded_bytes(void)
{
-
if (is_recording)
- {
return num_rec_bytes;
- }
- else
- return 0;
-}
-
-void pcm_pause_recording(void)
-{
- /* todo */
-}
-void pcm_resume_recording(void)
-{
- /* todo */
+ return 0;
}
/**
* Sets the audio source
*
- * Side effect: This functions starts feeding the CPU with audio data over the I2S bus
+ * This functions starts feeding the CPU with audio data over the I2S bus
*
- * @param source 0=line-in, 1=mic
+ * @param source 0=mic, 1=line-in, (todo: 2=spdif)
*/
-void pcm_set_recording_options(int source, bool enable_waveform)
+void audio_set_recording_options(int frequency, int quality,
+ int source, int channel_mode,
+ bool editable, int prerecord_time,
+ bool monitor)
{
-#if defined(HAVE_UDA1380)
- uda1380_enable_recording(source);
-#elif defined(HAVE_TLV320)
- tlv320_enable_recording(source);
-#endif
- show_waveform = enable_waveform;
+ /* TODO: */
+ (void)frequency;
+ (void)quality;
+ (void)channel_mode;
+ (void)editable;
+ (void)prerecord_time;
+
+ //logf("pcmrec: src=%d", source);
+
+ switch (source)
+ {
+ /* mic */
+ case 0:
+ uda1380_enable_recording(true);
+ break;
+
+ /* line-in */
+ case 1:
+ uda1380_enable_recording(false);
+ break;
+ }
+
+ uda1380_set_monitor(monitor);
}
/**
+ * Note that microphone is mono, only left value is used
+ * See uda1380_set_recvol() for exact ranges.
*
- * @param gain line-in and microphone gain (0-15)
- * @param volume ADC volume (0-255)
+ * @param type 0=line-in (radio), 1=mic, 2=ADC
+ *
*/
-void pcm_set_recording_gain(int gain, int volume)
+void audio_set_recording_gain(int left, int right, int type)
{
- rec_gain = gain;
- rec_volume = volume;
-
- queue_post(&pcmrec_queue, PCMREC_SET_GAIN, 0);
+ //logf("rcmrec: t=%d l=%d r=%d", type, left, right);
+ uda1380_set_recvol(left, right, type);
}
+
/**
* Start recording
*
- * Use pcm_set_recording_options before calling record
+ * Use audio_set_recording_options first to select recording options
*/
-void pcm_record(const char *filename)
+void audio_record(const char *filename)
{
+ if (is_recording)
+ {
+ logf("record while recording");
+ return;
+ }
+
strncpy(recording_filename, filename, MAX_PATH - 1);
recording_filename[MAX_PATH - 1] = 0;
+ record_done = false;
queue_post(&pcmrec_queue, PCMREC_START, 0);
+
+ while(!record_done)
+ sleep_thread();
+ wake_up_thread();
+}
+
+
+void audio_new_file(const char *filename)
+{
+ logf("pcm_new_file");
+
+ new_file_done = false;
+
+ strncpy(recording_filename, filename, MAX_PATH - 1);
+ recording_filename[MAX_PATH - 1] = 0;
+
+ queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
+
+ while(!new_file_done)
+ sleep_thread();
+ wake_up_thread();
+
+ logf("pcm_new_file done");
}
/**
*
*/
-void pcm_stop_recording(void)
+void audio_stop_recording(void)
{
- if (is_recording)
- is_stopping = 1;
+ if (!is_recording)
+ return;
+ logf("pcm_stop");
+
+ stop_done = false;
queue_post(&pcmrec_queue, PCMREC_STOP, 0);
- logf("pcm_stop_recording");
+ while(!stop_done)
+ sleep_thread();
+ wake_up_thread();
+
+ logf("pcm_stop done");
+}
- while (is_stopping)
+void audio_pause_recording(void)
+{
+ if (!is_recording)
+ {
+ logf("pause when not recording");
+ return;
+ }
+ if (is_paused)
{
- sleep(HZ >> 4);
+ logf("pause when paused");
+ return;
}
+
+ pause_done = false;
+ queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
- logf("pcm_stop_recording done");
+ while(!pause_done)
+ sleep_thread();
+ wake_up_thread();
}
+void audio_resume_recording(void)
+{
+ if (!is_paused)
+ {
+ logf("resume when not paused");
+ return;
+ }
+
+ resume_done = false;
+ queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
+
+ while(!resume_done)
+ sleep_thread();
+ wake_up_thread();
+}
+
+
/***************************************************************************/
/* Functions that executes in the context of pcmrec_thread */
@@ -288,100 +359,116 @@ void pcm_stop_recording(void)
/**
- * Process the buffers using read_index and write_index.
+ * Process the chunks using read_index and write_index.
*
- * DMA1 handler posts to pcmrec_queue so that pcmrec_thread calls this
- * function. Also pcmrec_stop will call this function when the recording
- * is stopping, and that call will have flush = true.
+ * DMA1 handler posts to pcmrec_queue and pcmrec_thread calls this
+ * function.
+ *
+ * Other function can also call this function with flush = true when
+ * they want to save everything recorded sofar to disk.
*
*/
-void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
-void pcmrec_callback(bool flush)
+static void pcmrec_callback(bool flush) __attribute__ ((section (".icode")));
+static void pcmrec_callback(bool flush)
{
- int num_ready;
+ int num_ready, num_free, num_new;
+ unsigned short *ptr;
+ int i, j, w;
+
+ w = write_index;
+
+ num_new = w - read2_index;
+ if (num_new < 0)
+ num_new += num_chunks;
+
+ for (i=0; i<num_new; i++)
+ {
+ /* Convert the samples to little-endian so we only have to write later
+ (Less hd-spinning time)
+ */
+ ptr = GET_CHUNK(read2_index);
+ for (j=0; j<CHUNK_SIZE/2; j++)
+ {
+ /* TODO: might be a good place to add the peak-meter.. */
+
+ *ptr = htole16(*ptr);
+ ptr++;
+ }
+
+ num_rec_bytes += CHUNK_SIZE;
+
+ read2_index++;
+ if (read2_index >= num_chunks)
+ read2_index = 0;
+ }
- num_ready = write_index - read_index;
+ num_ready = w - read_index;
if (num_ready < 0)
- num_ready += NUM_BUFFERS;
-
- /* we can consume up to num_ready buffers */
+ num_ready += num_chunks;
-#ifdef HAVE_REMOTE_LCD
- /* Draw waveform on remote LCD */
- if (show_waveform && num_ready>0)
+ if (num_ready >= num_chunks)
{
- short *buf;
- long x,y,offset;
- int show_index;
-
- /* Just display the last buffer (most recent one) */
- show_index = read_index + num_ready - 1;
- buf = (short*)rec_buffers[show_index];
-
- lcd_remote_clear_display();
-
- offset = 0;
- for (x=0; x<LCD_REMOTE_WIDTH-1; x++)
- {
- y = buf[offset] * (LCD_REMOTE_HEIGHT / 2) *5; /* The 5 is just 'zooming' */
- y = y >> 15; /* Divide with SHRT_MAX */
- y += LCD_REMOTE_HEIGHT/2;
+ logf("num_ready overflow?");
+ num_ready = num_chunks-1;
+ }
- if (y < 2) y=2;
- if (y >= LCD_REMOTE_HEIGHT-2) y = LCD_REMOTE_HEIGHT-2;
+ num_free = num_chunks - num_ready;
- lcd_remote_drawpixel(x,y);
+ if (wav_file == -1 || (!is_recording && !flush))
+ {
+ /* In this case we should consume the buffers to avoid */
+ /* getting 'dma1 overrun' */
- offset += (EACH_BUFFER_SIZE/2) / LCD_REMOTE_WIDTH;
- }
+ read_index+=num_ready;
+ if (read_index >= num_chunks)
+ read_index -= num_chunks;
- lcd_remote_update();
+ return;
}
-#endif
-
- /* Note: This might be a good place to call the 'codec' later */
-
- /* Check that we have the minimum amount of data to save or */
- /* that if it's closing time which mean we have to save.. */
- if (wav_file != -1)
+ if (num_free <= WRITE_THRESHOLD || flush)
{
- if (num_ready >= WRITE_THRESHOLD || flush)
+ logf("writing: %d (%d)", num_ready, flush);
+
+ for (i=0; i<num_ready; i++)
{
- unsigned short *ptr = (unsigned short*)rec_buffers[read_index];
- int i;
-
- for (i=0; i<EACH_BUFFER_SIZE * num_ready / 2; i++)
+ if (write(wav_file, GET_CHUNK(read_index), CHUNK_SIZE) != CHUNK_SIZE)
{
- *ptr = htole16(*ptr);
- ptr++;
+ logf("pcmrec: write err");
+ pcmrec_dma_stop();
+ return;
}
-
- write(wav_file, rec_buffers[read_index], EACH_BUFFER_SIZE * num_ready);
-
- read_index+=num_ready;
- if (read_index >= NUM_BUFFERS)
- read_index -= NUM_BUFFERS;
+
+ num_file_bytes += CHUNK_SIZE;
+
+ read_index++;
+ if (read_index >= num_chunks)
+ read_index = 0;
}
-
- } else
- {
- /* In this case we must consume the buffers otherwise we will */
- /* get 'dma1 overrun' pretty fast */
-
- read_index+=num_ready;
- if (read_index >= NUM_BUFFERS)
- read_index -= NUM_BUFFERS;
+
+ logf("done");
}
}
+/* Abort dma transfer */
+static void pcmrec_dma_stop(void)
+{
+ DCR1 = 0;
+
+ is_error = true;
+ is_recording = false;
+
+ error_count++;
+
+ logf("dma1 stopped");
+}
-void pcmrec_dma_start(void)
+static void pcmrec_dma_start(void)
{
- DAR1 = (unsigned long)rec_buffers[write_index++]; /* Destination address */
- SAR1 = (unsigned long)&PDIR2; /* Source address */
- BCR1 = EACH_BUFFER_SIZE; /* Bytes to transfer */
+ DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
+ SAR1 = (unsigned long)&PDIR2; /* Source address */
+ BCR1 = CHUNK_SIZE; /* Bytes to transfer */
/* Start the DMA transfer.. */
DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START;
@@ -404,36 +491,37 @@ void DMA1(void)
{
DCR1 = 0; /* Stop DMA transfer */
error_count++;
- is_recording = 0;
+ is_recording = false;
logf("dma1 err 0x%x", res);
+
+ /* Flush recorded data to disk and stop recording */
+ queue_post(&pcmrec_queue, PCMREC_STOP, NULL);
} else
{
- num_rec_bytes += EACH_BUFFER_SIZE;
-
write_index++;
- if (write_index >= NUM_BUFFERS)
+ if (write_index >= num_chunks)
write_index = 0;
if (is_stopping || !is_recording)
{
DCR1 = 0; /* Stop DMA transfer */
- is_recording = 0;
+ is_stopping = false;
logf("dma1 stopping");
} else if (write_index == read_index)
{
DCR1 = 0; /* Stop DMA transfer */
- is_recording = 0;
+ is_recording = false;
logf("dma1 overrun");
} else
{
- DAR1 = (unsigned long)rec_buffers[write_index]; /* Destination address */
- BCR1 = EACH_BUFFER_SIZE;
+ DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
+ BCR1 = CHUNK_SIZE;
queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL);
@@ -443,6 +531,8 @@ void DMA1(void)
IPR |= (1<<15); /* Clear pending interrupt request */
}
+/* Create WAVE file and write header */
+/* Sets returns 0 if success, -1 on failure */
static int start_wave(void)
{
unsigned char header[44] =
@@ -456,7 +546,8 @@ static int start_wave(void)
if (wav_file < 0)
{
wav_file = -1;
- logf("create failed: %d", wav_file);
+ logf("rec: create failed: %d", wav_file);
+ is_error = true;
return -1;
}
@@ -464,8 +555,9 @@ static int start_wave(void)
{
close(wav_file);
wav_file = -1;
- logf("write failed");
- return -2;
+ logf("rec: write failed");
+ is_error = true;
+ return -1;
}
return 0;
@@ -476,16 +568,19 @@ static void close_wave(void)
{
long l;
- l = htole32(num_rec_bytes + 36);
- lseek(wav_file, 4, SEEK_SET);
- write(wav_file, &l, 4);
-
- l = htole32(num_rec_bytes);
- lseek(wav_file, 40, SEEK_SET);
- write(wav_file, &l, 4);
-
- close(wav_file);
- wav_file = -1;
+ if (wav_file != -1)
+ {
+ l = htole32(num_file_bytes + 36);
+ lseek(wav_file, 4, SEEK_SET);
+ write(wav_file, &l, 4);
+
+ l = htole32(num_file_bytes);
+ lseek(wav_file, 40, SEEK_SET);
+ write(wav_file, &l, 4);
+
+ close(wav_file);
+ wav_file = -1;
+ }
}
static void pcmrec_start(void)
@@ -493,74 +588,206 @@ static void pcmrec_start(void)
logf("pcmrec_start");
if (is_recording)
+ {
+ logf("already recording");
+ record_done = true;
return;
-
+ }
+
if (wav_file != -1)
close(wav_file);
- logf("rec: %s", recording_filename);
-
- start_wave(); /* todo: send signal to pcm_record if we have failed */
-
+ if (start_wave() != 0)
+ {
+ /* failed to create the file */
+ record_done = true;
+ return;
+ }
+
num_rec_bytes = 0;
-
- /* Store the current time */
+ num_file_bytes = 0;
record_start_time = current_tick;
-
+ pause_start_time = 0;
+
write_index = 0;
read_index = 0;
+ read2_index = 0;
- is_stopping = 0;
- is_paused = 0;
- is_recording = 1;
-
+ is_stopping = false;
+ is_paused = false;
+ is_recording = true;
+
pcmrec_dma_start();
+ record_done = true;
}
static void pcmrec_stop(void)
{
- /* wait for recording to finish */
+ logf("pcmrec_stop");
+
+ if (!is_recording)
+ {
+ stop_done = true;
+ return;
+ }
+
+ if (!is_paused)
+ {
+ /* wait for recording to finish */
+ is_stopping = true;
+
+ while (is_stopping && is_recording)
+ sleep_thread();
+ wake_up_thread();
+
+ is_stopping = false;
+ }
+
+ is_recording = false;
+
+ /* Flush buffers to file */
+ pcmrec_callback(true);
- /* todo: Abort current DMA transfer using DCR1.. */
+ close_wave();
- logf("pcmrec_stop");
+ stop_done = true;
+
+ logf("pcmrec_stop done");
+}
- while (is_recording)
+static void pcmrec_new_file(void)
+{
+ logf("pcmrec_new_file");
+
+ if (!is_recording)
{
- sleep(HZ >> 4);
+ logf("not recording");
+ new_file_done = true;
+ return;
}
+
+ /* Since pcmrec_callback() blocks until the data has been written,
+ here is a good approximation when recording to the new file starts
+ */
+ record_start_time = current_tick;
+ num_rec_bytes = 0;
+
+ if (is_paused)
+ pause_start_time = record_start_time;
+
+ /* Flush what we got in buffers to file */
+ pcmrec_callback(true);
+
+ close_wave();
- logf("pcmrec_stop done");
+ num_file_bytes = 0;
+
+ /* start the new file */
+ if (start_wave() != 0)
+ {
+ logf("new_file failed");
+ pcmrec_stop();
+ }
- /* Write unfinished buffers to file */
+ new_file_done = true;
+ logf("pcmrec_new_file done");
+}
+
+static void pcmrec_pause(void)
+{
+ logf("pcmrec_pause");
+
+ if (!is_recording)
+ {
+ logf("pause: not recording");
+ pause_done = true;
+ return;
+ }
+
+ /* Abort DMA transfer and flush to file? */
+
+ is_stopping = true;
+
+ while (is_stopping && is_recording)
+ sleep_thread();
+ wake_up_thread();
+
+ pause_start_time = current_tick;
+ is_paused = true;
+
+ /* Flush what we got in buffers to file */
pcmrec_callback(true);
+
+ pause_done = true;
+
+ logf("pcmrec_pause done");
+}
- close_wave();
- is_stopping = 0;
+static void pcmrec_resume(void)
+{
+ logf("pcmrec_resume");
+
+ if (!is_paused)
+ {
+ logf("resume: not paused");
+ resume_done = true;
+ return;
+ }
+
+ is_paused = false;
+ is_recording = true;
+
+ /* Compensate for the time we have been paused */
+ if (pause_start_time)
+ {
+ record_start_time += current_tick - pause_start_time;
+ pause_start_time = 0;
+ }
+
+ pcmrec_dma_start();
+
+ resume_done = true;
+
+ logf("pcmrec_resume done");
}
-static void pcmrec_open(void)
+
+/**
+ * audio_init_recording calls this function using PCMREC_INIT
+ *
+ */
+static void pcmrec_init(void)
{
- unsigned long buffer_start;
- int i;
+ unsigned long buffer_size;
show_waveform = 0;
- is_recording = 0;
- is_stopping = 0;
- num_rec_bytes = 0;
wav_file = -1;
read_index = 0;
+ read2_index = 0;
write_index = 0;
-
- buffer_start = (unsigned long)(&audiobuf[(audiobufend - audiobuf) - (ALL_BUFFERS_SIZE + 16)]);
- buffer_start &= ~3;
-
- for (i=0; i<NUM_BUFFERS; i++)
- {
- rec_buffers[i] = (unsigned char*)(buffer_start + EACH_BUFFER_SIZE * i);
- }
+
+ num_rec_bytes = 0;
+ num_file_bytes = 0;
+ record_start_time = 0;
+ pause_start_time = 0;
+
+ is_recording = false;
+ is_stopping = false;
+ is_paused = false;
+ is_error = false;
+
+ rec_buffer = (unsigned char*)(((unsigned long)audiobuf) & ~3);
+ buffer_size = (long)audiobufend - (long)audiobuf - 16;
+
+ //buffer_size = 1024*1024*5;
+
+ logf("buf size: %d kb", buffer_size/1024);
+
+ num_chunks = buffer_size / CHUNK_SIZE;
+
+ logf("num_chunks: %d", num_chunks);
IIS1CONFIG = 0x800; /* Stop any playback */
AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
@@ -578,16 +805,13 @@ static void pcmrec_open(void)
static void pcmrec_close(void)
{
-#if defined(HAVE_UDA1380)
uda1380_disable_recording();
-#elif defined(HAVE_TLV320)
- tlv320_disable_recording();
-#endif
DMAROUTE = (DMAROUTE & 0xffff00ff);
ICR7 = 0x00; /* Disable interrupt */
IMR |= (1<<15); /* bit 15 is DMA1 */
+ close_done = true;
}
static void pcmrec_thread(void)
@@ -596,14 +820,17 @@ static void pcmrec_thread(void)
logf("thread pcmrec start");
+ int_count = 0;
+ error_count = 0;
+
while (1)
{
queue_wait(&pcmrec_queue, &ev);
switch (ev.id)
{
- case PCMREC_OPEN:
- pcmrec_open();
+ case PCMREC_INIT:
+ pcmrec_init();
break;
case PCMREC_CLOSE:
@@ -619,25 +846,18 @@ static void pcmrec_thread(void)
break;
case PCMREC_PAUSE:
- /* todo */
+ pcmrec_pause();
break;
case PCMREC_RESUME:
- /* todo */
+ pcmrec_resume();
break;
case PCMREC_NEW_FILE:
- /* todo */
- break;
-
- case PCMREC_SET_GAIN:
-#if defined(HAVE_UDA1380)
- uda1380_set_recvol(rec_gain, rec_gain, rec_volume);
-#elif defined(HAVE_TLV320)
- /* ToDo */
-#endif
+ pcmrec_new_file();
break;
+ /* Notification by DMA interrupt */
case PCMREC_GOT_DATA:
pcmrec_callback(false);
break;
@@ -655,7 +875,8 @@ static void pcmrec_thread(void)
logf("thread pcmrec done");
}
-void pcmrec_set_mux(int source)
+/* Select VINL & VINR source: 0=Line-in, 1=FM Radio */
+void pcm_rec_mux(int source)
{
if(source == 0)
and_l(~0x00800000, &GPIO_OUT); /* Line In */
diff --git a/firmware/sound.c b/firmware/sound.c
index 332cca0..9ab545f 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -84,6 +84,12 @@ static const struct sound_settings_info sound_settings_table[] = {
[SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL},
[SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 15, 8, NULL},
[SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 15, 2, NULL},
+#elif defined(HAVE_UDA1380)
+ [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 8, 8, NULL},
+ [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 8, 8, NULL},
+ [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 15, 2, NULL},
+ [SOUND_ADC_LEFT_GAIN] = {"dB", 1, 1,-128, 48, 0, NULL},
+ [SOUND_ADC_RIGHT_GAIN]= {"dB", 1, 1,-128, 48, 0, NULL},
#endif
};
@@ -668,6 +674,30 @@ int sound_val2phys(int setting, int value)
break;
}
return result;
+#elif defined(HAVE_UDA1380)
+ int result = 0;
+
+ switch(setting)
+ {
+ case SOUND_LEFT_GAIN:
+ case SOUND_RIGHT_GAIN:
+ result = value * 30; /* (24/8) *10 */
+ break;
+
+ case SOUND_MIC_GAIN:
+ result = value * 20; /* (30/15) *10 */
+ break;
+
+ case SOUND_ADC_LEFT_GAIN:
+ case SOUND_ADC_RIGHT_GAIN:
+ result = value * 5; /* (1/2) *10 */
+ break;
+
+ default:
+ result = value;
+ break;
+ }
+ return result;
#else
(void)setting;
return value;