1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qaudioengine_openal_p.h"
41 #include "qdebug.h"
42
43 #define DEBUG_AUDIOENGINE
44
45 QT_USE_NAMESPACE
46
QSoundSourcePrivate(QObject * parent)47 QSoundSourcePrivate::QSoundSourcePrivate(QObject *parent)
48 : QSoundSource(parent)
49 , m_alSource(0)
50 , m_bindBuffer(0)
51 , m_isReady(false)
52 , m_state(QSoundSource::StoppedState)
53 , m_gain(0)
54 , m_pitch(0)
55 , m_coneInnerAngle(0)
56 , m_coneOuterAngle(0)
57 , m_coneOuterGain(1)
58 {
59 #ifdef DEBUG_AUDIOENGINE
60 qDebug() << "creating new QSoundSourcePrivate";
61 #endif
62 alGenSources(1, &m_alSource);
63 QAudioEnginePrivate::checkNoError("create source");
64 setGain(1);
65 setPitch(1);
66 setCone(360, 360, 0);
67 }
68
~QSoundSourcePrivate()69 QSoundSourcePrivate::~QSoundSourcePrivate()
70 {
71 #ifdef DEBUG_AUDIOENGINE
72 qDebug() << "QSoundSourcePrivate::dtor";
73 #endif
74 release();
75 }
76
release()77 void QSoundSourcePrivate::release()
78 {
79 if (m_alSource) {
80 #ifdef DEBUG_AUDIOENGINE
81 qDebug() << "QSoundSourcePrivate::release";
82 #endif
83 stop();
84 unbindBuffer();
85 alDeleteSources(1, &m_alSource);
86 QAudioEnginePrivate::checkNoError("delete source");
87 m_alSource = 0;
88 }
89 }
90
bindBuffer(QSoundBuffer * soundBuffer)91 void QSoundSourcePrivate::bindBuffer(QSoundBuffer* soundBuffer)
92 {
93 unbindBuffer();
94 Q_ASSERT(soundBuffer->state() == QSoundBuffer::Ready);
95 m_bindBuffer = qobject_cast<QSoundBufferPrivateAL*>(soundBuffer);
96 m_bindBuffer->bindToSource(m_alSource);
97 m_isReady = true;
98 }
99
unbindBuffer()100 void QSoundSourcePrivate::unbindBuffer()
101 {
102 if (m_bindBuffer) {
103 m_bindBuffer->unbindFromSource(m_alSource);
104 m_bindBuffer = 0;
105 }
106 m_isReady = false;
107 if (m_state != QSoundSource::StoppedState) {
108 m_state = QSoundSource::StoppedState;
109 emit stateChanged(m_state);
110 }
111 }
112
play()113 void QSoundSourcePrivate::play()
114 {
115 if (!m_alSource || !m_isReady)
116 return;
117 alSourcePlay(m_alSource);
118 #ifdef DEBUG_AUDIOENGINE
119 QAudioEnginePrivate::checkNoError("play");
120 #endif
121 emit activate(this);
122 }
123
isLooping() const124 bool QSoundSourcePrivate::isLooping() const
125 {
126 if (!m_alSource)
127 return false;
128 ALint looping = 0;
129 alGetSourcei(m_alSource, AL_LOOPING, &looping);
130 return looping == AL_TRUE ? true : false;
131 }
132
pause()133 void QSoundSourcePrivate::pause()
134 {
135 if (!m_alSource || !m_isReady)
136 return;
137 alSourcePause(m_alSource);
138 #ifdef DEBUG_AUDIOENGINE
139 QAudioEnginePrivate::checkNoError("pause");
140 #endif
141 }
142
stop()143 void QSoundSourcePrivate::stop()
144 {
145 if (!m_alSource)
146 return;
147 alSourceStop(m_alSource);
148 #ifdef DEBUG_AUDIOENGINE
149 QAudioEnginePrivate::checkNoError("stop");
150 #endif
151 }
152
state() const153 QSoundSource::State QSoundSourcePrivate::state() const
154 {
155 return m_state;
156 }
157
checkState()158 void QSoundSourcePrivate::checkState()
159 {
160 QSoundSource::State st;
161 st = QSoundSource::StoppedState;
162 if (m_alSource && m_isReady) {
163 ALint s;
164 alGetSourcei(m_alSource, AL_SOURCE_STATE, &s);
165 switch (s) {
166 case AL_PLAYING:
167 st = QSoundSource::PlayingState;
168 break;
169 case AL_PAUSED:
170 st = QSoundSource::PausedState;
171 break;
172 }
173 }
174 if (st == m_state)
175 return;
176 m_state = st;
177 emit stateChanged(m_state);
178 }
179
setLooping(bool looping)180 void QSoundSourcePrivate::setLooping(bool looping)
181 {
182 if (!m_alSource)
183 return;
184 alSourcei(m_alSource, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
185 }
186
setPosition(const QVector3D & position)187 void QSoundSourcePrivate::setPosition(const QVector3D& position)
188 {
189 if (!m_alSource)
190 return;
191 alSource3f(m_alSource, AL_POSITION, position.x(), position.y(), position.z());
192 #ifdef DEBUG_AUDIOENGINE
193 QAudioEnginePrivate::checkNoError("source set position");
194 #endif
195 }
196
setDirection(const QVector3D & direction)197 void QSoundSourcePrivate::setDirection(const QVector3D& direction)
198 {
199 if (!m_alSource)
200 return;
201 alSource3f(m_alSource, AL_DIRECTION, direction.x(), direction.y(), direction.z());
202 #ifdef DEBUG_AUDIOENGINE
203 QAudioEnginePrivate::checkNoError("source set direction");
204 #endif
205 }
206
setVelocity(const QVector3D & velocity)207 void QSoundSourcePrivate::setVelocity(const QVector3D& velocity)
208 {
209 if (!m_alSource)
210 return;
211 alSource3f(m_alSource, AL_VELOCITY, velocity.x(), velocity.y(), velocity.z());
212 #ifdef DEBUG_AUDIOENGINE
213 QAudioEnginePrivate::checkNoError("source set velocity");
214 #endif
215 }
216
velocity() const217 QVector3D QSoundSourcePrivate::velocity() const
218 {
219 if (!m_alSource)
220 return QVector3D(0, 0, 0);
221 ALfloat x, y, z;
222 alGetSource3f(m_alSource, AL_VELOCITY, &x, &y, &z);
223 return QVector3D(x, y, z);
224 }
225
position() const226 QVector3D QSoundSourcePrivate::position() const
227 {
228 if (!m_alSource)
229 return QVector3D(0, 0, 0);
230 ALfloat x, y, z;
231 alGetSource3f(m_alSource, AL_POSITION, &x, &y, &z);
232 return QVector3D(x, y, z);
233 }
234
direction() const235 QVector3D QSoundSourcePrivate::direction() const
236 {
237 if (!m_alSource)
238 return QVector3D(0, 1, 0);
239 ALfloat x, y, z;
240 alGetSource3f(m_alSource, AL_DIRECTION, &x, &y, &z);
241 return QVector3D(x, y, z);
242 }
243
setGain(qreal gain)244 void QSoundSourcePrivate::setGain(qreal gain)
245 {
246 if (!m_alSource || gain == m_gain)
247 return;
248 alSourcef(m_alSource, AL_GAIN, gain);
249 #ifdef DEBUG_AUDIOENGINE
250 QAudioEnginePrivate::checkNoError("source set gain");
251 #endif
252 m_gain = gain;
253 }
254
setPitch(qreal pitch)255 void QSoundSourcePrivate::setPitch(qreal pitch)
256 {
257 if (!m_alSource || m_pitch == pitch)
258 return;
259 alSourcef(m_alSource, AL_PITCH, pitch);
260 #ifdef DEBUG_AUDIOENGINE
261 QAudioEnginePrivate::checkNoError("source set pitch");
262 #endif
263 m_pitch = pitch;
264 }
265
setCone(qreal innerAngle,qreal outerAngle,qreal outerGain)266 void QSoundSourcePrivate::setCone(qreal innerAngle, qreal outerAngle, qreal outerGain)
267 {
268 if (innerAngle > outerAngle)
269 outerAngle = innerAngle;
270 Q_ASSERT(outerAngle <= 360 && innerAngle >= 0);
271
272 //make sure the setting order will always keep outerAngle >= innerAngle in openAL
273 if (outerAngle >= m_coneInnerAngle) {
274 if (m_coneOuterAngle != outerAngle) {
275 alSourcef(m_alSource, AL_CONE_OUTER_ANGLE, outerAngle);
276 #ifdef DEBUG_AUDIOENGINE
277 QAudioEnginePrivate::checkNoError("source set cone outerAngle");
278 #endif
279 m_coneOuterAngle = outerAngle;
280 }
281 if (m_coneInnerAngle != innerAngle) {
282 alSourcef(m_alSource, AL_CONE_INNER_ANGLE, innerAngle);
283 #ifdef DEBUG_AUDIOENGINE
284 QAudioEnginePrivate::checkNoError("source set cone innerAngle");
285 #endif
286 m_coneInnerAngle = innerAngle;
287 }
288 } else {
289 if (m_coneInnerAngle != innerAngle) {
290 alSourcef(m_alSource, AL_CONE_INNER_ANGLE, innerAngle);
291 #ifdef DEBUG_AUDIOENGINE
292 QAudioEnginePrivate::checkNoError("source set cone innerAngle");
293 #endif
294 m_coneInnerAngle = innerAngle;
295 }
296 if (m_coneOuterAngle != outerAngle) {
297 alSourcef(m_alSource, AL_CONE_OUTER_ANGLE, outerAngle);
298 #ifdef DEBUG_AUDIOENGINE
299 QAudioEnginePrivate::checkNoError("source set cone outerAngle");
300 #endif
301 m_coneOuterAngle = outerAngle;
302 }
303 }
304
305 if (outerGain != m_coneOuterGain) {
306 alSourcef(m_alSource, AL_CONE_OUTER_GAIN, outerGain);
307 #ifdef DEBUG_AUDIOENGINE
308 QAudioEnginePrivate::checkNoError("source set cone outerGain");
309 #endif
310 m_coneOuterGain = outerGain;
311 }
312 }
313