src/3rdparty/phonon/ds9/volumeeffect.cpp
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5 This library is free software: you can redistribute it and/or modify
       
     6 it under the terms of the GNU Lesser General Public License as published by
       
     7 the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9 This library is distributed in the hope that it will be useful,
       
    10 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 GNU Lesser General Public License for more details.
       
    13 
       
    14 You should have received a copy of the GNU Lesser General Public License
       
    15 along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 #include "volumeeffect.h"
       
    19 #include "qbasefilter.h"
       
    20 #include "qmeminputpin.h"
       
    21 
       
    22 #include <QtCore/qmath.h> //for sqrt
       
    23 
       
    24 QT_BEGIN_NAMESPACE
       
    25 
       
    26 #ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
       
    27 
       
    28 
       
    29 namespace Phonon
       
    30 {
       
    31     namespace DS9
       
    32     {
       
    33         /**************************************************************************
       
    34         * curve functions
       
    35         *************************************************************************/
       
    36 
       
    37         static qreal curveValueFadeIn3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    38         {
       
    39             return (fadeStart + fadeDiff * sqrt(completed));
       
    40         }
       
    41         static qreal curveValueFadeOut3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    42         {
       
    43             return (fadeStart + fadeDiff * (1.0 - sqrt(1.0 - completed)));
       
    44         }
       
    45         // in == out for a linear fade
       
    46         static qreal curveValueFade6dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    47         {
       
    48             return (fadeStart + fadeDiff * completed);
       
    49         }
       
    50         static qreal curveValueFadeIn9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    51         {
       
    52             return (fadeStart + fadeDiff * pow(completed, 1.5));
       
    53         }
       
    54         static qreal curveValueFadeOut9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    55         {
       
    56             return (fadeStart + fadeDiff * (1.0 - pow(1.0 - completed, 1.5)));
       
    57         }
       
    58         static qreal curveValueFadeIn12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    59         {
       
    60             return (fadeStart + fadeDiff * completed * completed);
       
    61         }
       
    62         static qreal curveValueFadeOut12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
       
    63         {
       
    64             const qreal x = 1.0 - completed;
       
    65             return (fadeStart + fadeDiff * (1.0 - x * x));
       
    66         }
       
    67 
       
    68         static const QVector<AM_MEDIA_TYPE> audioMediaType()
       
    69         {
       
    70             QVector<AM_MEDIA_TYPE> ret;
       
    71             AM_MEDIA_TYPE mt = { MEDIATYPE_Audio, MEDIASUBTYPE_PCM, 1, 0, 1, GUID_NULL, 0, 0, 0};
       
    72             ret << mt;
       
    73             return ret;
       
    74         }
       
    75 
       
    76         class VolumeMemInputPin : public QMemInputPin
       
    77         {
       
    78         public:
       
    79             VolumeMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, QPin *output) : QMemInputPin(parent, mt, true /*transform*/, output)
       
    80             {
       
    81             }
       
    82 
       
    83             ~VolumeMemInputPin()
       
    84             {
       
    85             }
       
    86 
       
    87             STDMETHODIMP NotifyAllocator(IMemAllocator *alloc, BOOL b)
       
    88             {
       
    89                 ALLOCATOR_PROPERTIES prop;
       
    90                 HRESULT hr = alloc->GetProperties(&prop);
       
    91                 if (SUCCEEDED(hr) && prop.cBuffers > 1) {
       
    92                     //this allows to reduce the latency for sound
       
    93                     //the problem is that too low numbers makes the whole thing fail...
       
    94                     ALLOCATOR_PROPERTIES actual;
       
    95                     prop.cBuffers = 1;
       
    96                     alloc->SetProperties(&prop, &actual);
       
    97                 }
       
    98                 return QMemInputPin::NotifyAllocator(alloc, b);
       
    99             }
       
   100 
       
   101         };
       
   102 
       
   103         class VolumeMemOutputPin : public QPin
       
   104         {
       
   105         public:
       
   106             VolumeMemOutputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt) : QPin(parent, PINDIR_OUTPUT, mt)
       
   107             {
       
   108             }
       
   109 
       
   110             ~VolumeMemOutputPin()
       
   111             {
       
   112             }
       
   113 
       
   114         };
       
   115 
       
   116         class VolumeEffectFilter : public QBaseFilter
       
   117         {
       
   118         public:
       
   119             VolumeEffectFilter(VolumeEffect *);
       
   120 
       
   121             //reimplementation
       
   122             virtual HRESULT processSample(IMediaSample *);
       
   123 
       
   124         private:
       
   125             void treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency);
       
   126 
       
   127             QMemInputPin *m_input;
       
   128             QPin *m_output;
       
   129             VolumeEffect *m_volumeEffect;
       
   130         };
       
   131 
       
   132         VolumeEffectFilter::VolumeEffectFilter(VolumeEffect *ve) : QBaseFilter(CLSID_NULL),
       
   133             m_volumeEffect(ve)
       
   134         {
       
   135             QVector<AM_MEDIA_TYPE> mt;
       
   136 
       
   137             //creating the output
       
   138             m_output = new VolumeMemOutputPin(this, mt);
       
   139 
       
   140             //then creating the input
       
   141             mt << audioMediaType();
       
   142             m_input = new VolumeMemInputPin(this, mt, m_output);
       
   143         }
       
   144 
       
   145         void VolumeEffectFilter::treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency)
       
   146         {
       
   147             float volume = m_volumeEffect->volume();
       
   148             if (m_volumeEffect->m_fading) {
       
   149                 const qreal lastSample = m_volumeEffect->m_fadeDuration * frequency / 1000;
       
   150                 const qreal completed = qreal(m_volumeEffect->m_fadeSamplePosition++) / lastSample;
       
   151 
       
   152                 if (qFuzzyCompare(completed, qreal(1.))) {
       
   153                     m_volumeEffect->setVolume(m_volumeEffect->m_targetVolume);
       
   154                     m_volumeEffect->m_fading = false; //we end the fading effect
       
   155                 } else {
       
   156                     volume = m_volumeEffect->m_fadeCurveFn(m_volumeEffect->m_initialVolume, 
       
   157                         m_volumeEffect->m_targetVolume - m_volumeEffect->m_initialVolume,
       
   158                         completed);
       
   159                 }
       
   160             }
       
   161 
       
   162             for(int c = 0; c < channelCount; ++c) {
       
   163                 switch (sampleSize)
       
   164                 {
       
   165                 case 2:
       
   166                     {
       
   167                         short *shortBuffer = reinterpret_cast<short*>(*buffer);
       
   168                         *shortBuffer *= qRound(volume);
       
   169                     }
       
   170                     break;
       
   171                 case 1:
       
   172                     **buffer *= qRound(volume);
       
   173                     break;
       
   174                 default:
       
   175                     break;
       
   176                 }
       
   177 
       
   178                 *buffer += sampleSize;
       
   179             }
       
   180         }
       
   181 
       
   182         HRESULT VolumeEffectFilter::processSample(IMediaSample * ms)
       
   183         {
       
   184             BYTE *buffer = 0;
       
   185             ms->GetPointer(&buffer);
       
   186             if (buffer) {
       
   187                 const AM_MEDIA_TYPE &mt = m_output->connectedType();
       
   188                 if (mt.formattype != FORMAT_WaveFormatEx) {
       
   189                     return VFW_E_INVALIDMEDIATYPE;
       
   190                 }
       
   191                 WAVEFORMATEX *format = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);
       
   192                 const int channelCount = format->nChannels;
       
   193                 const int sampleSize = format->wBitsPerSample / 8; //...in bytes
       
   194 
       
   195 
       
   196                 const BYTE *end = buffer + ms->GetActualDataLength();
       
   197                 while (buffer < end) {
       
   198                     treatOneSamplePerChannel(&buffer, sampleSize, channelCount, format->nSamplesPerSec);
       
   199                 }
       
   200             }
       
   201 
       
   202             return S_OK;
       
   203         }
       
   204 
       
   205         VolumeEffect::VolumeEffect(QObject *parent) : Effect(parent), 
       
   206             m_volume(1), m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel),
       
   207             m_fading(false), m_initialVolume(0), m_targetVolume(0), m_fadeDuration(0),
       
   208             m_fadeSamplePosition(0)
       
   209         {
       
   210             //creation of the effects
       
   211             for(int i = 0; i < FILTER_COUNT; ++i) {
       
   212                 VolumeEffectFilter *f = new VolumeEffectFilter(this);
       
   213                 m_filters[i] = Filter(f);
       
   214             }
       
   215         }
       
   216 
       
   217         float VolumeEffect::volume() const
       
   218         {
       
   219             return m_volume;
       
   220         }
       
   221 
       
   222         void VolumeEffect::setVolume(float newVolume)
       
   223         {
       
   224             m_volume = newVolume;
       
   225         }
       
   226 
       
   227         Phonon::VolumeFaderEffect::FadeCurve VolumeEffect::fadeCurve() const
       
   228         {
       
   229             return m_fadeCurve;
       
   230         }
       
   231 
       
   232         void VolumeEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve curve)
       
   233         {
       
   234             m_fadeCurve = curve;
       
   235         }
       
   236 
       
   237 
       
   238         void VolumeEffect::fadeTo(float vol, int duration)
       
   239         {
       
   240             m_fading = true; //will be set back to false when fading is finished
       
   241             m_targetVolume = vol;
       
   242             m_fadeSamplePosition = 0;
       
   243             m_initialVolume = m_volume;
       
   244             m_fadeDuration = duration;
       
   245 
       
   246             //in or out?
       
   247             const bool in = vol > m_volume;
       
   248 
       
   249             switch(m_fadeCurve)
       
   250             {
       
   251             case Phonon::VolumeFaderEffect::Fade6Decibel:
       
   252                 m_fadeCurveFn = curveValueFade6dB;
       
   253                 break;
       
   254             case Phonon::VolumeFaderEffect::Fade9Decibel:
       
   255                 if (in) {
       
   256                     m_fadeCurveFn = curveValueFadeIn9dB;
       
   257                 } else {
       
   258                     m_fadeCurveFn = curveValueFadeOut9dB;
       
   259                 }
       
   260                 break;
       
   261             case Phonon::VolumeFaderEffect::Fade12Decibel:
       
   262                 if (in) {
       
   263                     m_fadeCurveFn = curveValueFadeIn12dB;
       
   264                 } else {
       
   265                     m_fadeCurveFn = curveValueFadeOut12dB;
       
   266                 }
       
   267                 break;
       
   268             case Phonon::VolumeFaderEffect::Fade3Decibel:
       
   269             default:
       
   270                 if (in) {
       
   271                     m_fadeCurveFn = curveValueFadeIn3dB;
       
   272                 } else {
       
   273                     m_fadeCurveFn = curveValueFadeOut3dB;
       
   274                 }
       
   275                 break;
       
   276             }
       
   277         }
       
   278     }
       
   279 }
       
   280 
       
   281 #endif //QT_NO_PHONON_VOLUMEFADEREFFECT
       
   282 
       
   283 QT_END_NAMESPACE
       
   284 
       
   285 #include "moc_volumeeffect.cpp"