mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
improved mpeg audio quality
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@548 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b133675d3e
commit
f622a630ca
1 changed files with 136 additions and 5 deletions
|
|
@ -8,6 +8,11 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 Dave Chapman
|
* 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.
|
* 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.
|
* 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 */
|
/* We want to use the "real" open in some cases */
|
||||||
#undef open
|
#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_stream Stream;
|
||||||
struct mad_frame Frame;
|
struct mad_frame Frame;
|
||||||
struct mad_synth Synth;
|
struct mad_synth Synth;
|
||||||
mad_timer_t Timer;
|
mad_timer_t Timer;
|
||||||
int sound;
|
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) {
|
void init_oss(int sound, int sound_freq, int channels) {
|
||||||
int format=AFMT_U16_LE;
|
int format=AFMT_U16_LE;
|
||||||
int setting=0x000C000D; // 12 fragments size 8kb ? WHAT IS THIS?
|
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");
|
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) {
|
if (ioctl(sound,SNDCTL_DSP_SPEED,&sound_freq)==-1) {
|
||||||
perror("SNDCTL_DSP_SPEED");
|
perror("SNDCTL_DSP_SPEED");
|
||||||
}
|
}
|
||||||
|
|
@ -81,6 +211,8 @@ int mpeg_play(char* fname)
|
||||||
unsigned long FrameCount=0;
|
unsigned long FrameCount=0;
|
||||||
int sound,fd;
|
int sound,fd;
|
||||||
mp3entry mp3;
|
mp3entry mp3;
|
||||||
|
register signed int s0, s1;
|
||||||
|
static struct dither d0, d1;
|
||||||
|
|
||||||
mp3info(&mp3, fname);
|
mp3info(&mp3, fname);
|
||||||
|
|
||||||
|
|
@ -108,7 +240,7 @@ int mpeg_play(char* fname)
|
||||||
|
|
||||||
do
|
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)
|
if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
|
||||||
{
|
{
|
||||||
|
|
@ -165,7 +297,7 @@ int mpeg_play(char* fname)
|
||||||
unsigned short Sample;
|
unsigned short Sample;
|
||||||
|
|
||||||
/* Left channel */
|
/* Left channel */
|
||||||
Sample=MadFixedToUshort(Synth.pcm.samples[0][i]);
|
Sample=scale(Synth.pcm.samples[0][i],&d0);
|
||||||
*(OutputPtr++)=Sample&0xff;
|
*(OutputPtr++)=Sample&0xff;
|
||||||
*(OutputPtr++)=Sample>>8;
|
*(OutputPtr++)=Sample>>8;
|
||||||
|
|
||||||
|
|
@ -173,7 +305,7 @@ int mpeg_play(char* fname)
|
||||||
* the right output channel is the same as the left one.
|
* the right output channel is the same as the left one.
|
||||||
*/
|
*/
|
||||||
if(MAD_NCHANNELS(&Frame.header)==2)
|
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&0xff;
|
||||||
*(OutputPtr++)=Sample>>8;
|
*(OutputPtr++)=Sample>>8;
|
||||||
|
|
||||||
|
|
@ -191,7 +323,6 @@ int mpeg_play(char* fname)
|
||||||
}
|
}
|
||||||
}while(1);
|
}while(1);
|
||||||
|
|
||||||
fprintf(stderr,"END OF MAD LOOP\n");
|
|
||||||
/* Mad is no longer used, the structures that were initialized must
|
/* Mad is no longer used, the structures that were initialized must
|
||||||
* now be cleared.
|
* now be cleared.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue