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