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 "Exception.h"
18 #include "IReader.h"
19 #include "file/File.h"
20 #include "respec/ChannelMapper.h"
21 #include "fx/Lowpass.h"
22 #include "fx/Highpass.h"
23 #include "fx/Envelope.h"
24 #include "respec/LinearResample.h"
25 #include "fx/Threshold.h"
26 #include "fx/Accumulator.h"
27 #include "fx/Sum.h"
28 #include "generator/Silence.h"
29 #include "fx/Limiter.h"
30 #include "devices/DeviceManager.h"
31 #include "sequence/Sequence.h"
32 #include "file/FileWriter.h"
33 #include "devices/ReadDevice.h"
34 #include "plugin/PluginManager.h"
35 #include "devices/DeviceManager.h"
36 #include "devices/IDeviceFactory.h"
37 #include "devices/NULLDevice.h"
38
39 #include <cassert>
40 #include <cstring>
41 #include <cmath>
42 #include <sstream>
43
44 using namespace aud;
45
46 #define AUD_CAPI_IMPLEMENTATION
47 #include "AUD_Special.h"
48
convSpecToC(aud::Specs specs)49 static inline AUD_Specs convSpecToC(aud::Specs specs)
50 {
51 AUD_Specs s;
52 s.channels = static_cast<AUD_Channels>(specs.channels);
53 s.rate = static_cast<AUD_SampleRate>(specs.rate);
54 return s;
55 }
56
convCToSpec(AUD_Specs specs)57 static inline aud::Specs convCToSpec(AUD_Specs specs)
58 {
59 aud::Specs s;
60 s.channels = static_cast<Channels>(specs.channels);
61 s.rate = static_cast<SampleRate>(specs.rate);
62 return s;
63 }
64
convDSpecToC(aud::DeviceSpecs specs)65 static inline AUD_DeviceSpecs convDSpecToC(aud::DeviceSpecs specs)
66 {
67 AUD_DeviceSpecs s;
68 s.specs = convSpecToC(specs.specs);
69 s.format = static_cast<AUD_SampleFormat>(specs.format);
70 return s;
71 }
72
convCToDSpec(AUD_DeviceSpecs specs)73 static inline aud::DeviceSpecs convCToDSpec(AUD_DeviceSpecs specs)
74 {
75 aud::DeviceSpecs s;
76 s.specs = convCToSpec(specs.specs);
77 s.format = static_cast<SampleFormat>(specs.format);
78 return s;
79 }
80
AUD_getInfo(AUD_Sound * sound)81 AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
82 {
83 assert(sound);
84
85 AUD_SoundInfo info;
86 info.specs.channels = AUD_CHANNELS_INVALID;
87 info.specs.rate = AUD_RATE_INVALID;
88 info.length = 0.0f;
89
90 try
91 {
92 std::shared_ptr<IReader> reader = (*sound)->createReader();
93
94 if(reader.get())
95 {
96 info.specs = convSpecToC(reader->getSpecs());
97 info.length = reader->getLength() / (float) info.specs.rate;
98 }
99 }
100 catch(Exception&)
101 {
102 }
103
104 return info;
105 }
106
AUD_readSoundBuffer(const char * filename,float low,float high,float attack,float release,float threshold,int accumulate,int additive,int square,float sthreshold,double samplerate,int * length)107 AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
108 float attack, float release, float threshold,
109 int accumulate, int additive, int square,
110 float sthreshold, double samplerate, int* length)
111 {
112 Buffer buffer;
113 DeviceSpecs specs;
114 specs.channels = CHANNELS_MONO;
115 specs.rate = (SampleRate)samplerate;
116 std::shared_ptr<ISound> sound;
117
118 std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename));
119
120 int position = 0;
121
122 try
123 {
124 std::shared_ptr<IReader> reader = file->createReader();
125
126 SampleRate rate = reader->getSpecs().rate;
127
128 sound = std::shared_ptr<ISound>(new ChannelMapper(file, specs));
129
130 if(high < rate)
131 sound = std::shared_ptr<ISound>(new Lowpass(sound, high));
132 if(low > 0)
133 sound = std::shared_ptr<ISound>(new Highpass(sound, low));
134
135 sound = std::shared_ptr<ISound>(new Envelope(sound, attack, release, threshold, 0.1f));
136 sound = std::shared_ptr<ISound>(new LinearResample(sound, specs));
137
138 if(square)
139 sound = std::shared_ptr<ISound>(new Threshold(sound, sthreshold));
140
141 if(accumulate)
142 sound = std::shared_ptr<ISound>(new Accumulator(sound, additive));
143 else if(additive)
144 sound = std::shared_ptr<ISound>(new Sum(sound));
145
146 reader = sound->createReader();
147
148 if(!reader.get())
149 return nullptr;
150
151 int len;
152 bool eos;
153 do
154 {
155 len = samplerate;
156 buffer.resize((position + len) * sizeof(float), true);
157 reader->read(len, eos, buffer.getBuffer() + position);
158 position += len;
159 } while(!eos);
160 }
161 catch(Exception&)
162 {
163 return nullptr;
164 }
165
166 float * result = (float *)malloc(position * sizeof(float));
167 std::memcpy(result, buffer.getBuffer(), position * sizeof(float));
168 *length = position;
169 return result;
170 }
171
pauseSound(AUD_Handle * handle)172 static void pauseSound(AUD_Handle* handle)
173 {
174 assert(handle);
175 (*handle)->pause();
176 }
177
AUD_pauseAfter(AUD_Handle * handle,double seconds)178 AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, double seconds)
179 {
180 auto device = DeviceManager::getDevice();
181
182 std::shared_ptr<ISound> silence = std::shared_ptr<ISound>(new Silence(device->getSpecs().rate));
183 std::shared_ptr<ISound> limiter = std::shared_ptr<ISound>(new Limiter(silence, 0, seconds));
184
185 std::lock_guard<ILockable> lock(*device);
186
187 try
188 {
189 AUD_Handle handle2 = device->play(limiter);
190 if(handle2.get())
191 {
192 handle2->setStopCallback((stopCallback)pauseSound, handle);
193 return new AUD_Handle(handle2);
194 }
195 }
196 catch(Exception&)
197 {
198 }
199
200 return nullptr;
201 }
202
AUD_readSound(AUD_Sound * sound,float * buffer,int length,int samples_per_second,short * interrupt)203 AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int samples_per_second, short* interrupt)
204 {
205 DeviceSpecs specs;
206 float* buf;
207 Buffer aBuffer;
208
209 specs.rate = RATE_INVALID;
210 specs.channels = CHANNELS_MONO;
211 specs.format = FORMAT_INVALID;
212
213 std::shared_ptr<IReader> reader = ChannelMapper(*sound, specs).createReader();
214
215 specs.specs = reader->getSpecs();
216 int len;
217 float samplejump = specs.rate / samples_per_second;
218 float min, max, power, overallmax;
219 bool eos;
220
221 overallmax = 0;
222
223 for(int i = 0; i < length; i++)
224 {
225 len = floor(samplejump * (i+1)) - floor(samplejump * i);
226
227 if(*interrupt)
228 return 0;
229
230 aBuffer.assureSize(len * AUD_SAMPLE_SIZE(specs));
231 buf = aBuffer.getBuffer();
232
233 reader->read(len, eos, buf);
234
235 max = min = *buf;
236 power = *buf * *buf;
237 for(int j = 1; j < len; j++)
238 {
239 if(buf[j] < min)
240 min = buf[j];
241 if(buf[j] > max)
242 max = buf[j];
243 power += buf[j] * buf[j];
244 }
245
246 buffer[i * 3] = min;
247 buffer[i * 3 + 1] = max;
248 buffer[i * 3 + 2] = sqrt(power) / len;
249
250 if(overallmax < max)
251 overallmax = max;
252 if(overallmax < -min)
253 overallmax = -min;
254
255 if(eos)
256 {
257 length = i;
258 break;
259 }
260 }
261
262 if(overallmax > 1.0f)
263 {
264 for(int i = 0; i < length * 3; i++)
265 {
266 buffer[i] /= overallmax;
267 }
268 }
269
270 return length;
271 }
272
AUD_mixdown(AUD_Sound * sound,unsigned int start,unsigned int length,unsigned int buffersize,const char * filename,AUD_DeviceSpecs specs,AUD_Container format,AUD_Codec codec,unsigned int bitrate,void (* callback)(float,void *),void * data)273 AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
274 {
275 try
276 {
277 Sequence* f = dynamic_cast<Sequence *>(sound->get());
278
279 f->setSpecs(convCToSpec(specs.specs));
280 std::shared_ptr<IReader> reader = f->createQualityReader();
281 reader->seek(start);
282 std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, convCToDSpec(specs), static_cast<Container>(format), static_cast<Codec>(codec), bitrate);
283 FileWriter::writeReader(reader, writer, length, buffersize, callback, data);
284
285 return nullptr;
286 }
287 catch(Exception& e)
288 {
289 return e.getMessage().c_str();
290 }
291 }
292
AUD_mixdown_per_channel(AUD_Sound * sound,unsigned int start,unsigned int length,unsigned int buffersize,const char * filename,AUD_DeviceSpecs specs,AUD_Container format,AUD_Codec codec,unsigned int bitrate,void (* callback)(float,void *),void * data)293 AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
294 {
295 try
296 {
297 Sequence* f = dynamic_cast<Sequence *>(sound->get());
298
299 f->setSpecs(convCToSpec(specs.specs));
300
301 std::vector<std::shared_ptr<IWriter> > writers;
302
303 int channels = specs.channels;
304 specs.channels = AUD_CHANNELS_MONO;
305
306 for(int i = 0; i < channels; i++)
307 {
308 std::stringstream stream;
309 std::string fn = filename;
310 size_t index = fn.find_last_of('.');
311 size_t index_slash = fn.find_last_of('/');
312 size_t index_backslash = fn.find_last_of('\\');
313
314 if((index == std::string::npos) ||
315 ((index < index_slash) && (index_slash != std::string::npos)) ||
316 ((index < index_backslash) && (index_backslash != std::string::npos)))
317 {
318 stream << filename << "_" << (i + 1);
319 }
320 else
321 {
322 stream << fn.substr(0, index) << "_" << (i + 1) << fn.substr(index);
323 }
324 writers.push_back(FileWriter::createWriter(stream.str(), convCToDSpec(specs), static_cast<Container>(format), static_cast<Codec>(codec), bitrate));
325 }
326
327 std::shared_ptr<IReader> reader = f->createQualityReader();
328 reader->seek(start);
329 FileWriter::writeReader(reader, writers, length, buffersize, callback, data);
330
331 return nullptr;
332 }
333 catch(Exception& e)
334 {
335 return e.getMessage().c_str();
336 }
337 }
338
AUD_openMixdownDevice(AUD_DeviceSpecs specs,AUD_Sound * sequencer,float volume,double start)339 AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, double start)
340 {
341 try
342 {
343 ReadDevice* device = new ReadDevice(convCToDSpec(specs));
344 device->setQuality(true);
345 device->setVolume(volume);
346
347 Sequence* f = dynamic_cast<Sequence*>(sequencer->get());
348
349 f->setSpecs(convCToSpec(specs.specs));
350
351 AUD_Handle handle = device->play(f->createQualityReader());
352 if(handle.get())
353 {
354 handle->seek(start);
355 }
356
357 return new AUD_Device(device);
358 }
359 catch(Exception&)
360 {
361 return nullptr;
362 }
363 }
364
AUD_initOnce()365 AUD_API void AUD_initOnce()
366 {
367 PluginManager::loadPlugins();
368 NULLDevice::registerPlugin();
369 }
370
AUD_exitOnce()371 AUD_API void AUD_exitOnce()
372 {
373 }
374
AUD_init(const char * device,AUD_DeviceSpecs specs,int buffersize,const char * name)375 AUD_API AUD_Device* AUD_init(const char* device, AUD_DeviceSpecs specs, int buffersize, const char* name)
376 {
377 try
378 {
379 std::shared_ptr<IDeviceFactory> factory = DeviceManager::getDeviceFactory(device);
380
381 if(factory)
382 {
383 factory->setName(name);
384 factory->setBufferSize(buffersize);
385 factory->setSpecs(convCToDSpec(specs));
386 auto device = factory->openDevice();
387 DeviceManager::setDevice(device);
388
389 return new AUD_Device(device);
390 }
391 }
392 catch(Exception&)
393 {
394 }
395 return nullptr;
396 }
397
AUD_exit(AUD_Device * device)398 AUD_API void AUD_exit(AUD_Device* device)
399 {
400 delete device;
401 DeviceManager::releaseDevice();
402 }
403
404
AUD_getDeviceNames()405 AUD_API char** AUD_getDeviceNames()
406 {
407 std::vector<std::string> v_names = DeviceManager::getAvailableDeviceNames();
408 char** names = (char**) malloc(sizeof(char*) * (v_names.size() + 1));
409
410 for(int i = 0; i < v_names.size(); i++)
411 {
412 std::string name = v_names[i];
413 names[i] = (char*) malloc(sizeof(char) * (name.length() + 1));
414 strcpy(names[i], name.c_str());
415 }
416
417 names[v_names.size()] = nullptr;
418
419 return names;
420 }
421