Big Patch adds primarily: Samplerate and format selection to recording for SWCODEC. Supprort for samplerates changing in playback (just goes with the recording part inseparably). Samplerates to all encoders. Encoders can be configured individually on a menu specific to the encoder in the recording menu. File creation is delayed until flush time to reduce spinups when splitting. Misc: statusbar icons for numbers are individual digits to display any number. Audio buffer was rearranged to maximize memory available to recording and properly reinitialized when trashed. ColdFire PCM stuff moved to target tree to avoid a complicated mess when adding samplerate switching. Some needed API changes and to neaten up growing gap between hardware and software codecs.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11452 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2006-11-06 18:07:30 +00:00
parent 0b22795e26
commit 0f5cb94aa4
58 changed files with 4769 additions and 2781 deletions

View file

@ -73,6 +73,9 @@ pcmbuf.c
playback.c playback.c
codecs.c codecs.c
dsp.c dsp.c
#ifdef HAVE_RECORDING
enc_config.c
#endif
eq.c eq.c
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) #if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
dsp_cf.S dsp_cf.S

View file

@ -50,6 +50,7 @@
#include "sound.h" #include "sound.h"
#include "database.h" #include "database.h"
#include "splash.h" #include "splash.h"
#include "general.h"
#ifdef SIMULATOR #ifdef SIMULATOR
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
@ -104,6 +105,7 @@ struct codec_api ci = {
PREFIX(remove), PREFIX(remove),
PREFIX(rename), PREFIX(rename),
PREFIX(ftruncate), PREFIX(ftruncate),
PREFIX(fsync),
fdprintf, fdprintf,
read_line, read_line,
settings_parseline, settings_parseline,
@ -187,6 +189,7 @@ struct codec_api ci = {
get_time, get_time,
set_time, set_time,
plugin_get_audio_buffer, plugin_get_audio_buffer,
round_value_to_list32,
#if defined(DEBUG) || defined(SIMULATOR) #if defined(DEBUG) || defined(SIMULATOR)
debugf, debugf,
@ -213,11 +216,11 @@ struct codec_api ci = {
false, false,
enc_get_inputs, enc_get_inputs,
enc_set_parameters, enc_set_parameters,
enc_alloc_chunk, enc_get_chunk,
enc_free_chunk, enc_finish_chunk,
enc_wavbuf_near_empty, enc_pcm_buf_near_empty,
enc_get_wav_data, enc_get_pcm_data,
&enc_set_header_callback, enc_unget_pcm_data
#endif #endif
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
@ -225,10 +228,10 @@ struct codec_api ci = {
}; };
void codec_get_full_path(char *path, const char *codec_fn) void codec_get_full_path(char *path, const char *codec_root_fn)
{ {
/* Create full codec path */ snprintf(path, MAX_PATH-1, CODECS_DIR "/%s." CODEC_EXTENSION,
snprintf(path, MAX_PATH-1, CODECS_DIR "/%s", codec_fn); codec_root_fn);
} }
int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,
@ -254,7 +257,11 @@ int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,
hdr = (struct codec_header *)codecbuf; hdr = (struct codec_header *)codecbuf;
if (size <= (signed)sizeof(struct codec_header) if (size <= (signed)sizeof(struct codec_header)
|| hdr->magic != CODEC_MAGIC || (hdr->magic != CODEC_MAGIC
#ifdef HAVE_RECORDING
&& hdr->magic != CODEC_ENC_MAGIC
#endif
)
|| hdr->target_id != TARGET_ID || hdr->target_id != TARGET_ID
|| hdr->load_addr != codecbuf || hdr->load_addr != codecbuf
|| hdr->end_addr > codecbuf + CODEC_SIZE) || hdr->end_addr > codecbuf + CODEC_SIZE)

View file

@ -46,7 +46,7 @@
#include "profile.h" #include "profile.h"
#endif #endif
#if (CONFIG_CODEC == SWCODEC) #if (CONFIG_CODEC == SWCODEC)
#if !defined(SIMULATOR) #if !defined(SIMULATOR) && defined(HAVE_RECORDING)
#include "pcm_record.h" #include "pcm_record.h"
#endif #endif
#include "dsp.h" #include "dsp.h"
@ -84,15 +84,18 @@
#define PREFIX(_x_) _x_ #define PREFIX(_x_) _x_
#endif #endif
/* magic for normal codecs */
#define CODEC_MAGIC 0x52434F44 /* RCOD */ #define CODEC_MAGIC 0x52434F44 /* RCOD */
/* magic for encoder codecs */
#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define CODEC_API_VERSION 9 #define CODEC_API_VERSION 10
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define CODEC_MIN_API_VERSION 8 #define CODEC_MIN_API_VERSION 10
/* codec return codes */ /* codec return codes */
enum codec_status { enum codec_status {
@ -176,6 +179,7 @@ struct codec_api {
int (*PREFIX(remove))(const char* pathname); int (*PREFIX(remove))(const char* pathname);
int (*PREFIX(rename))(const char* path, const char* newname); int (*PREFIX(rename))(const char* path, const char* newname);
int (*PREFIX(ftruncate))(int fd, off_t length); int (*PREFIX(ftruncate))(int fd, off_t length);
int (*PREFIX(fsync))(int fd);
int (*fdprintf)(int fd, const char *fmt, ...); int (*fdprintf)(int fd, const char *fmt, ...);
int (*read_line)(int fd, char* buffer, int buffer_size); int (*read_line)(int fd, char* buffer, int buffer_size);
@ -232,7 +236,8 @@ struct codec_api {
/* sound */ /* sound */
void (*sound_set)(int setting, int value); void (*sound_set)(int setting, int value);
#ifndef SIMULATOR #ifndef SIMULATOR
void (*mp3_play_data)(const unsigned char* start, int size, void (*get_more)(unsigned char** start, int* size)); void (*mp3_play_data)(const unsigned char* start,
int size, void (*get_more)(unsigned char** start, int* size));
void (*mp3_play_pause)(bool play); void (*mp3_play_pause)(bool play);
void (*mp3_play_stop)(void); void (*mp3_play_stop)(void);
bool (*mp3_is_playing)(void); bool (*mp3_is_playing)(void);
@ -263,6 +268,10 @@ struct codec_api {
struct tm* (*get_time)(void); struct tm* (*get_time)(void);
int (*set_time)(const struct tm *tm); int (*set_time)(const struct tm *tm);
void* (*plugin_get_audio_buffer)(int* buffer_size); void* (*plugin_get_audio_buffer)(int* buffer_size);
int (*round_value_to_list32)(unsigned long value,
const unsigned long list[],
int count,
bool signd);
#if defined(DEBUG) || defined(SIMULATOR) #if defined(DEBUG) || defined(SIMULATOR)
void (*debugf)(const char *fmt, ...); void (*debugf)(const char *fmt, ...);
@ -291,18 +300,14 @@ struct codec_api {
#endif #endif
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
bool enc_codec_loaded; volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */
void (*enc_get_inputs)(int *buffer_size, void (*enc_get_inputs)(struct enc_inputs *inputs);
int *channels, int *quality); void (*enc_set_parameters)(struct enc_parameters *params);
void (*enc_set_parameters)(int chunk_size, int num_chunks, struct enc_chunk_hdr * (*enc_get_chunk)(void);
int samp_per_chunk, char *head_ptr, int head_size, void (*enc_finish_chunk)(void);
int enc_id); int (*enc_pcm_buf_near_empty)(void);
unsigned int* (*enc_alloc_chunk)(void); unsigned char * (*enc_get_pcm_data)(size_t size);
void (*enc_free_chunk)(void); size_t (*enc_unget_pcm_data)(size_t size);
int (*enc_wavbuf_near_empty)(void);
char* (*enc_get_wav_data)(int size);
void (**enc_set_header_callback)(void *head_buffer,
int head_size, int num_samples, bool is_file_header);
#endif #endif
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
@ -312,34 +317,49 @@ struct codec_api {
/* codec header */ /* codec header */
struct codec_header { struct codec_header {
unsigned long magic; unsigned long magic; /* RCOD or RENC */
unsigned short target_id; unsigned short target_id;
unsigned short api_version; unsigned short api_version;
unsigned char *load_addr; unsigned char *load_addr;
unsigned char *end_addr; unsigned char *end_addr;
enum codec_status(*entry_point)(struct codec_api*); enum codec_status(*entry_point)(struct codec_api*);
}; };
#ifdef CODEC #ifdef CODEC
#ifndef SIMULATOR #ifndef SIMULATOR
/* plugin_* is correct, codecs use the plugin linker script */ /* plugin_* is correct, codecs use the plugin linker script */
extern unsigned char plugin_start_addr[]; extern unsigned char plugin_start_addr[];
extern unsigned char plugin_end_addr[]; extern unsigned char plugin_end_addr[];
/* decoders */
#define CODEC_HEADER \ #define CODEC_HEADER \
const struct codec_header __header \ const struct codec_header __header \
__attribute__ ((section (".header")))= { \ __attribute__ ((section (".header")))= { \
CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr, codec_start }; plugin_start_addr, plugin_end_addr, codec_start };
#else /* SIMULATOR */ /* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr, codec_start };
#else /* def SIMULATOR */
/* decoders */
#define CODEC_HEADER \ #define CODEC_HEADER \
const struct codec_header __header = { \ const struct codec_header __header = { \
CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
NULL, NULL, codec_start }; NULL, NULL, codec_start };
#endif /* encoders */
#endif #define CODEC_ENC_HEADER \
const struct codec_header __header = { \
CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
NULL, NULL, codec_start };
#endif /* SIMULATOR */
#endif /* CODEC */
/* create full codec path from filenames in audio_formats[] /* create full codec path from root filenames in audio_formats[]
assumes buffer size is MAX_PATH */ assumes buffer size is MAX_PATH */
void codec_get_full_path(char *path, const char *codec_fn); void codec_get_full_path(char *path, const char *codec_root_fn);
/* defined by the codec loader (codec.c) */ /* defined by the codec loader (codec.c) */
int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,

View file

@ -15,6 +15,7 @@
// the malloc() system is provided. // the malloc() system is provided.
#include "wavpack.h" #include "wavpack.h"
#include "system.h"
#include <string.h> #include <string.h>
@ -118,19 +119,16 @@ uint32_t bs_close_write (Bitstream *bs)
void little_endian_to_native (void *data, char *format) void little_endian_to_native (void *data, char *format)
{ {
uchar *cp = (uchar *) data; uchar *cp = (uchar *) data;
int32_t temp;
while (*format) { while (*format) {
switch (*format) { switch (*format) {
case 'L': case 'L':
temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); *(long *)cp = letoh32(*(long *)cp);
* (int32_t *) cp = temp;
cp += 4; cp += 4;
break; break;
case 'S': case 'S':
temp = cp [0] + (cp [1] << 8); *(short *)cp = letoh16(*(short *)cp);
* (short *) cp = (short) temp;
cp += 2; cp += 2;
break; break;
@ -148,28 +146,22 @@ void little_endian_to_native (void *data, char *format)
void native_to_little_endian (void *data, char *format) void native_to_little_endian (void *data, char *format)
{ {
uchar *cp = (uchar *) data; uchar *cp = (uchar *) data;
int32_t temp;
while (*format) { while (*format) {
switch (*format) { switch (*format) {
case 'L': case 'L':
temp = * (int32_t *) cp; *(long *)cp = htole32(*(long *)cp);
*cp++ = (uchar) temp; cp += 4;
*cp++ = (uchar) (temp >> 8);
*cp++ = (uchar) (temp >> 16);
*cp++ = (uchar) (temp >> 24);
break; break;
case 'S': case 'S':
temp = * (short *) cp; *(short *)cp = htole16(*(short *)cp);
*cp++ = (uchar) temp; cp += 2;
*cp++ = (uchar) (temp >> 8);
break; break;
default: default:
if (*format >= '0' && *format <= '9') if (*format >= '0' && *format <= '9')
cp += *format - '0'; cp += *format - '0';
break; break;
} }

File diff suppressed because it is too large Load diff

View file

@ -19,140 +19,364 @@
#ifndef SIMULATOR #ifndef SIMULATOR
#include <inttypes.h>
#include "codeclib.h" #include "codeclib.h"
CODEC_HEADER CODEC_ENC_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
struct riff_header
{
uint8_t riff_id[4]; /* 00h - "RIFF" */
uint32_t riff_size; /* 04h - sz following headers + data_size */
/* format header */
uint8_t format[4]; /* 08h - "WAVE" */
uint8_t format_id[4]; /* 0Ch - "fmt " */
uint32_t format_size; /* 10h - 16 for PCM (sz format data) */
/* format data */
uint16_t audio_format; /* 14h - 1=PCM */
uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */
uint32_t sample_rate; /* 18h - HZ */
uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */
uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */
/* Not for audio_format=1 (PCM) */
/* unsigned short extra_param_size; 24h - size of extra data */
/* unsigned char *extra_params; */
/* data header */
uint8_t data_id[4]; /* 24h - "data" */
uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */
/* unsigned char *data; 2ch - actual sound data */
};
#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
#define PCM_DEPTH_BYTES 2
#define PCM_DEPTH_BITS 16
#define PCM_SAMP_PER_CHUNK 2048
#define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4)
static struct codec_api *ci; static struct codec_api *ci;
static int enc_channels; static int num_channels;
uint32_t sample_rate;
uint32_t enc_size;
#define CHUNK_SIZE 8192 static const struct riff_header riff_header =
static unsigned char wav_header[44] =
{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16,
0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0};
static unsigned char wav_header_mono[44] =
{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16,
0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0};
/* update file header info callback function (called by main application) */
void enc_set_header(void *head_buffer, /* ptr to the file header data */
int head_size, /* size of this header data */
int num_pcm_samples, /* amount of processed pcm samples */
bool is_file_header)
{ {
int num_file_bytes = num_pcm_samples * 2 * enc_channels; /* "RIFF" header */
{ 'R', 'I', 'F', 'F' }, /* riff_id */
0, /* riff_size (*) */
/* format header */
{ 'W', 'A', 'V', 'E' }, /* format */
{ 'f', 'm', 't', ' ' }, /* format_id */
H_TO_LE32(16), /* format_size */
/* format data */
H_TO_LE16(1), /* audio_format */
0, /* num_channels (*) */
0, /* sample_rate (*) */
0, /* byte_rate (*) */
0, /* block_align (*) */
H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */
/* data header */
{ 'd', 'a', 't', 'a' }, /* data_id */
0 /* data_size (*) */
/* (*) updated during ENC_END_FILE event */
};
if(is_file_header) /* called version often - inline */
static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
static inline bool is_file_data_ok(struct enc_file_event_data *data)
{
return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
} /* is_file_data_ok */
/* called version often - inline */
static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
static inline bool on_write_chunk(struct enc_file_event_data *data)
{
if (!is_file_data_ok(data))
return false;
if (data->chunk->enc_data == NULL)
{ {
/* update file header before file closing */ #ifdef ROCKBOX_HAS_LOGF
if((int)sizeof(wav_header) < head_size) ci->logf("wav enc: NULL data");
{ #endif
/* update wave header size entries: special to WAV format */ return true;
*(long*)(head_buffer+ 4) = htole32(num_file_bytes + 36);
*(long*)(head_buffer+40) = htole32(num_file_bytes);
}
} }
}
if (ci->write(data->rec_file, data->chunk->enc_data,
data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
return false;
data->num_pcm_samples += data->chunk->num_pcm;
return true;
} /* on_write_chunk */
static bool on_start_file(struct enc_file_event_data *data)
{
if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
return false;
data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
if (data->rec_file < 0)
return false;
/* reset sample count */
data->num_pcm_samples = 0;
/* write template header */
if (ci->write(data->rec_file, &riff_header, sizeof (riff_header))
!= sizeof (riff_header))
{
return false;
}
data->new_enc_size += sizeof (riff_header);
return true;
} /* on_start_file */
static bool on_end_file(struct enc_file_event_data *data)
{
/* update template header */
struct riff_header hdr;
uint32_t data_size;
if (!is_file_data_ok(data))
return false;
if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
{
return false;
}
data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES;
/* "RIFF" header */
hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE
+ RIFF_DATA_HEADER_SIZE + data_size);
/* format data */
hdr.num_channels = htole16(num_channels);
hdr.sample_rate = htole32(sample_rate);
hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES);
hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES);
/* data header */
hdr.data_size = htole32(data_size);
if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
{
return false;
}
ci->fsync(data->rec_file);
ci->close(data->rec_file);
data->rec_file = -1;
return true;
} /* on_end_file */
static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR;
static void enc_events_callback(enum enc_events event, void *data)
{
if (event == ENC_WRITE_CHUNK)
{
if (on_write_chunk((struct enc_file_event_data *)data))
return;
}
else if (event == ENC_START_FILE)
{
if (on_start_file((struct enc_file_event_data *)data))
return;
}
else if (event == ENC_END_FILE)
{
if (on_end_file((struct enc_file_event_data *)data))
return;
}
else
{
return;
}
((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
} /* enc_events_callback */
/* convert native pcm samples to wav format samples */
static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR;
static void chunk_to_wav_format(uint32_t *src, uint32_t *dst)
{
if (num_channels == 1)
{
/* On big endian:
* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
* |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
*
* On little endian:
* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
* |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM|
*/
uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
inline void to_mono(uint32_t **src, uint32_t **dst)
{
int32_t lr1, lr2;
lr1 = *(*src)++;
lr1 = ((int16_t)lr1 + (lr1 >> 16)) >> 1;
lr2 = *(*src)++;
lr2 = ((int16_t)lr2 + (lr2 >> 16)) >> 1;
*(*dst)++ = swap_odd_even_be32((lr1 << 16) | (uint16_t)lr2);
} /* to_mono */
do
{
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
to_mono(&src, &dst);
}
while (src < src_end);
}
else
{
#ifdef ROCKBOX_BIG_ENDIAN
/* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
*/
uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
do
{
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
*dst++ = swap_odd_even32(*src++);
}
while (src < src_end);
#else
/* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
*/
ci->memcpy(dst, src, PCM_CHUNK_SIZE);
#endif
}
} /* chunk_to_wav_format */
static bool init_encoder(void)
{
struct enc_inputs inputs;
struct enc_parameters params;
if (ci->enc_get_inputs == NULL ||
ci->enc_set_parameters == NULL ||
ci->enc_get_chunk == NULL ||
ci->enc_finish_chunk == NULL ||
ci->enc_pcm_buf_near_empty == NULL ||
ci->enc_get_pcm_data == NULL )
return false;
ci->enc_get_inputs(&inputs);
if (inputs.config->afmt != AFMT_PCM_WAV)
return false;
sample_rate = inputs.sample_rate;
num_channels = inputs.num_channels;
/* configure the buffer system */
params.afmt = AFMT_PCM_WAV;
enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2;
params.chunk_size = enc_size;
params.enc_sample_rate = sample_rate;
params.reserve_bytes = 0;
params.events_callback = enc_events_callback;
ci->enc_set_parameters(&params);
return true;
} /* init_encoder */
/* main codec entry point */ /* main codec entry point */
enum codec_status codec_start(struct codec_api* api) enum codec_status codec_start(struct codec_api* api)
{ {
int i; bool cpu_boosted;
long lr;
unsigned long t;
unsigned long *src;
unsigned long *dst;
int chunk_size, num_chunks, samp_per_chunk;
int enc_buffer_size;
int enc_quality;
bool cpu_boosted = true; /* start boosted */
ci = api; // copy to global api pointer ci = api; // copy to global api pointer
if(ci->enc_get_inputs == NULL || #ifdef USE_IRAM
ci->enc_set_parameters == NULL || ci->memcpy(iramstart, iramcopy, iramend - iramstart);
ci->enc_alloc_chunk == NULL || ci->memset(iedata, 0, iend - iedata);
ci->enc_free_chunk == NULL || #endif
ci->enc_wavbuf_near_empty == NULL ||
ci->enc_get_wav_data == NULL || if (!init_encoder())
ci->enc_set_header_callback == NULL ) {
ci->enc_codec_loaded = -1;
return CODEC_ERROR; return CODEC_ERROR;
}
ci->cpu_boost(true);
*ci->enc_set_header_callback = enc_set_header;
ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality);
/* configure the buffer system */
chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2;
num_chunks = enc_buffer_size / chunk_size;
samp_per_chunk = CHUNK_SIZE / 4;
/* inform the main program about buffer dimensions and other params */
ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk,
(enc_channels == 2) ? wav_header : wav_header_mono,
sizeof(wav_header), AFMT_PCM_WAV);
/* main application waits for this flag during encoder loading */ /* main application waits for this flag during encoder loading */
ci->enc_codec_loaded = true; ci->enc_codec_loaded = 1;
ci->cpu_boost(true);
cpu_boosted = true;
/* main encoding loop */ /* main encoding loop */
while(!ci->stop_codec) while(!ci->stop_codec)
{ {
while((src = (unsigned long*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) uint32_t *src;
while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
{ {
if(ci->stop_codec) struct enc_chunk_hdr *chunk;
if (ci->stop_codec)
break; break;
if(ci->enc_wavbuf_near_empty() == 0) if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
{ {
if(!cpu_boosted) ci->cpu_boost(true);
{ cpu_boosted = true;
ci->cpu_boost(true);
cpu_boosted = true;
}
} }
dst = (unsigned long*)ci->enc_alloc_chunk(); chunk = ci->enc_get_chunk();
*dst++ = CHUNK_SIZE * enc_channels / 2; /* set size info */ chunk->enc_size = enc_size;
chunk->num_pcm = PCM_SAMP_PER_CHUNK;
chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
if(enc_channels == 2) chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
{
/* swap byte order & copy to destination */
for (i=0; i<CHUNK_SIZE/4; i++)
{
t = *src++;
*dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
}
}
else
{
/* mix left/right, swap byte order & copy to destination */
for (i=0; i<CHUNK_SIZE/8; i++)
{
lr = (long)*src++;
lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
t = (lr << 16);
lr = (long)*src++;
lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */
t |= lr & 0xffff;
*dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00);
}
}
ci->enc_free_chunk(); ci->enc_finish_chunk();
ci->yield(); ci->yield();
} }
if(ci->enc_wavbuf_near_empty()) if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0)
{ {
if(cpu_boosted) ci->cpu_boost(false);
{ cpu_boosted = false;
ci->cpu_boost(false);
cpu_boosted = false;
}
} }
ci->yield(); ci->yield();
@ -162,11 +386,12 @@ enum codec_status codec_start(struct codec_api* api)
ci->cpu_boost(false); ci->cpu_boost(false);
/* reset parameters to initial state */ /* reset parameters to initial state */
ci->enc_set_parameters(0, 0, 0, 0, 0, 0); ci->enc_set_parameters(NULL);
/* main application waits for this flag during encoder removing */ /* main application waits for this flag during encoder removing */
ci->enc_codec_loaded = false; ci->enc_codec_loaded = 0;
return CODEC_OK; return CODEC_OK;
} } /* codec_start */
#endif
#endif /* ndef SIMULATOR */

View file

@ -22,201 +22,474 @@
#include "codeclib.h" #include "codeclib.h"
#include "libwavpack/wavpack.h" #include "libwavpack/wavpack.h"
CODEC_HEADER CODEC_ENC_HEADER
typedef unsigned long uint32; #ifdef USE_IRAM
typedef unsigned short uint16; extern char iramcopy[];
typedef unsigned char uint8; extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
static unsigned char wav_header_ster [46] = /** Types **/
{33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, typedef struct
0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0};
static unsigned char wav_header_mono [46] =
{33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16,
0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0};
static struct codec_api *ci;
static int enc_channels;
#define CHUNK_SIZE 20000
static long input_buffer[CHUNK_SIZE/2] IBSS_ATTR;
/* update file header info callback function */
void enc_set_header(void *head_buffer, /* ptr to the file header data */
int head_size, /* size of this header data */
int num_pcm_sampl, /* amount of processed pcm samples */
bool is_file_header) /* update file/chunk header */
{ {
if(is_file_header) uint8_t type; /* Type of metadata */
uint8_t word_size; /* Size of metadata in words */
} WavpackMetadataHeader;
struct riff_header
{
uint8_t riff_id[4]; /* 00h - "RIFF" */
uint32_t riff_size; /* 04h - sz following headers + data_size */
/* format header */
uint8_t format[4]; /* 08h - "WAVE" */
uint8_t format_id[4]; /* 0Ch - "fmt " */
uint32_t format_size; /* 10h - 16 for PCM (sz format data) */
/* format data */
uint16_t audio_format; /* 14h - 1=PCM */
uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */
uint32_t sample_rate; /* 18h - HZ */
uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */
uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */
uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */
/* Not for audio_format=1 (PCM) */
/* unsigned short extra_param_size; 24h - size of extra data */
/* unsigned char *extra_params; */
/* data header */
uint8_t data_id[4]; /* 24h - "data" */
uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */
/* unsigned char *data; 2ch - actual sound data */
};
#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */
#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */
#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */
#define PCM_DEPTH_BITS 16
#define PCM_DEPTH_BYTES 2
#define PCM_SAMP_PER_CHUNK 5000
#define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK)
/** Data **/
static struct codec_api *ci;
static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR;
static WavpackConfig config IBSS_ATTR;
static WavpackContext *wpc;
static int32_t data_size, input_size, input_step IBSS_ATTR;
static const WavpackMetadataHeader wvpk_mdh =
{
ID_RIFF_HEADER,
sizeof (struct riff_header) / sizeof (uint16_t),
};
static const struct riff_header riff_header =
{
/* "RIFF" header */
{ 'R', 'I', 'F', 'F' }, /* riff_id */
0, /* riff_size (*) */
/* format header */
{ 'W', 'A', 'V', 'E' }, /* format */
{ 'f', 'm', 't', ' ' }, /* format_id */
H_TO_LE32(16), /* format_size */
/* format data */
H_TO_LE16(1), /* audio_format */
0, /* num_channels (*) */
0, /* sample_rate (*) */
0, /* byte_rate (*) */
0, /* block_align (*) */
H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */
/* data header */
{ 'd', 'a', 't', 'a' }, /* data_id */
0 /* data_size (*) */
/* (*) updated during ENC_END_FILE event */
};
static void chunk_to_int32(int32_t *src) ICODE_ATTR;
static void chunk_to_int32(int32_t *src)
{
int32_t *dst = (int32_t *)input_buffer + PCM_SAMP_PER_CHUNK;
int32_t *src_end = dst + PCM_SAMP_PER_CHUNK;
/* copy to IRAM before converting data */
memcpy(dst, src, PCM_CHUNK_SIZE);
src = dst;
dst = (int32_t *)input_buffer;
if (config.num_channels == 1)
{ {
/* update file header before file closing */ /*
if(sizeof(WavpackHeader) + sizeof(wav_header_mono) < (unsigned)head_size) * |llllllllllllllll|rrrrrrrrrrrrrrrr| =>
* |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm|
*/
inline void to_int32(int32_t **src, int32_t **dst)
{ {
char* riff_header = (char*)head_buffer + sizeof(WavpackHeader); int32_t t = *(*src)++;
char* wv_header = (char*)head_buffer + sizeof(wav_header_mono); /* endianness irrelevant */
int num_file_bytes = num_pcm_sampl * 2 * enc_channels; *(*dst)++ = ((int16_t)t + (t >> 16)) >> 1;
unsigned long ckSize; } /* to_int32 */
/* RIFF header and WVPK header have to be swapped */ do
/* copy wavpack header to file start position */ {
ci->memcpy(head_buffer, wv_header, sizeof(WavpackHeader)); /* read 10 longs and write 10 longs */
wv_header = head_buffer; /* recalc wavpack header position */ to_int32(&src, &dst);
to_int32(&src, &dst);
if(enc_channels == 2) to_int32(&src, &dst);
ci->memcpy(riff_header, wav_header_ster, sizeof(wav_header_ster)); to_int32(&src, &dst);
else to_int32(&src, &dst);
ci->memcpy(riff_header, wav_header_mono, sizeof(wav_header_mono)); to_int32(&src, &dst);
to_int32(&src, &dst);
/* update the Wavpack header first chunk size & total frame count */ to_int32(&src, &dst);
ckSize = htole32(((WavpackHeader*)wv_header)->ckSize) to_int32(&src, &dst);
+ sizeof(wav_header_mono); to_int32(&src, &dst);
((WavpackHeader*)wv_header)->total_samples = htole32(num_pcm_sampl);
((WavpackHeader*)wv_header)->ckSize = htole32(ckSize);
/* update the RIFF WAV header size entries */
*(long*)(riff_header+ 6) = htole32(num_file_bytes + 36);
*(long*)(riff_header+42) = htole32(num_file_bytes);
} }
while(src < src_end);
return;
} }
else else
{ {
/* update timestamp (block_index) */ /*
((WavpackHeader*)head_buffer)->block_index = htole32(num_pcm_sampl); * |llllllllllllllll|rrrrrrrrrrrrrrrr| =>
* |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
*/
inline void to_int32(int32_t **src, int32_t **dst)
{
int32_t t = *(*src)++;
#ifdef ROCKBOX_BIG_ENDIAN
*(*dst)++ = t >> 16, *(*dst)++ = (int16_t)t;
#else
*(*dst)++ = (int16_t)t, *(*dst)++ = t >> 16;
#endif
} /* to_int32 */
do
{
/* read 10 longs and write 20 longs */
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
to_int32(&src, &dst);
}
while (src < src_end);
return;
} }
} } /* chunk_to_int32 */
/* called very often - inline */
enum codec_status codec_start(struct codec_api* api) static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
static inline bool is_file_data_ok(struct enc_file_event_data *data)
{ {
int i; return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
long t; } /* is_file_data_ok */
uint32 *src;
uint32 *dst;
int chunk_size, num_chunks, samp_per_chunk;
int enc_buffer_size;
int enc_quality;
WavpackConfig config;
WavpackContext *wpc;
bool cpu_boosted = true; /* start boosted */
ci = api; // copy to global api pointer /* called very often - inline */
static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
static inline bool on_write_chunk(struct enc_file_event_data *data)
{
if (!is_file_data_ok(data))
return false;
if (data->chunk->enc_data == NULL)
{
#ifdef ROCKBOX_HAS_LOGF
ci->logf("wvpk enc: NULL data");
#endif
return true;
}
/* update timestamp (block_index) */
((WavpackHeader *)data->chunk->enc_data)->block_index =
htole32(data->num_pcm_samples);
if (ci->write(data->rec_file, data->chunk->enc_data,
data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
return false;
data->num_pcm_samples += data->chunk->num_pcm;
return true;
} /* on_write_chunk */
static bool on_start_file(struct enc_file_event_data *data)
{
if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
return false;
data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
if (data->rec_file < 0)
return false;
/* reset sample count */
data->num_pcm_samples = 0;
/* write template headers */
if (ci->write(data->rec_file, &wvpk_mdh, sizeof (wvpk_mdh))
!= sizeof (wvpk_mdh) ||
ci->write(data->rec_file, &riff_header, sizeof (riff_header))
!= sizeof (riff_header))
{
return false;
}
data->new_enc_size += sizeof(wvpk_mdh) + sizeof(riff_header);
return true;
} /* on_start_file */
static bool on_end_file(struct enc_file_event_data *data)
{
struct
{
WavpackMetadataHeader wpmdh;
struct riff_header rhdr;
WavpackHeader wph;
} __attribute__ ((packed)) h;
uint32_t data_size;
if (!is_file_data_ok(data))
return false;
/* read template headers at start */
if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
ci->read(data->rec_file, &h, sizeof (h)) != sizeof (h))
return false;
data_size = data->num_pcm_samples*config.num_channels*PCM_DEPTH_BYTES;
/** "RIFF" header **/
h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE +
RIFF_FMT_DATA_SIZE + RIFF_DATA_HEADER_SIZE + data_size);
/* format data */
h.rhdr.num_channels = htole16(config.num_channels);
h.rhdr.sample_rate = htole32(config.sample_rate);
h.rhdr.byte_rate = htole32(config.sample_rate*config.num_channels*
PCM_DEPTH_BYTES);
h.rhdr.block_align = htole16(config.num_channels*PCM_DEPTH_BYTES);
/* data header */
h.rhdr.data_size = htole32(data_size);
/** Wavpack header **/
h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh)
+ sizeof (h.rhdr));
h.wph.total_samples = htole32(data->num_pcm_samples);
/* MDH|RIFF|WVPK => WVPK|MDH|RIFF */
if (ci->lseek(data->rec_file, 0, SEEK_SET)
!= 0 ||
ci->write(data->rec_file, &h.wph, sizeof (h.wph))
!= sizeof (h.wph) ||
ci->write(data->rec_file, &h.wpmdh, sizeof (h.wpmdh))
!= sizeof (h.wpmdh) ||
ci->write(data->rec_file, &h.rhdr, sizeof (h.rhdr))
!= sizeof (h.rhdr))
{
return false;
}
ci->fsync(data->rec_file);
ci->close(data->rec_file);
data->rec_file = -1;
return true;
} /* on_end_file */
static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR;
static void enc_events_callback(enum enc_events event, void *data)
{
if (event == ENC_WRITE_CHUNK)
{
if (on_write_chunk((struct enc_file_event_data *)data))
return;
}
else if (event == ENC_START_FILE)
{
/* write metadata header and RIFF header */
if (on_start_file((struct enc_file_event_data *)data))
return;
}
else if (event == ENC_END_FILE)
{
if (on_end_file((struct enc_file_event_data *)data))
return;
}
else
{
return;
}
((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
} /* enc_events_callback */
static bool init_encoder(void)
{
struct enc_inputs inputs;
struct enc_parameters params;
codec_init(ci); codec_init(ci);
if(ci->enc_get_inputs == NULL || if (ci->enc_get_inputs == NULL ||
ci->enc_set_parameters == NULL || ci->enc_set_parameters == NULL ||
ci->enc_alloc_chunk == NULL || ci->enc_get_chunk == NULL ||
ci->enc_free_chunk == NULL || ci->enc_finish_chunk == NULL ||
ci->enc_wavbuf_near_empty == NULL || ci->enc_pcm_buf_near_empty == NULL ||
ci->enc_get_wav_data == NULL || ci->enc_get_pcm_data == NULL ||
ci->enc_set_header_callback == NULL ) ci->enc_unget_pcm_data == NULL )
return CODEC_ERROR; return false;
ci->cpu_boost(true); ci->enc_get_inputs(&inputs);
*ci->enc_set_header_callback = enc_set_header; if (inputs.config->afmt != AFMT_WAVPACK)
ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); return false;
/* configure the buffer system */ memset(&config, 0, sizeof (config));
chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; config.bits_per_sample = PCM_DEPTH_BITS;
num_chunks = enc_buffer_size / chunk_size; config.bytes_per_sample = PCM_DEPTH_BYTES;
samp_per_chunk = CHUNK_SIZE / 4; config.sample_rate = inputs.sample_rate;
config.num_channels = inputs.num_channels;
/* inform the main program about buffer dimensions and other params */
/* add wav_header_mono as place holder to file start position */
/* wav header and wvpk header have to be reordered later */
ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk,
wav_header_mono, sizeof(wav_header_mono),
AFMT_WAVPACK);
wpc = WavpackOpenFileOutput (); wpc = WavpackOpenFileOutput ();
memset (&config, 0, sizeof (config)); if (!WavpackSetConfiguration(wpc, &config, -1))
config.bits_per_sample = 16; return false;
config.bytes_per_sample = 2;
config.sample_rate = 44100;
config.num_channels = enc_channels;
if (!WavpackSetConfiguration (wpc, &config, 1)) /* configure the buffer system */
params.afmt = AFMT_WAVPACK;
input_size = PCM_CHUNK_SIZE*inputs.num_channels / 2;
data_size = 105*input_size / 100;
input_size *= 2;
input_step = input_size / 4;
params.chunk_size = data_size;
params.enc_sample_rate = inputs.sample_rate;
params.reserve_bytes = 0;
params.events_callback = enc_events_callback;
ci->enc_set_parameters(&params);
return true;
} /* init_encoder */
enum codec_status codec_start(struct codec_api* api)
{
bool cpu_boosted;
ci = api; /* copy to global api pointer */
#ifdef USE_IRAM
ci->memcpy(iramstart, iramcopy, iramend - iramstart);
ci->memset(iedata, 0, iend - iedata);
#endif
/* initialize params and config */
if (!init_encoder())
{
ci->enc_codec_loaded = -1;
return CODEC_ERROR; return CODEC_ERROR;
}
/* main application waits for this flag during encoder loading */ /* main application waits for this flag during encoder loading */
ci->enc_codec_loaded = true; ci->enc_codec_loaded = 1;
ci->cpu_boost(true);
cpu_boosted = true;
/* main encoding loop */ /* main encoding loop */
while(!ci->stop_codec) while(!ci->stop_codec)
{ {
while((src = (uint32*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) uint8_t *src;
while ((src = ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
{ {
struct enc_chunk_hdr *chunk;
bool abort_chunk;
uint8_t *dst;
uint8_t *src_end;
if(ci->stop_codec) if(ci->stop_codec)
break; break;
if(ci->enc_wavbuf_near_empty() == 0) abort_chunk = true;
if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
{ {
if(!cpu_boosted) ci->cpu_boost(true);
{ cpu_boosted = true;
ci->cpu_boost(true);
cpu_boosted = true;
}
} }
dst = (uint32*)ci->enc_alloc_chunk() + 1; chunk = ci->enc_get_chunk();
WavpackStartBlock (wpc, (uint8*)dst, (uint8*)dst + CHUNK_SIZE); /* reset counts and pointer */
chunk->enc_size = 0;
chunk->num_pcm = 0;
chunk->enc_data = NULL;
if(enc_channels == 2) dst = ENC_CHUNK_SKIP_HDR(dst, chunk);
WavpackStartBlock(wpc, dst, dst + data_size);
chunk_to_int32((uint32_t*)src);
src = input_buffer;
src_end = src + input_size;
/* encode chunk in four steps yielding between each */
do
{ {
for (i=0; i<CHUNK_SIZE/4; i++) if (WavpackPackSamples(wpc, (int32_t *)src,
PCM_SAMP_PER_CHUNK/4))
{ {
t = (long)*src++; chunk->num_pcm += PCM_SAMP_PER_CHUNK/4;
ci->yield();
input_buffer[2*i + 0] = t >> 16; /* could've been stopped in some way */
input_buffer[2*i + 1] = (short)t; abort_chunk = ci->stop_codec ||
(chunk->flags & CHUNKF_ABORT);
} }
src += input_step;
} }
else while (!abort_chunk && src < src_end);
if (!abort_chunk)
{ {
for (i=0; i<CHUNK_SIZE/4; i++) chunk->enc_data = dst;
{ if (chunk->num_pcm < PCM_SAMP_PER_CHUNK)
t = (long)*src++; ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4);
t = (((t<<16)>>16) + (t>>16)) >> 1; /* left+right */
input_buffer[i] = t;
}
}
if (!WavpackPackSamples (wpc, input_buffer, CHUNK_SIZE/4))
return CODEC_ERROR;
/* finish the chunk and store chunk size info */ /* finish the chunk and store chunk size info */
dst[-1] = WavpackFinishBlock (wpc); chunk->enc_size = WavpackFinishBlock(wpc);
ci->enc_finish_chunk();
ci->enc_free_chunk();
ci->yield();
}
if(ci->enc_wavbuf_near_empty())
{
if(cpu_boosted)
{
ci->cpu_boost(false);
cpu_boosted = false;
} }
} }
if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0)
{
ci->cpu_boost(false);
cpu_boosted = false;
}
ci->yield(); ci->yield();
} }
if(cpu_boosted) /* set initial boost state */ if (cpu_boosted) /* set initial boost state */
ci->cpu_boost(false); ci->cpu_boost(false);
/* reset parameters to initial state */ /* reset parameters to initial state */
ci->enc_set_parameters(0, 0, 0, 0, 0, 0); ci->enc_set_parameters(NULL);
/* main application waits for this flag during encoder removing */ /* main application waits for this flag during encoder removing */
ci->enc_codec_loaded = false; ci->enc_codec_loaded = 0;
return CODEC_OK; return CODEC_OK;
} } /* codec_start */
#endif
#endif /* ndef SIMULATOR */

View file

@ -710,7 +710,8 @@ static bool eq_save_preset(void)
char filename[MAX_PATH]; char filename[MAX_PATH];
int *setting; int *setting;
create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2); create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2
IF_CNFN_NUM_(, NULL));
/* allow user to modify filename */ /* allow user to modify filename */
while (true) { while (true) {

View file

@ -124,19 +124,6 @@
#endif #endif
#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \
STATUSBAR_DISK_WIDTH STATUSBAR_DISK_WIDTH
#if defined(HAVE_RECORDING)
/* analogue frequency numbers taken from the order of frequencies in sample_rate */
#define FREQ_44 7
#define FREQ_48 8
#define FREQ_32 6
#define FREQ_22 4
#define FREQ_24 5
#define FREQ_16 3
#ifdef HAVE_SPDIF_IN
#define SOURCE_SPDIF 2
#endif
#endif
struct gui_syncstatusbar statusbars; struct gui_syncstatusbar statusbars;
void gui_statusbar_init(struct gui_statusbar * bar) void gui_statusbar_init(struct gui_statusbar * bar)
@ -600,41 +587,113 @@ void gui_statusbar_time(struct screen * display, int hour, int minute)
#endif #endif
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
#if CONFIG_CODEC == SWCODEC
/**
* Write a number to the display using bitmaps and return new position
*/
static int write_bitmap_number(struct screen * display, int value,
int x, int y)
{
char buf[12], *ptr;
snprintf(buf, sizeof(buf), "%d", value);
for (ptr = buf; *ptr != '\0'; ptr++, x += BM_GLYPH_WIDTH)
display->mono_bitmap(bitmap_glyphs_4x8[*ptr - '0'], x, y,
BM_GLYPH_WIDTH, STATUSBAR_HEIGHT);
return x;
}
/**
* Write format info bitmaps - right justified
*/
static void gui_statusbar_write_format_info(struct screen * display)
{
/* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED
so must use icons */
int rec_format = global_settings.rec_format;
unsigned bitrk = 0; /* compiler warns about unitialized use !! */
int xpos = STATUSBAR_ENCODER_X_POS;
int width = STATUSBAR_ENCODER_WIDTH;
const unsigned char *bm = bitmap_formats_18x8[rec_format];
if (rec_format == REC_FORMAT_MPA_L3)
{
/* Special handling for mp3 */
bitrk = global_settings.mp3_enc_config.bitrate;
bitrk = mp3_enc_bitr[bitrk];
width = BM_MPA_L3_M_WIDTH;
/* Slide 'M' to right if fewer than three digits used */
if (bitrk > 999)
bitrk = 999; /* neurotic safety check if corrupted */
else
{
if (bitrk < 100)
xpos += BM_GLYPH_WIDTH;
if (bitrk < 10)
xpos += BM_GLYPH_WIDTH;
}
}
/* Show bitmap - clipping right edge if needed */
display->mono_bitmap_part(bm, 0, 0, STATUSBAR_ENCODER_WIDTH,
xpos, STATUSBAR_Y_POS, width, STATUSBAR_HEIGHT);
if (rec_format == REC_FORMAT_MPA_L3)
{
xpos += BM_MPA_L3_M_WIDTH; /* to right of 'M' */
write_bitmap_number(display, bitrk, xpos, STATUSBAR_Y_POS);
}
}
/**
* Write sample rate using bitmaps - left justified
*/
static void gui_statusbar_write_samplerate_info(struct screen * display)
{
unsigned long samprk;
int xpos;
#ifdef SIMULATOR
samprk = 44100;
#else
#ifdef HAVE_SPDIF_IN
if (global_settings.rec_source == AUDIO_SRC_SPDIF)
/* Use rate in use, not current measured rate if it changed */
samprk = pcm_rec_sample_rate();
else
#endif
samprk = rec_freq_sampr[global_settings.rec_frequency];
#endif /* SIMULATOR */
samprk /= 1000;
if (samprk > 99)
samprk = 99; /* Limit to 3 glyphs */
xpos = write_bitmap_number(display, (unsigned)samprk,
STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS);
/* write the 'k' */
display->mono_bitmap(bitmap_glyphs_4x8[Glyph_4x8_k], xpos,
STATUSBAR_Y_POS, BM_GLYPH_WIDTH,
STATUSBAR_HEIGHT);
}
#endif /* CONFIG_CODEC == SWCODEC */
void gui_statusbar_icon_recording_info(struct screen * display) void gui_statusbar_icon_recording_info(struct screen * display)
{ {
#if (CONFIG_CODEC != SWCODEC) || (defined(SIMULATOR) && defined(HAVE_SPDIF_IN))
char buffer[3];
#endif
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
char buffer[3];
int width, height; int width, height;
static char* const sample_rate[12] =
{
"8",
"11",
"12",
"16",
"22",
"24",
"32",
"44",
"48",
"64",
"88",
"96"
};
display->setfont(FONT_SYSFIXED); display->setfont(FONT_SYSFIXED);
#endif #endif /* CONFIG_CODEC != SWCODEC */
/* Display Codec info in statusbar */ /* Display Codec info in statusbar */
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
/* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED gui_statusbar_write_format_info(display);
so must use icons */ #else /* !SWCODEC */
display->mono_bitmap(bitmap_icons_18x8[global_settings.rec_quality],
STATUSBAR_ENCODER_X_POS, STATUSBAR_Y_POS,
STATUSBAR_ENCODER_WIDTH, STATUSBAR_HEIGHT);
#else
display->mono_bitmap(bitmap_icons_5x8[Icon_q], display->mono_bitmap(bitmap_icons_5x8[Icon_q],
STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS, STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS,
5, STATUSBAR_HEIGHT); 5, STATUSBAR_HEIGHT);
@ -643,56 +702,37 @@ void gui_statusbar_icon_recording_info(struct screen * display)
display->getstringsize(buffer, &width, &height); display->getstringsize(buffer, &width, &height);
if (height <= STATUSBAR_HEIGHT) if (height <= STATUSBAR_HEIGHT)
display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer); display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer);
#endif #endif /* CONFIG_CODEC == SWCODEC */
/* Display Samplerate info in statusbar */ /* Display Samplerate info in statusbar */
#if defined(HAVE_SPDIF_IN) #if CONFIG_CODEC == SWCODEC
if (global_settings.rec_source == SOURCE_SPDIF) /* SWCODEC targets use bitmaps for glyphs */
gui_statusbar_write_samplerate_info(display);
#else /* !SWCODEC */
/* hwcodec targets have sysfont characters */
#ifdef HAVE_SPDIF_IN
if (global_settings.rec_source == AUDIO_SRC_SPDIF)
{ {
#if (CONFIG_CODEC != MAS3587F) && !defined(SIMULATOR)
display->mono_bitmap(bitmap_icons_12x8[audio_get_spdif_sample_rate()],
STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS,
STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT);
#else
/* Can't measure S/PDIF sample rate on Archos/Sim yet */ /* Can't measure S/PDIF sample rate on Archos/Sim yet */
snprintf(buffer, sizeof(buffer), "--"); snprintf(buffer, sizeof(buffer), "--");
#endif
} }
else else
#endif /* HAVE_SPDIF_IN */ #endif /* HAVE_SPDIF_IN */
{ {
/* Analogue frequency in wrong order so remap settings numbers */ static char const * const freq_strings[12] =
int freq = global_settings.rec_frequency; { "44", "48", "32", "22", "24", "16" };
if (freq == 0) snprintf(buffer, sizeof(buffer), "%s",
freq = FREQ_44; freq_strings[global_settings.rec_frequency]);
else if (freq == 1)
freq = FREQ_48;
else if (freq == 2)
freq = FREQ_32;
else if (freq == 3)
freq = FREQ_22;
else if (freq == 4)
freq = FREQ_24;
else if (freq == 5)
freq = FREQ_16;
#if CONFIG_CODEC == SWCODEC
/* samplerate icons for swcodec targets*/
display->mono_bitmap(bitmap_icons_12x8[freq],
STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS,
STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT);
}
#else
/* hwcodec targets have sysfont characters */
snprintf(buffer, sizeof(buffer), "%s", sample_rate[freq]);
display->getstringsize(buffer, &width, &height);
} }
if (height <= STATUSBAR_HEIGHT) display->getstringsize(buffer, &width, &height);
display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer);
if (height <= STATUSBAR_HEIGHT)
display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer);
display->setfont(FONT_UI);
#endif /* CONFIG_CODEC == SWCODEC */
display->setfont(FONT_UI);
#endif
/* Display Channel status in status bar */ /* Display Channel status in status bar */
if(global_settings.rec_channels) if(global_settings.rec_channels)
{ {

View file

@ -9802,7 +9802,7 @@
</phrase> </phrase>
<phrase> <phrase>
id: VOICE_KBIT_PER_SEC id: VOICE_KBIT_PER_SEC
desc: spoken only, for file extension desc: spoken only, a unit postfix
user: user:
<source> <source>
*: "" *: ""
@ -10032,3 +10032,115 @@
*: "" *: ""
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_RECORDING_FORMAT
desc: audio format item in recording menu
user:
<source>
*: "Format"
</source>
<dest>
*: "Format"
</dest>
<voice>
*: "Format"
</voice>
</phrase>
<phrase>
id: LANG_AFMT_MPA_L3
desc: audio format description
user:
<source>
*: "MPEG Layer 3"
</source>
<dest>
*: "MPEG Layer 3"
</dest>
<voice>
*: "MPEG Layer 3"
</voice>
</phrase>
<phrase>
id: LANG_AFMT_PCM_WAV
desc: audio format description
user:
<source>
*: "PCM Wave"
</source>
<dest>
*: "PCM Wave"
</dest>
<voice>
*: "PCM Wave"
</voice>
</phrase>
<phrase>
id: LANG_AFMT_WAVPACK
desc: audio format description
user:
<source>
*: "WavPack"
</source>
<dest>
*: "WavPack"
</dest>
<voice>
*: "WavPack"
</voice>
</phrase>
<phrase>
id: LANG_ENCODER_SETTINGS
desc: encoder settings
user:
<source>
*: "Encoder Settings"
</source>
<dest>
*: "Encoder Settings"
</dest>
<voice>
*: "Encoder Settings"
</voice>
</phrase>
<phrase>
id: LANG_NO_SETTINGS
desc: when something has settings in a certain context
user:
<source>
*: "(No Settings)"
</source>
<dest>
*: "(No Settings)"
</dest>
<voice>
*: "No settings available"
</voice>
</phrase>
<phrase>
id: LANG_SOURCE_FREQUENCY
desc: when recording source frequency setting must follow source
user:
<source>
*: "(Same As Source)"
</source>
<dest>
*: "(Same As Source)"
</dest>
<voice>
*: "Same As Source"
</voice>
</phrase>
<phrase>
id: LANG_BITRATE
desc: bits-kilobits per unit time
user:
<source>
*: "Bitrate"
</source>
<dest>
*: "Bitrate"
</dest>
<voice>
*: "Bitrate"
</voice>
</phrase>

View file

@ -286,6 +286,9 @@ void init(void)
#ifdef HAVE_ADJUSTABLE_CPU_FREQ #ifdef HAVE_ADJUSTABLE_CPU_FREQ
set_cpu_frequency(CPUFREQ_NORMAL); set_cpu_frequency(CPUFREQ_NORMAL);
#ifdef CPU_COLDFIRE
coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
#endif
cpu_boost_id(true, CPUBOOSTID_MAININIT); cpu_boost_id(true, CPUBOOSTID_MAININIT);
#endif #endif

View file

@ -88,36 +88,6 @@ struct apetag_item_header
long flags; long flags;
}; };
struct format_list
{
char format;
char extension[5];
};
static const struct format_list formats[] =
{
{ AFMT_MPA_L1, "mp1" },
{ AFMT_MPA_L2, "mp2" },
{ AFMT_MPA_L2, "mpa" },
{ AFMT_MPA_L3, "mp3" },
#if CONFIG_CODEC == SWCODEC
{ AFMT_OGG_VORBIS, "ogg" },
{ AFMT_PCM_WAV, "wav" },
{ AFMT_FLAC, "flac" },
{ AFMT_MPC, "mpc" },
{ AFMT_A52, "a52" },
{ AFMT_A52, "ac3" },
{ AFMT_WAVPACK, "wv" },
{ AFMT_ALAC, "m4a" },
{ AFMT_AAC, "mp4" },
{ AFMT_SHN, "shn" },
{ AFMT_AIFF, "aif" },
{ AFMT_AIFF, "aiff" },
{ AFMT_SID, "sid" },
{ AFMT_ADX, "adx" },
#endif
};
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
static const unsigned short a52_bitrates[] = static const unsigned short a52_bitrates[] =
{ {
@ -1691,14 +1661,24 @@ unsigned int probe_file_format(const char *filename)
return AFMT_UNKNOWN; return AFMT_UNKNOWN;
} }
suffix += 1; /* skip '.' */
suffix++;
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++)
for (i = 1; i < AFMT_NUM_CODECS; i++)
{ {
if (strcasecmp(suffix, formats[i].extension) == 0) /* search extension list for type */
const char *ext = audio_formats[i].ext_list;
do
{
if (strcasecmp(suffix, ext) == 0)
{ {
return formats[i].format; return i;
}
ext += strlen(ext) + 1;
} }
while (*ext != '\0');
} }
return AFMT_UNKNOWN; return AFMT_UNKNOWN;

View file

@ -58,6 +58,8 @@
#endif /* End HAVE_LCD_BITMAP */ #endif /* End HAVE_LCD_BITMAP */
#include "gui/gwps-common.h" #include "gui/gwps-common.h"
#include "misc.h"
/* Format a large-range value for output, using the appropriate unit so that /* Format a large-range value for output, using the appropriate unit so that
* the displayed value is in the range 1 <= display < 1000 (1024 for "binary" * the displayed value is in the range 1 <= display < 1000 (1024 for "binary"
* units) if possible, and 3 significant digits are shown. If a buffer is * units) if possible, and 3 significant digits are shown. If a buffer is
@ -114,16 +116,20 @@ char *output_dyn_value(char *buf, int buf_size, int value,
} }
/* Create a filename with a number part in a way that the number is 1 /* Create a filename with a number part in a way that the number is 1
higher than the highest numbered file matching the same pattern. * higher than the highest numbered file matching the same pattern.
It is allowed that buffer and path point to the same memory location, * It is allowed that buffer and path point to the same memory location,
saving a strcpy(). Path must always be given without trailing slash,. */ * saving a strcpy(). Path must always be given without trailing slash.
* "num" can point to an int specifying the number to use or NULL or a value
* less than zero to number automatically. The final number used will also
* be returned in *num. If *num is >= 0 then *num will be incremented by
* one. */
char *create_numbered_filename(char *buffer, const char *path, char *create_numbered_filename(char *buffer, const char *path,
const char *prefix, const char *suffix, const char *prefix, const char *suffix,
int numberlen) int numberlen IF_CNFN_NUM_(, int *num))
{ {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
int max_num = 0; int max_num;
int pathlen; int pathlen;
int prefixlen = strlen(prefix); int prefixlen = strlen(prefix);
char fmtstring[12]; char fmtstring[12];
@ -133,6 +139,18 @@ char *create_numbered_filename(char *buffer, const char *path,
pathlen = strlen(buffer); pathlen = strlen(buffer);
#ifdef IF_CNFN_NUM
if (num && *num >= 0)
{
/* number specified */
max_num = *num;
}
else
#endif
{
/* automatic numbering */
max_num = 0;
dir = opendir(pathlen ? buffer : "/"); dir = opendir(pathlen ? buffer : "/");
if (!dir) if (!dir)
return NULL; return NULL;
@ -149,11 +167,20 @@ char *create_numbered_filename(char *buffer, const char *path,
if (curr_num > max_num) if (curr_num > max_num)
max_num = curr_num; max_num = curr_num;
} }
closedir(dir); closedir(dir);
}
max_num++;
snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen); snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix, snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix,
max_num + 1, suffix); max_num, suffix);
#ifdef IF_CNFN_NUM
if (num)
*num = max_num;
#endif
return buffer; return buffer;
} }
@ -161,13 +188,22 @@ char *create_numbered_filename(char *buffer, const char *path,
#ifdef CONFIG_RTC #ifdef CONFIG_RTC
/* Create a filename with a date+time part. /* Create a filename with a date+time part.
It is allowed that buffer and path point to the same memory location, It is allowed that buffer and path point to the same memory location,
saving a strcpy(). Path must always be given without trailing slash. */ saving a strcpy(). Path must always be given without trailing slash.
unique_time as true makes the function wait until the current time has
changed. */
char *create_datetime_filename(char *buffer, const char *path, char *create_datetime_filename(char *buffer, const char *path,
const char *prefix, const char *suffix) const char *prefix, const char *suffix,
bool unique_time)
{ {
struct tm *tm = get_time(); struct tm *tm = get_time();
static struct tm last_tm;
int pathlen; int pathlen;
while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
sleep(HZ/10);
last_tm = *tm;
if (buffer != path) if (buffer != path)
strncpy(buffer, path, MAX_PATH); strncpy(buffer, path, MAX_PATH);
@ -356,9 +392,10 @@ void screen_dump(void)
#endif #endif
#ifdef CONFIG_RTC #ifdef CONFIG_RTC
create_datetime_filename(filename, "", "dump ", ".bmp"); create_datetime_filename(filename, "", "dump ", ".bmp", false);
#else #else
create_numbered_filename(filename, "", "dump_", ".bmp", 4); create_numbered_filename(filename, "", "dump_", ".bmp", 4
IF_CNFN_NUM_(, NULL));
#endif #endif
fh = creat(filename, O_WRONLY); fh = creat(filename, O_WRONLY);

View file

@ -19,21 +19,46 @@
#ifndef MISC_H #ifndef MISC_H
#define MISC_H #define MISC_H
#include <stdbool.h>
/* Format a large-range value for output, using the appropriate unit so that /* Format a large-range value for output, using the appropriate unit so that
* the displayed value is in the range 1 <= display < 1000 (1024 for "binary" * the displayed value is in the range 1 <= display < 1000 (1024 for "binary"
* units) if possible, and 3 significant digits are shown. If a buffer is * units) if possible, and 3 significant digits are shown. If a buffer is
* given, the result is snprintf()'d into that buffer, otherwise the result is * given, the result is snprintf()'d into that buffer, otherwise the result is
* voiced.*/ * voiced.*/
void output_dyn_value(char *buf, int buf_size, int value, char *output_dyn_value(char *buf, int buf_size, int value,
const unsigned char **units, bool bin_scale); const unsigned char **units, bool bin_scale);
/* Create a filename with a number part in a way that the number is 1
* higher than the highest numbered file matching the same pattern.
* It is allowed that buffer and path point to the same memory location,
* saving a strcpy(). Path must always be given without trailing slash.
*
* "num" can point to an int specifying the number to use or NULL or a value
* less than zero to number automatically. The final number used will also
* be returned in *num. If *num is >= 0 then *num will be incremented by
* one. */
#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(CONFIG_RTC)
/* this feature is needed by SWCODEC recording without a RTC to prevent
disk access when changing files */
#define IF_CNFN_NUM_(...) __VA_ARGS__
#define IF_CNFN_NUM
#else
#define IF_CNFN_NUM_(...)
#endif
char *create_numbered_filename(char *buffer, const char *path, char *create_numbered_filename(char *buffer, const char *path,
const char *prefix, const char *suffix, const char *prefix, const char *suffix,
int numberlen); int numberlen IF_CNFN_NUM_(, int *num));
#ifdef CONFIG_RTC #ifdef CONFIG_RTC
/* Create a filename with a date+time part.
It is allowed that buffer and path point to the same memory location,
saving a strcpy(). Path must always be given without trailing slash.
unique_time as true makes the function wait until the current time has
changed. */
char *create_datetime_filename(char *buffer, const char *path, char *create_datetime_filename(char *buffer, const char *path,
const char *prefix, const char *suffix); const char *prefix, const char *suffix,
#endif bool unique_time);
#endif /* CONFIG_RTC */
/* Read (up to) a line of text from fd into buffer and return number of bytes /* Read (up to) a line of text from fd into buffer and return number of bytes
* read (which may be larger than the number of bytes stored in buffer). If * read (which may be larger than the number of bytes stored in buffer). If
@ -57,4 +82,4 @@ long default_event_handler(long event);
void car_adapter_mode_init(void); void car_adapter_mode_init(void);
extern int show_logo(void); extern int show_logo(void);
#endif #endif /* MISC_H */

View file

@ -51,9 +51,11 @@ struct pcmbufdesc
void (*callback)(void); void (*callback)(void);
}; };
#define PCMBUF_DESCS(bufsize) ((bufsize) / PCMBUF_MINAVG_CHUNK)
/* Size of the PCM buffer. */ /* Size of the PCM buffer. */
static size_t pcmbuf_size IDATA_ATTR = 0; static size_t pcmbuf_size IDATA_ATTR = 0;
static char *pcmbuf_bufend IDATA_ATTR;
static char *audiobuffer IDATA_ATTR; static char *audiobuffer IDATA_ATTR;
/* Current audio buffer write index. */ /* Current audio buffer write index. */
static size_t audiobuffer_pos IDATA_ATTR; static size_t audiobuffer_pos IDATA_ATTR;
@ -360,7 +362,7 @@ int pcmbuf_used_descs(void) {
} }
int pcmbuf_descs(void) { int pcmbuf_descs(void) {
return pcmbuf_size / PCMBUF_MINAVG_CHUNK; return PCMBUF_DESCS(pcmbuf_size);
} }
size_t get_pcmbuf_descsize(void) { size_t get_pcmbuf_descsize(void) {
@ -371,28 +373,37 @@ static void pcmbuf_init_pcmbuffers(void) {
struct pcmbufdesc *next = pcmbuf_write; struct pcmbufdesc *next = pcmbuf_write;
next++; next++;
pcmbuf_write_end = pcmbuf_write; pcmbuf_write_end = pcmbuf_write;
while ((void *)next < (void *)audiobufend) { while ((void *)next < (void *)pcmbuf_bufend) {
pcmbuf_write_end->link=next; pcmbuf_write_end->link=next;
pcmbuf_write_end=next; pcmbuf_write_end=next;
next++; next++;
} }
} }
bool pcmbuf_is_same_size(size_t bufsize)
{
/* keep calculations synced with pcmbuf_init */
bufsize += PCMBUF_MIX_CHUNK * 2 + PCMBUF_DESCS(bufsize);
return bufsize == (size_t)(pcmbuf_bufend - audiobuffer);
}
/* Initialize the pcmbuffer the structure looks like this: /* Initialize the pcmbuffer the structure looks like this:
* ...CODECBUFFER|---------PCMBUF---------|GUARDBUF|DESCS| */ * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
void pcmbuf_init(size_t bufsize) size_t pcmbuf_init(size_t bufsize, char *bufend)
{ {
pcmbuf_size = bufsize; pcmbuf_size = bufsize;
pcmbuf_bufend = bufend;
pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc); pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc);
audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - audiobuffer = pcmbuf_bufend - (pcmbuf_size + PCMBUF_MIX_CHUNK * 2
(pcmbuf_size + PCMBUF_MIX_CHUNK * 2 + pcmbuf_descsize)]; + pcmbuf_descsize);
fadebuf = &audiobuffer[pcmbuf_size]; fadebuf = &audiobuffer[pcmbuf_size];
voicebuf = &fadebuf[PCMBUF_MIX_CHUNK]; voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
pcmbuf_write = (struct pcmbufdesc *)(&voicebuf[PCMBUF_MIX_CHUNK]); pcmbuf_write = (struct pcmbufdesc *)&voicebuf[PCMBUF_MIX_CHUNK];
pcmbuf_init_pcmbuffers(); pcmbuf_init_pcmbuffers();
position_callback = NULL; position_callback = NULL;
pcmbuf_event_handler = NULL; pcmbuf_event_handler = NULL;
pcmbuf_play_stop(); pcmbuf_play_stop();
return pcmbuf_bufend - audiobuffer;
} }
size_t pcmbuf_get_bufsize(void) size_t pcmbuf_get_bufsize(void)

View file

@ -38,7 +38,7 @@
/* Returns true if the buffer needs to change size */ /* Returns true if the buffer needs to change size */
bool pcmbuf_is_same_size(size_t bufsize); bool pcmbuf_is_same_size(size_t bufsize);
void pcmbuf_init(size_t bufsize); size_t pcmbuf_init(size_t bufsize, char *bufend);
/* Size in bytes used by the pcmbuffer */ /* Size in bytes used by the pcmbuffer */
size_t pcmbuf_get_bufsize(void); size_t pcmbuf_get_bufsize(void);
size_t get_pcmbuf_descsize(void); size_t get_pcmbuf_descsize(void);

View file

@ -54,8 +54,6 @@
#include "playlist.h" #include "playlist.h"
#include "playback.h" #include "playback.h"
#include "pcmbuf.h" #include "pcmbuf.h"
#include "pcm_playback.h"
#include "pcm_record.h"
#include "buffer.h" #include "buffer.h"
#include "dsp.h" #include "dsp.h"
#include "abrepeat.h" #include "abrepeat.h"
@ -78,6 +76,7 @@
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
#include "recording.h" #include "recording.h"
#include "talk.h"
#endif #endif
#define PLAYBACK_VOICE #define PLAYBACK_VOICE
@ -93,9 +92,13 @@
* for their correct seeek target, 32k seems a good size */ * for their correct seeek target, 32k seems a good size */
#define AUDIO_REBUFFER_GUESS_SIZE (1024*32) #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
/* macros to enable logf for queues */ /* macros to enable logf for queues
logging on SYS_TIMEOUT can be disabled */
#ifdef SIMULATOR #ifdef SIMULATOR
#define PLAYBACK_LOGQUEUES /* Define this for logf output of all queuing */ /* Define this for logf output of all queuing except SYS_TIMEOUT */
#define PLAYBACK_LOGQUEUES
/* Define this to logf SYS_TIMEOUT messages */
#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT
#endif #endif
#ifdef PLAYBACK_LOGQUEUES #ifdef PLAYBACK_LOGQUEUES
@ -104,6 +107,18 @@
#define LOGFQUEUE(s) #define LOGFQUEUE(s)
#endif #endif
#ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
#define LOGFQUEUE_SYS_TIMEOUT(s) logf("%s", s)
#else
#define LOGFQUEUE_SYS_TIMEOUT(s)
#endif
/* Define one constant that includes recording related functionality */
#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
#define AUDIO_HAVE_RECORDING
#endif
enum { enum {
Q_AUDIO_PLAY = 1, Q_AUDIO_PLAY = 1,
Q_AUDIO_STOP, Q_AUDIO_STOP,
@ -122,6 +137,9 @@ enum {
#if MEM > 8 #if MEM > 8
Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
#endif #endif
#ifdef AUDIO_HAVE_RECORDING
Q_AUDIO_LOAD_ENCODER,
#endif
Q_CODEC_REQUEST_PENDING, Q_CODEC_REQUEST_PENDING,
Q_CODEC_REQUEST_COMPLETE, Q_CODEC_REQUEST_COMPLETE,
@ -133,7 +151,7 @@ enum {
Q_CODEC_LOAD, Q_CODEC_LOAD,
Q_CODEC_LOAD_DISK, Q_CODEC_LOAD_DISK,
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #ifdef AUDIO_HAVE_RECORDING
Q_ENCODER_LOAD_DISK, Q_ENCODER_LOAD_DISK,
Q_ENCODER_RECORD, Q_ENCODER_RECORD,
#endif #endif
@ -178,11 +196,16 @@ static volatile bool paused; /* Is audio paused? (A/C-) */
static volatile bool filling IDATA_ATTR; /* Is file buffer currently being refilled? (A/C-) */ static volatile bool filling IDATA_ATTR; /* Is file buffer currently being refilled? (A/C-) */
/* Ring buffer where tracks and codecs are loaded */ /* Ring buffer where tracks and codecs are loaded */
static char *filebuf; /* Pointer to start of ring buffer (A/C-) */ static unsigned char *filebuf; /* Pointer to start of ring buffer (A/C-) */
size_t filebuflen; /* Total size of the ring buffer FIXME: make static (A/C-)*/ size_t filebuflen; /* Total size of the ring buffer FIXME: make static (A/C-)*/
static volatile size_t buf_ridx IDATA_ATTR; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */ static volatile size_t buf_ridx IDATA_ATTR; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */
static volatile size_t buf_widx IDATA_ATTR; /* Ring buffer read position (A/C-) */ static volatile size_t buf_widx IDATA_ATTR; /* Ring buffer read position (A/C-) */
#define BUFFER_STATE_TRASHED -1 /* Buffer is in a trashed state and must be reset */
#define BUFFER_STATE_NORMAL 0 /* Buffer is arranged for voice and audio */
#define BUFFER_STATE_VOICED_ONLY 1 /* Buffer is arranged for voice-only use */
static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
#define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen) #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v) #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
#define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen) #define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
@ -235,7 +258,7 @@ static const char audio_thread_name[] = "audio";
static void audio_thread(void); static void audio_thread(void);
static void audio_initiate_track_change(long direction); static void audio_initiate_track_change(long direction);
static bool audio_have_tracks(void); static bool audio_have_tracks(void);
static void audio_reset_buffer(void); static void audio_reset_buffer(size_t pcmbufsize);
/* Codec thread */ /* Codec thread */
extern struct codec_api ci; extern struct codec_api ci;
@ -294,6 +317,10 @@ static void voice_thread(void);
void mp3_play_data(const unsigned char* start, int size, void mp3_play_data(const unsigned char* start, int size,
void (*get_more)(unsigned char** start, int* size)) void (*get_more)(unsigned char** start, int* size))
{ {
/* must reset the buffer before any playback begins if needed */
if (buffer_state == BUFFER_STATE_TRASHED)
audio_reset_buffer(pcmbuf_get_bufsize());
#ifdef PLAYBACK_VOICE #ifdef PLAYBACK_VOICE
static struct voice_info voice_clip; static struct voice_info voice_clip;
voice_clip.callback = get_more; voice_clip.callback = get_more;
@ -330,38 +357,95 @@ void mpeg_id3_options(bool _v1first)
v1first = _v1first; v1first = _v1first;
} }
void audio_load_encoder(int enc_id) unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
{ {
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) unsigned char *buf = audiobuf;
const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER); unsigned char *end = audiobufend;
audio_stop();
if (talk_buf || !talk_voice_required()
|| buffer_state == BUFFER_STATE_TRASHED)
{
logf("get buffer: talk_buf");
/* ok to use everything from audiobuf to audiobufend */
if (buffer_state != BUFFER_STATE_TRASHED)
talk_buffer_steal();
buffer_state = BUFFER_STATE_TRASHED;
}
else
{
/* skip talk buffer and move pcm buffer to end */
logf("get buffer: voice");
mp3_play_stop();
buf += talk_get_bufsize();
end -= pcmbuf_init(pcmbuf_get_bufsize(), audiobufend);
buffer_state = BUFFER_STATE_VOICED_ONLY;
}
*buffer_size = end - buf;
return buf;
}
#ifdef HAVE_RECORDING
unsigned char *audio_get_recording_buffer(size_t *buffer_size)
{
/* don't allow overwrite of voice swap area or we'll trash the
swapped-out voice codec but can use whole thing if none */
unsigned char *end = iram_buf[CODEC_IDX_VOICE] ?
iram_buf[CODEC_IDX_VOICE] : audiobufend;
audio_stop();
talk_buffer_steal();
buffer_state = BUFFER_STATE_TRASHED;
*buffer_size = end - audiobuf;
return (unsigned char *)audiobuf;
}
bool audio_load_encoder(int afmt)
{
#ifndef SIMULATOR
const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
if (!enc_fn) if (!enc_fn)
return; return false;
audio_remove_encoder(); audio_remove_encoder();
ci.enc_codec_loaded = 0; /* clear any previous error condition */
LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK"); LOGFQUEUE("audio > Q_AUDIO_LOAD_ENCODER");
queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn); queue_post(&audio_queue, Q_AUDIO_LOAD_ENCODER, (void *)enc_fn);
while (!ci.enc_codec_loaded) while (ci.enc_codec_loaded == 0)
yield(); yield();
logf("codec loaded: %d", ci.enc_codec_loaded);
return ci.enc_codec_loaded > 0;
#else
(void)afmt;
return true;
#endif #endif
return;
(void)enc_id;
} /* audio_load_encoder */ } /* audio_load_encoder */
void audio_remove_encoder(void) void audio_remove_encoder(void)
{ {
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #ifndef SIMULATOR
/* force encoder codec unload (if previously loaded) */ /* force encoder codec unload (if currently loaded) */
if (!ci.enc_codec_loaded) if (ci.enc_codec_loaded <= 0)
return; return;
ci.stop_codec = true; ci.stop_codec = true;
while (ci.enc_codec_loaded) while (ci.enc_codec_loaded > 0)
yield(); yield();
#endif #endif
} /* audio_remove_encoder */ } /* audio_remove_encoder */
#endif /* HAVE_RECORDING */
struct mp3entry* audio_current_track(void) struct mp3entry* audio_current_track(void)
{ {
const char *filename; const char *filename;
@ -553,6 +637,9 @@ void audio_flush_and_reload_tracks(void)
void audio_error_clear(void) void audio_error_clear(void)
{ {
#ifdef AUDIO_HAVE_RECORDING
pcm_rec_error_clear();
#endif
} }
int audio_status(void) int audio_status(void)
@ -573,11 +660,6 @@ int audio_status(void)
return ret; return ret;
} }
bool audio_query_poweroff(void)
{
return !(playing && paused);
}
int audio_get_file_pos(void) int audio_get_file_pos(void)
{ {
return 0; return 0;
@ -617,7 +699,7 @@ void audio_set_crossfade(int enable)
enable = 0; enable = 0;
size = NATIVE_FREQUENCY*2; size = NATIVE_FREQUENCY*2;
#endif #endif
if (pcmbuf_get_bufsize() == size) if (buffer_state == BUFFER_STATE_NORMAL && pcmbuf_is_same_size(size))
return ; return ;
if (was_playing) if (was_playing)
@ -633,9 +715,8 @@ void audio_set_crossfade(int enable)
voice_stop(); voice_stop();
/* Re-initialize audio system. */ /* Re-initialize audio system. */
pcmbuf_init(size); audio_reset_buffer(size);
pcmbuf_crossfade_enable(enable); pcmbuf_crossfade_enable(enable);
audio_reset_buffer();
logf("abuf:%dB", pcmbuf_get_bufsize()); logf("abuf:%dB", pcmbuf_get_bufsize());
logf("fbuf:%dB", filebuflen); logf("fbuf:%dB", filebuflen);
@ -714,8 +795,7 @@ void voice_stop(void)
{ {
#ifdef PLAYBACK_VOICE #ifdef PLAYBACK_VOICE
/* Messages should not be posted to voice codec queue unless it is the /* Messages should not be posted to voice codec queue unless it is the
current codec or deadlocks happen. current codec or deadlocks happen. */
-- jhMikeS */
if (current_codec != CODEC_IDX_VOICE) if (current_codec != CODEC_IDX_VOICE)
return; return;
@ -784,21 +864,32 @@ static void set_filebuf_watermark(int seconds)
conf_watermark = bytes; conf_watermark = bytes;
} }
static const char * get_codec_filename(int enc_spec) static const char * get_codec_filename(int cod_spec)
{ {
const char *fname; const char *fname;
int type = enc_spec & CODEC_TYPE_MASK;
int afmt = enc_spec & CODEC_AFMT_MASK; #ifdef HAVE_RECORDING
/* Can choose decoder or encoder if one available */
int type = cod_spec & CODEC_TYPE_MASK;
int afmt = cod_spec & CODEC_AFMT_MASK;
if ((unsigned)afmt >= AFMT_NUM_CODECS) if ((unsigned)afmt >= AFMT_NUM_CODECS)
type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK); type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
fname = (type == CODEC_TYPE_DECODER) ? fname = (type == CODEC_TYPE_ENCODER) ?
audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn; audio_formats[afmt].codec_enc_root_fn :
audio_formats[afmt].codec_root_fn;
logf("%s: %d - %s", logf("%s: %d - %s",
(type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder", (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
afmt, fname ? fname : "<unknown>"); afmt, fname ? fname : "<unknown>");
#else /* !HAVE_RECORDING */
/* Always decoder */
if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
cod_spec = AFMT_UNKNOWN;
fname = audio_formats[cod_spec].codec_root_fn;
logf("Codec: %d - %s", cod_spec, fname ? fname : "<unknown>");
#endif /* HAVE_RECORDING */
return fname; return fname;
} /* get_codec_filename */ } /* get_codec_filename */
@ -940,7 +1031,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
} }
break; break;
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_RECORD: case Q_ENCODER_RECORD:
LOGFQUEUE("voice < Q_ENCODER_RECORD"); LOGFQUEUE("voice < Q_ENCODER_RECORD");
swap_codec(); swap_codec();
@ -995,7 +1086,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
goto voice_play_clip; goto voice_play_clip;
case SYS_TIMEOUT: case SYS_TIMEOUT:
LOGFQUEUE("voice < SYS_TIMEOUT"); LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
goto voice_play_clip; goto voice_play_clip;
default: default:
@ -1773,7 +1864,7 @@ static void codec_thread(void)
#endif #endif
break ; break ;
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_LOAD_DISK: case Q_ENCODER_LOAD_DISK:
LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
audio_codec_loaded = false; /* Not audio codec! */ audio_codec_loaded = false; /* Not audio codec! */
@ -1785,12 +1876,14 @@ static void codec_thread(void)
} }
#endif #endif
mutex_lock(&mutex_codecthread); mutex_lock(&mutex_codecthread);
logf("loading encoder");
current_codec = CODEC_IDX_AUDIO; current_codec = CODEC_IDX_AUDIO;
ci.stop_codec = false; ci.stop_codec = false;
status = codec_load_file((const char *)ev.data, &ci); status = codec_load_file((const char *)ev.data, &ci);
mutex_unlock(&mutex_codecthread); mutex_unlock(&mutex_codecthread);
logf("encoder stopped");
break; break;
#endif #endif /* AUDIO_HAVE_RECORDING */
#ifndef SIMULATOR #ifndef SIMULATOR
case SYS_USB_CONNECTED: case SYS_USB_CONNECTED:
@ -1872,6 +1965,24 @@ static void codec_thread(void)
} }
break; break;
#ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_LOAD_DISK:
LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
if (status == CODEC_OK)
break;
logf("Encoder failure");
gui_syncsplash(HZ*2, true, "Encoder failure");
if (ci.enc_codec_loaded < 0)
break;
logf("Encoder failed to load");
ci.enc_codec_loaded = -1;
break;
#endif /* AUDIO_HAVE_RECORDING */
default: default:
LOGFQUEUE("codec < default"); LOGFQUEUE("codec < default");
@ -2992,6 +3103,10 @@ static void audio_play_start(size_t offset)
/* Wait for any previously playing audio to flush - TODO: Not necessary? */ /* Wait for any previously playing audio to flush - TODO: Not necessary? */
audio_stop_codec_flush(); audio_stop_codec_flush();
/* must reset the buffer before any playback begins if needed */
if (buffer_state != BUFFER_STATE_NORMAL)
audio_reset_buffer(pcmbuf_get_bufsize());
track_changed = true; track_changed = true;
playlist_end = false; playlist_end = false;
@ -3084,51 +3199,60 @@ static void audio_initiate_dir_change(long direction)
ci.new_track = direction; ci.new_track = direction;
} }
static void audio_reset_buffer(void) /*
* Layout audio buffer as follows:
* [|TALK]|MALLOC|FILE|GUARD|PCM|AUDIOCODEC|[VOICECODEC|]
*/
static void audio_reset_buffer(size_t pcmbufsize)
{ {
/* see audio_get_recording_buffer if this is modified */
size_t offset; size_t offset;
/* Set up file buffer as all space available */ logf("audio_reset_buffer");
filebuf = (char *)&audiobuf[talk_get_bufsize()+MALLOC_BUFSIZE]; logf(" size:%08X", pcmbufsize);
filebuflen = audiobufend - (unsigned char *) filebuf - GUARD_BUFSIZE -
(pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_MIX_CHUNK * 2);
/* Allow for codec(s) at end of file buffer */ /* Initially set up file buffer as all space available */
filebuf = audiobuf + MALLOC_BUFSIZE + talk_get_bufsize();
filebuflen = audiobufend - filebuf;
/* Allow for codec(s) at end of audio buffer */
if (talk_voice_required()) if (talk_voice_required())
{ {
/* Allow 2 codecs at end of file buffer */ #ifdef PLAYBACK_VOICE
/* Allow 2 codecs at end of audio buffer */
filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE); filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE);
#ifdef PLAYBACK_VOICE iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
iram_buf[0] = &filebuf[filebuflen]; dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE]; iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2]; dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE;
dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
#endif #endif
} }
else else
{ {
/* Allow for 1 codec at end of file buffer */ #ifdef PLAYBACK_VOICE
/* Allow for 1 codec at end of audio buffer */
filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE; filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE;
#ifdef PLAYBACK_VOICE iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
iram_buf[0] = &filebuf[filebuflen]; dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
iram_buf[1] = NULL; iram_buf[CODEC_IDX_VOICE] = NULL;
dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE]; dram_buf[CODEC_IDX_VOICE] = NULL;
dram_buf[1] = NULL;
#endif #endif
} }
filebuflen -= pcmbuf_init(pcmbufsize, filebuf + filebuflen) + GUARD_BUFSIZE;
/* Ensure that file buffer is aligned */ /* Ensure that file buffer is aligned */
offset = (-(size_t)filebuf) & 3; offset = -(size_t)filebuf & 3;
filebuf += offset; filebuf += offset;
filebuflen -= offset; filebuflen -= offset;
filebuflen &= ~3; filebuflen &= ~3;
/* Clear any references to the file buffer */ /* Clear any references to the file buffer */
buffer_state = BUFFER_STATE_NORMAL;
} }
#ifdef ROCKBOX_HAS_LOGF #ifdef ROCKBOX_HAS_LOGF
static void audio_test_track_changed_event(struct mp3entry *id3) static void audio_test_track_changed_event(struct mp3entry *id3)
{ {
@ -3149,9 +3273,8 @@ static void audio_playback_init(void)
logf("playback api init"); logf("playback api init");
pcm_init(); pcm_init();
#if defined(HAVE_RECORDING) && !defined(SIMULATOR) #ifdef AUDIO_HAVE_RECORDING
/* Set the input multiplexer to Line In */ rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
pcm_rec_mux(0);
#endif #endif
#ifdef ROCKBOX_HAS_LOGF #ifdef ROCKBOX_HAS_LOGF
@ -3219,8 +3342,9 @@ static void audio_playback_init(void)
#endif #endif
} }
filebuf = (char *)&audiobuf[MALLOC_BUFSIZE]; /* Will be reset by reset_buffer */ /* initialize the buffer */
filebuf = audiobuf; /* must be non-NULL for audio_set_crossfade */
buffer_state = BUFFER_STATE_TRASHED; /* force it */
audio_set_crossfade(global_settings.crossfade); audio_set_crossfade(global_settings.crossfade);
audio_is_initialized = true; audio_is_initialized = true;
@ -3358,6 +3482,14 @@ static void audio_thread(void)
playlist_update_resume_info(audio_current_track()); playlist_update_resume_info(audio_current_track());
break ; break ;
#ifdef AUDIO_HAVE_RECORDING
case Q_AUDIO_LOAD_ENCODER:
LOGFQUEUE("audio < Q_AUDIO_LOAD_ENCODER");
LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, ev.data);
break;
#endif
#ifndef SIMULATOR #ifndef SIMULATOR
case SYS_USB_CONNECTED: case SYS_USB_CONNECTED:
LOGFQUEUE("audio < SYS_USB_CONNECTED"); LOGFQUEUE("audio < SYS_USB_CONNECTED");
@ -3368,7 +3500,7 @@ static void audio_thread(void)
#endif #endif
case SYS_TIMEOUT: case SYS_TIMEOUT:
LOGFQUEUE("audio < SYS_TIMEOUT"); LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
break; break;
default: default:

