diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2013-10-07 12:18:16 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2013-10-07 12:18:16 +0000 |
| commit | 6a8185ef6679cc329a5fde14bfe97eadca0d2f91 (patch) | |
| tree | b3a862160efc964f10ca3690523b47a55b054c2f | |
| parent | 803d0ca7c17bfddde8d74ab914ebc519f66bb50d (diff) | |
| download | qmmp-6a8185ef6679cc329a5fde14bfe97eadca0d2f91.tar.gz qmmp-6a8185ef6679cc329a5fde14bfe97eadca0d2f91.tar.bz2 qmmp-6a8185ef6679cc329a5fde14bfe97eadca0d2f91.zip | |
prepare for new replaygain implementation
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@3753 90c681e8-e032-0410-971d-27865f9a5e38
| -rw-r--r-- | src/plugins/General/rgscan/rgscaner.cpp | 29 | ||||
| -rw-r--r-- | src/plugins/Input/mad/decoder_mad.cpp | 140 | ||||
| -rw-r--r-- | src/plugins/Input/mad/decoder_mad.h | 3 | ||||
| -rw-r--r-- | src/qmmp/decoder.cpp | 5 | ||||
| -rw-r--r-- | src/qmmp/decoder.h | 1 | ||||
| -rw-r--r-- | src/qmmp/qmmpaudioengine.cpp | 4 | ||||
| -rw-r--r-- | src/qmmp/replaygain.cpp | 91 | ||||
| -rw-r--r-- | src/qmmp/replaygain_p.h | 11 |
8 files changed, 193 insertions, 91 deletions
diff --git a/src/plugins/General/rgscan/rgscaner.cpp b/src/plugins/General/rgscan/rgscaner.cpp index 069a4e0da..0fc2e3833 100644 --- a/src/plugins/General/rgscan/rgscaner.cpp +++ b/src/plugins/General/rgscan/rgscaner.cpp @@ -22,6 +22,7 @@ #include <stdint.h> #include <QStringList> #include <QThread> +#include <math.h> #include <qmmp/inputsourcefactory.h> #include <qmmp/decoderfactory.h> #include "rgscaner.h" @@ -143,14 +144,14 @@ void RGScaner::run() const int buf_size = 8192; //samples AudioParameters ap = m_decoder->audioParameters(); //Qmmp::AudioFormat format = ap.format(); - unsigned char output_buf[buf_size]; + float output_buf[buf_size]; qint64 output_at = 0; qint64 total = 0; qint64 len = 0; - qint64 totalSize = m_decoder->totalTime() * ap.sampleRate() * ap.channels() * ap.sampleSize() / 1000; - qint32 max = 0; - double out_left[buf_size/4]; - double out_right[buf_size/4]; + qint64 totalSamples = m_decoder->totalTime() * ap.sampleRate() * ap.channels() / 1000; + float max = 0; + double out_left[buf_size/2]; + double out_right[buf_size/2]; if(m_handle) @@ -164,22 +165,22 @@ void RGScaner::run() forever { // decode - len = m_decoder->read((char *)(output_buf + output_at), buf_size - output_at); + len = m_decoder->read((float *)(output_buf + output_at), buf_size - output_at); if (len > 0) { output_at += len; total += len; - emit progress(100 * total / totalSize); + emit progress(100 * total / totalSamples); - for(int i = 0; i < len/4; ++i) + for(int i = 0; i < len/2; ++i) { - out_left[i] = ((short *) output_buf)[i*2]; - out_right[i] = ((short *) output_buf)[i*2+1]; - max = qMax(abs(out_left[i]), max); - max = qMax(abs(out_right[i]), max); + out_left[i] = output_buf[i*2]*32767.0; + out_right[i] = output_buf[i*2+1]*32767.0; + max = qMax(fabs(out_left[i]), (double)max); + max = qMax(fabs(out_right[i]), (double)max); } - AnalyzeSamples(m_handle, out_left, out_right, len/4, 2); + AnalyzeSamples(m_handle, out_left, out_right, len/2, 2); output_at = 0; } @@ -196,7 +197,7 @@ void RGScaner::run() } m_gain = GetTitleGain(m_handle); - m_peak = max / 32768.0; + m_peak = max/32767.0; qDebug("peak = %f", m_peak); qDebug("RGScaner: thread %ld finished", QThread::currentThreadId()); m_is_running = false; diff --git a/src/plugins/Input/mad/decoder_mad.cpp b/src/plugins/Input/mad/decoder_mad.cpp index 331453362..b4087c06b 100644 --- a/src/plugins/Input/mad/decoder_mad.cpp +++ b/src/plugins/Input/mad/decoder_mad.cpp @@ -340,48 +340,18 @@ int DecoderMAD::bitrate() qint64 DecoderMAD::read(char *data, qint64 size) { - forever - { - if(((m_stream.error == MAD_ERROR_BUFLEN) || !m_stream.buffer) && !m_eof) - { - m_eof = !fillBuffer(); - } - if(mad_frame_decode(&m_frame, &m_stream) < 0) - { - switch((int) m_stream.error) - { - case MAD_ERROR_LOSTSYNC: - { - //skip ID3v2 tag - uint tagSize = findID3v2((uchar *)m_stream.this_frame, - (ulong) (m_stream.bufend - m_stream.this_frame)); - if (tagSize > 0) - { - mad_stream_skip(&m_stream, tagSize); - qDebug("DecoderMAD: %d bytes skipped", tagSize); - } - continue; - } - case MAD_ERROR_BUFLEN: - if(m_eof) - return 0; - continue; - default: - if (!MAD_RECOVERABLE(m_stream.error)) - return 0; - else - continue; - } - } - if(m_skip_frames) - { - m_skip_frames--; - continue; - } - mad_synth_frame(&m_synth, &m_frame); + if(decodeFrame()) return madOutput(data, size); - } + return 0; } + +qint64 DecoderMAD::read(float *data, qint64 samples) +{ + if(decodeFrame()) + return madOutputFloat(data, samples); + return 0; +} + void DecoderMAD::seek(qint64 pos) { if(m_totalTime > 0) @@ -508,12 +478,58 @@ long DecoderMAD::audio_linear_round(unsigned int bits, mad_fixed_t sample) return sample >> (MAD_F_FRACBITS + 1 - bits); } +bool DecoderMAD::decodeFrame() +{ + forever + { + if(((m_stream.error == MAD_ERROR_BUFLEN) || !m_stream.buffer) && !m_eof) + { + m_eof = !fillBuffer(); + } + if(mad_frame_decode(&m_frame, &m_stream) < 0) + { + switch((int) m_stream.error) + { + case MAD_ERROR_LOSTSYNC: + { + //skip ID3v2 tag + uint tagSize = findID3v2((uchar *)m_stream.this_frame, + (ulong) (m_stream.bufend - m_stream.this_frame)); + if (tagSize > 0) + { + mad_stream_skip(&m_stream, tagSize); + qDebug("DecoderMAD: %d bytes skipped", tagSize); + } + continue; + } + case MAD_ERROR_BUFLEN: + if(m_eof) + return false; + continue; + default: + if (!MAD_RECOVERABLE(m_stream.error)) + return false; + else + continue; + } + } + if(m_skip_frames) + { + m_skip_frames--; + continue; + } + mad_synth_frame(&m_synth, &m_frame); + break; + } + return true; +} + qint64 DecoderMAD::madOutput(char *data, qint64 size) { - unsigned int samples, channels; + unsigned int samples_per_channel, channels; mad_fixed_t const *left, *right; - samples = m_synth.pcm.length; + samples_per_channel = m_synth.pcm.length; channels = m_synth.pcm.channels; left = m_synth.pcm.samples[0]; right = m_synth.pcm.samples[1]; @@ -521,13 +537,13 @@ qint64 DecoderMAD::madOutput(char *data, qint64 size) m_output_at = 0; m_output_bytes = 0; - if(samples * channels * 2 > size) + if(samples_per_channel * channels * 2 > size) { qWarning("DecoderMad: input buffer is too small"); - samples = size / channels / 2; + samples_per_channel = size / channels / 2; } - while (samples--) + while (samples_per_channel--) { signed int sample; #ifdef USE_DITHERING @@ -553,3 +569,37 @@ qint64 DecoderMAD::madOutput(char *data, qint64 size) } return m_output_bytes; } + +qint64 DecoderMAD::madOutputFloat(float *data, qint64 samples) +{ + float *data_it = data; + unsigned int samples_per_channel, channels; + mad_fixed_t const *left, *right; + + samples_per_channel = m_synth.pcm.length; + channels = m_synth.pcm.channels; + left = m_synth.pcm.samples[0]; + right = m_synth.pcm.samples[1]; + m_bitrate = m_frame.header.bitrate / 1000; + m_output_at = 0; + m_output_bytes = 0; + qint64 output_samples = 0; + + if(samples_per_channel * channels > samples) + { + qWarning("DecoderMad: input buffer is too small"); + samples_per_channel = samples / channels; + } + + while (samples_per_channel--) + { + *data_it++ = mad_f_todouble(*left++); + output_samples++; + if (channels == 2) + { + *data_it++ = mad_f_todouble(*right++); + output_samples++; + } + } + return output_samples; +} diff --git a/src/plugins/Input/mad/decoder_mad.h b/src/plugins/Input/mad/decoder_mad.h index 002caa53d..d15508848 100644 --- a/src/plugins/Input/mad/decoder_mad.h +++ b/src/plugins/Input/mad/decoder_mad.h @@ -46,11 +46,14 @@ public: qint64 totalTime(); int bitrate(); qint64 read(char *data, qint64 size); + qint64 read(float *data, qint64 samples); void seek(qint64); private: // helper functions + bool decodeFrame(); qint64 madOutput(char *data, qint64 size); + qint64 madOutputFloat(float *data, qint64 samples); bool fillBuffer(); void deinit(); bool findHeader(); diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp index 7f5c4b9be..9b48c6a35 100644 --- a/src/qmmp/decoder.cpp +++ b/src/qmmp/decoder.cpp @@ -36,6 +36,11 @@ void Decoder::configure(quint32 srate, int chan, Qmmp::AudioFormat format) m_parameters = AudioParameters(srate, chan, format); } +qint64 Decoder::read(float *data, qint64 samples) +{ + return -1; +} + void Decoder::next() {} diff --git a/src/qmmp/decoder.h b/src/qmmp/decoder.h index 76e8445ac..d568aacbe 100644 --- a/src/qmmp/decoder.h +++ b/src/qmmp/decoder.h @@ -55,6 +55,7 @@ public: * Subclass should reimplement this function. */ virtual qint64 read(char *data, qint64 maxSize) = 0; + virtual qint64 read(float *data, qint64 samples); /*! * Returns current bitrate (in kbps). * Subclass should reimplement this function. diff --git a/src/qmmp/qmmpaudioengine.cpp b/src/qmmp/qmmpaudioengine.cpp index 8307ebf2e..4cd25e05f 100644 --- a/src/qmmp/qmmpaudioengine.cpp +++ b/src/qmmp/qmmpaudioengine.cpp @@ -282,7 +282,7 @@ qint64 QmmpAudioEngine::produceSound(char *data, qint64 size, quint32 brate) { Buffer *b = m_output->recycler()->get(); uint sz = size < m_bks ? size : m_bks; - m_replayGain->applyReplayGain(data, sz); + //m_replayGain->applyReplayGain(data, sz); memcpy(b->data, data, sz); b->nbytes = sz; b->rate = brate; @@ -594,6 +594,8 @@ void QmmpAudioEngine::prepareEffects(Decoder *d) { m_ap = d->audioParameters(); + m_replayGain->configure(m_ap); + foreach(Effect *e, m_effects) //remove disabled and external effects { if(!e->factory() || !Effect::isEnabled(e->factory())) diff --git a/src/qmmp/replaygain.cpp b/src/qmmp/replaygain.cpp index 2653edc2e..7e309b2f3 100644 --- a/src/qmmp/replaygain.cpp +++ b/src/qmmp/replaygain.cpp @@ -19,22 +19,32 @@ ***************************************************************************/ #include <math.h> +#include "buffer.h" #include "replaygain_p.h" ReplayGain::ReplayGain() { - m_sampleSize = 2; m_scale = 1.0; m_mode = QmmpSettings::REPLAYGAIN_DISABLED; + m_format = Qmmp::PCM_UNKNOWM; m_preamp = 0.0; m_default_gain = 0.0; + m_prebuf = 0; m_prevent_clipping = false; } -void ReplayGain::setSampleSize(int size) +ReplayGain::~ReplayGain() { - m_sampleSize = size; - updateScale(); + if(m_prebuf) + delete [] m_prebuf; +} + +void ReplayGain::configure(const AudioParameters &p) +{ + m_format = p.format(); + if(m_prebuf) + delete [] m_prebuf; + m_prebuf = new float[QMMP_BLOCK_FRAMES * p.channels() * 4]; } void ReplayGain::setReplayGainInfo(const QMap<Qmmp::ReplayGainKey, double> &info) @@ -54,6 +64,56 @@ void ReplayGain::setReplayGainInfo(const QMap<Qmmp::ReplayGainKey, double> &info qDebug("ReplayGain: disabled"); } +qint64 ReplayGain::read(Decoder *decoder, char *data, qint64 size) +{ + if(m_mode == QmmpSettings::REPLAYGAIN_DISABLED || m_scale == 1.0) + return decoder->read(data, size); + + qint64 samples = 0; + + switch (m_format) + { + case Qmmp::PCM_S8: + samples = decoder->read(m_prebuf, size); + break; + case Qmmp::PCM_S16LE: + samples = decoder->read(m_prebuf, size >> 1); + break; + case Qmmp::PCM_S24LE: + samples = decoder->read(m_prebuf, size >> 2); + break; + case Qmmp::PCM_S32LE: + samples = decoder->read(m_prebuf, size >> 2); + break; + default: + break; + } + + for(qint64 i = 0; i < samples; ++i) + { + m_prebuf[i] *= m_scale; + m_prebuf[i] = qBound((float)-1.0, m_prebuf[i], (float)1.0); + + switch (m_format) + { + case Qmmp::PCM_S8: + ((char*)data)[i] = m_prebuf[i] * 127.0; + break; + case Qmmp::PCM_S16LE: + ((short*)data)[i] = m_prebuf[i] * 32767.0; + break; + case Qmmp::PCM_S24LE: + ((qint32*)data)[i] = m_prebuf[i] * 32767.0; + break; + case Qmmp::PCM_S32LE: + ((qint32*)data)[i] = m_prebuf[i] * 32767.0; + break; + default: + break; + } + } +} + void ReplayGain::updateSettings(QmmpSettings::ReplayGainMode mode, double preamp, double default_gain, bool clip) { @@ -64,29 +124,6 @@ void ReplayGain::updateSettings(QmmpSettings::ReplayGainMode mode, double preamp setReplayGainInfo(m_info); } -void ReplayGain::applyReplayGain(char *data, qint64 size) -{ - if(m_mode == QmmpSettings::REPLAYGAIN_DISABLED || m_scale == 1.0) - return; - size = size/m_sampleSize; - if(m_sampleSize == 2) - { - for (qint64 i = 0; i < size; i++) - ((short*)data)[i]*= m_scale; - - } - else if(m_sampleSize == 1) - { - for (qint64 i = 0; i < size; i++) - ((char*)data)[i]*= m_scale; - } - else if(m_sampleSize == 4) - { - for (qint64 i = 0; i < size; i++) - ((qint32*)data)[i]*= m_scale; - } -} - void ReplayGain::updateScale() { double peak = 0.0; diff --git a/src/qmmp/replaygain_p.h b/src/qmmp/replaygain_p.h index b219f51ee..46fc1da62 100644 --- a/src/qmmp/replaygain_p.h +++ b/src/qmmp/replaygain_p.h @@ -23,6 +23,7 @@ #include <QtGlobal> #include <QMap> +#include "decoder.h" #include "qmmpsettings.h" #include "qmmp.h" @@ -33,22 +34,24 @@ class ReplayGain { public: ReplayGain(); + ~ReplayGain(); - void setSampleSize(int size); + void configure(const AudioParameters &p); void updateSettings(QmmpSettings::ReplayGainMode mode, double preamp, double default_gain, bool clip); void setReplayGainInfo(const QMap<Qmmp::ReplayGainKey, double> &info); - void applyReplayGain(char *data, qint64 size); + qint64 read(Decoder *decoder, char *data, qint64 size); private: void updateScale(); - int m_sampleSize; QMap<Qmmp::ReplayGainKey, double> m_info; - double m_scale; QmmpSettings::ReplayGainMode m_mode; + double m_scale; double m_preamp; double m_default_gain; + float *m_prebuf; bool m_prevent_clipping; + int m_format; }; #endif // REPLAYGAIN_H |
