src/3rdparty/phonon/mmf/effectfactory.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 33 3e2da88830cd
--- a/src/3rdparty/phonon/mmf/effectfactory.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/3rdparty/phonon/mmf/effectfactory.cpp	Fri Feb 19 23:40:16 2010 +0200
@@ -19,19 +19,13 @@
 #include <QObject>
 #include <QCoreApplication>
 
-#include <AudioEqualizerBase.h>
-#include <BassBoostBase.h>
-#include <DistanceAttenuationBase.h>
-#include <DopplerBase.h>
-#include <EnvironmentalReverbBase.h>
-#include <ListenerOrientationBase.h>
-#include <LocationBase.h>
-#include <LoudnessBase.h>
-#include <SourceOrientationBase.h>
-#include <StereoWideningBase.h>
+#include <mdaaudiooutputstream.h>
 
 #include "audioequalizer.h"
 #include "bassboost.h"
+#include "environmentalreverb.h"
+#include "loudness.h"
+#include "stereowidening.h"
 
 #include "effectfactory.h"
 
@@ -44,111 +38,176 @@
   \internal
 */
 
-QHash<QByteArray, QVariant> EffectFactory::constructEffectDescription(const QString &name,
-                                                                      const QString &description)
+EffectFactory::EffectFactory(QObject *parent)
+    :   QObject(parent)
+    ,   m_initialized(false)
 {
-    QHash<QByteArray, QVariant> retval;
 
-    retval.insert("name", name);
-    retval.insert("description", description);
-    retval.insert("available", true);
+}
 
-    return retval;
+EffectFactory::~EffectFactory()
+{
+
 }
 
+//-----------------------------------------------------------------------------
+// Public functions
+//-----------------------------------------------------------------------------
 
-QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type type)
-{
-    switch (type)
-    {
-        case AbstractAudioEffect::EffectAudioEqualizer:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Audio Equalizer"), "Audio equalizer.");
-        case AbstractAudioEffect::EffectBassBoost:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Bass Boost"), "Bass boost.");
-        case AbstractAudioEffect::EffectDistanceAttenuation:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Distance Attenuation"), "Distance Attenuation.");
-        case AbstractAudioEffect::EffectEnvironmentalReverb:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb.");
-        case AbstractAudioEffect::EffectListenerOrientation:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb.");
-        case AbstractAudioEffect::EffectLoudness:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Loudness"), "Loudness.");
-        case AbstractAudioEffect::EffectSourceOrientation:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Source Orientation"), "Source Orientation.");
-        case AbstractAudioEffect::EffectStereoWidening:
-            return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Stereo Widening"), "Stereo Widening.");
-    }
-
-    Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect type.");
-    return QHash<QByteArray, QVariant>();
-}
-
-AbstractAudioEffect *EffectFactory::createAudioEffect(AbstractAudioEffect::Type type,
+AbstractAudioEffect *EffectFactory::createAudioEffect(Type type,
                                                       QObject *parent)
 {
+    // Lazily initialize
+    if (!m_initialized)
+        initialize();
+
     Q_ASSERT(parent);
 
+    const QList<EffectParameter>& parameters = data(type).m_parameters;
+
+    AbstractAudioEffect *effect = 0;
+
     switch (type)
     {
-        case AbstractAudioEffect::EffectBassBoost:
-            return new BassBoost(parent);
-        case AbstractAudioEffect::EffectAudioEqualizer:
-            return new AudioEqualizer(parent);
-        case AbstractAudioEffect::EffectDistanceAttenuation:
-        case AbstractAudioEffect::EffectEnvironmentalReverb:
-        case AbstractAudioEffect::EffectListenerOrientation:
-        case AbstractAudioEffect::EffectLoudness:
-        case AbstractAudioEffect::EffectSourceOrientation:
-        case AbstractAudioEffect::EffectStereoWidening:
-            ;
+    case TypeBassBoost:
+        effect = new BassBoost(parent, parameters);
+        break;
+    case TypeAudioEqualizer:
+        effect = new AudioEqualizer(parent, parameters);
+        break;
+    case TypeEnvironmentalReverb:
+        effect = new EnvironmentalReverb(parent, parameters);
+        break;
+    case TypeLoudness:
+        effect = new Loudness(parent, parameters);
+        break;
+    case TypeStereoWidening:
+        effect = new StereoWidening(parent, parameters);
+        break;
+
+    // Not implemented
+    case TypeDistanceAttenuation:
+    case TypeListenerOrientation:
+    case TypeSourceOrientation:
+    // Fall through
+    default:
+        Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect");
     }
 
-    Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect.");
-    return 0;
+    return effect;
 }
 
-template<typename TEffect>
-bool isEffectSupported()
+QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(Type type)
 {
-    AudioPlayer audioPlayer;
+    // Lazily initialize
+    if (!m_initialized)
+        initialize();
 
-    QScopedPointer<TEffect> eff;
-    TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player())));
-
-    return errorCode != KErrNone;
+    return data(type).m_descriptions;
 }
 
 QList<int> EffectFactory::effectIndexes()
 {
-    QList<int> retval;
+    // Lazily initialize
+    if (!m_initialized)
+        initialize();
+
+    QList<int> result;
 
-    if (isEffectSupported<CAudioEqualizer>())
-        retval.append(AbstractAudioEffect::EffectAudioEqualizer);
+    QHash<Type, EffectData>::const_iterator i = m_effectData.begin();
+    for ( ; i != m_effectData.end(); ++i)
+        if (i.value().m_supported)
+            result.append(i.key());
+
+    return result;
+}
+
+//-----------------------------------------------------------------------------
+// Private functions
+//-----------------------------------------------------------------------------
 
