--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/3rdparty/phonon/ds9/volumeeffect.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,285 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "volumeeffect.h"
+#include "qbasefilter.h"
+#include "qmeminputpin.h"
+
+#include <QtCore/qmath.h> //for sqrt
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ /**************************************************************************
+ * curve functions
+ *************************************************************************/
+
+ static qreal curveValueFadeIn3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * sqrt(completed));
+ }
+ static qreal curveValueFadeOut3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * (1.0 - sqrt(1.0 - completed)));
+ }
+ // in == out for a linear fade
+ static qreal curveValueFade6dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * completed);
+ }
+ static qreal curveValueFadeIn9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * pow(completed, 1.5));
+ }
+ static qreal curveValueFadeOut9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * (1.0 - pow(1.0 - completed, 1.5)));
+ }
+ static qreal curveValueFadeIn12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * completed * completed);
+ }
+ static qreal curveValueFadeOut12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ const qreal x = 1.0 - completed;
+ return (fadeStart + fadeDiff * (1.0 - x * x));
+ }
+
+ static const QVector<AM_MEDIA_TYPE> audioMediaType()
+ {
+ QVector<AM_MEDIA_TYPE> ret;
+ AM_MEDIA_TYPE mt = { MEDIATYPE_Audio, MEDIASUBTYPE_PCM, 1, 0, 1, GUID_NULL, 0, 0, 0};
+ ret << mt;
+ return ret;
+ }
+
+ class VolumeMemInputPin : public QMemInputPin
+ {
+ public:
+ VolumeMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, QPin *output) : QMemInputPin(parent, mt, true /*transform*/, output)
+ {
+ }
+
+ ~VolumeMemInputPin()
+ {
+ }
+
+ STDMETHODIMP NotifyAllocator(IMemAllocator *alloc, BOOL b)
+ {
+ ALLOCATOR_PROPERTIES prop;
+ HRESULT hr = alloc->GetProperties(&prop);
+ if (SUCCEEDED(hr) && prop.cBuffers > 1) {
+ //this allows to reduce the latency for sound
+ //the problem is that too low numbers makes the whole thing fail...
+ ALLOCATOR_PROPERTIES actual;
+ prop.cBuffers = 1;
+ alloc->SetProperties(&prop, &actual);
+ }
+ return QMemInputPin::NotifyAllocator(alloc, b);
+ }
+
+ };
+
+ class VolumeMemOutputPin : public QPin
+ {
+ public:
+ VolumeMemOutputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt) : QPin(parent, PINDIR_OUTPUT, mt)
+ {
+ }
+
+ ~VolumeMemOutputPin()
+ {
+ }
+
+ };
+
+ class VolumeEffectFilter : public QBaseFilter
+ {
+ public:
+ VolumeEffectFilter(VolumeEffect *);
+
+ //reimplementation
+ virtual HRESULT processSample(IMediaSample *);
+
+ private:
+ void treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency);
+
+ QMemInputPin *m_input;
+ QPin *m_output;
+ VolumeEffect *m_volumeEffect;
+ };
+
+ VolumeEffectFilter::VolumeEffectFilter(VolumeEffect *ve) : QBaseFilter(CLSID_NULL),
+ m_volumeEffect(ve)
+ {
+ QVector<AM_MEDIA_TYPE> mt;
+
+ //creating the output
+ m_output = new VolumeMemOutputPin(this, mt);
+
+ //then creating the input
+ mt << audioMediaType();
+ m_input = new VolumeMemInputPin(this, mt, m_output);
+ }
+
+ void VolumeEffectFilter::treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency)
+ {
+ float volume = m_volumeEffect->volume();
+ if (m_volumeEffect->m_fading) {
+ const qreal lastSample = m_volumeEffect->m_fadeDuration * frequency / 1000;
+ const qreal completed = qreal(m_volumeEffect->m_fadeSamplePosition++) / lastSample;
+
+ if (qFuzzyCompare(completed, qreal(1.))) {
+ m_volumeEffect->setVolume(m_volumeEffect->m_targetVolume);
+ m_volumeEffect->m_fading = false; //we end the fading effect
+ } else {
+ volume = m_volumeEffect->m_fadeCurveFn(m_volumeEffect->m_initialVolume,
+ m_volumeEffect->m_targetVolume - m_volumeEffect->m_initialVolume,
+ completed);
+ }
+ }
+
+ for(int c = 0; c < channelCount; ++c) {
+ switch (sampleSize)
+ {
+ case 2:
+ {
+ short *shortBuffer = reinterpret_cast<short*>(*buffer);
+ *shortBuffer *= qRound(volume);
+ }
+ break;
+ case 1:
+ **buffer *= qRound(volume);
+ break;
+ default:
+ break;
+ }
+
+ *buffer += sampleSize;
+ }
+ }
+
+ HRESULT VolumeEffectFilter::processSample(IMediaSample * ms)
+ {
+ BYTE *buffer = 0;
+ ms->GetPointer(&buffer);
+ if (buffer) {
+ const AM_MEDIA_TYPE &mt = m_output->connectedType();
+ if (mt.formattype != FORMAT_WaveFormatEx) {
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+ WAVEFORMATEX *format = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);
+ const int channelCount = format->nChannels;
+ const int sampleSize = format->wBitsPerSample / 8; //...in bytes
+
+
+ const BYTE *end = buffer + ms->GetActualDataLength();
+ while (buffer < end) {
+ treatOneSamplePerChannel(&buffer, sampleSize, channelCount, format->nSamplesPerSec);
+ }
+ }
+
+ return S_OK;
+ }
+
+ VolumeEffect::VolumeEffect(QObject *parent) : Effect(parent),
+ m_volume(1), m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel),
+ m_fading(false), m_initialVolume(0), m_targetVolume(0), m_fadeDuration(0),
+ m_fadeSamplePosition(0)
+ {
+ //creation of the effects
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ VolumeEffectFilter *f = new VolumeEffectFilter(this);
+ m_filters[i] = Filter(f);
+ }
+ }
+
+ float VolumeEffect::volume() const
+ {
+ return m_volume;
+ }
+
+ void VolumeEffect::setVolume(float newVolume)
+ {
+ m_volume = newVolume;
+ }
+
+ Phonon::VolumeFaderEffect::FadeCurve VolumeEffect::fadeCurve() const
+ {
+ return m_fadeCurve;
+ }
+
+ void VolumeEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve curve)
+ {
+ m_fadeCurve = curve;
+ }
+
+
+ void VolumeEffect::fadeTo(float vol, int duration)
+ {
+ m_fading = true; //will be set back to false when fading is finished
+ m_targetVolume = vol;
+ m_fadeSamplePosition = 0;
+ m_initialVolume = m_volume;
+ m_fadeDuration = duration;
+
+ //in or out?
+ const bool in = vol > m_volume;
+
+ switch(m_fadeCurve)
+ {
+ case Phonon::VolumeFaderEffect::Fade6Decibel:
+ m_fadeCurveFn = curveValueFade6dB;
+ break;
+ case Phonon::VolumeFaderEffect::Fade9Decibel:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn9dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut9dB;
+ }
+ break;
+ case Phonon::VolumeFaderEffect::Fade12Decibel:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn12dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut12dB;
+ }
+ break;
+ case Phonon::VolumeFaderEffect::Fade3Decibel:
+ default:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn3dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut3dB;
+ }
+ break;
+ }
+ }
+ }
+}
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+
+#include "moc_volumeeffect.cpp"