improved mpeg audio quality

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@548 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dave Chapman 2002-05-12 10:37:49 +00:00
parent b133675d3e
commit f622a630ca

View file

@ -8,6 +8,11 @@
*
* Copyright (C) 2002 Dave Chapman
*
* This file contains significant code from two other projects:
*
* 1) madldd - a sample application to use libmad
* 2) CoolPlayer - a win32 audio player that also uses libmad
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
@ -33,12 +38,137 @@
/* We want to use the "real" open in some cases */
#undef open
/* The "dither" code to convert the 24-bit samples produced by libmad was
taken from the coolplayer project - coolplayer.sourceforge.net */
struct dither {
mad_fixed_t error[3];
mad_fixed_t random;
};
# define SAMPLE_DEPTH 16
# define scale(x, y) dither((x), (y))
struct mad_stream Stream;
struct mad_frame Frame;
struct mad_synth Synth;
mad_timer_t Timer;
int sound;
/*
* NAME: prng()
* DESCRIPTION: 32-bit pseudo-random number generator
*/
static __inline
unsigned long prng(unsigned long state)
{
return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
}
/*
* NAME: dither()
* DESCRIPTION: dither and scale sample
*/
static __inline
signed int dither(mad_fixed_t sample, struct dither *dither)
{
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 - SAMPLE_DEPTH - 1));
scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
mask = (1L << scalebits) - 1;
/* dither */
random = prng(dither->random);
output += (random & mask) - (dither->random & mask);
dither->random = random;
/* clip */
if (output > MAX) {
output = MAX;
if (sample > MAX)
sample = MAX;
}
else if (output < MIN) {
output = MIN;
if (sample < MIN)
sample = MIN;
}
/* quantize */
output &= ~mask;
/* error feedback */
dither->error[0] = sample - output;
/* scale */
return output >> scalebits;
}
/*
* NAME: pack_pcm()
* DESCRIPTION: scale and dither MAD output
*/
static
void pack_pcm(unsigned char **pcm, unsigned int nsamples,
mad_fixed_t const *ch1, mad_fixed_t const *ch2)
{
register signed int s0, s1;
static struct dither d0, d1;
if (ch2) { /* stereo */
while (nsamples--) {
s0 = scale(*ch1++, &d0);
s1 = scale(*ch2++, &d1);
# if SAMPLE_DEPTH == 16
(*pcm)[0 + 0] = s0 >> 0;
(*pcm)[0 + 1] = s0 >> 8;
(*pcm)[2 + 0] = s1 >> 0;
(*pcm)[2 + 1] = s1 >> 8;
*pcm += 2 * 2;
# elif SAMPLE_DEPTH == 8
(*pcm)[0] = s0 ^ 0x80;
(*pcm)[1] = s1 ^ 0x80;
*pcm += 2;
# else
# error "bad SAMPLE_DEPTH"
# endif
}
}
else { /* mono */
while (nsamples--) {
s0 = scale(*ch1++, &d0);
# if SAMPLE_DEPTH == 16
(*pcm)[0] = s0 >> 0;
(*pcm)[1] = s0 >> 8;
*pcm += 2;
# elif SAMPLE_DEPTH == 8
*(*pcm)++ = s0 ^ 0x80;
# endif
}
}
}
void init_oss(int sound, int sound_freq, int channels) {
int format=AFMT_U16_LE;
int setting=0x000C000D; // 12 fragments size 8kb ? WHAT IS THIS?
@ -56,7 +186,7 @@ void init_oss(int sound, int sound_freq, int channels) {
perror("SNDCTL_DSP_SETFMT");
}
fprintf(stderr,"SETTING /dev/dsp to %dHz\n",sound_freq);
// fprintf(stderr,"SETTING /dev/dsp to %dHz\n",sound_freq);
if (ioctl(sound,SNDCTL_DSP_SPEED,&sound_freq)==-1) {
perror("SNDCTL_DSP_SPEED");
}
@ -81,6 +211,8 @@ int mpeg_play(char* fname)
unsigned long FrameCount=0;
int sound,fd;
mp3entry mp3;
register signed int s0, s1;
static struct dither d0, d1;
mp3info(&mp3, fname);
@ -108,7 +240,7 @@ int mpeg_play(char* fname)
do
{
if (button_get()) break; /* Return if a key is pressed */
//if (button_get()) break; /* Return if a key is pressed */
if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
{
@ -165,7 +297,7 @@ int mpeg_play(char* fname)
unsigned short Sample;
/* Left channel */
Sample=MadFixedToUshort(Synth.pcm.samples[0][i]);
Sample=scale(Synth.pcm.samples[0][i],&d0);
*(OutputPtr++)=Sample&0xff;
*(OutputPtr++)=Sample>>8;
@ -173,7 +305,7 @@ int mpeg_play(char* fname)
* the right output channel is the same as the left one.
*/
if(MAD_NCHANNELS(&Frame.header)==2)
Sample=MadFixedToUshort(Synth.pcm.samples[1][i]);
Sample=scale(Synth.pcm.samples[1][i],&d0);
*(OutputPtr++)=Sample&0xff;
*(OutputPtr++)=Sample>>8;
@ -191,7 +323,6 @@ int mpeg_play(char* fname)
}
}while(1);
fprintf(stderr,"END OF MAD LOOP\n");
/* Mad is no longer used, the structures that were initialized must
* now be cleared.
*/