diff options
author | Dave Chapman <dave@dchapman.com> | 2002-05-12 10:37:49 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2002-05-12 10:37:49 +0000 |
commit | f622a630ca4b2c828271fc0f7a1367cd94ad9103 (patch) | |
tree | 942d4d191008b90b30678e3a8743a85f8913cdfe /uisimulator | |
parent | b133675d3e39ee9e25f4c6e919b88ceb3e9d51c0 (diff) |
improved mpeg audio quality
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@548 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator')
-rw-r--r-- | uisimulator/x11/mpegplay.c | 141 |
1 files changed, 136 insertions, 5 deletions
diff --git a/uisimulator/x11/mpegplay.c b/uisimulator/x11/mpegplay.c index 2d31c073dd..c01ab2487c 100644 --- a/uisimulator/x11/mpegplay.c +++ b/uisimulator/x11/mpegplay.c @@ -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. */ |