-    if (isEffectSupported<CBassBoost>())
-        retval.append(AbstractAudioEffect::EffectBassBoost);
+#define INITIALIZE_EFFECT(Effect) \
+    { \
+    EffectData data = getData<Effect>(); \
+    m_effectData.insert(Type##Effect, data); \
+    }
 
-    /* We haven't implemented these yet.
-    if (isEffectSupported<CDistanceAttenuation>())
-        retval.append(AbstractAudioEffect::EffectDistanceAttenuation);
+void EffectFactory::initialize()
+{
+    Q_ASSERT_X(!m_initialized, Q_FUNC_INFO, "Already initialized");
 
-    if (isEffectSupported<CEnvironmentalReverb>())
-        retval.append(AbstractAudioEffect::EffectEnvironmentalReverb);
+    INITIALIZE_EFFECT(AudioEqualizer)
+    INITIALIZE_EFFECT(BassBoost)
+    INITIALIZE_EFFECT(EnvironmentalReverb)
+    INITIALIZE_EFFECT(Loudness)
+    INITIALIZE_EFFECT(StereoWidening)
+
+    m_initialized = true;
+}
 
-    if (isEffectSupported<CLoudness>())
-        retval.append(AbstractAudioEffect::EffectLoudness);
+// This class is just a wrapper which allows us to instantiate a
+// CMdaAudioOutputStream object.  This is done in order to allow the
+// effects API to query the DevSound implementation, to discover
+// which effects are supported and what parameters they take.
+// Ideally, we would use CMMFDevSound directly, but this class is not
+// available in the public S60 SDK.
+class OutputStreamFactory : public MMdaAudioOutputStreamCallback
+{
+public:
+    CMdaAudioOutputStream* create()
+    {
+        CMdaAudioOutputStream* stream = 0;
+        QT_TRAP_THROWING(stream = CMdaAudioOutputStream::NewL(*this));
+        return stream;
+    }
+private:
+    void MaoscOpenComplete(TInt /*aError*/) { }
+    void MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/) { }
+    void MaoscPlayComplete(TInt /*aError*/) { }
+};
 
-    if (isEffectSupported<CListenerOrientation>())
-        retval.append(AbstractAudioEffect::EffectListenerOrientation);
+template<typename BackendNode>
+EffectFactory::EffectData EffectFactory::getData()
+{
+    EffectData data;
+
+    // Create a temporary CMdaAudioOutputStream object, so that the effects
+    // API can query DevSound to discover which effects are supported.
+    OutputStreamFactory streamFactory;
+    QScopedPointer<CMdaAudioOutputStream> stream(streamFactory.create());
 
-    if (isEffectSupported<CSourceOrientation>())
-        retval.append(AbstractAudioEffect::EffectSourceOrientation);
+    EffectParameter param(
+         /* parameterId */        AbstractAudioEffect::ParameterEnable,
+         /* name */               tr("Enabled"),
+         /* hints */              EffectParameter::ToggledHint,
+         /* defaultValue */       QVariant(bool(true)));
+    data.m_parameters.append(param);
+
+    if (data.m_supported = BackendNode::getParameters
+            (stream.data(), data.m_parameters)) {
+        const QString description = QCoreApplication::translate
+            ("Phonon::MMF::EffectFactory", BackendNode::description());
+        data.m_descriptions.insert("name", description);
+        data.m_descriptions.insert("description", description);
+        data.m_descriptions.insert("available", true);
+    }
 
-    if (isEffectSupported<CStereoWidening>())
-        retval.append(AbstractAudioEffect::EffectStereoWidening);
-    */
+    // Sanity check to ensure that all parameter IDs are unique
+    QSet<int> ids;
+    foreach (param, data.m_parameters) {
+        Q_ASSERT_X(ids.find(param.id()) == ids.end(), Q_FUNC_INFO,
+            "Parameter list contains duplicates");
+        ids.insert(param.id());
+    }
 
-    return retval;
+    return data;
+}
+
+const EffectFactory::EffectData& EffectFactory::data(Type type) const
+{
+    QHash<Type, EffectData>::const_iterator i = m_effectData.find(type);
+    Q_ASSERT_X(i != m_effectData.end(), Q_FUNC_INFO, "Effect data not found");
+    return i.value();
 }
 
 QT_END_NAMESPACE