src/3rdparty/phonon/mmf/effectfactory.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 33 3e2da88830cd
equal deleted inserted replaced
3:41300fa6a67c 18:2f34d5167611
    17 */
    17 */
    18 
    18 
    19 #include <QObject>
    19 #include <QObject>
    20 #include <QCoreApplication>
    20 #include <QCoreApplication>
    21 
    21 
    22 #include <AudioEqualizerBase.h>
    22 #include <mdaaudiooutputstream.h>
    23 #include <BassBoostBase.h>
       
    24 #include <DistanceAttenuationBase.h>
       
    25 #include <DopplerBase.h>
       
    26 #include <EnvironmentalReverbBase.h>
       
    27 #include <ListenerOrientationBase.h>
       
    28 #include <LocationBase.h>
       
    29 #include <LoudnessBase.h>
       
    30 #include <SourceOrientationBase.h>
       
    31 #include <StereoWideningBase.h>
       
    32 
    23 
    33 #include "audioequalizer.h"
    24 #include "audioequalizer.h"
    34 #include "bassboost.h"
    25 #include "bassboost.h"
       
    26 #include "environmentalreverb.h"
       
    27 #include "loudness.h"
       
    28 #include "stereowidening.h"
    35 
    29 
    36 #include "effectfactory.h"
    30 #include "effectfactory.h"
    37 
    31 
    38 QT_BEGIN_NAMESPACE
    32 QT_BEGIN_NAMESPACE
    39 
    33 
    42 
    36 
    43 /*! \class MMF::EffectFactory
    37 /*! \class MMF::EffectFactory
    44   \internal
    38   \internal
    45 */
    39 */
    46 
    40 
    47 QHash<QByteArray, QVariant> EffectFactory::constructEffectDescription(const QString &name,
    41 EffectFactory::EffectFactory(QObject *parent)
    48                                                                       const QString &description)
    42     :   QObject(parent)
    49 {
    43     ,   m_initialized(false)
    50     QHash<QByteArray, QVariant> retval;
    44 {
    51 
    45 
    52     retval.insert("name", name);
    46 }
    53     retval.insert("description", description);
    47 
    54     retval.insert("available", true);
    48 EffectFactory::~EffectFactory()
    55 
    49 {
    56     return retval;
    50 
    57 }
    51 }
    58 
    52 
    59 
    53 //-----------------------------------------------------------------------------
    60 QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type type)
    54 // Public functions
    61 {
    55 //-----------------------------------------------------------------------------
       
    56 
       
    57 AbstractAudioEffect *EffectFactory::createAudioEffect(Type type,
       
    58                                                       QObject *parent)
       
    59 {
       
    60     // Lazily initialize
       
    61     if (!m_initialized)
       
    62         initialize();
       
    63 
       
    64     Q_ASSERT(parent);
       
    65 
       
    66     const QList<EffectParameter>& parameters = data(type).m_parameters;
       
    67 
       
    68     AbstractAudioEffect *effect = 0;
       
    69 
    62     switch (type)
    70     switch (type)
    63     {
    71     {
    64         case AbstractAudioEffect::EffectAudioEqualizer:
    72     case TypeBassBoost:
    65             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Audio Equalizer"), "Audio equalizer.");
    73         effect = new BassBoost(parent, parameters);
    66         case AbstractAudioEffect::EffectBassBoost:
    74         break;
    67             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Bass Boost"), "Bass boost.");
    75     case TypeAudioEqualizer:
    68         case AbstractAudioEffect::EffectDistanceAttenuation:
    76         effect = new AudioEqualizer(parent, parameters);
    69             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Distance Attenuation"), "Distance Attenuation.");
    77         break;
    70         case AbstractAudioEffect::EffectEnvironmentalReverb:
    78     case TypeEnvironmentalReverb:
    71             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb.");
    79         effect = new EnvironmentalReverb(parent, parameters);
    72         case AbstractAudioEffect::EffectListenerOrientation:
    80         break;
    73             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb.");
    81     case TypeLoudness:
    74         case AbstractAudioEffect::EffectLoudness:
    82         effect = new Loudness(parent, parameters);
    75             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Loudness"), "Loudness.");
    83         break;
    76         case AbstractAudioEffect::EffectSourceOrientation:
    84     case TypeStereoWidening:
    77             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Source Orientation"), "Source Orientation.");
    85         effect = new StereoWidening(parent, parameters);
    78         case AbstractAudioEffect::EffectStereoWidening:
    86         break;
    79             return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Stereo Widening"), "Stereo Widening.");
    87 
    80     }
    88     // Not implemented
    81 
    89     case TypeDistanceAttenuation:
    82     Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect type.");
    90     case TypeListenerOrientation:
    83     return QHash<QByteArray, QVariant>();
    91     case TypeSourceOrientation:
    84 }
    92     // Fall through
    85 
    93     default:
    86 AbstractAudioEffect *EffectFactory::createAudioEffect(AbstractAudioEffect::Type type,
    94         Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect");
    87                                                       QObject *parent)
    95     }
    88 {
    96 
    89     Q_ASSERT(parent);
    97     return effect;
    90 
    98 }
    91     switch (type)
    99 
       
   100 QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(Type type)
       
   101 {
       
   102     // Lazily initialize
       
   103     if (!m_initialized)
       
   104         initialize();
       
   105 
       
   106     return data(type).m_descriptions;
       
   107 }
       
   108 
       
   109 QList<int> EffectFactory::effectIndexes()
       
   110 {
       
   111     // Lazily initialize
       
   112     if (!m_initialized)
       
   113         initialize();
       
   114 
       
   115     QList<int> result;
       
   116 
       
   117     QHash<Type, EffectData>::const_iterator i = m_effectData.begin();
       
   118     for ( ; i != m_effectData.end(); ++i)
       
   119         if (i.value().m_supported)
       
   120             result.append(i.key());
       
   121 
       
   122     return result;
       
   123 }
       
   124 
       
   125 //-----------------------------------------------------------------------------
       
   126 // Private functions
       
   127 //-----------------------------------------------------------------------------
       
   128 
       
   129 #define INITIALIZE_EFFECT(Effect) \
       
   130     { \
       
   131     EffectData data = getData<Effect>(); \
       
   132     m_effectData.insert(Type##Effect, data); \
       
   133     }
       
   134 
       
   135 void EffectFactory::initialize()
       
   136 {
       
   137     Q_ASSERT_X(!m_initialized, Q_FUNC_INFO, "Already initialized");
       
   138 
       
   139     INITIALIZE_EFFECT(AudioEqualizer)
       
   140     INITIALIZE_EFFECT(BassBoost)
       
   141     INITIALIZE_EFFECT(EnvironmentalReverb)
       
   142     INITIALIZE_EFFECT(Loudness)
       
   143     INITIALIZE_EFFECT(StereoWidening)
       
   144 
       
   145     m_initialized = true;
       
   146 }
       
   147 
       
   148 // This class is just a wrapper which allows us to instantiate a
       
   149 // CMdaAudioOutputStream object.  This is done in order to allow the
       
   150 // effects API to query the DevSound implementation, to discover
       
   151 // which effects are supported and what parameters they take.
       
   152 // Ideally, we would use CMMFDevSound directly, but this class is not
       
   153 // available in the public S60 SDK.
       
   154 class OutputStreamFactory : public MMdaAudioOutputStreamCallback
       
   155 {
       
   156 public:
       
   157     CMdaAudioOutputStream* create()
    92     {
   158     {
    93         case AbstractAudioEffect::EffectBassBoost:
   159         CMdaAudioOutputStream* stream = 0;
    94             return new BassBoost(parent);
   160         QT_TRAP_THROWING(stream = CMdaAudioOutputStream::NewL(*this));
    95         case AbstractAudioEffect::EffectAudioEqualizer:
   161         return stream;
    96             return new AudioEqualizer(parent);
   162     }
    97         case AbstractAudioEffect::EffectDistanceAttenuation:
   163 private:
    98         case AbstractAudioEffect::EffectEnvironmentalReverb:
   164     void MaoscOpenComplete(TInt /*aError*/) { }
    99         case AbstractAudioEffect::EffectListenerOrientation:
   165     void MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/) { }
   100         case AbstractAudioEffect::EffectLoudness:
   166     void MaoscPlayComplete(TInt /*aError*/) { }
   101         case AbstractAudioEffect::EffectSourceOrientation:
   167 };
   102         case AbstractAudioEffect::EffectStereoWidening:
   168 
   103             ;
   169 template<typename BackendNode>
   104     }
   170 EffectFactory::EffectData EffectFactory::getData()
   105 
   171 {
   106     Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect.");
   172     EffectData data;
   107     return 0;
   173 
   108 }
   174     // Create a temporary CMdaAudioOutputStream object, so that the effects
   109 
   175     // API can query DevSound to discover which effects are supported.
   110 template<typename TEffect>
   176     OutputStreamFactory streamFactory;
   111 bool isEffectSupported()
   177     QScopedPointer<CMdaAudioOutputStream> stream(streamFactory.create());
   112 {
   178 
   113     AudioPlayer audioPlayer;
   179     EffectParameter param(
   114 
   180          /* parameterId */        AbstractAudioEffect::ParameterEnable,
   115     QScopedPointer<TEffect> eff;
   181          /* name */               tr("Enabled"),
   116     TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player())));
   182          /* hints */              EffectParameter::ToggledHint,
   117 
   183          /* defaultValue */       QVariant(bool(true)));
   118     return errorCode != KErrNone;
   184     data.m_parameters.append(param);
   119 }
   185 
   120 
   186     if (data.m_supported = BackendNode::getParameters
   121 QList<int> EffectFactory::effectIndexes()
   187             (stream.data(), data.m_parameters)) {
   122 {
   188         const QString description = QCoreApplication::translate
   123     QList<int> retval;
   189             ("Phonon::MMF::EffectFactory", BackendNode::description());
   124 
   190         data.m_descriptions.insert("name", description);
   125     if (isEffectSupported<CAudioEqualizer>())
   191         data.m_descriptions.insert("description", description);
   126         retval.append(AbstractAudioEffect::EffectAudioEqualizer);
   192         data.m_descriptions.insert("available", true);
   127 
   193     }
   128     if (isEffectSupported<CBassBoost>())
   194 
   129         retval.append(AbstractAudioEffect::EffectBassBoost);
   195     // Sanity check to ensure that all parameter IDs are unique
   130 
   196     QSet<int> ids;
   131     /* We haven't implemented these yet.
   197     foreach (param, data.m_parameters) {
   132     if (isEffectSupported<CDistanceAttenuation>())
   198         Q_ASSERT_X(ids.find(param.id()) == ids.end(), Q_FUNC_INFO,
   133         retval.append(AbstractAudioEffect::EffectDistanceAttenuation);
   199             "Parameter list contains duplicates");
   134 
   200         ids.insert(param.id());
   135     if (isEffectSupported<CEnvironmentalReverb>())
   201     }
   136         retval.append(AbstractAudioEffect::EffectEnvironmentalReverb);
   202 
   137 
   203     return data;
   138     if (isEffectSupported<CLoudness>())
   204 }
   139         retval.append(AbstractAudioEffect::EffectLoudness);
   205 
   140 
   206 const EffectFactory::EffectData& EffectFactory::data(Type type) const
   141     if (isEffectSupported<CListenerOrientation>())
   207 {
   142         retval.append(AbstractAudioEffect::EffectListenerOrientation);
   208     QHash<Type, EffectData>::const_iterator i = m_effectData.find(type);
   143 
   209     Q_ASSERT_X(i != m_effectData.end(), Q_FUNC_INFO, "Effect data not found");
   144     if (isEffectSupported<CSourceOrientation>())
   210     return i.value();
   145         retval.append(AbstractAudioEffect::EffectSourceOrientation);
       
   146 
       
   147     if (isEffectSupported<CStereoWidening>())
       
   148         retval.append(AbstractAudioEffect::EffectStereoWidening);
       
   149     */
       
   150 
       
   151     return retval;
       
   152 }
   211 }
   153 
   212 
   154 QT_END_NAMESPACE
   213 QT_END_NAMESPACE
   155 
   214