Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaudioroom.cpp
Go to the documentation of this file.
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
4#include "qaudioroom_p.h"
5
6#include <QtCore/qspan.h>
7
8#include "platforms/common/room_effects_utils.h"
9
11
12namespace {
13
14inline QVector3D toVector(QSpan<const float, 3> f)
15{
16 return QVector3D(f[0], f[1], f[2]);
17}
18
19inline void toFloats(QVector3D v, QSpan<float, 3> f)
20{
21 f[0] = v.x();
22 f[1] = v.y();
23 f[2] = v.z();
24}
25
26inline QQuaternion toQuaternion(QSpan<const float, 4> f)
27{
28 // resonance audio puts the scalar component last
29 return QQuaternion(f[3], f[0], f[1], f[2]);
30}
31
32inline void toFloats(QQuaternion q, QSpan<float, 4> f)
33{
34 f[0] = q.x();
35 f[1] = q.y();
36 f[2] = q.z();
37 f[3] = q.scalar();
38}
39
40// Default values for occlusion and dampening of different wall materials.
41// These values are used as defaults if a wall is only defined by a material
42// and define how sound passes through the wall.
43// We define both occlusion and dampening constants to be able to tune the
44// sound. Dampening only reduces the level of the sound without affecting its
45// tone, while occlusion will dampen higher frequencies more than lower ones
46constexpr struct {
47 float occlusion;
48 float dampening;
49} occlusionAndDampening[] = {
50 { 0.f, 1.f }, // Transparent,
51 { 0.f, .1f }, // AcousticCeilingTiles,
52 { 2.f, .4f }, // BrickBare,
53 { 2.f, .4f }, // BrickPainted,
54 { 4.f, 1.f }, // ConcreteBlockCoarse,
55 { 4.f, 1.f }, // ConcreteBlockPainted,
56 { .7f, .7f }, // CurtainHeavy,
57 { .5f, .5f }, // FiberGlassInsulation,
58 { .2f, .3f }, // GlassThin,
59 { .5f, .2f }, // GlassThick,
60 { 7.f, 1.f }, // Grass,
61 { 4.f, 1.f }, // LinoleumOnConcrete,
62 { 4.f, 1.f }, // Marble,
63 { 0.f, .2f }, // Metal,
64 { 4.f, 1.f }, // ParquetOnConcrete,
65 { 2.f, .4f }, // PlasterRough,
66 { 2.f, .4f }, // PlasterSmooth,
67 { 1.5f, .2f }, // PlywoodPanel,
68 { 4.f, 1.f }, // PolishedConcreteOrTile,
69 { 4.f, 1.f }, // Sheetrock,
70 { 4.f, 1.f }, // WaterOrIceSurface,
71 { 1.f, .3f }, // WoodCeiling,
72 { 1.f, .3f }, // WoodPanel,
73 { 0.f, .0f }, // UniformMaterial,
74};
75
76}
77
78// make sure the wall definitions agree with resonance audio
79
80static_assert(QAudioRoom::LeftWall == 0);
81static_assert(QAudioRoom::RightWall == 1);
82static_assert(QAudioRoom::Floor == 2);
83static_assert(QAudioRoom::Ceiling == 3);
84static_assert(QAudioRoom::FrontWall == 4);
85static_assert(QAudioRoom::BackWall == 5);
86
87float QAudioRoomPrivate::wallOcclusion(QAudioRoom::Wall wall) const
88{
89 return m_wallOcclusion[wall] < 0 ? occlusionAndDampening[roomProperties.material_names[wall]].occlusion : m_wallOcclusion[wall];
90}
91
92float QAudioRoomPrivate::wallDampening(QAudioRoom::Wall wall) const
93{
94 return m_wallDampening[wall] < 0 ? occlusionAndDampening[roomProperties.material_names[wall]].dampening : m_wallDampening[wall];
95}
96
97void QAudioRoomPrivate::update()
98{
99 if (!dirty)
100 return;
101 reflections = vraudio::ComputeReflectionProperties(roomProperties);
102 reverb = vraudio::ComputeReverbProperties(roomProperties);
103 dirty = false;
104}
105
106
107/*!
108 \class QAudioRoom
109 \inmodule QtSpatialAudio
110 \ingroup spatialaudio
111 \ingroup multimedia_audio
112
113 Defines a room for the spatial audio engine.
114
115 If the listener is inside a room, first order sound reflections and reverb
116 matching the rooms properties will get applied to the sound field.
117
118 A room is always square and defined by its center position, its orientation and dimensions.
119 Each of the 6 walls of the room can be made of different materials that will contribute
120 to the computed reflections and reverb that the listener will experience while being inside
121 the room.
122
123 If multiple rooms cover the same position, the engine will use the room with the smallest
124 volume.
125 */
126
127/*!
128 Constructs a QAudioRoom for \a engine.
129 */
130QAudioRoom::QAudioRoom(QAudioEngine *engine) : QObject(*new QAudioRoomPrivate)
131{
132 Q_ASSERT(engine);
133 Q_D(QAudioRoom);
134 d->engine = engine;
135 auto *ep = QAudioEnginePrivate::get(engine);
136 ep->addRoom(this);
137}
138
139/*!
140 Destroys the room.
141 */
142QAudioRoom::~QAudioRoom()
143{
144 Q_D(QAudioRoom);
145 auto *ep = QAudioEnginePrivate::get(d->engine);
146 if (ep)
147 ep->removeRoom(this);
148}
149
150/*!
151 \enum QAudioRoom::Material
152
153 Defines different materials that can be applied to the different walls of the room.
154
155 \value Transparent The side of the room is open and won't contribute to reflections or reverb.
156 \value AcousticCeilingTiles Acoustic tiles that suppress most reflections and reverb.
157 \value BrickBare Bare brick wall.
158 \value BrickPainted Painted brick wall.
159 \value ConcreteBlockCoarse Raw concrete wall
160 \value ConcreteBlockPainted Painted concrete wall
161 \value CurtainHeavy Heavy curtain. Will mostly reflect low frequencies
162 \value FiberGlassInsulation Fiber glass insulation. Only reflects very low frequencies
163 \value GlassThin Thin glass wall
164 \value GlassThick Thick glass wall
165 \value Grass Grass
166 \value LinoleumOnConcrete Linoleum floor
167 \value Marble Marble floor
168 \value Metal Metal
169 \value ParquetOnConcrete Parquet wooden floor on concrete
170 \value PlasterRough Rough plaster
171 \value PlasterSmooth Smooth plaster
172 \value PlywoodPanel Plywodden panel
173 \value PolishedConcreteOrTile Polished concrete or tiles
174 \value Sheetrock Rock
175 \value WaterOrIceSurface Water or ice
176 \value WoodCeiling Wooden ceiling
177 \value WoodPanel Wooden panel
178 \value UniformMaterial Artificial material giving uniform reflections on all frequencies
179*/
180
181/*!
182 \enum QAudioRoom::Wall
183
184 An enum defining the 6 walls of the room
185
186 \value LeftWall Left wall (negative x)
187 \value RightWall Right wall (positive x)
188 \value Floor Bottom wall (negative y)
189 \value Ceiling Top wall (positive y)
190 \value FrontWall Front wall (negative z)
191 \value BackWall Back wall (positive z)
192*/
193
194
195/*!
196 \property QAudioRoom::position
197
198 Defines the position of the center of the room in 3D space. Units are in centimeters
199 by default.
200
201 \sa dimensions, QAudioEngine::distanceScale
202 */
203void QAudioRoom::setPosition(QVector3D pos)
204{
205 Q_D(QAudioRoom);
206 auto *ep = QAudioEnginePrivate::get(d->engine);
207 pos *= ep->distanceScale;
208 if (toVector(d->roomProperties.position) == pos)
209 return;
210 toFloats(pos, d->roomProperties.position);
211 d->dirty = true;
212 emit positionChanged();
213}
214
215QVector3D QAudioRoom::position() const
216{
217 Q_D(const QAudioRoom);
218 auto *ep = QAudioEnginePrivate::get(d->engine);
219 auto pos = toVector(d->roomProperties.position);
220 pos /= ep->distanceScale;
221 return pos;
222}
223
224/*!
225 \property QAudioRoom::dimensions
226
227 Defines the dimensions of the room in 3D space. Units are in centimeters
228 by default.
229
230 \sa position, QAudioEngine::distanceScale
231 */
232void QAudioRoom::setDimensions(QVector3D dim)
233{
234 Q_D(QAudioRoom);
235 auto *ep = QAudioEnginePrivate::get(d->engine);
236 dim *= ep->distanceScale;
237 if (toVector(d->roomProperties.dimensions) == dim)
238 return;
239 toFloats(dim, d->roomProperties.dimensions);
240 d->dirty = true;
241 emit dimensionsChanged();
242}
243
244QVector3D QAudioRoom::dimensions() const
245{
246 Q_D(const QAudioRoom);
247
248 auto *ep = QAudioEnginePrivate::get(d->engine);
249 auto dim = toVector(d->roomProperties.dimensions);
250 dim /= ep->distanceScale;
251 return dim;
252}
253
254/*!
255 \property QAudioRoom::rotation
256
257 Defines the orientation of the room in 3D space.
258 */
259void QAudioRoom::setRotation(const QQuaternion &q)
260{
261 Q_D(QAudioRoom);
262
263 if (toQuaternion(d->roomProperties.rotation) == q)
264 return;
265 toFloats(q, d->roomProperties.rotation);
266 d->dirty = true;
267 emit rotationChanged();
268}
269
270QQuaternion QAudioRoom::rotation() const
271{
272 Q_D(const QAudioRoom);
273
274 return toQuaternion(d->roomProperties.rotation);
275}
276
277/*!
278 \fn void QAudioRoom::wallsChanged()
279
280 Signals when the wall material changes.
281*/
282/*!
283 Sets \a wall to \a material.
284
285 Different wall materials have different reflection and reverb properties
286 that influence the sound of the room.
287
288 \sa wallMaterial(), Material, QAudioRoom::Wall
289 */
290void QAudioRoom::setWallMaterial(Wall wall, Material material)
291{
292 Q_D(QAudioRoom);
293
294 static_assert(vraudio::kUniform == int(UniformMaterial));
295 static_assert(vraudio::kTransparent == int(Transparent));
296
297 if (d->roomProperties.material_names[int(wall)] == int(material))
298 return;
299 d->roomProperties.material_names[int(wall)] = vraudio::MaterialName(int(material));
300 d->dirty = true;
301 emit wallsChanged();
302}
303
304/*!
305 returns the material being used for \a wall.
306
307 \sa setWallMaterial(), Material, QAudioRoom::Wall
308 */
309QAudioRoom::Material QAudioRoom::wallMaterial(Wall wall) const
310{
311 Q_D(const QAudioRoom);
312 return Material(d->roomProperties.material_names[int(wall)]);
313}
314
315/*!
316 \property QAudioRoom::reflectionGain
317
318 A gain factor for reflections generated in this room. A value
319 from 0 to 1 will dampen reflections, while a value larger than 1
320 will apply a gain to reflections, making them louder.
321
322 The default is 1, a factor of 0 disables reflections. Negative
323 values are mapped to 0.
324 */
325void QAudioRoom::setReflectionGain(float factor)
326{
327 Q_D(QAudioRoom);
328
329 if (factor < 0.)
330 factor = 0.;
331 if (d->roomProperties.reflection_scalar == factor)
332 return;
333 d->roomProperties.reflection_scalar = factor;
334 d->dirty = true;
335 emit reflectionGainChanged();
336}
337
338float QAudioRoom::reflectionGain() const
339{
340 Q_D(const QAudioRoom);
341 return d->roomProperties.reflection_scalar;
342}
343
344/*!
345 \property QAudioRoom::reverbGain
346
347 A gain factor for reverb generated in this room. A value
348 from 0 to 1 will dampen reverb, while a value larger than 1
349 will apply a gain to the reverb, making it louder.
350
351 The default is 1, a factor of 0 disables reverb. Negative
352 values are mapped to 0.
353 */
354void QAudioRoom::setReverbGain(float factor)
355{
356 Q_D(QAudioRoom);
357
358 if (factor < 0)
359 factor = 0;
360 if (d->roomProperties.reverb_gain == factor)
361 return;
362 d->roomProperties.reverb_gain = factor;
363 d->dirty = true;
364 emit reverbGainChanged();
365}
366
367float QAudioRoom::reverbGain() const
368{
369 Q_D(const QAudioRoom);
370
371 return d->roomProperties.reverb_gain;
372}
373
374/*!
375 \property QAudioRoom::reverbTime
376
377 A factor to be applies to all reverb timings generated for this room.
378 Larger values will lead to longer reverb timings, making the room sound
379 larger.
380
381 The default is 1. Negative values are mapped to 0.
382 */
383void QAudioRoom::setReverbTime(float factor)
384{
385 Q_D(QAudioRoom);
386
387 if (factor < 0)
388 factor = 0;
389 if (d->roomProperties.reverb_time == factor)
390 return;
391 d->roomProperties.reverb_time = factor;
392 d->dirty = true;
393 emit reverbTimeChanged();
394}
395
396float QAudioRoom::reverbTime() const
397{
398 Q_D(const QAudioRoom);
399
400 return d->roomProperties.reverb_time;
401}
402
403/*!
404 \property QAudioRoom::reverbBrightness
405
406 A brightness factor to be applied to the generated reverb.
407 A positive value will increase reverb for higher frequencies and
408 dampen lower frequencies, a negative value does the reverse.
409
410 The default is 0.
411 */
412void QAudioRoom::setReverbBrightness(float factor)
413{
414 Q_D(QAudioRoom);
415
416 if (d->roomProperties.reverb_brightness == factor)
417 return;
418 d->roomProperties.reverb_brightness = factor;
419 d->dirty = true;
420 emit reverbBrightnessChanged();
421}
422
423float QAudioRoom::reverbBrightness() const
424{
425 Q_D(const QAudioRoom);
426
427 return d->roomProperties.reverb_brightness;
428}
429
430QT_END_NAMESPACE
431
432#include "moc_qaudioroom.cpp"
QQuaternion toQuaternion(QSpan< const float, 4 > f)
QVector3D toVector(QSpan< const float, 3 > f)
void toFloats(QVector3D v, QSpan< float, 3 > f)