summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/codecs.c25
-rw-r--r--apps/codecs.h64
-rw-r--r--apps/codecs/libwavpack/bits.c22
-rw-r--r--apps/codecs/mp3_enc.c1182
-rw-r--r--apps/codecs/wav_enc.c419
-rw-r--r--apps/codecs/wavpack_enc.c539
-rw-r--r--apps/eq_menu.c3
-rw-r--r--apps/gui/statusbar.c196
-rw-r--r--apps/lang/english.lang114
-rw-r--r--apps/main.c3
-rw-r--r--apps/metadata.c48
-rw-r--r--apps/misc.c57
-rw-r--r--apps/misc.h35
-rw-r--r--apps/pcmbuf.c27
-rw-r--r--apps/pcmbuf.h2
-rw-r--r--apps/playback.c262
-rw-r--r--apps/playlist.c12
-rw-r--r--apps/plugin.c8
-rw-r--r--apps/recorder/icons.c90
-rw-r--r--apps/recorder/icons.h60
-rw-r--r--apps/recorder/peakmeter.c6
-rw-r--r--apps/recorder/radio.c25
-rw-r--r--apps/recorder/recording.c250
-rw-r--r--apps/recorder/recording.h13
-rw-r--r--apps/settings.c44
-rw-r--r--apps/settings.h34
-rw-r--r--apps/sound_menu.c288
-rw-r--r--apps/status.c6
-rw-r--r--apps/talk.c27
-rw-r--r--apps/tree.c2
31 files changed, 2605 insertions, 1261 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index e1d8e7bbdd..ccfc7fa280 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -73,6 +73,9 @@ pcmbuf.c
playback.c
codecs.c
dsp.c
+#ifdef HAVE_RECORDING
+enc_config.c
+#endif
eq.c
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
dsp_cf.S
diff --git a/apps/codecs.c b/apps/codecs.c
index f33957eba2..4491dadf49 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -50,6 +50,7 @@
#include "sound.h"
#include "database.h"
#include "splash.h"
+#include "general.h"
#ifdef SIMULATOR
#if CONFIG_CODEC == SWCODEC
@@ -104,6 +105,7 @@ struct codec_api ci = {
PREFIX(remove),
PREFIX(rename),
PREFIX(ftruncate),
+ PREFIX(fsync),
fdprintf,
read_line,
settings_parseline,
@@ -187,6 +189,7 @@ struct codec_api ci = {
get_time,
set_time,
plugin_get_audio_buffer,
+ round_value_to_list32,
#if defined(DEBUG) || defined(SIMULATOR)
debugf,
@@ -213,11 +216,11 @@ struct codec_api ci = {
false,
enc_get_inputs,
enc_set_parameters,
- enc_alloc_chunk,
- enc_free_chunk,
- enc_wavbuf_near_empty,
- enc_get_wav_data,
- &enc_set_header_callback,
+ enc_get_chunk,
+ enc_finish_chunk,
+ enc_pcm_buf_near_empty,
+ enc_get_pcm_data,
+ enc_unget_pcm_data
#endif
/* 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_fn);
+ snprintf(path, MAX_PATH-1, CODECS_DIR "/%s." CODEC_EXTENSION,
+ codec_root_fn);
}
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;
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->load_addr != codecbuf
|| hdr->end_addr > codecbuf + CODEC_SIZE)
diff --git a/apps/codecs.h b/apps/codecs.h
index 96804a889b..0b90ef9c19 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -46,7 +46,7 @@
#include "profile.h"
#endif
#if (CONFIG_CODEC == SWCODEC)
-#if !defined(SIMULATOR)
+#if !defined(SIMULATOR) && defined(HAVE_RECORDING)
#include "pcm_record.h"
#endif
#include "dsp.h"
@@ -84,15 +84,18 @@
#define PREFIX(_x_) _x_
#endif
+/* magic for normal codecs */
#define CODEC_MAGIC 0x52434F44 /* RCOD */
+/* magic for encoder codecs */
+#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
/* 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
backwards compatibility (and please take the opportunity to sort in any
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 */
enum codec_status {
@@ -176,6 +179,7 @@ struct codec_api {
int (*PREFIX(remove))(const char* pathname);
int (*PREFIX(rename))(const char* path, const char* newname);
int (*PREFIX(ftruncate))(int fd, off_t length);
+ int (*PREFIX(fsync))(int fd);
int (*fdprintf)(int fd, const char *fmt, ...);
int (*read_line)(int fd, char* buffer, int buffer_size);
@@ -232,7 +236,8 @@ struct codec_api {
/* sound */
void (*sound_set)(int setting, int value);
#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_stop)(void);
bool (*mp3_is_playing)(void);
@@ -263,6 +268,10 @@ struct codec_api {
struct tm* (*get_time)(void);
int (*set_time)(const struct tm *tm);
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)
void (*debugf)(const char *fmt, ...);
@@ -291,18 +300,14 @@ struct codec_api {
#endif
#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
- bool enc_codec_loaded;
- void (*enc_get_inputs)(int *buffer_size,
- int *channels, int *quality);
- void (*enc_set_parameters)(int chunk_size, int num_chunks,
- int samp_per_chunk, char *head_ptr, int head_size,
- int enc_id);
- unsigned int* (*enc_alloc_chunk)(void);
- void (*enc_free_chunk)(void);
- 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);
+ volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */
+ void (*enc_get_inputs)(struct enc_inputs *inputs);
+ void (*enc_set_parameters)(struct enc_parameters *params);
+ struct enc_chunk_hdr * (*enc_get_chunk)(void);
+ void (*enc_finish_chunk)(void);
+ int (*enc_pcm_buf_near_empty)(void);
+ unsigned char * (*enc_get_pcm_data)(size_t size);
+ size_t (*enc_unget_pcm_data)(size_t size);
#endif
/* new stuff at the end, sort into place next time
@@ -312,34 +317,49 @@ struct codec_api {
/* codec header */
struct codec_header {
- unsigned long magic;
+ unsigned long magic; /* RCOD or RENC */
unsigned short target_id;
unsigned short api_version;
unsigned char *load_addr;
unsigned char *end_addr;
enum codec_status(*entry_point)(struct codec_api*);
};
+
#ifdef CODEC
#ifndef SIMULATOR
/* plugin_* is correct, codecs use the plugin linker script */
extern unsigned char plugin_start_addr[];
extern unsigned char plugin_end_addr[];
+/* decoders */
#define CODEC_HEADER \
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
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 \
const struct codec_header __header = { \
CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
NULL, NULL, codec_start };
-#endif
-#endif
+/* encoders */
+#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 */
-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) */
int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,
diff --git a/apps/codecs/libwavpack/bits.c b/apps/codecs/libwavpack/bits.c
index 0a148e123f..0f0e79c292 100644
--- a/apps/codecs/libwavpack/bits.c
+++ b/apps/codecs/libwavpack/bits.c
@@ -15,6 +15,7 @@
// the malloc() system is provided.
#include "wavpack.h"
+#include "system.h"
#include <string.h>
@@ -118,19 +119,16 @@ uint32_t bs_close_write (Bitstream *bs)
void little_endian_to_native (void *data, char *format)
{
uchar *cp = (uchar *) data;
- int32_t temp;
while (*format) {
switch (*format) {
case 'L':
- temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24);
- * (int32_t *) cp = temp;
+ *(long *)cp = letoh32(*(long *)cp);
cp += 4;
break;
case 'S':
- temp = cp [0] + (cp [1] << 8);
- * (short *) cp = (short) temp;
+ *(short *)cp = letoh16(*(short *)cp);
cp += 2;
break;
@@ -148,28 +146,22 @@ void little_endian_to_native (void *data, char *format)
void native_to_little_endian (void *data, char *format)
{
uchar *cp = (uchar *) data;
- int32_t temp;
while (*format) {
switch (*format) {
case 'L':
- temp = * (int32_t *) cp;
- *cp++ = (uchar) temp;
- *cp++ = (uchar) (temp >> 8);
- *cp++ = (uchar) (temp >> 16);
- *cp++ = (uchar) (temp >> 24);
+ *(long *)cp = htole32(*(long *)cp);
+ cp += 4;
break;
case 'S':
- temp = * (short *) cp;
- *cp++ = (uchar) temp;
- *cp++ = (uchar) (temp >> 8);
+ *(short *)cp = htole16(*(short *)cp);
+ cp += 2;
break;
default:
if (*format >= '0' && *format <= '9')
cp += *format - '0';
-
break;
}
diff --git a/apps/codecs/mp3_enc.c b/apps/codecs/mp3_enc.c
index 3caca94f35..cb727ce01e 100644
--- a/apps/codecs/mp3_enc.c
+++ b/apps/codecs/mp3_enc.c
@@ -32,20 +32,19 @@
#ifndef SIMULATOR
+#include <inttypes.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
-
-
-#define SAMP_PER_FRAME 1152
+#define ENC_PADDING_FRAMES1 2
+#define ENC_PADDING_FRAMES2 4
+#define ENC_DELAY_SAMP 576
+#define ENC_DELAY_SIZE (ENC_DELAY_SAMP*4)
+#define SAMP_PER_FRAME1 1152
+#define SAMP_PER_FRAME2 576
+#define PCM_CHUNK_SIZE1 (SAMP_PER_FRAME1*4)
+#define PCM_CHUNK_SIZE2 (SAMP_PER_FRAME2*4)
#define SAMPL2 576
#define SBLIMIT 32
#define HTN 16
@@ -54,15 +53,16 @@ extern char iend[];
#define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \
else { putbits(cc, sz); cc = c; sz = s; }
-enum e_byte_order { order_unknown, order_bigEndian, order_littleEndian };
-
-typedef unsigned long uint32;
-typedef unsigned short uint16;
-typedef unsigned char uint8;
-
+#ifdef USE_IRAM
+extern char iramcopy[];
+extern char iramstart[];
+extern char iramend[];
+extern char iedata[];
+extern char iend[];
+#endif
typedef struct {
- int type; /* 0=(22.05,24,16kHz) 1=(44.1,48,32kHz) */
+ int type; /* 0=(MPEG2 - 22.05,24,16kHz) 1=(MPEG1 - 44.1,48,32kHz) */
int mode; /* 0=stereo, 1=jstereo, 2=dual, 3=mono */
int bitrate;
int padding;
@@ -73,21 +73,20 @@ typedef struct {
/* Side information */
typedef struct {
- uint32 part2_3_length;
+ uint32_t part2_3_length;
int count1; /* number of 0-1-quadruples */
- uint32 global_gain;
- uint32 table_select[4];
- uint32 region_0_1;
- uint32 address1;
- uint32 address2;
- uint32 address3;
+ uint32_t global_gain;
+ uint32_t table_select[4];
+ uint32_t region_0_1;
+ uint32_t address1;
+ uint32_t address2;
+ uint32_t address3;
long quantStep;
long additStep;
long max_val;
} side_info_t;
typedef struct {
- enum e_byte_order byte_order;
side_info_t cod_info[2][2];
mpeg_t mpg;
long frac_per_frame;
@@ -98,19 +97,18 @@ typedef struct {
int ResvSize;
int channels;
int granules;
- int resample;
long samplerate;
} config_t;
typedef struct {
int bitpos; /* current bitpos for writing */
- uint32 bbuf[263];
+ uint32_t bbuf[263];
} BF_Data;
struct huffcodetab {
int len; /* max. index */
- const uint8 *table; /* pointer to array[len][len] */
- const uint8 *hlen; /* pointer to array[len][len] */
+ const uint8_t *table; /* pointer to array[len][len] */
+ const uint8_t *hlen; /* pointer to array[len][len] */
};
struct huffcodebig {
@@ -127,102 +125,105 @@ struct huffcodebig {
#define shft_n(x,n) ((x) >> n)
#define SQRT 724 /* sqrt(2) * 512 */
-short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */
-int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */
-int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */
-short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */
-uint32 scalefac [23] IBSS_ATTR; /* 92 Bytes */
-BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */
-int ca [8] IBSS_ATTR; /* 32 Bytes */
-int cs [8] IBSS_ATTR; /* 32 Bytes */
-int cx [9] IBSS_ATTR; /* 36 Bytes */
-int win [18][4] IBSS_ATTR; /* 288 Bytes */
-short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */
-short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */
-uint8 ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */
-uint32 tab01 [ 16] IBSS_ATTR; /* 64 Bytes */
-uint32 tab23 [ 9] IBSS_ATTR; /* 36 Bytes */
-uint32 tab56 [ 16] IBSS_ATTR; /* 64 Bytes */
-uint32 tab1315 [256] IBSS_ATTR; /* 1024 Bytes */
-uint32 tab1624 [256] IBSS_ATTR; /* 1024 Bytes */
-uint32 tab789 [ 36] IBSS_ATTR; /* 144 Bytes */
-uint32 tabABC [ 64] IBSS_ATTR; /* 256 Bytes */
-uint8 t1HB [ 4] IBSS_ATTR;
-uint8 t2HB [ 9] IBSS_ATTR;
-uint8 t3HB [ 9] IBSS_ATTR;
-uint8 t5HB [ 16] IBSS_ATTR;
-uint8 t6HB [ 16] IBSS_ATTR;
-uint8 t7HB [ 36] IBSS_ATTR;
-uint8 t8HB [ 36] IBSS_ATTR;
-uint8 t9HB [ 36] IBSS_ATTR;
-uint8 t10HB [ 64] IBSS_ATTR;
-uint8 t11HB [ 64] IBSS_ATTR;
-uint8 t12HB [ 64] IBSS_ATTR;
-uint8 t13HB [256] IBSS_ATTR;
-uint8 t15HB [256] IBSS_ATTR;
-uint16 t16HB [256] IBSS_ATTR;
-uint16 t24HB [256] IBSS_ATTR;
-uint8 t1l [ 8] IBSS_ATTR;
-uint8 t2l [ 9] IBSS_ATTR;
-uint8 t3l [ 9] IBSS_ATTR;
-uint8 t5l [ 16] IBSS_ATTR;
-uint8 t6l [ 16] IBSS_ATTR;
-uint8 t7l [ 36] IBSS_ATTR;
-uint8 t8l [ 36] IBSS_ATTR;
-uint8 t9l [ 36] IBSS_ATTR;
-uint8 t10l [ 64] IBSS_ATTR;
-uint8 t11l [ 64] IBSS_ATTR;
-uint8 t12l [ 64] IBSS_ATTR;
-uint8 t13l [256] IBSS_ATTR;
-uint8 t15l [256] IBSS_ATTR;
-uint8 t16l [256] IBSS_ATTR;
-uint8 t24l [256] IBSS_ATTR;
-struct huffcodetab ht [HTN] IBSS_ATTR;
-
-static config_t cfg;
+static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */
+static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */
+static int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */
+static short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */
+static uint32_t scalefac [23] IBSS_ATTR; /* 92 Bytes */
+static BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */
+static int ca [8] IBSS_ATTR; /* 32 Bytes */
+static int cs [8] IBSS_ATTR; /* 32 Bytes */
+static int cx [9] IBSS_ATTR; /* 36 Bytes */
+static int win [18][4] IBSS_ATTR; /* 288 Bytes */
+static short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */
+static short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */
+static uint8_t ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */
+static uint32_t tab01 [ 16] IBSS_ATTR; /* 64 Bytes */
+static uint32_t tab23 [ 9] IBSS_ATTR; /* 36 Bytes */
+static uint32_t tab56 [ 16] IBSS_ATTR; /* 64 Bytes */
+static uint32_t tab1315 [256] IBSS_ATTR; /* 1024 Bytes */
+static uint32_t tab1624 [256] IBSS_ATTR; /* 1024 Bytes */
+static uint32_t tab789 [ 36] IBSS_ATTR; /* 144 Bytes */
+static uint32_t tabABC [ 64] IBSS_ATTR; /* 256 Bytes */
+static uint8_t t1HB [ 4] IBSS_ATTR;
+static uint8_t t2HB [ 9] IBSS_ATTR;
+static uint8_t t3HB [ 9] IBSS_ATTR;
+static uint8_t t5HB [ 16] IBSS_ATTR;
+static uint8_t t6HB [ 16] IBSS_ATTR;
+static uint8_t t7HB [ 36] IBSS_ATTR;
+static uint8_t t8HB [ 36] IBSS_ATTR;
+static uint8_t t9HB [ 36] IBSS_ATTR;
+static uint8_t t10HB [ 64] IBSS_ATTR;
+static uint8_t t11HB [ 64] IBSS_ATTR;
+static uint8_t t12HB [ 64] IBSS_ATTR;
+static uint8_t t13HB [256] IBSS_ATTR;
+static uint8_t t15HB [256] IBSS_ATTR;
+static uint16_t t16HB [256] IBSS_ATTR;
+static uint16_t t24HB [256] IBSS_ATTR;
+static uint8_t t1l [ 8] IBSS_ATTR;
+static uint8_t t2l [ 9] IBSS_ATTR;
+static uint8_t t3l [ 9] IBSS_ATTR;
+static uint8_t t5l [ 16] IBSS_ATTR;
+static uint8_t t6l [ 16] IBSS_ATTR;
+static uint8_t t7l [ 36] IBSS_ATTR;
+static uint8_t t8l [ 36] IBSS_ATTR;
+static uint8_t t9l [ 36] IBSS_ATTR;
+static uint8_t t10l [ 64] IBSS_ATTR;
+static uint8_t t11l [ 64] IBSS_ATTR;
+static uint8_t t12l [ 64] IBSS_ATTR;
+static uint8_t t13l [256] IBSS_ATTR;
+static uint8_t t15l [256] IBSS_ATTR;
+static uint8_t t16l [256] IBSS_ATTR;
+static uint8_t t24l [256] IBSS_ATTR;
+static struct huffcodetab ht [HTN] IBSS_ATTR;
+
+static unsigned pcm_chunk_size IBSS_ATTR;
+static unsigned samp_per_frame IBSS_ATTR;
+
+static config_t cfg IBSS_ATTR;
static struct codec_api *ci;
-static int enc_channels;
+static char *res_buffer;
-static const uint8 ht_count_const[2][2][16] =
+static const uint8_t ht_count_const[2][2][16] =
{ { { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1 }, /* table0 */
{ 1, 5, 5, 7, 5, 8, 7, 9, 5, 7, 7, 9, 7, 9, 9,10 } }, /* hleng0 */
{ {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, /* table1 */
{ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 } } }; /* hleng1 */
-static const uint8 t1HB_const[4] = {1,1,1,0};
-static const uint8 t2HB_const[9] = {1,2,1,3,1,1,3,2,0};
-static const uint8 t3HB_const[9] = {3,2,1,1,1,1,3,2,0};
-static const uint8 t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0};
-static const uint8 t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0};
+static const uint8_t t1HB_const[4] = {1,1,1,0};
+static const uint8_t t2HB_const[9] = {1,2,1,3,1,1,3,2,0};
+static const uint8_t t3HB_const[9] = {3,2,1,1,1,1,3,2,0};
+static const uint8_t t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0};
+static const uint8_t t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0};
-static const uint8 t7HB_const[36] =
+static const uint8_t t7HB_const[36] =
{ 1, 2,10,19,16,10, 3, 3, 7,10, 5, 3,11, 4,13,17, 8, 4,
12,11,18,15,11, 2, 7, 6, 9,14, 3, 1, 6, 4, 5, 3, 2, 0 };
-static const uint8 t8HB_const[36] =
+static const uint8_t t8HB_const[36] =
{ 3, 4, 6,18,12, 5, 5, 1, 2,16, 9, 3, 7, 3, 5,14, 7, 3,
19,17,15,13,10, 4,13, 5, 8,11, 5, 1,12, 4, 4, 1, 1, 0 };
-static const uint8 t9HB_const[36] =
+static const uint8_t t9HB_const[36] =
{ 7, 5, 9,14,15, 7, 6, 4, 5, 5, 6, 7, 7, 6, 8, 8, 8, 5,
15, 6, 9,10, 5, 1,11, 7, 9, 6, 4, 1,14, 4, 6, 2, 6, 0 };
-static const uint8 t10HB_const[64] =
+static const uint8_t t10HB_const[64] =
{1,2,10,23,35,30,12,17,3,3,8,12,18,21,12,7,11,9,15,21,32,
40,19,6,14,13,22,34,46,23,18,7,20,19,33,47,27,22,9,3,31,22,
41,26,21,20,5,3,14,13,10,11,16,6,5,1,9,8,7,8,4,4,2,0 };
-static const uint8 t11HB_const[64] =
+static const uint8_t t11HB_const[64] =
{3,4,10,24,34,33,21,15,5,3,4,10,32,17,11,10,11,7,13,18,30,
31,20,5,25,11,19,59,27,18,12,5,35,33,31,58,30,16,7,5,28,26,
32,19,17,15,8,14,14,12,9,13,14,9,4,1,11,4,6,6,6,3,2,0 };
-static const uint8 t12HB_const[64] =
+static const uint8_t t12HB_const[64] =
{9,6,16,33,41,39,38,26,7,5,6,9,23,16,26,11,17,7,11,14,21,
30,10,7,17,10,15,12,18,28,14,5,32,13,22,19,18,16,9,5,40,17,
31,29,17,13,4,2,27,12,11,15,10,7,4,1,27,12,8,12,6,3,1,0 };
-static const uint8 t13HB_const[256] =
+static const uint8_t t13HB_const[256] =
{1,5,14,21,34,51,46,71,42,52,68,52,67,44,43,19,3,4,12,19,31,26,44,33,31,24,32,
24,31,35,22,14,15,13,23,36,59,49,77,65,29,40,30,40,27,33,42,16,22,20,37,61,56,
79,73,64,43,76,56,37,26,31,25,14,35,16,60,57,97,75,114,91,54,73,55,41,48,53,
@@ -234,7 +235,7 @@ static const uint8 t13HB_const[256] =
45,21,34,64,56,50,49,45,31,19,12,15,10,7,6,3,48,23,20,39,36,35,53,21,16,23,13,
10,6,1,4,2,16,15,17,27,25,20,29,11,17,12,16,8,1,1,0,1 };
-static const uint8 t15HB_const[256] =
+static const uint8_t t15HB_const[256] =
{7,12,18,53,47,76,124,108,89,123,108,119,107,81,122,63,13,5,16,27,46,36,61,51,
42,70,52,83,65,41,59,36,19,17,15,24,41,34,59,48,40,64,50,78,62,80,56,33,29,28,
25,43,39,63,55,93,76,59,93,72,54,75,50,29,52,22,42,40,67,57,95,79,72,57,89,69,
@@ -246,7 +247,7 @@ static const uint8 t15HB_const[256] =
24,16,22,13,14,7,91,44,39,38,34,63,52,45,31,52,28,19,14,8,9,3,123,60,58,53,47,
43,32,22,37,24,17,12,15,10,2,1,71,37,34,30,28,20,17,26,21,16,10,6,8,6,2,0};
-static const uint16 t16HB_const[256] =
+static const uint16_t t16HB_const[256] =
{1,5,14,44,74,63,110,93,172,149,138,242,225,195,376,17,3,4,12,20,35,62,53,47,
83,75,68,119,201,107,207,9,15,13,23,38,67,58,103,90,161,72,127,117,110,209,
206,16,45,21,39,69,64,114,99,87,158,140,252,212,199,387,365,26,75,36,68,65,
@@ -261,7 +262,7 @@ static const uint16 t16HB_const[256] =
358,711,709,866,1734,871,3458,870,434,0,12,10,7,11,10,17,11,9,13,12,10,7,5,3,
1,3};
-static const uint16 t24HB_const[256] =
+static const uint16_t t24HB_const[256] =
{15,13,46,80,146,262,248,434,426,669,653,649,621,517,1032,88,14,12,21,38,71,
130,122,216,209,198,327,345,319,297,279,42,47,22,41,74,68,128,120,221,207,194,
182,340,315,295,541,18,81,39,75,70,134,125,116,220,204,190,178,325,311,293,
@@ -276,7 +277,7 @@ static const uint16 t24HB_const[256] =
374,369,365,361,357,2,1033,280,278,274,267,264,259,382,378,372,367,363,360,
358,356,0,43,20,19,17,15,13,11,9,7,6,4,7,5,3,1,3};
-static const uint32 tab1315_const[256] =
+static const uint32_t tab1315_const[256] =
{ 0x010003,0x050005,0x070006,0x080008,0x090008,0x0a0009,0x0a000a,0x0b000a,
0x0a000a,0x0b000b,0x0c000b,0x0c000c,0x0d000c,0x0d000c,0x0e000d,0x0e000e,
0x040005,0x060005,0x080007,0x090008,0x0a0009,0x0a0009,0x0b000a,0x0b000a,
@@ -310,18 +311,18 @@ static const uint32 tab1315_const[256] =
0x0d000d,0x0e000d,0x0f000d,0x10000d,0x10000d,0x10000d,0x11000d,0x10000e,
0x11000e,0x11000e,0x12000e,0x12000e,0x15000f,0x14000f,0x15000f,0x12000f };
-static const uint32 tab01_const[16] =
+static const uint32_t tab01_const[16] =
{ 0x10004,0x50005,0x50005,0x70006,0x50005,0x80006,0x70006,0x90007,
0x50005,0x70006,0x70006,0x90007,0x70006,0x90007,0x90007,0xa0008 };
-static const uint32 tab23_const[ 9] =
+static const uint32_t tab23_const[ 9] =
{ 0x10002,0x40003,0x70007,0x40004,0x50004,0x70007,0x60006,0x70007,0x80008 };
-static const uint32 tab56_const[16] =
+static const uint32_t tab56_const[16] =
{ 0x10003,0x40004,0x70006,0x80008,0x40004,0x50004,0x80006,0x90007,
0x70005,0x80006,0x90007,0xa0008,0x80007,0x80007,0x90008,0xa0009 };
-static const uint32 tab789_const[36] =
+static const uint32_t tab789_const[36] =
{0x00100803,0x00401004,0x00701c06,0x00902407,0x00902409,0x00a0280a,0x00401004,
0x00601005,0x00801806,0x00902807,0x00902808,0x00a0280a,0x00701c05,0x00701806,
0x00902007,0x00a02808,0x00a02809,0x00b02c0a,0x00802407,0x00902807,0x00a02808,
@@ -329,7 +330,7 @@ static const uint32 tab789_const[36] =
0x00b0300a,0x00c0300b,0x00902809,0x00a02809,0x00b02c0a,0x00c02c0a,0x00c0340b,
0x00c0340b};
-static const uint32 tabABC_const[64] =
+static const uint32_t tabABC_const[64] =
{0x00100804,0x00401004,0x00701806,0x00902008,0x00a02409,0x00a0280a,0x00a0240a,
0x00b0280a,0x00401004,0x00601405,0x00801806,0x00902007,0x00a02809,0x00b02809,
0x00a0240a,0x00a0280a,0x00701806,0x00801c06,0x00902007,0x00a02408,0x00b02809,
@@ -341,7 +342,7 @@ static const uint32 tabABC_const[64] =
0x00a0240a,0x00a0240a,0x00b0280a,0x00c02c0b,0x00c0300b,0x00d0300b,0x00d0300b,
0x00d0300c};
-static const uint32 tab1624_const[256] =
+static const uint32_t tab1624_const[256] =
{0x00010004,0x00050005,0x00070007,0x00090008,0x000a0009,0x000a000a,0x000b000a,
0x000b000b,0x000c000b,0x000c000c,0x000c000c,0x000d000c,0x000d000c,0x000d000c,
0x000e000d,0x000a000a,0x00040005,0x00060006,0x00080007,0x00090008,0x000a0009,
@@ -380,34 +381,34 @@ static const uint32 tab1624_const[256] =
0x000c0009,0x000c0009,0x000c0009,0x000d0009,0x000d0009,0x000d0009,0x000d000a,
0x000d000a,0x000d000a,0x000d000a,0x000a0006};
-static const uint8 t1l_const[8] = {1,3,2,3,1,4,3,5};
-static const uint8 t2l_const[9] = {1,3,6,3,3,5,5,5,6};
-static const uint8 t3l_const[9] = {2,2,6,3,2,5,5,5,6};
-static const uint8 t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8};
-static const uint8 t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7};
+static const uint8_t t1l_const[8] = {1,3,2,3,1,4,3,5};
+static const uint8_t t2l_const[9] = {1,3,6,3,3,5,5,5,6};
+static const uint8_t t3l_const[9] = {2,2,6,3,2,5,5,5,6};
+static const uint8_t t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8};
+static const uint8_t t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7};
-static const uint8 t7l_const[36] =
+static const uint8_t t7l_const[36] =
{1,3,6,8,8,9,3,4,6,7,7,8,6,5,7,8,8,9,7,7,8,9,9,9,7,7,8,9,9,10,8,8,9,10,10,10};
-static const uint8 t8l_const[36] =
+static const uint8_t t8l_const[36] =
{2,3,6,8,8,9,3,2,4,8,8,8,6,4,6,8,8,9,8,8,8,9,9,10,8,7,8,9,10,10,9,8,9,9,11,11};
-static const uint8 t9l_const[36] =
+static const uint8_t t9l_const[36] =
{3,3,5,6,8,9,3,3,4,5,6,8,4,4,5,6,7,8,6,5,6,7,7,8,7,6,7,7,8,9,8,7,8,8,9,9};
-static const uint8 t10l_const[64] =
+static const uint8_t t10l_const[64] =
{1,3,6,8,9,9,9,10,3,4,6,7,8,9,8,8,6,6,7,8,9,10,9,9,7,7,8,9,10,10,9,10,8,8,9,10,
10,10,10,10,9,9,10,10,11,11,10,11,8,8,9,10,10,10,11,11,9,8,9,10,10,11,11,11};
-static const uint8 t11l_const[64] =
+static const uint8_t t11l_const[64] =
{2,3,5,7,8,9,8,9,3,3,4,6,8,8,7,8,5,5,6,7,8,9,8,8,7,6,7,9,8,10,8,9,8,8,8,9,9,10,
9,10,8,8,9,10,10,11,10,11,8,7,7,8,9,10,10,10,8,7,8,9,10,10,10,10};
-static const uint8 t12l_const[64] =
+static const uint8_t t12l_const[64] =
{4,3,5,7,8,9,9,9,3,3,4,5,7,7,8,8,5,4,5,6,7,8,7,8,6,5,6,6,7,8,8,8,7,6,7,7,8,
8,8,9,8,7,8,8,8,9,8,9,8,7,7,8,8,9,9,10,9,8,8,9,9,9,9,10};
-static const uint8 t13l_const[256] =
+static const uint8_t t13l_const[256] =
{1,4,6,7,8,9,9,10,9,10,11,11,12,12,13,13,3,4,6,7,8,8,9,9,9,9,10,10,11,12,12,12,
6,6,7,8,9,9,10,10,9,10,10,11,11,12,13,13,7,7,8,9,9,10,10,10,10,11,11,11,11,12,
13,13,8,7,9,9,10,10,11,11,10,11,11,12,12,13,13,14,9,8,9,10,10,10,11,11,11,11,
@@ -419,7 +420,7 @@ static const uint8 t13l_const[256] =
16,16,13,12,12,13,13,13,15,14,14,17,15,15,15,17,16,16,12,12,13,14,14,14,15,14,
15,15,16,16,19,18,19,16};
-static const uint8 t15l_const[256] =
+static const uint8_t t15l_const[256] =
{3,4,5,7,7,8,9,9,9,10,10,11,11,11,12,13,4,3,5,6,7,7,8,8,8,9,9,10,10,10,11,11,5,
5,5,6,7,7,8,8,8,9,9,10,10,11,11,11,6,6,6,7,7,8,8,9,9,9,10,10,10,11,11,11,7,6,
7,7,8,8,9,9,9,9,10,10,10,11,11,11,8,7,7,8,8,8,9,9,9,9,10,10,11,11,11,12,9,7,8,
@@ -430,7 +431,7 @@ static const uint8 t15l_const[256] =
11,11,11,11,12,12,12,12,12,13,13,12,11,11,11,11,11,11,11,12,12,12,12,13,13,12,
13,12,11,11,11,11,11,11,12,12,12,12,12,13,13,13,13};
-static const uint8 t16l_const[256] =
+static const uint8_t t16l_const[256] =
{1,4,6,8,9,9,10,10,11,11,11,12,12,12,13,9,3,4,6,7,8,9,9,9,10,10,10,11,12,11,12,
8,6,6,7,8,9,9,10,10,11,10,11,11,11,12,12,9,8,7,8,9,9,10,10,10,11,11,12,12,12,
13,13,10,9,8,9,9,10,10,11,11,11,12,12,12,13,13,13,9,9,8,9,9,10,11,11,12,11,12,
@@ -442,7 +443,7 @@ static const uint8 t16l_const[256] =
17,15,11,13,13,11,12,14,14,13,14,14,15,16,15,17,15,14,11,9,8,8,9,9,10,10,10,
11,11,11,11,11,11,11,8};
-static const uint8 t24l_const[256] =
+static const uint8_t t24l_const[256] =
{4,4,6,7,8,9,9,10,10,11,11,11,11,11,12,9,4,4,5,6,7,8,8,9,9,9,10,10,10,10,10,8,
6,5,6,7,7,8,8,9,9,9,9,10,10,10,11,7,7,6,7,7,8,8,8,9,9,9,9,10,10,10,10,7,8,7,7,
8,8,8,8,9,9,9,10,10,10,10,11,7,9,7,8,8,8,8,9,9,9,9,10,10,10,10,10,7,9,8,8,8,8,
@@ -491,8 +492,8 @@ static const struct huffcodebig ht_big[HTN] =
static const struct
{
- uint32 region0_cnt;
- uint32 region1_cnt;
+ uint32_t region0_cnt;
+ uint32_t region1_cnt;
} subdv_table[23] =
{ {0, 0}, /* 0 bands */
{0, 0}, /* 1 bands */
@@ -519,7 +520,7 @@ static const struct
{6, 7}, /* 22 bands */
};
-static const uint32 sfBand[6][23] =
+static const uint32_t sfBand[6][23] =
{
/* Table B.2.b: 22.05 kHz */
{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
@@ -747,9 +748,13 @@ static const int order[32] =
{ 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29,
2, 3, 18, 19,10,11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 };
-static const int bitr_index[2][15] =
-{ {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160},
- {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} };
+static const long sampr_index[2][3] =
+{ { 22050, 24000, 16000 }, /* MPEG 2 */
+ { 44100, 48000, 32000 } }; /* MPEG 1 */
+
+static const long bitr_index[2][15] =
+{ {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160}, /* MPEG 2 */
+ {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} }; /* MPEG 1 */
static const int num_bands[3][15] =
{ {0,10,10,10,10,12,14,16, 20, 22, 24, 26, 28, 30, 32},
@@ -837,35 +842,55 @@ static const int win_const[18][4] = {
{ 134, -146,-3352,-3072 } };
/* forward declarations */
-int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table);
-int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int table);
-void putbits(uint32 val, uint32 nbit);
-int find_best_2( short *ix, uint32 start, uint32 end, const uint32 *table,
- uint32 len, int *bits);
-int find_best_3( short *ix, uint32 start, uint32 end, const uint32 *table,
- uint32 len, int *bits);
-int count_bit1 ( short *ix, uint32 start, uint32 end, int *bits );
-int count_bigv ( short *ix, uint32 start, uint32 end, int table0, int table1,
+static int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table);
+static int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int table);
+static void putbits(uint32_t val, uint32_t nbit);
+static int find_best_2( short *ix, uint32_t start, uint32_t end, const uint32_t *table,
+ uint32_t len, int *bits);
+static int find_best_3( short *ix, uint32_t start, uint32_t end, const uint32_t *table,
+ uint32_t len, int *bits);
+static int count_bit1 ( short *ix, uint32_t start, uint32_t end, int *bits );
+static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1,
int *bits);
-void encodeSideInfo( side_info_t si[2][2] )
+static void encodeSideInfo( side_info_t si[2][2] )
{
int gr, ch, header;
- uint32 cc=0, sz=0;
+ uint32_t cc=0, sz=0;
- header = 0xfff00000;
- header |= cfg.mpg.type << 19; /* mp3 type: 1 */
- header |= 1 << 17; /* mp3 layer: 1 */
- header |= 1 << 16; /* mp3 crc: 0 */
+ /*
+ * MPEG header layout:
+ * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
+ * A (31-21) = frame sync
+ * B (20-19) = MPEG type
+ * C (18-17) = MPEG layer
+ * D (16) = protection bit
+ * E (15-12) = bitrate index
+ * F (11-10) = samplerate index
+ * G (9) = padding bit
+ * H (8) = private bit
+ * I (7-6) = channel mode
+ * J (5-4) = mode extension (jstereo only)
+ * K (3) = copyright bit
+ * L (2) = original
+ * M (1-0) = emphasis
+ */
+
+ header = (0xfff00000) | /* frame sync (AAAAAAAAA AAA)
+ mp3 type (upper): 1 (B) */
+ (0x01 << 17) | /* mp3 layer: 01 (CC) */
+ ( 0x1 << 16) | /* mp3 crc: 1 (D) */
+ ( 0x1 << 2); /* mp3 org: 1 (L) */
+ header |= cfg.mpg.type << 19;
header |= cfg.mpg.bitr_id << 12;
header |= cfg.mpg.smpl_id << 10;
header |= cfg.mpg.padding << 9;
header |= cfg.mpg.mode << 6;
- header |= 1 << 2; /* mp3 original: 1 */
+ /* no emphasis (bits 0-1) */
putbits( header, 32 );
- if(cfg.mpg.type)
+ if(cfg.mpg.type == 1)
{ /* MPEG1 */
if(cfg.channels == 2) { putlong( 0, 20); }
else { putlong( 0, 18); }
@@ -910,7 +935,7 @@ void encodeSideInfo( side_info_t si[2][2] )
/* Note the discussion of huffmancodebits() on pages 28 and 29 of the IS,
as well as the definitions of the side information on pages 26 and 27. */
-void Huffmancodebits( short *ix, int *xr, side_info_t *gi )
+static void Huffmancodebits( short *ix, int *xr, side_info_t *gi )
{
int region1 = gi->address1;
int region2 = gi->address2;
@@ -944,10 +969,10 @@ void Huffmancodebits( short *ix, int *xr, side_info_t *gi )
}
}
-int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int tbl)
+int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int tbl)
{
- uint32 cc=0, sz=0;
- uint32 i, d, p;
+ uint32_t cc=0, sz=0;
+ uint32_t i, d, p;
int sumbit=0, s=0, l=0, v, w, x, y;
#define sgnv (xr[i+0] < 0 ? 1 : 0)
#define sgnw (xr[i+1] < 0 ? 1 : 0)
@@ -995,10 +1020,10 @@ int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int tbl)
}
/* Implements the pseudocode of page 98 of the IS */
-int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table)
+int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table)
{
- uint32 cc=0, sz=0, code;
- uint32 i, xl=0, yl=0, idx;
+ uint32_t cc=0, sz=0, code;
+ uint32_t i, xl=0, yl=0, idx;
int x, y, bit, sumbit=0;
#define sign_x (xr[i+0] < 0 ? 1 : 0)
#define sign_y (xr[i+1] < 0 ? 1 : 0)
@@ -1008,9 +1033,9 @@ int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table)
if( table > 15 )
{ /* ESC-table is used */
- uint32 linbits = ht_big[table-16].linbits;
- uint16 *hffcode = table < 24 ? t16HB : t24HB;
- uint8 *hlen = table < 24 ? t16l : t24l;
+ uint32_t linbits = ht_big[table-16].linbits;
+ uint16_t *hffcode = table < 24 ? t16HB : t24HB;
+ uint8_t *hlen = table < 24 ? t16l : t24l;
for(i=begin; i<end; i+=2)
{
@@ -1088,14 +1113,14 @@ int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table)
return sumbit;
}
-void putbits(uint32 val, uint32 nbit)
+void putbits(uint32_t val, uint32_t nbit)
{
int new_bitpos = CodedData.bitpos + nbit;
int ptrpos = CodedData.bitpos >> 5;
val = val & (0xffffffff >> (32 - nbit));
- /* data fit in one uint32 */
+ /* data fit in one uint32_t */
if(((new_bitpos - 1) >> 5) == ptrpos)
CodedData.bbuf[ptrpos] |= val << ((32 - new_bitpos) & 31);
else
@@ -1114,9 +1139,9 @@ void putbits(uint32 val, uint32 nbit)
/* of the Huffman tables as defined in the IS (Table B.7), and will not */
/* work with any arbitrary tables. */
/***************************************************************************/
-int choose_table( short *ix, uint32 begin, uint32 end, int *bits )
+int choose_table( short *ix, uint32_t begin, uint32_t end, int *bits )
{
- uint32 i;
+ uint32_t i;
int max, table0, table1;
for(i=begin,max=0; i<end; i++)
@@ -1158,10 +1183,10 @@ int choose_table( short *ix, uint32 begin, uint32 end, int *bits )
}
}
-int find_best_2(short *ix, uint32 start, uint32 end, const uint32 *table,
- uint32 len, int *bits)
+int find_best_2(short *ix, uint32_t start, uint32_t end, const uint32_t *table,
+ uint32_t len, int *bits)
{
- uint32 i, sum = 0;
+ uint32_t i, sum = 0;
for(i=start; i<end; i+=2)
sum += table[ix[i] * len + ix[i+1]];
@@ -1178,10 +1203,10 @@ int find_best_2(short *ix, uint32 start, uint32 end, const uint32 *table,
}
}
-int find_best_3(short *ix, uint32 start, uint32 end, const uint32 *table,
- uint32 len, int *bits)
+int find_best_3(short *ix, uint32_t start, uint32_t end, const uint32_t *table,
+ uint32_t len, int *bits)
{
- uint32 i, j, sum = 0;
+ uint32_t i, j, sum = 0;
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
@@ -1211,9 +1236,9 @@ int find_best_3(short *ix, uint32 start, uint32 end, const uint32 *table,
/*************************************************************************/
/* Function: Count the number of bits necessary to code the subregion. */
/*************************************************************************/
-int count_bit1(short *ix, uint32 start, uint32 end, int *bits )
+int count_bit1(short *ix, uint32_t start, uint32_t end, int *bits )
{
- uint32 i, sum = 0;
+ uint32_t i, sum = 0;
for(i=start; i<end; i+=2)
sum += t1l[4 + ix[i] * 2 + ix[i+1]];
@@ -1223,10 +1248,10 @@ int count_bit1(short *ix, uint32 start, uint32 end, int *bits )
return 1; /* this is table1 */
}
-int count_bigv(short *ix, uint32 start, uint32 end, int table0,
+int count_bigv(short *ix, uint32_t start, uint32_t end, int table0,
int table1, int *bits )
{
- uint32 i, sum0, sum1, sum=0, bigv=0, x, y;
+ uint32_t i, sum0, sum1, sum=0, bigv=0, x, y;
/* ESC-table is used */
for(i=start; i<end; i+=2)
@@ -1264,7 +1289,7 @@ int calc_runlen( short *ix, side_info_t *si )
int p, i, sum = 0;
for(i=SAMPL2; i-=2; )
- if(*(uint32*)&ix[i-2]) /* !!!! short *ix; !!!!! */
+ if(*(uint32_t*)&ix[i-2]) /* !!!! short *ix; !!!!! */
break;
si->count1 = 0;
@@ -1899,276 +1924,275 @@ void mdct_long(int *out, int *in)
out[16] = ct - st;
}
-static int find_bitrate_index(int type, int bitrate)
+static int find_bitrate_index(int type, int bitrate, bool stereo)
{
- int i;
+ if (type == 1 && !stereo && bitrate > 160)
+ bitrate = 160;
- for(i=0;i<14;i++)
- if(bitrate == bitr_index[type][i])
- break;
-
- return i;
+ return ci->round_value_to_list32(bitrate,
+ &bitr_index[type][1], 14, true) + 1;
}
static int find_samplerate_index(long freq, int *mp3_type)
-{ /* MPEG 2 */ /* MPEG 1 */
- static long mpeg[2][3] = { {22050, 24000, 16000}, {44100, 48000, 32000} };
- int mpg, rate;
-
- /* set default values: MPEG1 at 44100/s */
- *mp3_type = 1;
-
- for(mpg=0; mpg<2; mpg++)
- for(rate=0; rate<3; rate++)
- if(freq == mpeg[mpg][rate])
- { *mp3_type = mpg; return rate; }
-
- return 0;
+{
+ int mpeg = freq >= (32000+24000)/2 ? 1 : 0;
+ int i = ci->round_value_to_list32(freq, sampr_index[mpeg], 3, true);
+ *mp3_type = mpeg;
+ return i;
}
-void init_mp3_encoder_engine(bool stereo, int quality, int sample_rate)
+bool init_mp3_encoder_engine(int sample_rate,
+ int num_channels,
+ struct encoder_config *enc_cfg)
{
- /* keep in sync with rec_quality_info_afmt in id3.h/.c */
- static int bitr_s[9] = { 64, 96, 128, 160, 192, 224, 320, 64, 64 };
- static int bitr_m[9] = { 64, 96, 128, 160, 160, 160, 160, 64, 64 };
- uint32 avg_byte_per_frame;
-
- if(quality == 0 && stereo && sample_rate >= 32000)
- { /* use MPEG2 format */
- sample_rate >>= 1;
- cfg.resample = 1;
- cfg.granules = 1;
- }
- else
- { /* use MPEG1 format */
- cfg.resample = 0;
- cfg.granules = 2;
- }
+ const bool stereo = num_channels > 1;
+ uint32_t avg_byte_per_frame;
+
+ cfg.channels = stereo ? 2 : 1;
+ cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */
+ cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type);
+ cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id];
+ cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type,
+ enc_cfg->mp3_enc.bitrate,
+ stereo);
+ cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id];
+ cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id];
+
+ if (cfg.mpg.type == 1)
+ {
+ cfg.granules = 2;
+ pcm_chunk_size = PCM_CHUNK_SIZE1;
+ samp_per_frame = SAMP_PER_FRAME1;
+ }
+ else
+ {
+ cfg.granules = 1;
+ pcm_chunk_size = PCM_CHUNK_SIZE2;
+ samp_per_frame = SAMP_PER_FRAME2;
+ }
- cfg.byte_order = order_bigEndian;
- cfg.samplerate = sample_rate;
- cfg.channels = stereo ? 2 : 1;
- cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */
- cfg.mpg.bitrate = stereo ? bitr_s[quality] : bitr_m[quality];
- cfg.mpg.smpl_id = find_samplerate_index(cfg.samplerate, &cfg.mpg.type);
- cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, cfg.mpg.bitrate);
- cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id];
-
- memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac));
- memset(mfbuf , 0 , sizeof(mfbuf ));
- memset(mdct_freq , 0 , sizeof(mdct_freq ));
- memset(enc_data , 0 , sizeof(enc_data ));
- memset(sb_data , 0 , sizeof(sb_data ));
- memset(&CodedData, 0 , sizeof(CodedData ));
- memcpy(ca , ca_const , sizeof(ca ));
- memcpy(cs , cs_const , sizeof(cs ));
- memcpy(cx , cx_const , sizeof(cx ));
- memcpy(win , win_const , sizeof(win ));
- memcpy(enwindow , enwindow_const , sizeof(enwindow ));
- memcpy(int2idx , int2idx_const , sizeof(int2idx ));
- memcpy(ht_count , ht_count_const , sizeof(ht_count ));
- memcpy( tab01 , tab01_const , sizeof(tab01 ));
- memcpy( tab23 , tab23_const , sizeof(tab23 ));
- memcpy( tab56 , tab56_const , sizeof(tab56 ));
- memcpy( tab1315 , tab1315_const , sizeof(tab1315 ));
- memcpy( tab1624 , tab1624_const , sizeof(tab1624 ));
- memcpy( tab789 , tab789_const , sizeof(tab789 ));
- memcpy( tabABC , tabABC_const , sizeof(tabABC ));
- memcpy( t1HB , t1HB_const , sizeof(t1HB ));
- memcpy( t2HB , t2HB_const , sizeof(t2HB ));
- memcpy( t3HB , t3HB_const , sizeof(t3HB ));
- memcpy( t5HB , t5HB_const , sizeof(t5HB ));
- memcpy( t6HB , t6HB_const , sizeof(t6HB ));
- memcpy( t7HB , t7HB_const , sizeof(t7HB ));
- memcpy( t8HB , t8HB_const , sizeof(t8HB ));
- memcpy( t9HB , t9HB_const , sizeof(t9HB ));
- memcpy(t10HB , t10HB_const , sizeof(t10HB ));
- memcpy(t11HB , t11HB_const , sizeof(t11HB ));
- memcpy(t12HB , t12HB_const , sizeof(t12HB ));
- memcpy(t13HB , t13HB_const , sizeof(t13HB ));
- memcpy(t15HB , t15HB_const , sizeof(t15HB ));
- memcpy(t16HB , t16HB_const , sizeof(t16HB ));
- memcpy(t24HB , t24HB_const , sizeof(t24HB ));
- memcpy( t1l , t1l_const , sizeof(t1l ));
- memcpy( t2l , t2l_const , sizeof(t2l ));
- memcpy( t3l , t3l_const , sizeof(t3l ));
- memcpy( t5l , t5l_const , sizeof(t5l ));
- memcpy( t6l , t6l_const , sizeof(t6l ));
- memcpy( t7l , t7l_const , sizeof(t7l ));
- memcpy( t8l , t8l_const , sizeof(t8l ));
- memcpy( t9l , t9l_const , sizeof(t9l ));
- memcpy(t10l , t10l_const , sizeof(t10l ));
- memcpy(t11l , t11l_const , sizeof(t11l ));
- memcpy(t12l , t12l_const , sizeof(t12l ));
- memcpy(t13l , t13l_const , sizeof(t13l ));
- memcpy(t15l , t15l_const , sizeof(t15l ));
- memcpy(t16l , t16l_const , sizeof(t16l ));
- memcpy(t24l , t24l_const , sizeof(t24l ));
- memcpy(ht , ht_const , sizeof(ht ));
-
- ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */
- ht[ 1].table = t1HB; ht[ 1].hlen = t1l;
- ht[ 2].table = t2HB; ht[ 2].hlen = t2l;
- ht[ 3].table = t3HB; ht[ 3].hlen = t3l;
- ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */
- ht[ 5].table = t5HB; ht[ 5].hlen = t5l;
- ht[ 6].table = t6HB; ht[ 6].hlen = t6l;
- ht[ 7].table = t7HB; ht[ 7].hlen = t7l;
- ht[ 8].table = t8HB; ht[ 8].hlen = t8l;
- ht[ 9].table = t9HB; ht[ 9].hlen = t9l;
- ht[10].table = t10HB; ht[10].hlen = t10l;
- ht[11].table = t11HB; ht[11].hlen = t11l;
- ht[12].table = t12HB; ht[12].hlen = t12l;
- ht[13].table = t13HB; ht[13].hlen = t13l;
- ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */
- ht[15].table = t15HB; ht[15].hlen = t15l;
-
- /* Figure average number of 'bytes' per frame */
- avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type);
- avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate;
- cfg.byte_per_frame = avg_byte_per_frame / 64;
- cfg.frac_per_frame = avg_byte_per_frame & 63;
- cfg.slot_lag = 0;
- cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256)
- : (cfg.channels == 1 ? 72 : 136));
+ memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac));
+ memset(mfbuf , 0 , sizeof(mfbuf ));
+ memset(mdct_freq , 0 , sizeof(mdct_freq ));
+ memset(enc_data , 0 , sizeof(enc_data ));
+ memset(sb_data , 0 , sizeof(sb_data ));
+ memset(&CodedData, 0 , sizeof(CodedData ));
+ memcpy(ca , ca_const , sizeof(ca ));
+ memcpy(cs , cs_const , sizeof(cs ));
+ memcpy(cx , cx_const , sizeof(cx ));
+ memcpy(win , win_const , sizeof(win ));
+ memcpy(enwindow , enwindow_const , sizeof(enwindow ));
+ memcpy(int2idx , int2idx_const , sizeof(int2idx ));
+ memcpy(ht_count , ht_count_const , sizeof(ht_count ));
+ memcpy( tab01 , tab01_const , sizeof(tab01 ));
+ memcpy( tab23 , tab23_const , sizeof(tab23 ));
+ memcpy( tab56 , tab56_const , sizeof(tab56 ));
+ memcpy( tab1315 , tab1315_const , sizeof(tab1315 ));
+ memcpy( tab1624 , tab1624_const , sizeof(tab1624 ));
+ memcpy( tab789 , tab789_const , sizeof(tab789 ));
+ memcpy( tabABC , tabABC_const , sizeof(tabABC ));
+ memcpy( t1HB , t1HB_const , sizeof(t1HB ));
+ memcpy( t2HB , t2HB_const , sizeof(t2HB ));
+ memcpy( t3HB , t3HB_const , sizeof(t3HB ));
+ memcpy( t5HB , t5HB_const , sizeof(t5HB ));
+ memcpy( t6HB , t6HB_const , sizeof(t6HB ));
+ memcpy( t7HB , t7HB_const , sizeof(t7HB ));
+ memcpy( t8HB , t8HB_const , sizeof(t8HB ));
+ memcpy( t9HB , t9HB_const , sizeof(t9HB ));
+ memcpy(t10HB , t10HB_const , sizeof(t10HB ));
+ memcpy(t11HB , t11HB_const , sizeof(t11HB ));
+ memcpy(t12HB , t12HB_const , sizeof(t12HB ));
+ memcpy(t13HB , t13HB_const , sizeof(t13HB ));
+ memcpy(t15HB , t15HB_const , sizeof(t15HB ));
+ memcpy(t16HB , t16HB_const , sizeof(t16HB ));
+ memcpy(t24HB , t24HB_const , sizeof(t24HB ));
+ memcpy( t1l , t1l_const , sizeof(t1l ));
+ memcpy( t2l , t2l_const , sizeof(t2l ));
+ memcpy( t3l , t3l_const , sizeof(t3l ));
+ memcpy( t5l , t5l_const , sizeof(t5l ));
+ memcpy( t6l , t6l_const , sizeof(t6l ));
+ memcpy( t7l , t7l_const , sizeof(t7l ));
+ memcpy( t8l , t8l_const , sizeof(t8l ));
+ memcpy( t9l , t9l_const , sizeof(t9l ));
+ memcpy(t10l , t10l_const , sizeof(t10l ));
+ memcpy(t11l , t11l_const , sizeof(t11l ));
+ memcpy(t12l , t12l_const , sizeof(t12l ));
+ memcpy(t13l , t13l_const , sizeof(t13l ));
+ memcpy(t15l , t15l_const , sizeof(t15l ));
+ memcpy(t16l , t16l_const , sizeof(t16l ));
+ memcpy(t24l , t24l_const , sizeof(t24l ));
+ memcpy(ht , ht_const , sizeof(ht ));
+
+ ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */
+ ht[ 1].table = t1HB; ht[ 1].hlen = t1l;
+ ht[ 2].table = t2HB; ht[ 2].hlen = t2l;
+ ht[ 3].table = t3HB; ht[ 3].hlen = t3l;
+ ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */
+ ht[ 5].table = t5HB; ht[ 5].hlen = t5l;
+ ht[ 6].table = t6HB; ht[ 6].hlen = t6l;
+ ht[ 7].table = t7HB; ht[ 7].hlen = t7l;
+ ht[ 8].table = t8HB; ht[ 8].hlen = t8l;
+ ht[ 9].table = t9HB; ht[ 9].hlen = t9l;
+ ht[10].table = t10HB; ht[10].hlen = t10l;
+ ht[11].table = t11HB; ht[11].hlen = t11l;
+ ht[12].table = t12HB; ht[12].hlen = t12l;
+ ht[13].table = t13HB; ht[13].hlen = t13l;
+ ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */
+ ht[15].table = t15HB; ht[15].hlen = t15l;
+
+ /* Figure average number of 'bytes' per frame */
+ avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type);
+ avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate;
+ cfg.byte_per_frame = avg_byte_per_frame / 64;
+ cfg.frac_per_frame = avg_byte_per_frame & 63;
+ cfg.slot_lag = 0;
+ cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256)
+ : (cfg.channels == 1 ? 72 : 136));
+
+ return true;
}
-
-enum codec_status codec_start(struct codec_api* api)
+static void to_mono_mm(void) ICODE_ATTR;
+static void to_mono_mm(void)
{
- int i, ii, gr, k, ch, shift, gr_cnt;
- int max, min;
- long *buffer;
- int chunk_size, num_chunks;
- int enc_buffer_size;
- int enc_quality;
- uint32 *mp3_chunk_ptr;
- bool cpu_boosted = true; /* start boosted */
+ /* |llllllllllllllll|rrrrrrrrrrrrrrrr| =>
+ * |mmmmmmmmmmmmmmmm|mmmmmmmmmmmmmmmm|
+ */
+ uint32_t *samp = (uint32_t *)&mfbuf[2*512];
+ uint32_t *samp_end = samp + samp_per_frame;
- /* Generic codec initialisation */
- ci = api;
-
-#ifdef USE_IRAM
- memcpy(iramstart, iramcopy, iramend - iramstart);
- memset(iedata, 0, iend - iedata);
-#endif
-
- if(ci->enc_get_inputs == NULL ||
- ci->enc_set_parameters == NULL ||
- ci->enc_alloc_chunk == NULL ||
- ci->enc_free_chunk == NULL ||
- ci->enc_wavbuf_near_empty == NULL ||
- ci->enc_get_wav_data == NULL ||
- ci->enc_set_header_callback == NULL )
- return CODEC_ERROR;
+ inline void to_mono(uint32_t **samp)
+ {
+ int32_t lr = **samp;
+ int32_t m = ((int16_t)lr + (lr >> 16)) >> 1;
+ *(*samp)++ = (m << 16) | (uint16_t)m;
+ } /* to_mono */
- ci->cpu_boost(true);
+ do
+ {
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ to_mono(&samp);
+ }
+ while (samp < samp_end);
+} /* to_mono_mm */
+
+#ifdef ROCKBOX_LITTLE_ENDIAN
+/* Swaps a frame to big endian */
+static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src,
+ size_t size) ICODE_ATTR;
+static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src,
+ size_t size)
+{
+ uint32_t *src_end = SKIPBYTES(src, size);
- *ci->enc_set_header_callback = NULL;
- ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality);
+ do
+ {
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ *dst++ = swap32(*src++);
+ }
+ while(src < src_end);
+} /* byte_swap_frame32 */
+#endif /* ROCKBOX_LITTLE_ENDIAN */
- init_mp3_encoder_engine(enc_channels == 2, enc_quality, 44100);
+static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) ICODE_ATTR;
+static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk)
+{
+ int gr, gr_cnt;
+ int max, min;
- /* must be 4byte aligned */
- chunk_size = (sizeof(long) + cfg.byte_per_frame + 1 + 3) & ~3;
- num_chunks = enc_buffer_size / chunk_size;
+ /* encode one mp3 frame in this loop */
+ CodedData.bitpos = 0;
+ memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf));
- /* inform the main program about the buffer dimensions */
- ci->enc_set_parameters(chunk_size, num_chunks, SAMP_PER_FRAME,
- NULL, 0, AFMT_MPA_L3);
+ if((cfg.slot_lag += cfg.frac_per_frame) >= 64)
+ { /* Padding for this frame */
+ cfg.slot_lag -= 64;
+ cfg.mpg.padding = 1;
+ }
+ else
+ cfg.mpg.padding = 0;
-#ifdef CPU_COLDFIRE
- asm volatile ("move.l #0, %macsr"); /* integer mode */
-#endif
+ cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding
+ - cfg.sideinfo_len) / cfg.granules / cfg.channels;
- /* main application waits for this flag during encoder loading */
- ci->enc_codec_loaded = true;
+ /* shift out old samples */
+ memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512);
- /* main encoding loop */
- while(!ci->stop_codec)
+ if (chunk->flags & CHUNKF_START_FILE)
{
- while((buffer = (long*)ci->enc_get_wav_data(SAMP_PER_FRAME*4)) != NULL)
- {
- if(ci->stop_codec)
- break;
-
- if(ci->enc_wavbuf_near_empty() == 0)
- {
- if(!cpu_boosted)
- {
- ci->cpu_boost(true);
- cpu_boosted = true;
- }
- }
+ /* prefix silent samples for encoder delay */
+ memset(mfbuf + 2*512, 0, ENC_DELAY_SIZE);
+ /* read new samples to iram for further processing */
+ memcpy(mfbuf + 2*512 + ENC_DELAY_SIZE/2,
+ buffer, pcm_chunk_size - ENC_DELAY_SIZE);
+ chunk->num_pcm = samp_per_frame - ENC_DELAY_SAMP;
+ }
+ else
+ {
+ /* read new samples to iram for further processing */
+ memcpy(mfbuf + 2*512, buffer, pcm_chunk_size);
+ chunk->num_pcm = samp_per_frame;
+ }
- /* encode one mp3 frame in this loop */
- CodedData.bitpos = 0;
- memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf));
-
- if((cfg.slot_lag += cfg.frac_per_frame) >= 64)
- { /* Padding for this frame */
- cfg.slot_lag -= 64;
- cfg.mpg.padding = 1;
- }
- else
- cfg.mpg.padding = 0;
+ if (cfg.channels == 1)
+ to_mono_mm();
- cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding
- - cfg.sideinfo_len) / cfg.granules / cfg.channels;
+ cfg.ResvSize = 0;
+ gr_cnt = cfg.granules * cfg.channels;
+ CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */
- /* shift out old samples */
- memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512);
- /* read new samples to iram for further processing */
- memcpy((uint32*)(mfbuf + 2*512), buffer, 4*SAMP_PER_FRAME);
+ for(gr=0; gr<cfg.granules; gr++)
+ {
+ short *wk = mfbuf + 2*286 + gr*1152;
+ int ch;
- if(cfg.resample) /* downsample to half of original */
- for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=4)
- {
- mfbuf[i/2+512] = (short)(((int)mfbuf[i+0] + mfbuf[i+2]) >> 1);
- mfbuf[i/2+513] = (short)(((int)mfbuf[i+1] + mfbuf[i+3]) >> 1);
- }
+ /* 16bit packed wav data can be windowed efficiently on coldfire */
+ window_subband1(wk, sb_data[0][1-gr][0], sb_data[1][1-gr][0]);
- if(cfg.channels == 1) /* mix left and right channels to mono */
- for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=2)
- mfbuf[i] = mfbuf[i+1] = (short)(((int)mfbuf[i] + mfbuf[i+1]) >> 1);
+ for(ch=0; ch<cfg.channels; ch++)
+ {
+ int ii, k, shift;
- cfg.ResvSize = 0;
- gr_cnt = cfg.granules * cfg.channels;
- CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */
+ wk = mfbuf + 2*286 + gr*1152 + ch;
- for(gr=0; gr<cfg.granules; gr++)
+ /* 36864=4*18*16*32 */
+ for(k=0; k<18; k++, wk+=64)
{
- short *wk = mfbuf + 2*286 + gr*1152;
-
- /* 16bit packed wav data can be windowed efficiently on coldfire */
- window_subband1(wk, sb_data[0][1-gr][0], sb_data[1][1-gr][0]);
-
- for(ch=0; ch<cfg.channels; ch++)
- {
- int band;
- int *mdct;
-
- wk = mfbuf + 2*286 + gr*1152 + ch;
-
- /* 36864=4*18*16*32 */
- for(k=0; k<18; k++, wk+=64)
+ window_subband2(wk, sb_data[ch][1-gr][k]);
+ /* Compensate for inversion in the analysis filter */
+ if(k & 1)
{
- window_subband2(wk, sb_data[ch][1-gr][k]);
- /* Compensate for inversion in the analysis filter */
- if(k & 1)
+ int band;
for(band=1; band<32; band+=2)
- sb_data[ch][1-gr][k][band] *= -1;
+ sb_data[ch][1-gr][k][band] *= -1;
}
+ }
- /* Perform imdct of 18 previous + 18 current subband samples */
- /* for integer precision do this loop twice (if neccessary) */
- shift = k = 14;
- for(ii=0; ii<2 && k; ii++)
+ /* Perform imdct of 18 previous + 18 current subband samples
+ for integer precision do this loop twice (if neccessary)
+ */
+ shift = k = 14;
+ for(ii=0; ii<2 && k; ii++)
+ {
+ int *mdct = mdct_freq;
+ int band;
+
+ cfg.cod_info[gr][ch].additStep = 4 * (14 - shift);
+
+ for(band=0; band<cfg.mpg.num_bands; band++, mdct+=18)
{
- mdct = mdct_freq;
- cfg.cod_info[gr][ch].additStep = 4 * (14 - shift);
- for(band=0; band<cfg.mpg.num_bands; band++, mdct+=18)
- {
int *band0 = sb_data[ch][ gr][0] + order[band];
int *band1 = sb_data[ch][1-gr][0] + order[band];
int work[18];
@@ -2176,16 +2200,20 @@ enum codec_status codec_start(struct codec_api* api)
/* 9216=4*32*9*8 */
for(k=-9; k<0; k++)
{
- int a = shft_n(band1[(k+9)*32], shift);
- int b = shft_n(band1[(8-k)*32], shift);
- int c = shft_n(band0[(k+9)*32], shift);
- int d = shft_n(band0[(8-k)*32], shift);
-
- work[k+ 9] = shft16(a * win[k+ 9][0] + b * win[k+ 9][1]
- + c * win[k+ 9][2] + d * win[k+ 9][3]);
-
- work[k+18] = shft16(c * win[k+18][0] + d * win[k+18][1]
- + a * win[k+18][2] + b * win[k+18][3]);
+ int a = shft_n(band1[(k+9)*32], shift);
+ int b = shft_n(band1[(8-k)*32], shift);
+ int c = shft_n(band0[(k+9)*32], shift);
+ int d = shft_n(band0[(8-k)*32], shift);
+
+ work[k+ 9] = shft16(a * win[k+ 9][0] +
+ b * win[k+ 9][1] +
+ c * win[k+ 9][2] +
+ d * win[k+ 9][3]);
+
+ work[k+18] = shft16(c * win[k+18][0] +
+ d * win[k+18][1] +
+ a * win[k+18][2] +
+ b * win[k+18][3]);
}
/* 7200=4*18*100 */
@@ -2193,67 +2221,309 @@ enum codec_status codec_start(struct codec_api* api)
/* Perform aliasing reduction butterfly */
if(band != 0)
- for(k=7; k>=0; --k)
- {
- int bu, bd;
- bu = shft15(mdct[k]) * ca[k] + shft15(mdct[-1-k]) * cs[k];
- bd = shft15(mdct[k]) * cs[k] - shft15(mdct[-1-k]) * ca[k];
- mdct[-1-k] = bu;
- mdct[ k ] = bd;
- }
- }
-
- max = min = 0;
- for(k=0; k<576; k++)
- {
+ {
+ for(k=7; k>=0; --k)
+ {
+ int bu, bd;
+ bu = shft15(mdct[k]) * ca[k] +
+ shft15(mdct[-1-k]) * cs[k];
+ bd = shft15(mdct[k]) * cs[k] -
+ shft15(mdct[-1-k]) * ca[k];
+ mdct[-1-k] = bu;
+ mdct[ k ] = bd;
+ }
+ }
+ }
+
+ max = min = 0;
+ for(k=0; k<576; k++)
+ {
mdct_freq[k] = shft13(mdct_freq[k]);
if(max < mdct_freq[k]) max = mdct_freq[k];
if(min > mdct_freq[k]) min = mdct_freq[k];
- }
+ }
- max = (max > -min) ? max : -min;
- cfg.cod_info[gr][ch].max_val = (long)max;
+ max = (max > -min) ? max : -min;
+ cfg.cod_info[gr][ch].max_val = (long)max;
- /* calc new shift for higher integer precision */
- for(k=0; max<(0x3c00>>k); k++);
+ /* calc new shift for higher integer precision */
+ for(k=0; max<(0x3c00>>k); k++);
shift = 12 - k;
- }
+ }
- cfg.cod_info[gr][ch].quantStep += cfg.cod_info[gr][ch].additStep;
+ cfg.cod_info[gr][ch].quantStep +=
+ cfg.cod_info[gr][ch].additStep;
- /* bit and noise allocation */
- iteration_loop(mdct_freq, &cfg.cod_info[gr][ch], gr_cnt--);
- /* write the frame to the bitstream */
- Huffmancodebits(enc_data, mdct_freq, &cfg.cod_info[gr][ch]);
+ /* bit and noise allocation */
+ iteration_loop(mdct_freq, &cfg.cod_info[gr][ch],
+ gr_cnt--);
+ /* write the frame to the bitstream */
+ Huffmancodebits(enc_data, mdct_freq,
+ &cfg.cod_info[gr][ch]);
- cfg.cod_info[gr][ch].quantStep -= cfg.cod_info[gr][ch].additStep;
+ cfg.cod_info[gr][ch].quantStep -=
+ cfg.cod_info[gr][ch].additStep;
- if(cfg.granules == 1)
- memcpy(sb_data[ch][0], sb_data[ch][1], sizeof(sb_data[ch][0]));
- }
+ if(cfg.granules == 1)
+ {
+ memcpy(sb_data[ch][0], sb_data[ch][1],
+ sizeof(sb_data[ch][0]));
}
+ }
+ }
+
+ chunk->enc_size = cfg.byte_per_frame + cfg.mpg.padding;
- mp3_chunk_ptr = (uint32*)ci->enc_alloc_chunk();
- mp3_chunk_ptr[0] = cfg.byte_per_frame + cfg.mpg.padding; //(CodedData.bitpos + 7) >> 3;
/* finish this chunk by adding sideinfo header data */
CodedData.bitpos = 0;
encodeSideInfo( cfg.cod_info );
- /* allocate mp3 chunk, set chunk size, copy chunk to enc_buffer */
- memcpy(&mp3_chunk_ptr[1], CodedData.bbuf, mp3_chunk_ptr[0]);
- ci->enc_free_chunk();
+#ifdef ROCKBOX_BIG_ENDIAN
+ /* copy chunk to enc_buffer */
+ memcpy(chunk->enc_data, CodedData.bbuf, chunk->enc_size);
+#else
+ /* swap frame to big endian */
+ byte_swap_frame32(chunk->enc_data, CodedData.bbuf, chunk->enc_size);
+#endif
+} /* encode_frame */
+
+/* called very often - inline */
+static inline bool is_file_data_ok(struct enc_file_event_data *filed) ICODE_ATTR;
+static inline bool is_file_data_ok(struct enc_file_event_data *filed)
+{
+ return filed->rec_file >= 0 && (long)filed->chunk->flags >= 0;
+} /* is_event_ok */
- ci->yield();
+/* 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("mp3 enc: NULL data");
+#endif
+ return true;
+ }
+
+ 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;
+ return true;
+} /* on_start_file */
+
+static bool on_end_file(struct enc_file_event_data *data)
+{
+ if (!is_file_data_ok(data))
+ return false;
+
+ ci->fsync(data->rec_file);
+ ci->close(data->rec_file);
+ data->rec_file = -1;
+
+ return true;
+} /* on_end_file */
+
+static void on_rec_new_stream(struct enc_buffer_event_data *data)
+{
+ int num_frames = cfg.mpg.type == 1 ?
+ ENC_PADDING_FRAMES1 : ENC_PADDING_FRAMES2;
+
+ if (data->flags & CHUNKF_END_FILE)
+ {
+ /* add silent frames to end - encoder will also be flushed for start
+ of next file if any */
+ memset(res_buffer, 0, pcm_chunk_size);
+
+ /* the initial chunk given for the end is at enc_wr_index */
+ while (num_frames-- > 0)
+ {
+ data->chunk->enc_data = ENC_CHUNK_SKIP_HDR(data->chunk->enc_data,
+ data->chunk);
+
+ encode_frame(res_buffer, data->chunk);
+ data->chunk->num_pcm = samp_per_frame;
+
+ ci->enc_finish_chunk();
+ data->chunk = ci->enc_get_chunk();
}
+ }
+ else if (data->flags & CHUNKF_PRERECORD)
+ {
+ /* nothing to add and we cannot change prerecorded data */
+ }
+ else if (data->flags & CHUNKF_START_FILE)
+ {
+ /* starting fresh ... be sure to flush encoder first */
+ struct enc_chunk_hdr *chunk = ENC_CHUNK_HDR(res_buffer);
- if(ci->enc_wavbuf_near_empty())
+ chunk->flags = 0;
+ chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
+
+ while (num_frames-- > 0)
{
- if(cpu_boosted)
+ memset(chunk->enc_data, 0, pcm_chunk_size);
+ encode_frame(chunk->enc_data, chunk);
+ }
+ }
+} /* on_rec_new_stream */
+
+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 if (event == ENC_REC_NEW_STREAM)
+ {
+ on_rec_new_stream((struct enc_buffer_event_data *)data);
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
+} /* enc_events_callback */
+
+static bool enc_init(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 ||
+ ci->enc_unget_pcm_data == NULL )
+ return false;
+
+ ci->enc_get_inputs(&inputs);
+
+ if (inputs.config->afmt != AFMT_MPA_L3)
+ return false;
+
+ init_mp3_encoder_engine(inputs.sample_rate, inputs.num_channels,
+ inputs.config);
+
+ /* configure the buffer system */
+ params.afmt = AFMT_MPA_L3;
+ params.chunk_size = cfg.byte_per_frame + 1;
+ params.enc_sample_rate = cfg.samplerate;
+ /* need enough reserved bytes to hold one frame of pcm samples + hdr
+ for padding and flushing */
+ params.reserve_bytes = ENC_CHUNK_HDR_SIZE + pcm_chunk_size;
+ params.events_callback = enc_events_callback;
+ ci->enc_set_parameters(&params);
+
+ res_buffer = params.reserve_buffer;
+
+#ifdef CPU_COLDFIRE
+ asm volatile ("move.l #0, %macsr"); /* integer mode */
+#endif
+
+ return true;
+} /* enc_init */
+
+enum codec_status codec_start(struct codec_api* api)
+{
+ bool cpu_boosted;
+
+ /* Generic codec initialisation */
+ ci = api;
+
+#ifdef USE_IRAM
+ memcpy(iramstart, iramcopy, iramend - iramstart);
+ memset(iedata, 0, iend - iedata);
+#endif
+
+ if (!enc_init())
+ {
+ ci->enc_codec_loaded = -1;
+ return CODEC_ERROR;
+ }
+
+ /* main application waits for this flag during encoder loading */
+ ci->enc_codec_loaded = 1;
+
+ ci->cpu_boost(true);
+ cpu_boosted = true;
+
+ /* main encoding loop */
+ while (!ci->stop_codec)
+ {
+ char *buffer;
+
+ while ((buffer = ci->enc_get_pcm_data(pcm_chunk_size)) != NULL)
+ {
+ struct enc_chunk_hdr *chunk;
+
+ if (ci->stop_codec)
+ break;
+
+ if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
+ {
+ ci->cpu_boost(true);
+ cpu_boosted = true;
+ }
+
+ chunk = ci->enc_get_chunk();
+ chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
+
+ encode_frame(buffer, chunk);
+
+ if (chunk->num_pcm < samp_per_frame)
+ {
+ ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4);
+ chunk->num_pcm = samp_per_frame;
+ }
+
+ ci->enc_finish_chunk();
+
+ ci->yield();
+ }
+
+ if (cpu_boosted && ci->enc_pcm_buf_near_empty())
{
ci->cpu_boost(false);
cpu_boosted = false;
}
- }
+
ci->yield();
}
@@ -2261,12 +2531,12 @@ enum codec_status codec_start(struct codec_api* api)
ci->cpu_boost(false);
/* 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 */
- ci->enc_codec_loaded = false;
+ ci->enc_codec_loaded = 0;
return CODEC_OK;
-}
+} /* codec_start */
-#endif
+#endif /* ndef SIMULATOR */
diff --git a/apps/codecs/wav_enc.c b/apps/codecs/wav_enc.c
index 5aabb5d8e8..974a903310 100644
--- a/apps/codecs/wav_enc.c
+++ b/apps/codecs/wav_enc.c
@@ -19,140 +19,364 @@
#ifndef SIMULATOR
+#include <inttypes.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 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 =
+{
+ /* "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 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};
+/* 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 */
-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};
+/* 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;
-/* 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)
+ if (data->chunk->enc_data == NULL)
+ {
+#ifdef ROCKBOX_HAS_LOGF
+ ci->logf("wav enc: NULL data");
+#endif
+ return true;
+ }
+
+ 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)
{
- int num_file_bytes = num_pcm_samples * 2 * enc_channels;
+ 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;
- if(is_file_header)
+ /* write template header */
+ if (ci->write(data->rec_file, &riff_header, sizeof (riff_header))
+ != sizeof (riff_header))
{
- /* update file header before file closing */
- if((int)sizeof(wav_header) < head_size)
+ 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)
{
- /* update wave header size entries: special to WAV format */
- *(long*)(head_buffer+ 4) = htole32(num_file_bytes + 36);
- *(long*)(head_buffer+40) = htole32(num_file_bytes);
+ 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;
-/* main codec entry point */
-enum codec_status codec_start(struct codec_api* api)
+ 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)
{
- int i;
- 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 */
+ struct enc_inputs inputs;
+ struct enc_parameters params;
- ci = api; // copy to global api pointer
+ 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;
- if(ci->enc_get_inputs == NULL ||
- ci->enc_set_parameters == NULL ||
- ci->enc_alloc_chunk == NULL ||
- ci->enc_free_chunk == NULL ||
- ci->enc_wavbuf_near_empty == NULL ||
- ci->enc_get_wav_data == NULL ||
- ci->enc_set_header_callback == NULL )
- return CODEC_ERROR;
+ ci->enc_get_inputs(&inputs);
- ci->cpu_boost(true);
+ if (inputs.config->afmt != AFMT_PCM_WAV)
+ return false;
- *ci->enc_set_header_callback = enc_set_header;
- ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality);
+ sample_rate = inputs.sample_rate;
+ num_channels = inputs.num_channels;
/* 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;
+ 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 */
+enum codec_status codec_start(struct codec_api* api)
+{
+ bool cpu_boosted;
- /* 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);
+ ci = api; // copy to global api pointer
+
+#ifdef USE_IRAM
+ ci->memcpy(iramstart, iramcopy, iramend - iramstart);
+ ci->memset(iedata, 0, iend - iedata);
+#endif
+
+ if (!init_encoder())
+ {
+ ci->enc_codec_loaded = -1;
+ return CODEC_ERROR;
+ }
/* 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 */
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;
- 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();
- *dst++ = CHUNK_SIZE * enc_channels / 2; /* set size info */
+ chunk = ci->enc_get_chunk();
+ 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)
- {
- /* 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);
- }
- }
+ chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
- ci->enc_free_chunk();
+ ci->enc_finish_chunk();
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();
@@ -162,11 +386,12 @@ enum codec_status codec_start(struct codec_api* api)
ci->cpu_boost(false);
/* 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 */
- ci->enc_codec_loaded = false;
+ ci->enc_codec_loaded = 0;
return CODEC_OK;
-}
-#endif
+} /* codec_start */
+
+#endif /* ndef SIMULATOR */
diff --git a/apps/codecs/wavpack_enc.c b/apps/codecs/wavpack_enc.c
index eced7f1f4e..5318abc8fb 100644
--- a/apps/codecs/wavpack_enc.c
+++ b/apps/codecs/wavpack_enc.c
@@ -22,201 +22,474 @@
#include "codeclib.h"
#include "libwavpack/wavpack.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
-typedef unsigned long uint32;
-typedef unsigned short uint16;
-typedef unsigned char uint8;
+/** Types **/
+typedef struct
+{
+ uint8_t type; /* Type of metadata */
+ uint8_t word_size; /* Size of metadata in words */
+} WavpackMetadataHeader;
-static unsigned char wav_header_ster [46] =
-{33,22,'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};
+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 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 const WavpackMetadataHeader wvpk_mdh =
+{
+ ID_RIFF_HEADER,
+ sizeof (struct riff_header) / sizeof (uint16_t),
+};
-static struct codec_api *ci;
-static int enc_channels;
+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;
-#define CHUNK_SIZE 20000
+ /* copy to IRAM before converting data */
+ memcpy(dst, src, PCM_CHUNK_SIZE);
-static long input_buffer[CHUNK_SIZE/2] IBSS_ATTR;
+ src = dst;
+ dst = (int32_t *)input_buffer;
-/* 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)
+ 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);
- char* wv_header = (char*)head_buffer + sizeof(wav_header_mono);
- int num_file_bytes = num_pcm_sampl * 2 * enc_channels;
- unsigned long ckSize;
-
- /* RIFF header and WVPK header have to be swapped */
- /* copy wavpack header to file start position */
- ci->memcpy(head_buffer, wv_header, sizeof(WavpackHeader));
- wv_header = head_buffer; /* recalc wavpack header position */
-
- if(enc_channels == 2)
- ci->memcpy(riff_header, wav_header_ster, sizeof(wav_header_ster));
- else
- ci->memcpy(riff_header, wav_header_mono, sizeof(wav_header_mono));
-
- /* update the Wavpack header first chunk size & total frame count */
- ckSize = htole32(((WavpackHeader*)wv_header)->ckSize)
- + sizeof(wav_header_mono);
- ((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);
+ int32_t t = *(*src)++;
+ /* endianness irrelevant */
+ *(*dst)++ = ((int16_t)t + (t >> 16)) >> 1;
+ } /* to_int32 */
+
+ do
+ {
+ /* read 10 longs and write 10 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;
}
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 */
+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 */
-enum codec_status codec_start(struct codec_api* api)
+/* 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)
{
- int i;
- long t;
- 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
+ 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);
- if(ci->enc_get_inputs == NULL ||
- ci->enc_set_parameters == NULL ||
- ci->enc_alloc_chunk == NULL ||
- ci->enc_free_chunk == NULL ||
- ci->enc_wavbuf_near_empty == NULL ||
- ci->enc_get_wav_data == NULL ||
- ci->enc_set_header_callback == NULL )
- return CODEC_ERROR;
+ 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 ||
+ ci->enc_unget_pcm_data == NULL )
+ return false;
- ci->cpu_boost(true);
+ ci->enc_get_inputs(&inputs);
+
+ if (inputs.config->afmt != AFMT_WAVPACK)
+ return false;
- *ci->enc_set_header_callback = enc_set_header;
- ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality);
+ memset(&config, 0, sizeof (config));
+ config.bits_per_sample = PCM_DEPTH_BITS;
+ config.bytes_per_sample = PCM_DEPTH_BYTES;
+ config.sample_rate = inputs.sample_rate;
+ config.num_channels = inputs.num_channels;
+
+ wpc = WavpackOpenFileOutput ();
+
+ if (!WavpackSetConfiguration(wpc, &config, -1))
+ return false;
/* 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;
+ 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;
- /* 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);
+ ci->enc_set_parameters(&params);
- wpc = WavpackOpenFileOutput ();
+ return true;
+} /* init_encoder */
+
+enum codec_status codec_start(struct codec_api* api)
+{
+ bool cpu_boosted;
+
+ ci = api; /* copy to global api pointer */
- memset (&config, 0, sizeof (config));
- config.bits_per_sample = 16;
- config.bytes_per_sample = 2;
- config.sample_rate = 44100;
- config.num_channels = enc_channels;
+#ifdef USE_IRAM
+ ci->memcpy(iramstart, iramcopy, iramend - iramstart);
+ ci->memset(iedata, 0, iend - iedata);
+#endif
- if (!WavpackSetConfiguration (wpc, &config, 1))
+ /* initialize params and config */
+ if (!init_encoder())
+ {
+ ci->enc_codec_loaded = -1;
return CODEC_ERROR;
+ }
/* 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 */
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)
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)
- {
- for (i=0; i<CHUNK_SIZE/4; i++)
- {
- t = (long)*src++;
+ dst = ENC_CHUNK_SKIP_HDR(dst, chunk);
- input_buffer[2*i + 0] = t >> 16;
- input_buffer[2*i + 1] = (short)t;
- }
- }
- else
+ 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++;
- t = (((t<<16)>>16) + (t>>16)) >> 1; /* left+right */
-
- input_buffer[i] = t;
+ chunk->num_pcm += PCM_SAMP_PER_CHUNK/4;
+ ci->yield();
+ /* could've been stopped in some way */
+ abort_chunk = ci->stop_codec ||
+ (chunk->flags & CHUNKF_ABORT);
}
- }
- if (!WavpackPackSamples (wpc, input_buffer, CHUNK_SIZE/4))
- return CODEC_ERROR;
+ src += input_step;
+ }
+ while (!abort_chunk && src < src_end);
+ if (!abort_chunk)
+ {
+ chunk->enc_data = dst;
+ if (chunk->num_pcm < PCM_SAMP_PER_CHUNK)
+ ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4);
/* finish the chunk and store chunk size info */
- dst[-1] = WavpackFinishBlock (wpc);
-
- ci->enc_free_chunk();
- ci->yield();
+ chunk->enc_size = WavpackFinishBlock(wpc);
+ ci->enc_finish_chunk();
+ }
}
- 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();
}
- if(cpu_boosted) /* set initial boost state */
+ if (cpu_boosted) /* set initial boost state */
ci->cpu_boost(false);
/* 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 */
- ci->enc_codec_loaded = false;
+ ci->enc_codec_loaded = 0;
return CODEC_OK;
-}
-#endif
+} /* codec_start */
+
+#endif /* ndef SIMULATOR */
diff --git a/apps/eq_menu.c b/apps/eq_menu.c
index 6c4dde4a78..9939ee77fe 100644
--- a/apps/eq_menu.c
+++ b/apps/eq_menu.c
@@ -710,7 +710,8 @@ static bool eq_save_preset(void)
char filename[MAX_PATH];
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 */
while (true) {
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index a8b8c5061b..ae8bba0538 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -124,19 +124,6 @@
#endif
#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \
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;
void gui_statusbar_init(struct gui_statusbar * bar)
@@ -600,41 +587,113 @@ void gui_statusbar_time(struct screen * display, int hour, int minute)
#endif
#ifdef HAVE_RECORDING
-void gui_statusbar_icon_recording_info(struct screen * display)
+#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)
{
-#if (CONFIG_CODEC != SWCODEC) || (defined(SIMULATOR) && defined(HAVE_SPDIF_IN))
- char buffer[3];
+ 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)
+{
#if CONFIG_CODEC != SWCODEC
+ char buffer[3];
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);
-#endif
+#endif /* CONFIG_CODEC != SWCODEC */
/* Display Codec info in statusbar */
#if CONFIG_CODEC == SWCODEC
- /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED
- so must use icons */
- display->mono_bitmap(bitmap_icons_18x8[global_settings.rec_quality],
- STATUSBAR_ENCODER_X_POS, STATUSBAR_Y_POS,
- STATUSBAR_ENCODER_WIDTH, STATUSBAR_HEIGHT);
-#else
-
+ gui_statusbar_write_format_info(display);
+#else /* !SWCODEC */
display->mono_bitmap(bitmap_icons_5x8[Icon_q],
STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS,
5, STATUSBAR_HEIGHT);
@@ -643,56 +702,37 @@ void gui_statusbar_icon_recording_info(struct screen * display)
display->getstringsize(buffer, &width, &height);
if (height <= STATUSBAR_HEIGHT)
display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer);
-#endif
+#endif /* CONFIG_CODEC == SWCODEC */
/* Display Samplerate info in statusbar */
-#if defined(HAVE_SPDIF_IN)
- if (global_settings.rec_source == SOURCE_SPDIF)
+#if CONFIG_CODEC == SWCODEC
+ /* 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 */
snprintf(buffer, sizeof(buffer), "--");
-#endif
}
else
#endif /* HAVE_SPDIF_IN */
{
- /* Analogue frequency in wrong order so remap settings numbers */
- int freq = global_settings.rec_frequency;
- if (freq == 0)
- freq = FREQ_44;
- 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);
+ static char const * const freq_strings[12] =
+ { "44", "48", "32", "22", "24", "16" };
+ snprintf(buffer, sizeof(buffer), "%s",
+ freq_strings[global_settings.rec_frequency]);
}
- if (height <= STATUSBAR_HEIGHT)
- display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer);
+ display->getstringsize(buffer, &width, &height);
+
+ 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 */
if(global_settings.rec_channels)
{
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 40d7bb7b19..8f7deb78a9 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -9802,7 +9802,7 @@
</phrase>
<phrase>
id: VOICE_KBIT_PER_SEC
- desc: spoken only, for file extension
+ desc: spoken only, a unit postfix
user:
<source>
*: ""
@@ -10032,3 +10032,115 @@
*: ""
</voice>
</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>
diff --git a/apps/main.c b/apps/main.c
index c4ee45cb89..05b4ab54a3 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -286,6 +286,9 @@ void init(void)
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
set_cpu_frequency(CPUFREQ_NORMAL);
+#ifdef CPU_COLDFIRE
+ coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
+#endif
cpu_boost_id(true, CPUBOOSTID_MAININIT);
#endif
diff --git a/apps/metadata.c b/apps/metadata.c
index ee0100ecf7..845536877c 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -88,36 +88,6 @@ struct apetag_item_header
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
static const unsigned short a52_bitrates[] =
{
@@ -1691,14 +1661,24 @@ unsigned int probe_file_format(const char *filename)
return AFMT_UNKNOWN;
}
- suffix += 1;
+ /* skip '.' */
+ suffix++;
+
+ for (i = 1; i < AFMT_NUM_CODECS; i++)
+ {
+ /* search extension list for type */
+ const char *ext = audio_formats[i].ext_list;
- for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++)
+ do
{
- if (strcasecmp(suffix, formats[i].extension) == 0)
+ if (strcasecmp(suffix, ext) == 0)
{
- return formats[i].format;
+ return i;
+ }
+
+ ext += strlen(ext) + 1;
}
+ while (*ext != '\0');
}
return AFMT_UNKNOWN;
diff --git a/apps/misc.c b/apps/misc.c
index c36d61914b..01463851be 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -58,6 +58,8 @@
#endif /* End HAVE_LCD_BITMAP */
#include "gui/gwps-common.h"
+#include "misc.h"
+
/* 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"
* 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
- 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,. */
+ * 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. */
char *create_numbered_filename(char *buffer, const char *path,
const char *prefix, const char *suffix,
- int numberlen)
+ int numberlen IF_CNFN_NUM_(, int *num))
{
DIR *dir;
struct dirent *entry;
- int max_num = 0;
+ int max_num;
int pathlen;
int prefixlen = strlen(prefix);
char fmtstring[12];
@@ -133,6 +139,18 @@ char *create_numbered_filename(char *buffer, const char *path,
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 : "/");
if (!dir)
return NULL;
@@ -149,11 +167,20 @@ char *create_numbered_filename(char *buffer, const char *path,
if (curr_num > max_num)
max_num = curr_num;
}
+
closedir(dir);
+ }
+
+ max_num++;
snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen);
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;
}
@@ -161,13 +188,22 @@ char *create_numbered_filename(char *buffer, const char *path,
#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. */
+ 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,
- const char *prefix, const char *suffix)
+ const char *prefix, const char *suffix,
+ bool unique_time)
{
struct tm *tm = get_time();
+ static struct tm last_tm;
int pathlen;
+ while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm)))
+ sleep(HZ/10);
+
+ last_tm = *tm;
+
if (buffer != path)
strncpy(buffer, path, MAX_PATH);
@@ -356,9 +392,10 @@ void screen_dump(void)
#endif
#ifdef CONFIG_RTC
- create_datetime_filename(filename, "", "dump ", ".bmp");
+ create_datetime_filename(filename, "", "dump ", ".bmp", false);
#else
- create_numbered_filename(filename, "", "dump_", ".bmp", 4);
+ create_numbered_filename(filename, "", "dump_", ".bmp", 4
+ IF_CNFN_NUM_(, NULL));
#endif
fh = creat(filename, O_WRONLY);
diff --git a/apps/misc.h b/apps/misc.h
index 1bc9a23447..6c660e0a5e 100644
--- a/apps/misc.h
+++ b/apps/misc.h
@@ -19,21 +19,46 @@
#ifndef MISC_H
#define MISC_H
+#include <stdbool.h>
+
/* 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"
* 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
* 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);
+/* 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,
const char *prefix, const char *suffix,
- int numberlen);
+ int numberlen IF_CNFN_NUM_(, int *num));
#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,
- const char *prefix, const char *suffix);
-#endif
+ const char *prefix, const char *suffix,
+ bool unique_time);
+#endif /* CONFIG_RTC */
/* 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
@@ -57,4 +82,4 @@ long default_event_handler(long event);
void car_adapter_mode_init(void);
extern int show_logo(void);
-#endif
+#endif /* MISC_H */
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 44f175c67d..5119d20ebd 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -51,9 +51,11 @@ struct pcmbufdesc
void (*callback)(void);
};
+#define PCMBUF_DESCS(bufsize) ((bufsize) / PCMBUF_MINAVG_CHUNK)
+
/* Size of the PCM buffer. */
static size_t pcmbuf_size IDATA_ATTR = 0;
-
+static char *pcmbuf_bufend IDATA_ATTR;
static char *audiobuffer IDATA_ATTR;
/* Current audio buffer write index. */
static size_t audiobuffer_pos IDATA_ATTR;
@@ -360,7 +362,7 @@ int pcmbuf_used_descs(void) {
}
int pcmbuf_descs(void) {
- return pcmbuf_size / PCMBUF_MINAVG_CHUNK;
+ return PCMBUF_DESCS(pcmbuf_size);
}
size_t get_pcmbuf_descsize(void) {
@@ -371,28 +373,37 @@ static void pcmbuf_init_pcmbuffers(void) {
struct pcmbufdesc *next = pcmbuf_write;
next++;
pcmbuf_write_end = pcmbuf_write;
- while ((void *)next < (void *)audiobufend) {
+ while ((void *)next < (void *)pcmbuf_bufend) {
pcmbuf_write_end->link=next;
pcmbuf_write_end=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:
- * ...CODECBUFFER|---------PCMBUF---------|GUARDBUF|DESCS| */
-void pcmbuf_init(size_t bufsize)
+ * ...|---------PCMBUF---------|FADEBUF|VOICEBUF|DESCS|... */
+size_t pcmbuf_init(size_t bufsize, char *bufend)
{
pcmbuf_size = bufsize;
+ pcmbuf_bufend = bufend;
pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc);
- audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) -
- (pcmbuf_size + PCMBUF_MIX_CHUNK * 2 + pcmbuf_descsize)];
+ audiobuffer = pcmbuf_bufend - (pcmbuf_size + PCMBUF_MIX_CHUNK * 2
+ + pcmbuf_descsize);
fadebuf = &audiobuffer[pcmbuf_size];
voicebuf = &fadebuf[PCMBUF_MIX_CHUNK];
- pcmbuf_write = (struct pcmbufdesc *)(&voicebuf[PCMBUF_MIX_CHUNK]);
+ pcmbuf_write = (struct pcmbufdesc *)&voicebuf[PCMBUF_MIX_CHUNK];
pcmbuf_init_pcmbuffers();
position_callback = NULL;
pcmbuf_event_handler = NULL;
pcmbuf_play_stop();
+ return pcmbuf_bufend - audiobuffer;
}
size_t pcmbuf_get_bufsize(void)
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index b5035f4405..a408cdae42 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -38,7 +38,7 @@
/* Returns true if the buffer needs to change size */
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_t pcmbuf_get_bufsize(void);
size_t get_pcmbuf_descsize(void);
diff --git a/apps/playback.c b/apps/playback.c
index f8372665a4..af6b573f1d 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -54,8 +54,6 @@
#include "playlist.h"
#include "playback.h"
#include "pcmbuf.h"
-#include "pcm_playback.h"
-#include "pcm_record.h"
#include "buffer.h"
#include "dsp.h"
#include "abrepeat.h"
@@ -78,6 +76,7 @@
#ifdef HAVE_RECORDING
#include "recording.h"
+#include "talk.h"
#endif
#define PLAYBACK_VOICE
@@ -93,9 +92,13 @@
* for their correct seeek target, 32k seems a good size */
#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
-#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
#ifdef PLAYBACK_LOGQUEUES
@@ -104,6 +107,18 @@
#define LOGFQUEUE(s)
#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 {
Q_AUDIO_PLAY = 1,
Q_AUDIO_STOP,
@@ -122,6 +137,9 @@ enum {
#if MEM > 8
Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
#endif
+#ifdef AUDIO_HAVE_RECORDING
+ Q_AUDIO_LOAD_ENCODER,
+#endif
Q_CODEC_REQUEST_PENDING,
Q_CODEC_REQUEST_COMPLETE,
@@ -133,7 +151,7 @@ enum {
Q_CODEC_LOAD,
Q_CODEC_LOAD_DISK,
-#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
+#ifdef AUDIO_HAVE_RECORDING
Q_ENCODER_LOAD_DISK,
Q_ENCODER_RECORD,
#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-) */
/* 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-)*/
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-) */
+#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_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)
@@ -235,7 +258,7 @@ static const char audio_thread_name[] = "audio";
static void audio_thread(void);
static void audio_initiate_track_change(long direction);
static bool audio_have_tracks(void);
-static void audio_reset_buffer(void);
+static void audio_reset_buffer(size_t pcmbufsize);
/* Codec thread */
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 (*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
static struct voice_info voice_clip;
voice_clip.callback = get_more;
@@ -330,38 +357,95 @@ void mpeg_id3_options(bool _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)
- const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER);
+ unsigned char *buf = audiobuf;
+ 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)
- return;
+ return false;
audio_remove_encoder();
+ ci.enc_codec_loaded = 0; /* clear any previous error condition */
- LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
- queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn);
+ LOGFQUEUE("audio > Q_AUDIO_LOAD_ENCODER");
+ queue_post(&audio_queue, Q_AUDIO_LOAD_ENCODER, (void *)enc_fn);
- while (!ci.enc_codec_loaded)
+ while (ci.enc_codec_loaded == 0)
yield();
+
+ logf("codec loaded: %d", ci.enc_codec_loaded);
+
+ return ci.enc_codec_loaded > 0;
+#else
+ (void)afmt;
+ return true;
#endif
- return;
- (void)enc_id;
} /* audio_load_encoder */
void audio_remove_encoder(void)
{
-#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
- /* force encoder codec unload (if previously loaded) */
- if (!ci.enc_codec_loaded)
+#ifndef SIMULATOR
+ /* force encoder codec unload (if currently loaded) */
+ if (ci.enc_codec_loaded <= 0)
return;
ci.stop_codec = true;
- while (ci.enc_codec_loaded)
+ while (ci.enc_codec_loaded > 0)
yield();
#endif
} /* audio_remove_encoder */
+#endif /* HAVE_RECORDING */
+
struct mp3entry* audio_current_track(void)
{
const char *filename;
@@ -553,6 +637,9 @@ void audio_flush_and_reload_tracks(void)
void audio_error_clear(void)
{
+#ifdef AUDIO_HAVE_RECORDING
+ pcm_rec_error_clear();
+#endif
}
int audio_status(void)
@@ -573,11 +660,6 @@ int audio_status(void)
return ret;
}
-bool audio_query_poweroff(void)
-{
- return !(playing && paused);
-}
-
int audio_get_file_pos(void)
{
return 0;
@@ -617,7 +699,7 @@ void audio_set_crossfade(int enable)
enable = 0;
size = NATIVE_FREQUENCY*2;
#endif
- if (pcmbuf_get_bufsize() == size)
+ if (buffer_state == BUFFER_STATE_NORMAL && pcmbuf_is_same_size(size))
return ;
if (was_playing)
@@ -633,9 +715,8 @@ void audio_set_crossfade(int enable)
voice_stop();
/* Re-initialize audio system. */
- pcmbuf_init(size);
+ audio_reset_buffer(size);
pcmbuf_crossfade_enable(enable);
- audio_reset_buffer();
logf("abuf:%dB", pcmbuf_get_bufsize());
logf("fbuf:%dB", filebuflen);
@@ -714,8 +795,7 @@ void voice_stop(void)
{
#ifdef PLAYBACK_VOICE
/* Messages should not be posted to voice codec queue unless it is the
- current codec or deadlocks happen.
- -- jhMikeS */
+ current codec or deadlocks happen. */
if (current_codec != CODEC_IDX_VOICE)
return;
@@ -784,21 +864,32 @@ static void set_filebuf_watermark(int seconds)
conf_watermark = bytes;
}
-static const char * get_codec_filename(int enc_spec)
+static const char * get_codec_filename(int cod_spec)
{
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)
type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
- fname = (type == CODEC_TYPE_DECODER) ?
- audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn;
+ fname = (type == CODEC_TYPE_ENCODER) ?
+ audio_formats[afmt].codec_enc_root_fn :
+ audio_formats[afmt].codec_root_fn;
logf("%s: %d - %s",
(type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
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;
} /* get_codec_filename */
@@ -940,7 +1031,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
}
break;
-#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
+#ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_RECORD:
LOGFQUEUE("voice < Q_ENCODER_RECORD");
swap_codec();
@@ -995,7 +1086,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
goto voice_play_clip;
case SYS_TIMEOUT:
- LOGFQUEUE("voice < SYS_TIMEOUT");
+ LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
goto voice_play_clip;
default:
@@ -1773,7 +1864,7 @@ static void codec_thread(void)
#endif
break ;
-#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
+#ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_LOAD_DISK:
LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
audio_codec_loaded = false; /* Not audio codec! */
@@ -1785,12 +1876,14 @@ static void codec_thread(void)
}
#endif
mutex_lock(&mutex_codecthread);
+ logf("loading encoder");
current_codec = CODEC_IDX_AUDIO;
ci.stop_codec = false;
status = codec_load_file((const char *)ev.data, &ci);
mutex_unlock(&mutex_codecthread);
+ logf("encoder stopped");
break;
-#endif
+#endif /* AUDIO_HAVE_RECORDING */
#ifndef SIMULATOR
case SYS_USB_CONNECTED:
@@ -1872,6 +1965,24 @@ static void codec_thread(void)
}
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:
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? */
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;
playlist_end = false;
@@ -3084,51 +3199,60 @@ static void audio_initiate_dir_change(long 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;
- /* Set up file buffer as all space available */
- filebuf = (char *)&audiobuf[talk_get_bufsize()+MALLOC_BUFSIZE];
- filebuflen = audiobufend - (unsigned char *) filebuf - GUARD_BUFSIZE -
- (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_MIX_CHUNK * 2);
+ logf("audio_reset_buffer");
+ logf(" size:%08X", pcmbufsize);
+
+ /* 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 file buffer */
+ /* Allow for codec(s) at end of audio buffer */
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);
-#ifdef PLAYBACK_VOICE
- iram_buf[0] = &filebuf[filebuflen];
- iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
- dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2];
- dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
+ iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
+ dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
+ iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
+ dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE;
#endif
}
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;
-#ifdef PLAYBACK_VOICE
- iram_buf[0] = &filebuf[filebuflen];
- iram_buf[1] = NULL;
- dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE];
- dram_buf[1] = NULL;
+ iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
+ dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
+ iram_buf[CODEC_IDX_VOICE] = NULL;
+ dram_buf[CODEC_IDX_VOICE] = NULL;
#endif
}
+ filebuflen -= pcmbuf_init(pcmbufsize, filebuf + filebuflen) + GUARD_BUFSIZE;
+
/* Ensure that file buffer is aligned */
- offset = (-(size_t)filebuf) & 3;
+ offset = -(size_t)filebuf & 3;
filebuf += offset;
filebuflen -= offset;
filebuflen &= ~3;
/* Clear any references to the file buffer */
+ buffer_state = BUFFER_STATE_NORMAL;
}
-
#ifdef ROCKBOX_HAS_LOGF
static void audio_test_track_changed_event(struct mp3entry *id3)
{
@@ -3149,9 +3273,8 @@ static void audio_playback_init(void)
logf("playback api init");
pcm_init();
-#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
- /* Set the input multiplexer to Line In */
- pcm_rec_mux(0);
+#ifdef AUDIO_HAVE_RECORDING
+ rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
#endif
#ifdef ROCKBOX_HAS_LOGF
@@ -3219,8 +3342,9 @@ static void audio_playback_init(void)
#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_is_initialized = true;
@@ -3358,6 +3482,14 @@ static void audio_thread(void)
playlist_update_resume_info(audio_current_track());
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
case SYS_USB_CONNECTED:
LOGFQUEUE("audio < SYS_USB_CONNECTED");
@@ -3368,7 +3500,7 @@ static void audio_thread(void)
#endif
case SYS_TIMEOUT:
- LOGFQUEUE("audio < SYS_TIMEOUT");
+ LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
break;
default:
diff --git a/apps/playlist.c b/apps/playlist.c
index 5a5313b736..134b52ea8b 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -155,7 +155,7 @@ static int recreate_control(struct playlist_info* playlist);
static void update_playlist_filename(struct playlist_info* playlist,
const char *dir, const char *file);
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,
const char *filename, int position,
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
*/
static int add_indices_to_playlist(struct playlist_info* playlist,
- char* buffer, int buflen)
+ char* buffer, size_t buflen)
{
unsigned int nread;
unsigned int i = 0;
@@ -489,8 +489,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf;
#else
- buflen = (audiobufend - audiobuf - talk_get_bufsize());
- buffer = (char *)&audiobuf[talk_get_bufsize()];
+ buffer = (char *)audio_get_buffer(false, &buflen);
#endif
}
@@ -1853,7 +1852,7 @@ int playlist_resume(void)
{
struct playlist_info* playlist = &current_playlist;
char *buffer;
- int buflen;
+ size_t buflen;
int nread;
int total_read = 0;
int control_file_size = 0;
@@ -1866,8 +1865,7 @@ int playlist_resume(void)
buflen = (audiobufend - audiobuf);
buffer = (char *)audiobuf;
#else
- buflen = (audiobufend - audiobuf - talk_get_bufsize());
- buffer = (char *)&audiobuf[talk_get_bufsize()];
+ buffer = (char *)audio_get_buffer(false, &buflen);
#endif
empty_playlist(playlist, true);
diff --git a/apps/plugin.c b/apps/plugin.c
index 25f1865c9e..3a893fc537 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -674,12 +674,18 @@ void* plugin_get_buffer(int* buffer_size)
}
/* 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)
{
+#if CONFIG_CODEC == SWCODEC
+ return audio_get_buffer(true, (size_t *)buffer_size);
+#else
audio_stop();
talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
*buffer_size = audiobufend - audiobuf;
+#endif
return audiobuf;
}
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index 46d628e780..ba22bb5a2c 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -30,12 +30,17 @@
const unsigned char bitmap_icons_5x8[][5] =
{
- [Icon_Lock_Main] ={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Main */
- [Icon_Lock_Remote]={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Remote */
- [Icon_Stereo]={0x7f, 0x1c, 0x00, 0x1c, 0x7f}, /* Stereo recording */
- [Icon_Mono]={0x00, 0x1c, 0x7f, 0x00, 0x00}, /* Mono recording */
+ [Icon_Lock_Main] =
+ {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Main */
+ [Icon_Lock_Remote] =
+ {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
- [Icon_q]={0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */
+ [Icon_q] =
+ {0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */
#endif
};
@@ -81,45 +86,52 @@ const unsigned char bitmap_icons_7x8[][7] =
{0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */
};
-#if CONFIG_CODEC == SWCODEC
-const unsigned char bitmap_icons_18x8[][18] =
+#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
+const unsigned char bitmap_glyphs_4x8[][4] =
{
- {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3e, 0x2a,
- 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 64kbps */
- {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x0e, 0x0a,
- 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00}, /* mp3 96kbps */
- {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a,
- 0x2e, 0x00, 0x3e, 0x2a, 0x3e, 0x00}, /* mp3 128kbps */
- {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a,
- 0x3a, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 160kbps */
- {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x0e, 0x0a,
- 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00}, /* mp3 192kbps */
- {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a,
- 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 224kbps */
- {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a,
- 0x2e, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 320kbps */
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x1e, 0x20, 0x18, 0x20, 0x1e,
- 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00}, /* wv */
- {0x00, 0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x12, 0x12, 0x3c,
- 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00} /* wav */
+ /* Keep digits together and first! */
+ [0] =
+ {0x00, 0x3e, 0x22, 0x3e}, /* 0 */
+ [1] =
+ {0x00, 0x24, 0x3e, 0x20}, /* 1 */
+ [2] =
+ {0x00, 0x3a, 0x2a, 0x2e}, /* 2 */
+ [3] =
+ {0x00, 0x22, 0x2a, 0x36}, /* 3 */
+ [4] =
+ {0x00, 0x0e, 0x08, 0x3e}, /* 4 */
+ [5] =
+ {0x00, 0x2e, 0x2a, 0x3a}, /* 5 */
+ [6] =
+ {0x00, 0x3e, 0x2a, 0x3a}, /* 6 */
+ [7] =
+ {0x00, 0x02, 0x02, 0x3e}, /* 7 */
+ [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 */
- {0x00, 0x24, 0x3e, 0x20, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x10, 0x28}, /* 11khz */
- {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 12khz */
- {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28}, /* 16khz */
- {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 22khz */
- {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 24khz */
- {0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 32khz */
- {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 44.1khz */
- {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 48khz */
- {0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 64khz */
- {0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 88.2khz */
- {0x00, 0x0e, 0x0a, 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28} /* 96khz */
+ [0 ... Format_18x8Last-1] = /* auto-blank */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ___ */
+ [Format_18x8_MPA_L3] =
+ {0x00, 0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* M__ */
+ [Format_18x8_WAVPACK] =
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20,
+ 0x18, 0x20, 0x1e, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* _WV */
+ [Format_18x8_PCM_WAV] =
+ {0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x0a,
+ 0x0a, 0x0a, 0x3c, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* WAV */
};
-#endif
+#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
/* Disk/MMC activity */
const unsigned char bitmap_icon_disk[12] =
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 75401f6f0b..1e7b8dba1e 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -89,44 +89,40 @@ enum icons_7x8 {
Icon7x8Last
};
-#if CONFIG_CODEC == SWCODEC
-enum icons_12x8 {
- Icon_8000,
- Icon_11025,
- Icon_12000,
- Icon_16000,
- Icon_22050,
- Icon_24000,
- Icon_32000,
- Icon_44100,
- Icon_48000,
- Icon_64000,
- Icon_88200,
- Icon_96000,
- Icon12x8Last
+#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
+#define BM_GLYPH_WIDTH 4
+enum Glyphs_4x8 {
+ Glyph_4x8_0 = 0,
+ Glyph_4x8_1,
+ Glyph_4x8_2,
+ Glyph_4x8_3,
+ Glyph_4x8_4,
+ Glyph_4x8_5,
+ Glyph_4x8_6,
+ Glyph_4x8_7,
+ Glyph_4x8_8,
+ Glyph_4x8_9,
+ Glyph_4x8_k,
+ Glyph_4x8Last
};
-
-enum icons_18x8 {
- Icon_mp364,
- Icon_mp396,
- Icon_mp3128,
- Icon_mp3160,
- Icon_mp3192,
- Icon_mp3224,
- Icon_mp3320,
- Icon_wv,
- Icon_wav,
- Icon18x8Last
+extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4];
+
+#define BM_MPA_L3_M_WIDTH 6
+#ifdef ID3_H
+/* This enum is redundant but sort of in keeping with the style */
+enum rec_format_18x8 {
+ Format_18x8_MPA_L3 = REC_FORMAT_MPA_L3,
+ Format_18x8_WAVPACK = REC_FORMAT_WAVPACK,
+ Format_18x8_PCM_WAV = REC_FORMAT_PCM_WAV,
+ Format_18x8Last = REC_NUM_FORMATS
};
-#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_6x8[Icon6x8Last][6];
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[];
#define STATUSBAR_X_POS 0
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index 0370f4deea..44be43124a 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -540,10 +540,8 @@ void peak_meter_peek(void)
if (pm_playback)
pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
#ifdef HAVE_RECORDING
- if (!pm_playback)
- {
- pcm_rec_get_peaks(&pm_cur_left, &pm_cur_right);
- }
+ else
+ pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
#endif
left = pm_cur_left;
right = pm_cur_right;
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index d74437a8c9..7a0cc6543e 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -386,6 +386,7 @@ bool radio_screen(void)
unsigned int last_seconds = 0;
#if CONFIG_CODEC != SWCODEC
int hours, minutes;
+ struct audio_recording_options rec_options;
#endif
bool keep_playing = false;
bool statusbar = global_settings.statusbar;
@@ -436,12 +437,9 @@ bool radio_screen(void)
peak_meter_enabled = true;
- rec_set_recording_options(global_settings.rec_frequency,
- global_settings.rec_quality,
- AUDIO_SRC_LINEIN, 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ rec_init_recording_options(&rec_options);
+ rec_options.rec_source = AUDIO_SRC_LINEIN;
+ rec_set_recording_options(&rec_options);
audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
@@ -881,7 +879,7 @@ bool radio_screen(void)
}
else
{
- if(global_settings.rec_prerecord_time)
+ if(rec_options.rec_prerecord_time)
{
snprintf(buf, 32, "%s %02d",
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 */
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)
{
@@ -1534,12 +1533,10 @@ static bool fm_recording_settings(void)
#if CONFIG_CODEC != SWCODEC
if (!ret)
{
- rec_set_recording_options(global_settings.rec_frequency,
- global_settings.rec_quality,
- AUDIO_SRC_LINEIN, 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ struct audio_recording_options rec_options;
+ rec_init_recording_options(&rec_options);
+ rec_options.rec_source = AUDIO_SRC_LINEIN;
+ rec_set_recording_options(&rec_options);
}
#endif
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 0a21d96566..6a053cd12e 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -30,8 +30,10 @@
#include "mpeg.h"
#include "audio.h"
#if CONFIG_CODEC == SWCODEC
-#include "pcm_record.h"
+#include "thread.h"
+#include "pcm_playback.h"
#include "playback.h"
+#include "enc_config.h"
#endif
#ifdef HAVE_UDA1380
#include "uda1380.h"
@@ -73,36 +75,40 @@
#define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1)
+#if CONFIG_KEYPAD == RECORDER_PAD
bool f2_rec_screen(void);
bool f3_rec_screen(void);
+#endif
#define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */
int screen_update = NB_SCREENS;
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
-#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
+
+#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_QUALITY_LABEL(q) "MP3"
-#define REC_FILE_ENDING(q) ".mp3"
-#endif
+#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
/* Timing counters:
* 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 ext[16];
+
if(global_settings.rec_directory)
getcwd(buffer, MAX_PATH);
else
strncpy(buffer, rec_base_directory, MAX_PATH);
+ snprintf(ext, sizeof(ext), ".%s",
+ REC_FILE_ENDING(global_settings.rec_format));
#ifdef CONFIG_RTC
- create_datetime_filename(buffer, buffer, "R",
- REC_FILE_ENDING(global_settings.rec_quality));
+ /* We'll wait at least up to the start of the next second so no duplicate
+ names are created */
+ return create_datetime_filename(buffer, buffer, "R", ext, true);
#else
- create_numbered_filename(buffer, buffer, "rec_",
- REC_FILE_ENDING(global_settings.rec_quality), 4);
+ return create_numbered_filename(buffer, buffer, "rec_", ext, 4
+ IF_CNFN_NUM_(, &file_number));
#endif
- return buffer;
}
int rec_create_directory(void)
@@ -557,9 +567,15 @@ static void rec_boost(bool state)
/**
* 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.
* 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)
#define ac_disable_recording uda1380_disable_recording
@@ -571,7 +587,13 @@ static void rec_boost(bool state)
#define ac_set_monitor tlv320_set_monitor
#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 */
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) **/
+ /** SPDIF **/
#ifdef HAVE_SPDIF_IN
+ /* Always boost for SPDIF */
if ((source == AUDIO_SRC_SPDIF) != (source == last_source))
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
the case on H1x0. */
spdif_power_enable((source == AUDIO_SRC_SPDIF) ||
- global_settings.spdif_enable);
+ audio_get_spdif_power_setting());
#endif
#endif
+ /** Tuner **/
#ifdef CONFIG_TUNER
/* Switch radio off or on per source and flags. */
if (source != AUDIO_SRC_FMRADIO)
@@ -612,12 +637,15 @@ void rec_set_source(int source, int flags)
switch (source)
{
default: /* playback - no recording */
+ source = AUDIO_SRC_PLAYBACK;
+ case AUDIO_SRC_PLAYBACK:
pm_playback = true;
if (source == last_source)
break;
ac_disable_recording();
ac_set_monitor(false);
pcm_rec_mux(0); /* line in */
+ rec_spdif_set_monitor(-1); /* silence it */
break;
case AUDIO_SRC_MIC: /* recording only */
@@ -625,6 +653,7 @@ void rec_set_source(int source, int flags)
break;
ac_enable_recording(true); /* source mic */
pcm_rec_mux(0); /* line in */
+ rec_spdif_set_monitor(0);
break;
case AUDIO_SRC_LINEIN: /* recording only */
@@ -632,29 +661,20 @@ void rec_set_source(int source, int flags)
break;
pcm_rec_mux(0); /* line in */
ac_enable_recording(false); /* source line */
+ rec_spdif_set_monitor(0);
break;
#ifdef HAVE_SPDIF_IN
case AUDIO_SRC_SPDIF: /* recording only */
- if (recording)
- {
- /* This was originally done in audio_set_recording_options only */
-#ifdef HAVE_SPDIF_POWER
- 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();
+ if (source == last_source)
+ break;
+ ac_disable_recording();
+ audio_spdif_set_monitor(1);
break;
#endif /* HAVE_SPDIF_IN */
#ifdef HAVE_FMRADIO_IN
- case AUDIO_SRC_FMRADIO:
+ case AUDIO_SRC_FMRADIO: /* recording and playback */
if (!recording)
{
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 */
}
#endif
+
+ rec_spdif_set_monitor(0);
break;
/* #elif defined(CONFIG_TUNER) */
/* Have radio but cannot record it */
@@ -702,33 +724,50 @@ void rec_set_source(int source, int flags)
} /* rec_set_source */
#endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */
-/* steal the mp3 buffer then actually set options */
-void rec_set_recording_options(int frequency, int quality,
- int source, int source_flags,
- int channel_mode, bool editable,
- int prerecord_time)
+void rec_init_recording_options(struct audio_recording_options *options)
+{
+ options->rec_source = global_settings.rec_source;
+ options->rec_frequency = global_settings.rec_frequency;
+ 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 (global_settings.rec_prerecord_time)
-#endif
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
- rec_set_source(source, source_flags | SRCF_RECORDING);
-#else
- (void)source_flags;
+ rec_set_source(options->rec_source,
+ options->rec_source_flags | SRCF_RECORDING);
#endif
- audio_set_recording_options(frequency, quality, source,
- channel_mode, editable, prerecord_time);
+ audio_set_recording_options(options);
}
-static char path_buffer[MAX_PATH];
-
/* steals mp3 buffer, creates unique filename and starts recording */
void rec_record(void)
{
+#if CONFIG_CODEC != SWCODEC
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));
}
@@ -753,7 +792,6 @@ static void trigger_listener(int trigger_status)
case TRIG_GO:
if((audio_status() & AUDIO_STATUS_RECORD) != AUDIO_STATUS_RECORD)
{
- talk_buffer_steal(); /* we use the mp3 buffer */
rec_record();
/* give control to mpeg thread so that it can start
recording */
@@ -831,6 +869,8 @@ bool recording_screen(bool no_source)
ID2P(LANG_GIGABYTE)
};
+ struct audio_recording_options rec_options;
+
global_settings.recscreen_on = true;
cursor = 0;
#if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR)
@@ -838,35 +878,26 @@ bool recording_screen(bool no_source)
#endif
#if CONFIG_CODEC == SWCODEC
- audio_stop();
- voice_stop();
/* recording_menu gets messed up: so reset talk_menu */
talk_menu = global_settings.talk_menu;
global_settings.talk_menu = 0;
+ /* audio_init_recording stops anything playing when it takes the audio
+ buffer */
#else
/* Yes, we use the D/A for monitoring */
peak_meter_enabled = true;
peak_meter_playback(true);
#endif
-#if CONFIG_CODEC == SWCODEC
- audio_init_recording(talk_get_bufsize());
-#else
audio_init_recording(0);
-#endif
sound_set_volume(global_settings.volume);
#ifdef HAVE_AGC
peak_meter_get_peakhold(&peak_l, &peak_r);
#endif
- rec_set_recording_options(global_settings.rec_frequency,
- global_settings.rec_quality,
- global_settings.rec_source,
- 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ rec_init_recording_options(&rec_options);
+ rec_set_recording_options(&rec_options);
set_gain();
settings_apply_trigger();
@@ -1025,7 +1056,6 @@ bool recording_screen(bool no_source)
{
/* manual recording */
have_recorded = true;
- talk_buffer_steal(); /* we use the mp3 buffer */
rec_record();
last_seconds = 0;
if (talk_menu)
@@ -1253,16 +1283,10 @@ bool recording_screen(bool no_source)
#if CONFIG_CODEC == SWCODEC
/* reinit after submenu exit */
audio_close_recording();
- audio_init_recording(talk_get_bufsize());
+ audio_init_recording(0);
#endif
- rec_set_recording_options(
- global_settings.rec_frequency,
- global_settings.rec_quality,
- global_settings.rec_source,
- 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ rec_init_recording_options(&rec_options);
+ rec_set_recording_options(&rec_options);
if(rec_create_directory() > 0)
have_recorded = true;
@@ -1739,11 +1763,7 @@ bool recording_screen(bool no_source)
}
} /* end while(!done) */
-#if CONFIG_CODEC == SWCODEC
- audio_stat = pcm_rec_status();
-#else
audio_stat = audio_status();
-#endif
if (audio_stat & AUDIO_STATUS_ERROR)
{
gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL));
@@ -1804,11 +1824,22 @@ bool recording_screen(bool no_source)
#if CONFIG_KEYPAD == RECORDER_PAD
bool f2_rec_screen(void)
{
+ static const char* const freq_str[6] =
+ {
+ "44.1kHz",
+ "48kHz",
+ "32kHz",
+ "22.05kHz",
+ "24kHz",
+ "16kHz"
+ };
+
bool exit = false;
bool used = false;
int w, h, i;
char buf[32];
int button;
+ struct audio_recording_options rec_options;
FOR_NB_SCREENS(i)
{
@@ -1919,13 +1950,8 @@ bool f2_rec_screen(void)
}
}
- rec_set_recording_options(global_settings.rec_frequency,
- global_settings.rec_quality,
- global_settings.rec_source,
- 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ rec_init_recording_options(&rec_options);
+ rec_set_recording_options(&rec_options);
set_gain();
@@ -1948,6 +1974,8 @@ bool f3_rec_screen(void)
str(LANG_SYSFONT_RECORDING_SRC_LINE),
str(LANG_SYSFONT_RECORDING_SRC_DIGITAL)
};
+ struct audio_recording_options rec_options;
+
FOR_NB_SCREENS(i)
{
screens[i].setfont(FONT_SYSFIXED);
@@ -2019,13 +2047,8 @@ bool f3_rec_screen(void)
}
}
- rec_set_recording_options(global_settings.rec_frequency,
- global_settings.rec_quality,
- global_settings.rec_source,
- 0,
- global_settings.rec_channels,
- global_settings.rec_editable,
- global_settings.rec_prerecord_time);
+ rec_init_recording_options(&rec_options);
+ rec_set_recording_options(&rec_options);
set_gain();
@@ -2066,23 +2089,30 @@ unsigned long audio_num_recorded_bytes(void)
}
#if CONFIG_CODEC == SWCODEC
-void rec_set_source(int source, int flags)
+void rec_set_source(int source, unsigned flags)
{
source = source;
flags = flags;
}
-#endif
-void audio_set_recording_options(int frequency, int quality,
- int source, int channel_mode,
- bool editable, int prerecord_time)
+#ifdef HAVE_SPDIF_IN
+#ifdef HAVE_SPDIF_POWER
+void audio_set_spdif_power_setting(bool on)
{
- frequency = frequency;
- quality = quality;
- source = source;
- channel_mode = channel_mode;
- editable = editable;
- prerecord_time = prerecord_time;
+ on = on;
+}
+
+bool audio_get_spdif_power_setting(void)
+{
+ 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)
@@ -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)
*left = 0;
diff --git a/apps/recorder/recording.h b/apps/recorder/recording.h
index aa216e757f..a977efa749 100644
--- a/apps/recorder/recording.h
+++ b/apps/recorder/recording.h
@@ -32,15 +32,16 @@ int rec_create_directory(void);
#define SRCF_FMRADIO_PLAYING 0x0000 /* default */
#define SRCF_FMRADIO_PAUSED 0x2000
#endif
-void rec_set_source(int source, int flags);
+void rec_set_source(int source, unsigned flags);
#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 */
-/* SRCF_RECORDING is implied */
-void rec_set_recording_options(int frequency, int quality,
- int source, int source_flags,
- int channel_mode, bool editable,
- int prerecord_time);
+/* SRCF_RECORDING is implied for SWCODEC */
+void rec_set_recording_options(struct audio_recording_options *options);
/* steals mp3 buffer, creates unique filename and starts recording */
void rec_record(void);
diff --git a/apps/settings.c b/apps/settings.c
index a4320eda7b..ec96cc760b 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -90,13 +90,16 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "pcmbuf.h"
#include "pcm_playback.h"
#include "dsp.h"
+#ifdef HAVE_RECORDING
+#include "enc_config.h"
#endif
+#endif /* CONFIG_CODEC == SWCODEC */
#ifdef HAVE_WM8758
#include "eq_menu.h"
#endif
-#define CONFIG_BLOCK_VERSION 55
+#define CONFIG_BLOCK_VERSION 56
#define CONFIG_BLOCK_SIZE 512
#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 },
#endif /* CONFIG_CODEC == MAS3587F */
-#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
+#if CONFIG_CODEC == SWCODEC
#ifdef HAVE_UDA1380
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
#endif
@@ -524,16 +527,20 @@ static const struct bit_entry hd_bits[] =
#endif
{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 */
-#if 0 /* Till samplerates are added for SWCODEC */
- {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
- "rec frequency", "44,48,32,22,24,16" },
-#else
- {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
- "rec frequency", "44" },
-#endif
-
- {4, S_O(rec_quality), 4 /* MP3 L3 192 kBit/s */, "rec quality", NULL },
-#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
+ {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
+ "rec frequency", REC_FREQ_CFG_VAL_LIST },
+ {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
+ "rec format", REC_FORMAT_CFG_VAL_LIST },
+ /** Encoder settings start - keep these together **/
+ /* mp3_enc */
+ {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
+ "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
+ /* wav_enc */
+ /* (no settings yet) */
+ /* wavpack_enc */
+ /* (no settings yet) */
+ /** Encoder settings end **/
+#endif /* CONFIG_CODEC == SWCODEC */
/* values for the trigger */
{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);
#endif
#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)
{
int fd;
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 */
while (true) {
@@ -1887,6 +1899,10 @@ void settings_reset(void) {
global_settings.kbd_file[0] = '\0';
#endif
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 )
diff --git a/apps/settings.h b/apps/settings.h
index 435d8e9ce2..09d4974eee 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -29,6 +29,10 @@
#include "tagcache.h"
#include "button.h"
+#if CONFIG_CODEC == SWCODEC
+#include "audio.h"
+#endif
+
#ifdef HAVE_BACKLIGHT_BRIGHTNESS
#include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */
#endif
@@ -142,18 +146,22 @@ struct user_settings
int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */
#endif
+#if CONFIG_CODEC == SWCODEC
+ int rec_format; /* record format index */
+#else
int rec_quality; /* 0-7 */
- int rec_source; /* 0=mic, 1=line, 2=S/PDIF */
- int rec_frequency; /* 0 = 44.1kHz
+#endif /* CONFIG_CODEC == SWCODEC */
+ 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
2 = 32kHz
3 = 22.05kHz
4 = 24kHz
5 = 16kHz */
int rec_channels; /* 0=Stereo, 1=Mono */
- int rec_mic_gain; /* 0-15 */
- int rec_left_gain; /* 0-15 */
- int rec_right_gain; /* 0-15 */
+ int rec_mic_gain; /* depends on target */
+ int rec_left_gain; /* depends on target */
+ int rec_right_gain; /* depands on target */
bool rec_editable; /* true means that the bit reservoir is off */
bool recscreen_on; /* true if using the recording screen */
@@ -504,6 +512,20 @@ struct user_settings
#endif
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 };
@@ -584,7 +606,7 @@ extern const char rec_base_directory[];
/* argument bits for settings_load() */
#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 */
/* repeat mode options */
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index c10ba9417e..fb766d604c 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -54,6 +54,10 @@
#include "dsp.h"
#include "eq_menu.h"
#include "pcmbuf.h"
+#ifdef HAVE_RECORDING
+#include "enc_config.h"
+#endif
+#include "general.h"
#endif
#include "action.h"
@@ -308,22 +312,20 @@ static bool recsource(void)
{
int n_opts = AUDIO_NUM_SOURCES;
- struct opt_items names[AUDIO_NUM_SOURCES] = {
- { STR(LANG_RECORDING_SRC_MIC) },
- { STR(LANG_RECORDING_SRC_LINE) },
+ static const struct opt_items names[AUDIO_NUM_SOURCES] = {
+ [AUDIO_SRC_MIC] = { STR(LANG_RECORDING_SRC_MIC) },
+ [AUDIO_SRC_LINEIN] = { STR(LANG_RECORDING_SRC_LINE) },
#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
};
/* caveat: assumes it's the last item! */
#ifdef HAVE_FMRADIO_IN
- if (radio_hardware_present())
- {
- names[AUDIO_SRC_FMRADIO].string = ID2P(LANG_FM_RADIO);
- names[AUDIO_SRC_FMRADIO].voice_id = LANG_FM_RADIO;
- }
- else
+ if (!radio_hardware_present())
n_opts--;
#endif
@@ -332,28 +334,7 @@ static bool recsource(void)
n_opts, NULL );
}
-/* To be removed when we add support for sample rates and channel settings */
-#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
+#if CONFIG_CODEC == MAS3587F
static bool recquality(void)
{
return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT,
@@ -368,32 +349,182 @@ static bool receditable(void)
}
#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 const struct opt_items names[] = {
+#if CONFIG_CODEC == MAS3587F
+ static const struct opt_items names[6] = {
{ "44.1kHz", TALK_ID(44, UNIT_KHZ) },
-#if CONFIG_CODEC != SWCODEC /* This is temporary */
{ "48kHz", TALK_ID(48, UNIT_KHZ) },
{ "32kHz", TALK_ID(32, UNIT_KHZ) },
{ "22.05kHz", TALK_ID(22, UNIT_KHZ) },
{ "24kHz", TALK_ID(24, UNIT_KHZ) },
{ "16kHz", TALK_ID(16, UNIT_KHZ) }
-#endif
};
return set_option(str(LANG_RECORDING_FREQUENCY),
&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 const struct opt_items names[] = {
- { STR(LANG_CHANNEL_STEREO) },
- { STR(LANG_CHANNEL_MONO) }
+ static const struct opt_items names[CHN_NUM_MODES] = {
+ [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) },
+ [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) }
};
+#if CONFIG_CODEC == MAS3587F
return set_option(str(LANG_RECORDING_CHANNELS),
&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)
@@ -1049,58 +1180,59 @@ bool rectrigger(void)
action_signalscreenchange();
return retval;
}
-#endif
+#endif /* !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F */
bool recording_menu(bool no_source)
{
- int m;
- 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;
+ static const struct menu_item static_items[] = {
+#if CONFIG_CODEC == MAS3587F
+ { ID2P(LANG_RECORDING_QUALITY), 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 == SWCODEC
+ { ID2P(LANG_RECORDING_FORMAT), recformat },
+ { ID2P(LANG_ENCODER_SETTINGS), enc_global_config_menu },
+#endif
+ { ID2P(LANG_RECORDING_FREQUENCY), recfrequency },
+ { ID2P(LANG_RECORDING_SOURCE), recsource }, /* not shown if no_source */
+ { ID2P(LANG_RECORDING_CHANNELS), recchannels },
#if CONFIG_CODEC == MAS3587F
- items[i].desc = ID2P(LANG_RECORDING_EDITABLE);
- items[i++].function = receditable;
+ { ID2P(LANG_RECORDING_EDITABLE), receditable },
#endif
- items[i].desc = ID2P(LANG_RECORD_TIMESPLIT);
- items[i++].function = filesplitoptionsmenu;
- items[i].desc = ID2P(LANG_RECORD_PRERECORD_TIME);
- items[i++].function = recprerecord;
- items[i].desc = ID2P(LANG_RECORD_DIRECTORY);
- items[i++].function = recdirectory;
- items[i].desc = ID2P(LANG_RECORD_STARTUP);
- items[i++].function = reconstartup;
+ { ID2P(LANG_RECORD_TIMESPLIT), filesplitoptionsmenu },
+ { ID2P(LANG_RECORD_PRERECORD_TIME), recprerecord },
+ { ID2P(LANG_RECORD_DIRECTORY), recdirectory },
+ { ID2P(LANG_RECORD_STARTUP), reconstartup },
#ifdef CONFIG_BACKLIGHT
- items[i].desc = ID2P(LANG_CLIP_LIGHT);
- items[i++].function = cliplight;
+ { ID2P(LANG_CLIP_LIGHT), cliplight },
#endif
#if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F
- items[i].desc = ID2P(LANG_RECORD_TRIGGER);
- items[i++].function = rectrigger;
+ { ID2P(LANG_RECORD_TRIGGER), rectrigger },
#endif
#ifdef HAVE_AGC
- items[i].desc = ID2P(LANG_RECORD_AGC_PRESET);
- items[i++].function = agc_preset;
- items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME);
- items[i++].function = agc_cliptime;
+ { ID2P(LANG_RECORD_AGC_PRESET), agc_preset },
+ { ID2P(LANG_RECORD_AGC_CLIPTIME), agc_cliptime },
#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);
menu_exit(m);
return result;
-}
-#endif
+} /* recording_menu */
+
+#endif /* HAVE_RECORDING */
diff --git a/apps/status.c b/apps/status.c
index 2a57db0f89..75219d604c 100644
--- a/apps/status.c
+++ b/apps/status.c
@@ -46,7 +46,7 @@
#ifdef CONFIG_TUNER
#include "radio.h"
#endif
-#if CONFIG_CODEC == SWCODEC
+#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
#include "pcm_record.h"
#endif
@@ -87,10 +87,6 @@ int current_playmode(void)
}
#ifdef HAVE_RECORDING
-#if CONFIG_CODEC == SWCODEC
- audio_stat = pcm_rec_status();
-#endif
-
if(audio_stat & AUDIO_STATUS_RECORD)
{
if(audio_stat & AUDIO_STATUS_PAUSE)
diff --git a/apps/talk.c b/apps/talk.c
index d81aa082c9..018f6ed5ab 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -46,13 +46,17 @@
MASCODEC | MASCODEC | SWCODEC
(playing) | (stopped) |
- audiobuf-----------+-----------+-----------
+ audiobuf-----------+-----------+------------
audio | voice | thumbnail
- |-----------|----------- filebuf
+ |-----------|------------
| thumbnail | voice
- | |-----------
+ | |------------
+ | | filebuf
+ | |------------
| | audio
- audiobufend----------+-----------+-----------
+ | |------------
+ | | codec swap
+ audiobufend----------+-----------+------------
SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */
@@ -102,7 +106,7 @@ struct queue_entry /* one entry of the internal queue */
/***************** 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 struct voicefile* p_voicefile; /* loaded voicefile */
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 */
p_voicefile = NULL; /* indicate no voicefile (trashed) */
#if CONFIG_CODEC == SWCODEC
- /* Allocate a dedicated thumbnail buffer */
- size_for_thumbnail = audiobufend - audiobuf;
- if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE)
- size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
- p_thumbnail = buffer_alloc(size_for_thumbnail);
+ /* Allocate a dedicated thumbnail buffer - once */
+ if (p_thumbnail == NULL)
+ {
+ size_for_thumbnail = audiobufend - audiobuf;
+ if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE)
+ size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
+ p_thumbnail = buffer_alloc(size_for_thumbnail);
+ }
#else
/* Just use the audiobuf, without allocating anything */
p_thumbnail = audiobuf;
diff --git a/apps/tree.c b/apps/tree.c
index 653da791a8..6465b50e6f 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -58,7 +58,9 @@
#include "misc.h"
#include "filetree.h"
#include "tagtree.h"
+#ifdef HAVE_RECORDING
#include "recorder/recording.h"
+#endif
#include "rtc.h"
#include "dircache.h"
#ifdef HAVE_TAGCACHE