Overte C++ Documentation
Sound.h
1 //
2 // Sound.h
3 // libraries/audio/src
4 //
5 // Created by Stephen Birarda on 1/2/2014.
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2023 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 // SPDX-License-Identifier: Apache-2.0
12 //
13 
14 #ifndef hifi_Sound_h
15 #define hifi_Sound_h
16 
17 #include <QRunnable>
18 #include <QtCore/QObject>
19 #include <QtCore/QSharedPointer>
20 #include <QtNetwork/QNetworkReply>
21 #include <QtCore/QSharedPointer>
22 
23 #include <ResourceCache.h>
24 #include <ScriptValue.h>
25 
26 #include "AudioConstants.h"
27 
28 class AudioData;
29 class ScriptEngine;
30 using AudioDataPointer = std::shared_ptr<const AudioData>;
31 
32 Q_DECLARE_METATYPE(AudioDataPointer);
33 
34 // AudioData is designed to be immutable
35 // All of its members and methods are const
36 // This makes it perfectly safe to access from multiple threads at once
37 class AudioData {
38 public:
39  using AudioSample = AudioConstants::AudioSample;
40 
41  // Allocates the buffer memory contiguous with the object
42  static AudioDataPointer make(uint32_t numSamples, uint32_t numChannels,
43  const AudioSample* samples);
44 
45  uint32_t getNumSamples() const { return _numSamples; }
46  uint32_t getNumChannels() const { return _numChannels; }
47  const AudioSample* data() const { return _data; }
48  const char* rawData() const { return reinterpret_cast<const char*>(_data); }
49 
50  float isStereo() const { return _numChannels == 2; }
51  float isAmbisonic() const { return _numChannels == 4; }
52  float getDuration() const { return (float)_numSamples / (_numChannels * AudioConstants::SAMPLE_RATE); }
53  uint32_t getNumFrames() const { return _numSamples / _numChannels; }
54  uint32_t getNumBytes() const { return _numSamples * sizeof(AudioSample); }
55 
56 private:
57  AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSample* samples);
58 
59  const uint32_t _numSamples { 0 };
60  const uint32_t _numChannels { 0 };
61  const AudioSample* const _data { nullptr };
62 };
63 
64 class Sound : public Resource {
65  Q_OBJECT
66 
67 public:
68  Sound(const QUrl& url, bool isStereo = false, bool isAmbisonic = false);
69  Sound(const Sound& other) : Resource(other), _audioData(other._audioData), _numChannels(other._numChannels) {}
70 
71  bool isReady() const { return (bool)_audioData; }
72 
73  bool isStereo() const { return _audioData ? _audioData->isStereo() : false; }
74  bool isAmbisonic() const { return _audioData ? _audioData->isAmbisonic() : false; }
75  float getDuration() const { return _audioData ? _audioData->getDuration() : 0.0f; }
76 
77  AudioDataPointer getAudioData() const { return _audioData; }
78 
79  int getNumChannels() const { return _numChannels; }
80 
81 signals:
82  void ready();
83 
84 protected slots:
85  void soundProcessSuccess(AudioDataPointer audioData);
86  void soundProcessError(int error, QString str);
87 
88 private:
89  virtual void downloadFinished(const QByteArray& data) override;
90 
91  AudioDataPointer _audioData;
92 
93  // Only used for caching until the download has finished
94  int _numChannels { 0 };
95 };
96 
97 class SoundProcessor : public QObject, public QRunnable {
98  Q_OBJECT
99 
100 public:
101  struct AudioProperties {
102  uint8_t numChannels { 0 };
103  uint32_t sampleRate { 0 };
104  };
105 
106  SoundProcessor(QWeakPointer<Resource> sound, QByteArray data);
107 
108  virtual void run() override;
109 
110  QByteArray downSample(const QByteArray& rawAudioByteArray,
111  AudioProperties properties);
112  AudioProperties interpretAsWav(const QByteArray& inputAudioByteArray,
113  QByteArray& outputAudioByteArray);
114  AudioProperties interpretAsMP3(const QByteArray& inputAudioByteArray,
115  QByteArray& outputAudioByteArray);
116 
117 signals:
118  void onSuccess(AudioDataPointer audioData);
119  void onError(int error, QString str);
120 
121 private:
122  const QWeakPointer<Resource> _sound;
123  const QByteArray _data;
124 };
125 
126 typedef QSharedPointer<Sound> SharedSoundPointer;
127 
128 /*@jsdoc
129  * An audio resource, created by {@link SoundCache.getSound}, to be played back using {@link Audio.playSound}.
130  * <p>Supported formats:</p>
131  * <ul>
132  * <li>WAV: 16-bit uncompressed at any sample rate, with 1 (mono), 2 (stereo), or 4 (ambisonic) channels.</li>
133  * <li>MP3: Mono or stereo, at any sample rate.</li>
134  * <li>RAW: 48khz 16-bit mono or stereo. File name must include <code>".stereo"</code> to be interpreted as stereo.</li>
135  * </ul>
136  *
137  * @class SoundObject
138  * @hideconstructor
139  *
140  * @hifi-interface
141  * @hifi-client-entity
142  * @hifi-avatar
143  * @hifi-server-entity
144  * @hifi-assignment-client
145  *
146  * @property {boolean} downloaded - <code>true</code> if the sound has been downloaded and is ready to be played, otherwise
147  * <code>false</code>. <em>Read-only.</em>
148  * @property {number} duration - The duration of the sound, in seconds. <em>Read-only.</em>
149  */
150 class SoundScriptingInterface : public QObject {
151  Q_OBJECT
152 
153  Q_PROPERTY(bool downloaded READ isReady)
154  Q_PROPERTY(float duration READ getDuration)
155 
156 public:
157  SoundScriptingInterface(const SharedSoundPointer& sound);
158  const SharedSoundPointer& getSound() { return _sound; }
159 
160  bool isReady() const { return _sound ? _sound->isReady() : false; }
161  float getDuration() { return _sound ? _sound->getDuration() : 0.0f; }
162 
163 /*@jsdoc
164  * Triggered when the sound has been downloaded and is ready to be played.
165  * @function SoundObject.ready
166  * @returns {Signal}
167  */
168 signals:
169  void ready();
170 
171 private:
172  SharedSoundPointer _sound;
173 };
174 
175 Q_DECLARE_METATYPE(SharedSoundPointer)
176 ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in);
177 bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out);
178 
179 #endif // hifi_Sound_h
Base class for resources.
Definition: ResourceCache.h:409
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40