1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-3.0-only
3#include "qquick3dspatialsound_p.h"
4#include "qquick3daudioengine_p.h"
5#include "qspatialsound.h"
6#include <QAudioFormat>
7#include <qdir.h>
8#include <QQmlContext>
9#include <QQmlFile>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \qmltype SpatialSound
15 \inqmlmodule QtQuick3D.SpatialAudio
16 \ingroup quick3d_spatialaudio
17 \ingroup multimedia_audio_qml
18
19 \brief A sound object in 3D space.
20
21 A SpatialSound represents an audible object in 3D space. You can define
22 it's position and orientation in space, set the sound it is playing and define a
23 volume for the object.
24
25 The object can have different attenuation behavior, emit sound mainly in one direction
26 or spherically, and behave as if occluded by some other object.
27 */
28
29QQuick3DSpatialSound::QQuick3DSpatialSound()
30{
31 m_sound = new QSpatialSound(QQuick3DAudioEngine::getEngine());
32
33 connect(sender: this, signal: &QQuick3DNode::scenePositionChanged, context: this, slot: &QQuick3DSpatialSound::updatePosition);
34 connect(sender: this, signal: &QQuick3DNode::sceneRotationChanged, context: this, slot: &QQuick3DSpatialSound::updateRotation);
35 connect(sender: m_sound, signal: &QSpatialSound::sourceChanged, context: this, slot: &QQuick3DSpatialSound::sourceChanged);
36 connect(sender: m_sound, signal: &QSpatialSound::volumeChanged, context: this, slot: &QQuick3DSpatialSound::volumeChanged);
37 connect(sender: m_sound, signal: &QSpatialSound::distanceModelChanged, context: this, slot: &QQuick3DSpatialSound::distanceModelChanged);
38 connect(sender: m_sound, signal: &QSpatialSound::sizeChanged, context: this, slot: &QQuick3DSpatialSound::sizeChanged);
39 connect(sender: m_sound, signal: &QSpatialSound::distanceCutoffChanged, context: this, slot: &QQuick3DSpatialSound::distanceCutoffChanged);
40 connect(sender: m_sound, signal: &QSpatialSound::manualAttenuationChanged, context: this, slot: &QQuick3DSpatialSound::manualAttenuationChanged);
41 connect(sender: m_sound, signal: &QSpatialSound::occlusionIntensityChanged, context: this, slot: &QQuick3DSpatialSound::occlusionIntensityChanged);
42 connect(sender: m_sound, signal: &QSpatialSound::directivityChanged, context: this, slot: &QQuick3DSpatialSound::directivityChanged);
43 connect(sender: m_sound, signal: &QSpatialSound::directivityOrderChanged, context: this, slot: &QQuick3DSpatialSound::directivityOrderChanged);
44 connect(sender: m_sound, signal: &QSpatialSound::nearFieldGainChanged, context: this, slot: &QQuick3DSpatialSound::nearFieldGainChanged);
45 connect(sender: m_sound, signal: &QSpatialSound::loopsChanged, context: this, slot: &QQuick3DSpatialSound::loopsChanged);
46 connect(sender: m_sound, signal: &QSpatialSound::autoPlayChanged, context: this, slot: &QQuick3DSpatialSound::autoPlayChanged);
47}
48
49QQuick3DSpatialSound::~QQuick3DSpatialSound()
50{
51 delete m_sound;
52}
53
54/*!
55 \qmlproperty url SpatialSound::source
56
57 The source file for the sound to be played.
58 */
59QUrl QQuick3DSpatialSound::source() const
60{
61 return m_sound->source();
62}
63
64void QQuick3DSpatialSound::setSource(QUrl source)
65{
66 const QQmlContext *context = qmlContext(this);
67 QUrl url;
68 if (context) {
69 url = context->resolvedUrl(source);
70 } else {
71 url = QUrl::fromLocalFile(localfile: QDir::currentPath() + u"/");
72 url = url.resolved(relative: source);
73 }
74 m_sound->setSource(url);
75}
76
77/*!
78 \qmlproperty float SpatialSound::volume
79
80 Defines an overall volume for this sound source.
81
82 Values between 0 and 1 will attenuate the sound, while values above 1
83 provide an additional gain boost.
84 */
85void QQuick3DSpatialSound::setVolume(float volume)
86{
87 m_sound->setVolume(volume);
88}
89
90float QQuick3DSpatialSound::volume() const
91{
92 return m_sound->volume();
93}
94
95/*!
96 \qmlproperty enumeration SpatialSound::distanceModel
97
98 Defines how the volume of the sound scales with distance to the listener.
99 The volume starts scaling down
100 from \l size to \l distanceCutoff. The volume is constant for distances smaller
101 than size and zero for distances larger than the cutoff distance.
102
103 \table
104 \header \li Property value
105 \li Description
106 \row \li Logarithmic
107 \li Volume decreases logarithmically with distance.
108 \row \li Linear
109 \li Volume decreases linearly with distance.
110 \row \li ManualAttenuation
111 \li Attenuation is defined manually using the \l manualAttenuation property.
112 \endtable
113 */
114void QQuick3DSpatialSound::setDistanceModel(DistanceModel model)
115{
116 m_sound->setDistanceModel(QSpatialSound::DistanceModel(model));
117}
118
119QQuick3DSpatialSound::DistanceModel QQuick3DSpatialSound::distanceModel() const
120{
121 return DistanceModel(m_sound->distanceModel());
122}
123
124/*!
125 \qmlproperty float SpatialSound::size
126
127 Defines the size of the sound source. If the listener is closer to the sound
128 object than the size, volume will stay constant. The size is also used to for
129 occlusion calculations, where large sources can be partially occluded by a wall.
130 */
131void QQuick3DSpatialSound::setSize(float min)
132{
133 m_sound->setSize(min);
134}
135
136float QQuick3DSpatialSound::size() const
137{
138 return m_sound->size();
139}
140
141/*!
142 \qmlproperty float SpatialSound::distanceCutoff
143
144 Defines a distance beyond which sound coming from the source will cutoff.
145 If the listener is further away from the sound object than the cutoff
146 distance it won't be audible anymore.
147 */
148void QQuick3DSpatialSound::setDistanceCutoff(float max)
149{
150 m_sound->setDistanceCutoff(max);
151}
152
153float QQuick3DSpatialSound::distanceCutoff() const
154{
155 return m_sound->distanceCutoff();
156}
157
158/*!
159 \qmlproperty float SpatialSound::manualAttenuation
160
161 Defines a manual attenuation factor if \l distanceModel is set to
162 SpatialSound.ManualAttenuation.
163 */
164void QQuick3DSpatialSound::setManualAttenuation(float attenuation)
165{
166 m_sound->setManualAttenuation(attenuation);
167}
168
169float QQuick3DSpatialSound::manualAttenuation() const
170{
171 return m_sound->manualAttenuation();
172}
173
174/*!
175 \qmlproperty float SpatialSound::occlusionIntensity
176
177 Defines how much the object is occluded. 0 implies the object is
178 not occluded at all, while a large number implies a large occlusion.
179
180 The default is 0.
181 */
182void QQuick3DSpatialSound::setOcclusionIntensity(float occlusion)
183{
184 m_sound->setOcclusionIntensity(occlusion);
185}
186
187float QQuick3DSpatialSound::occlusionIntensity() const
188{
189 return m_sound->occlusionIntensity();
190}
191
192/*!
193 \qmlproperty float SpatialSound::directivity
194
195 Defines the directivity of the sound source. A value of 0 implies that the sound is
196 emitted equally in all directions, while a value of 1 implies that the source mainly
197 emits sound in the forward direction.
198
199 Valid values are between 0 and 1, the default is 0.
200 */
201void QQuick3DSpatialSound::setDirectivity(float alpha)
202{
203 m_sound->setDirectivity(alpha);
204}
205
206float QQuick3DSpatialSound::directivity() const
207{
208 return m_sound->directivity();
209}
210
211/*!
212 \qmlproperty float SpatialSound::directivityOrder
213
214 Defines the order of the directivity of the sound source. A higher order
215 implies a sharper localization of the sound cone.
216
217 The minimum value and default for this property is 1.
218 */
219void QQuick3DSpatialSound::setDirectivityOrder(float alpha)
220{
221 m_sound->setDirectivityOrder(alpha);
222}
223
224float QQuick3DSpatialSound::directivityOrder() const
225{
226 return m_sound->directivityOrder();
227}
228
229/*!
230 \qmlproperty float SpatialSound::nearFieldGain
231
232 Defines the near field gain for the sound source. Valid values are between 0 and 1.
233 A near field gain of 1 will raise the volume of the sound signal by approx 20 dB for
234 distances very close to the listener.
235 */
236void QQuick3DSpatialSound::setNearFieldGain(float gain)
237{
238 m_sound->setNearFieldGain(gain);
239}
240
241float QQuick3DSpatialSound::nearFieldGain() const
242{
243 return m_sound->nearFieldGain();
244}
245
246void QQuick3DSpatialSound::updatePosition()
247{
248 m_sound->setPosition(scenePosition());
249}
250
251void QQuick3DSpatialSound::updateRotation()
252{
253 m_sound->setRotation(sceneRotation());
254}
255
256/*!
257 \qmlproperty int SpatialSound::loops
258
259 Determines how often the sound is played before the player stops.
260 Set to SpatialSound::Infinite to loop the current sound forever.
261
262 The default value is \c 1.
263 */
264int QQuick3DSpatialSound::loops() const
265{
266 return m_sound->loops();
267}
268
269void QQuick3DSpatialSound::setLoops(int loops)
270{
271 m_sound->setLoops(loops);
272}
273
274/*!
275 \qmlproperty bool SpatialSound::autoPlay
276
277 Determines whether the sound should automatically start playing when a source
278 gets specified.
279
280 The default value is \c true.
281 */
282bool QQuick3DSpatialSound::autoPlay() const
283{
284 return m_sound->autoPlay();
285}
286
287void QQuick3DSpatialSound::setAutoPlay(bool autoPlay)
288{
289 m_sound->setAutoPlay(autoPlay);
290}
291
292/*!
293 \qmlmethod SpatialSound::play()
294
295 Starts playing back the sound. Does nothing if the sound is already playing.
296 */
297void QQuick3DSpatialSound::play()
298{
299 m_sound->play();
300}
301
302/*!
303 \qmlmethod SpatialSound::pause()
304
305 Pauses sound playback at the current position. Calling play() will continue playback.
306 */
307void QQuick3DSpatialSound::pause()
308{
309 m_sound->pause();
310}
311
312/*!
313 \qmlmethod SpatialSound::stop()
314
315 Stops sound playback and resets the current position and loop count to 0. Calling play() will
316 begin playback at the beginning of the sound file.
317 */
318void QQuick3DSpatialSound::stop()
319{
320 m_sound->stop();
321}
322
323QT_END_NAMESPACE
324

source code of qtmultimedia/src/spatialaudioquick3d/qquick3dspatialsound.cpp