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 | #include "Audio/BsAudioUtility.h" |
4 | |
5 | namespace bs |
6 | { |
7 | void convertToMono8(const INT8* input, UINT8* output, UINT32 numSamples, UINT32 numChannels) |
8 | { |
9 | for (UINT32 i = 0; i < numSamples; i++) |
10 | { |
11 | INT16 sum = 0; |
12 | for (UINT32 j = 0; j < numChannels; j++) |
13 | { |
14 | sum += *input; |
15 | ++input; |
16 | } |
17 | |
18 | *output = sum / numChannels; |
19 | ++output; |
20 | } |
21 | } |
22 | |
23 | void convertToMono16(const INT16* input, INT16* output, UINT32 numSamples, UINT32 numChannels) |
24 | { |
25 | for (UINT32 i = 0; i < numSamples; i++) |
26 | { |
27 | INT32 sum = 0; |
28 | for (UINT32 j = 0; j < numChannels; j++) |
29 | { |
30 | sum += *input; |
31 | ++input; |
32 | } |
33 | |
34 | *output = sum / numChannels; |
35 | ++output; |
36 | } |
37 | } |
38 | |
39 | void convert32To24Bits(const INT32 input, UINT8* output) |
40 | { |
41 | UINT32 valToEncode = *(UINT32*)&input; |
42 | output[0] = (valToEncode >> 8) & 0x000000FF; |
43 | output[1] = (valToEncode >> 16) & 0x000000FF; |
44 | output[2] = (valToEncode >> 24) & 0x000000FF; |
45 | } |
46 | |
47 | void convertToMono24(const UINT8* input, UINT8* output, UINT32 numSamples, UINT32 numChannels) |
48 | { |
49 | for (UINT32 i = 0; i < numSamples; i++) |
50 | { |
51 | INT64 sum = 0; |
52 | for (UINT32 j = 0; j < numChannels; j++) |
53 | { |
54 | sum += AudioUtility::convert24To32Bits(input); |
55 | input += 3; |
56 | } |
57 | |
58 | INT32 avg = (INT32)(sum / numChannels); |
59 | convert32To24Bits(avg, output); |
60 | output += 3; |
61 | } |
62 | } |
63 | |
64 | void convertToMono32(const INT32* input, INT32* output, UINT32 numSamples, UINT32 numChannels) |
65 | { |
66 | for (UINT32 i = 0; i < numSamples; i++) |
67 | { |
68 | INT64 sum = 0; |
69 | for (UINT32 j = 0; j < numChannels; j++) |
70 | { |
71 | sum += *input; |
72 | ++input; |
73 | } |
74 | |
75 | *output = (INT32)(sum / numChannels); |
76 | ++output; |
77 | } |
78 | } |
79 | |
80 | void convert8To32Bits(const INT8* input, INT32* output, UINT32 numSamples) |
81 | { |
82 | for (UINT32 i = 0; i < numSamples; i++) |
83 | { |
84 | INT8 val = input[i]; |
85 | output[i] = val << 24; |
86 | } |
87 | } |
88 | |
89 | void convert16To32Bits(const INT16* input, INT32* output, UINT32 numSamples) |
90 | { |
91 | for (UINT32 i = 0; i < numSamples; i++) |
92 | output[i] = input[i] << 16; |
93 | } |
94 | |
95 | void convert24To32Bits(const UINT8* input, INT32* output, UINT32 numSamples) |
96 | { |
97 | for (UINT32 i = 0; i < numSamples; i++) |
98 | { |
99 | output[i] = AudioUtility::convert24To32Bits(input); |
100 | input += 3; |
101 | } |
102 | } |
103 | |
104 | void convert32To8Bits(const INT32* input, UINT8* output, UINT32 numSamples) |
105 | { |
106 | for (UINT32 i = 0; i < numSamples; i++) |
107 | output[i] = (INT8)(input[i] >> 24); |
108 | } |
109 | |
110 | void convert32To16Bits(const INT32* input, INT16* output, UINT32 numSamples) |
111 | { |
112 | for (UINT32 i = 0; i < numSamples; i++) |
113 | output[i] = (INT16)(input[i] >> 16); |
114 | } |
115 | |
116 | void convert32To24Bits(const INT32* input, UINT8* output, UINT32 numSamples) |
117 | { |
118 | for (UINT32 i = 0; i < numSamples; i++) |
119 | { |
120 | convert32To24Bits(input[i], output); |
121 | output += 3; |
122 | } |
123 | } |
124 | |
125 | void AudioUtility::convertToMono(const UINT8* input, UINT8* output, UINT32 bitDepth, UINT32 numSamples, UINT32 numChannels) |
126 | { |
127 | switch (bitDepth) |
128 | { |
129 | case 8: |
130 | convertToMono8((INT8*)input, output, numSamples, numChannels); |
131 | break; |
132 | case 16: |
133 | convertToMono16((INT16*)input, (INT16*)output, numSamples, numChannels); |
134 | break; |
135 | case 24: |
136 | convertToMono24(input, output, numSamples, numChannels); |
137 | break; |
138 | case 32: |
139 | convertToMono32((INT32*)input, (INT32*)output, numSamples, numChannels); |
140 | break; |
141 | default: |
142 | assert(false); |
143 | break; |
144 | } |
145 | } |
146 | |
147 | void AudioUtility::convertBitDepth(const UINT8* input, UINT32 inBitDepth, UINT8* output, UINT32 outBitDepth, UINT32 numSamples) |
148 | { |
149 | INT32* srcBuffer = nullptr; |
150 | |
151 | const bool needTempBuffer = inBitDepth != 32; |
152 | if (needTempBuffer) |
153 | srcBuffer = (INT32*)bs_stack_alloc(numSamples * sizeof(INT32)); |
154 | else |
155 | srcBuffer = (INT32*)input; |
156 | |
157 | // Note: I convert to a temporary 32-bit buffer and then use that to convert to actual requested bit depth. |
158 | // It would be more efficient to convert directly from source to requested depth without a temporary buffer, |
159 | // at the cost of additional complexity. If this method ever becomes a performance issue consider that. |
160 | switch (inBitDepth) |
161 | { |
162 | case 8: |
163 | convert8To32Bits((INT8*)input, srcBuffer, numSamples); |
164 | break; |
165 | case 16: |
166 | convert16To32Bits((INT16*)input, srcBuffer, numSamples); |
167 | break; |
168 | case 24: |
169 | bs::convert24To32Bits(input, srcBuffer, numSamples); |
170 | break; |
171 | case 32: |
172 | // Do nothing |
173 | break; |
174 | default: |
175 | assert(false); |
176 | break; |
177 | } |
178 | |
179 | switch (outBitDepth) |
180 | { |
181 | case 8: |
182 | convert32To8Bits(srcBuffer, output, numSamples); |
183 | break; |
184 | case 16: |
185 | convert32To16Bits(srcBuffer, (INT16*)output, numSamples); |
186 | break; |
187 | case 24: |
188 | convert32To24Bits(srcBuffer, output, numSamples); |
189 | break; |
190 | case 32: |
191 | memcpy(output, srcBuffer, numSamples * sizeof(INT32)); |
192 | break; |
193 | default: |
194 | assert(false); |
195 | break; |
196 | } |
197 | |
198 | if (needTempBuffer) |
199 | { |
200 | bs_stack_free(srcBuffer); |
201 | srcBuffer = nullptr; |
202 | } |
203 | } |
204 | |
205 | void AudioUtility::convertToFloat(const UINT8* input, UINT32 inBitDepth, float* output, UINT32 numSamples) |
206 | { |
207 | if (inBitDepth == 8) |
208 | { |
209 | for (UINT32 i = 0; i < numSamples; i++) |
210 | { |
211 | INT8 sample = *(INT8*)input; |
212 | output[i] = sample / 127.0f; |
213 | |
214 | input++; |
215 | } |
216 | } |
217 | else if (inBitDepth == 16) |
218 | { |
219 | for (UINT32 i = 0; i < numSamples; i++) |
220 | { |
221 | INT16 sample = *(INT16*)input; |
222 | output[i] = sample / 32767.0f; |
223 | |
224 | input += 2; |
225 | } |
226 | } |
227 | else if (inBitDepth == 24) |
228 | { |
229 | for (UINT32 i = 0; i < numSamples; i++) |
230 | { |
231 | INT32 sample = convert24To32Bits(input); |
232 | output[i] = sample / 2147483647.0f; |
233 | |
234 | input += 3; |
235 | } |
236 | } |
237 | else if (inBitDepth == 32) |
238 | { |
239 | for (UINT32 i = 0; i < numSamples; i++) |
240 | { |
241 | INT32 sample = *(INT32*)input; |
242 | output[i] = sample / 2147483647.0f; |
243 | |
244 | input += 4; |
245 | } |
246 | } |
247 | else |
248 | assert(false); |
249 | } |
250 | |
251 | INT32 AudioUtility::convert24To32Bits(const UINT8* input) |
252 | { |
253 | return (input[2] << 24) | (input[1] << 16) | (input[0] << 8); |
254 | } |
255 | } |