update libchdr
[pcsx_rearmed.git] / deps / libretro-common / audio / audio_mix.c
CommitLineData
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
41void 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__
49void 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
81void 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
116audio_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
275error:
276 audio_mix_free_chunk(chunk);
277#endif
278 return NULL;
279}
280
281size_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 **/
309int16_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
343int16_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
365int 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}