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