diff -r 41300fa6a67c -r 3b1da2848fc7 src/3rdparty/phonon/mmf/effectfactory.cpp --- 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 #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "audioequalizer.h" #include "bassboost.h" +#include "environmentalreverb.h" +#include "loudness.h" +#include "stereowidening.h" #include "effectfactory.h" @@ -44,111 +38,176 @@ \internal */ -QHash EffectFactory::constructEffectDescription(const QString &name, - const QString &description) +EffectFactory::EffectFactory(QObject *parent) + : QObject(parent) + , m_initialized(false) { - QHash retval; - retval.insert("name", name); - retval.insert("description", description); - retval.insert("available", true); +} - return retval; +EffectFactory::~EffectFactory() +{ + } +//----------------------------------------------------------------------------- +// Public functions +//----------------------------------------------------------------------------- -QHash 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(); -} - -AbstractAudioEffect *EffectFactory::createAudioEffect(AbstractAudioEffect::Type type, +AbstractAudioEffect *EffectFactory::createAudioEffect(Type type, QObject *parent) { + // Lazily initialize + if (!m_initialized) + initialize(); + Q_ASSERT(parent); + const QList& 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 -bool isEffectSupported() +QHash EffectFactory::audioEffectDescriptions(Type type) { - AudioPlayer audioPlayer; + // Lazily initialize + if (!m_initialized) + initialize(); - QScopedPointer eff; - TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player()))); - - return errorCode != KErrNone; + return data(type).m_descriptions; } QList EffectFactory::effectIndexes() { - QList retval; + // Lazily initialize + if (!m_initialized) + initialize(); + + QList result; - if (isEffectSupported()) - retval.append(AbstractAudioEffect::EffectAudioEqualizer); + QHash::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()) - retval.append(AbstractAudioEffect::EffectBassBoost); +#define INITIALIZE_EFFECT(Effect) \ + { \ + EffectData data = getData(); \ + m_effectData.insert(Type##Effect, data); \ + } - /* We haven't implemented these yet. - if (isEffectSupported()) - retval.append(AbstractAudioEffect::EffectDistanceAttenuation); +void EffectFactory::initialize() +{ + Q_ASSERT_X(!m_initialized, Q_FUNC_INFO, "Already initialized"); - if (isEffectSupported()) - retval.append(AbstractAudioEffect::EffectEnvironmentalReverb); + INITIALIZE_EFFECT(AudioEqualizer) + INITIALIZE_EFFECT(BassBoost) + INITIALIZE_EFFECT(EnvironmentalReverb) + INITIALIZE_EFFECT(Loudness) + INITIALIZE_EFFECT(StereoWidening) + + m_initialized = true; +} - if (isEffectSupported()) - 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()) - retval.append(AbstractAudioEffect::EffectListenerOrientation); +template +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 stream(streamFactory.create()); - if (isEffectSupported()) - 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()) - retval.append(AbstractAudioEffect::EffectStereoWidening); - */ + // Sanity check to ensure that all parameter IDs are unique + QSet 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::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