diff -r 000000000000 -r 1918ee327afb src/3rdparty/phonon/ds9/volumeeffect.cpp --- /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 . +*/ + +#include "volumeeffect.h" +#include "qbasefilter.h" +#include "qmeminputpin.h" + +#include //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 audioMediaType() + { + QVector 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 &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 &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 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(*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(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"