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 |