View file

@ -155,7 +155,7 @@ static int recreate_control(struct playlist_info* playlist);
static void update_playlist_filename(struct playlist_info* playlist, static void update_playlist_filename(struct playlist_info* playlist,
const char *dir, const char *file); const char *dir, const char *file);
static int add_indices_to_playlist(struct playlist_info* playlist, static int add_indices_to_playlist(struct playlist_info* playlist,
char* buffer, int buflen); char* buffer, size_t buflen);
static int add_track_to_playlist(struct playlist_info* playlist, static int add_track_to_playlist(struct playlist_info* playlist,
const char *filename, int position, const char *filename, int position,
bool queue, int seek_pos); bool queue, int seek_pos);
@ -457,7 +457,7 @@ static void update_playlist_filename(struct playlist_info* playlist,
* calculate track offsets within a playlist file * calculate track offsets within a playlist file
*/ */
static int add_indices_to_playlist(struct playlist_info* playlist, static int add_indices_to_playlist(struct playlist_info* playlist,
char* buffer, int buflen) char* buffer, size_t buflen)
{ {
unsigned int nread; unsigned int nread;
unsigned int i = 0; unsigned int i = 0;
@ -489,8 +489,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
buflen = (audiobufend - audiobuf); buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf; buffer = (char *)audiobuf;
#else #else
buflen = (audiobufend - audiobuf - talk_get_bufsize()); buffer = (char *)audio_get_buffer(false, &buflen);
buffer = (char *)&audiobuf[talk_get_bufsize()];
#endif #endif
} }
@ -1853,7 +1852,7 @@ int playlist_resume(void)
{ {
struct playlist_info* playlist = &current_playlist; struct playlist_info* playlist = &current_playlist;
char *buffer; char *buffer;
int buflen; size_t buflen;
int nread; int nread;
int total_read = 0; int total_read = 0;
int control_file_size = 0; int control_file_size = 0;
@ -1866,8 +1865,7 @@ int playlist_resume(void)
buflen = (audiobufend - audiobuf); buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf; buffer = (char *)audiobuf;
#else #else
buflen = (audiobufend - audiobuf - talk_get_bufsize()); buffer = (char *)audio_get_buffer(false, &buflen);
buffer = (char *)&audiobuf[talk_get_bufsize()];
#endif #endif
empty_playlist(playlist, true); empty_playlist(playlist, true);

View file

@ -674,12 +674,18 @@ void* plugin_get_buffer(int* buffer_size)
} }
/* Returns a pointer to the mp3 buffer. /* Returns a pointer to the mp3 buffer.
Playback gets stopped, to avoid conflicts. */ Playback gets stopped, to avoid conflicts.
Talk buffer is stolen as well.
*/
void* plugin_get_audio_buffer(int* buffer_size) void* plugin_get_audio_buffer(int* buffer_size)
{ {
#if CONFIG_CODEC == SWCODEC
return audio_get_buffer(true, (size_t *)buffer_size);
#else
audio_stop(); audio_stop();
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
*buffer_size = audiobufend - audiobuf; *buffer_size = audiobufend - audiobuf;
#endif
return audiobuf; return audiobuf;
} }

View file

@ -30,12 +30,17 @@
const unsigned char bitmap_icons_5x8[][5] = const unsigned char bitmap_icons_5x8[][5] =
{ {
[Icon_Lock_Main] ={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Main */ [Icon_Lock_Main] =
[Icon_Lock_Remote]={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Remote */ {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Main */
[Icon_Stereo]={0x7f, 0x1c, 0x00, 0x1c, 0x7f}, /* Stereo recording */ [Icon_Lock_Remote] =
[Icon_Mono]={0x00, 0x1c, 0x7f, 0x00, 0x00}, /* Mono recording */ {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Remote */
[Icon_Stereo] =
{0x7f, 0x22, 0x1c, 0x22, 0x7f}, /* Stereo recording */
[Icon_Mono] =
{0x00, 0x1c, 0x22, 0x7f, 0x00}, /* Mono recording */
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
[Icon_q]={0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */ [Icon_q] =
{0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */
#endif #endif
}; };
@ -81,45 +86,52 @@ const unsigned char bitmap_icons_7x8[][7] =
{0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */ {0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */
}; };
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
const unsigned char bitmap_icons_18x8[][18] = const unsigned char bitmap_glyphs_4x8[][4] =
{ {
{0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3e, 0x2a, /* Keep digits together and first! */
0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 64kbps */ [0] =
{0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x0e, 0x0a, {0x00, 0x3e, 0x22, 0x3e}, /* 0 */
0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00}, /* mp3 96kbps */ [1] =
{0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, {0x00, 0x24, 0x3e, 0x20}, /* 1 */
0x2e, 0x00, 0x3e, 0x2a, 0x3e, 0x00}, /* mp3 128kbps */ [2] =
{0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, {0x00, 0x3a, 0x2a, 0x2e}, /* 2 */
0x3a, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 160kbps */ [3] =
{0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x0e, 0x0a, {0x00, 0x22, 0x2a, 0x36}, /* 3 */
0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00}, /* mp3 192kbps */ [4] =
{0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, {0x00, 0x0e, 0x08, 0x3e}, /* 4 */
0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 224kbps */ [5] =
{0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, {0x00, 0x2e, 0x2a, 0x3a}, /* 5 */
0x2e, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 320kbps */ [6] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x1e, 0x20, 0x18, 0x20, 0x1e, {0x00, 0x3e, 0x2a, 0x3a}, /* 6 */
0x00, 0x1e, 0x20, 0x18, 0x06, 0x00}, /* wv */ [7] =
{0x00, 0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x12, 0x12, 0x3c, {0x00, 0x02, 0x02, 0x3e}, /* 7 */
0x00, 0x1e, 0x20, 0x18, 0x06, 0x00} /* wav */ [8] =
{0x00, 0x3e, 0x2a, 0x3e}, /* 8 */
[9] =
{0x00, 0x0e, 0x0a, 0x3e}, /* 9 */
[10 ... Glyph_4x8Last-1] =
{0x00, 0x00, 0x00, 0x00}, /* auto-blank */
[Glyph_4x8_k] =
{0x00, 0x3e, 0x10, 0x28}, /* k */
}; };
const unsigned char bitmap_icons_12x8[][12] = const unsigned char bitmap_formats_18x8[Format_18x8Last][18]=
{ {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 8khz */ [0 ... Format_18x8Last-1] = /* auto-blank */
{0x00, 0x24, 0x3e, 0x20, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x10, 0x28}, /* 11khz */ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 12khz */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ___ */
{0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28}, /* 16khz */ [Format_18x8_MPA_L3] =
{0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 22khz */ {0x00, 0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00,
{0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 24khz */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* M__ */
{0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 32khz */ [Format_18x8_WAVPACK] =
{0x00, 0x0e, 0x08, 0x3e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 44.1khz */ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20,
{0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 48khz */ 0x18, 0x20, 0x1e, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* _WV */
{0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 64khz */ [Format_18x8_PCM_WAV] =
{0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 88.2khz */ {0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x0a,
{0x00, 0x0e, 0x0a, 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28} /* 96khz */ 0x0a, 0x0a, 0x3c, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* WAV */
}; };
#endif #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
/* Disk/MMC activity */ /* Disk/MMC activity */
const unsigned char bitmap_icon_disk[12] = const unsigned char bitmap_icon_disk[12] =

View file

@ -89,44 +89,40 @@ enum icons_7x8 {
Icon7x8Last Icon7x8Last
}; };
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
enum icons_12x8 { #define BM_GLYPH_WIDTH 4
Icon_8000, enum Glyphs_4x8 {
Icon_11025, Glyph_4x8_0 = 0,
Icon_12000, Glyph_4x8_1,
Icon_16000, Glyph_4x8_2,
Icon_22050, Glyph_4x8_3,
Icon_24000, Glyph_4x8_4,
Icon_32000, Glyph_4x8_5,
Icon_44100, Glyph_4x8_6,
Icon_48000, Glyph_4x8_7,
Icon_64000, Glyph_4x8_8,
Icon_88200, Glyph_4x8_9,
Icon_96000, Glyph_4x8_k,
Icon12x8Last Glyph_4x8Last
}; };
extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4];
enum icons_18x8 { #define BM_MPA_L3_M_WIDTH 6
Icon_mp364, #ifdef ID3_H
Icon_mp396, /* This enum is redundant but sort of in keeping with the style */
Icon_mp3128, enum rec_format_18x8 {
Icon_mp3160, Format_18x8_MPA_L3 = REC_FORMAT_MPA_L3,
Icon_mp3192, Format_18x8_WAVPACK = REC_FORMAT_WAVPACK,
Icon_mp3224, Format_18x8_PCM_WAV = REC_FORMAT_PCM_WAV,
Icon_mp3320, Format_18x8Last = REC_NUM_FORMATS
Icon_wv,
Icon_wav,
Icon18x8Last
}; };
#endif extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18];
#endif /* ID3_H */
#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5];
extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6];
extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7];
#if CONFIG_CODEC == SWCODEC
extern const unsigned char bitmap_icons_12x8[Icon12x8Last][12];
extern const unsigned char bitmap_icons_18x8[Icon18x8Last][18];
#endif
extern const unsigned char bitmap_icon_disk[]; extern const unsigned char bitmap_icon_disk[];
#define STATUSBAR_X_POS 0 #define STATUSBAR_X_POS 0

View file

@ -540,10 +540,8 @@ void peak_meter_peek(void)
if (pm_playback) if (pm_playback)
pcm_calculate_peaks(&pm_cur_left, &pm_cur_right); pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
if (!pm_playback) else
{ pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
pcm_rec_get_peaks(&pm_cur_left, &pm_cur_right);
}
#endif #endif
left = pm_cur_left; left = pm_cur_left;
right = pm_cur_right; right = pm_cur_right;

View file

@ -386,6 +386,7 @@ bool radio_screen(void)
unsigned int last_seconds = 0; unsigned int last_seconds = 0;
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
int hours, minutes; int hours, minutes;
struct audio_recording_options rec_options;
#endif #endif
bool keep_playing = false; bool keep_playing = false;
bool statusbar = global_settings.statusbar; bool statusbar = global_settings.statusbar;
@ -436,12 +437,9 @@ bool radio_screen(void)
peak_meter_enabled = true; peak_meter_enabled = true;
rec_set_recording_options(global_settings.rec_frequency, rec_init_recording_options(&rec_options);
global_settings.rec_quality, rec_options.rec_source = AUDIO_SRC_LINEIN;
AUDIO_SRC_LINEIN, 0, rec_set_recording_options(&rec_options);
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
@ -881,7 +879,7 @@ bool radio_screen(void)
} }
else else
{ {
if(global_settings.rec_prerecord_time) if(rec_options.rec_prerecord_time)
{ {
snprintf(buf, 32, "%s %02d", snprintf(buf, 32, "%s %02d",
str(LANG_RECORD_PRERECORD), seconds%60); str(LANG_RECORD_PRERECORD), seconds%60);
@ -1173,7 +1171,8 @@ bool save_preset_list(void)
if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */ if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */
mkdir(FMPRESET_PATH, 0); mkdir(FMPRESET_PATH, 0);
create_numbered_filename(filepreset,FMPRESET_PATH,"preset",".fmr",2); create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
".fmr", 2 IF_CNFN_NUM_(, NULL));
while(bad_file_name) while(bad_file_name)
{ {
@ -1534,12 +1533,10 @@ static bool fm_recording_settings(void)
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
if (!ret) if (!ret)
{ {
rec_set_recording_options(global_settings.rec_frequency, struct audio_recording_options rec_options;
global_settings.rec_quality, rec_init_recording_options(&rec_options);
AUDIO_SRC_LINEIN, 0, rec_options.rec_source = AUDIO_SRC_LINEIN;
global_settings.rec_channels, rec_set_recording_options(&rec_options);
global_settings.rec_editable,
global_settings.rec_prerecord_time);
} }
#endif #endif

View file

@ -30,8 +30,10 @@
#include "mpeg.h" #include "mpeg.h"
#include "audio.h" #include "audio.h"
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
#include "pcm_record.h" #include "thread.h"
#include "pcm_playback.h"
#include "playback.h" #include "playback.h"
#include "enc_config.h"
#endif #endif
#ifdef HAVE_UDA1380 #ifdef HAVE_UDA1380
#include "uda1380.h" #include "uda1380.h"
@ -73,36 +75,40 @@
#define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1)
#if CONFIG_KEYPAD == RECORDER_PAD
bool f2_rec_screen(void); bool f2_rec_screen(void);
bool f3_rec_screen(void); bool f3_rec_screen(void);
#endif
#define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */
int screen_update = NB_SCREENS; int screen_update = NB_SCREENS;
bool remote_display_on = true; bool remote_display_on = true;
const char* const freq_str[6] =
{
"44.1kHz",
"48kHz",
"32kHz",
"22.05kHz",
"24kHz",
"16kHz"
};
/** File name creation **/
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
#define REC_ENCODER_ID(q) \
rec_quality_info_afmt[q]
#define REC_QUALITY_LABEL(q) \
(audio_formats[REC_ENCODER_ID(q)].label)
#define REC_FILE_ENDING(q) \
(audio_formats[REC_ENCODER_ID(q)].ext)
#else
/* default record file extension for HWCODEC */
#define REC_QUALITY_LABEL(q) "MP3"
#define REC_FILE_ENDING(q) ".mp3"
#endif
#ifdef IF_CNFN_NUM
/* current file number to assist in creating unique numbered filenames
without actually having to create the file on disk */
static int file_number = -1;
#endif /* IF_CNFN_NUM */
#define REC_FILE_ENDING(rec_format) \
(audio_formats[rec_format_afmt[rec_format]].ext_list)
#else /* CONFIG_CODEC != SWCODEC */
/* default record file extension for HWCODEC */
#define REC_FILE_ENDING(rec_format) \
(audio_formats[AFMT_MPA_L3].ext_list)
#endif /* CONFIG_CODEC == SWCODEC */
/* path for current file */
static char path_buffer[MAX_PATH];
/** Automatic Gain Control (AGC) **/
#ifdef HAVE_AGC #ifdef HAVE_AGC
/* Timing counters: /* Timing counters:
* peak_time is incremented every 0.2s, every 2nd run of record screen loop. * peak_time is incremented every 0.2s, every 2nd run of record screen loop.
@ -496,20 +502,24 @@ void adjust_cursor(void)
char *rec_create_filename(char *buffer) char *rec_create_filename(char *buffer)
{ {
char ext[16];
if(global_settings.rec_directory) if(global_settings.rec_directory)
getcwd(buffer, MAX_PATH); getcwd(buffer, MAX_PATH);
else else
strncpy(buffer, rec_base_directory, MAX_PATH); strncpy(buffer, rec_base_directory, MAX_PATH);
snprintf(ext, sizeof(ext), ".%s",
REC_FILE_ENDING(global_settings.rec_format));
#ifdef CONFIG_RTC #ifdef CONFIG_RTC
create_datetime_filename(buffer, buffer, "R", /* We'll wait at least up to the start of the next second so no duplicate
REC_FILE_ENDING(global_settings.rec_quality)); names are created */
return create_datetime_filename(buffer, buffer, "R", ext, true);
#else #else
create_numbered_filename(buffer, buffer, "rec_", return create_numbered_filename(buffer, buffer, "rec_", ext, 4
REC_FILE_ENDING(global_settings.rec_quality), 4); IF_CNFN_NUM_(, &file_number));
#endif #endif
return buffer;
} }
int rec_create_directory(void) int rec_create_directory(void)
@ -557,9 +567,15 @@ static void rec_boost(bool state)
/** /**
* Selects an audio source for recording or playback * Selects an audio source for recording or playback
* powers/unpowers related devices. * powers/unpowers related devices and sets up monitoring.
* Here because it calls app code and used only for HAVE_RECORDING atm. * Here because it calls app code and used only for HAVE_RECORDING atm.
* Would like it in pcm_record.c. * Would like it in pcm_record.c.
*
* Behaves like a firmware function in that it does not use global settings
* to determine the state.
*
* The order of setting monitoring may need tweaking dependent upon the
* selected source to get the smoothest transition.
*/ */
#if defined(HAVE_UDA1380) #if defined(HAVE_UDA1380)
#define ac_disable_recording uda1380_disable_recording #define ac_disable_recording uda1380_disable_recording
@ -571,7 +587,13 @@ static void rec_boost(bool state)
#define ac_set_monitor tlv320_set_monitor #define ac_set_monitor tlv320_set_monitor
#endif #endif
void rec_set_source(int source, int flags) #ifdef HAVE_SPDIF_IN
#define rec_spdif_set_monitor(m) audio_spdif_set_monitor(m)
#else
#define rec_spdif_set_monitor(m)
#endif
void rec_set_source(int source, unsigned flags)
{ {
/* Prevent pops from unneeded switching */ /* Prevent pops from unneeded switching */
static int last_source = AUDIO_SRC_PLAYBACK; static int last_source = AUDIO_SRC_PLAYBACK;
@ -586,7 +608,9 @@ void rec_set_source(int source, int flags)
/** Do power up/down of associated device(s) **/ /** Do power up/down of associated device(s) **/
/** SPDIF **/
#ifdef HAVE_SPDIF_IN #ifdef HAVE_SPDIF_IN
/* Always boost for SPDIF */
if ((source == AUDIO_SRC_SPDIF) != (source == last_source)) if ((source == AUDIO_SRC_SPDIF) != (source == last_source))
rec_boost(source == AUDIO_SRC_SPDIF); rec_boost(source == AUDIO_SRC_SPDIF);
@ -595,10 +619,11 @@ void rec_set_source(int source, int flags)
both optical in and out is controlled by the same power source, which is both optical in and out is controlled by the same power source, which is
the case on H1x0. */ the case on H1x0. */
spdif_power_enable((source == AUDIO_SRC_SPDIF) || spdif_power_enable((source == AUDIO_SRC_SPDIF) ||
global_settings.spdif_enable); audio_get_spdif_power_setting());
#endif #endif
#endif #endif
/** Tuner **/
#ifdef CONFIG_TUNER #ifdef CONFIG_TUNER
/* Switch radio off or on per source and flags. */ /* Switch radio off or on per source and flags. */
if (source != AUDIO_SRC_FMRADIO) if (source != AUDIO_SRC_FMRADIO)
@ -612,12 +637,15 @@ void rec_set_source(int source, int flags)
switch (source) switch (source)
{ {
default: /* playback - no recording */ default: /* playback - no recording */
source = AUDIO_SRC_PLAYBACK;
case AUDIO_SRC_PLAYBACK:
pm_playback = true; pm_playback = true;
if (source == last_source) if (source == last_source)
break; break;
ac_disable_recording(); ac_disable_recording();
ac_set_monitor(false); ac_set_monitor(false);
pcm_rec_mux(0); /* line in */ pcm_rec_mux(0); /* line in */
rec_spdif_set_monitor(-1); /* silence it */
break; break;
case AUDIO_SRC_MIC: /* recording only */ case AUDIO_SRC_MIC: /* recording only */
@ -625,6 +653,7 @@ void rec_set_source(int source, int flags)
break; break;
ac_enable_recording(true); /* source mic */ ac_enable_recording(true); /* source mic */
pcm_rec_mux(0); /* line in */ pcm_rec_mux(0); /* line in */
rec_spdif_set_monitor(0);
break; break;
case AUDIO_SRC_LINEIN: /* recording only */ case AUDIO_SRC_LINEIN: /* recording only */
@ -632,29 +661,20 @@ void rec_set_source(int source, int flags)
break; break;
pcm_rec_mux(0); /* line in */ pcm_rec_mux(0); /* line in */
ac_enable_recording(false); /* source line */ ac_enable_recording(false); /* source line */
rec_spdif_set_monitor(0);
break; break;
#ifdef HAVE_SPDIF_IN #ifdef HAVE_SPDIF_IN
case AUDIO_SRC_SPDIF: /* recording only */ case AUDIO_SRC_SPDIF: /* recording only */
if (recording) if (source == last_source)
{ break;
/* This was originally done in audio_set_recording_options only */ ac_disable_recording();
#ifdef HAVE_SPDIF_POWER audio_spdif_set_monitor(1);
EBU1CONFIG = global_settings.spdif_enable ? (1 << 2) : 0;
/* Input source is EBUin1, Feed-through monitoring if desired */
#else
EBU1CONFIG = (1 << 2);
/* Input source is EBUin1, Feed-through monitoring */
#endif
}
if (source != last_source)
uda1380_disable_recording();
break; break;
#endif /* HAVE_SPDIF_IN */ #endif /* HAVE_SPDIF_IN */
#ifdef HAVE_FMRADIO_IN #ifdef HAVE_FMRADIO_IN
case AUDIO_SRC_FMRADIO: case AUDIO_SRC_FMRADIO: /* recording and playback */
if (!recording) if (!recording)
{ {
audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
@ -687,6 +707,8 @@ void rec_set_source(int source, int flags)
tlv320_set_monitor(true); /* analog bypass */ tlv320_set_monitor(true); /* analog bypass */
} }
#endif #endif
rec_spdif_set_monitor(0);
break; break;
/* #elif defined(CONFIG_TUNER) */ /* #elif defined(CONFIG_TUNER) */
/* Have radio but cannot record it */ /* Have radio but cannot record it */
@ -702,33 +724,50 @@ void rec_set_source(int source, int flags)
} /* rec_set_source */ } /* rec_set_source */
#endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */ #endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */
/* steal the mp3 buffer then actually set options */ void rec_init_recording_options(struct audio_recording_options *options)
void rec_set_recording_options(int frequency, int quality, {
int source, int source_flags, options->rec_source = global_settings.rec_source;
int channel_mode, bool editable, options->rec_frequency = global_settings.rec_frequency;
int prerecord_time) options->rec_channels = global_settings.rec_channels;
options->rec_prerecord_time = global_settings.rec_prerecord_time;
#if CONFIG_CODEC == SWCODEC
options->rec_source_flags = 0;
options->enc_config.rec_format = global_settings.rec_format;
global_to_encoder_config(&options->enc_config);
#else
options->rec_quality = global_settings.rec_quality;
options->rec_editable = global_settings.rec_editable;
#endif
}
void rec_set_recording_options(struct audio_recording_options *options)
{ {
#if CONFIG_CODEC != SWCODEC #if CONFIG_CODEC != SWCODEC
if (global_settings.rec_prerecord_time) if (global_settings.rec_prerecord_time)
#endif
talk_buffer_steal(); /* will use the mp3 buffer */ talk_buffer_steal(); /* will use the mp3 buffer */
#endif
#ifdef HAVE_SPDIF_IN
#ifdef HAVE_SPDIF_POWER
audio_set_spdif_power_setting(global_settings.spdif_enable);
#endif
#endif
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
rec_set_source(source, source_flags | SRCF_RECORDING); rec_set_source(options->rec_source,
#else options->rec_source_flags | SRCF_RECORDING);
(void)source_flags;
#endif #endif
audio_set_recording_options(frequency, quality, source, audio_set_recording_options(options);
channel_mode, editable, prerecord_time);
} }
static char path_buffer[MAX_PATH];
/* steals mp3 buffer, creates unique filename and starts recording */ /* steals mp3 buffer, creates unique filename and starts recording */
void rec_record(void) void rec_record(void)
{ {
#if CONFIG_CODEC != SWCODEC
talk_buffer_steal(); /* we use the mp3 buffer */ talk_buffer_steal(); /* we use the mp3 buffer */
#endif
IF_CNFN_NUM_(file_number = -1;) /* Hit disk for number */
audio_record(rec_create_filename(path_buffer)); audio_record(rec_create_filename(path_buffer));
} }
@ -753,7 +792,6 @@ static void trigger_listener(int trigger_status)
case TRIG_GO: case TRIG_GO:
if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD) if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD)
{ {
talk_buffer_steal(); /* we use the mp3 buffer */
rec_record(); rec_record();
/* give control to mpeg thread so that it can start /* give control to mpeg thread so that it can start
recording */ recording */
@ -831,6 +869,8 @@ bool recording_screen(bool no_source)
ID2P(LANG_GIGABYTE) ID2P(LANG_GIGABYTE)
}; };
struct audio_recording_options rec_options;
global_settings.recscreen_on = true; global_settings.recscreen_on = true;
cursor = 0; cursor = 0;
#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
@ -838,35 +878,26 @@ bool recording_screen(bool no_source)
#endif #endif
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
audio_stop();
voice_stop();
/* recording_menu gets messed up: so reset talk_menu */ /* recording_menu gets messed up: so reset talk_menu */
talk_menu = global_settings.talk_menu; talk_menu = global_settings.talk_menu;
global_settings.talk_menu = 0; global_settings.talk_menu = 0;
/* audio_init_recording stops anything playing when it takes the audio
buffer */
#else #else
/* Yes, we use the D/A for monitoring */ /* Yes, we use the D/A for monitoring */
peak_meter_enabled = true; peak_meter_enabled = true;
peak_meter_playback(true); peak_meter_playback(true);
#endif #endif
#if CONFIG_CODEC == SWCODEC
audio_init_recording(talk_get_bufsize());
#else
audio_init_recording(0); audio_init_recording(0);
#endif
sound_set_volume(global_settings.volume); sound_set_volume(global_settings.volume);
#ifdef HAVE_AGC #ifdef HAVE_AGC
peak_meter_get_peakhold(&peak_l, &peak_r); peak_meter_get_peakhold(&peak_l, &peak_r);
#endif #endif
rec_set_recording_options(global_settings.rec_frequency, rec_init_recording_options(&rec_options);
global_settings.rec_quality, rec_set_recording_options(&rec_options);
global_settings.rec_source,
0,
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
set_gain(); set_gain();
settings_apply_trigger(); settings_apply_trigger();
@ -1025,7 +1056,6 @@ bool recording_screen(bool no_source)
{ {
/* manual recording */ /* manual recording */
have_recorded = true; have_recorded = true;
talk_buffer_steal(); /* we use the mp3 buffer */
rec_record(); rec_record();
last_seconds = 0; last_seconds = 0;
if (talk_menu) if (talk_menu)
@ -1253,16 +1283,10 @@ bool recording_screen(bool no_source)
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
/* reinit after submenu exit */ /* reinit after submenu exit */
audio_close_recording(); audio_close_recording();
audio_init_recording(talk_get_bufsize()); audio_init_recording(0);
#endif #endif
rec_set_recording_options( rec_init_recording_options(&rec_options);
global_settings.rec_frequency, rec_set_recording_options(&rec_options);
global_settings.rec_quality,
global_settings.rec_source,
0,
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
if(rec_create_directory() > 0) if(rec_create_directory() > 0)
have_recorded = true; have_recorded = true;
@ -1739,11 +1763,7 @@ bool recording_screen(bool no_source)
} }
} /* end while(!done) */ } /* end while(!done) */
#if CONFIG_CODEC == SWCODEC
audio_stat = pcm_rec_status();
#else
audio_stat = audio_status(); audio_stat = audio_status();
#endif
if (audio_stat & AUDIO_STATUS_ERROR) if (audio_stat & AUDIO_STATUS_ERROR)
{ {
gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL)); gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL));
@ -1804,11 +1824,22 @@ bool recording_screen(bool no_source)
#if CONFIG_KEYPAD == RECORDER_PAD #if CONFIG_KEYPAD == RECORDER_PAD
bool f2_rec_screen(void) bool f2_rec_screen(void)
{ {
static const char* const freq_str[6] =
{
"44.1kHz",
"48kHz",
"32kHz",
"22.05kHz",
"24kHz",
"16kHz"
};
bool exit = false; bool exit = false;
bool used = false; bool used = false;
int w, h, i; int w, h, i;
char buf[32]; char buf[32];
int button; int button;
struct audio_recording_options rec_options;
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
{ {
@ -1919,13 +1950,8 @@ bool f2_rec_screen(void)
} }
} }
rec_set_recording_options(global_settings.rec_frequency, rec_init_recording_options(&rec_options);
global_settings.rec_quality, rec_set_recording_options(&rec_options);
global_settings.rec_source,
0,
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
set_gain(); set_gain();
@ -1948,6 +1974,8 @@ bool f3_rec_screen(void)
str(LANG_SYSFONT_RECORDING_SRC_LINE), str(LANG_SYSFONT_RECORDING_SRC_LINE),
str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) str(LANG_SYSFONT_RECORDING_SRC_DIGITAL)
}; };
struct audio_recording_options rec_options;
FOR_NB_SCREENS(i) FOR_NB_SCREENS(i)
{ {
screens[i].setfont(FONT_SYSFIXED); screens[i].setfont(FONT_SYSFIXED);
@ -2019,13 +2047,8 @@ bool f3_rec_screen(void)
} }
} }
rec_set_recording_options(global_settings.rec_frequency, rec_init_recording_options(&rec_options);
global_settings.rec_quality, rec_set_recording_options(&rec_options);
global_settings.rec_source,
0,
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
set_gain(); set_gain();
@ -2066,23 +2089,30 @@ unsigned long audio_num_recorded_bytes(void)
} }
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
void rec_set_source(int source, int flags) void rec_set_source(int source, unsigned flags)
{ {
source = source; source = source;
flags = flags; flags = flags;
} }
#endif
void audio_set_recording_options(int frequency, int quality, #ifdef HAVE_SPDIF_IN
int source, int channel_mode, #ifdef HAVE_SPDIF_POWER
bool editable, int prerecord_time) void audio_set_spdif_power_setting(bool on)
{ {
frequency = frequency; on = on;
quality = quality; }
source = source;
channel_mode = channel_mode; bool audio_get_spdif_power_setting(void)
editable = editable; {
prerecord_time = prerecord_time; return true;
}
#endif /* HAVE_SPDIF_POWER */
#endif /* HAVE_SPDIF_IN */
#endif /* CONFIG_CODEC == SWCODEC */
void audio_set_recording_options(struct audio_recording_options *options)
{
options = options;
} }
void audio_set_recording_gain(int left, int right, int type) void audio_set_recording_gain(int left, int right, int type)
@ -2104,7 +2134,7 @@ void audio_resume_recording(void)
{ {
} }
void pcm_rec_get_peaks(int *left, int *right) void pcm_calculate_rec_peaks(int *left, int *right)
{ {
if (left) if (left)
*left = 0; *left = 0;

View file

@ -32,15 +32,16 @@ int rec_create_directory(void);
#define SRCF_FMRADIO_PLAYING 0x0000 /* default */ #define SRCF_FMRADIO_PLAYING 0x0000 /* default */
#define SRCF_FMRADIO_PAUSED 0x2000 #define SRCF_FMRADIO_PAUSED 0x2000
#endif #endif
void rec_set_source(int source, int flags); void rec_set_source(int source, unsigned flags);
#endif /* CONFIG_CODEC == SW_CODEC */ #endif /* CONFIG_CODEC == SW_CODEC */
/* Initializes a recording_options structure with global settings.
pass returned data to audio_set_recording_options or
rec_set_recording_options */
void rec_init_recording_options(struct audio_recording_options *options);
/* steals mp3 buffer, sets source and then options */ /* steals mp3 buffer, sets source and then options */
/* SRCF_RECORDING is implied */ /* SRCF_RECORDING is implied for SWCODEC */
void rec_set_recording_options(int frequency, int quality, void rec_set_recording_options(struct audio_recording_options *options);
int source, int source_flags,
int channel_mode, bool editable,
int prerecord_time);
/* steals mp3 buffer, creates unique filename and starts recording */ /* steals mp3 buffer, creates unique filename and starts recording */
void rec_record(void); void rec_record(void);

View file

@ -90,13 +90,16 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "pcmbuf.h" #include "pcmbuf.h"
#include "pcm_playback.h" #include "pcm_playback.h"
#include "dsp.h" #include "dsp.h"
#ifdef HAVE_RECORDING
#include "enc_config.h"
#endif #endif
#endif /* CONFIG_CODEC == SWCODEC */
#ifdef HAVE_WM8758 #ifdef HAVE_WM8758
#include "eq_menu.h" #include "eq_menu.h"
#endif #endif
#define CONFIG_BLOCK_VERSION 55 #define CONFIG_BLOCK_VERSION 56
#define CONFIG_BLOCK_SIZE 512 #define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44 #define RTC_BLOCK_SIZE 44
@ -514,7 +517,7 @@ static const struct bit_entry hd_bits[] =
{1, S_O(rec_editable), false, "editable recordings", off_on }, {1, S_O(rec_editable), false, "editable recordings", off_on },
#endif /* CONFIG_CODEC == MAS3587F */ #endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) #if CONFIG_CODEC == SWCODEC
#ifdef HAVE_UDA1380 #ifdef HAVE_UDA1380
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
#endif #endif
@ -524,16 +527,20 @@ static const struct bit_entry hd_bits[] =
#endif #endif
{8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
{8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
#if 0 /* Till samplerates are added for SWCODEC */ {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
{3, S_O(rec_frequency), 0, /* 0=44.1kHz */ "rec frequency", REC_FREQ_CFG_VAL_LIST },
"rec frequency", "44,48,32,22,24,16" }, {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
#else "rec format", REC_FORMAT_CFG_VAL_LIST },
{3, S_O(rec_frequency), 0, /* 0=44.1kHz */ /** Encoder settings start - keep these together **/
"rec frequency", "44" }, /* mp3_enc */
#endif {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
"mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
{4, S_O(rec_quality), 4 /* MP3 L3 192 kBit/s */, "rec quality", NULL }, /* wav_enc */
#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ /* (no settings yet) */
/* wavpack_enc */
/* (no settings yet) */
/** Encoder settings end **/
#endif /* CONFIG_CODEC == SWCODEC */
/* values for the trigger */ /* values for the trigger */
{8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
@ -1301,6 +1308,11 @@ void settings_apply(void)
lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off);
#endif #endif
#endif /* CONFIG_BACKLIGHT */ #endif /* CONFIG_BACKLIGHT */
/* This should stay last */
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
enc_global_settings_apply();
#endif
} }
@ -1727,13 +1739,13 @@ static void save_cfg_table(const struct bit_entry* p_table, int count, int fd)
} }
} }
bool settings_save_config(void) bool settings_save_config(void)
{ {
int fd; int fd;
char filename[MAX_PATH]; char filename[MAX_PATH];
create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2); create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2
IF_CNFN_NUM_(, NULL));
/* allow user to modify filename */ /* allow user to modify filename */
while (true) { while (true) {
@ -1887,6 +1899,10 @@ void settings_reset(void) {
global_settings.kbd_file[0] = '\0'; global_settings.kbd_file[0] = '\0';
#endif #endif
global_settings.hold_lr_for_scroll_in_list = true; global_settings.hold_lr_for_scroll_in_list = true;
#if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
enc_global_settings_reset();
#endif
} }
bool set_bool(const char* string, bool* variable ) bool set_bool(const char* string, bool* variable )

View file

@ -29,6 +29,10 @@
#include "tagcache.h" #include "tagcache.h"
#include "button.h" #include "button.h"
#if CONFIG_CODEC == SWCODEC
#include "audio.h"
#endif
#ifdef HAVE_BACKLIGHT_BRIGHTNESS #ifdef HAVE_BACKLIGHT_BRIGHTNESS
#include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */ #include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */
#endif #endif
@ -142,18 +146,22 @@ struct user_settings
int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */ int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */
#endif #endif
#if CONFIG_CODEC == SWCODEC
int rec_format; /* record format index */
#else
int rec_quality; /* 0-7 */ int rec_quality; /* 0-7 */
int rec_source; /* 0=mic, 1=line, 2=S/PDIF */ #endif /* CONFIG_CODEC == SWCODEC */
int rec_frequency; /* 0 = 44.1kHz int rec_source; /* 0=mic, 1=line, 2=S/PDIF, 2 or 3=FM Radio */
int rec_frequency; /* 0 = 44.1kHz (depends on target)
1 = 48kHz 1 = 48kHz
2 = 32kHz 2 = 32kHz
3 = 22.05kHz 3 = 22.05kHz
4 = 24kHz 4 = 24kHz
5 = 16kHz */ 5 = 16kHz */
int rec_channels; /* 0=Stereo, 1=Mono */ int rec_channels; /* 0=Stereo, 1=Mono */
int rec_mic_gain; /* 0-15 */ int rec_mic_gain; /* depends on target */
int rec_left_gain; /* 0-15 */ int rec_left_gain; /* depends on target */
int rec_right_gain; /* 0-15 */ int rec_right_gain; /* depands on target */
bool rec_editable; /* true means that the bit reservoir is off */ bool rec_editable; /* true means that the bit reservoir is off */
bool recscreen_on; /* true if using the recording screen */ bool recscreen_on; /* true if using the recording screen */
@ -504,6 +512,20 @@ struct user_settings
#endif #endif
bool audioscrobbler; /* Audioscrobbler logging */ bool audioscrobbler; /* Audioscrobbler logging */
/* If values are just added to the end, no need to bump plugin API
version. */
/* new stuff to be added at the end */
#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
/* Encoder Settings Start - keep these together */
struct mp3_enc_config mp3_enc_config;
#if 0 /* These currently contain no members but their places in line
should be held */
struct wav_enc_config wav_enc_config;
struct wavpack_enc_config wavpack_enc_config;
#endif
/* Encoder Settings End */
#endif /* CONFIG_CODEC == SWCODEC */
}; };
enum optiontype { INT, BOOL }; enum optiontype { INT, BOOL };
@ -584,7 +606,7 @@ extern const char rec_base_directory[];
/* argument bits for settings_load() */ /* argument bits for settings_load() */
#define SETTINGS_RTC 1 /* only the settings from the RTC nonvolatile RAM */ #define SETTINGS_RTC 1 /* only the settings from the RTC nonvolatile RAM */
#define SETTINGS_HD 2 /* only the settings fron the disk sector */ #define SETTINGS_HD 2 /* only the settings from the disk sector */
#define SETTINGS_ALL 3 /* both */ #define SETTINGS_ALL 3 /* both */
/* repeat mode options */ /* repeat mode options */

View file

@ -54,6 +54,10 @@
#include "dsp.h" #include "dsp.h"
#include "eq_menu.h" #include "eq_menu.h"
#include "pcmbuf.h" #include "pcmbuf.h"
#ifdef HAVE_RECORDING
#include "enc_config.h"
#endif
#include "general.h"
#endif #endif
#include "action.h" #include "action.h"
@ -308,22 +312,20 @@ static bool recsource(void)
{ {
int n_opts = AUDIO_NUM_SOURCES; int n_opts = AUDIO_NUM_SOURCES;
struct opt_items names[AUDIO_NUM_SOURCES] = { static const struct opt_items names[AUDIO_NUM_SOURCES] = {
{ STR(LANG_RECORDING_SRC_MIC) }, [AUDIO_SRC_MIC] = { STR(LANG_RECORDING_SRC_MIC) },
{ STR(LANG_RECORDING_SRC_LINE) }, [AUDIO_SRC_LINEIN] = { STR(LANG_RECORDING_SRC_LINE) },
#ifdef HAVE_SPDIF_IN #ifdef HAVE_SPDIF_IN
{ STR(LANG_RECORDING_SRC_DIGITAL) }, [AUDIO_SRC_SPDIF] = { STR(LANG_RECORDING_SRC_DIGITAL) },
#endif
#ifdef HAVE_FMRADIO_IN
[AUDIO_SRC_FMRADIO] = { STR(LANG_FM_RADIO) }
#endif #endif
}; };
/* caveat: assumes it's the last item! */ /* caveat: assumes it's the last item! */
#ifdef HAVE_FMRADIO_IN #ifdef HAVE_FMRADIO_IN
if (radio_hardware_present()) if (!radio_hardware_present())
{
names[AUDIO_SRC_FMRADIO].string = ID2P(LANG_FM_RADIO);
names[AUDIO_SRC_FMRADIO].voice_id = LANG_FM_RADIO;
}
else
n_opts--; n_opts--;
#endif #endif
@ -332,28 +334,7 @@ static bool recsource(void)
n_opts, NULL ); n_opts, NULL );
} }
/* To be removed when we add support for sample rates and channel settings */ #if CONFIG_CODEC == MAS3587F
#if CONFIG_CODEC == SWCODEC
static bool recquality(void)
{
static const struct opt_items names[] = {
{ "MP3 64 kBit/s", TALK_ID( 64, UNIT_KBIT) },
{ "MP3 96 kBit/s", TALK_ID( 96, UNIT_KBIT) },
{ "MP3 128 kBit/s", TALK_ID( 128, UNIT_KBIT) },
{ "MP3 160 kBit/s", TALK_ID( 160, UNIT_KBIT) },
{ "MP3 192 kBit/s", TALK_ID( 192, UNIT_KBIT) },
{ "MP3 224 kBit/s", TALK_ID( 224, UNIT_KBIT) },
{ "MP3 320 kBit/s", TALK_ID( 320, UNIT_KBIT) },
{ "WV 900 kBit/s", TALK_ID( 900, UNIT_KBIT) },
{ "WAV 1411 kBit/s", TALK_ID(1411, UNIT_KBIT) }
};
return set_option(str(LANG_RECORDING_QUALITY),
&global_settings.rec_quality, INT,
names, sizeof (names)/sizeof(struct opt_items),
NULL );
}
#elif CONFIG_CODEC == MAS3587F
static bool recquality(void) static bool recquality(void)
{ {
return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT, return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT,
@ -368,32 +349,182 @@ static bool receditable(void)
} }
#endif /* CONFIG_CODEC == MAS3587F */ #endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC
/* Makes an options list from a source list of options and indexes */
void make_options_from_indexes(const struct opt_items *src_names,
const long *src_indexes,
int n_indexes,
struct opt_items *dst_names)
{
while (--n_indexes >= 0)
dst_names[n_indexes] = src_names[src_indexes[n_indexes]];
} /* make_options_from_indexes */
static bool recformat(void)
{
static const struct opt_items names[REC_NUM_FORMATS] = {
[REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) },
[REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) },
[REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) },
};
int rec_format = global_settings.rec_format;
bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT,
names, REC_NUM_FORMATS, NULL );
if (rec_format != global_settings.rec_format)
{
global_settings.rec_format = rec_format;
enc_global_settings_apply();
}
return res;
} /* recformat */
#endif /* CONFIG_CODEC == SWCODEC */
static bool recfrequency(void) static bool recfrequency(void)
{ {
static const struct opt_items names[] = { #if CONFIG_CODEC == MAS3587F
static const struct opt_items names[6] = {
{ "44.1kHz", TALK_ID(44, UNIT_KHZ) }, { "44.1kHz", TALK_ID(44, UNIT_KHZ) },
#if CONFIG_CODEC != SWCODEC /* This is temporary */
{ "48kHz", TALK_ID(48, UNIT_KHZ) }, { "48kHz", TALK_ID(48, UNIT_KHZ) },
{ "32kHz", TALK_ID(32, UNIT_KHZ) }, { "32kHz", TALK_ID(32, UNIT_KHZ) },
{ "22.05kHz", TALK_ID(22, UNIT_KHZ) }, { "22.05kHz", TALK_ID(22, UNIT_KHZ) },
{ "24kHz", TALK_ID(24, UNIT_KHZ) }, { "24kHz", TALK_ID(24, UNIT_KHZ) },
{ "16kHz", TALK_ID(16, UNIT_KHZ) } { "16kHz", TALK_ID(16, UNIT_KHZ) }
#endif
}; };
return set_option(str(LANG_RECORDING_FREQUENCY), return set_option(str(LANG_RECORDING_FREQUENCY),
&global_settings.rec_frequency, INT, &global_settings.rec_frequency, INT,
names, sizeof(names)/sizeof(*names), NULL ); names, 6, NULL );
#endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC
static const struct opt_items names[REC_NUM_FREQ] = {
REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },)
REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },)
REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },)
REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },)
REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },)
REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },)
REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },)
REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },)
REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },)
REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },)
REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },)
REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },)
};
struct opt_items opts[REC_NUM_FREQ];
unsigned long table[REC_NUM_FREQ];
int n_opts;
int rec_frequency;
bool ret;
#ifdef HAVE_SPDIF_IN
if (global_settings.rec_source == AUDIO_SRC_SPDIF)
{
/* Inform user that frequency follows the source's frequency */
opts[0].string = ID2P(LANG_SOURCE_FREQUENCY);
opts[0].voice_id = LANG_SOURCE_FREQUENCY;
n_opts = 1;
rec_frequency = 0;
} }
else
#endif
{
struct encoder_caps caps;
struct encoder_config cfg;
cfg.rec_format = global_settings.rec_format;
global_to_encoder_config(&cfg);
if (!enc_get_caps(&cfg, &caps, true))
return false;
/* Construct samplerate menu based upon encoder settings */
n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL,
caps.samplerate_caps, table);
if (n_opts == 0)
return false; /* No common flags...?? */
make_options_from_indexes(names, table, n_opts, opts);
/* Find closest rate that the potentially restricted list
comes to */
make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
caps.samplerate_caps, table);
rec_frequency = round_value_to_list32(
rec_freq_sampr[global_settings.rec_frequency],
table, n_opts, false);
}
ret = set_option(str(LANG_RECORDING_FREQUENCY),
&rec_frequency, INT, opts, n_opts, NULL );
if (!ret
#ifdef HAVE_SPDIF_IN
&& global_settings.rec_source != AUDIO_SRC_SPDIF
#endif
)
{
/* Translate back to full index */
global_settings.rec_frequency =
round_value_to_list32(table[rec_frequency],
rec_freq_sampr,
REC_NUM_FREQ,
false);
}
return ret;
#endif /* CONFIG_CODEC == SWCODEC */
} /* recfrequency */
static bool recchannels(void) static bool recchannels(void)
{ {
static const struct opt_items names[] = { static const struct opt_items names[CHN_NUM_MODES] = {
{ STR(LANG_CHANNEL_STEREO) }, [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) },
{ STR(LANG_CHANNEL_MONO) } [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) }
}; };
#if CONFIG_CODEC == MAS3587F
return set_option(str(LANG_RECORDING_CHANNELS), return set_option(str(LANG_RECORDING_CHANNELS),
&global_settings.rec_channels, INT, &global_settings.rec_channels, INT,
names, 2, NULL ); names, CHN_NUM_MODES, NULL );
#endif /* CONFIG_CODEC == MAS3587F */
#if CONFIG_CODEC == SWCODEC
struct opt_items opts[CHN_NUM_MODES];
long table[CHN_NUM_MODES];
struct encoder_caps caps;
struct encoder_config cfg;
int n_opts;
int rec_channels;
bool ret;
cfg.rec_format = global_settings.rec_format;
global_to_encoder_config(&cfg);
if (!enc_get_caps(&cfg, &caps, true))
return false;
n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL,
caps.channel_caps, table);
rec_channels = round_value_to_list32(global_settings.rec_channels,
table, n_opts, false);
make_options_from_indexes(names, table, n_opts, opts);
ret = set_option(str(LANG_RECORDING_CHANNELS), &rec_channels,
INT, opts, n_opts, NULL );
if (!ret)
global_settings.rec_channels = table[rec_channels];
return ret;
#endif /* CONFIG_CODEC == SWCODEC */
} }
static bool rectimesplit(void) static bool rectimesplit(void)
@ -1049,58 +1180,59 @@ bool rectrigger(void)
action_signalscreenchange(); action_signalscreenchange();
return retval; return retval;
} }
#endif #endif /* !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F */
bool recording_menu(bool no_source) bool recording_menu(bool no_source)
{ {
int m; static const struct menu_item static_items[] = {
int i = 0;
struct menu_item items[13];
bool result;
#if CONFIG_CODEC == MAS3587F || CONFIG_CODEC == SWCODEC
items[i].desc = ID2P(LANG_RECORDING_QUALITY);
items[i++].function = recquality;
#endif
items[i].desc = ID2P(LANG_RECORDING_FREQUENCY);
items[i++].function = recfrequency;
if(!no_source) {
items[i].desc = ID2P(LANG_RECORDING_SOURCE);
items[i++].function = recsource;
}
items[i].desc = ID2P(LANG_RECORDING_CHANNELS);
items[i++].function = recchannels;
#if CONFIG_CODEC == MAS3587F #if CONFIG_CODEC == MAS3587F
items[i].desc = ID2P(LANG_RECORDING_EDITABLE); { ID2P(LANG_RECORDING_QUALITY), recquality },
items[i++].function = receditable;
#endif #endif
items[i].desc = ID2P(LANG_RECORD_TIMESPLIT); #if CONFIG_CODEC == SWCODEC
items[i++].function = filesplitoptionsmenu; { ID2P(LANG_RECORDING_FORMAT), recformat },
items[i].desc = ID2P(LANG_RECORD_PRERECORD_TIME); { ID2P(LANG_ENCODER_SETTINGS), enc_global_config_menu },
items[i++].function = recprerecord; #endif
items[i].desc = ID2P(LANG_RECORD_DIRECTORY); { ID2P(LANG_RECORDING_FREQUENCY), recfrequency },
items[i++].function = recdirectory; { ID2P(LANG_RECORDING_SOURCE), recsource }, /* not shown if no_source */
items[i].desc = ID2P(LANG_RECORD_STARTUP); { ID2P(LANG_RECORDING_CHANNELS), recchannels },
items[i++].function = reconstartup; #if CONFIG_CODEC == MAS3587F
{ ID2P(LANG_RECORDING_EDITABLE), receditable },
#endif
{ ID2P(LANG_RECORD_TIMESPLIT), filesplitoptionsmenu },
{ ID2P(LANG_RECORD_PRERECORD_TIME), recprerecord },
{ ID2P(LANG_RECORD_DIRECTORY), recdirectory },
{ ID2P(LANG_RECORD_STARTUP), reconstartup },
#ifdef CONFIG_BACKLIGHT #ifdef CONFIG_BACKLIGHT
items[i].desc = ID2P(LANG_CLIP_LIGHT); { ID2P(LANG_CLIP_LIGHT), cliplight },
items[i++].function = cliplight;
#endif #endif
#if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F #if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F
items[i].desc = ID2P(LANG_RECORD_TRIGGER); { ID2P(LANG_RECORD_TRIGGER), rectrigger },
items[i++].function = rectrigger;
#endif #endif
#ifdef HAVE_AGC #ifdef HAVE_AGC
items[i].desc = ID2P(LANG_RECORD_AGC_PRESET); { ID2P(LANG_RECORD_AGC_PRESET), agc_preset },
items[i++].function = agc_preset; { ID2P(LANG_RECORD_AGC_CLIPTIME), agc_cliptime },
items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME);
items[i++].function = agc_cliptime;
#endif #endif
};
m=menu_init( items, i, NULL, NULL, NULL, NULL); struct menu_item items[ARRAYLEN(static_items)];
int i, n_items;
int m;
bool result;
for (i = 0, n_items = 0; i < (int)ARRAYLEN(items); i++)
{
const struct menu_item *mi = &static_items[i];
if (no_source && mi->function == recsource)
continue;
items[n_items++] = *mi;
}
m = menu_init(items, n_items, NULL, NULL, NULL, NULL);
result = menu_run(m); result = menu_run(m);
menu_exit(m); menu_exit(m);
return result; return result;
} } /* recording_menu */
#endif
#endif /* HAVE_RECORDING */

