Patch from T. Million for 24-bit mad output.
parent
ede099be25
commit
f1b965bf12
|
@ -14,12 +14,26 @@
|
||||||
|
|
||||||
#define INPUT_BUFFER_SIZE 5*8192
|
#define INPUT_BUFFER_SIZE 5*8192
|
||||||
|
|
||||||
|
struct audio_dither {
|
||||||
|
mad_fixed_t error[3];
|
||||||
|
mad_fixed_t random;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct audio_stats {
|
||||||
|
unsigned long clipped_samples;
|
||||||
|
mad_fixed_t peak_clipping;
|
||||||
|
mad_fixed_t peak_sample;
|
||||||
|
};
|
||||||
|
|
||||||
@interface MADDecoder : NSObject <CogDecoder>
|
@interface MADDecoder : NSObject <CogDecoder>
|
||||||
{
|
{
|
||||||
struct mad_stream _stream;
|
struct mad_stream _stream;
|
||||||
struct mad_frame _frame;
|
struct mad_frame _frame;
|
||||||
struct mad_synth _synth;
|
struct mad_synth _synth;
|
||||||
|
|
||||||
|
struct audio_dither channel_dither[2];
|
||||||
|
struct audio_stats stats;
|
||||||
|
|
||||||
unsigned char _inputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
|
unsigned char _inputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
|
||||||
unsigned char *_outputBuffer;
|
unsigned char *_outputBuffer;
|
||||||
int _outputFrames;
|
int _outputFrames;
|
||||||
|
|
|
@ -277,7 +277,7 @@
|
||||||
mad_frame_finish (&frame);
|
mad_frame_finish (&frame);
|
||||||
mad_stream_finish (&stream);
|
mad_stream_finish (&stream);
|
||||||
|
|
||||||
bitsPerSample = 16;
|
bitsPerSample = 24;
|
||||||
|
|
||||||
bytesPerFrame = (bitsPerSample/8) * channels;
|
bytesPerFrame = (bitsPerSample/8) * channels;
|
||||||
|
|
||||||
|
@ -321,6 +321,89 @@
|
||||||
return [self scanFile];
|
return [self scanFile];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NAME: prng()
|
||||||
|
* DESCRIPTION: 32-bit pseudo-random number generator
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
unsigned long prng(unsigned long state)
|
||||||
|
{
|
||||||
|
return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clipping and rounding code from madplay(audio.c):
|
||||||
|
/*
|
||||||
|
* madplay - MPEG audio decoder and player
|
||||||
|
* Copyright (C) 2000-2004 Robert Leslie
|
||||||
|
*/
|
||||||
|
static inline signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample,
|
||||||
|
struct audio_dither *dither,
|
||||||
|
struct audio_stats *stats)
|
||||||
|
{
|
||||||
|
unsigned int scalebits;
|
||||||
|
mad_fixed_t output, mask, random;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MIN = -MAD_F_ONE,
|
||||||
|
MAX = MAD_F_ONE - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* noise shape */
|
||||||
|
sample += dither->error[0] - dither->error[1] + dither->error[2];
|
||||||
|
|
||||||
|
dither->error[2] = dither->error[1];
|
||||||
|
dither->error[1] = dither->error[0] / 2;
|
||||||
|
|
||||||
|
/* bias */
|
||||||
|
output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
|
||||||
|
|
||||||
|
scalebits = MAD_F_FRACBITS + 1 - bits;
|
||||||
|
mask = (1L << scalebits) - 1;
|
||||||
|
|
||||||
|
/* dither */
|
||||||
|
random = prng(dither->random);
|
||||||
|
output += (random & mask) - (dither->random & mask);
|
||||||
|
|
||||||
|
dither->random = random;
|
||||||
|
|
||||||
|
/* clip */
|
||||||
|
if (output >= stats->peak_sample) {
|
||||||
|
if (output > MAX) {
|
||||||
|
++stats->clipped_samples;
|
||||||
|
if (output - MAX > stats->peak_clipping)
|
||||||
|
stats->peak_clipping = output - MAX;
|
||||||
|
|
||||||
|
output = MAX;
|
||||||
|
|
||||||
|
if (sample > MAX)
|
||||||
|
sample = MAX;
|
||||||
|
}
|
||||||
|
stats->peak_sample = output;
|
||||||
|
}
|
||||||
|
else if (output < -stats->peak_sample) {
|
||||||
|
if (output < MIN) {
|
||||||
|
++stats->clipped_samples;
|
||||||
|
if (MIN - output > stats->peak_clipping)
|
||||||
|
stats->peak_clipping = MIN - output;
|
||||||
|
|
||||||
|
output = MIN;
|
||||||
|
|
||||||
|
if (sample < MIN)
|
||||||
|
sample = MIN;
|
||||||
|
}
|
||||||
|
stats->peak_sample = -output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* quantize */
|
||||||
|
output &= ~mask;
|
||||||
|
|
||||||
|
/* error feedback */
|
||||||
|
dither->error[0] = sample - output;
|
||||||
|
|
||||||
|
/* scale */
|
||||||
|
return output >> scalebits;
|
||||||
|
}
|
||||||
|
|
||||||
// Clipping and rounding code from madplay(audio.c):
|
// Clipping and rounding code from madplay(audio.c):
|
||||||
/*
|
/*
|
||||||
|
@ -402,20 +485,33 @@ audio_linear_round(unsigned int bits,
|
||||||
|
|
||||||
_outputBuffer = (unsigned char *) malloc (_outputFrames * bytesPerFrame * sizeof (char));
|
_outputBuffer = (unsigned char *) malloc (_outputFrames * bytesPerFrame * sizeof (char));
|
||||||
|
|
||||||
unsigned int i, j;
|
int ch;
|
||||||
unsigned int stride = channels * 2;
|
int i;
|
||||||
for (j = 0; j < channels; j++)
|
int stride = bitsPerSample/8;
|
||||||
|
unsigned char *outputPtr = _outputBuffer;
|
||||||
|
|
||||||
|
// samples [0 ... n]
|
||||||
|
for(i = startingSample; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
/* output sample(s) in 16-bit signed little-endian PCM */
|
// channels [0 .. n] in this case LRLRLRLR
|
||||||
mad_fixed_t const *channel = _synth.pcm.samples[j];
|
for (ch = 0; ch < channels; ch++)
|
||||||
unsigned char *outputPtr = _outputBuffer + (j * 2);
|
|
||||||
|
|
||||||
for (i = startingSample; i < sampleCount; i++)
|
|
||||||
{
|
{
|
||||||
signed short sample = audio_linear_round(bitsPerSample, channel[i]);
|
signed long sample = audio_linear_dither(bitsPerSample,
|
||||||
|
_synth.pcm.samples[ch][i],
|
||||||
|
&channel_dither[ch],
|
||||||
|
&stats);
|
||||||
|
|
||||||
outputPtr[0] = sample>>8;
|
if(bitsPerSample == 24)
|
||||||
outputPtr[1] = sample & 0xff;
|
{
|
||||||
|
outputPtr[0] = sample >> 16;
|
||||||
|
outputPtr[1] = sample >> 8;
|
||||||
|
outputPtr[2] = sample >> 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outputPtr[0] = sample >> 8;
|
||||||
|
outputPtr[1] = sample & 0xff;
|
||||||
|
}
|
||||||
outputPtr += stride;
|
outputPtr += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue