summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2006-11-06 18:07:30 +0000
committerMichael Sevakis <jethead71@rockbox.org>2006-11-06 18:07:30 +0000
commit0f5cb94aa4a334366a746fcbb22f3335ca413265 (patch)
tree8f89a96628c1810d51ee9816daf78edb8c76fcd4 /apps
parent0b22795e26ee09de14f6ac23219adeda12f2fd5b (diff)
downloadrockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.tar.gz
rockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.tar.bz2
rockbox-0f5cb94aa4a334366a746fcbb22f3335ca413265.zip
Big Patch adds primarily: Samplerate and format selection to recording for SWCODEC. Supprort for samplerates changing in playback (just goes with the recording part inseparably). Samplerates to all encoders. Encoders can be configured individually on a menu specific to the encoder in the recording menu. File creation is delayed until flush time to reduce spinups when splitting. Misc: statusbar icons for numbers are individual digits to display any number. Audio buffer was rearranged to maximize memory available to recording and properly reinitialized when trashed. ColdFire PCM stuff moved to target tree to avoid a complicated mess when adding samplerate switching. Some needed API changes and to neaten up growing gap between hardware and software codecs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11452 a1c6a512-1295-4272-9138-f99709370657
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