View file

@ -46,7 +46,7 @@
#ifdef CONFIG_TUNER #ifdef CONFIG_TUNER
#include "radio.h" #include "radio.h"
#endif #endif
#if CONFIG_CODEC == SWCODEC #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
#include "pcm_record.h" #include "pcm_record.h"
#endif #endif
@ -87,10 +87,6 @@ int current_playmode(void)
} }
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
#if CONFIG_CODEC == SWCODEC
audio_stat = pcm_rec_status();
#endif
if(audio_stat & AUDIO_STATUS_RECORD) if(audio_stat & AUDIO_STATUS_RECORD)
{ {
if(audio_stat & AUDIO_STATUS_PAUSE) if(audio_stat & AUDIO_STATUS_PAUSE)

View file

@ -46,13 +46,17 @@
MASCODEC | MASCODEC | SWCODEC MASCODEC | MASCODEC | SWCODEC
(playing) | (stopped) | (playing) | (stopped) |
audiobuf-----------+-----------+----------- audiobuf-----------+-----------+------------
audio | voice | thumbnail audio | voice | thumbnail
|-----------|----------- filebuf |-----------|------------
| thumbnail | voice | thumbnail | voice
| |----------- | |------------
| | filebuf
| |------------
| | audio | | audio
audiobufend----------+-----------+----------- | |------------
| | codec swap
audiobufend----------+-----------+------------
SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */ SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */
@ -102,7 +106,7 @@ struct queue_entry /* one entry of the internal queue */
/***************** Globals *****************/ /***************** Globals *****************/
static unsigned char* p_thumbnail; /* buffer for thumbnail */ static unsigned char* p_thumbnail = NULL; /* buffer for thumbnail */
static long size_for_thumbnail; /* leftover buffer size for it */ static long size_for_thumbnail; /* leftover buffer size for it */
static struct voicefile* p_voicefile; /* loaded voicefile */ static struct voicefile* p_voicefile; /* loaded voicefile */
static bool has_voicefile; /* a voicefile file is present */ static bool has_voicefile; /* a voicefile file is present */
@ -479,11 +483,14 @@ static void reset_state(void)
queue_write = queue_read = 0; /* reset the queue */ queue_write = queue_read = 0; /* reset the queue */
p_voicefile = NULL; /* indicate no voicefile (trashed) */ p_voicefile = NULL; /* indicate no voicefile (trashed) */
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
/* Allocate a dedicated thumbnail buffer */ /* Allocate a dedicated thumbnail buffer - once */
size_for_thumbnail = audiobufend - audiobuf; if (p_thumbnail == NULL)
if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE) {
size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE; size_for_thumbnail = audiobufend - audiobuf;
p_thumbnail = buffer_alloc(size_for_thumbnail); if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE)
size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
p_thumbnail = buffer_alloc(size_for_thumbnail);
}
#else #else
/* Just use the audiobuf, without allocating anything */ /* Just use the audiobuf, without allocating anything */
p_thumbnail = audiobuf; p_thumbnail = audiobuf;

