Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 : #ifndef MOZILLA_AUDIOSAMPLEFORMAT_H_
7 : #define MOZILLA_AUDIOSAMPLEFORMAT_H_
8 :
9 : #include "nsAlgorithm.h"
10 : #include <algorithm>
11 :
12 : namespace mozilla {
13 :
14 : /**
15 : * Audio formats supported in MediaStreams and media elements.
16 : *
17 : * Only one of these is supported by AudioStream, and that is determined
18 : * at compile time (roughly, FLOAT32 on desktops, S16 on mobile). Media decoders
19 : * produce that format only; queued AudioData always uses that format.
20 : */
21 : enum AudioSampleFormat
22 : {
23 : // Native-endian signed 16-bit audio samples
24 : AUDIO_FORMAT_S16,
25 : // Signed 32-bit float samples
26 : AUDIO_FORMAT_FLOAT32,
27 : // Silence: format will be chosen later
28 : AUDIO_FORMAT_SILENCE,
29 : // The format used for output by AudioStream.
30 : #ifdef MOZ_SAMPLE_TYPE_S16
31 : AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_S16
32 : #else
33 : AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_FLOAT32
34 : #endif
35 : };
36 :
37 : enum {
38 : MAX_AUDIO_SAMPLE_SIZE = sizeof(float)
39 : };
40 :
41 : template <AudioSampleFormat Format> class AudioSampleTraits;
42 :
43 : template <> class AudioSampleTraits<AUDIO_FORMAT_FLOAT32> {
44 : public:
45 : typedef float Type;
46 : };
47 : template <> class AudioSampleTraits<AUDIO_FORMAT_S16> {
48 : public:
49 : typedef int16_t Type;
50 : };
51 :
52 : typedef AudioSampleTraits<AUDIO_OUTPUT_FORMAT>::Type AudioDataValue;
53 :
54 : template<typename T> class AudioSampleTypeToFormat;
55 :
56 : template <> class AudioSampleTypeToFormat<float> {
57 : public:
58 : static const AudioSampleFormat Format = AUDIO_FORMAT_FLOAT32;
59 : };
60 :
61 : template <> class AudioSampleTypeToFormat<short> {
62 : public:
63 : static const AudioSampleFormat Format = AUDIO_FORMAT_S16;
64 : };
65 :
66 : // Single-sample conversion
67 : /*
68 : * Use "2^N" conversion since it's simple, fast, "bit transparent", used by
69 : * many other libraries and apparently behaves reasonably.
70 : * http://blog.bjornroche.com/2009/12/int-float-int-its-jungle-out-there.html
71 : * http://blog.bjornroche.com/2009/12/linearity-and-dynamic-range-in-int.html
72 : */
73 : inline float
74 0 : AudioSampleToFloat(float aValue)
75 : {
76 0 : return aValue;
77 : }
78 : inline float
79 0 : AudioSampleToFloat(int16_t aValue)
80 : {
81 0 : return aValue/32768.0f;
82 : }
83 : inline float
84 0 : AudioSampleToFloat(int32_t aValue)
85 : {
86 0 : return aValue/(float)(1U<<31);
87 : }
88 :
89 : template <typename T> T FloatToAudioSample(float aValue);
90 :
91 : template <> inline float
92 0 : FloatToAudioSample<float>(float aValue)
93 : {
94 0 : return aValue;
95 : }
96 : template <> inline int16_t
97 0 : FloatToAudioSample<int16_t>(float aValue)
98 : {
99 0 : float v = aValue*32768.0f;
100 0 : float clamped = std::max(-32768.0f, std::min(32767.0f, v));
101 0 : return int16_t(clamped);
102 : }
103 :
104 : template <typename T> T UInt8bitToAudioSample(uint8_t aValue);
105 :
106 : template <> inline float
107 0 : UInt8bitToAudioSample<float>(uint8_t aValue)
108 : {
109 0 : return aValue * (static_cast<float>(2) / UINT8_MAX) - static_cast<float>(1);
110 : }
111 : template <> inline int16_t
112 : UInt8bitToAudioSample<int16_t>(uint8_t aValue)
113 : {
114 : return (int16_t(aValue) << 8) + aValue + INT16_MIN;
115 : }
116 :
117 : template <typename T> T IntegerToAudioSample(int16_t aValue);
118 :
119 : template <> inline float
120 0 : IntegerToAudioSample<float>(int16_t aValue)
121 : {
122 0 : return aValue / 32768.0f;
123 : }
124 : template <> inline int16_t
125 : IntegerToAudioSample<int16_t>(int16_t aValue)
126 : {
127 : return aValue;
128 : }
129 :
130 : template <typename T> T Int24bitToAudioSample(int32_t aValue);
131 :
132 : template <> inline float
133 0 : Int24bitToAudioSample<float>(int32_t aValue)
134 : {
135 0 : return aValue / static_cast<float>(1 << 23);
136 : }
137 : template <> inline int16_t
138 : Int24bitToAudioSample<int16_t>(int32_t aValue)
139 : {
140 : return aValue / 256;
141 : }
142 :
143 : template<typename SrcT, typename DstT>
144 : inline void
145 : ConvertAudioSample(SrcT aIn, DstT& aOut);
146 :
147 : template<>
148 : inline void
149 0 : ConvertAudioSample(int16_t aIn, int16_t & aOut)
150 : {
151 0 : aOut = aIn;
152 0 : }
153 :
154 : template<>
155 : inline void
156 : ConvertAudioSample(int16_t aIn, float& aOut)
157 : {
158 : aOut = AudioSampleToFloat(aIn);
159 : }
160 :
161 : template<>
162 : inline void
163 0 : ConvertAudioSample(float aIn, float& aOut)
164 : {
165 0 : aOut = aIn;
166 0 : }
167 :
168 : template<>
169 : inline void
170 : ConvertAudioSample(float aIn, int16_t& aOut)
171 : {
172 : aOut = FloatToAudioSample<int16_t>(aIn);
173 : }
174 :
175 : // Sample buffer conversion
176 :
177 : template <typename From, typename To> inline void
178 0 : ConvertAudioSamples(const From* aFrom, To* aTo, int aCount)
179 : {
180 0 : for (int i = 0; i < aCount; ++i) {
181 0 : aTo[i] = FloatToAudioSample<To>(AudioSampleToFloat(aFrom[i]));
182 : }
183 0 : }
184 : inline void
185 0 : ConvertAudioSamples(const int16_t* aFrom, int16_t* aTo, int aCount)
186 : {
187 0 : memcpy(aTo, aFrom, sizeof(*aTo)*aCount);
188 0 : }
189 : inline void
190 0 : ConvertAudioSamples(const float* aFrom, float* aTo, int aCount)
191 : {
192 0 : memcpy(aTo, aFrom, sizeof(*aTo)*aCount);
193 0 : }
194 :
195 : // Sample buffer conversion with scale
196 :
197 : template <typename From, typename To> inline void
198 0 : ConvertAudioSamplesWithScale(const From* aFrom, To* aTo, int aCount, float aScale)
199 : {
200 0 : if (aScale == 1.0f) {
201 0 : ConvertAudioSamples(aFrom, aTo, aCount);
202 0 : return;
203 : }
204 0 : for (int i = 0; i < aCount; ++i) {
205 0 : aTo[i] = FloatToAudioSample<To>(AudioSampleToFloat(aFrom[i])*aScale);
206 : }
207 : }
208 : inline void
209 0 : ConvertAudioSamplesWithScale(const int16_t* aFrom, int16_t* aTo, int aCount, float aScale)
210 : {
211 0 : if (aScale == 1.0f) {
212 0 : ConvertAudioSamples(aFrom, aTo, aCount);
213 0 : return;
214 : }
215 0 : if (0.0f <= aScale && aScale < 1.0f) {
216 0 : int32_t scale = int32_t((1 << 16) * aScale);
217 0 : for (int i = 0; i < aCount; ++i) {
218 0 : aTo[i] = int16_t((int32_t(aFrom[i]) * scale) >> 16);
219 : }
220 0 : return;
221 : }
222 0 : for (int i = 0; i < aCount; ++i) {
223 0 : aTo[i] = FloatToAudioSample<int16_t>(AudioSampleToFloat(aFrom[i])*aScale);
224 : }
225 : }
226 :
227 : // In place audio sample scaling.
228 : inline void
229 : ScaleAudioSamples(float* aBuffer, int aCount, float aScale)
230 : {
231 : for (int32_t i = 0; i < aCount; ++i) {
232 : aBuffer[i] *= aScale;
233 : }
234 : }
235 :
236 : inline void
237 : ScaleAudioSamples(short* aBuffer, int aCount, float aScale)
238 : {
239 : int32_t volume = int32_t((1 << 16) * aScale);
240 : for (int32_t i = 0; i < aCount; ++i) {
241 : aBuffer[i] = short((int32_t(aBuffer[i]) * volume) >> 16);
242 : }
243 : }
244 :
245 : inline const void*
246 0 : AddAudioSampleOffset(const void* aBase, AudioSampleFormat aFormat,
247 : int32_t aOffset)
248 : {
249 : static_assert(AUDIO_FORMAT_S16 == 0, "Bad constant");
250 : static_assert(AUDIO_FORMAT_FLOAT32 == 1, "Bad constant");
251 0 : NS_ASSERTION(aFormat == AUDIO_FORMAT_S16 || aFormat == AUDIO_FORMAT_FLOAT32,
252 : "Unknown format");
253 :
254 0 : return static_cast<const uint8_t*>(aBase) + (aFormat + 1)*2*aOffset;
255 : }
256 :
257 : } // namespace mozilla
258 :
259 : #endif /* MOZILLA_AUDIOSAMPLEFORMAT_H_ */
|