1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Resources/BsResource.h"
7
8namespace bs
9{
10 /** @addtogroup Audio
11 * @{
12 */
13
14 /** Valid internal engine audio formats. */
15 enum class BS_SCRIPT_EXPORT(m:Audio) AudioFormat
16 {
17 PCM, /**< Pulse code modulation audio ("raw" uncompressed audio). */
18 VORBIS /**< Vorbis compressed audio. */
19 };
20
21 /** Modes that determine how and when is audio data read. */
22 enum class BS_SCRIPT_EXPORT(m:Audio) AudioReadMode
23 {
24 /** Entire audio clip will be loaded and decompressed. Uses most memory but has lowest CPU impact. */
25 LoadDecompressed,
26 /**
27 * Entire audio clip will be loaded, but will be decompressed while playing. Uses medium amount of memory and has
28 * the highest CPU impact.
29 */
30 LoadCompressed,
31 /**
32 * Audio will be slowly streamed from the disk, and decompressed if needed. Uses very little memory, and has either
33 * low or high CPU impact depending if the audio is in a compressed format. Since data is streamed from the disk,
34 * read speeds could also be a bottleneck.
35 */
36 Stream
37 };
38
39 /** Descriptor used for initializing an audio clip. */
40 struct AUDIO_CLIP_DESC
41 {
42 /** Determines how is audio data read. */
43 AudioReadMode readMode = AudioReadMode::LoadDecompressed;
44
45 /** Determines in which format is the audio data in. */
46 AudioFormat format = AudioFormat::PCM;
47
48 /** Sample rate (frequency) of the audio data. */
49 UINT32 frequency = 44100;
50
51 /** Number of bits per sample. Not used for compressed formats. */
52 UINT32 bitDepth = 16;
53
54 /** Number of channels. Each channel has its own step of samples. */
55 UINT32 numChannels = 2;
56
57 /** Determines should the audio clip be played using 3D positioning. Only valid for mono audio. */
58 bool is3D = true;
59
60 /**
61 * Determines should the audio clip keep the original data in memory after creation. For example if the audio data
62 * is normally compressed, but audio clip uncompresses it on load, the original compressed data will be lost unless
63 * this is enabled. This will cause extra memory to be used, but can be useful in certain circumstances (for example
64 * you might require that data to save the audio clip on disk).
65 *
66 * When loading audio clip directly from disk, this properly is controlled by the ResourceLoadFlag::KeepSourceData.
67 */
68 bool keepSourceData = true;
69 };
70
71 /**
72 * Audio clip stores audio data in a compressed or uncompressed format. Clips can be provided to audio sources or
73 * other audio methods to be played.
74 */
75 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Audio) AudioClip : public Resource
76 {
77 public:
78 virtual ~AudioClip() = default;
79
80 /** Returns the size of a single sample, in bits. */
81 BS_SCRIPT_EXPORT(n:BitDepth,pr:getter)
82 UINT32 getBitDepth() const { return mDesc.bitDepth; }
83
84 /** Returns how many samples per second is the audio encoded in. */
85 BS_SCRIPT_EXPORT(n:SampleRate,pr:getter)
86 UINT32 getFrequency() const { return mDesc.frequency; }
87
88 /** Returns the number of channels provided by the clip. */
89 BS_SCRIPT_EXPORT(n:NumChannels,pr:getter)
90 UINT32 getNumChannels() const { return mDesc.numChannels; }
91
92 /**
93 * Returns in which format is audio data stored in.
94 *
95 * @see AudioFormat
96 */
97 BS_SCRIPT_EXPORT(n:Format,pr:getter)
98 AudioFormat getFormat() const { return mDesc.format; }
99
100 /**
101 * Returns how is the audio data read/decoded.
102 *
103 * @see AudioReadMode
104 */
105 BS_SCRIPT_EXPORT(n:ReadMode,pr:getter)
106 AudioReadMode getReadMode() const { return mDesc.readMode; }
107
108 /** Returns the length of the audio clip, in seconds. */
109 BS_SCRIPT_EXPORT(n:Duration,pr:getter)
110 float getLength() const { return mLength; }
111
112 /** Returns the total number of samples in the clip (includes all channels). */
113 BS_SCRIPT_EXPORT(n:NumSamples,pr:getter)
114 UINT32 getNumSamples() const { return mNumSamples; }
115
116 /** Determines will the clip be played a spatial 3D sound, or as a normal sound (for example music). */
117 BS_SCRIPT_EXPORT(n:Is3D,pr:getter)
118 bool is3D() const { return mDesc.is3D; }
119
120 /**
121 * Creates a new AudioClip and populates it with provided samples.
122 *
123 * @param[in] samples Data streams containing the samples to load. Data will be read starting from the current
124 * position in the stream. The samples should be in audio format as specified in the
125 * @p desc parameter. Ownership of the data stream is taken by the audio clip and the
126 * caller must not close it manually.
127 * @param[in] streamSize Number of bytes to read from the @p samples stream.
128 * @param[in] numSamples Total number of samples (including all channels).
129 * @param[in] desc Descriptor containing meta-data for the provided samples.
130 *
131 * @note If the provided samples are in PCM format, they should be signed integers of provided bit depth.
132 */
133 static HAudioClip create(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples,
134 const AUDIO_CLIP_DESC& desc);
135
136 public: // ***** INTERNAL ******
137 /** @name Internal
138 * @{
139 */
140
141 /** Creates a new AudioClip without initializing it. Use create() for normal use. */
142 static SPtr<AudioClip> _createPtr(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples,
143 const AUDIO_CLIP_DESC& desc);
144
145 /** @} */
146 protected:
147 AudioClip(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples, const AUDIO_CLIP_DESC& desc);
148
149 /** @copydoc Resource::initialize */
150 void initialize() override;
151
152 /** @copydoc Resource::isCompressible */
153 bool isCompressible() const override { return false; } // Compression handled on a case by case basis manually by the audio system
154
155 /** Returns original audio data. Only available if @p keepSourceData has been provided on creation. */
156 virtual SPtr<DataStream> getSourceStream(UINT32& size) = 0;
157
158 protected:
159 AUDIO_CLIP_DESC mDesc;
160 UINT32 mNumSamples;
161 UINT32 mStreamSize;
162 UINT32 mStreamOffset = 0;
163 float mLength = 0.0f;
164 SPtr<DataStream> mStreamData;
165
166 /************************************************************************/
167 /* SERIALIZATION */
168 /************************************************************************/
169 public:
170 friend class AudioClipRTTI;
171 static RTTITypeBase* getRTTIStatic();
172 RTTITypeBase* getRTTI() const override;
173
174 /**
175 * Creates an AudioClip with no samples. You must populate its data manually followed by a call to initialize().
176 *
177 * @note For serialization use only.
178 */
179 static SPtr<AudioClip> createEmpty();
180 };
181
182 /** @} */
183}