View file

@ -58,7 +58,9 @@
#include "misc.h" #include "misc.h"
#include "filetree.h" #include "filetree.h"
#include "tagtree.h" #include "tagtree.h"
#ifdef HAVE_RECORDING
#include "recorder/recording.h" #include "recorder/recording.h"
#endif
#include "rtc.h" #include "rtc.h"
#include "dircache.h" #include "dircache.h"
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE

View file

@ -204,6 +204,7 @@ void main(void)
kernel_init(); kernel_init();
set_cpu_frequency(CPUFREQ_NORMAL); set_cpu_frequency(CPUFREQ_NORMAL);
coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
set_irq_level(0); set_irq_level(0);
lcd_init(); lcd_init();
@ -311,6 +312,9 @@ void main(void)
#ifdef HAVE_ADJUSTABLE_CPU_FREQ #ifdef HAVE_ADJUSTABLE_CPU_FREQ
/* Set up waitstates for the peripherals */ /* Set up waitstates for the peripherals */
set_cpu_frequency(0); /* PLL off */ set_cpu_frequency(0); /* PLL off */
#ifdef CPU_COLDFIRE
coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
#endif
#endif #endif
#ifdef HAVE_UDA1380 #ifdef HAVE_UDA1380

View file

@ -4,6 +4,7 @@ logf.c
#endif #endif
backlight.c backlight.c
buffer.c buffer.c
general.c
common/atoi.c common/atoi.c
common/crc32.c common/crc32.c
common/ctype.c common/ctype.c
@ -45,7 +46,12 @@ target/coldfire/memcpy-coldfire.S
target/coldfire/memmove-coldfire.S target/coldfire/memmove-coldfire.S
target/coldfire/memset-coldfire.S target/coldfire/memset-coldfire.S
target/coldfire/memset16-coldfire.S target/coldfire/memset16-coldfire.S
#ifndef SIMULATOR
#ifndef BOOTLOADER
target/coldfire/pcm-coldfire.c
#endif
target/coldfire/system-coldfire.c target/coldfire/system-coldfire.c
#endif
#elif (CONFIG_CPU == SH7034) #elif (CONFIG_CPU == SH7034)
target/sh/memcpy-sh.S target/sh/memcpy-sh.S
target/sh/memmove-sh.S target/sh/memmove-sh.S
@ -207,15 +213,21 @@ drivers/wm8731l.c
#elif defined(HAVE_TLV320) && !defined(SIMULATOR) #elif defined(HAVE_TLV320) && !defined(SIMULATOR)
drivers/tlv320.c drivers/tlv320.c
#endif #endif
#if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) #if (CONFIG_CODEC == SWCODEC) && !defined(BOOTLOADER)
pcm_playback.c pcm_sampr.c
#endif
#if CONFIG_CODEC == SWCODEC
replaygain.c replaygain.c
#endif #ifndef SIMULATOR
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) pcm_playback.c
#endif /* SIMULATOR */
#ifdef HAVE_RECORDING
enc_base.c
#if defined(CPU_COLDFIRE)
#ifndef SIMULATOR
pcm_record.c pcm_record.c
#endif #endif /* SIMULATOR */
#endif /* CPU_COLDFIRE */
#endif /* HAVE_RECORDING */
#endif /* SWCODEC && !BOOTLOADER */
sound.c sound.c
#if defined(IRIVER_IFP7XX_SERIES) && defined(STUB) #if defined(IRIVER_IFP7XX_SERIES) && defined(STUB)
common/sscanf.c common/sscanf.c

