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
5namespace 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}