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