View file

@ -82,7 +82,7 @@ void tlv320_init(void)
tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */
tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S);
tlv320_write_reg(REG_DIA, DIA_ACT); tlv320_write_reg(REG_DIA, DIA_ACT);
tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ tlv320_set_frequency(-1); /* default */
/* All ON except ADC, MIC and LINE */ /* All ON except ADC, MIC and LINE */
tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE);
} }
@ -95,6 +95,32 @@ void tlv320_reset(void)
tlv320_write_reg(REG_RR, RR_RESET); tlv320_write_reg(REG_RR, RR_RESET);
} }
/**
* Sets internal sample rate for DAC and ADC relative to MCLK
* Selection for frequency:
* Fs: tlv: with:
* 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16
* 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8
* 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default)
* 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2
*/
void tlv320_set_frequency(unsigned fsel)
{
/* All rates available for 11.2896MHz besides 8.021 */
unsigned char values_src[3] =
{
/* Fs: */
(0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */
(0x8 << 2), /* 44100 */
(0xf << 2), /* 88200 */
};
if (fsel >= ARRAYLEN(values_src))
fsel = 1;
tlv320_write_reg(REG_SRC, values_src[fsel]);
}
/** /**
* Sets left and right headphone volume * Sets left and right headphone volume
* *
@ -142,7 +168,6 @@ void tlv320_set_recvol(int left, int right, int type)
value_aap &= ~AAP_MICB; value_aap &= ~AAP_MICB;
tlv320_write_reg(REG_AAP, value_aap); tlv320_write_reg(REG_AAP, value_aap);
} }
else if (type == AUDIO_GAIN_LINEIN) else if (type == AUDIO_GAIN_LINEIN)
{ {
@ -180,15 +205,17 @@ void tlv320_mute(bool mute)
} }
/* Nice shutdown of TLV320 codec */ /* Nice shutdown of TLV320 codec */
void tlv320_close() void tlv320_close(void)
{ {
tlv320_mute(true);
sleep(HZ/8);
tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT |
PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */
} }
void tlv320_enable_recording(bool source_mic) void tlv320_enable_recording(bool source_mic)
{ {
unsigned value_daif = tlv320_regs[REG_DAIF];
unsigned value_aap, value_pc; unsigned value_aap, value_pc;
if (source_mic) if (source_mic)
@ -205,20 +232,12 @@ void tlv320_enable_recording(bool source_mic)
tlv320_write_reg(REG_PC, value_pc); tlv320_write_reg(REG_PC, value_pc);
tlv320_write_reg(REG_AAP, value_aap); tlv320_write_reg(REG_AAP, value_aap);
/* Enable MASTER mode (start sending I2S data to the CPU) */
value_daif |= DAIF_MS;
tlv320_write_reg(REG_DAIF, value_daif);
} }
void tlv320_disable_recording() void tlv320_disable_recording(void)
{ {
unsigned value_pc = tlv320_regs[REG_PC]; unsigned value_pc = tlv320_regs[REG_PC];
unsigned value_aap = tlv320_regs[REG_AAP]; unsigned value_aap = tlv320_regs[REG_AAP];
unsigned value_daif = tlv320_regs[REG_DAIF];
value_daif &= ~DAIF_MS; /* disable MASTER mode */
tlv320_write_reg(REG_DAIF, value_daif);
value_aap |= AAP_MICM; /* mute MIC */ value_aap |= AAP_MICM; /* mute MIC */
tlv320_write_reg(REG_PC, value_aap); tlv320_write_reg(REG_PC, value_aap);

View file

@ -49,9 +49,10 @@ short recgain_line;
#define NUM_DEFAULT_REGS 13 #define NUM_DEFAULT_REGS 13
unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] =
{ {
REG_0, EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50, REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK |
SYSCLK_256FS | WSPLL_25_50,
REG_I2S, I2S_IFMT_IIS, REG_I2S, I2S_IFMT_IIS,
REG_PWR, PON_BIAS, REG_PWR, PON_PLL | PON_BIAS,
/* PON_HP & PON_DAC is enabled later */ /* PON_HP & PON_DAC is enabled later */
REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f),
/* 00=max, 3f=mute */ /* 00=max, 3f=mute */
@ -60,7 +61,7 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] =
REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff),
/* 00=max, ff=mute */ /* 00=max, ff=mute */
REG_EQ, EQ_MODE_MAX, REG_EQ, EQ_MODE_MAX,
/* Bass and tremble = 0 dB */ /* Bass and treble = 0 dB */
REG_MUTE, MUTE_MASTER | MUTE_CH2, REG_MUTE, MUTE_MASTER | MUTE_CH2,
/* Mute everything to start with */ /* Mute everything to start with */
REG_MIX_CTL, MIX_CTL_MIX, REG_MIX_CTL, MIX_CTL_MIX,
@ -192,6 +193,43 @@ void uda1380_reset(void)
#endif #endif
} }
/**
* Sets frequency settings for DAC and ADC relative to MCLK
*
* Selection for frequency ranges:
* Fs: range: with:
* 11025: 0 = 6.25 to 12.5 MCLK/2 SCLK, LRCK: Audio Clk / 16
* 22050: 1 = 12.5 to 25 MCLK/2 SCLK, LRCK: Audio Clk / 8
* 44100: 2 = 25 to 50 MCLK SCLK, LRCK: Audio Clk / 4 (default)
* 88200: 3 = 50 to 100 MCLK SCLK, LRCK: Audio Clk / 2 <= TODO: Needs WSPLL
*/
void uda1380_set_frequency(unsigned fsel)
{
static const unsigned short values_reg[4][2] =
{
/* Fs: */
{ 0, WSPLL_625_125 | SYSCLK_512FS }, /* 11025 */
{ 0, WSPLL_125_25 | SYSCLK_256FS }, /* 22050 */
{ MIX_CTL_SEL_NS, WSPLL_25_50 | SYSCLK_256FS }, /* 44100 */
{ MIX_CTL_SEL_NS, WSPLL_50_100 | SYSCLK_256FS }, /* 88200 */
};
const unsigned short *ent;
if (fsel >= ARRAYLEN(values_reg))
fsel = 2;
ent = values_reg[fsel];
/* Set WSPLL input frequency range or SYSCLK divider */
uda1380_regs[REG_0] &= ~0xf;
uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]);
/* Choose 3rd order or 5th order noise shaper */
uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS;
uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]);
}
/* Initialize UDA1380 codec with default register values (uda1380_defaults) */ /* Initialize UDA1380 codec with default register values (uda1380_defaults) */
int uda1380_init(void) int uda1380_init(void)
{ {
@ -227,30 +265,34 @@ void uda1380_close(void)
*/ */
void uda1380_enable_recording(bool source_mic) void uda1380_enable_recording(bool source_mic)
{ {
uda1380_regs[REG_0] &= ~(ADC_CLK | DAC_CLK);
uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC); uda1380_write_reg(REG_0, uda1380_regs[REG_0] | EN_ADC);
if (source_mic) if (source_mic)
{ {
/* VGA_GAIN: 0=0 dB, F=30dB */ /* VGA_GAIN: 0=0 dB, F=30dB */
/* Output of left ADC is fed into right bitstream */
uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_PGAR | PON_ADCR);
uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL);
uda1380_regs[REG_ADC] &= ~SKIP_DCFIL;
uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK)
| SEL_LNA | SEL_MIC | EN_DCFIL); | SEL_LNA | SEL_MIC | EN_DCFIL);
uda1380_write_reg(REG_PGA, 0); uda1380_write_reg(REG_PGA, 0);
} else }
else
{ {
/* PGA_GAIN: 0=0 dB, F=24dB */ /* PGA_GAIN: 0=0 dB, F=24dB */
uda1380_regs[REG_PWR] &= ~(PON_PLL | PON_LNA);
uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL
| PON_PGAR | PON_ADCR); | PON_PGAR | PON_ADCR);
uda1380_write_reg(REG_ADC, EN_DCFIL); uda1380_write_reg(REG_ADC, EN_DCFIL);
uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & PGA_GAIN_MASK) uda1380_write_reg(REG_PGA, uda1380_regs[REG_PGA] & PGA_GAIN_MASK);
| PGA_GAINL(0) | PGA_GAINR(0));
} }
sleep(HZ/8); sleep(HZ/8);
uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER);
uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1));
} }
/** /**
@ -262,10 +304,13 @@ void uda1380_disable_recording(void)
sleep(HZ/8); sleep(HZ/8);
uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); uda1380_write_reg(REG_I2S, I2S_IFMT_IIS);
uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] & ~(PON_LNA | PON_ADCL
| PON_ADCR | PON_PGAL uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | PON_PGAL | PON_PGAR);
| PON_PGAR)); uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PLL);
uda1380_write_reg(REG_0, uda1380_regs[REG_0] & ~EN_ADC);
uda1380_regs[REG_0] &= ~EN_ADC;
uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ADC_CLK | DAC_CLK);
uda1380_write_reg(REG_ADC, SKIP_DCFIL); uda1380_write_reg(REG_ADC, SKIP_DCFIL);
} }
@ -373,20 +418,3 @@ void uda1380_set_monitor(int enable)
else /* mute channel 2 */ else /* mute channel 2 */
uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2);
} }
/* Change the order of the noise chaper,
5th order is recommended above 32kHz */
void uda1380_set_nsorder(int order)
{
switch(order)
{
case 5:
uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL]
| MIX_CTL_SEL_NS);
break;
case 3:
default:
uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL]
& ~MIX_CTL_SEL_NS);
}
}

