aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2013-10-07 12:18:16 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2013-10-07 12:18:16 +0000
commit6a8185ef6679cc329a5fde14bfe97eadca0d2f91 (patch)
treeb3a862160efc964f10ca3690523b47a55b054c2f
parent803d0ca7c17bfddde8d74ab914ebc519f66bb50d (diff)
downloadqmmp-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.cpp29
-rw-r--r--src/plugins/Input/mad/decoder_mad.cpp140
-rw-r--r--src/plugins/Input/mad/decoder_mad.h3
-rw-r--r--src/qmmp/decoder.cpp5
-rw-r--r--src/qmmp/decoder.h1
-rw-r--r--src/qmmp/qmmpaudioengine.cpp4
-rw-r--r--src/qmmp/replaygain.cpp91
-rw-r--r--src/qmmp/replaygain_p.h11
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