diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio.c | 9 | ||||
-rw-r--r-- | src/pcm_utils.c | 92 | ||||
-rw-r--r-- | src/player.c | 2 | ||||
-rw-r--r-- | src/playerData.c | 2 | ||||
-rw-r--r-- | src/replayGain.c | 47 | ||||
-rw-r--r-- | src/replayGain.h | 2 | ||||
-rw-r--r-- | src/volume.c | 4 |
7 files changed, 90 insertions, 68 deletions
diff --git a/src/audio.c b/src/audio.c index 1bcd24de6..d622d45df 100644 --- a/src/audio.c +++ b/src/audio.c @@ -107,16 +107,11 @@ void initAudioDriver() { void getInternalAudioFormat(AudioFormat * inAudioFormat, AudioFormat * outAudioFormat) { - /*TODO add #define for integer version */ - /* take the input format... */ copyAudioFormat(outAudioFormat,inAudioFormat); - /* .. change to 32 bit integers with 28 bit resolution */ + /* .. change to 32 bit integers with 28 bit fractional part */ outAudioFormat->bits = 32; outAudioFormat->fracBits = 28; - /* if forced output sample rate - use that as internal sample rate */ - if(audio_configFormat && (audio_configFormat->sampleRate != 0)) - outAudioFormat->sampleRate = audio_configFormat->sampleRate; } void getOutputAudioFormat(AudioFormat * inAudioFormat, @@ -208,7 +203,7 @@ int parseAudioConfig(AudioFormat * audioFormat, char * conf) { return -1; } - /* audioFormat is never shifted */ + /* The output audio format is never shifted */ audioFormat->fracBits = 0; return 0; diff --git a/src/pcm_utils.c b/src/pcm_utils.c index e92089f31..8454c8871 100644 --- a/src/pcm_utils.c +++ b/src/pcm_utils.c @@ -78,12 +78,16 @@ void pcm_convertToIntWithDither(int bits, const mpd_fixed_t max = (1L << (fracBits)) - 1; const mpd_fixed_t min = ~0L << (fracBits); mpd_fixed_t sample; + /* need to split in two cases to avoid negative shifting */ if(bits>fracBits) { /* left shift - no need to dither */ while(samples--) { sample = *buffer; - sample = sample>max ? max : (sample<min ? min : sample); + if(sample>max) + sample = max; + else if(sample<min) + sample = min; *buffer++ = sample << (bits - fracBits - 1); } } @@ -92,7 +96,10 @@ void pcm_convertToIntWithDither(int bits, while(samples--) { sample = *buffer + half + (ditherRandom[0] & mask) - (ditherRandom[1] & mask); - sample = sample>max ? max : (sample<min ? min : sample); + if(sample>max) + sample = max; + else if(sample<min) + sample = min; *buffer++ = sample >> (fracBits - bits + 1); ditherRandom[1] = ditherRandom[0] >> 1; ditherRandom[0] = prng(ditherRandom[0]); @@ -232,47 +239,52 @@ void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format, int volume) { mpd_fixed_t * buffer32 = (mpd_fixed_t *)buffer; - int iScale; - int samples; - int shift; + int samples = bufferSize >> 2; + static int iScale; + static int shift; + static int currentVolume = -1; if(format->bits!=32 || format->fracBits == 0) { - ERROR("Only 32 bit mpd_fixed_t samples are supported in pcm_volumeChange!\n"); + ERROR("Only 32 bit mpd_fixed_t samples are supported in" + " pcm_volumeChange!\n"); exit(EXIT_FAILURE); } /* take care of full and no volume cases */ - if(volume>=1000) return; + if(volume>=1024) return; if(volume<=0) { memset(buffer,0,bufferSize); return; } - /****** change volume ******/ - samples = bufferSize >> 2; - iScale = (mpd_uint32)(volume * 256) / 1000; - shift = 8; - - /* lower shifting value as much as possible */ - while(!(iScale & 1) && shift) { - iScale >>= 1; - shift--; + /* recalculate if volume has changed */ + if(volume != currentVolume) { + currentVolume = volume; + iScale = volume; + shift = 10; + + /* Minimize values to get the precision loss as small as + * possible in the integer calculations. Make iScale less + * then 5 bits. This results in a volume change precision + * of approx. 0.5dB */ + while((iScale>31 || !(iScale & 1)) && shift) { + iScale >>= 1; + shift--; + } } - /* change */ - if(iScale == 1) { + + /* change the volume */ + if(iScale == 1) while(samples--) { *buffer32 = *buffer32 >> shift; buffer32++; } - } - else { + else while(samples--) { *buffer32 = (*buffer32 >> shift) * iScale; buffer32++; } - } - } void pcm_add(char * buffer1, char * buffer2, size_t bufferSize1, @@ -281,29 +293,33 @@ void pcm_add(char * buffer1, char * buffer2, size_t bufferSize1, mpd_fixed_t * buffer32_1 = (mpd_fixed_t *)buffer1; mpd_fixed_t * buffer32_2 = (mpd_fixed_t *)buffer2; mpd_fixed_t temp; - int samples1; - int samples2; - int iScale1; - int iScale2; - int shift; + int samples1 = bufferSize1 >> 2; + int samples2 = bufferSize2 >> 2; + int iScale1 = vol1 >> 2; + int iScale2 = vol2 >> 2; + int shift = 8; if(format->bits!=32 || format->fracBits==0 ) { - ERROR("Only 32 bit mpd_fixed_t samples are supported in pcm_add!\n"); + ERROR("Only 32 bit mpd_fixed_t samples are supported in" + " pcm_add!\n"); exit(EXIT_FAILURE); } - samples1 = bufferSize1 >> 2; - samples2 = bufferSize1 >> 2; - iScale1 = (mpd_uint32)(vol1 * 256) / 1000; - iScale2 = (mpd_uint32)(vol2 * 256) / 1000; - shift = 8; - + /* lower iScale to minimize audio resolution loss */ + /* as long as it can be done without loss */ + while(!(iScale1 & 1) && !(iScale2 & 1) && shift) { + iScale1 >>= 1; + iScale2 >>= 1; + shift--; + } + /* scale and add samples */ /* no check for overflow needed - we trust our headroom is enough */ while(samples1 && samples2) { temp = (*buffer32_1 >> shift) * iScale1 + (*buffer32_2 >> shift) * iScale2; - *buffer32_1++ = temp; + *buffer32_1 = temp; + buffer32_1++; buffer32_2++; } /* take care of case where buffer2 > buffer1 */ @@ -319,10 +335,10 @@ void pcm_mix(char * buffer1, char * buffer2, size_t bufferSize1, float s = sin(M_PI_2*portion1); s*=s; - vol1 = s*1000+0.5; - vol1 = vol1>1000 ? 1000 : ( vol1<0 ? 0 : vol1 ); + vol1 = s*1024+0.5; + vol1 = vol1>1024 ? 1024 : ( vol1<0 ? 0 : vol1 ); - pcm_add(buffer1,buffer2,bufferSize1,bufferSize2,vol1,1000-vol1,format); + pcm_add(buffer1,buffer2,bufferSize1,bufferSize2,vol1,1024-vol1,format); } diff --git a/src/player.c b/src/player.c index e398323e8..d0d9a2764 100644 --- a/src/player.c +++ b/src/player.c @@ -417,7 +417,7 @@ void setPlayerCrossFade(float crossFadeInSeconds) { void setPlayerSoftwareVolume(int volume) { PlayerControl * pc; - volume = (volume>1000) ? 1000 : (volume<0 ? 0 : volume); + volume = (volume>1024) ? 1024 : (volume<0 ? 0 : volume); pc = &(getPlayerData()->playerControl); diff --git a/src/playerData.c b/src/playerData.c index 281453548..c9472a5bd 100644 --- a/src/playerData.c +++ b/src/playerData.c @@ -129,7 +129,7 @@ void initPlayerData() { memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN+1); memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN+1); playerData_pd->playerControl.crossFade = crossfade; - playerData_pd->playerControl.softwareVolume = 1000; + playerData_pd->playerControl.softwareVolume = 1024; playerData_pd->playerControl.totalPlayTime = 0; playerData_pd->playerControl.decode_pid = 0; playerData_pd->playerControl.metadataState = diff --git a/src/replayGain.c b/src/replayGain.c index ace70b0e5..308ea7054 100644 --- a/src/replayGain.c +++ b/src/replayGain.c @@ -108,17 +108,18 @@ void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize, AudioFormat * format) { mpd_sint32 * buffer32 = (mpd_sint32 *)buffer; - int samples; - int shift; - int iScale; + int samples = bufferSize >> 2; + int iScale = info->iScale; + int shift = info->shift; - if(format->bits!=32 || format->channels!=2 ) { - ERROR("Only 32 bit stereo is supported for doReplayGain!\n"); + if(replayGainState == REPLAYGAIN_OFF || !info) return; + + if(format->bits!=32 || format->fracBits==0 ) { + ERROR("Only 32 bit mpd_fixed_t samples are supported in" + " doReplayGain!\n"); exit(EXIT_FAILURE); return; } - - if(replayGainState == REPLAYGAIN_OFF || !info) return; if(info->scale < 0) { switch(replayGainState) { @@ -131,13 +132,26 @@ void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize, info->albumPeak); break; } - } + + /* Calculate integer scale and shift to use in + * integer calculations. Make iScale as small as + * possible and no more then 5 bits. This gives a + * precision of approx. 0.5 dB */ + iScale = info->scale * 1024; + shift = 10; - samples = bufferSize >> 2; - /* 64 steps is enough - gives 0.13db resolution at 0dB and 2.5dB at -25dB*/ - iScale = info->scale * 64; - shift = 6; + while((iScale>31 || !(iScale & 1)) && shift) { + iScale >>= 1; + shift--; + } + info->iScale = iScale; + info->shift = shift; + + /*ERROR("Info: ReplayGain scale %f gives iScale=%i and shift=%i" + " resulting in %f\n", + info->scale, iScale, shift, (float)iScale / (1<<shift));*/ + } /* handle negative or zero scale */ if(iScale<=0) { @@ -145,14 +159,9 @@ void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize, return; } - /* lower shift value as much as possible */ - while(!(iScale & 1) && shift) { - iScale >>= 1; - shift--; - } - + /* change samples */ - /* no check for overflow needed - replaygain peak info prevent + /* no overflow check needed - replaygain peak info prevent * clipping and we have 3 headroom bits in our 32 bit samples */ if(iScale == 1) { while(samples--) { diff --git a/src/replayGain.h b/src/replayGain.h index 112034fbe..22728ef2d 100644 --- a/src/replayGain.h +++ b/src/replayGain.h @@ -34,6 +34,8 @@ typedef struct _ReplayGainInfo { /* used internally by mpd, to mess with it*/ float scale; + int iScale; + int shift; } ReplayGainInfo; ReplayGainInfo * newReplayGainInfo(); diff --git a/src/volume.c b/src/volume.c index c16938042..b99bd9156 100644 --- a/src/volume.c +++ b/src/volume.c @@ -433,9 +433,9 @@ int changeSoftwareVolume(FILE * fp, int change, int rel) { volume_softwareSet = new; /*new = 100.0*(exp(new/50.0)-1)/(M_E*M_E-1)+0.5;*/ - if(new>=100) new = 1000; + if(new>=100) new = 1024; else if(new<=0) new = 0; - else new = 1000.0*(exp(new/25.0)-1)/(54.5981500331F-1)+0.5; + else new = 1024.0*(exp(new/25.0)-1)/(54.5981500331F-1)+0.5; setPlayerSoftwareVolume(new); |