View file

@ -20,6 +20,20 @@
#define AUDIO_H #define AUDIO_H
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h>
/* These must always be included with audio.h for this to compile under
cetain conditions. Do it here or else spread the complication around to
many files. */
#if CONFIG_CODEC == SWCODEC
#include "pcm_sampr.h"
#include "pcm_playback.h"
#ifdef HAVE_RECORDING
#include "pcm_record.h"
#include "id3.h"
#include "enc_base.h"
#endif /* HAVE_RECORDING */
#endif /* CONFIG_CODEC == SWCODEC */
#ifdef SIMULATOR #ifdef SIMULATOR
#define audio_play(x) sim_audio_play(x) #define audio_play(x) sim_audio_play(x)
@ -31,9 +45,6 @@
#define AUDIO_STATUS_PRERECORD 8 #define AUDIO_STATUS_PRERECORD 8
#define AUDIO_STATUS_ERROR 16 #define AUDIO_STATUS_ERROR 16
#define AUDIO_STATUS_STAYON_FLAGS \
(AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE | AUDIO_STATUS_RECORD | AUDIO_)
#define AUDIOERR_DISK_FULL 1 #define AUDIOERR_DISK_FULL 1
#define AUDIO_GAIN_LINEIN 0 #define AUDIO_GAIN_LINEIN 0
@ -72,10 +83,11 @@ void audio_resume(void);
void audio_next(void); void audio_next(void);
void audio_prev(void); void audio_prev(void);
int audio_status(void); int audio_status(void);
bool audio_query_poweroff(void); #if CONFIG_CODEC == SWCODEC
int audio_track_count(void); /* SWCODEC only */ int audio_track_count(void); /* SWCODEC only */
long audio_filebufused(void); /* SWCODEC only */ long audio_filebufused(void); /* SWCODEC only */
void audio_pre_ff_rewind(void); /* SWCODEC only */ void audio_pre_ff_rewind(void); /* SWCODEC only */
#endif /* CONFIG_CODEC == SWCODEC */
void audio_ff_rewind(long newtime); void audio_ff_rewind(long newtime);
void audio_flush_and_reload_tracks(void); void audio_flush_and_reload_tracks(void);
struct mp3entry* audio_current_track(void); struct mp3entry* audio_current_track(void);
@ -89,18 +101,28 @@ void audio_error_clear(void);
int audio_get_file_pos(void); int audio_get_file_pos(void);
void audio_beep(int duration); void audio_beep(int duration);
void audio_init_playback(void); void audio_init_playback(void);
unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size);
/* audio recording functions */ /* channel modes */
void audio_init_recording(unsigned int buffer_offset); enum rec_channel_modes
void audio_close_recording(void); {
void audio_record(const char *filename); __CHN_MODE_START_INDEX = -1,
void audio_stop_recording(void);
void audio_pause_recording(void); CHN_MODE_STEREO,
void audio_resume_recording(void); CHN_MODE_MONO,
void audio_new_file(const char *filename);
CHN_NUM_MODES
};
#if CONFIG_CODEC == SWCODEC
/* channel mode capability bits */
#define CHN_CAP_STEREO (1 << CHN_MODE_STEREO)
#define CHN_CAP_MONO (1 << CHN_MODE_MONO)
#define CHN_CAP_ALL (CHN_CAP_STEREO | CHN_CAP_MONO)
#endif /* CONFIG_CODEC == SWCODEC */
/* audio sources */ /* audio sources */
enum enum audio_sources
{ {
AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */
AUDIO_SRC_MIC, /* monitor mic */ AUDIO_SRC_MIC, /* monitor mic */
@ -123,33 +145,57 @@ enum
AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1
}; };
/* channel modes */ #ifdef HAVE_RECORDING
enum /* parameters for audio_set_recording_options */
struct audio_recording_options
{ {
CHN_MODE_MONO = 1, int rec_source;
CHN_MODE_STEREO, int rec_frequency;
int rec_channels;
int rec_prerecord_time;
#if CONFIG_CODEC == SWCODEC
int rec_source_flags; /* for rec_set_source */
struct encoder_config enc_config;
#else
int rec_quality;
bool rec_editable;
#endif
}; };
void audio_set_recording_options(int frequency, int quality,
int source, int channel_mode, /* audio recording functions */
bool editable, int prerecord_time); void audio_init_recording(unsigned int buffer_offset);
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(struct audio_recording_options *options);
void audio_set_recording_gain(int left, int right, int type); void audio_set_recording_gain(int left, int right, int type);
unsigned long audio_recorded_time(void); unsigned long audio_recorded_time(void);
unsigned long audio_num_recorded_bytes(void); unsigned long audio_num_recorded_bytes(void);
#if 0
#if CONFIG_CODEC == SWCODEC
/* SWCODEC recoring functions */
/* playback.c */
bool audio_load_encoder(int afmt);
void audio_remove_encoder(void);
unsigned char *audio_get_recording_buffer(size_t *buffer_size);
#endif /* CONFIG_CODEC == SWCODEC */
#endif /* HAVE_RECORDING */
#ifdef HAVE_SPDIF_IN
#ifdef HAVE_SPDIF_POWER #ifdef HAVE_SPDIF_POWER
void audio_set_spdif_power_setting(bool on); void audio_set_spdif_power_setting(bool on);
bool audio_get_spdif_power_setting(void);
#endif #endif
#endif /* returns index into rec_master_sampr_list */
unsigned long audio_get_spdif_sample_rate(void); int audio_get_spdif_sample_rate(void);
/* > 0: monitor EBUin, 0: Monitor IISrecv, <0: reset only */
void audio_spdif_set_monitor(int monitor_spdif);
#endif /* HAVE_SPDIF_IN */
unsigned long audio_prev_elapsed(void); unsigned long audio_prev_elapsed(void);
#if CONFIG_CODEC == SWCODEC
/* audio encoder functions (defined in playback.c) */
int audio_get_encoder_id(void);
void audio_load_encoder(int enc_id);
void audio_remove_encoder(void);
#endif /* CONFIG_CODEC == SWCODEC */
/***********************************************************************/ /***********************************************************************/

View file

@ -84,6 +84,12 @@
/* define this if you have recording possibility */ /* define this if you have recording possibility */
#define HAVE_RECORDING 1 #define HAVE_RECORDING 1
/* define hardware samples rate caps mask */
#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
/* define the bitmask of recording sample rates */
#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
#define HAVE_AGC #define HAVE_AGC
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -77,6 +77,12 @@
/* define this if you have recording possibility */ /* define this if you have recording possibility */
#define HAVE_RECORDING 1 #define HAVE_RECORDING 1
/* define hardware samples rate caps mask */
#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
/* define the bitmask of recording sample rates */
#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
#define HAVE_AGC #define HAVE_AGC
#define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */

View file

@ -72,6 +72,12 @@
/* define this if you have recording possibility */ /* define this if you have recording possibility */
#define HAVE_RECORDING 1 #define HAVE_RECORDING 1
/* define hardware samples rate caps mask */
#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
/* define the bitmask of recording sample rates */
#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
#define HAVE_AGC #define HAVE_AGC
#define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */
@ -157,4 +163,3 @@
/* Define this for FM radio input available */ /* Define this for FM radio input available */
#define HAVE_FMRADIO_IN #define HAVE_FMRADIO_IN

View file

@ -9,6 +9,12 @@
/* define this if you have recording possibility */ /* define this if you have recording possibility */
#define HAVE_RECORDING 1 #define HAVE_RECORDING 1
/* define the bitmask of hardware sample rates */
#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
/* define the bitmask of recording sample rates */
#define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11)
/* define this if you have a bitmap LCD display */ /* define this if you have a bitmap LCD display */
#define HAVE_LCD_BITMAP 1 #define HAVE_LCD_BITMAP 1

View file

