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
#include "audioeffects.h"
19
20
QT_BEGIN_NAMESPACE
21
22
namespace Phonon
23
{
24
namespace QT7
25
{
26
27
AudioEffectAudioNode::AudioEffectAudioNode(int effectType)
28
    : AudioNode(1, 1), m_effectType(effectType)
29
{
30
}
31
32
ComponentDescription AudioEffectAudioNode::getAudioNodeDescription() const
33
{
34
	ComponentDescription d;
35
	d.componentType = kAudioUnitType_Effect;
36
	d.componentSubType = m_effectType;
37
	d.componentManufacturer = kAudioUnitManufacturer_Apple;
38
	d.componentFlags = 0;
39
	d.componentFlagsMask = 0;
40
    return d;
41
}
42
43
void AudioEffectAudioNode::initializeAudioUnit()
44
{
45
    if (!m_audioUnit)
46
        return;
47
    foreach(int id, m_alteredParameters.keys()){
48
        Float32 value = m_alteredParameters.value(id);
49
        ComponentResult res = AudioUnitSetParameter(m_audioUnit, id, kAudioUnitScope_Global, 0, value, 0);
50
        BACKEND_ASSERT2(res == noErr, "Could not initialize audio effect.", NORMAL_ERROR)
51
    }
52
}
53
54
QVariant AudioEffectAudioNode::parameterValue(const Phonon::EffectParameter &parameter) const
55
{
56
    if (m_audioUnit){
57
        Float32 value = 0;
58
        AudioUnitGetParameter(m_audioUnit, parameter.id(), kAudioUnitScope_Global, 0, &value);
59
        return QVariant(value);
60
    } else if (m_alteredParameters.contains(parameter.id())){
61
        return QVariant(m_alteredParameters.value(parameter.id()));
62
    } else {
63
        // Use default value:
64
        AudioUnit tmpAudioUnit;
65
        ComponentDescription description = getAudioNodeDescription();
66
        Component component = FindNextComponent(0, &description);
67
        BACKEND_ASSERT3(component, "Could not get parameters of audio effect.", NORMAL_ERROR, QVariant())
68
        OSErr err = OpenAComponent(component, &tmpAudioUnit);
69
        BACKEND_ASSERT3(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR, QVariant())
70
        AudioUnitParameterInfo info;
71
        UInt32 size = sizeof(info);
72
        ComponentResult res = AudioUnitGetProperty(tmpAudioUnit,
73
            kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, parameter.id(), &info, &size);
74
        BACKEND_ASSERT3(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR, QVariant())
75
        return QVariant(info.defaultValue);
76
    }
77
}
78
79
void AudioEffectAudioNode::setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue)
80
{
81
    Float32 value = 0;
82
    if (newValue.isValid()){
83
        value = newValue.toDouble();
84
        m_alteredParameters.insert(parameter.id(), value);
85
    } else {
86
        // Use default value:
87
        m_alteredParameters.remove(parameter.id());
88
        if (m_audioUnit){
89
            AudioUnit tmpAudioUnit;
90
            ComponentDescription description = getAudioNodeDescription();
91
            Component component = FindNextComponent(0, &description);
92
            BACKEND_ASSERT2(component, "Could not get parameters of audio effect.", NORMAL_ERROR)
93
            OSErr err = OpenAComponent(component, &tmpAudioUnit);
94
            BACKEND_ASSERT2(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR)
95
            AudioUnitParameterInfo info;
96
            UInt32 size = sizeof(info);
97
            ComponentResult res = AudioUnitGetProperty(tmpAudioUnit,
98
                kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, parameter.id(), &info, &size);
99
            BACKEND_ASSERT2(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR)
100
            value = info.defaultValue;
101
        }
102
    }
103
104
    if (m_audioUnit){
105
        ComponentResult res = AudioUnitSetParameter(m_audioUnit, parameter.id(), kAudioUnitScope_Global, 0, value, 0);
106
        BACKEND_ASSERT2(res == noErr, "Could not set effect parameter value.", NORMAL_ERROR)
107
    }
108
}
109
110
///////////////////////////////////////////////////////////////////////
111
112
AudioEffect::AudioEffect(int effectType, QObject *parent)
113
    : MediaNode(AudioSink | AudioSource, 0, parent)
114
{
115
    m_audioNode = new AudioEffectAudioNode(effectType);
116
    setAudioNode(m_audioNode);
117
}
118
119
QList<Phonon::EffectParameter> AudioEffect::parameters() const
120
{
121
    QList<Phonon::EffectParameter> effectList;
122
    // Create a temporary audio unit:
123
    AudioUnit audioUnit;
124
    ComponentDescription description = m_audioNode->getAudioNodeDescription();
125
    Component component = FindNextComponent(0, &description);
126
    BACKEND_ASSERT3(component, "Could not get parameters of audio effect.", NORMAL_ERROR, effectList)
127
    OSErr err = OpenAComponent(component, &audioUnit);
128
    BACKEND_ASSERT3(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR, effectList)
129
130
    UInt32 size = 0;
131
    // Get parameter count:
132
    ComponentResult res = AudioUnitGetProperty(audioUnit, 
133
        kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, 0, &size);
134
    BACKEND_ASSERT3(res == noErr, "Could not get parameter count from audio effect.", NORMAL_ERROR, effectList)
135
    int paramCount = size / sizeof(AudioUnitParameterID);
136
137
    // Get parameters:
138
    AudioUnitParameterID parameters[paramCount];
139
    res = AudioUnitGetProperty(audioUnit, 
140
        kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, &parameters, &size);
141
    BACKEND_ASSERT3(res == noErr, "Could not get parameter list from audio effect.", NORMAL_ERROR, effectList)
142
143
    for (int i=0; i<paramCount; ++i)
144
        effectList << createParameter(audioUnit, parameters[i]);
145
    
146
    CloseComponent(audioUnit);
147
    return effectList;
148
}
149
150
QString AudioEffect::name()
151
{
152
    ComponentDescription description = m_audioNode->getAudioNodeDescription();
153
    Component component = FindNextComponent(0, &description);
154
    BACKEND_ASSERT3(component, "Could not get audio effect name.", NORMAL_ERROR, QLatin1String("<unknown effect>"))
155
156
    ComponentDescription cDesc;
157
    Handle nameH = NewHandle(0);
158
    GetComponentInfo(component, &cDesc, nameH, 0, 0); 
159
    HLock(nameH);
160
    char *namePtr = *nameH;
161
    int len = *namePtr++;
162
    namePtr[len] = 0;
163
    QString qsName = QString::fromUtf8(namePtr);
164
    DisposeHandle(nameH);
165
    return qsName;
166
}
167
168
QString AudioEffect::description()
169
{
170
    ComponentDescription description = m_audioNode->getAudioNodeDescription();
171
    Component component = FindNextComponent(0, &description);
172
    BACKEND_ASSERT3(component, "Could not get audio effect description.", NORMAL_ERROR, QLatin1String("<unknown effect>"))
173
174
    ComponentDescription cDesc;
175
    Handle descH = NewHandle(0);
176
    GetComponentInfo(component, &cDesc, 0, descH, 0); 
177
    HLock(descH);
178
    char *descPtr = *descH;
179
    int len = *descPtr++;
180
    descPtr[len] = 0;
181
    QString qsDesc = QString::fromUtf8(descPtr);
182
    DisposeHandle(descH);
183
    return qsDesc;
184
}
185
186
QList<int> AudioEffect::effectList()
187
{
188
    QList<int> effects;
189
190
	ComponentDescription d;
191
	d.componentType = kAudioUnitType_Effect;
192
	d.componentSubType = 0;
193
	d.componentManufacturer = 0;
194
	d.componentFlags = 0;
195
	d.componentFlagsMask = 0;
196
    Component component = FindNextComponent(0, &d);
197
    
198
    while (component) {
199
        ComponentDescription cDesc;
200
        GetComponentInfo(component, &cDesc, 0, 0, 0); 
201
        effects << cDesc.componentSubType;
202
        component = FindNextComponent(component, &d);
203
    }
204
    return effects;
205
}
206
207
Phonon::EffectParameter AudioEffect::createParameter(const AudioUnit &audioUnit, const AudioUnitParameterID &id) const
208
{
209
    AudioUnitParameterInfo info;
210
    UInt32 size = sizeof(info);
211
    ComponentResult res = AudioUnitGetProperty(audioUnit,
212
        kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, id, &info, &size);
213
    BACKEND_ASSERT3(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR, Phonon::EffectParameter())
214
    
215
    QString name = info.flags & kAudioUnitParameterFlag_HasCFNameString
216
        ? PhononCFString::toQString(info.cfNameString) : QLatin1String("<unknown parameter>");
217
        
218
    Phonon::EffectParameter::Hint hint;
219
    switch(info.unit){
220
    case (kAudioUnitParameterUnit_Indexed):
221
    case (kAudioUnitParameterUnit_Seconds):
222
    case (kAudioUnitParameterUnit_SampleFrames):
223
    case (kAudioUnitParameterUnit_Milliseconds):
224
        hint = Phonon::EffectParameter::IntegerHint;
225
        break;
226
    case (kAudioUnitParameterUnit_Boolean):
227
        hint = Phonon::EffectParameter::ToggledHint;
228
        break;
229
    default:
230
        hint = Phonon::EffectParameter::LogarithmicHint;
231
        break;
232
    }
233
    
234
    QVariant def(info.defaultValue);    
235
    QVariant min(info.minValue);
236
    QVariant max(info.maxValue);
237
    return Phonon::EffectParameter(id, name, hint, def, min, max, QVariantList(), name);
238
}
239
240
QVariant AudioEffect::parameterValue(const Phonon::EffectParameter &value) const
241
{
242
    return m_audioNode->parameterValue(value);
243
}
244
245
void AudioEffect::setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue)
246
{
247
    m_audioNode->setParameterValue(parameter, newValue);
248
}
249
250
}} //namespace Phonon::QT7
251
252
QT_END_NAMESPACE
253
254
#include "moc_audioeffects.cpp"