Commit b04de17f authored by Josh Coalson's avatar Josh Coalson
Browse files

add support for 24-bit input

parent 52a7ae78
......@@ -304,12 +304,14 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
FILE *fout = stream_info->fout;
unsigned bps = stream_info->bps, channels = stream_info->channels;
bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
bool is_unsigned_samples = (stream_info->is_wave_out? bps==8 : stream_info->is_unsigned_samples);
bool is_unsigned_samples = (stream_info->is_wave_out? bps<=8 : stream_info->is_unsigned_samples);
unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */
unsigned char *ucbuffer = (unsigned char *)scbuffer;
signed short *ssbuffer = (signed short *)scbuffer;
unsigned short *usbuffer = (unsigned short *)scbuffer;
signed *slbuffer = (signed *)scbuffer;
unsigned *ulbuffer = (unsigned *)scbuffer;
(void)decoder;
......@@ -353,7 +355,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
ucbuffer[sample] = buffer[channel][wide_sample] + 128;
ucbuffer[sample] = buffer[channel][wide_sample] + 0x80;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
......@@ -363,11 +365,11 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
if(fwrite(ucbuffer, 1, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else { /* bps == 16 */
else if(bps == 16) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
usbuffer[sample] = buffer[channel][wide_sample] + 32768;
usbuffer[sample] = buffer[channel][wide_sample] + 0x8000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
......@@ -376,7 +378,8 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
}
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
for(byte = 0; byte < sample<<1; byte += 2) {
const unsigned bytes = sample * 2;
for(byte = 0; byte < bytes; byte += 2) {
tmp = ucbuffer[byte];
ucbuffer[byte] = ucbuffer[byte+1];
ucbuffer[byte+1] = tmp;
......@@ -385,6 +388,78 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
if(fwrite(usbuffer, 2, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else if(bps == 24) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
ulbuffer[sample] = buffer[channel][wide_sample] + 0x800000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
slbuffer[sample] = buffer[channel][wide_sample];
}
/*@@@
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; byte += 4, lbyte += 3) {
tmp = ucbuffer[byte];
ucbuffer[lbyte] = ucbuffer[byte+2];
ucbuffer[lbyte+2] = tmp;
ucbuffer[lbyte+1] = ucbuffer[byte+1];
}
}
else {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
byte++;
}
}
*/
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
const unsigned bytes = sample * 4;
for(byte = 0; byte < bytes; byte += 4) {
tmp = ucbuffer[byte];
ucbuffer[byte] = ucbuffer[byte+3];
ucbuffer[byte+3] = tmp;
tmp = ucbuffer[byte+1];
ucbuffer[byte+1] = ucbuffer[byte+2];
ucbuffer[byte+2] = tmp;
}
}
if(is_big_endian) {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
byte++;
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
}
}
else {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
ucbuffer[lbyte++] = ucbuffer[byte++];
byte++;
}
}
if(fwrite(ucbuffer, 3, sample, fout) != sample)
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
else {
assert(0);
}
}
return FLAC__STREAM_DECODER_WRITE_CONTINUE;
}
......@@ -399,8 +474,8 @@ void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaD
stream_info->channels = metadata->data.stream_info.channels;
stream_info->sample_rate = metadata->data.stream_info.sample_rate;
if(stream_info->bps != 8 && stream_info->bps != 16) {
fprintf(stderr, "ERROR: bits per sample is not 8 or 16\n");
if(stream_info->bps != 8 && stream_info->bps != 16 && stream_info->bps != 24) {
fprintf(stderr, "ERROR: bits per sample is not 8/16/24\n");
stream_info->abort_flag = true;
return;
}
......
......@@ -72,7 +72,7 @@ typedef struct {
static bool is_big_endian_host;
static unsigned char ucbuffer[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*(FLAC__MAX_BITS_PER_SAMPLE>>3)];
static unsigned char ucbuffer[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*((FLAC__MAX_BITS_PER_SAMPLE+7)/8)];
static signed char *scbuffer = (signed char *)ucbuffer;
static uint16 *usbuffer = (uint16 *)ucbuffer;
static int16 *ssbuffer = (int16 *)ucbuffer;
......@@ -489,7 +489,7 @@ bool init(encoder_wrapper_struct *encoder_wrapper)
bool init_encoder(bool lax, bool do_mid_side, bool loose_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, unsigned padding, encoder_wrapper_struct *encoder_wrapper)
{
if(channels != 2 || bps > 16)
if(channels != 2 /*@@@ not necessary? || bps > 16*/)
do_mid_side = loose_mid_side = false;
if(encoder_wrapper->verify) {
......@@ -550,7 +550,7 @@ void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_sa
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
input[channel][wide_sample] = (int32)ucbuffer[sample] - 128;
input[channel][wide_sample] = (int32)ucbuffer[sample] - 0x80;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
......@@ -558,7 +558,7 @@ void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_sa
input[channel][wide_sample] = (int32)scbuffer[sample];
}
}
else {
else if(bps == 16) {
if(is_big_endian != is_big_endian_host) {
unsigned char tmp;
const unsigned bytes = wide_samples * channels * (bps >> 3);
......@@ -571,7 +571,7 @@ void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_sa
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
input[channel][wide_sample] = (int32)usbuffer[sample] - 32768;
input[channel][wide_sample] = (int32)usbuffer[sample] - 0x8000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
......@@ -579,6 +579,37 @@ void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_sa
input[channel][wide_sample] = (int32)ssbuffer[sample];
}
}
else if(bps == 24) {
if(!is_big_endian) {
unsigned char tmp;
const unsigned bytes = wide_samples * channels * (bps >> 3);
for(byte = 0; byte < bytes; byte += 3) {
tmp = ucbuffer[byte];
ucbuffer[byte] = ucbuffer[byte+2];
ucbuffer[byte+2] = tmp;
}
}
if(is_unsigned_samples) {
for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++) {
input[channel][wide_sample] = ucbuffer[byte++]; input[channel][wide_sample] <<= 8;
input[channel][wide_sample] |= ucbuffer[byte++]; input[channel][wide_sample] <<= 8;
input[channel][wide_sample] |= ucbuffer[byte++];
input[channel][wide_sample] -= 0x800000;
}
}
else {
for(byte = sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++) {
input[channel][wide_sample] = scbuffer[byte++]; input[channel][wide_sample] <<= 8;
input[channel][wide_sample] |= ucbuffer[byte++]; input[channel][wide_sample] <<= 8;
input[channel][wide_sample] |= ucbuffer[byte++];
}
}
}
else {
assert(0);
}
if(encoder_wrapper->verify) {
for(channel = 0; channel < channels; channel++)
......@@ -711,6 +742,9 @@ FLAC__StreamDecoderWriteStatus verify_write_callback(const FLAC__StreamDecoder *
if(0 != memcmp(buffer[channel], encoder_wrapper->verify_fifo.original[channel], sizeof(int32) * decoder->blocksize)) {
fprintf(stderr, "\nERROR: mismatch in decoded data, verify FAILED!\n");
fprintf(stderr, " Please submit a bug report to http://sourceforge.net/bugs/?func=addbug&group_id=13478\n");
for(l=0;l<decoder->blocksize;l++)
if(buffer[channel][l]!=encoder_wrapper->verify_fifo.original[channel][l])break;
fprintf(stderr,"@@@channel=%u, sample=%u, expected %08x, got %08x\n",channel,l,buffer[channel][l],encoder_wrapper->verify_fifo.original[channel][l]);
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
}
......
......@@ -240,8 +240,8 @@ int main(int argc, char *argv[])
return usage("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", format_channels, FLAC__MAX_CHANNELS);
}
if(format_bps >= 0) {
if(format_bps != 8 && format_bps != 16)
return usage("ERROR: invalid bits per sample '%u' (must be 8 or 16)\n", format_bps);
if(format_bps != 8 && format_bps != 16 && format_bps != 24)
return usage("ERROR: invalid bits per sample '%u' (must be 8/16/24)\n", format_bps);
}
if(format_sample_rate >= 0) {
if(format_sample_rate == 0 || (unsigned)format_sample_rate > FLAC__MAX_SAMPLE_RATE)
......
......@@ -263,8 +263,10 @@ FLAC__EncoderState FLAC__encoder_init(FLAC__Encoder *encoder, FLAC__EncoderWrite
if(encoder->do_mid_side_stereo && encoder->channels != 2)
return encoder->state = FLAC__ENCODER_MID_SIDE_CHANNELS_MISMATCH;
/*@@@ necessary?
if(encoder->do_mid_side_stereo && encoder->bits_per_sample > 16)
return encoder->state = FLAC__ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH;
*/
if(encoder->loose_mid_side_stereo && !encoder->do_mid_side_stereo)
return encoder->state = FLAC__ENCODER_ILLEGAL_MID_SIDE_FORCE;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment