1 /*******************************************************************************
2 * Copyright 2009-2016 Jörg Müller
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16
17 #include "generator/Sawtooth.h"
18 #include "generator/Sine.h"
19 #include "generator/Silence.h"
20 #include "generator/Square.h"
21 #include "generator/Triangle.h"
22 #include "file/File.h"
23 #include "file/FileWriter.h"
24 #include "util/StreamBuffer.h"
25 #include "fx/Accumulator.h"
26 #include "fx/ADSR.h"
27 #include "fx/Delay.h"
28 #include "fx/Envelope.h"
29 #include "fx/Fader.h"
30 #include "fx/Highpass.h"
31 #include "fx/IIRFilter.h"
32 #include "fx/Limiter.h"
33 #include "fx/Loop.h"
34 #include "fx/Lowpass.h"
35 #include "fx/Modulator.h"
36 #include "fx/Pitch.h"
37 #include "fx/Reverse.h"
38 #include "fx/Sum.h"
39 #include "fx/Threshold.h"
40 #include "fx/Volume.h"
41 #include "fx/SoundList.h"
42 #include "fx/MutableSound.h"
43 #include "sequence/Double.h"
44 #include "sequence/Superpose.h"
45 #include "sequence/PingPong.h"
46 #include "respec/LinearResample.h"
47 #include "respec/JOSResample.h"
48 #include "respec/JOSResampleReader.h"
49 #include "respec/ChannelMapper.h"
50 #include "respec/ChannelMapperReader.h"
51 #include "util/Buffer.h"
52 #include "Exception.h"
53
54 #ifdef WITH_CONVOLUTION
55 #include "fx/BinauralSound.h"
56 #include "fx/ConvolverSound.h"
57 #endif
58
59 #include <cassert>
60 #include <cstring>
61
62 using namespace aud;
63
64 #define AUD_CAPI_IMPLEMENTATION
65 #include "AUD_Sound.h"
66
convSpecToC(aud::Specs specs)67 static inline AUD_Specs convSpecToC(aud::Specs specs)
68 {
69 AUD_Specs s;
70 s.channels = static_cast<AUD_Channels>(specs.channels);
71 s.rate = static_cast<AUD_SampleRate>(specs.rate);
72 return s;
73 }
74
convCToSpec(AUD_Specs specs)75 static inline aud::Specs convCToSpec(AUD_Specs specs)
76 {
77 aud::Specs s;
78 s.channels = static_cast<Channels>(specs.channels);
79 s.rate = static_cast<SampleRate>(specs.rate);
80 return s;
81 }
82
AUD_Sound_getSpecs(AUD_Sound * sound)83 AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound)
84 {
85 assert(sound);
86
87 return convSpecToC((*sound)->createReader()->getSpecs());
88 }
89
AUD_Sound_getLength(AUD_Sound * sound)90 AUD_API int AUD_Sound_getLength(AUD_Sound* sound)
91 {
92 assert(sound);
93
94 return (*sound)->createReader()->getLength();
95 }
96
AUD_Sound_data(AUD_Sound * sound,int * length,AUD_Specs * specs)97 AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs)
98 {
99 assert(sound);
100 assert(length);
101 assert(specs);
102
103 auto stream_buffer = std::dynamic_pointer_cast<StreamBuffer>(*sound);
104 if(!stream_buffer)
105 stream_buffer = std::make_shared<StreamBuffer>(*sound);
106 *specs = convSpecToC(stream_buffer->getSpecs());
107 auto buffer = stream_buffer->getBuffer();
108
109 *length = buffer->getSize() / AUD_SAMPLE_SIZE((*specs));
110
111 sample_t* data = new sample_t[buffer->getSize()];
112
113 std::memcpy(data, buffer->getBuffer(), buffer->getSize());
114
115 return data;
116 }
117
AUD_Sound_freeData(sample_t * data)118 AUD_API void AUD_Sound_freeData(sample_t* data)
119 {
120 delete[] data;
121 }
122
AUD_Sound_write(AUD_Sound * sound,const char * filename,AUD_SampleRate rate,AUD_Channels channels,AUD_SampleFormat format,AUD_Container container,AUD_Codec codec,int bitrate,int buffersize)123 AUD_API const char* AUD_Sound_write(AUD_Sound* sound, const char* filename, AUD_SampleRate rate, AUD_Channels channels, AUD_SampleFormat format, AUD_Container container, AUD_Codec codec, int bitrate, int buffersize)
124 {
125 assert(sound);
126 assert(filename);
127
128 try
129 {
130 std::shared_ptr<IReader> reader = (*sound)->createReader();
131
132 DeviceSpecs specs;
133 specs.specs = reader->getSpecs();
134
135 if((rate != RATE_INVALID) && (specs.rate != rate))
136 {
137 specs.rate = rate;
138 reader = std::make_shared<JOSResampleReader>(reader, rate);
139 }
140
141 if((channels != AUD_CHANNELS_INVALID) && (specs.channels != static_cast<Channels>(channels)))
142 {
143 specs.channels = static_cast<Channels>(channels);
144 reader = std::make_shared<ChannelMapperReader>(reader, specs.channels);
145 }
146
147 if(format == AUD_FORMAT_INVALID)
148 format = AUD_FORMAT_S16;
149 specs.format = static_cast<SampleFormat>(format);
150
151 const char* invalid_container_error = "Container could not be determined from filename.";
152
153 if(container == AUD_CONTAINER_INVALID)
154 {
155 std::string path = filename;
156
157 if(path.length() < 4)
158 return invalid_container_error;
159
160 std::string extension = path.substr(path.length() - 4);
161
162 if(extension == ".ac3")
163 container = AUD_CONTAINER_AC3;
164 else if(extension == "flac")
165 container = AUD_CONTAINER_FLAC;
166 else if(extension == ".mkv")
167 container = AUD_CONTAINER_MATROSKA;
168 else if(extension == ".mp2")
169 container = AUD_CONTAINER_MP2;
170 else if(extension == ".mp3")
171 container = AUD_CONTAINER_MP3;
172 else if(extension == ".ogg")
173 container = AUD_CONTAINER_OGG;
174 else if(extension == ".wav")
175 container = AUD_CONTAINER_WAV;
176 else
177 return invalid_container_error;
178 }
179
180 if(codec == AUD_CODEC_INVALID)
181 {
182 switch(container)
183 {
184 case AUD_CONTAINER_AC3:
185 codec = AUD_CODEC_AC3;
186 break;
187 case AUD_CONTAINER_FLAC:
188 codec = AUD_CODEC_FLAC;
189 break;
190 case AUD_CONTAINER_MATROSKA:
191 codec = AUD_CODEC_OPUS;
192 break;
193 case AUD_CONTAINER_MP2:
194 codec = AUD_CODEC_MP2;
195 break;
196 case AUD_CONTAINER_MP3:
197 codec = AUD_CODEC_MP3;
198 break;
199 case AUD_CONTAINER_OGG:
200 codec = AUD_CODEC_VORBIS;
201 break;
202 case AUD_CONTAINER_WAV:
203 codec = AUD_CODEC_PCM;
204 break;
205 default:
206 return "Unknown container, cannot select default codec.";
207 }
208 }
209
210 if(buffersize <= 0)
211 buffersize = AUD_DEFAULT_BUFFER_SIZE;
212
213 std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, specs, static_cast<Container>(container), static_cast<Codec>(codec), bitrate);
214 FileWriter::writeReader(reader, writer, 0, buffersize);
215 }
216 catch(Exception&)
217 {
218 return "An exception occured while writing.";
219 }
220
221 return nullptr;
222 }
223
AUD_Sound_buffer(sample_t * data,int length,AUD_Specs specs)224 AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs specs)
225 {
226 assert(data);
227
228 if(length <= 0 || specs.rate <= 0 || specs.channels <= 0)
229 {
230 return nullptr;
231 }
232
233 int size = length * AUD_SAMPLE_SIZE(specs);
234
235 std::shared_ptr<Buffer> buffer = std::make_shared<Buffer>(size);
236
237 std::memcpy(buffer->getBuffer(), data, size);
238
239 try
240 {
241 return new AUD_Sound(new StreamBuffer(buffer, convCToSpec(specs)));
242 }
243 catch(Exception&)
244 {
245 return nullptr;
246 }
247 }
248
AUD_Sound_bufferFile(unsigned char * buffer,int size)249 AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size)
250 {
251 assert(buffer);
252 return new AUD_Sound(new File(buffer, size));
253 }
254
AUD_Sound_cache(AUD_Sound * sound)255 AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound)
256 {
257 assert(sound);
258
259 try
260 {
261 return new AUD_Sound(new StreamBuffer(*sound));
262 }
263 catch(Exception&)
264 {
265 return nullptr;
266 }
267 }
268
AUD_Sound_file(const char * filename)269 AUD_API AUD_Sound* AUD_Sound_file(const char* filename)
270 {
271 assert(filename);
272 return new AUD_Sound(new File(filename));
273 }
274
AUD_Sound_sawtooth(float frequency,AUD_SampleRate rate)275 AUD_API AUD_Sound* AUD_Sound_sawtooth(float frequency, AUD_SampleRate rate)
276 {
277 return new AUD_Sound(new Sawtooth(frequency, rate));
278 }
279
AUD_Sound_silence(AUD_SampleRate rate)280 AUD_API AUD_Sound* AUD_Sound_silence(AUD_SampleRate rate)
281 {
282 return new AUD_Sound(new Silence(rate));
283 }
284
AUD_Sound_sine(float frequency,AUD_SampleRate rate)285 AUD_API AUD_Sound* AUD_Sound_sine(float frequency, AUD_SampleRate rate)
286 {
287 return new AUD_Sound(new Sine(frequency, rate));
288 }
289
AUD_Sound_square(float frequency,AUD_SampleRate rate)290 AUD_API AUD_Sound* AUD_Sound_square(float frequency, AUD_SampleRate rate)
291 {
292 return new AUD_Sound(new Square(frequency, rate));
293 }
294
AUD_Sound_triangle(float frequency,AUD_SampleRate rate)295 AUD_API AUD_Sound* AUD_Sound_triangle(float frequency, AUD_SampleRate rate)
296 {
297 return new AUD_Sound(new Triangle(frequency, rate));
298 }
299
AUD_Sound_accumulate(AUD_Sound * sound,int additive)300 AUD_API AUD_Sound* AUD_Sound_accumulate(AUD_Sound* sound, int additive)
301 {
302 assert(sound);
303
304 try
305 {
306 return new AUD_Sound(new Accumulator(*sound, additive));
307 }
308 catch(Exception&)
309 {
310 return nullptr;
311 }
312 }
313
AUD_Sound_ADSR(AUD_Sound * sound,float attack,float decay,float sustain,float release)314 AUD_API AUD_Sound* AUD_Sound_ADSR(AUD_Sound* sound, float attack, float decay, float sustain, float release)
315 {
316 assert(sound);
317
318 try
319 {
320 return new AUD_Sound(new ADSR(*sound, attack, decay, sustain, release));
321 }
322 catch(Exception&)
323 {
324 return nullptr;
325 }
326 }
327
AUD_Sound_delay(AUD_Sound * sound,float delay)328 AUD_API AUD_Sound* AUD_Sound_delay(AUD_Sound* sound, float delay)
329 {
330 assert(sound);
331
332 try
333 {
334 return new AUD_Sound(new Delay(*sound, delay));
335 }
336 catch(Exception&)
337 {
338 return nullptr;
339 }
340 }
341
AUD_Sound_envelope(AUD_Sound * sound,float attack,float release,float threshold,float arthreshold)342 AUD_API AUD_Sound* AUD_Sound_envelope(AUD_Sound* sound, float attack, float release, float threshold, float arthreshold)
343 {
344 assert(sound);
345
346 try
347 {
348 return new AUD_Sound(new Envelope(*sound, attack, release, threshold, arthreshold));
349 }
350 catch(Exception&)
351 {
352 return nullptr;
353 }
354 }
355
AUD_Sound_fadein(AUD_Sound * sound,float start,float length)356 AUD_API AUD_Sound* AUD_Sound_fadein(AUD_Sound* sound, float start, float length)
357 {
358 assert(sound);
359
360 try
361 {
362 return new AUD_Sound(new Fader(*sound, FADE_IN, start, length));
363 }
364 catch(Exception&)
365 {
366 return nullptr;
367 }
368 }
369
AUD_Sound_fadeout(AUD_Sound * sound,float start,float length)370 AUD_API AUD_Sound* AUD_Sound_fadeout(AUD_Sound* sound, float start, float length)
371 {
372 assert(sound);
373
374 try
375 {
376 return new AUD_Sound(new Fader(*sound, FADE_OUT, start, length));
377 }
378 catch(Exception&)
379 {
380 return nullptr;
381 }
382 }
383
AUD_Sound_filter(AUD_Sound * sound,float * b,int b_length,float * a,int a_length)384 AUD_API AUD_Sound* AUD_Sound_filter(AUD_Sound* sound, float* b, int b_length, float* a, int a_length)
385 {
386 assert(sound);
387
388 try
389 {
390 std::vector<float> a_coeff, b_coeff;
391
392 if(b)
393 for(int i = 0; i < b_length; i++)
394 b_coeff.push_back(b[i]);
395
396 if(a)
397 {
398 for(int i = 0; i < a_length; i++)
399 a_coeff.push_back(a[i]);
400
401 if(*a == 0.0f)
402 a_coeff[0] = 1.0f;
403 }
404
405 return new AUD_Sound(new IIRFilter(*sound, b_coeff, a_coeff));
406 }
407 catch(Exception&)
408 {
409 return nullptr;
410 }
411 }
412
AUD_Sound_highpass(AUD_Sound * sound,float frequency,float Q)413 AUD_API AUD_Sound* AUD_Sound_highpass(AUD_Sound* sound, float frequency, float Q)
414 {
415 assert(sound);
416
417 try
418 {
419 return new AUD_Sound(new Highpass(*sound, frequency, Q));
420 }
421 catch(Exception&)
422 {
423 return nullptr;
424 }
425 }
426
AUD_Sound_limit(AUD_Sound * sound,float start,float end)427 AUD_API AUD_Sound* AUD_Sound_limit(AUD_Sound* sound, float start, float end)
428 {
429 assert(sound);
430
431 try
432 {
433 return new AUD_Sound(new Limiter(*sound, start, end));
434 }
435 catch(Exception&)
436 {
437 return nullptr;
438 }
439 }
440
AUD_Sound_loop(AUD_Sound * sound,int count)441 AUD_API AUD_Sound* AUD_Sound_loop(AUD_Sound* sound, int count)
442 {
443 assert(sound);
444
445 try
446 {
447 return new AUD_Sound(new Loop(*sound, count));
448 }
449 catch(Exception&)
450 {
451 return nullptr;
452 }
453 }
454
AUD_Sound_lowpass(AUD_Sound * sound,float frequency,float Q)455 AUD_API AUD_Sound* AUD_Sound_lowpass(AUD_Sound* sound, float frequency, float Q)
456 {
457 assert(sound);
458
459 try
460 {
461 return new AUD_Sound(new Lowpass(*sound, frequency, Q));
462 }
463 catch(Exception&)
464 {
465 return nullptr;
466 }
467 }
468
AUD_Sound_modulate(AUD_Sound * first,AUD_Sound * second)469 AUD_API AUD_Sound* AUD_Sound_modulate(AUD_Sound* first, AUD_Sound* second)
470 {
471 assert(first);
472 assert(second);
473
474 try
475 {
476 return new AUD_Sound(new Modulator(*first, *second));
477 }
478 catch(Exception&)
479 {
480 return nullptr;
481 }
482 }
483
AUD_Sound_pitch(AUD_Sound * sound,float factor)484 AUD_API AUD_Sound* AUD_Sound_pitch(AUD_Sound* sound, float factor)
485 {
486 assert(sound);
487
488 try
489 {
490 return new AUD_Sound(new Pitch(*sound, factor));
491 }
492 catch(Exception&)
493 {
494 return nullptr;
495 }
496 }
497
AUD_Sound_rechannel(AUD_Sound * sound,AUD_Channels channels)498 AUD_API AUD_Sound* AUD_Sound_rechannel(AUD_Sound* sound, AUD_Channels channels)
499 {
500 assert(sound);
501
502 try
503 {
504 DeviceSpecs specs;
505 specs.channels = static_cast<Channels>(channels);
506 specs.rate = RATE_INVALID;
507 specs.format = FORMAT_INVALID;
508 return new AUD_Sound(new ChannelMapper(*sound, specs));
509 }
510 catch(Exception&)
511 {
512 return nullptr;
513 }
514 }
515
AUD_Sound_resample(AUD_Sound * sound,AUD_SampleRate rate,bool high_quality)516 AUD_API AUD_Sound* AUD_Sound_resample(AUD_Sound* sound, AUD_SampleRate rate, bool high_quality)
517 {
518 assert(sound);
519
520 try
521 {
522 DeviceSpecs specs;
523 specs.channels = CHANNELS_INVALID;
524 specs.rate = rate;
525 specs.format = FORMAT_INVALID;
526 if(high_quality)
527 return new AUD_Sound(new JOSResample(*sound, specs));
528 else
529 return new AUD_Sound(new LinearResample(*sound, specs));
530 }
531 catch(Exception&)
532 {
533 return nullptr;
534 }
535 }
536
AUD_Sound_reverse(AUD_Sound * sound)537 AUD_API AUD_Sound* AUD_Sound_reverse(AUD_Sound* sound)
538 {
539 assert(sound);
540
541 try
542 {
543 return new AUD_Sound(new Reverse(*sound));
544 }
545 catch(Exception&)
546 {
547 return nullptr;
548 }
549 }
550
AUD_Sound_sum(AUD_Sound * sound)551 AUD_API AUD_Sound* AUD_Sound_sum(AUD_Sound* sound)
552 {
553 assert(sound);
554
555 try
556 {
557 return new AUD_Sound(new Sum(*sound));
558 }
559 catch(Exception&)
560 {
561 return nullptr;
562 }
563 }
564
AUD_Sound_threshold(AUD_Sound * sound,float threshold)565 AUD_API AUD_Sound* AUD_Sound_threshold(AUD_Sound* sound, float threshold)
566 {
567 assert(sound);
568
569 try
570 {
571 return new AUD_Sound(new Threshold(*sound, threshold));
572 }
573 catch(Exception&)
574 {
575 return nullptr;
576 }
577 }
578
AUD_Sound_volume(AUD_Sound * sound,float volume)579 AUD_API AUD_Sound* AUD_Sound_volume(AUD_Sound* sound, float volume)
580 {
581 assert(sound);
582
583 try
584 {
585 return new AUD_Sound(new Volume(*sound, volume));
586 }
587 catch(Exception&)
588 {
589 return nullptr;
590 }
591 }
592
AUD_Sound_join(AUD_Sound * first,AUD_Sound * second)593 AUD_API AUD_Sound* AUD_Sound_join(AUD_Sound* first, AUD_Sound* second)
594 {
595 assert(first);
596 assert(second);
597
598 try
599 {
600 return new AUD_Sound(new Double(*first, *second));
601 }
602 catch(Exception&)
603 {
604 return nullptr;
605 }
606 }
607
AUD_Sound_mix(AUD_Sound * first,AUD_Sound * second)608 AUD_API AUD_Sound* AUD_Sound_mix(AUD_Sound* first, AUD_Sound* second)
609 {
610 assert(first);
611 assert(second);
612
613 try
614 {
615 return new AUD_Sound(new Superpose(*first, *second));
616 }
617 catch(Exception&)
618 {
619 return nullptr;
620 }
621 }
622
AUD_Sound_pingpong(AUD_Sound * sound)623 AUD_API AUD_Sound* AUD_Sound_pingpong(AUD_Sound* sound)
624 {
625 assert(sound);
626
627 try
628 {
629 return new AUD_Sound(new PingPong(*sound));
630 }
631 catch(Exception&)
632 {
633 return nullptr;
634 }
635 }
636
AUD_Sound_free(AUD_Sound * sound)637 AUD_API void AUD_Sound_free(AUD_Sound* sound)
638 {
639 assert(sound);
640 delete sound;
641 }
642
AUD_Sound_copy(AUD_Sound * sound)643 AUD_API AUD_Sound* AUD_Sound_copy(AUD_Sound* sound)
644 {
645 return new std::shared_ptr<ISound>(*sound);
646 }
647
AUD_Sound_list(int random)648 AUD_API AUD_Sound* AUD_Sound_list(int random)
649 {
650 try
651 {
652 return new AUD_Sound(new SoundList(random));
653 }
654 catch(Exception&)
655 {
656 return nullptr;
657 }
658 }
659
AUD_SoundList_addSound(AUD_Sound * list,AUD_Sound * sound)660 AUD_API int AUD_SoundList_addSound(AUD_Sound* list, AUD_Sound* sound)
661 {
662 assert(sound);
663 assert(list);
664
665 std::shared_ptr<SoundList> s = std::dynamic_pointer_cast<SoundList>(*list);
666 if(s.get())
667 {
668 s->addSound(*sound);
669 return 1;
670 }
671 else
672 return 0;
673
674 }
675
AUD_Sound_mutable(AUD_Sound * sound)676 AUD_API AUD_Sound* AUD_Sound_mutable(AUD_Sound* sound)
677 {
678 assert(sound);
679
680 try
681 {
682 return new AUD_Sound(new MutableSound(*sound));
683 }
684 catch(Exception&)
685 {
686 return nullptr;
687 }
688 }
689
690 #ifdef WITH_CONVOLUTION
691
AUD_Sound_Convolver(AUD_Sound * sound,AUD_ImpulseResponse * filter,AUD_ThreadPool * threadPool)692 AUD_API AUD_Sound* AUD_Sound_Convolver(AUD_Sound* sound, AUD_ImpulseResponse* filter, AUD_ThreadPool* threadPool)
693 {
694 assert(sound);
695 assert(filter);
696 assert(threadPool);
697
698 try
699 {
700 return new AUD_Sound(new ConvolverSound(*sound, *filter, *threadPool));
701 }
702 catch(Exception&)
703 {
704 return nullptr;
705 }
706 }
707
AUD_Sound_Binaural(AUD_Sound * sound,AUD_HRTF * hrtfs,AUD_Source * source,AUD_ThreadPool * threadPool)708 AUD_API AUD_Sound* AUD_Sound_Binaural(AUD_Sound* sound, AUD_HRTF* hrtfs, AUD_Source* source, AUD_ThreadPool* threadPool)
709 {
710 assert(sound);
711 assert(hrtfs);
712 assert(source);
713 assert(threadPool);
714
715 try
716 {
717 return new AUD_Sound(new BinauralSound(*sound, *hrtfs, *source, *threadPool));
718 }
719 catch(Exception&)
720 {
721 return nullptr;
722 }
723 }
724
725 #endif
726