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
19
#include <QObject>
20
#include <QCoreApplication>
21
22
#include <mdaaudiooutputstream.h>
23
24
#include "audioequalizer.h"
25
#include "bassboost.h"
26
#include "environmentalreverb.h"
27
#include "loudness.h"
28
#include "stereowidening.h"
29
30
#include "effectfactory.h"
31
32
QT_BEGIN_NAMESPACE
33
34
using namespace Phonon;
35
using namespace Phonon::MMF;
36
37
/*! \class MMF::EffectFactory
38
  \internal
39
*/
40
41
EffectFactory::EffectFactory(QObject *parent)
42
    :   QObject(parent)
43
    ,   m_initialized(false)
44
{
45
46
}
47
48
EffectFactory::~EffectFactory()
49
{
50
51
}
52
53
//-----------------------------------------------------------------------------
54
// Public functions
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
70
    switch (type)
71
    {
72
    case TypeBassBoost:
73
        effect = new BassBoost(parent, parameters);
74
        break;
75
    case TypeAudioEqualizer:
76
        effect = new AudioEqualizer(parent, parameters);
77
        break;
78
    case TypeEnvironmentalReverb:
79
        effect = new EnvironmentalReverb(parent, parameters);
80
        break;
81
    case TypeLoudness:
82
        effect = new Loudness(parent, parameters);
83
        break;
84
    case TypeStereoWidening:
85
        effect = new StereoWidening(parent, parameters);
86
        break;
87
88
    // Not implemented
89
    case TypeDistanceAttenuation:
90
    case TypeListenerOrientation:
91
    case TypeSourceOrientation:
92
    // Fall through
93
    default:
94
        Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect");
95
    }
96
97
    return effect;
98
}
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()
158
    {
159
        CMdaAudioOutputStream* stream = 0;
160
        QT_TRAP_THROWING(stream = CMdaAudioOutputStream::NewL(*this));
161
        return stream;
162
    }
163
private:
164
    void MaoscOpenComplete(TInt /*aError*/) { }
165
    void MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/) { }
166
    void MaoscPlayComplete(TInt /*aError*/) { }
167
};
168
169
template<typename BackendNode>
170
EffectFactory::EffectData EffectFactory::getData()
171
{
172
    EffectData data;
173
174
    // Create a temporary CMdaAudioOutputStream object, so that the effects
175
    // API can query DevSound to discover which effects are supported.
176
    OutputStreamFactory streamFactory;
177
    QScopedPointer<CMdaAudioOutputStream> stream(streamFactory.create());
178
179
    EffectParameter param(
180
         /* parameterId */        AbstractAudioEffect::ParameterEnable,
181
         /* name */               tr("Enabled"),
182
         /* hints */              EffectParameter::ToggledHint,
183
         /* defaultValue */       QVariant(bool(true)));
184
    data.m_parameters.append(param);
185
186
    data.m_supported = BackendNode::getParameters(stream.data(),
187
                                                  data.m_parameters);
188
    if (data.m_supported) {
189
        const QString description = QCoreApplication::translate
190
            ("Phonon::MMF::EffectFactory", BackendNode::description());
191
        data.m_descriptions.insert("name", description);
192
        data.m_descriptions.insert("description", description);
193
        data.m_descriptions.insert("available", true);
194
    }
195
196
    // Sanity check to ensure that all parameter IDs are unique
197
    QSet<int> ids;
198
    foreach (param, data.m_parameters) {
199
        Q_ASSERT_X(ids.find(param.id()) == ids.end(), Q_FUNC_INFO,
200
            "Parameter list contains duplicates");
201
        ids.insert(param.id());
202
    }
203
204
    return data;
205
}
206
207
const EffectFactory::EffectData& EffectFactory::data(Type type) const
208
{
209
    QHash<Type, EffectData>::const_iterator i = m_effectData.find(type);
210
    Q_ASSERT_X(i != m_effectData.end(), Q_FUNC_INFO, "Effect data not found");
211
    return i.value();
212
}
213
214
QT_END_NAMESPACE