Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (audio_mix.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include <memalign.h> | |
26 | ||
27 | #include <retro_environment.h> | |
28 | ||
29 | #if defined(__SSE2__) | |
30 | #include <emmintrin.h> | |
31 | #elif defined(__ALTIVEC__) | |
32 | #include <altivec.h> | |
33 | #endif | |
34 | ||
35 | #include <retro_miscellaneous.h> | |
36 | #include <audio/audio_mix.h> | |
37 | #include <streams/file_stream.h> | |
38 | #include <audio/conversion/float_to_s16.h> | |
39 | #include <audio/conversion/s16_to_float.h> | |
40 | ||
41 | void audio_mix_volume_C(float *out, const float *in, float vol, size_t samples) | |
42 | { | |
43 | size_t i; | |
44 | for (i = 0; i < samples; i++) | |
45 | out[i] += in[i] * vol; | |
46 | } | |
47 | ||
48 | #ifdef __SSE2__ | |
49 | void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t samples) | |
50 | { | |
51 | size_t i, remaining_samples; | |
52 | __m128 volume = _mm_set1_ps(vol); | |
53 | ||
54 | for (i = 0; i + 16 <= samples; i += 16, out += 16, in += 16) | |
55 | { | |
56 | unsigned j; | |
57 | __m128 input[4]; | |
58 | __m128 additive[4]; | |
59 | ||
60 | input[0] = _mm_loadu_ps(out + 0); | |
61 | input[1] = _mm_loadu_ps(out + 4); | |
62 | input[2] = _mm_loadu_ps(out + 8); | |
63 | input[3] = _mm_loadu_ps(out + 12); | |
64 | ||
65 | additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in + 0)); | |
66 | additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in + 4)); | |
67 | additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in + 8)); | |
68 | additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12)); | |
69 | ||
70 | for (j = 0; j < 4; j++) | |
71 | _mm_storeu_ps(out + 4 * j, _mm_add_ps(input[j], additive[j])); | |
72 | } | |
73 | ||
74 | remaining_samples = samples - i; | |
75 | ||
76 | for (i = 0; i < remaining_samples; i++) | |
77 | out[i] += in[i] * vol; | |
78 | } | |
79 | #endif | |
80 | ||
81 | void audio_mix_free_chunk(audio_chunk_t *chunk) | |
82 | { | |
83 | if (!chunk) | |
84 | return; | |
85 | ||
86 | #ifdef HAVE_RWAV | |
87 | if (chunk->rwav && chunk->rwav->samples) | |
88 | { | |
89 | /* rwav_free only frees the samples */ | |
90 | rwav_free(chunk->rwav); | |
91 | free(chunk->rwav); | |
92 | } | |
93 | #endif | |
94 | ||
95 | if (chunk->buf) | |
96 | free(chunk->buf); | |
97 | ||
98 | if (chunk->upsample_buf) | |
99 | memalign_free(chunk->upsample_buf); | |
100 | ||
101 | if (chunk->float_buf) | |
102 | memalign_free(chunk->float_buf); | |
103 | ||
104 | if (chunk->float_resample_buf) | |
105 | memalign_free(chunk->float_resample_buf); | |
106 | ||
107 | if (chunk->resample_buf) | |
108 | memalign_free(chunk->resample_buf); | |
109 | ||
110 | if (chunk->resampler && chunk->resampler_data) | |
111 | chunk->resampler->free(chunk->resampler_data); | |
112 | ||
113 | free(chunk); | |
114 | } | |
115 | ||
116 | audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate, | |
117 | const char *resampler_ident, enum resampler_quality quality) | |
118 | { | |
119 | #ifdef HAVE_RWAV | |
120 | int sample_size; | |
121 | int64_t len = 0; | |
122 | void *buf = NULL; | |
123 | audio_chunk_t *chunk = (audio_chunk_t*)malloc(sizeof(*chunk)); | |
124 | ||
125 | if (!chunk) | |
126 | return NULL; | |
127 | ||
128 | chunk->buf = NULL; | |
129 | chunk->upsample_buf = NULL; | |
130 | chunk->float_buf = NULL; | |
131 | chunk->float_resample_buf = NULL; | |
132 | chunk->resample_buf = NULL; | |
133 | chunk->len = 0; | |
134 | chunk->resample_len = 0; | |
135 | chunk->sample_rate = sample_rate; | |
136 | chunk->resample = false; | |
137 | chunk->resampler = NULL; | |
138 | chunk->resampler_data = NULL; | |
139 | chunk->ratio = 0.00f; | |
140 | chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t)); | |
141 | ||
142 | if (!chunk->rwav) | |
143 | goto error; | |
144 | ||
145 | chunk->rwav->bitspersample = 0; | |
146 | chunk->rwav->numchannels = 0; | |
147 | chunk->rwav->samplerate = 0; | |
148 | chunk->rwav->numsamples = 0; | |
149 | chunk->rwav->subchunk2size = 0; | |
150 | chunk->rwav->samples = NULL; | |
151 | ||
152 | if (!filestream_read_file(path, &buf, &len)) | |
153 | goto error; | |
154 | ||
155 | chunk->buf = buf; | |
156 | chunk->len = len; | |
157 | ||
158 | if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR) | |
159 | goto error; | |
160 | ||
161 | /* numsamples does not know or care about | |
162 | * multiple channels, but we need space for 2 */ | |
163 | chunk->upsample_buf = (int16_t*)memalign_alloc(128, | |
164 | chunk->rwav->numsamples * 2 * sizeof(int16_t)); | |
165 | ||
166 | sample_size = chunk->rwav->bitspersample / 8; | |
167 | ||
168 | if (sample_size == 1) | |
169 | { | |
170 | unsigned i; | |
171 | ||
172 | if (chunk->rwav->numchannels == 1) | |
173 | { | |
174 | for (i = 0; i < chunk->rwav->numsamples; i++) | |
175 | { | |
176 | uint8_t *sample = ( | |
177 | (uint8_t*)chunk->rwav->samples) + i; | |
178 | ||
179 | chunk->upsample_buf[i * 2] = | |
180 | (int16_t)((sample[0] - 128) << 8); | |
181 | chunk->upsample_buf[(i * 2) + 1] = | |
182 | (int16_t)((sample[0] - 128) << 8); | |
183 | } | |
184 | } | |
185 | else if (chunk->rwav->numchannels == 2) | |
186 | { | |
187 | for (i = 0; i < chunk->rwav->numsamples; i++) | |
188 | { | |
189 | uint8_t *sample = ( | |
190 | (uint8_t*)chunk->rwav->samples) + | |
191 | (i * 2); | |
192 | ||
193 | chunk->upsample_buf[i * 2] = | |
194 | (int16_t)((sample[0] - 128) << 8); | |
195 | chunk->upsample_buf[(i * 2) + 1] = | |
196 | (int16_t)((sample[1] - 128) << 8); | |
197 | } | |
198 | } | |
199 | } | |
200 | else if (sample_size == 2) | |
201 | { | |
202 | if (chunk->rwav->numchannels == 1) | |
203 | { | |
204 | unsigned i; | |
205 | ||
206 | for (i = 0; i < chunk->rwav->numsamples; i++) | |
207 | { | |
208 | int16_t sample = ((int16_t*) | |
209 | chunk->rwav->samples)[i]; | |
210 | ||
211 | chunk->upsample_buf[i * 2] = sample; | |
212 | chunk->upsample_buf[(i * 2) + 1] = sample; | |
213 | } | |
214 | } | |
215 | else if (chunk->rwav->numchannels == 2) | |
216 | memcpy(chunk->upsample_buf, chunk->rwav->samples, | |
217 | chunk->rwav->subchunk2size); | |
218 | } | |
219 | else if (sample_size != 2) | |
220 | { | |
221 | /* we don't support any other sample size besides 8 and 16-bit yet */ | |
222 | goto error; | |
223 | } | |
224 | ||
225 | if (sample_rate != (int)chunk->rwav->samplerate) | |
226 | { | |
227 | chunk->resample = true; | |
228 | chunk->ratio = (double)sample_rate / chunk->rwav->samplerate; | |
229 | ||
230 | retro_resampler_realloc(&chunk->resampler_data, | |
231 | &chunk->resampler, | |
232 | resampler_ident, | |
233 | quality, | |
234 | chunk->ratio); | |
235 | ||
236 | if (chunk->resampler && chunk->resampler_data) | |
237 | { | |
238 | struct resampler_data info; | |
239 | ||
240 | chunk->float_buf = (float*)memalign_alloc(128, | |
241 | chunk->rwav->numsamples * 2 * | |
242 | chunk->ratio * sizeof(float)); | |
243 | ||
244 | /* why is *3 needed instead of just *2? Does the | |
245 | * sinc driver require more space than we know about? */ | |
246 | chunk->float_resample_buf = (float*)memalign_alloc(128, | |
247 | chunk->rwav->numsamples * 3 * | |
248 | chunk->ratio * sizeof(float)); | |
249 | ||
250 | convert_s16_to_float(chunk->float_buf, | |
251 | chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0); | |
252 | ||
253 | info.data_in = (const float*)chunk->float_buf; | |
254 | info.data_out = chunk->float_resample_buf; | |
255 | /* a 'frame' consists of two channels, so we set this | |
256 | * to the number of samples irrespective of channel count */ | |
257 | info.input_frames = chunk->rwav->numsamples; | |
258 | info.output_frames = 0; | |
259 | info.ratio = chunk->ratio; | |
260 | ||
261 | chunk->resampler->process(chunk->resampler_data, &info); | |
262 | ||
263 | /* number of output_frames does not increase with | |
264 | * multiple channels, but assume we need space for 2 */ | |
265 | chunk->resample_buf = (int16_t*)memalign_alloc(128, | |
266 | info.output_frames * 2 * sizeof(int16_t)); | |
267 | chunk->resample_len = info.output_frames; | |
268 | convert_float_to_s16(chunk->resample_buf, | |
269 | chunk->float_resample_buf, info.output_frames * 2); | |
270 | } | |
271 | } | |
272 | ||
273 | return chunk; | |
274 | ||
275 | error: | |
276 | audio_mix_free_chunk(chunk); | |
277 | #endif | |
278 | return NULL; | |
279 | } | |
280 | ||
281 | size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk) | |
282 | { | |
283 | if (!chunk) | |
284 | return 0; | |
285 | ||
286 | #ifdef HAVE_RWAV | |
287 | if (chunk->rwav) | |
288 | { | |
289 | if (chunk->resample) | |
290 | return chunk->resample_len; | |
291 | return chunk->rwav->numsamples; | |
292 | } | |
293 | #endif | |
294 | ||
295 | /* no other filetypes supported yet */ | |
296 | return 0; | |
297 | } | |
298 | ||
299 | /** | |
300 | * audio_mix_get_chunk_sample: | |
301 | * @chunk : audio chunk instance | |
302 | * @channel : channel of the sample (0=left, 1=right) | |
303 | * @index : index of the sample | |
304 | * | |
305 | * Get a sample from an audio chunk. | |
306 | * | |
307 | * Returns: A signed 16-bit audio sample. | |
308 | **/ | |
309 | int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, | |
310 | unsigned channel, size_t index) | |
311 | { | |
312 | if (!chunk) | |
313 | return 0; | |
314 | ||
315 | #ifdef HAVE_RWAV | |
316 | if (chunk->rwav) | |
317 | { | |
318 | int sample_size = chunk->rwav->bitspersample / 8; | |
319 | int16_t sample_out = 0; | |
320 | ||
321 | /* 0 is the first/left channel */ | |
322 | uint8_t *sample = NULL; | |
323 | ||
324 | if (chunk->resample) | |
325 | sample = (uint8_t*)chunk->resample_buf + | |
326 | (sample_size * index * chunk->rwav->numchannels) | |
327 | + (channel * sample_size); | |
328 | else | |
329 | sample = (uint8_t*)chunk->upsample_buf + | |
330 | (sample_size * index * chunk->rwav->numchannels) | |
331 | + (channel * sample_size); | |
332 | ||
333 | sample_out = (int16_t)*sample; | |
334 | ||
335 | return sample_out; | |
336 | } | |
337 | #endif | |
338 | ||
339 | /* no other filetypes supported yet */ | |
340 | return 0; | |
341 | } | |
342 | ||
343 | int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk) | |
344 | { | |
345 | if (!chunk) | |
346 | return 0; | |
347 | ||
348 | #ifdef HAVE_RWAV | |
349 | if (chunk->rwav) | |
350 | { | |
351 | int16_t *sample; | |
352 | ||
353 | if (chunk->resample) | |
354 | sample = chunk->resample_buf; | |
355 | else | |
356 | sample = chunk->upsample_buf; | |
357 | ||
358 | return sample; | |
359 | } | |
360 | #endif | |
361 | ||
362 | return NULL; | |
363 | } | |
364 | ||
365 | int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk) | |
366 | { | |
367 | if (!chunk) | |
368 | return 0; | |
369 | ||
370 | #ifdef HAVE_RWAV | |
371 | if (chunk->rwav) | |
372 | return chunk->rwav->numchannels; | |
373 | #endif | |
374 | ||
375 | /* don't support other formats yet */ | |
376 | return 0; | |
377 | } |