From 2cc2420f8cb71be62851273fc4ce9bf5223155f6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 23 Oct 2008 16:58:38 +0200 Subject: mp3: send 24 bit PCM data libmad produces samples of more than 24 bit. Rounding that down to 16 bits using dithering makes those people lose quality who have a 24 bit capable sound device. Send 24 bit PCM data, and let the receiver decide whether to apply 16 bit dithering. --- src/inputPlugins/mp3_plugin.c | 87 ++++++++++++------------------------------- 1 file changed, 24 insertions(+), 63 deletions(-) diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index 158a152cd..a0de30ba7 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -51,77 +51,39 @@ enum muteframe { static int gaplessPlaybackEnabled; -/* this is stolen from mpg321! */ -struct audio_dither { - mad_fixed_t error[3]; - mad_fixed_t random; -}; - -static unsigned long prng(unsigned long state) -{ - return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; -} - -static int16_t audio_linear_dither(mad_fixed_t sample, - struct audio_dither *dither) +static inline int32_t +mad_fixed_to_24_sample(mad_fixed_t sample) { - mad_fixed_t output, mask, rnd; - enum { - bits = 16, - scalebits = MAD_F_FRACBITS + 1 - bits, + bits = 24, MIN = -MAD_F_ONE, MAX = MAD_F_ONE - 1 }; - sample += dither->error[0] - dither->error[1] + dither->error[2]; - - dither->error[2] = dither->error[1]; - dither->error[1] = dither->error[0] / 2; - - output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1)); - - mask = (1L << scalebits) - 1; + /* round */ + sample = sample + (1L << (MAD_F_FRACBITS - bits)); - rnd = prng(dither->random); - output += (rnd & mask) - (dither->random & mask); + /* clip */ + if (sample > MAX) + sample = MAX; + else if (sample < MIN) + sample = MIN; - dither->random = rnd; - - if (output > MAX) { - output = MAX; - - if (sample > MAX) - sample = MAX; - } else if (output < MIN) { - output = MIN; - - if (sample < MIN) - sample = MIN; - } - - output &= ~mask; - - dither->error[0] = sample - output; - - return (int16_t)(output >> scalebits); + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - bits); } -static unsigned dither_buffer(int16_t *dest0, const struct mad_synth *synth, - struct audio_dither *dither, - unsigned int start, unsigned int end, - unsigned int num_channels) +static void +mad_fixed_to_24_buffer(int32_t *dest, const struct mad_synth *synth, + unsigned int start, unsigned int end, + unsigned int num_channels) { - int16_t *dest = dest0; unsigned int i, c; for (i = start; i < end; ++i) { for (c = 0; c < num_channels; ++c) - *dest++ = audio_linear_dither(synth->pcm.samples[c][i], - dither); + *dest++ = mad_fixed_to_24_sample(synth->pcm.samples[c][i]); } - - return dest - dest0; } /* end of stolen stuff from mpg321 */ @@ -145,7 +107,7 @@ typedef struct _mp3DecodeData { struct mad_synth synth; mad_timer_t timer; unsigned char readBuffer[READ_BUFFER_SIZE]; - int16_t outputBuffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; + int32_t outputBuffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; float totalTime; float elapsedTime; enum muteframe muteFrame; @@ -164,7 +126,6 @@ typedef struct _mp3DecodeData { unsigned long bitRate; struct decoder *decoder; InputStream *inStream; - struct audio_dither dither; enum mad_layer layer; } mp3DecodeData; @@ -187,7 +148,6 @@ static void initMp3DecodeData(mp3DecodeData * data, struct decoder *decoder, data->decoder = decoder; data->inStream = inStream; data->layer = 0; - memset(&(data->dither), 0, sizeof(struct audio_dither)); mad_stream_init(&data->stream); mad_stream_options(&data->stream, MAD_OPTION_IGNORECRC); @@ -933,10 +893,11 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) i += num_samples; - num_samples = dither_buffer(data->outputBuffer, - &data->synth, &data->dither, - i - num_samples, i, - MAD_NCHANNELS(&(data->frame).header)); + mad_fixed_to_24_buffer(data->outputBuffer, + &data->synth, + i - num_samples, i, + MAD_NCHANNELS(&(data->frame).header)); + num_samples *= MAD_NCHANNELS(&(data->frame).header); cmd = decoder_data(decoder, data->inStream, data->inStream->seekable, @@ -1022,7 +983,7 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) static void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, struct audio_format * af) { - af->bits = 16; + af->bits = 24; af->sample_rate = (data->frame).header.samplerate; af->channels = MAD_NCHANNELS(&(data->frame).header); } -- cgit v1.2.3