diff options
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/SOURCES | 3 | ||||
| -rw-r--r-- | apps/codecs.c | 25 | ||||
| -rw-r--r-- | apps/codecs.h | 64 | ||||
| -rw-r--r-- | apps/codecs/libwavpack/bits.c | 22 | ||||
| -rw-r--r-- | apps/codecs/mp3_enc.c | 1182 | ||||
| -rw-r--r-- | apps/codecs/wav_enc.c | 419 | ||||
| -rw-r--r-- | apps/codecs/wavpack_enc.c | 539 | ||||
| -rw-r--r-- | apps/eq_menu.c | 3 | ||||
| -rw-r--r-- | apps/gui/statusbar.c | 196 | ||||
| -rw-r--r-- | apps/lang/english.lang | 114 | ||||
| -rw-r--r-- | apps/main.c | 3 | ||||
| -rw-r--r-- | apps/metadata.c | 48 | ||||
| -rw-r--r-- | apps/misc.c | 57 | ||||
| -rw-r--r-- | apps/misc.h | 35 | ||||
| -rw-r--r-- | apps/pcmbuf.c | 27 | ||||
| -rw-r--r-- | apps/pcmbuf.h | 2 | ||||
| -rw-r--r-- | apps/playback.c | 262 | ||||
| -rw-r--r-- | apps/playlist.c | 12 | ||||
| -rw-r--r-- | apps/plugin.c | 8 | ||||
| -rw-r--r-- | apps/recorder/icons.c | 90 | ||||
| -rw-r--r-- | apps/recorder/icons.h | 60 | ||||
| -rw-r--r-- | apps/recorder/peakmeter.c | 6 | ||||
| -rw-r--r-- | apps/recorder/radio.c | 25 | ||||
| -rw-r--r-- | apps/recorder/recording.c | 250 | ||||
| -rw-r--r-- | apps/recorder/recording.h | 13 | ||||
| -rw-r--r-- | apps/settings.c | 44 | ||||
| -rw-r--r-- | apps/settings.h | 34 | ||||
| -rw-r--r-- | apps/sound_menu.c | 288 | ||||
| -rw-r--r-- | apps/status.c | 6 | ||||
| -rw-r--r-- | apps/talk.c | 27 | ||||
| -rw-r--r-- | apps/tree.c | 2 |
31 files changed, 2605 insertions, 1261 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index e1d8e7b..ccfc7fa2 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 f33957e..4491dad 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 96804a8..0b90ef9 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 0a148e1..0f0e79c 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 3caca94..cb727ce 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(¶ms); + + 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 5aabb5d..974a903 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(¶ms); + + 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 eced7f1..5318abc 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(¶ms); - 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 6c4dde4..9939ee7 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 a8b8c50..ae8bba0 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 40d7bb7..8f7deb7 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 c4ee45c..05b4ab5 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 ee0100e..8455368 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 c36d619..0146385 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 1bc9a23..6c660e0 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 44f175c..5119d20 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 b5035f4..a408cda 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 f837266..af6b573 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 5a5313b..134b52e 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 = ¤t_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 25f1865..3a893fc 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 46d628e..ba22bb5 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 75401f6..1e7b8db 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 0370f4d..44be431 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 d74437a..7a0cc65 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 0a21d96..6a053cd 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 aa216e7..a977efa 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 a4320ed..ec96cc7 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 435d8e9..09d4974 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 c10ba94..fb766d6 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 2a57db0..75219d6 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 d81aa08..018f6ed 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 653da79..6465b50 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 |