@ -24,13 +24,19 @@
#include "file.h" #include "file.h"
/* Audio file types. */ /* Audio file types. */
enum { enum
{
AFMT_UNKNOWN = 0, /* Unknown file format */ AFMT_UNKNOWN = 0, /* Unknown file format */
/* start formats */
AFMT_MPA_L1, /* MPEG Audio layer 1 */ AFMT_MPA_L1, /* MPEG Audio layer 1 */
AFMT_MPA_L2, /* MPEG Audio layer 2 */ AFMT_MPA_L2, /* MPEG Audio layer 2 */
AFMT_MPA_L3, /* MPEG Audio layer 3 */ AFMT_MPA_L3, /* MPEG Audio layer 3 */
AFMT_AIFF, /* Audio Interchange File Format */
#if CONFIG_CODEC == SWCODEC
AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */
AFMT_OGG_VORBIS, /* Ogg Vorbis */ AFMT_OGG_VORBIS, /* Ogg Vorbis */
AFMT_FLAC, /* FLAC */ AFMT_FLAC, /* FLAC */
@ -40,54 +46,91 @@ enum {
AFMT_ALAC, /* Apple Lossless Audio Codec */ AFMT_ALAC, /* Apple Lossless Audio Codec */
AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */
AFMT_SHN, /* Shorten */ AFMT_SHN, /* Shorten */
AFMT_AIFF, /* Audio Interchange File Format */
AFMT_SID, /* SID File Format */ AFMT_SID, /* SID File Format */
AFMT_ADX, /* ADX */ AFMT_ADX, /* ADX File Format */
#endif
/* New formats must be added to the end of this list */ /* add new formats at any index above this line to have a sensible order -
specified array index inits are used */
/* format arrays defined in id3.c */
AFMT_NUM_CODECS, AFMT_NUM_CODECS,
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
/* masks to decompose parts */ /* masks to decompose parts */
CODEC_AFMT_MASK = 0x0fff, CODEC_AFMT_MASK = 0x0fff,
CODEC_TYPE_MASK = 0x7000, CODEC_TYPE_MASK = 0x7000,
/* switch for specifying codec type when requesting a filename */ /* switch for specifying codec type when requesting a filename */
CODEC_TYPE_DECODER = (0 << 12), /* default */ CODEC_TYPE_DECODER = (0 << 12), /* default */
CODEC_TYPE_ENCODER = (1 << 12) CODEC_TYPE_ENCODER = (1 << 12),
#endif #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
}; };
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
#define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ #define CODEC_EXTENSION "codec"
{ label, codec_fname, codec_enc_fname, enc_ext }
#else #ifdef HAVE_RECORDING
#define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ #define ENCODER_SUFFIX "_enc"
{ label } enum rec_format_indexes
#endif {
__REC_FORMAT_START_INDEX = -1,
/* start formats */
REC_FORMAT_PCM_WAV,
REC_FORMAT_WAVPACK,
REC_FORMAT_MPA_L3,
/* add new formats at any index above this line to have a sensible order -
specified array index inits are used
REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
*/
REC_NUM_FORMATS,
REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
REC_FORMAT_CFG_NUM_BITS = 2
};
#define REC_FORMAT_CFG_VAL_LIST "wave,wvpk,mpa3"
/* get REC_FORMAT_* corresponding AFMT_* */
extern const int rec_format_afmt[REC_NUM_FORMATS];
/* get AFMT_* corresponding REC_FORMAT_* */
extern const int afmt_rec_format[AFMT_NUM_CODECS];
#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
{ label, root_fname, enc_root_fname, ext_list }
#else /* !HAVE_RECORDING */
#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
{ label, root_fname, ext_list }
#endif /* HAVE_RECORDING */
#else /* !SWCODEC */
#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
{ label, ext_list }
#endif /* CONFIG_CODEC == SWCODEC */
/* record describing the audio format */ /* record describing the audio format */
struct afmt_entry struct afmt_entry
{ {
#if CONFIG_CODEC == SWCODEC
char label[8]; /* format label */ char label[8]; /* format label */
char *codec_fn; /* filename of decoder codec */ #if CONFIG_CODEC == SWCODEC
char *codec_enc_fn; /* filename of encoder codec */ char *codec_root_fn; /* root codec filename (sans _enc and .codec) */
char *ext; /* default extension for file (enc only for now) */ #ifdef HAVE_RECORDING
#else char *codec_enc_root_fn; /* filename of encoder codec */
char label[4];
#endif #endif
#endif
char *ext_list; /* double NULL terminated extension
list for type with the first as
the default for recording */
}; };
/* database of labels and codecs. add formats per above enum */ /* database of labels and codecs. add formats per above enum */
extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS];
#if CONFIG_CODEC == SWCODEC
/* recording quality to AFMT_* */
extern const int rec_quality_info_afmt[9];
#endif
struct mp3entry { struct mp3entry {
char path[MAX_PATH]; char path[MAX_PATH];
char* title; char* title;

View file

@ -19,11 +19,23 @@
#ifndef PCM_PLAYBACK_H #ifndef PCM_PLAYBACK_H
#define PCM_PLAYBACK_H #define PCM_PLAYBACK_H
#include <sys/types.h>
/* Typedef for registered callback (play and record) */
typedef void (*pcm_more_callback_type)(unsigned char **start,
size_t *size);
void pcm_init(void); void pcm_init(void);
/* set the pcm frequency - use values in hw_sampr_list
* use -1 for the default frequency
*/
void pcm_set_frequency(unsigned int frequency); void pcm_set_frequency(unsigned int frequency);
/* apply settings to hardware immediately */
void pcm_apply_settings(bool reset);
/* This is for playing "raw" PCM data */ /* This is for playing "raw" PCM data */
void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), void pcm_play_data(pcm_more_callback_type get_more,
unsigned char* start, size_t size); unsigned char* start, size_t size);
void pcm_calculate_peaks(int *left, int *right); void pcm_calculate_peaks(int *left, int *right);
@ -35,4 +47,4 @@ void pcm_play_pause(bool play);
bool pcm_is_paused(void); bool pcm_is_paused(void);
bool pcm_is_playing(void); bool pcm_is_playing(void);
#endif #endif /* PCM_PLAYBACK_H */

View file

@ -20,24 +20,44 @@
#ifndef PCM_RECORD_H #ifndef PCM_RECORD_H
#define PCM_RECORD_H #define PCM_RECORD_H
void enc_set_parameters(int chunk_size, int num_chunks, #define DMA_REC_ERROR_DMA ((size_t)-1)
int samp_per_chunk, char *head_ptr, int head_size, #ifdef HAVE_SPDIF_IN
int enc_id); #define DMA_REC_ERROR_SPDIF ((size_t)-2)
void enc_get_inputs(int *buffer_size, int *channels, int *quality); #endif
unsigned int* enc_alloc_chunk(void); /* Use AUDIO_SRC_* enumeration values */
void enc_free_chunk(void); void pcm_set_monitor(int monitor);
int enc_wavbuf_near_empty(void); void pcm_set_rec_source(int source);
char* enc_get_wav_data(int size);
extern void (*enc_set_header_callback)(void *head_buffer, int head_size,
int num_pcm_samples, bool is_file_header);
/**
* RAW pcm data recording
* These calls are nescessary only when using the raw pcm apis directly.
*/
/* Initialize pcm recording interface */
void pcm_init_recording(void);
/* Uninitialze pcm recording interface */
void pcm_close_recording(void);
/* Start recording "raw" PCM data */
void pcm_record_data(pcm_more_callback_type more_ready,
unsigned char *start, size_t size);
/* Stop tranferring data into supplied buffer */
void pcm_stop_recording(void);
void pcm_calculate_rec_peaks(int *left, int *right);
/** General functions for high level codec recording **/
void pcm_rec_error_clear(void);
unsigned long pcm_rec_status(void); 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);
int pcm_rec_current_bitrate(void); int pcm_rec_current_bitrate(void);
int pcm_rec_encoder_afmt(void); /* AFMT_* value, AFMT_UNKNOWN if none */
int pcm_rec_rec_format(void); /* Format index or -1 otherwise */
unsigned long pcm_rec_sample_rate(void);
int pcm_get_num_unprocessed(void); int pcm_get_num_unprocessed(void);
void pcm_rec_get_peaks(int *left, int *right);
/* audio.h contains audio recording functions */ /* audio.h contains audio_* recording functions */
#endif #endif /* PCM_RECORD_H */

View file

@ -21,7 +21,6 @@
#define __SYSTEM_H__ #define __SYSTEM_H__
#include "cpu.h" #include "cpu.h"
#include "config.h"
#include "stdbool.h" #include "stdbool.h"
extern void system_reboot (void); extern void system_reboot (void);
@ -111,6 +110,23 @@ const char *get_cpu_boost_tracker(void);
#define MAX(a, b) (((a)>(b))?(a):(b)) #define MAX(a, b) (((a)>(b))?(a):(b))
#endif #endif
/* return number of elements in array a */
#define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0]))
/* return p incremented by specified number of bytes */
#define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count)))
#define P2_M1(p2) ((1 << (p2))-1)
/* align up or down to nearest 2^p2 */
#define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2))
#define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2)
/* align up or down to nearest integer multiple of a */
#define ALIGN_DOWN(n, a) ((n)/(a)*(a))
#define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a)
/* live endianness conversion */
#ifdef ROCKBOX_LITTLE_ENDIAN #ifdef ROCKBOX_LITTLE_ENDIAN
#define letoh16(x) (x) #define letoh16(x) (x)
#define letoh32(x) (x) #define letoh32(x) (x)
@ -120,6 +136,8 @@ const char *get_cpu_boost_tracker(void);
#define betoh32(x) swap32(x) #define betoh32(x) swap32(x)
#define htobe16(x) swap16(x) #define htobe16(x) swap16(x)
#define htobe32(x) swap32(x) #define htobe32(x) swap32(x)
#define swap_odd_even_be32(x) (x)
#define swap_odd_even_le32(x) swap_odd_even32(x)
#else #else
#define letoh16(x) swap16(x) #define letoh16(x) swap16(x)
#define letoh32(x) swap32(x) #define letoh32(x) swap32(x)
@ -129,6 +147,37 @@ const char *get_cpu_boost_tracker(void);
#define betoh32(x) (x) #define betoh32(x) (x)
#define htobe16(x) (x) #define htobe16(x) (x)
#define htobe32(x) (x) #define htobe32(x) (x)
#define swap_odd_even_be32(x) swap_odd_even32(x)
#define swap_odd_even_le32(x) (x)
#endif
/* static endianness conversion */
#define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \
((unsigned short)(x) << 8)))
#define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \
(((unsigned long)(x) & 0xff0000ul) >> 8) | \
(((unsigned long)(x) & 0xff00ul) << 8) | \
((unsigned long)(x) << 24)))
#ifdef ROCKBOX_LITTLE_ENDIAN
#define LE_TO_H16(x) (x)
#define LE_TO_H32(x) (x)
#define H_TO_LE16(x) (x)
#define H_TO_LE32(x) (x)
#define BE_TO_H16(x) SWAP_16(x)
#define BE_TO_H32(x) SWAP_32(x)
#define H_TO_BE16(x) SWAP_16(x)
#define H_TO_BE32(x) SWAP_32(x)
#else
#define LE_TO_H16(x) SWAP_16(x)
#define LE_TO_H32(x) SWAP_32(x)
#define H_TO_LE16(x) SWAP_16(x)
#define H_TO_LE32(x) SWAP_32(x)
#define BE_TO_H16(x) (x)
#define BE_TO_H32(x) (x)
#define H_TO_BE16(x) (x)
#define H_TO_BE32(x) (x)
#endif #endif
@ -181,6 +230,7 @@ enum {
: /* %0 */ I_CONSTRAINT((char)(mask)), \ : /* %0 */ I_CONSTRAINT((char)(mask)), \
/* %1 */ "z"(address-GBR)) /* %1 */ "z"(address-GBR))
#endif /* CONFIG_CPU == SH7034 */ #endif /* CONFIG_CPU == SH7034 */
#ifndef SIMULATOR #ifndef SIMULATOR
@ -388,7 +438,20 @@ static inline unsigned long swap32(unsigned long value)
#define invalidate_icache() #define invalidate_icache()
#endif #endif
#else
#ifndef CPU_COLDFIRE
static inline unsigned long swap_odd_even32(unsigned long value)
{
/*
result[31..24],[15.. 8] = value[23..16],[ 7.. 0]
result[23..16],[ 7.. 0] = value[31..24],[15.. 8]
*/
unsigned long t = value & 0xff00ff00;
return (t >> 8) | ((t ^ value) << 8);
}
#endif
#else /* SIMULATOR */
static inline unsigned short swap16(unsigned short value) static inline unsigned short swap16(unsigned short value)
/* /*
@ -412,8 +475,18 @@ static inline unsigned long swap32(unsigned long value)
return (lo << 16) | hi; return (lo << 16) | hi;
} }
static inline unsigned long swap_odd_even32(unsigned long value)
{
/*
result[31..24],[15.. 8] = value[23..16],[ 7.. 0]
result[23..16],[ 7.. 0] = value[31..24],[15.. 8]
*/
unsigned long t = value & 0xff00ff00;
return (t >> 8) | ((t ^ value) << 8);
}
#define invalidate_icache() #define invalidate_icache()
#endif #endif /* !SIMULATOR */
#endif #endif /* __SYSTEM_H__ */

View file

@ -142,7 +142,10 @@ void switch_thread(bool save_context, struct thread_entry **blocked_list);
void sleep_thread(int ticks); void sleep_thread(int ticks);
void block_thread(struct thread_entry **thread, int timeout); void block_thread(struct thread_entry **thread, int timeout);
void wakeup_thread(struct thread_entry **thread); void wakeup_thread(struct thread_entry **thread);
#ifdef HAVE_PRIORITY_SCHEDULING
int thread_set_priority(struct thread_entry *thread, int priority); int thread_set_priority(struct thread_entry *thread, int priority);
int thread_get_priority(struct thread_entry *thread);
#endif
void init_threads(void); void init_threads(void);
int thread_stack_usage(const struct thread_entry *thread); int thread_stack_usage(const struct thread_entry *thread);
int thread_get_status(const struct thread_entry *thread); int thread_get_status(const struct thread_entry *thread);

View file

@ -24,6 +24,16 @@
extern void tlv320_init(void); extern void tlv320_init(void);
extern void tlv320_reset(void); extern void tlv320_reset(void);
/**
* Sets internal sample rate for DAC and ADC relative to MCLK
* Selection for frequency:
* Fs: tlv: with:
* 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16
* 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8
* 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default)
* 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2
*/
extern void tlv320_set_frequency(unsigned fsel);
extern void tlv320_enable_output(bool enable); extern void tlv320_enable_output(bool enable);
extern void tlv320_set_headphone_vol(int vol_l, int vol_r); extern void tlv320_set_headphone_vol(int vol_l, int vol_r);
extern void tlv320_set_recvol(int left, int right, int type); extern void tlv320_set_recvol(int left, int right, int type);

View file

@ -28,8 +28,17 @@ extern void uda1380_set_bass(int value);
extern void uda1380_set_treble(int value); extern void uda1380_set_treble(int value);
extern int uda1380_mute(int mute); extern int uda1380_mute(int mute);
extern void uda1380_close(void); extern void uda1380_close(void);
extern void uda1380_set_nsorder(int order); /**
* Sets frequency settings for DAC and ADC relative to MCLK
*
* Selection for frequency ranges:
* Fs: range: with:
* 11025: 0 = 6.25 to 12.5 SCLK, LRCK: Audio Clk / 16
* 22050: 1 = 12.5 to 25 SCLK, LRCK: Audio Clk / 8
* 44100: 2 = 25 to 50 SCLK, LRCK: Audio Clk / 4 (default)
* 88200: 3 = 50 to 100 SCLK, LRCK: Audio Clk / 2
*/
extern void uda1380_set_frequency(unsigned fsel);
extern void uda1380_enable_recording(bool source_mic); extern void uda1380_enable_recording(bool source_mic);
extern void uda1380_disable_recording(void); extern void uda1380_disable_recording(void);
extern void uda1380_set_recvol(int left, int right, int type); extern void uda1380_set_recvol(int left, int right, int type);

View file

