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