1
0
Fork 0
forked from len0rd/rockbox

iRiver recording changes:

- Added Peakmeter in recording screen
- Fix for stop bug
- Fix for playback peakmeter not working after recording


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8120 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Andy 2005-12-02 01:04:03 +00:00
parent 9758911be0
commit 1e4d1f8de7
4 changed files with 108 additions and 62 deletions

View file

@ -35,6 +35,11 @@
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
#include "pcm_playback.h" #include "pcm_playback.h"
#ifdef HAVE_RECORDING
#include "pcm_record.h"
#endif
static bool pm_playback = true; /* selects between playback and recording peaks */
#endif #endif
#if !defined(SIMULATOR) && CONFIG_CODEC != SWCODEC #if !defined(SIMULATOR) && CONFIG_CODEC != SWCODEC
@ -491,8 +496,7 @@ void peak_meter_playback(bool playback)
#ifdef SIMULATOR #ifdef SIMULATOR
(void)playback; (void)playback;
#elif CONFIG_CODEC == SWCODEC #elif CONFIG_CODEC == SWCODEC
/* FIX: not for the sw-based ones yes */ pm_playback = playback;
(void)playback;
#else #else
if (playback) { if (playback) {
pm_src_left = MAS_REG_DQPEAK_L; pm_src_left = MAS_REG_DQPEAK_L;
@ -531,7 +535,15 @@ void peak_meter_peek(void)
pm_cur_left = left = 8000; pm_cur_left = left = 8000;
pm_cur_right = right = 9000; pm_cur_right = right = 9000;
#elif CONFIG_CODEC == SWCODEC #elif CONFIG_CODEC == SWCODEC
pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
if (pm_playback)
pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
#ifdef HAVE_RECORDING
if (!pm_playback)
{
pcm_rec_get_peaks(&pm_cur_left, &pm_cur_right);
}
#endif
left = pm_cur_left; left = pm_cur_left;
right = pm_cur_right; right = pm_cur_right;
#else #else

View file

@ -328,15 +328,17 @@ bool recording_screen(void)
audio_init_recording(); audio_init_recording();
sound_set_volume(global_settings.volume); sound_set_volume(global_settings.volume);
/* Yes, we use the D/A for monitoring */
peak_meter_playback(true);
peak_meter_enabled = true;
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
audio_stop(); audio_stop();
/* Set peak meter to recording mode */
peak_meter_playback(false);
cpu_boost(true);
#else
/* Yes, we use the D/A for monitoring */
peak_meter_playback(true);
#endif #endif
peak_meter_enabled = true;
if (global_settings.rec_prerecord_time) if (global_settings.rec_prerecord_time)
talk_buffer_steal(); /* will use the mp3 buffer */ talk_buffer_steal(); /* will use the mp3 buffer */
@ -440,7 +442,9 @@ bool recording_screen(void)
else else
{ {
peak_meter_playback(true); peak_meter_playback(true);
#if CONFIG_CODEC != SWCODEC
peak_meter_enabled = false; peak_meter_enabled = false;
#endif
done = true; done = true;
} }
update_countdown = 1; /* Update immediately */ update_countdown = 1; /* Update immediately */
@ -875,6 +879,7 @@ bool recording_screen(void)
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
audio_stop_recording(); audio_stop_recording();
audio_close_recording(); audio_close_recording();
cpu_boost(false);
#else #else
audio_init_playback(); audio_init_playback();
#endif #endif

View file

@ -24,6 +24,8 @@ unsigned long pcm_rec_status(void);
void pcm_rec_init(void); void pcm_rec_init(void);
void pcm_rec_mux(int source); void pcm_rec_mux(int source);
void pcm_rec_get_peaks(int *left, int *right);
/* audio.h contains audio recording functions */ /* audio.h contains audio recording functions */
#endif #endif

View file

@ -56,18 +56,17 @@ static volatile bool is_error; /* An error has occured */
static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ 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 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 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 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 unsigned long pause_start_time; /* Value of current_tick when pause was started */
static bool show_waveform;
static int wav_file; static int wav_file;
static char recording_filename[MAX_PATH]; static char recording_filename[MAX_PATH];
static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done;
static int peak_left, peak_right;
/***************************************************************************/ /***************************************************************************/
@ -75,17 +74,10 @@ static bool init_done, close_done, record_done, stop_done, pause_done, resume_do
Some estimates: Some estimates:
Normal recording rate: 44100 HZ * 4 = 176 KB/s Normal recording rate: 44100 HZ * 4 = 176 KB/s
Total buffer size: 32 MB / 176 KB/s = 181s before writing to disk 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..
*/ */
#define CHUNK_SIZE 65536 /* Multiple of 4 */ #define CHUNK_SIZE 8192 /* Multiple of 4 */
#define WRITE_THRESHOLD 30 /* Write when this many chunks (or less) until buffer full */ #define WRITE_THRESHOLD 250 /* (2 MB) Write when this many chunks (or less) until buffer full */
#define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)]) #define GET_CHUNK(x) (short*)(&rec_buffer[CHUNK_SIZE*(x)])
@ -123,8 +115,6 @@ static void pcmrec_dma_stop(void);
#define PCMREC_RESUME 11 #define PCMREC_RESUME 11
#define PCMREC_NEW_FILE 12 #define PCMREC_NEW_FILE 12
#define PCMREC_SET_GAIN 13 #define PCMREC_SET_GAIN 13
#define PCMREC_GOT_DATA 20 /* DMA1 notifies when data has arrived */
/*******************************************************************/ /*******************************************************************/
/* Functions that are not executing in the pcmrec_thread first */ /* Functions that are not executing in the pcmrec_thread first */
@ -350,21 +340,68 @@ void audio_resume_recording(void)
wake_up_thread(); wake_up_thread();
} }
void pcm_rec_get_peaks(int *left, int *right)
{
if (!is_recording)
{
peak_left = 0;
peak_right = 0;
}
if (left)
*left = peak_left;
if (right)
*right = peak_right;
}
/***************************************************************************/ /***************************************************************************/
/* Functions that executes in the context of pcmrec_thread */ /* Functions that executes in the context of pcmrec_thread */
/***************************************************************************/ /***************************************************************************/
/* Skip PEAK_STRIDE sample-pairs for each compare */
#define PEAK_STRIDE 3
static void pcmrec_find_peaks(int chunk)
{
short *ptr, value;
int peak_l, peak_r;
int j;
ptr = GET_CHUNK(chunk);
peak_l = 0;
peak_r = 0;
for (j=0; j<CHUNK_SIZE/4; j+=PEAK_STRIDE+1)
{
if ((value = ptr[0]) > peak_l)
peak_l = value;
else if (-value > peak_l)
peak_l = -value;
ptr++;
if ((value = ptr[0]) > peak_r)
peak_r = value;
else if (-value > peak_r)
peak_r = -value;
ptr++;
ptr += PEAK_STRIDE * 2;
}
peak_left = peak_l;
peak_right = peak_r;
}
/** /**
* Process the chunks using read_index and write_index. * Process the chunks using read_index and write_index.
* *
* DMA1 handler posts to pcmrec_queue and pcmrec_thread calls this * This function is called when queue_get_w_tmo times out.
* function.
* *
* Other function can also call this function with flush = true when * Other functions can also call this function with flush = true when
* they want to save everything recorded sofar to disk. * they want to save everything in the buffers to disk.
* *
*/ */
@ -375,12 +412,24 @@ static void pcmrec_callback(bool flush)
unsigned short *ptr; unsigned short *ptr;
int i, j, w; int i, j, w;
if ((!is_recording || is_paused) && !flush)
return;
w = write_index; w = write_index;
num_new = w - read2_index; num_new = w - read2_index;
if (num_new < 0) if (num_new < 0)
num_new += num_chunks; num_new += num_chunks;
if (num_new > 0)
{
/* Collect peak values for the last buffer only */
j = w - 1;
if (j < 0)
j += num_chunks;
pcmrec_find_peaks(j);
}
for (i=0; i<num_new; i++) for (i=0; i<num_new; i++)
{ {
/* Convert the samples to little-endian so we only have to write later /* Convert the samples to little-endian so we only have to write later
@ -389,12 +438,10 @@ static void pcmrec_callback(bool flush)
ptr = GET_CHUNK(read2_index); ptr = GET_CHUNK(read2_index);
for (j=0; j<CHUNK_SIZE/2; j++) for (j=0; j<CHUNK_SIZE/2; j++)
{ {
/* TODO: might be a good place to add the peak-meter.. */
*ptr = htole16(*ptr); *ptr = htole16(*ptr);
ptr++; ptr++;
} }
num_rec_bytes += CHUNK_SIZE; num_rec_bytes += CHUNK_SIZE;
read2_index++; read2_index++;
@ -406,26 +453,8 @@ static void pcmrec_callback(bool flush)
if (num_ready < 0) if (num_ready < 0)
num_ready += num_chunks; num_ready += num_chunks;
if (num_ready >= num_chunks)
{
logf("num_ready overflow?");
num_ready = num_chunks-1;
}
num_free = num_chunks - num_ready; num_free = num_chunks - num_ready;
if (wav_file == -1 || (!is_recording && !flush))
{
/* In this case we should consume the buffers to avoid */
/* getting 'dma1 overrun' */
read_index+=num_ready;
if (read_index >= num_chunks)
read_index -= num_chunks;
return;
}
if (num_free <= WRITE_THRESHOLD || flush) if (num_free <= WRITE_THRESHOLD || flush)
{ {
logf("writing: %d (%d)", num_ready, flush); logf("writing: %d (%d)", num_ready, flush);
@ -484,15 +513,13 @@ void DMA1(void)
DSR1 = 1; /* Clear interrupt */ DSR1 = 1; /* Clear interrupt */
int_count++;
if (res & 0x70) if (res & 0x70)
{ {
DCR1 = 0; /* Stop DMA transfer */ DCR1 = 0; /* Stop DMA transfer */
error_count++; error_count++;
is_recording = false; is_recording = false;
logf("dma1 err 0x%x", res); logf("dma1 err: 0x%x", res);
/* Flush recorded data to disk and stop recording */ /* Flush recorded data to disk and stop recording */
queue_post(&pcmrec_queue, PCMREC_STOP, NULL); queue_post(&pcmrec_queue, PCMREC_STOP, NULL);
@ -521,9 +548,6 @@ void DMA1(void)
{ {
DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */ DAR1 = (unsigned long)GET_CHUNK(write_index); /* Destination address */
BCR1 = CHUNK_SIZE; BCR1 = CHUNK_SIZE;
queue_post(&pcmrec_queue, PCMREC_GOT_DATA, NULL);
} }
} }
@ -603,6 +627,9 @@ static void pcmrec_start(void)
return; return;
} }
peak_left = 0;
peak_right = 0;
num_rec_bytes = 0; num_rec_bytes = 0;
num_file_bytes = 0; num_file_bytes = 0;
record_start_time = current_tick; record_start_time = current_tick;
@ -761,12 +788,14 @@ static void pcmrec_init(void)
{ {
unsigned long buffer_size; unsigned long buffer_size;
show_waveform = 0;
wav_file = -1; wav_file = -1;
read_index = 0; read_index = 0;
read2_index = 0; read2_index = 0;
write_index = 0; write_index = 0;
peak_left = 0;
peak_right = 0;
num_rec_bytes = 0; num_rec_bytes = 0;
num_file_bytes = 0; num_file_bytes = 0;
record_start_time = 0; record_start_time = 0;
@ -819,12 +848,11 @@ static void pcmrec_thread(void)
logf("thread pcmrec start"); logf("thread pcmrec start");
int_count = 0;
error_count = 0; error_count = 0;
while (1) while (1)
{ {
queue_wait(&pcmrec_queue, &ev); queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 40);
switch (ev.id) switch (ev.id)
{ {
@ -856,8 +884,7 @@ static void pcmrec_thread(void)
pcmrec_new_file(); pcmrec_new_file();
break; break;
/* Notification by DMA interrupt */ case SYS_TIMEOUT:
case PCMREC_GOT_DATA:
pcmrec_callback(false); pcmrec_callback(false);
break; break;