@ -44,6 +44,89 @@
#include "replaygain.h" #include "replaygain.h"
#include "rbunicode.h" #include "rbunicode.h"
/** Database of audio formats **/
const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
{
/* Unknown file format */
[AFMT_UNKNOWN] =
AFMT_ENTRY("???", NULL, NULL, NULL ),
/* MPEG Audio layer 1 */
[AFMT_MPA_L1] =
AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ),
/* MPEG Audio layer 2 */
[AFMT_MPA_L2] =
AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ),
/* MPEG Audio layer 3 */
[AFMT_MPA_L3] =
AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ),
/* Audio Interchange File Format */
[AFMT_AIFF] =
AFMT_ENTRY("AIFF", "aiff", NULL, "aiff\0aif\0"),
#if CONFIG_CODEC == SWCODEC
/* Uncompressed PCM in a WAV file */
[AFMT_PCM_WAV] =
AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ),
/* Ogg Vorbis */
[AFMT_OGG_VORBIS] =
AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ),
/* FLAC */
[AFMT_FLAC] =
AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ),
/* Musepack */
[AFMT_MPC] =
AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ),
/* A/52 (aka AC3) audio */
[AFMT_A52] =
AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ),
/* WavPack */
[AFMT_WAVPACK] =
AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ),
/* Apple Lossless Audio Codec */
[AFMT_ALAC] =
AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0" ),
/* Advanced Audio Coding in M4A container */
[AFMT_AAC] =
AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ),
/* Shorten */
[AFMT_SHN] =
AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ),
/* SID File Format */
[AFMT_SID] =
AFMT_ENTRY("SID", "sid", NULL, "sid\0" ),
/* ADX File Format */
[AFMT_ADX] =
AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ),
#endif
};
#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
/* get REC_FORMAT_* corresponding AFMT_* */
const int rec_format_afmt[REC_NUM_FORMATS] =
{
/* give AFMT_UNKNOWN by default */
[0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
/* add new entries below this line */
[REC_FORMAT_MPA_L3] = AFMT_MPA_L3,
[REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
[REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
};
/* get AFMT_* corresponding REC_FORMAT_* */
const int afmt_rec_format[AFMT_NUM_CODECS] =
{
/* give -1 by default */
[0 ... AFMT_NUM_CODECS-1] = -1,
/* add new entries below this line */
[AFMT_MPA_L3] = REC_FORMAT_MPA_L3,
[AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
[AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,
};
#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
/****/
#define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \
((long)(b1 & 0x7F) << (2*7)) | \ ((long)(b1 & 0x7F) << (2*7)) | \
((long)(b2 & 0x7F) << (1*7)) | \ ((long)(b2 & 0x7F) << (1*7)) | \
@ -85,61 +168,6 @@ static const char* const genres[] = {
"Synthpop" "Synthpop"
}; };
/* database of audio formats */
const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
{
/* Unknown file format */
AFMT_ENTRY("???", NULL, NULL, NULL ),
/* MPEG Audio layer 1 */
AFMT_ENTRY("MP1", "mpa.codec", NULL, NULL ),
/* MPEG Audio layer 2 */
AFMT_ENTRY("MP2", "mpa.codec", NULL, NULL ),
/* MPEG Audio layer 3 */
AFMT_ENTRY("MP3", "mpa.codec", "mp3_enc.codec", ".mp3"),
#if CONFIG_CODEC == SWCODEC
/* Uncompressed PCM in a WAV file */
AFMT_ENTRY("WAV", "wav.codec", "wav_enc.codec", ".wav"),
/* Ogg Vorbis */
AFMT_ENTRY("Ogg", "vorbis.codec", NULL, NULL ),
/* FLAC */
AFMT_ENTRY("FLAC", "flac.codec", NULL, NULL ),
/* Musepack */
AFMT_ENTRY("MPC", "mpc.codec", NULL, NULL ),
/* A/52 (aka AC3) audio */
AFMT_ENTRY("AC3", "a52.codec", NULL, NULL ),
/* WavPack */
AFMT_ENTRY("WV", "wavpack.codec", "wavpack_enc.codec", ".wv" ),
/* Apple Lossless Audio Codec */
AFMT_ENTRY("ALAC", "alac.codec", NULL, NULL ),
/* Advanced Audio Coding in M4A container */
AFMT_ENTRY("AAC", "aac.codec", NULL, NULL ),
/* Shorten */
AFMT_ENTRY("SHN", "shorten.codec", NULL, NULL ),
/* Audio Interchange File Format */
AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ),
/* SID File Format */
AFMT_ENTRY("SID", "sid.codec", NULL, NULL ),
/* ADX File Format */
AFMT_ENTRY("ADX", "adx.codec", NULL, NULL ),
#endif
};
#if CONFIG_CODEC == SWCODEC
/* recording quality to AFMT_* */
const int rec_quality_info_afmt[9] =
{
AFMT_MPA_L3, /* MPEG L3 64 kBit/s */
AFMT_MPA_L3, /* MPEG L3 96 kBit/s */
AFMT_MPA_L3, /* MPEG L3 128 kBit/s */
AFMT_MPA_L3, /* MPEG L3 160 kBit/s */
AFMT_MPA_L3, /* MPEG L3 192 kBit/s */
AFMT_MPA_L3, /* MPEG L3 224 kBit/s */
AFMT_MPA_L3, /* MPEG L3 320 kBit/s */
AFMT_WAVPACK, /* WavPack 909 kBit/s */
AFMT_PCM_WAV, /* PCM Wav 1411 kBit/s */
};
#endif /* SWCODEC */
char* id3_get_genre(const struct mp3entry* id3) char* id3_get_genre(const struct mp3entry* id3)
{ {
if( id3->genre_string ) if( id3->genre_string )

View file

@ -2453,34 +2453,32 @@ static void stop_recording(void)
resume_recording(); resume_recording();
} }
void audio_set_recording_options(int frequency, int quality, void audio_set_recording_options(struct audio_recording_options *options)
int source, int channel_mode,
bool editable, int prerecord_time)
{ {
bool is_mpeg1; bool is_mpeg1;
is_mpeg1 = (frequency < 3)?true:false; is_mpeg1 = (options->rec_frequency < 3)?true:false;
rec_version_index = is_mpeg1?3:2; rec_version_index = is_mpeg1?3:2;
rec_frequency_index = frequency % 3; rec_frequency_index = options->rec_frequency % 3;
shadow_encoder_control = (quality << 17) | shadow_encoder_control = (options->rec_quality << 17) |
(rec_frequency_index << 10) | (rec_frequency_index << 10) |
((is_mpeg1?1:0) << 9) | ((is_mpeg1?1:0) << 9) |
(((channel_mode * 2 + 1) & 3) << 6) | (((options->rec_channels * 2 + 1) & 3) << 6) |
(1 << 5) /* MS-stereo */ | (1 << 5) /* MS-stereo */ |
(1 << 2) /* Is an original */; (1 << 2) /* Is an original */;
mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1);
DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control);
shadow_soft_mute = editable?4:0; shadow_soft_mute = options->rec_editable?4:0;
mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1);
DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); 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 = ((1 << 10) | /* Monitoring ON */
((source < 2)?1:2) << 8) | /* Input select */ ((options->rec_source < 2)?1:2) << 8) | /* Input select */
(1 << 5) | /* SDO strobe invert */ (1 << 5) | /* SDO strobe invert */
((is_mpeg1?0:1) << 3) | ((is_mpeg1?0:1) << 3) |
(1 << 2) | /* Inverted SIBC clock signal */ (1 << 2) | /* Inverted SIBC clock signal */
@ -2489,7 +2487,7 @@ void audio_set_recording_options(int frequency, int quality,
DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main);
if(source == AUDIO_SRC_MIC) if(options->rec_source == AUDIO_SRC_MIC)
{ {
/* Copy left channel to right (mono mode) */ /* Copy left channel to right (mono mode) */
mas_codec_writereg(8, 0x8000); mas_codec_writereg(8, 0x8000);
@ -2500,7 +2498,7 @@ void audio_set_recording_options(int frequency, int quality,
mas_codec_writereg(8, 0); mas_codec_writereg(8, 0);
} }
prerecording_max_seconds = prerecord_time; prerecording_max_seconds = options->rec_prerecord_time;
if(prerecording_max_seconds) if(prerecording_max_seconds)
{ {
prerecording = true; prerecording = true;

View file

@ -16,260 +16,87 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#include <stdbool.h> #include "system.h"
#include "config.h" #include "kernel.h"
#include "debug.h" #include "logf.h"
#include "panic.h" #include "audio.h"
#include <kernel.h> #if defined(HAVE_WM8975)
#include "cpu.h"
#include "i2c.h"
#if defined(HAVE_UDA1380)
#include "uda1380.h"
#elif defined(HAVE_WM8975)
#include "wm8975.h" #include "wm8975.h"
#elif defined(HAVE_WM8758) #elif defined(HAVE_WM8758)
#include "wm8758.h" #include "wm8758.h"
#elif defined(HAVE_TLV320)
#include "tlv320.h"
#elif defined(HAVE_WM8731) || defined(HAVE_WM8721) #elif defined(HAVE_WM8731) || defined(HAVE_WM8721)
#include "wm8731l.h" #include "wm8731l.h"
#elif CONFIG_CPU == PNX0101 #elif CONFIG_CPU == PNX0101
#include "string.h"
#include "pnx0101.h" #include "pnx0101.h"
#endif #endif
#include "system.h"
#include "logf.h"
#include <stdio.h> /**
#include <string.h> * APIs implemented in the target-specific portion:
#include <stdarg.h> * Public -
#include "pcm_playback.h" * pcm_init
#include "lcd.h" * pcm_get_bytes_waiting
#include "button.h" * pcm_calculate_peaks
#include "file.h" * Semi-private -
#include "buffer.h" * pcm_play_dma_start
#include "sprintf.h" * pcm_play_dma_stop
#include "button.h" * pcm_play_pause_pause
#include <string.h> * pcm_play_pause_unpause
*/
static bool pcm_playing; /** These items may be implemented target specifically or need to
static bool pcm_paused; be shared semi-privately **/
/* the registered callback function to ask for more mp3 data */ /* the registered callback function to ask for more mp3 data */
static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL; pcm_more_callback_type pcm_callback_for_more = NULL;
bool pcm_playing = false;
bool pcm_paused = false;
void pcm_play_dma_start(const void *addr, size_t size);
void pcm_play_dma_stop(void);
void pcm_play_pause_pause(void);
void pcm_play_pause_unpause(void);
/** Functions that require targeted implementation **/
#ifndef CPU_COLDFIRE
#if (CONFIG_CPU == S3C2440) #if (CONFIG_CPU == S3C2440)
/* TODO: Implement for Gigabeat /* TODO: Implement for Gigabeat
For now, just implement some dummy functions. For now, just implement some dummy functions.
*/ */
void pcm_init(void) void pcm_init(void)
{ {
} }
static void dma_start(const void *addr, size_t size) void pcm_play_dma_start(const void *addr, size_t size)
{ {
(void)addr; (void)addr;
(void)size; (void)size;
} }
void pcm_play_dma_stop(void)
{
}
void pcm_play_pause_pause(void)
{
}
void pcm_play_pause_unpause(void)
{
}
void pcm_set_frequency(unsigned int frequency) void pcm_set_frequency(unsigned int frequency)
{ {
(void)frequency; (void)frequency;
} }
void pcm_play_stop(void)
{
}
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
return 0; return 0;
} }
#else
#ifdef CPU_COLDFIRE
#ifdef HAVE_SPDIF_OUT
#define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2))
#endif
#define IIS_DEFPARM(freq) ((freq << 12) | 0x300 | 4 << 2)
#define IIS_RESET 0x800
#ifdef IAUDIO_X5
#define SET_IIS_CONFIG(x) IIS1CONFIG = (x);
#else
#define SET_IIS_CONFIG(x) IIS2CONFIG = (x);
#endif
static int pcm_freq = 0x6; /* 44.1 is default */
int peak_left = 0, peak_right = 0;
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
static void dma_start(const void *addr, size_t size)
{
pcm_playing = true;
addr = (void *)((unsigned long)addr & ~3); /* Align data */
size &= ~3; /* Size must be multiple of 4 */
/* Reset the audio FIFO */
#ifdef HAVE_SPDIF_OUT
EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
#endif
/* Set up DMA transfer */
SAR0 = (unsigned long)addr; /* Source address */
DAR0 = (unsigned long)&PDOR3; /* Destination address */
BCR0 = size; /* Bytes to transfer */
/* Enable the FIFO and force one write to it */
SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq));
/* Also send the audio to S/PDIF */
#ifdef HAVE_SPDIF_OUT
EBU1CONFIG = EBU_DEFPARM;
#endif
DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | (3 << 20) | DMA_START;
}
/* Stops the DMA transfer and interrupt */
static void dma_stop(void)
{
pcm_playing = false;
DCR0 = 0;
DSR0 = 1;
/* Reset the FIFO */
SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq));
#ifdef HAVE_SPDIF_OUT
EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
#endif
}
/* sets frequency of input to DAC */
void pcm_set_frequency(unsigned int frequency)
{
switch(frequency)
{
case 11025:
pcm_freq = 0x2;
#ifdef HAVE_UDA1380
uda1380_set_nsorder(3);
#endif
break;
case 22050:
pcm_freq = 0x4;
#ifdef HAVE_UDA1380
uda1380_set_nsorder(3);
#endif
break;
case 44100:
default:
pcm_freq = 0x6;
#ifdef HAVE_UDA1380
uda1380_set_nsorder(5);
#endif
break;
}
}
size_t pcm_get_bytes_waiting(void)
{
return (BCR0 & 0xffffff);
}
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk */
void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
void DMA0(void)
{
int res = DSR0;
DSR0 = 1; /* Clear interrupt */
DCR0 &= ~DMA_EEXT;
/* Stop on error */
if(res & 0x70)
{
dma_stop();
logf("DMA Error:0x%04x", res);
}
else
{
size_t next_size;
unsigned char *next_start;
{
void (*get_more)(unsigned char**, size_t*) = callback_for_more;
if (get_more)
get_more(&next_start, &next_size);
else
{
next_size = 0;
next_start = NULL;
}
}
if(next_size)
{
SAR0 = (unsigned long)next_start; /* Source address */
BCR0 = next_size; /* Bytes to transfer */
DCR0 |= DMA_EEXT;
}
else
{
/* Finished playing */
dma_stop();
logf("DMA No Data:0x%04x", res);
}
}
IPR |= (1<<14); /* Clear pending interrupt request */
}
void pcm_init(void)
{
pcm_playing = false;
pcm_paused = false;
MPARK = 0x81; /* PARK[1,0]=10 + BCR24BIT */
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1;
DMACONFIG = 1; /* DMA0Req = PDOR3 */
/* Reset the audio FIFO */
SET_IIS_CONFIG(IIS_RESET);
/* Enable interrupt at level 7, priority 0 */
ICR6 = 0x1c;
IMR &= ~(1<<14); /* bit 14 is DMA0 */
pcm_set_frequency(44100);
/* Prevent pops (resets DAC to zero point) */
SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq) | IIS_RESET);
#if defined(HAVE_UDA1380)
/* Initialize default register values. */
uda1380_init();
/* Sleep a while so the power can stabilize (especially a long
delay is needed for the line out connector). */
sleep(HZ);
/* Power on FSDAC and HP amp. */
uda1380_enable_output(true);
/* Unmute the master channel (DAC should be at zero point now). */
uda1380_mute(false);
#elif defined(HAVE_TLV320)
tlv320_init();
sleep(HZ/4);
tlv320_mute(false);
#endif
/* Call dma_stop to initialize everything. */
dma_stop();
}
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8731) || defined(HAVE_WM8721)
@ -286,14 +113,14 @@ void pcm_init(void)
#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
#endif #endif
static int pcm_freq = 44100; /* 44.1 is default */ static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
/* NOTE: The order of these two variables is important if you use the iPod /* NOTE: The order of these two variables is important if you use the iPod
assembler optimised fiq handler, so don't change it. */ assembler optimised fiq handler, so don't change it. */
unsigned short* p IBSS_ATTR; unsigned short* p IBSS_ATTR;
size_t p_size IBSS_ATTR; size_t p_size IBSS_ATTR;
static void dma_start(const void *addr, size_t size) void pcm_play_dma_start(const void *addr, size_t size)
{ {
p=(unsigned short*)addr; p=(unsigned short*)addr;
p_size=size; p_size=size;
@ -341,7 +168,7 @@ static void dma_start(const void *addr, size_t size)
} }
/* Stops the DMA transfer and interrupt */ /* Stops the DMA transfer and interrupt */
static void dma_stop(void) void pcm_play_dma_stop(void)
{ {
pcm_playing = false; pcm_playing = false;
@ -365,9 +192,58 @@ static void dma_stop(void)
disable_fiq(); disable_fiq();
} }
void pcm_play_pause_pause(void)
{
#if CONFIG_CPU == PP5020
/* Disable the interrupt */
IISCONFIG &= ~0x2;
/* Disable playback FIFO */
IISCONFIG &= ~0x20000000;
#elif CONFIG_CPU == PP5002
/* Disable the interrupt */
IISFIFO_CFG &= ~(1<<9);
/* Disable playback FIFO */
IISCONFIG &= ~0x4;
#endif
disable_fiq();
}
void pcm_play_pause_unpause(void)
{
/* Enable the FIFO and fill it */
enable_fiq();
/* Enable playback FIFO */
#if CONFIG_CPU == PP5020
IISCONFIG |= 0x20000000;
#elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4;
#endif
/* Fill the FIFO - we assume there are enough bytes in the
pcm buffer to fill the 32-byte FIFO. */
while (p_size > 0) {
if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */
#if CONFIG_CPU == PP5020
IISCONFIG |= 0x2;
#elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9);
#endif
return;
}
IISFIFO_WR = (*(p++))<<16;
IISFIFO_WR = (*(p++))<<16;
p_size-=4;
}
}
void pcm_set_frequency(unsigned int frequency) void pcm_set_frequency(unsigned int frequency)
{ {
pcm_freq=frequency; (void)frequency;
pcm_freq = HW_SAMPR_DEFAULT;
} }
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
@ -378,8 +254,8 @@ size_t pcm_get_bytes_waiting(void)
/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
has registers r8-r14 banked, and so does not need to be saved. This routine has registers r8-r14 banked, and so does not need to be saved. This routine
uses only these registers, and so will never touch the stack unless it uses only these registers, and so will never touch the stack unless it
actually needs to do so when calling callback_for_more. C version is still actually needs to do so when calling pcm_callback_for_more. C version is
included below for reference. still included below for reference.
*/ */
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
void fiq(void) ICODE_ATTR __attribute__((naked)); void fiq(void) ICODE_ATTR __attribute__((naked));
@ -433,10 +309,10 @@ void fiq(void)
"add r1, r11, #4 \n\t" /* r1 = &p_size */ "add r1, r11, #4 \n\t" /* r1 = &p_size */
"str r9, [r0] \n\t" /* save internal copies of variables back */ "str r9, [r0] \n\t" /* save internal copies of variables back */
"str r8, [r1] \n\t" "str r8, [r1] \n\t"
"ldr r2, =callback_for_more\n\t" "ldr r2, =pcm_callback_for_more\n\t"
"ldr r2, [r2] \n\t" /* get callback address */ "ldr r2, [r2] \n\t" /* get callback address */
"cmp r2, #0 \n\t" /* check for null pointer */ "cmp r2, #0 \n\t" /* check for null pointer */
"movne lr, pc \n\t" /* call callback_for_more */ "movne lr, pc \n\t" /* call pcm_callback_for_more */
"bxne r2 \n\t" "bxne r2 \n\t"
"ldmia sp!, { r0-r3, r12, lr}\n\t" "ldmia sp!, { r0-r3, r12, lr}\n\t"
"ldr r8, [r11, #4] \n\t" /* reload p_size and p */ "ldr r8, [r11, #4] \n\t" /* reload p_size and p */
@ -477,7 +353,7 @@ void fiq(void)
"b .exit \n\t" "b .exit \n\t"
); );
} }
#else #else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
void fiq(void) void fiq(void)
{ {
@ -507,20 +383,21 @@ void fiq(void)
} }
/* p is empty, get some more data */ /* p is empty, get some more data */
if (callback_for_more) { if (pcm_callback_for_more) {
callback_for_more((unsigned char**)&p,&p_size); pcm_callback_for_more((unsigned char**)&p,&p_size);
} }
} while (p_size); } while (p_size);
/* No more data, so disable the FIFO/FIQ */ /* No more data, so disable the FIFO/FIQ */
dma_stop(); pcm_play_dma_stop();
} }
#endif #endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
void pcm_init(void) void pcm_init(void)
{ {
pcm_playing = false; pcm_playing = false;
pcm_paused = false; pcm_paused = false;
pcm_callback_for_more = NULL;
/* Initialize default register values. */ /* Initialize default register values. */
wmcodec_init(); wmcodec_init();
@ -531,8 +408,8 @@ void pcm_init(void)
/* Unmute the master channel (DAC should be at zero point now). */ /* Unmute the master channel (DAC should be at zero point now). */
wmcodec_mute(false); wmcodec_mute(false);
/* Call dma_stop to initialize everything. */ /* Call pcm_play_dma_stop to initialize everything. */
dma_stop(); pcm_play_dma_stop();
} }
#elif (CONFIG_CPU == PNX0101) #elif (CONFIG_CPU == PNX0101)
@ -542,12 +419,16 @@ void pcm_init(void)
short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES];
short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES];
static int pcm_freq = 44100; /* 44.1 is default */ static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
unsigned short* p IBSS_ATTR; unsigned short* p IBSS_ATTR;
size_t p_size IBSS_ATTR; size_t p_size IBSS_ATTR;
static void dma_start(const void *addr, size_t size) void pcm_init(void)
{
}
void pcm_play_dma_start(const void *addr, size_t size)
{ {
p = (unsigned short*)addr; p = (unsigned short*)addr;
p_size = size; p_size = size;
@ -555,11 +436,19 @@ static void dma_start(const void *addr, size_t size)
pcm_playing = true; pcm_playing = true;
} }
static void dma_stop(void) void pcm_play_dma_stop(void)
{ {
pcm_playing = false; pcm_playing = false;
} }
void pcm_play_pause_pause(void)
{
}
void pcm_play_pause_unpause(void)
{
}
static inline void fill_dma_buf(int offset) static inline void fill_dma_buf(int offset)
{ {
short *l, *r, *lend; short *l, *r, *lend;
@ -611,8 +500,8 @@ static inline void fill_dma_buf(int offset)
p = tmp_p; p = tmp_p;
if (l >= lend) if (l >= lend)
return; return;
else if (callback_for_more) else if (pcm_callback_for_more)
callback_for_more((unsigned char**)&p, pcm_callback_for_more((unsigned char**)&p,
&p_size); &p_size);
} }
while (p_size); while (p_size);
@ -647,9 +536,10 @@ unsigned long physical_address(void *p)
void pcm_init(void) void pcm_init(void)
{ {
int i; int i;
callback_for_more = NULL;
pcm_playing = false; pcm_playing = false;
pcm_paused = false; pcm_paused = false;
pcm_callback_for_more = NULL;
memset(dma_buf_left, 0, sizeof(dma_buf_left)); memset(dma_buf_left, 0, sizeof(dma_buf_left));
memset(dma_buf_right, 0, sizeof(dma_buf_right)); memset(dma_buf_right, 0, sizeof(dma_buf_right));
@ -691,271 +581,37 @@ void pcm_init(void)
void pcm_set_frequency(unsigned int frequency) void pcm_set_frequency(unsigned int frequency)
{ {
pcm_freq=frequency; (void)frequency;
pcm_freq = HW_SAMPR_DEFAULT;
} }
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
return p_size; return p_size;
} }
#endif #endif /* CONFIG_CPU == */
void pcm_play_stop(void) /* dummy functions for those not actually supporting all this yet */
void pcm_apply_settings(bool reset)
{ {
if (pcm_playing) { (void)reset;
dma_stop();
}
} }
#endif void pcm_set_monitor(int monitor)
void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
unsigned char* start, size_t size)
{ {
callback_for_more = get_more; (void)monitor;
if (!(start && size))
{
if (get_more)
get_more(&start, &size);
else
return;
}
if (start && size)
{
dma_start(start, size);
if (pcm_paused) {
pcm_paused = false;
pcm_play_pause(false);
}
}
} }
/** **/
void pcm_mute(bool mute) void pcm_mute(bool mute)
{ {
#ifdef HAVE_UDA1380 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
uda1380_mute(mute);
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8731) || defined(HAVE_WM8721)
wmcodec_mute(mute); wmcodec_mute(mute);
#elif defined(HAVE_TLV320)
tlv320_mute(mute);
#endif #endif
if (mute) if (mute)
sleep(HZ/16); sleep(HZ/16);
} }
void pcm_play_pause(bool play)
{
bool needs_change = pcm_paused == play;
/* This needs to be done ahead of the rest to prevent infinite
* recursion from dma_start */
pcm_paused = !play;
if (pcm_playing && needs_change) {
if(play) {
if (pcm_get_bytes_waiting()) {
logf("unpause");
#ifdef CPU_COLDFIRE
/* Enable the FIFO and force one write to it */
SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq));
#ifdef HAVE_SPDIF_OUT
EBU1CONFIG = EBU_DEFPARM;
#endif
DCR0 |= DMA_EEXT | DMA_START;
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|| defined(HAVE_WM8731) || defined(HAVE_WM8721)
/* Enable the FIFO and fill it */
enable_fiq();
/* Enable playback FIFO */
#if CONFIG_CPU == PP5020
IISCONFIG |= 0x20000000;
#elif CONFIG_CPU == PP5002
IISCONFIG |= 0x4;
#endif
/* Fill the FIFO - we assume there are enough bytes in the
pcm buffer to fill the 32-byte FIFO. */
while (p_size > 0) {
if (FIFO_FREE_COUNT < 2) {
/* Enable interrupt */
#if CONFIG_CPU == PP5020
IISCONFIG |= 0x2;
#elif CONFIG_CPU == PP5002
IISFIFO_CFG |= (1<<9);
#endif
return;
}
IISFIFO_WR = (*(p++))<<16;
IISFIFO_WR = (*(p++))<<16;
p_size-=4;
}
#elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */
/* nothing yet */
#endif
} else {
#if (CONFIG_CPU != PNX0101 && CONFIG_CPU != S3C2440)
size_t next_size;
unsigned char *next_start;
void (*get_more)(unsigned char**, size_t*) = callback_for_more;
logf("unpause, no data waiting");
if (get_more)
get_more(&next_start, &next_size);
if (next_start && next_size)
dma_start(next_start, next_size);
else
{
dma_stop();
logf("unpause attempted, no data");
}
#endif
}
} else {
logf("pause");
#ifdef CPU_COLDFIRE
/* Disable DMA peripheral request. */
DCR0 &= ~DMA_EEXT;
SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq));
#ifdef HAVE_SPDIF_OUT
EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
#endif
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|| defined(HAVE_WM8731) || defined(HAVE_WM8721)
#if CONFIG_CPU == PP5020
/* Disable the interrupt */
IISCONFIG &= ~0x2;
/* Disable playback FIFO */
IISCONFIG &= ~0x20000000;
#elif CONFIG_CPU == PP5002
/* Disable the interrupt */
IISFIFO_CFG &= ~(1<<9);
/* Disable playback FIFO */
IISCONFIG &= ~0x4;
#endif
disable_fiq();
#elif (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) /* End wmcodecs */
/* nothing yet */
#endif
}
} /* pcm_playing && needs_change */
}
bool pcm_is_playing(void) {
return pcm_playing;
}
bool pcm_is_paused(void) {
return pcm_paused;
}
#if defined(CPU_COLDFIRE)
/* Peaks ahead in the DMA buffer based upon the calling period to
attempt to compensate for the delay. Keeps a moving average of
length four. */
void pcm_calculate_peaks(int *left, int *right)
{
unsigned long samples;
unsigned long *addr, *end;
long peak_p, peak_n;
static unsigned long last_peak_tick = 0;
static unsigned long frame_period = 0;
/* Throttled peak ahead based on calling period */
unsigned long period = current_tick - last_peak_tick;
/* Keep reasonable limits on period */
if (period < 1)
period = 1;
else if (period > HZ/5)
period = HZ/5;
frame_period = (3*frame_period + period) >> 2;
last_peak_tick = current_tick;
if (!pcm_playing || pcm_paused)
{
peak_left = peak_right = 0;
goto peak_done;
}
samples = (BCR0 & 0xffffff) >> 2;
addr = (long *)(SAR0 & ~3);
samples = MIN(frame_period*44100/HZ, samples);
end = addr + samples;
peak_p = peak_n = 0;
if (left && right)
{
if (samples > 0)
{
long peak_rp = 0, peak_rn = 0;
do
{
long value = *addr;
long ch;
ch = value >> 16;
if (ch > peak_p) peak_p = ch;
else if (ch < peak_n) peak_n = ch;
ch = (short)value;
if (ch > peak_rp) peak_rp = ch;
else if (ch < peak_rn) peak_rn = ch;
addr += 4;
}
while (addr < end);
peak_left = MAX(peak_p, -peak_n);
peak_right = MAX(peak_rp, -peak_rn);
}
}
else if (left || right)
{
if (samples > 0)
{
if (left)
{
/* Put left channel in low word */
addr = (long *)((short *)addr - 1);
end = (long *)((short *)end - 1);
}
do
{
long value = *(short *)addr;
if (value > peak_p) peak_p = value;
else if (value < peak_n) peak_n = value;
addr += 4;
}
while (addr < end);
if (left)
peak_left = MAX(peak_p, -peak_n);
else
peak_right = MAX(peak_p, -peak_n);
}
}
peak_done:
if (left)
*left = peak_left;
if (right)
*right = peak_right;
}
#else
/* /*
* This function goes directly into the DMA buffer to calculate the left and * This function goes directly into the DMA buffer to calculate the left and
* right peak values. To avoid missing peaks it tries to look forward two full * right peak values. To avoid missing peaks it tries to look forward two full
@ -1037,4 +693,94 @@ void pcm_calculate_peaks(int *left, int *right)
} }
#endif #endif
} }
#endif /* CPU_COLDFIRE */ #endif /* CPU_COLDFIRE */
/****************************************************************************
* Functions that do not require targeted implementation but only a targeted
* interface
*/
/* Common code to pcm_play_data and pcm_play_pause
Returns true if DMA playback was started, else false. */
bool pcm_play_data_start(pcm_more_callback_type get_more,
unsigned char *start, size_t size)
{
if (!(start && size))
{
size = 0;
if (get_more)
get_more(&start, &size);
}
if (start && size)
{
pcm_play_dma_start(start, size);
return true;
}
return false;
}
void pcm_play_data(pcm_more_callback_type get_more,
unsigned char *start, size_t size)
{
pcm_callback_for_more = get_more;
if (pcm_play_data_start(get_more, start, size) && pcm_paused)
{
pcm_paused = false;
pcm_play_pause(false);
}
}
void pcm_play_pause(bool play)
{
bool needs_change = pcm_paused == play;
/* This needs to be done ahead of the rest to prevent infinite
recursion from pcm_play_data */
pcm_paused = !play;
if (pcm_playing && needs_change)
{
if (play)
{
if (pcm_get_bytes_waiting())
{
logf("unpause");
pcm_play_pause_unpause();
}
else
{
logf("unpause, no data waiting");
if (!pcm_play_data_start(pcm_callback_for_more, NULL, 0))
{
pcm_play_dma_stop();
logf("unpause attempted, no data");
}
}
}
else
{
logf("pause");
pcm_play_pause_pause();
}
} /* pcm_playing && needs_change */
}
void pcm_play_stop(void)
{
if (pcm_playing)
pcm_play_dma_stop();
}
bool pcm_is_playing(void)
{
return pcm_playing;
}
bool pcm_is_paused(void)
{
return pcm_paused;
}

File diff suppressed because it is too large Load diff

View file

@ -390,8 +390,7 @@ int system_memory_guard(int newmode)
(void)newmode; (void)newmode;
return 0; return 0;
} }
#elif defined(CPU_COLDFIRE)
/* system code is in target tree for all coldfire targets */
#elif CONFIG_CPU == SH7034 #elif CONFIG_CPU == SH7034
#include "led.h" #include "led.h"
#include "system.h" #include "system.h"

View file

@ -42,7 +42,7 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false);
RECALC_DELAYS(CPUFREQ_MAX); RECALC_DELAYS(CPUFREQ_MAX);
PLLCR = 0x13442045; PLLCR = 0x03042045 | (PLLCR & 0x70C00000);
CSCR0 = 0x00001180; /* Flash: 4 wait states */ CSCR0 = 0x00001180; /* Flash: 4 wait states */
CSCR1 = 0x00000980; /* LCD: 2 wait states */ CSCR1 = 0x00000980; /* LCD: 2 wait states */
while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked.
@ -60,7 +60,7 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false);
RECALC_DELAYS(CPUFREQ_NORMAL); RECALC_DELAYS(CPUFREQ_NORMAL);
PLLCR = 0x16430045; PLLCR = 0x06030045 | (PLLCR & 0x70C00000);
CSCR0 = 0x00000580; /* Flash: 1 wait state */ CSCR0 = 0x00000580; /* Flash: 1 wait state */
CSCR1 = 0x00000180; /* LCD: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */
while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked.
@ -77,7 +77,8 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true);
RECALC_DELAYS(CPUFREQ_DEFAULT); RECALC_DELAYS(CPUFREQ_DEFAULT);
PLLCR = 0x10400200; /* Power down PLL, but keep CLSEL and CRSEL */ /* Power down PLL, but keep CLSEL and CRSEL */
PLLCR = 0x00000200 | (PLLCR & 0x70C00000);
CSCR0 = 0x00000180; /* Flash: 0 wait states */ CSCR0 = 0x00000180; /* Flash: 0 wait states */
CSCR1 = 0x00000180; /* LCD: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */
DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */

View file

@ -81,7 +81,7 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false);
RECALC_DELAYS(CPUFREQ_MAX); RECALC_DELAYS(CPUFREQ_MAX);
PLLCR = 0x11c56005; PLLCR = 0x01056005 | (PLLCR & 0x70c00000);
CSCR0 = 0x00001180; /* Flash: 4 wait states */ CSCR0 = 0x00001180; /* Flash: 4 wait states */
CSCR1 = 0x00001580; /* LCD: 5 wait states */ CSCR1 = 0x00001580; /* LCD: 5 wait states */
#if CONFIG_USBOTG == USBOTG_ISP1362 #if CONFIG_USBOTG == USBOTG_ISP1362
@ -108,7 +108,7 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false);
RECALC_DELAYS(CPUFREQ_NORMAL); RECALC_DELAYS(CPUFREQ_NORMAL);
PLLCR = 0x13c5e005; PLLCR = 0x0305e005 | (PLLCR & 0x70c00000);
CSCR0 = 0x00000580; /* Flash: 1 wait state */ CSCR0 = 0x00000580; /* Flash: 1 wait state */
CSCR1 = 0x00000180; /* LCD: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */
#if CONFIG_USBOTG == USBOTG_ISP1362 #if CONFIG_USBOTG == USBOTG_ISP1362
@ -134,7 +134,8 @@ void set_cpu_frequency(long frequency)
PLLCR &= ~1; /* Bypass mode */ PLLCR &= ~1; /* Bypass mode */
timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true);
RECALC_DELAYS(CPUFREQ_DEFAULT); RECALC_DELAYS(CPUFREQ_DEFAULT);
PLLCR = 0x10c00200; /* Power down PLL, but keep CLSEL and CRSEL */ /* Power down PLL, but keep CLSEL and CRSEL */
PLLCR = 0x00000200 | (PLLCR & 0x70c00000);
CSCR0 = 0x00000180; /* Flash: 0 wait states */ CSCR0 = 0x00000180; /* Flash: 0 wait states */
CSCR1 = 0x00000180; /* LCD: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */
#if CONFIG_USBOTG == USBOTG_ISP1362 #if CONFIG_USBOTG == USBOTG_ISP1362

View file

@ -310,3 +310,10 @@ int system_memory_guard(int newmode)
return oldmode; return oldmode;
} }
/* allow setting of audio clock related bits */
void coldfire_set_pllcr_audio_bits(long bits)
{
PLLCR = (PLLCR & ~0x70c00000) | (bits & 0x70c00000);
}

View file

@ -110,6 +110,28 @@ static inline unsigned long swap32(unsigned long value)
return value; return value;
} }
static inline unsigned long swap_odd_even32(unsigned long value)
{
/*
result[31..24],[15.. 8] = value[23..16],[ 7.. 0]
result[23..16],[ 7.. 0] = value[31..24],[15.. 8]
*/
unsigned long mask = 0x00FF00FF;
asm ( /* val = ABCD */
"and.l %[val],%[mask] \n" /* mask = .B.D */
"eor.l %[mask],%[val] \n" /* val = A.C. */
"lsl.l #8,%[mask] \n" /* mask = B.D. */
"lsr.l #8,%[val] \n" /* val = .A.C */
"or.l %[mask],%[val] \n" /* val = BADC */
: /* outputs */
[val] "+d"(value),
[mask]"+d"(mask)
);
return value;
}
static inline void invalidate_icache(void) static inline void invalidate_icache(void)
{ {
asm volatile ("move.l #0x01000000,%d0\n" asm volatile ("move.l #0x01000000,%d0\n"
@ -118,6 +140,13 @@ static inline void invalidate_icache(void)
"movec.l %d0,%cacr"); "movec.l %d0,%cacr");
} }
#ifdef IAUDIO_X5
#define DEFAULT_PLLCR_AUDIO_BITS 0x10400000
#else
#define DEFAULT_PLLCR_AUDIO_BITS 0x10c00000
#endif
void coldfire_set_pllcr_audio_bits(long bits);
/* 11.2896 MHz */ /* 11.2896 MHz */
#define CPUFREQ_DEFAULT_MULT 1 #define CPUFREQ_DEFAULT_MULT 1
#define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ) #define CPUFREQ_DEFAULT (CPUFREQ_DEFAULT_MULT * CPU_FREQ)

View file

@ -711,6 +711,14 @@ int thread_set_priority(struct thread_entry *thread, int priority)
return old_priority; return old_priority;
} }
int thread_get_priority(struct thread_entry *thread)
{
if (thread == NULL)
thread = cores[CURRENT_CORE].running;
return thread->priority;
}
#endif #endif
void init_threads(void) void init_threads(void)

View file

@ -181,7 +181,8 @@ void screen_dump(void)
int x, y; int x, y;
static unsigned char line[BMP_LINESIZE]; static unsigned char line[BMP_LINESIZE];
create_numbered_filename(filename, "", "dump_", ".bmp", 4); create_numbered_filename(filename, "", "dump_", ".bmp", 4,
IF_CNFN_NUM_(, NULL));
DEBUGF("screen_dump\n"); DEBUGF("screen_dump\n");
fd = sim_creat(filename, O_WRONLY); fd = sim_creat(filename, O_WRONLY);