Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "Exception.h"
#include <sstream>
AUD_NAMESPACE_BEGIN
Exception::Exception(const Exception& exception) :
Exception(exception.m_message, exception.m_file, exception.m_line)
{
}
Exception::Exception(const std::string &message, const std::string &file, int line) :
m_message(message),
m_file(file),
m_line(line)
{
}
Exception::~Exception() AUD_NOEXCEPT
{
}
const char* Exception::what() const AUD_NOEXCEPT
{
return m_message.c_str();
}
std::string Exception::getDebugMessage() const
{
std::stringstream out;
out << m_message << " File " << m_file << ":" << m_line;
return out.str();
}
const std::string& Exception::getMessage() const
{
return m_message;
}
const std::string& Exception::getFile() const
{
return m_file;
}
int Exception::getLine() const
{
return m_line;
}
FileException::FileException(const std::string &message, const std::string &file, int line) :
Exception(message, file, line)
{
}
FileException::FileException(const FileException& exception) :
Exception(exception)
{
}
FileException::~FileException() AUD_NOEXCEPT
{
}
DeviceException::DeviceException(const std::string &message, const std::string &file, int line) :
Exception(message, file, line)
{
}
DeviceException::DeviceException(const DeviceException& exception) :
Exception(exception)
{
}
DeviceException::~DeviceException() AUD_NOEXCEPT
{
}
StateException::StateException(const std::string &message, const std::string &file, int line) :
Exception(message, file, line)
{
}
StateException::StateException(const StateException& exception) :
Exception(exception)
{
}
StateException::~StateException() AUD_NOEXCEPT
{
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,158 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/DeviceManager.h"
#include "devices/ICaptureDeviceFactory.h"
#include "devices/IDeviceFactory.h"
#include "devices/IDevice.h"
#include "devices/I3DDevice.h"
#include "Exception.h"
#include <limits>
#include <string>
#include <algorithm>
AUD_NAMESPACE_BEGIN
std::unordered_map<std::string, std::shared_ptr<IDeviceFactory>> DeviceManager::m_factories;
std::shared_ptr<IDevice> DeviceManager::m_device;
std::unordered_map<std::string, std::shared_ptr<ICaptureDeviceFactory>> DeviceManager::m_capture_factories;
void DeviceManager::registerDevice(const std::string &name, std::shared_ptr<IDeviceFactory> factory)
{
m_factories[name] = factory;
}
std::shared_ptr<IDeviceFactory> DeviceManager::getDeviceFactory(const std::string &name)
{
auto it = m_factories.find(name);
if(it == m_factories.end())
return nullptr;
return it->second;
}
std::shared_ptr<IDeviceFactory> DeviceManager::getDefaultDeviceFactory()
{
int min = std::numeric_limits<int>::min();
std::shared_ptr<IDeviceFactory> result;
for(auto factory : m_factories)
{
if(factory.second->getPriority() >= min)
{
result = factory.second;
min = result->getPriority();
}
}
return result;
}
void DeviceManager::setDevice(std::shared_ptr<IDevice> device)
{
m_device = device;
}
void DeviceManager::openDevice(const std::string &name)
{
setDevice(getDeviceFactory(name)->openDevice());
}
void DeviceManager::openDefaultDevice()
{
setDevice(getDefaultDeviceFactory()->openDevice());
}
void DeviceManager::releaseDevice()
{
m_device = nullptr;
}
std::shared_ptr<IDevice> DeviceManager::getDevice()
{
return m_device;
}
std::shared_ptr<I3DDevice> DeviceManager::get3DDevice()
{
return std::dynamic_pointer_cast<I3DDevice>(m_device);
}
std::vector<std::string> DeviceManager::getAvailableDeviceNames()
{
struct DeviceNamePriority {
std::string name;
int priority;
};
std::vector<DeviceNamePriority> devices;
devices.reserve(m_factories.size());
for(const auto& pair : m_factories)
devices.push_back({pair.first, pair.second->getPriority()});
auto sort = [](const DeviceNamePriority& lhs, const DeviceNamePriority& rhs){
return lhs.priority > rhs.priority;
};
std::sort(devices.begin(), devices.end(), sort);
std::vector<std::string> names;
names.reserve(devices.size());
for(const auto& device : devices)
names.push_back(device.name);
return names;
}
std::vector<std::string> DeviceManager::getAvailableCaptureDeviceNames()
{
std::vector<std::string> names;
names.reserve(m_capture_factories.size());
for(auto& entry : m_capture_factories)
names.push_back(entry.first);
return names;
}
std::shared_ptr<ICaptureDeviceFactory> DeviceManager::getCaptureDeviceFactory(const std::string& name)
{
auto it = m_capture_factories.find(name);
if(it == m_capture_factories.end())
return nullptr;
return it->second;
}
void DeviceManager::registerCaptureDevice(const std::string& name, std::shared_ptr<ICaptureDeviceFactory> factory)
{
m_capture_factories[name] = factory;
}
std::shared_ptr<IReader> DeviceManager::openCaptureDevice(const std::string& name,
Specs specs,
int buffersize)
{
return getCaptureDeviceFactory(name)->openDevice(specs, buffersize);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,102 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/MixingThreadDevice.h"
AUD_NAMESPACE_BEGIN
void MixingThreadDevice::updateRingBuffer()
{
unsigned int samplesize = AUD_DEVICE_SAMPLE_SIZE(m_specs);
std::unique_lock<std::mutex> lock(m_mixingLock);
while(m_valid)
{
{
std::lock_guard<ILockable> device_lock(*this);
preMixingWork(m_playback);
if(m_playback)
{
size_t size = m_ringBuffer.getWriteSize();
size_t sample_count = size / samplesize;
while(sample_count > 0)
{
size = sample_count * samplesize;
mix(reinterpret_cast<data_t*>(m_mixingBuffer.getBuffer()), sample_count);
m_ringBuffer.write(reinterpret_cast<data_t*>(m_mixingBuffer.getBuffer()), size);
sample_count = m_ringBuffer.getWriteSize() / samplesize;
}
}
}
m_mixingCondition.wait(lock);
}
}
void MixingThreadDevice::startMixingThread(size_t buffersize)
{
m_mixingBuffer.resize(buffersize);
m_ringBuffer.resize(buffersize);
m_valid = true;
m_mixingThread = std::thread(&MixingThreadDevice::updateRingBuffer, this);
}
void MixingThreadDevice::notifyMixingThread()
{
m_mixingCondition.notify_all();
}
void MixingThreadDevice::playing(bool playing)
{
std::lock_guard<ILockable> lock(*this);
m_playback = playing;
if(playing)
notifyMixingThread();
}
void MixingThreadDevice::preMixingWork(bool playing)
{
}
MixingThreadDevice::MixingThreadDevice()
{
}
void aud::MixingThreadDevice::stopMixingThread()
{
{
std::unique_lock<std::mutex> lock(m_mixingLock);
m_valid = false;
}
m_mixingCondition.notify_all();
m_mixingThread.join();
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/NULLDevice.h"
#include "devices/DeviceManager.h"
#include "devices/IDeviceFactory.h"
#include <limits>
#include <string>
AUD_NAMESPACE_BEGIN
NULLDevice::NULLHandle::NULLHandle()
{
}
bool NULLDevice::NULLHandle::pause()
{
return false;
}
bool NULLDevice::NULLHandle::resume()
{
return false;
}
bool NULLDevice::NULLHandle::stop()
{
return false;
}
bool NULLDevice::NULLHandle::getKeep()
{
return false;
}
bool NULLDevice::NULLHandle::setKeep(bool keep)
{
return false;
}
bool NULLDevice::NULLHandle::seek(double position)
{
return false;
}
double NULLDevice::NULLHandle::getPosition()
{
return std::numeric_limits<float>::quiet_NaN();
}
Status NULLDevice::NULLHandle::getStatus()
{
return STATUS_INVALID;
}
float NULLDevice::NULLHandle::getVolume()
{
return std::numeric_limits<float>::quiet_NaN();
}
bool NULLDevice::NULLHandle::setVolume(float volume)
{
return false;
}
float NULLDevice::NULLHandle::getPitch()
{
return std::numeric_limits<float>::quiet_NaN();
}
bool NULLDevice::NULLHandle::setPitch(float pitch)
{
return false;
}
int NULLDevice::NULLHandle::getLoopCount()
{
return 0;
}
bool NULLDevice::NULLHandle::setLoopCount(int count)
{
return false;
}
bool NULLDevice::NULLHandle::setStopCallback(stopCallback callback, void* data)
{
return false;
}
NULLDevice::NULLDevice()
{
}
NULLDevice::~NULLDevice()
{
}
DeviceSpecs NULLDevice::getSpecs() const
{
DeviceSpecs specs;
specs.channels = CHANNELS_INVALID;
specs.format = FORMAT_INVALID;
specs.rate = RATE_INVALID;
return specs;
}
std::shared_ptr<IHandle> NULLDevice::play(std::shared_ptr<IReader> reader, bool keep)
{
return std::shared_ptr<IHandle>(new NULLHandle());
}
std::shared_ptr<IHandle> NULLDevice::play(std::shared_ptr<ISound> sound, bool keep)
{
return std::shared_ptr<IHandle>(new NULLHandle());
}
void NULLDevice::stopAll()
{
}
void NULLDevice::lock()
{
}
void NULLDevice::unlock()
{
}
float NULLDevice::getVolume() const
{
return std::numeric_limits<float>::quiet_NaN();
}
void NULLDevice::setVolume(float volume)
{
}
void NULLDevice::seekSynchronizer(double time)
{
}
double NULLDevice::getSynchronizerPosition()
{
return std::numeric_limits<double>::quiet_NaN();
}
void NULLDevice::playSynchronizer()
{
}
void NULLDevice::stopSynchronizer()
{
}
void NULLDevice::setSyncCallback(syncFunction function, void* data)
{
}
int NULLDevice::isSynchronizerPlaying()
{
return 0;
}
class NULLDeviceFactory : public IDeviceFactory
{
public:
NULLDeviceFactory()
{
}
virtual std::shared_ptr<IDevice> openDevice()
{
return std::shared_ptr<IDevice>(new NULLDevice());
}
virtual int getPriority()
{
return std::numeric_limits<int>::min();
}
virtual void setSpecs(DeviceSpecs specs)
{
}
virtual void setBufferSize(int buffersize)
{
}
virtual void setName(const std::string &name)
{
}
};
void NULLDevice::registerPlugin()
{
DeviceManager::registerDevice("None", std::shared_ptr<IDeviceFactory>(new NULLDeviceFactory));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/ReadDevice.h"
#include "IReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
ReadDevice::ReadDevice(DeviceSpecs specs) :
m_playing(false)
{
m_specs = specs;
create();
}
ReadDevice::ReadDevice(Specs specs) :
m_playing(false)
{
m_specs.specs = specs;
m_specs.format = FORMAT_FLOAT32;
create();
}
ReadDevice::~ReadDevice()
{
destroy();
}
bool ReadDevice::read(data_t* buffer, int length)
{
if(m_playing)
mix(buffer, length);
else
if(m_specs.format == FORMAT_U8)
std::memset(buffer, 0x80, length * AUD_DEVICE_SAMPLE_SIZE(m_specs));
else
std::memset(buffer, 0, length * AUD_DEVICE_SAMPLE_SIZE(m_specs));
return m_playing;
}
void ReadDevice::changeSpecs(Specs specs)
{
if(!AUD_COMPARE_SPECS(specs, m_specs.specs))
setSpecs(specs);
}
void ReadDevice::playing(bool playing)
{
m_playing = playing;
}
AUD_NAMESPACE_END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/ThreadedDevice.h"
#include <mutex>
AUD_NAMESPACE_BEGIN
void ThreadedDevice::start()
{
std::lock_guard<ILockable> lock(*this);
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&ThreadedDevice::runMixingThread, this);
}
}
void ThreadedDevice::playing(bool playing)
{
if((!m_playing || m_stop) && playing)
start();
else
m_stop = true;
}
ThreadedDevice::ThreadedDevice() :
m_playing(false),
m_stop(false)
{
}
void aud::ThreadedDevice::stopMixingThread()
{
stopAll();
if(m_thread.joinable())
m_thread.join();
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "file/File.h"
#include "file/FileManager.h"
#include "util/Buffer.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
File::File(const std::string &filename, int stream) :
m_filename(filename), m_stream(stream)
{
}
File::File(const data_t* buffer, int size, int stream) :
m_buffer(new Buffer(size)), m_stream(stream)
{
std::memcpy(m_buffer->getBuffer(), buffer, size);
}
std::vector<StreamInfo> File::queryStreams()
{
if(m_buffer.get())
return FileManager::queryStreams(m_buffer);
else
return FileManager::queryStreams(m_filename);
}
std::shared_ptr<IReader> File::createReader()
{
if(m_buffer.get())
return FileManager::createReader(m_buffer, m_stream);
else
return FileManager::createReader(m_filename, m_stream);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,116 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "file/FileManager.h"
#include "file/IFileInput.h"
#include "file/IFileOutput.h"
#include "Exception.h"
AUD_NAMESPACE_BEGIN
std::list<std::shared_ptr<IFileInput>>& FileManager::inputs()
{
static std::list<std::shared_ptr<IFileInput>> inputs;
return inputs;
}
std::list<std::shared_ptr<IFileOutput>>& FileManager::outputs()
{
static std::list<std::shared_ptr<IFileOutput>> outputs;
return outputs;
}
void FileManager::registerInput(std::shared_ptr<IFileInput> input)
{
inputs().push_back(input);
}
void FileManager::registerOutput(std::shared_ptr<aud::IFileOutput> output)
{
outputs().push_back(output);
}
std::shared_ptr<IReader> FileManager::createReader(const std::string &filename, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->createReader(filename, stream);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->createReader(buffer, stream);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::vector<StreamInfo> FileManager::queryStreams(const std::string &filename)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->queryStreams(filename);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::vector<StreamInfo> FileManager::queryStreams(std::shared_ptr<Buffer> buffer)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->queryStreams(buffer);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::shared_ptr<IWriter> FileManager::createWriter(const std::string &filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
{
for(std::shared_ptr<IFileOutput> output : outputs())
{
try
{
return output->createWriter(filename, specs, format, codec, bitrate);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be written with any installed writer.");
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "file/FileWriter.h"
#include "file/FileManager.h"
#include "util/Buffer.h"
#include "IReader.h"
#include "Exception.h"
AUD_NAMESPACE_BEGIN
std::shared_ptr<IWriter> FileWriter::createWriter(const std::string &filename,DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
{
return FileManager::createWriter(filename, specs, format, codec, bitrate);
}
void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::shared_ptr<IWriter> writer, unsigned int length, unsigned int buffersize, bool(*callback)(float, void*), void* data)
{
Buffer buffer(buffersize * AUD_SAMPLE_SIZE(writer->getSpecs()));
sample_t* buf = buffer.getBuffer();
int len;
bool eos = false;
int channels = writer->getSpecs().channels;
for(unsigned int pos = 0; ((pos < length) || (length <= 0)) && !eos; pos += len)
{
len = buffersize;
if((len > length - pos) && (length > 0))
len = length - pos;
reader->read(len, eos, buf);
for(int i = 0; i < len * channels; i++)
{
// clamping!
if(buf[i] > 1)
buf[i] = 1;
else if(buf[i] < -1)
buf[i] = -1;
}
writer->write(len, buf);
if(callback)
{
float progress = -1;
if(length > 0)
progress = pos / float(length);
if (!callback(progress, data))
{
break;
}
}
}
}
void FileWriter::writeReader(std::shared_ptr<IReader> reader, std::vector<std::shared_ptr<IWriter> >& writers, unsigned int length, unsigned int buffersize, bool(*callback)(float, void*), void* data)
{
Buffer buffer(buffersize * AUD_SAMPLE_SIZE(reader->getSpecs()));
Buffer buffer2(buffersize * sizeof(sample_t));
sample_t* buf = buffer.getBuffer();
sample_t* buf2 = buffer2.getBuffer();
int len;
bool eos = false;
int channels = reader->getSpecs().channels;
for(unsigned int pos = 0; ((pos < length) || (length <= 0)) && !eos; pos += len)
{
len = buffersize;
if((len > length - pos) && (length > 0))
len = length - pos;
reader->read(len, eos, buf);
for(int channel = 0; channel < channels; channel++)
{
for(int i = 0; i < len; i++)
{
// clamping!
if(buf[i * channels + channel] > 1)
buf2[i] = 1;
else if(buf[i * channels + channel] < -1)
buf2[i] = -1;
else
buf2[i] = buf[i * channels + channel];
}
writers[channel]->write(len, buf2);
}
if(callback)
{
float progress = -1;
if(length > 0)
progress = pos / float(length);
if (!callback(progress, data))
{
break;
}
}
}
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ADSR.h"
#include "fx/ADSRReader.h"
AUD_NAMESPACE_BEGIN
ADSR::ADSR(std::shared_ptr<ISound> sound, float attack, float decay, float sustain, float release) :
Effect(sound),
m_attack(attack), m_decay(decay), m_sustain(sustain), m_release(release)
{
}
float ADSR::getAttack() const
{
return m_attack;
}
void ADSR::setAttack(float attack)
{
m_attack = attack;
}
float ADSR::getDecay() const
{
return m_decay;
}
void ADSR::setDecay(float decay)
{
m_decay = decay;
}
float ADSR::getSustain() const
{
return m_sustain;
}
void ADSR::setSustain(float sustain)
{
m_sustain = sustain;
}
float ADSR::getRelease() const
{
return m_release;
}
void ADSR::setRelease(float release)
{
m_release = release;
}
std::shared_ptr<IReader> ADSR::createReader()
{
return std::shared_ptr<IReader>(new ADSRReader(getReader(), m_attack, m_decay, m_sustain, m_release));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,115 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ADSRReader.h"
AUD_NAMESPACE_BEGIN
ADSRReader::ADSRReader(std::shared_ptr<IReader> reader, float attack, float decay, float sustain, float release) :
EffectReader(reader),
m_attack(attack), m_decay(decay), m_sustain(sustain), m_release(release)
{
nextState(ADSR_STATE_ATTACK);
}
ADSRReader::~ADSRReader()
{
}
void ADSRReader::nextState(ADSRState state)
{
m_state = state;
switch(m_state)
{
case ADSR_STATE_ATTACK:
m_level = 0;
if(m_attack <= 0)
{
nextState(ADSR_STATE_DECAY);
return;
}
return;
case ADSR_STATE_DECAY:
if(m_decay <= 0)
{
nextState(ADSR_STATE_SUSTAIN);
return;
}
if(m_level > 1.0)
m_level = 1 - (m_level - 1) * m_attack / m_decay * (1 - m_sustain);
if(m_level <= m_sustain)
nextState(ADSR_STATE_SUSTAIN);
break;
case ADSR_STATE_SUSTAIN:
m_level = m_sustain;
break;
case ADSR_STATE_RELEASE:
if(m_release <= 0)
{
nextState(ADSR_STATE_INVALID);
return;
}
break;
case ADSR_STATE_INVALID:
break;
}
}
void ADSRReader::read(int & length, bool &eos, sample_t* buffer)
{
Specs specs = m_reader->getSpecs();
m_reader->read(length, eos, buffer);
for(int i = 0; i < length; i++)
{
for(int channel = 0; channel < specs.channels; channel++)
{
buffer[i * specs.channels + channel] *= m_level;
}
switch(m_state)
{
case ADSR_STATE_ATTACK:
m_level += 1 / m_attack / specs.rate;
if(m_level >= 1)
nextState(ADSR_STATE_DECAY);
break;
case ADSR_STATE_DECAY:
m_level -= (1 - m_sustain) / m_decay / specs.rate;
if(m_level <= m_sustain)
nextState(ADSR_STATE_SUSTAIN);
break;
case ADSR_STATE_SUSTAIN:
break;
case ADSR_STATE_RELEASE:
m_level -= m_sustain / m_release / specs.rate ;
if(m_level <= 0)
nextState(ADSR_STATE_INVALID);
break;
case ADSR_STATE_INVALID:
length = i;
return;
}
}
}
void ADSRReader::release()
{
nextState(ADSR_STATE_RELEASE);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Accumulator.h"
#include "fx/CallbackIIRFilterReader.h"
AUD_NAMESPACE_BEGIN
sample_t Accumulator::accumulatorFilterAdditive(CallbackIIRFilterReader* reader, void* useless)
{
float in = reader->x(0);
float lastin = reader->x(-1);
float out = reader->y(-1) + in - lastin;
if(in > lastin)
out += in - lastin;
return out;
}
sample_t Accumulator::accumulatorFilter(CallbackIIRFilterReader* reader, void* useless)
{
float in = reader->x(0);
float lastin = reader->x(-1);
float out = reader->y(-1);
if(in > lastin)
out += in - lastin;
return out;
}
Accumulator::Accumulator(std::shared_ptr<ISound> sound,
bool additive) :
Effect(sound),
m_additive(additive)
{
}
std::shared_ptr<IReader> Accumulator::createReader()
{
return std::shared_ptr<IReader>(new CallbackIIRFilterReader(getReader(), 2, 2, m_additive ? accumulatorFilterAdditive : accumulatorFilter));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/AnimateableTimeStretchPitchScale.h"
#include "fx/AnimateableTimeStretchPitchScaleReader.h"
AUD_NAMESPACE_BEGIN
AnimateableTimeStretchPitchScale::AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, float timeStretch, float pitchScale, StretcherQuality quality,
bool preserveFormant) :
Effect(sound),
m_fps(fps),
m_timeStretch(std::make_shared<AnimateableProperty>(1, timeStretch)),
m_pitchScale(std::make_shared<AnimateableProperty>(1, pitchScale)),
m_quality(quality),
m_preserveFormant(preserveFormant)
{
}
AnimateableTimeStretchPitchScale::AnimateableTimeStretchPitchScale(std::shared_ptr<ISound> sound, float fps, std::shared_ptr<AnimateableProperty> timeStretch,
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant) :
Effect(sound), m_fps(fps), m_timeStretch(timeStretch), m_pitchScale(pitchScale), m_quality(quality), m_preserveFormant(preserveFormant)
{
}
std::shared_ptr<IReader> AnimateableTimeStretchPitchScale::createReader()
{
return std::make_shared<AnimateableTimeStretchPitchScaleReader>(getReader(), m_fps, m_timeStretch, m_pitchScale, m_quality, m_preserveFormant);
}
bool AnimateableTimeStretchPitchScale::getPreserveFormant() const
{
return m_preserveFormant;
}
StretcherQuality AnimateableTimeStretchPitchScale::getStretcherQuality() const
{
return m_quality;
}
std::shared_ptr<AnimateableProperty> AnimateableTimeStretchPitchScale::getAnimProperty(AnimateablePropertyType type)
{
switch(type)
{
case AP_TIME_STRETCH:
return m_timeStretch;
case AP_PITCH_SCALE:
return m_pitchScale;
default:
return nullptr;
}
}
float AnimateableTimeStretchPitchScale::getFPS() const
{
return m_fps;
}
void AnimateableTimeStretchPitchScale::setFPS(float fps)
{
m_fps = fps;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/AnimateableTimeStretchPitchScaleReader.h"
#include "IReader.h"
AUD_NAMESPACE_BEGIN
AnimateableTimeStretchPitchScaleReader::AnimateableTimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, float fps, std::shared_ptr<AnimateableProperty> timeStretch,
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant) :
TimeStretchPitchScaleReader(reader, timeStretch->readSingle(0), pitchScale->readSingle(0), quality, preserveFormant),
m_fps(fps),
m_timeStretch(timeStretch),
m_pitchScale(pitchScale)
{
}
void AnimateableTimeStretchPitchScaleReader::read(int& length, bool& eos, sample_t* buffer)
{
int position = getPosition();
double time = double(position) / double(m_reader->getSpecs().rate);
float frame = time * m_fps;
float timeRatio = m_timeStretch->readSingle(frame);
setTimeRatio(timeRatio);
float pitchScale = m_pitchScale->readSingle(frame);
setPitchScale(pitchScale);
TimeStretchPitchScaleReader::read(length, eos, buffer);
}
void AnimateableTimeStretchPitchScaleReader::seek(int position)
{
const double sampleRate = double(m_reader->getSpecs().rate);
const double samplesPerFrame = sampleRate / m_fps;
const double frame = double(position) / samplesPerFrame;
float timeRatio = m_timeStretch->readSingle(frame);
setTimeRatio(timeRatio);
float pitchScale = m_pitchScale->readSingle(frame);
setPitchScale(pitchScale);
const int totalFrames = static_cast<int>(frame);
float ratio = 1.0f;
double inputSamplePos = 0.0;
const sample_t* animationSamples = m_timeStretch->getBuffer().getBuffer();
const int bufferFrames = m_timeStretch->getBuffer().getSize() / (sizeof(sample_t) * m_timeStretch->getCount());
for(int frameIndex = 0; frameIndex < std::min(bufferFrames, totalFrames); frameIndex++)
{
ratio = std::max(animationSamples[frameIndex], 1.0f / 256.0f);
inputSamplePos += samplesPerFrame / ratio;
}
if(totalFrames > bufferFrames)
{
// The position is past the end of animation buffer and so use the last read ratio
// This already includes the fractional frame
inputSamplePos += (samplesPerFrame * (frame - bufferFrames)) / ratio;
}
else
{
// The position is before the end of the animation buffer and so read one last time for the remaining fractional frame
double remainderFrame = frame - totalFrames;
float remainderRatio = std::max(m_timeStretch->readSingle(frame), 1.0f / 256.0f);
inputSamplePos += (samplesPerFrame * remainderFrame) / remainderRatio;
}
m_reader->seek(static_cast<int>(inputSamplePos));
m_finishedReader = false;
m_stretcher->reset();
reset();
m_position = position;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,125 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/BaseIIRFilterReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
BaseIIRFilterReader::BaseIIRFilterReader(std::shared_ptr<IReader> reader, int in, int out) :
EffectReader(reader),
m_specs(reader->getSpecs()),
m_xlen(in), m_ylen(out),
m_xpos(0), m_ypos(0), m_channel(0)
{
m_x = new sample_t[m_xlen * m_specs.channels];
m_y = new sample_t[m_ylen * m_specs.channels];
std::memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
std::memset(m_y, 0, sizeof(sample_t) * m_ylen * m_specs.channels);
}
BaseIIRFilterReader::~BaseIIRFilterReader()
{
delete[] m_x;
delete[] m_y;
}
void BaseIIRFilterReader::setLengths(int in, int out)
{
if(in != m_xlen)
{
sample_t* xn = new sample_t[in * m_specs.channels];
std::memset(xn, 0, sizeof(sample_t) * in * m_specs.channels);
for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{
for(int i = 1; i <= in && i <= m_xlen; i++)
{
xn[(in - i) * m_specs.channels + m_channel] = x(-i);
}
}
delete[] m_x;
m_x = xn;
m_xpos = 0;
m_xlen = in;
}
if(out != m_ylen)
{
sample_t* yn = new sample_t[out * m_specs.channels];
std::memset(yn, 0, sizeof(sample_t) * out * m_specs.channels);
for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{
for(int i = 1; i <= out && i <= m_ylen; i++)
{
yn[(out - i) * m_specs.channels + m_channel] = y(-i);
}
}
delete[] m_y;
m_y = yn;
m_ypos = 0;
m_ylen = out;
}
}
void BaseIIRFilterReader::read(int& length, bool& eos, sample_t* buffer)
{
Specs specs = m_reader->getSpecs();
if(specs.channels != m_specs.channels)
{
m_specs.channels = specs.channels;
delete[] m_x;
delete[] m_y;
m_x = new sample_t[m_xlen * m_specs.channels];
m_y = new sample_t[m_ylen * m_specs.channels];
std::memset(m_x, 0, sizeof(sample_t) * m_xlen * m_specs.channels);
std::memset(m_y, 0, sizeof(sample_t) * m_ylen * m_specs.channels);
}
if(specs.rate != m_specs.rate)
{
m_specs = specs;
sampleRateChanged(m_specs.rate);
}
m_reader->read(length, eos, buffer);
for(m_channel = 0; m_channel < m_specs.channels; m_channel++)
{
for(int i = 0; i < length; i++)
{
m_x[m_xpos * m_specs.channels + m_channel] = buffer[i * m_specs.channels + m_channel];
m_y[m_ypos * m_specs.channels + m_channel] = buffer[i * m_specs.channels + m_channel] = filter();
m_xpos = m_xlen ? (m_xpos + 1) % m_xlen : 0;
m_ypos = m_ylen ? (m_ypos + 1) % m_ylen : 0;
}
}
}
void BaseIIRFilterReader::sampleRateChanged(SampleRate rate)
{
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,255 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/BinauralReader.h"
#include "Exception.h"
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define NUM_OUTCHANNELS 2
#define NUM_CONVOLVERS 4
#define CROSSFADE_SAMPLES 1024
AUD_NAMESPACE_BEGIN
BinauralReader::BinauralReader(std::shared_ptr<IReader> reader, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
m_position(0), m_reader(reader), m_hrtfs(hrtfs), m_source(source), m_N(plan->getSize()), m_transition(false), m_transPos(CROSSFADE_SAMPLES*NUM_OUTCHANNELS), m_eosReader(false), m_eosTail(false), m_threadPool(threadPool)
{
if(m_hrtfs->isEmpty())
AUD_THROW(StateException, "The provided HRTF object is empty");
if(m_reader->getSpecs().channels != 1)
AUD_THROW(StateException, "The sound must have only one channel");
if(m_reader->getSpecs().rate != m_hrtfs->getSpecs().rate)
AUD_THROW(StateException, "The sound and the HRTFs must have the same rate");
m_M = m_L = m_N / 2;
m_RealAzimuth = m_Azimuth = m_source->getAzimuth();
m_RealElevation = m_Elevation = m_source->getElevation();
auto irs = m_hrtfs->getImpulseResponse(m_RealAzimuth, m_RealElevation);
for(unsigned int i = 0; i < NUM_CONVOLVERS; i++)
if(i%NUM_OUTCHANNELS==0)
m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(irs.first->getChannel(0), irs.first->getLength(), m_threadPool, plan)));
else
m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(irs.second->getChannel(0), irs.second->getLength(), m_threadPool, plan)));
m_futures.resize(NUM_CONVOLVERS);
m_outBuffer = (sample_t*)std::malloc(m_L*NUM_OUTCHANNELS*sizeof(sample_t));
m_eOutBufLen = m_outBufLen = m_outBufferPos = m_L * NUM_OUTCHANNELS;
m_inBuffer = (sample_t*)std::malloc(m_L * sizeof(sample_t));
for(int i = 0; i < NUM_CONVOLVERS; i++)
m_vecOut.push_back((sample_t*)std::calloc(m_L, sizeof(sample_t)));
}
BinauralReader::~BinauralReader()
{
std::free(m_outBuffer);
std::free(m_inBuffer);
for(int i = 0; i < m_vecOut.size(); i++)
std::free(m_vecOut[i]);
}
bool BinauralReader::isSeekable() const
{
return m_reader->isSeekable();
}
void BinauralReader::seek(int position)
{
m_position = position;
m_reader->seek(position);
for(int i = 0; i < NUM_CONVOLVERS; i++)
m_convolvers[i]->reset();
m_eosTail = false;
m_eosReader = false;
m_outBufferPos = m_eOutBufLen = m_outBufLen;
m_transition = false;
m_transPos = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
}
int BinauralReader::getLength() const
{
return m_reader->getLength();
}
int BinauralReader::getPosition() const
{
return m_position;
}
Specs BinauralReader::getSpecs() const
{
Specs specs = m_reader->getSpecs();
specs.channels = CHANNELS_STEREO;
return specs;
}
void BinauralReader::read(int& length, bool& eos, sample_t* buffer)
{
int samples = 0;
int iteration = 0;
if(length <= 0)
{
length = 0;
eos = (m_eosTail && m_outBufferPos >= m_eOutBufLen);
return;
}
eos = false;
int writePos = 0;
do
{
int bufRest = m_eOutBufLen - m_outBufferPos;
int writeLength = std::min((length*NUM_OUTCHANNELS) - writePos, m_eOutBufLen + bufRest);
if(bufRest < writeLength || (m_eOutBufLen == 0 && m_eosTail))
{
if(bufRest > 0)
std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, bufRest*sizeof(sample_t));
if(!m_eosTail)
{
int n = NUM_OUTCHANNELS;
if(m_transition)
n = NUM_CONVOLVERS;
else if(checkSource())
n = NUM_CONVOLVERS;
loadBuffer(n);
int len = std::min(std::abs(writeLength - bufRest), m_eOutBufLen);
std::memcpy(buffer + writePos + bufRest, m_outBuffer, len*sizeof(sample_t));
samples += len;
m_outBufferPos = len;
writeLength = std::min((length*NUM_OUTCHANNELS) - writePos, m_eOutBufLen + bufRest);
}
else
{
m_outBufferPos += bufRest;
length = (writePos+bufRest) / NUM_OUTCHANNELS;
eos = true;
return;
}
}
else
{
std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, writeLength*sizeof(sample_t));
m_outBufferPos += writeLength;
}
writePos += writeLength;
iteration++;
} while(writePos < length*NUM_OUTCHANNELS);
m_position += length;
}
bool BinauralReader::checkSource()
{
if((m_Azimuth != m_source->getAzimuth() || m_Elevation != m_source->getElevation()) && (!m_eosReader && !m_eosTail))
{
float az = m_Azimuth = m_source->getAzimuth();
float el = m_Elevation = m_source->getElevation();
auto irs = m_hrtfs->getImpulseResponse(az, el);
if(az != m_RealAzimuth || el != m_RealElevation)
{
m_RealAzimuth = az;
m_RealElevation = el;
for(int i = 0; i < NUM_OUTCHANNELS; i++)
{
auto temp = std::move(m_convolvers[i]);
m_convolvers[i] = std::move(m_convolvers[i + NUM_OUTCHANNELS]);
m_convolvers[i + NUM_OUTCHANNELS] = std::move(temp);
}
for(int i = 0; i < NUM_OUTCHANNELS; i++)
if(i%NUM_OUTCHANNELS == 0)
m_convolvers[i]->setImpulseResponse(irs.first->getChannel(0));
else
m_convolvers[i]->setImpulseResponse(irs.second->getChannel(0));
m_transPos = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
m_transition = true;
return true;
}
}
return false;
}
void BinauralReader::loadBuffer(int nConvolvers)
{
m_lastLengthIn = m_L;
m_reader->read(m_lastLengthIn, m_eosReader, m_inBuffer);
if(!m_eosReader || m_lastLengthIn > 0)
{
int len = m_lastLengthIn;
for(int i = 0; i < nConvolvers; i++)
m_futures[i] = m_threadPool->enqueue(&BinauralReader::threadFunction, this, i, true);
for(int i = 0; i < nConvolvers; i++)
len = m_futures[i].get();
joinByChannel(0, len, nConvolvers);
m_eOutBufLen = len*NUM_OUTCHANNELS;
}
else if(!m_eosTail)
{
int len = m_lastLengthIn = m_L;
for(int i = 0; i < nConvolvers; i++)
m_futures[i] = m_threadPool->enqueue(&BinauralReader::threadFunction, this, i, false);
for(int i = 0; i < nConvolvers; i++)
len = m_futures[i].get();
joinByChannel(0, len, nConvolvers);
m_eOutBufLen = len*NUM_OUTCHANNELS;
}
}
void BinauralReader::joinByChannel(int start, int len, int nConvolvers)
{
int k = 0;
float vol = 0;
const int l = CROSSFADE_SAMPLES*NUM_OUTCHANNELS;
for(int i = 0; i < len*NUM_OUTCHANNELS; i += NUM_OUTCHANNELS)
{
if(m_transition)
{
vol = (m_transPos - i) / (float)l;
if(vol > 1.0f)
vol = 1.0f;
else if(vol < 0.0f)
vol = 0.0f;
}
for(int j = 0; j < NUM_OUTCHANNELS; j++)
m_outBuffer[i + j + start] = ((m_vecOut[j][k] * (1.0f - vol)) + (m_vecOut[j + NUM_OUTCHANNELS][k] * vol))*m_source->getVolume();
k++;
}
if(m_transition)
{
m_transPos -= len*NUM_OUTCHANNELS;
if(m_transPos <= 0)
{
m_transition = false;
m_transPos = l;
}
}
}
int BinauralReader::threadFunction(int id, bool input)
{
int l = m_lastLengthIn;
if(input)
m_convolvers[id]->getNext(m_inBuffer, m_vecOut[id], l, m_eosTail);
else
m_convolvers[id]->getNext(nullptr, m_vecOut[id], l, m_eosTail);
return l;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/BinauralSound.h"
#include "fx/BinauralReader.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
BinauralSound::BinauralSound(std::shared_ptr<ISound> sound, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool) :
BinauralSound(sound, hrtfs, source, threadPool, std::make_shared<FFTPlan>(0.0))
{
}
BinauralSound::BinauralSound(std::shared_ptr<ISound> sound, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
m_sound(sound), m_hrtfs(hrtfs), m_source(source), m_threadPool(threadPool), m_plan(plan)
{
}
std::shared_ptr<IReader> BinauralSound::createReader()
{
return std::make_shared<BinauralReader>(m_sound->createReader(), m_hrtfs, m_source, m_threadPool, m_plan);
}
std::shared_ptr<HRTF> BinauralSound::getHRTFs()
{
return m_hrtfs;
}
void BinauralSound::setHRTFs(std::shared_ptr<HRTF> hrtfs)
{
m_hrtfs = hrtfs;
}
std::shared_ptr<Source> BinauralSound::getSource()
{
return m_source;
}
void BinauralSound::setSource(std::shared_ptr<Source> source)
{
m_source = source;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Butterworth.h"
#include "fx/ButterworthCalculator.h"
AUD_NAMESPACE_BEGIN
Butterworth::Butterworth(std::shared_ptr<ISound> sound, float frequency) :
DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new ButterworthCalculator(frequency)))
{
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ButterworthCalculator.h"
#include <cmath>
#define BWPB41 0.76536686473
#define BWPB42 1.84775906502
AUD_NAMESPACE_BEGIN
ButterworthCalculator::ButterworthCalculator(float frequency) :
m_frequency(frequency)
{
}
void ButterworthCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
{
float omega = 2 * std::tan(m_frequency * M_PI / rate);
float o2 = omega * omega;
float o4 = o2 * o2;
float x1 = o2 + 2.0f * (float)BWPB41 * omega + 4.0f;
float x2 = o2 + 2.0f * (float)BWPB42 * omega + 4.0f;
float y1 = o2 - 2.0f * (float)BWPB41 * omega + 4.0f;
float y2 = o2 - 2.0f * (float)BWPB42 * omega + 4.0f;
float o228 = 2.0f * o2 - 8.0f;
float norm = x1 * x2;
a.push_back(1);
a.push_back((x1 + x2) * o228 / norm);
a.push_back((x1 * y2 + x2 * y1 + o228 * o228) / norm);
a.push_back((y1 + y2) * o228 / norm);
a.push_back(y1 * y2 / norm);
b.push_back(o4 / norm);
b.push_back(4 * o4 / norm);
b.push_back(6 * o4 / norm);
b.push_back(b[1]);
b.push_back(b[0]);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/CallbackIIRFilterReader.h"
AUD_NAMESPACE_BEGIN
CallbackIIRFilterReader::CallbackIIRFilterReader(std::shared_ptr<IReader> reader, int in, int out, doFilterIIR doFilter, endFilterIIR endFilter, void* data) :
BaseIIRFilterReader(reader, in, out),
m_filter(doFilter), m_endFilter(endFilter), m_data(data)
{
}
CallbackIIRFilterReader::~CallbackIIRFilterReader()
{
if(m_endFilter)
m_endFilter(m_data);
}
sample_t CallbackIIRFilterReader::filter()
{
return m_filter(this, m_data);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,156 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Convolver.h"
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <cstring>
AUD_NAMESPACE_BEGIN
Convolver::Convolver(std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ir, int irLength, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
m_N(plan->getSize()), m_M(plan->getSize()/2), m_L(plan->getSize()/2), m_irBuffers(ir), m_numThreads(std::min(threadPool->getNumOfThreads(), static_cast<unsigned int>(m_irBuffers->size() - 1))), m_threadPool(threadPool), m_irLength(irLength), m_tailCounter(0), m_eos(false)
{
m_resetFlag = false;
m_futures.resize(m_numThreads);
for(int i = 0; i < m_irBuffers->size(); i++)
{
m_fftConvolvers.push_back(std::unique_ptr<FFTConvolver>(new FFTConvolver((*m_irBuffers)[i], plan)));
m_delayLine.push_front((fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex)));
}
m_accBuffer = (fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex));
for(int i = 0; i < m_numThreads; i++)
m_threadAccBuffers.push_back((fftwf_complex*)std::calloc((m_N / 2) + 1, sizeof(fftwf_complex)));
}
Convolver::~Convolver()
{
m_resetFlag = true;
for(auto &fut : m_futures)
if(fut.valid())
fut.get();
std::free(m_accBuffer);
for(auto buf : m_threadAccBuffers)
std::free(buf);
while(!m_delayLine.empty())
{
std::free(m_delayLine.front());
m_delayLine.pop_front();
}
}
void Convolver::getNext(sample_t* inBuffer, sample_t* outBuffer, int& length, bool& eos)
{
if(length > m_L)
{
length = 0;
eos = m_eos;
return;
}
if(m_eos)
{
eos = m_eos;
length = 0;
return;
}
eos = false;
for(auto &fut : m_futures)
if(fut.valid())
fut.get();
if(inBuffer != nullptr)
m_fftConvolvers[0]->getNextFDL(inBuffer, reinterpret_cast<std::complex<sample_t>*>(m_accBuffer), length, m_delayLine[0]);
else
{
m_tailCounter++;
std::memset(outBuffer, 0, m_L*sizeof(sample_t));
m_fftConvolvers[0]->getNextFDL(outBuffer, reinterpret_cast<std::complex<sample_t>*>(m_accBuffer), length, m_delayLine[0]);
}
m_delayLine.push_front(m_delayLine.back());
m_delayLine.pop_back();
length = m_L;
m_fftConvolvers[0]->IFFT_FDL(m_accBuffer, outBuffer, length);
std::memset(m_accBuffer, 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
if(m_tailCounter >= m_delayLine.size() && inBuffer == nullptr)
{
eos = m_eos = true;
length = m_irLength%m_M;
if(length == 0)
length = m_M;
}
else
for(int i = 0; i < m_futures.size(); i++)
m_futures[i] = m_threadPool->enqueue(&Convolver::threadFunction, this, i);
}
void Convolver::reset()
{
m_resetFlag = true;
for(auto &fut : m_futures)
if(fut.valid())
fut.get();
for(int i = 0; i < m_delayLine.size();i++)
std::memset(m_delayLine[i], 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
for(int i = 0; i < m_fftConvolvers.size(); i++)
m_fftConvolvers[i]->clear();
std::memset(m_accBuffer, 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
m_tailCounter = 0;
m_eos = false;
m_resetFlag = false;
}
std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> Convolver::getImpulseResponse()
{
return m_irBuffers;
}
void Convolver::setImpulseResponse(std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ir)
{
reset();
m_irBuffers = ir;
for(int i = 0; i < m_irBuffers->size(); i++)
m_fftConvolvers[i]->setImpulseResponse((*m_irBuffers)[i]);
}
bool Convolver::threadFunction(int id)
{
int total = m_irBuffers->size();
int share = std::ceil(((float)total - 1) / (float)m_numThreads);
int start = id*share + 1;
int end = std::min(start + share, total);
std::memset(m_threadAccBuffers[id], 0, ((m_N / 2) + 1)*sizeof(fftwf_complex));
for(int i = start; i < end && !m_resetFlag; i++)
m_fftConvolvers[i]->getNextFDL(reinterpret_cast<std::complex<sample_t>*>(m_delayLine[i]), reinterpret_cast<std::complex<sample_t>*>(m_threadAccBuffers[id]));
m_sumMutex.lock();
for(int i = 0; (i < m_N / 2 + 1) && !m_resetFlag; i++)
{
m_accBuffer[i][0] += m_threadAccBuffers[id][i][0];
m_accBuffer[i][1] += m_threadAccBuffers[id][i][1];
}
m_sumMutex.unlock();
return true;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,203 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ConvolverReader.h"
#include "Exception.h"
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
AUD_NAMESPACE_BEGIN
ConvolverReader::ConvolverReader(std::shared_ptr<IReader> reader, std::shared_ptr<ImpulseResponse> ir, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
m_position(0), m_reader(reader), m_ir(ir), m_N(plan->getSize()), m_eosReader(false), m_eosTail(false), m_inChannels(reader->getSpecs().channels), m_irChannels(ir->getSpecs().channels), m_threadPool(threadPool)
{
m_nChannelThreads = std::min((int)threadPool->getNumOfThreads(), m_inChannels);
m_futures.resize(m_nChannelThreads);
int irLength = m_ir->getLength();
if(m_irChannels != 1 && m_irChannels != m_inChannels)
AUD_THROW(StateException, "The impulse response and the sound must either have the same amount of channels or the impulse response must be mono");
if(m_reader->getSpecs().rate != m_ir->getSpecs().rate)
AUD_THROW(StateException, "The sound and the impulse response. must have the same rate");
m_M = m_L = m_N / 2;
if(m_irChannels > 1)
for(int i = 0; i < m_inChannels; i++)
m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(ir->getChannel(i), irLength, m_threadPool, plan)));
else
for(int i = 0; i < m_inChannels; i++)
m_convolvers.push_back(std::unique_ptr<Convolver>(new Convolver(ir->getChannel(0), irLength, m_threadPool, plan)));
for(int i = 0; i < m_inChannels; i++)
m_vecInOut.push_back((sample_t*)std::malloc(m_L*sizeof(sample_t)));
m_outBuffer = (sample_t*)std::malloc(m_L*m_inChannels*sizeof(sample_t));
m_outBufLen = m_eOutBufLen = m_outBufferPos = m_L*m_inChannels;
}
ConvolverReader::~ConvolverReader()
{
std::free(m_outBuffer);
for(int i = 0; i < m_inChannels; i++)
std::free(m_vecInOut[i]);
}
bool ConvolverReader::isSeekable() const
{
return m_reader->isSeekable();
}
void ConvolverReader::seek(int position)
{
m_position = position;
m_reader->seek(position);
for(int i = 0; i < m_inChannels; i++)
m_convolvers[i]->reset();
m_eosTail = false;
m_eosReader = false;
m_outBufferPos = m_eOutBufLen = m_outBufLen;
}
int ConvolverReader::getLength() const
{
return m_reader->getLength();
}
int ConvolverReader::getPosition() const
{
return m_position;
}
Specs ConvolverReader::getSpecs() const
{
return m_reader->getSpecs();
}
void ConvolverReader::read(int& length, bool& eos, sample_t* buffer)
{
if(length <= 0)
{
length = 0;
eos = (m_eosTail && m_outBufferPos >= m_eOutBufLen);
return;
}
eos = false;
int writePos = 0;
do
{
int bufRest = m_eOutBufLen - m_outBufferPos;
int writeLength = std::min((length*m_inChannels) - writePos, m_eOutBufLen + bufRest);
if(bufRest < writeLength || (m_eOutBufLen == 0 && m_eosTail))
{
if(bufRest > 0)
std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, bufRest*sizeof(sample_t));
if(!m_eosTail)
{
loadBuffer();
int len = std::min(std::abs(writeLength - bufRest), m_eOutBufLen);
std::memcpy(buffer + writePos + bufRest, m_outBuffer, len*sizeof(sample_t));
m_outBufferPos = len;
writeLength = std::min((length*m_inChannels) - writePos, m_eOutBufLen + bufRest);
}
else
{
m_outBufferPos += bufRest;
length = (writePos + bufRest) / m_inChannels;
eos = true;
return;
}
}
else
{
std::memcpy(buffer + writePos, m_outBuffer + m_outBufferPos, writeLength*sizeof(sample_t));
m_outBufferPos += writeLength;
}
writePos += writeLength;
} while(writePos < length*m_inChannels);
m_position += length;
}
void ConvolverReader::loadBuffer()
{
m_lastLengthIn = m_L;
m_reader->read(m_lastLengthIn, m_eosReader, m_outBuffer);
if(!m_eosReader || m_lastLengthIn>0)
{
divideByChannel(m_outBuffer, m_lastLengthIn*m_inChannels);
int len = m_lastLengthIn;
for(int i = 0; i < m_futures.size(); i++)
m_futures[i] = m_threadPool->enqueue(&ConvolverReader::threadFunction, this, i, true);
for(auto &fut : m_futures)
len = fut.get();
joinByChannel(0, len);
m_eOutBufLen = len*m_inChannels;
}
else if(!m_eosTail)
{
int len = m_lastLengthIn = m_L;
for(int i = 0; i < m_futures.size(); i++)
m_futures[i] = m_threadPool->enqueue(&ConvolverReader::threadFunction, this, i, false);
for(auto &fut : m_futures)
len = fut.get();
joinByChannel(0, len);
m_eOutBufLen = len*m_inChannels;
}
}
void ConvolverReader::divideByChannel(const sample_t* buffer, int len)
{
int k = 0;
for(int i = 0; i < len; i += m_inChannels)
{
for(int j = 0; j < m_inChannels; j++)
m_vecInOut[j][k] = buffer[i + j];
k++;
}
}
void ConvolverReader::joinByChannel(int start, int len)
{
int k = 0;
for(int i = 0; i < len*m_inChannels; i += m_inChannels)
{
for(int j = 0; j < m_vecInOut.size(); j++)
m_outBuffer[i + j + start] = m_vecInOut[j][k];
k++;
}
}
int ConvolverReader::threadFunction(int id, bool input)
{
int share = std::ceil((float)m_inChannels / (float)m_nChannelThreads);
int start = id*share;
int end = std::min(start + share, m_inChannels);
int l=m_lastLengthIn;
for(int i = start; i < end; i++)
if(input)
m_convolvers[i]->getNext(m_vecInOut[i], m_vecInOut[i], l, m_eosTail);
else
m_convolvers[i]->getNext(nullptr, m_vecInOut[i], l, m_eosTail);
return l;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ConvolverSound.h"
#include "fx/ConvolverReader.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
ConvolverSound::ConvolverSound(std::shared_ptr<ISound> sound, std::shared_ptr<ImpulseResponse> impulseResponse, std::shared_ptr<ThreadPool> threadPool) :
ConvolverSound(sound, impulseResponse, threadPool, std::make_shared<FFTPlan>(0.0))
{
}
ConvolverSound::ConvolverSound(std::shared_ptr<ISound> sound, std::shared_ptr<ImpulseResponse> impulseResponse, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan) :
m_sound(sound), m_impulseResponse(impulseResponse), m_threadPool(threadPool), m_plan(plan)
{
}
std::shared_ptr<IReader> ConvolverSound::createReader()
{
return std::make_shared<ConvolverReader>(m_sound->createReader(), m_impulseResponse, m_threadPool, m_plan);
}
std::shared_ptr<ImpulseResponse> ConvolverSound::getImpulseResponse()
{
return m_impulseResponse;
}
void ConvolverSound::setImpulseResponse(std::shared_ptr<ImpulseResponse> impulseResponse)
{
m_impulseResponse = impulseResponse;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Delay.h"
#include "fx/DelayReader.h"
AUD_NAMESPACE_BEGIN
Delay::Delay(std::shared_ptr<ISound> sound, double delay) :
Effect(sound),
m_delay(delay)
{
}
double Delay::getDelay() const
{
return m_delay;
}
std::shared_ptr<IReader> Delay::createReader()
{
return std::shared_ptr<IReader>(new DelayReader(getReader(), m_delay));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/DelayReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
DelayReader::DelayReader(std::shared_ptr<IReader> reader, double delay) :
EffectReader(reader),
m_delay(int((SampleRate)delay * reader->getSpecs().rate)),
m_remdelay(int((SampleRate)delay * reader->getSpecs().rate))
{
}
void DelayReader::seek(int position)
{
if(position < m_delay)
{
m_remdelay = m_delay - position;
m_reader->seek(0);
}
else
{
m_remdelay = 0;
m_reader->seek(position - m_delay);
}
}
int DelayReader::getLength() const
{
int len = m_reader->getLength();
if(len < 0)
return len;
return len + m_delay;
}
int DelayReader::getPosition() const
{
if(m_remdelay > 0)
return m_delay - m_remdelay;
return m_reader->getPosition() + m_delay;
}
void DelayReader::read(int& length, bool& eos, sample_t* buffer)
{
if(m_remdelay > 0)
{
Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
if(length > m_remdelay)
{
std::memset(buffer, 0, m_remdelay * samplesize);
int len = length - m_remdelay;
m_reader->read(len, eos, buffer + m_remdelay * specs.channels);
length = m_remdelay + len;
m_remdelay = 0;
}
else
{
std::memset(buffer, 0, length * samplesize);
m_remdelay -= length;
}
}
else
m_reader->read(length, eos, buffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/DynamicIIRFilter.h"
#include "fx/DynamicIIRFilterReader.h"
AUD_NAMESPACE_BEGIN
DynamicIIRFilter::DynamicIIRFilter(std::shared_ptr<ISound> sound,
std::shared_ptr<IDynamicIIRFilterCalculator> calculator) :
Effect(sound),
m_calculator(calculator)
{
}
std::shared_ptr<IReader> DynamicIIRFilter::createReader()
{
return std::shared_ptr<IReader>(new DynamicIIRFilterReader(getReader(), m_calculator));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/DynamicIIRFilterReader.h"
#include "fx/IDynamicIIRFilterCalculator.h"
AUD_NAMESPACE_BEGIN
DynamicIIRFilterReader::DynamicIIRFilterReader(std::shared_ptr<IReader> reader, std::shared_ptr<IDynamicIIRFilterCalculator> calculator) :
IIRFilterReader(reader, std::vector<float>(), std::vector<float>()),
m_calculator(calculator)
{
sampleRateChanged(reader->getSpecs().rate);
}
void DynamicIIRFilterReader::sampleRateChanged(SampleRate rate)
{
std::vector<float> a, b;
m_calculator->recalculateCoefficients(rate, b, a);
setCoefficients(b, a);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,343 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/DynamicMusic.h"
#include <mutex>
#include <condition_variable>
AUD_NAMESPACE_BEGIN
DynamicMusic::DynamicMusic(std::shared_ptr<IDevice> device) :
m_fadeTime(1.0f), m_device(device)
{
m_id = 0;
m_transitioning = false;
m_stopThread = false;
m_volume = m_device->getVolume();
m_scenes.push_back(std::vector<std::shared_ptr<ISound>>(1, nullptr));
}
DynamicMusic::~DynamicMusic()
{
stop();
}
int DynamicMusic::addScene(std::shared_ptr<ISound> sound)
{
std::vector<std::shared_ptr<ISound>> v;
m_scenes.push_back(v);
for(int i = 0; i < m_scenes.size()-1; i++)
m_scenes.back().push_back(nullptr);
for(int i = 0; i < m_scenes.size()-1; i++)
m_scenes[i].push_back(nullptr);
m_scenes.back().push_back(sound);
return m_scenes.size() - 1;
}
bool DynamicMusic::changeScene(int id)
{
if(id >= m_scenes.size() || m_transitioning)
return false;
else
{
if(m_fadeThread.joinable())
m_fadeThread.join();
m_device->lock();
if(id == m_id)
{
m_currentHandle->setVolume(m_volume);
m_currentHandle->setLoopCount(-1);
}
else
{
m_soundTarget = id;
if(m_scenes[m_id][id] == nullptr)
{
m_stopThread = false;
if((m_scenes[m_id][m_id] != nullptr && m_currentHandle->getStatus() != STATUS_INVALID) || m_scenes[m_soundTarget][m_soundTarget] != nullptr)
{
m_transitioning = true;
if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
{
m_device->lock();
m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
m_currentHandle->setVolume(0.0f);
m_currentHandle->setLoopCount(-1);
m_device->unlock();
m_fadeThread = std::thread(&DynamicMusic::fadeInThread, this);
}
else
{
if(m_scenes[m_soundTarget][m_soundTarget] != nullptr)
{
m_device->lock();
m_transitionHandle = m_currentHandle;
m_currentHandle = m_device->play(m_scenes[m_soundTarget][m_soundTarget]);
m_currentHandle->setVolume(0.0f);
m_currentHandle->setLoopCount(-1);
m_device->unlock();
m_fadeThread = std::thread(&DynamicMusic::crossfadeThread, this);
}
else
{
m_transitionHandle = m_currentHandle;
m_currentHandle = nullptr;
m_fadeThread = std::thread(&DynamicMusic::fadeOutThread, this);
}
}
}
}
else
{
if(m_scenes[m_id][m_id] == nullptr || m_currentHandle->getStatus() == STATUS_INVALID)
transitionCallback(this);
else
{
m_currentHandle->setLoopCount(0);
m_currentHandle->setStopCallback(transitionCallback, this);
}
}
}
m_device->unlock();
return true;
}
}
int DynamicMusic::getScene()
{
return m_id;
}
bool DynamicMusic::addTransition(int init, int end, std::shared_ptr<ISound> sound)
{
if(init != end && init < m_scenes.size() && end < m_scenes.size() && init >= 0 && end >= 0)
{
m_scenes[init][end] = sound;
return true;
}
return false;
}
void DynamicMusic::setFadeTime(double seconds)
{
m_device->lock();
m_fadeTime = seconds;
m_device->unlock();
}
double DynamicMusic::getFadeTime()
{
return m_fadeTime;
}
bool DynamicMusic::resume()
{
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->resume();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->resume();
return result || resultTrans;
}
bool DynamicMusic::pause()
{
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->pause();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->pause();
return result || resultTrans;
}
bool DynamicMusic::seek(double position)
{
bool result = false;
if(m_currentHandle != nullptr)
{
result = m_currentHandle->seek(position);
if(m_transitionHandle != nullptr && result == true)
m_transitionHandle->stop();
}
return result;
}
double DynamicMusic::getPosition()
{
double result = 0.0f;
if(m_currentHandle != nullptr)
result = m_currentHandle->getPosition();
return result;
}
float DynamicMusic::getVolume()
{
return m_volume;
}
bool DynamicMusic::setVolume(float volume)
{
m_volume = volume;
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->setVolume(volume);
if(m_transitionHandle != nullptr)
{
m_device->lock();
if(volume<m_transitionHandle->getVolume())
resultTrans = m_transitionHandle->setVolume(0.0f);
m_device->unlock();
}
if(m_currentHandle == nullptr && m_transitionHandle == nullptr)
result = true;
return result || resultTrans;
}
Status DynamicMusic::getStatus()
{
if(m_currentHandle != nullptr)
{
Status result = m_currentHandle->getStatus();
return result;
}
else
return STATUS_INVALID;
}
bool DynamicMusic::stop()
{
m_stopThread = true;
bool result = false, resultTrans = false;
if(m_currentHandle != nullptr)
result = m_currentHandle->stop();
if(m_transitionHandle != nullptr)
resultTrans = m_transitionHandle->stop();
if(m_fadeThread.joinable())
m_fadeThread.join();
m_id = 0;
return result || resultTrans;
}
void DynamicMusic::transitionCallback(void* player)
{
auto dat = reinterpret_cast<DynamicMusic*>(player);
dat->m_transitioning = true;
dat->m_device->lock();
dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_id][dat->m_soundTarget]);
dat->m_currentHandle->setVolume(dat->m_volume);
if(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget] != nullptr)
dat->m_currentHandle->setStopCallback(sceneCallback, player);
dat->m_device->unlock();
}
void DynamicMusic::sceneCallback(void* player)
{
auto dat = reinterpret_cast<DynamicMusic*>(player);
dat->m_device->lock();
dat->m_currentHandle = dat->m_device->play(dat->m_scenes[dat->m_soundTarget][dat->m_soundTarget]);
dat->m_currentHandle->setVolume(dat->m_volume);
dat->m_currentHandle->setLoopCount(-1);
dat->m_device->unlock();
dat->m_id = int(dat->m_soundTarget);
dat->m_soundTarget = -1;
dat->m_transitioning = false;
}
void DynamicMusic::crossfadeThread()
{
float currentVol = m_transitionHandle->getVolume();
float nextVol = m_currentHandle->getVolume();
float increment;
while(nextVol < m_volume && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
currentVol -= increment;
nextVol += increment;
if(currentVol < 0)
currentVol = 0;
if(nextVol > m_volume)
nextVol = m_volume;
m_transitionHandle->setVolume(currentVol);
m_currentHandle->setVolume(nextVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
if(m_stopThread)
m_transitionHandle->setVolume(m_volume);
m_transitionHandle->stop();
m_id = int(m_soundTarget);
m_transitioning = false;
}
void DynamicMusic::fadeInThread()
{
float nextVol = m_currentHandle->getVolume();
float increment;
while(nextVol < m_volume && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
nextVol += increment;
if(nextVol > m_volume)
nextVol = m_volume;
m_currentHandle->setVolume(nextVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
if(m_stopThread)
m_currentHandle->setVolume(m_volume);
m_id = int(m_soundTarget);
m_transitioning = false;
}
void DynamicMusic::fadeOutThread()
{
float currentVol = m_transitionHandle->getVolume();
float increment;
while(currentVol > 0.0f && !m_stopThread)
{
increment = (m_volume / (m_fadeTime * 1000)) * 20;
currentVol -= increment;
if(currentVol < 0)
currentVol = 0;
m_transitionHandle->setVolume(currentVol);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
m_transitionHandle->stop();
m_id = int(m_soundTarget);
m_transitioning = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,17 @@
#include "fx/Echo.h"
#include "fx/EchoReader.h"
AUD_NAMESPACE_BEGIN
Echo::Echo(std::shared_ptr<ISound> sound, float delay, float feedback, float mix, bool resetBuffer) :
Effect(sound), m_delay(delay), m_feedback(feedback), m_mix(mix), m_resetBuffer(resetBuffer)
{
}
std::shared_ptr<IReader> Echo::createReader()
{
return std::make_shared<EchoReader>(getReader(), m_delay, m_feedback, m_mix, m_resetBuffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/EchoReader.h"
#include <cstring>
#include "IReader.h"
#include "util/Buffer.h"
AUD_NAMESPACE_BEGIN
EchoReader::EchoReader(std::shared_ptr<IReader> reader, float delay, float feedback, float mix, bool resetBuffer) :
EffectReader(reader), m_delay(delay), m_feedback(feedback), m_mix(mix), m_resetBuffer(resetBuffer)
{
}
void EchoReader::read(int& length, bool& eos, sample_t* buffer)
{
auto specs = m_reader->getSpecs();
auto delaySamples = static_cast<int>(m_delay * specs.rate);
m_inBuffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
// Note: should this ever do something another time than in the beginning,
// it will likely cause an audible glitch, as samples are not reordered
m_delayBuffer.assureSize(delaySamples * AUD_SAMPLE_SIZE(specs));
m_reader->read(length, eos, m_inBuffer.getBuffer());
sample_t* delayBuffer = m_delayBuffer.getBuffer();
for(int i = 0; i < length; i++)
{
for(int channel = 0; channel < specs.channels; channel++)
{
int delayPosition = ((m_writePosition + i) % delaySamples) * specs.channels + channel;
sample_t inSample = m_inBuffer.getBuffer()[i * specs.channels + channel];
sample_t delayedSample = delayPosition < m_samplesAvailable * specs.channels ? delayBuffer[delayPosition] : 0;
sample_t outSample = inSample + delayedSample * m_feedback;
buffer[i * specs.channels + channel] = inSample * (1.0f - m_mix) + outSample * m_mix;
// Update delay buffer with feedback
delayBuffer[delayPosition] = outSample;
}
}
m_writePosition = (m_writePosition + length) % delaySamples;
m_samplesAvailable = std::min(delaySamples, m_samplesAvailable + length);
}
void EchoReader::seek(int position)
{
m_reader->seek(position);
if(m_resetBuffer)
{
m_samplesAvailable = 0;
m_writePosition = 0;
}
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Effect.h"
AUD_NAMESPACE_BEGIN
Effect::Effect(std::shared_ptr<ISound> sound)
{
m_sound = sound;
}
Effect::~Effect()
{
}
std::shared_ptr<ISound> Effect::getSound() const
{
return m_sound;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/EffectReader.h"
AUD_NAMESPACE_BEGIN
EffectReader::EffectReader(std::shared_ptr<IReader> reader)
{
m_reader = reader;
}
EffectReader::~EffectReader()
{
}
bool EffectReader::isSeekable() const
{
return m_reader->isSeekable();
}
void EffectReader::seek(int position)
{
m_reader->seek(position);
}
int EffectReader::getLength() const
{
return m_reader->getLength();
}
int EffectReader::getPosition() const
{
return m_reader->getPosition();
}
Specs EffectReader::getSpecs() const
{
return m_reader->getSpecs();
}
void EffectReader::read(int& length, bool& eos, sample_t* buffer)
{
m_reader->read(length, eos, buffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Envelope.h"
#include "fx/CallbackIIRFilterReader.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
struct EnvelopeParameters
{
float attack;
float release;
float threshold;
float arthreshold;
};
sample_t Envelope::envelopeFilter(CallbackIIRFilterReader* reader, EnvelopeParameters* param)
{
float in = std::fabs(reader->x(0));
float out = reader->y(-1);
if(in < param->threshold)
in = 0.0f;
return (in > out ? param->attack : param->release) * (out - in) + in;
}
void Envelope::endEnvelopeFilter(EnvelopeParameters* param)
{
delete param;
}
Envelope::Envelope(std::shared_ptr<ISound> sound, float attack, float release, float threshold, float arthreshold) :
Effect(sound),
m_attack(attack),
m_release(release),
m_threshold(threshold),
m_arthreshold(arthreshold)
{
}
std::shared_ptr<IReader> Envelope::createReader()
{
std::shared_ptr<IReader> reader = getReader();
EnvelopeParameters* param = new EnvelopeParameters();
param->arthreshold = m_arthreshold;
param->attack = std::pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_attack));
param->release = std::pow(m_arthreshold, 1.0f/(static_cast<float>(reader->getSpecs().rate) * m_release));
param->threshold = m_threshold;
return std::shared_ptr<IReader>(new CallbackIIRFilterReader(reader, 1, 2,
(doFilterIIR) envelopeFilter,
(endFilterIIR) endEnvelopeFilter,
param));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,367 @@
/*******************************************************************************
* Copyright 2022 Marcos Perez Gonzalez
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Equalizer.h"
#include <chrono>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
#include "Exception.h"
#include "fx/ConvolverReader.h"
#include "fx/ImpulseResponse.h"
#include "util/Buffer.h"
#include "util/FFTPlan.h"
#include "util/ThreadPool.h"
AUD_NAMESPACE_BEGIN
Equalizer::Equalizer(std::shared_ptr<ISound> sound, std::shared_ptr<Buffer> bufEQ, int externalSizeEq, float maxFreqEq, int sizeConversion) : m_sound(sound), m_bufEQ(bufEQ)
{
this->maxFreqEq = maxFreqEq;
this->external_size_eq = externalSizeEq;
filter_length = sizeConversion;
}
Equalizer::~Equalizer()
{
}
std::shared_ptr<IReader> Equalizer::createReader()
{
std::shared_ptr<FFTPlan> fp = std::shared_ptr<FFTPlan>(new FFTPlan(filter_length));
// 2 threads to start with
return std::shared_ptr<ConvolverReader>(new ConvolverReader(m_sound->createReader(), createImpulseResponse(), std::shared_ptr<ThreadPool>(new ThreadPool(2)), fp));
}
float calculateValueArray(float* data, float minX, float maxX, int length, float posX)
{
if(posX < minX)
return 1.0;
if(posX > maxX)
return data[length - 1];
float interval = (maxX - minX) / (float) length;
int idx = (int) ((posX - minX) / interval);
return data[idx];
}
void complex_prod(float a, float b, float c, float d, float* r, float* imag)
{
float prod1 = a * c;
float prod2 = b * d;
float prod3 = (a + b) * (c + d);
// Real Part
*r = prod1 - prod2;
// Imaginary Part
*imag = prod3 - (prod1 + prod2);
}
/**
* The creation of the ImpuseResponse which will be convoluted with the sound
*
* The implementation is based on scikit-signal
*/
std::shared_ptr<ImpulseResponse> Equalizer::createImpulseResponse()
{
std::shared_ptr<FFTPlan> fp = std::shared_ptr<FFTPlan>(new FFTPlan(filter_length));
fftwf_complex* buffer = (fftwf_complex*) fp->getBuffer();
std::memset(buffer, 0, filter_length * sizeof(fftwf_complex));
std::shared_ptr<IReader> soundReader = m_sound.get()->createReader();
Specs specsSound = soundReader.get()->getSpecs();
int sampleRate = specsSound.rate;
for(unsigned i = 0; i < filter_length / 2; i++)
{
double freq = (((float) i) / (float) filter_length) * (float) sampleRate;
double dbGain = calculateValueArray(m_bufEQ->getBuffer(), 0.0, maxFreqEq, external_size_eq, freq);
// gain = 10^(decibels / 20.0)
// 0 db = 1
// 20 db = 10
// 40 db = 100
float gain = (float) pow(10.0, dbGain / 20.0);
if(i == filter_length / 2 - 1)
{
gain = 0;
}
// IMPORTANT!!!! It is needed for the minimum phase step.
// Without this, the amplitude would be square rooted
//
gain *= gain;
// Calculation of exponential with std.. or "by hand"
/*
std::complex<float> preShift= std::complex<float>(0.0, -(filter_length - 1)
/ 2. * M_PI * freq / ( sampleRate/2)); std::complex<float> shift =
std::exp(preShift);
std::complex<float> cGain = gain * shift;
*/
float imaginary_shift = -(filter_length - 1) / 2. * M_PI * freq / (sampleRate / 2);
float cGain_real = gain * cos(imaginary_shift);
float cGain_imag = gain * sin(imaginary_shift);
int i2 = filter_length - i - 1;
buffer[i][0] = cGain_real; // Real
buffer[i][1] = cGain_imag; // Imag
if(i > 0 && i2 < filter_length)
{
buffer[i2][0] = cGain_real; // Real
buffer[i2][1] = cGain_imag; // Imag
}
}
// In place. From Complex to sample_t
fp->IFFT(buffer);
// Window Hamming
sample_t* pt_sample_t = (sample_t*) buffer;
float half_filter = ((float) filter_length) / 2.0;
for(int i = 0; i < filter_length; i++)
{
// Centered in filter_length/2
float window = 0.54 - 0.46 * cos((2 * M_PI * (float) i) / (float) (filter_length - 1));
pt_sample_t[i] *= window;
}
std::shared_ptr<Buffer> b2 = std::shared_ptr<Buffer>(new Buffer(filter_length * sizeof(sample_t)));
sample_t* buffer_real = (sample_t*) buffer;
sample_t* buffer2 = b2->getBuffer();
float normaliziter = (float) filter_length;
for(int i = 0; i < filter_length; i++)
{
buffer2[i] = (buffer_real[i] / normaliziter);
}
fp->freeBuffer(buffer);
//
// Here b2 is the buffer with a "valid" FIR (remember the squared amplitude
//
std::shared_ptr<Buffer> ir_minimum = minimumPhaseFilterHomomorphic(b2, filter_length, -1);
Specs specsIR;
specsIR.rate = sampleRate;
specsIR.channels = CHANNELS_MONO;
return std::shared_ptr<ImpulseResponse>(new ImpulseResponse(std::shared_ptr<StreamBuffer>(new StreamBuffer(ir_minimum, specsIR)), fp));
}
std::shared_ptr<Buffer> Equalizer::minimumPhaseFilterHomomorphic(std::shared_ptr<Buffer> original, int lOriginal, int lWork)
{
void* b_orig = original->getBuffer();
if(lWork < lOriginal || lWork < 0)
{
lWork = (int) pow(2, ceil(log2((float) (2 * (lOriginal - 1) / 0.01))));
}
std::shared_ptr<FFTPlan> fp = std::shared_ptr<FFTPlan>(new FFTPlan(lWork, 0.1));
fftwf_complex* buffer = (fftwf_complex*) fp->getBuffer();
sample_t* b_work = (sample_t*) buffer;
// Padding with 0
std::memset(b_work, 0, lWork * sizeof(sample_t));
std::memcpy(b_work, b_orig, lOriginal * sizeof(sample_t));
fp->FFT(b_work);
for(int i = 0; i < lWork / 2; i++)
{
buffer[i][0] = fabs(sqrt(buffer[i][0] * buffer[i][0] + buffer[i][1] * buffer[i][1]));
buffer[i][1] = 0.0;
int conjugate = lWork - i - 1;
buffer[conjugate][0] = buffer[i][0];
buffer[conjugate][1] = 0.0;
}
double threshold = pow(10.0, -7);
float logThreshold = (float) log(threshold);
// take 0.25*log(|H|**2) = 0.5*log(|H|)
for(int i = 0; i < lWork; i++)
{
if(buffer[i][0] < threshold)
{
buffer[i][0] = 0.5 * logThreshold;
}
else
{
buffer[i][0] = 0.5 * log(buffer[i][0]);
}
}
fp->IFFT(buffer);
// homomorphic filter
int stop = (lOriginal + 1) / 2;
b_work[0] = b_work[0] / (float) lWork;
for(int i = 1; i < stop; i++)
{
b_work[i] = b_work[i] / (float) lWork * 2.0;
}
for(int i = stop; i < lWork; i++)
{
b_work[i] = 0;
}
fp->FFT(buffer);
// EXP
// e^x = e^ (a+bi)= e^a * e^bi = e^a * (cos b + i sin b)
for(int i = 0; i < lWork / 2; i++)
{
float new_real;
float new_imag;
new_real = exp(buffer[i][0]) * cos(buffer[i][1]);
new_imag = exp(buffer[i][0]) * sin(buffer[i][1]);
buffer[i][0] = new_real;
buffer[i][1] = new_imag;
int conjugate = lWork - i - 1;
buffer[conjugate][0] = new_real;
buffer[conjugate][1] = new_imag;
}
// IFFT
fp->IFFT(buffer);
// Create new clean Buffer with only the result and normalization
int lOut = (lOriginal / 2) + lOriginal % 2;
std::shared_ptr<Buffer> bOut = std::shared_ptr<Buffer>(new Buffer(sizeof(float) * lOut));
float* bbOut = (float*) bOut->getBuffer();
// Copy and normalize
for(int i = 0; i < lOut; i++)
{
bbOut[i] = b_work[i] / (float) lWork;
}
fp->freeBuffer(buffer);
return bOut;
}
std::shared_ptr<Buffer> Equalizer::minimumPhaseFilterHilbert(std::shared_ptr<Buffer> original, int lOriginal, int lWork)
{
void* b_orig = original->getBuffer();
if(lWork < lOriginal || lWork < 0)
{
lWork = (int) pow(2, ceil(log2((float) (2 * (lOriginal - 1) / 0.01))));
}
std::shared_ptr<FFTPlan> fp = std::shared_ptr<FFTPlan>(new FFTPlan(lWork, 0.1));
fftwf_complex* buffer = (fftwf_complex*) fp->getBuffer();
sample_t* b_work = (sample_t*) buffer;
// Padding with 0
std::memset(b_work, 0, lWork * sizeof(sample_t));
std::memcpy(b_work, b_orig, lOriginal * sizeof(sample_t));
fp->FFT(b_work);
float mymax, mymin;
float n_half = (float) (lOriginal >> 1);
for(int i = 0; i < lWork; i++)
{
float w = ((float) i) * 2.0 * M_PI / (float) lWork * n_half;
float f1 = cos(w);
float f2 = sin(w);
float f3, f4;
complex_prod(buffer[i][0], buffer[i][1], f1, f2, &f3, &f4);
buffer[i][0] = f3;
buffer[i][1] = 0.0;
if(i == 0)
{
mymax = f3;
mymin = f3;
}
else
{
if(f3 < mymin)
mymin = f3;
if(f3 > mymax)
mymax = f3;
}
}
float dp = mymax - 1;
float ds = 0 - mymin;
float S = 4.0 / pow(2, (sqrt(1 + dp + ds) + sqrt(1 - dp + ds)));
for(int i = 0; i < lWork; i++)
{
buffer[i][0] = sqrt((buffer[i][0] + ds) * S) + 1.0E-10;
}
fftwf_complex* buffer_tmp = (fftwf_complex*) std::malloc(lWork * sizeof(fftwf_complex));
std::memcpy(buffer_tmp, buffer, lWork * sizeof(fftwf_complex));
//
// Hilbert transform
//
int midpt = lWork >> 1;
for(int i = 0; i < lWork; i++)
buffer[i][0] = log(buffer[i][0]);
fp->IFFT(buffer);
b_work[0] = 0.0;
for(int i = 1; i < midpt; i++)
{
b_work[i] /= (float) lWork;
}
b_work[midpt] = 0.0;
for(int i = midpt + 1; i < lWork; i++)
{
b_work[i] /= (-1.0 * lWork);
}
fp->FFT(b_work);
// Exp
for(int i = 0; i < lWork; i++)
{
float base = exp(buffer[i][0]);
buffer[i][0] = base * cos(buffer[i][1]);
buffer[i][1] = base * sin(buffer[i][1]);
complex_prod(buffer_tmp[i][0], buffer_tmp[i][1], buffer[i][0], buffer[i][1], &(buffer[i][0]), &(buffer[i][1]));
}
std::free(buffer_tmp);
fp->IFFT(buffer);
//
// Copy and normalization
//
int n_out = n_half + lOriginal % 2;
std::shared_ptr<Buffer> b_minimum = std::shared_ptr<Buffer>(new Buffer(n_out * sizeof(sample_t)));
std::memcpy(b_minimum->getBuffer(), buffer, n_out * sizeof(sample_t));
sample_t* b_final = (sample_t*) b_minimum->getBuffer();
for(int i = 0; i < n_out; i++)
{
b_final[i] /= (float) lWork;
}
return b_minimum;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/FFTConvolver.h"
#include <cstring>
#include <cstdlib>
AUD_NAMESPACE_BEGIN
FFTConvolver::FFTConvolver(std::shared_ptr<std::vector<std::complex<sample_t>>> ir, std::shared_ptr<FFTPlan> plan) :
m_plan(plan), m_N(plan->getSize()), m_M(plan->getSize()/2), m_L(plan->getSize()/2), m_irBuffer(ir), m_tailPos(0)
{
m_tail = (float*)calloc(m_M - 1, sizeof(float));
m_realBufLen = ((m_N / 2) + 1) * 2;
m_inBuffer = nullptr;
m_shiftBuffer = (sample_t*)std::calloc(m_N, sizeof(sample_t));
}
FFTConvolver::~FFTConvolver()
{
std::free(m_tail);
std::free(m_shiftBuffer);
if(m_inBuffer != nullptr)
m_plan->freeBuffer(m_inBuffer);
}
void FFTConvolver::getNext(const sample_t* inBuffer, sample_t* outBuffer, int& length)
{
if(length > m_L || length <= 0)
{
length = 0;
return;
}
if(m_inBuffer == nullptr)
m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
std::memcpy(m_inBuffer, inBuffer, length*sizeof(sample_t));
m_plan->FFT(m_inBuffer);
for(int i = 0; i < m_realBufLen / 2; i++)
{
m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
}
m_plan->IFFT(m_inBuffer);
for(int i = 0; i < m_M - 1; i++)
((float*)m_inBuffer)[i] += m_tail[i];
for(int i = 0; i < m_M - 1; i++)
m_tail[i] = ((float*)m_inBuffer)[i + length];
std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
}
void FFTConvolver::getNext(const sample_t* inBuffer, sample_t* outBuffer, int& length, fftwf_complex* transformedData)
{
if(length > m_L || length <= 0)
{
length = 0;
return;
}
if(m_inBuffer == nullptr)
m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
std::memcpy(m_inBuffer, inBuffer, length*sizeof(sample_t));
m_plan->FFT(m_inBuffer);
std::memcpy(transformedData, m_inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
for(int i = 0; i < m_realBufLen / 2; i++)
{
m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
}
m_plan->IFFT(m_inBuffer);
for(int i = 0; i < m_M - 1; i++)
((float*)m_inBuffer)[i] += m_tail[i];
for(int i = 0; i < m_M - 1; i++)
m_tail[i] = ((float*)m_inBuffer)[i + length];
std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
}
void FFTConvolver::getNext(const fftwf_complex* inBuffer, sample_t* outBuffer, int& length)
{
if(length > m_L || length <= 0)
{
length = 0;
return;
}
if(m_inBuffer == nullptr)
m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
for(int i = 0; i < m_realBufLen / 2; i++)
{
m_inBuffer[i] = m_inBuffer[i] * (*m_irBuffer)[i] / sample_t(m_N);
}
m_plan->IFFT(m_inBuffer);
for(int i = 0; i < m_M - 1; i++)
((float*)m_inBuffer)[i] += m_tail[i];
for(int i = 0; i < m_M - 1; i++)
m_tail[i] = ((float*)m_inBuffer)[i + length];
std::memcpy(outBuffer, m_inBuffer, length * sizeof(sample_t));
}
void FFTConvolver::getTail(int& length, bool& eos, sample_t* buffer)
{
if(length <= 0)
{
length = 0;
eos = m_tailPos >= m_M - 1;
return;
}
eos = false;
if(m_tailPos + length > m_M - 1)
{
length = m_M - 1 - m_tailPos;
if(length < 0)
length = 0;
eos = true;
m_tailPos = m_M - 1;
}
else
m_tailPos += length;
std::memcpy(buffer, m_tail, length*sizeof(sample_t));
}
void FFTConvolver::clear()
{
std::memset(m_shiftBuffer, 0, m_N * sizeof(sample_t));
std::memset(m_tail, 0, m_M - 1);
}
void FFTConvolver::IFFT_FDL(const fftwf_complex* inBuffer, sample_t* outBuffer, int& length)
{
if(length > m_L || length <= 0)
{
length = 0;
return;
}
if(m_inBuffer == nullptr)
m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
std::memcpy(m_inBuffer, inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
m_plan->IFFT(m_inBuffer);
std::memcpy(outBuffer, ((sample_t*)m_inBuffer)+m_L, length*sizeof(sample_t));
}
void FFTConvolver::getNextFDL(const std::complex<sample_t>* inBuffer, std::complex<sample_t>* accBuffer)
{
for(int i = 0; i < m_realBufLen / 2; i++)
{
accBuffer[i] += (inBuffer[i] * (*m_irBuffer)[i]) / sample_t(m_N);
}
}
void FFTConvolver::getNextFDL(const sample_t* inBuffer, std::complex<sample_t>* accBuffer, int& length, fftwf_complex* transformedData)
{
if(length > m_L || length <= 0)
{
length = 0;
return;
}
if(m_inBuffer == nullptr)
m_inBuffer = reinterpret_cast<std::complex<sample_t>*>(m_plan->getBuffer());
std::memcpy(m_shiftBuffer, m_shiftBuffer + m_L, m_L*sizeof(sample_t));
std::memcpy(m_shiftBuffer + m_L, inBuffer, length*sizeof(sample_t));
std::memset(m_inBuffer, 0, m_realBufLen * sizeof(fftwf_complex));
std::memcpy(m_inBuffer, m_shiftBuffer, (m_L+length)*sizeof(sample_t));
m_plan->FFT(m_inBuffer);
std::memcpy(transformedData, m_inBuffer, (m_realBufLen / 2)*sizeof(fftwf_complex));
for(int i = 0; i < m_realBufLen / 2; i++)
{
accBuffer[i] += (m_inBuffer[i] * (*m_irBuffer)[i]) / sample_t(m_N);
}
}
void FFTConvolver::setImpulseResponse(std::shared_ptr<std::vector<std::complex<sample_t>>> ir)
{
clear();
m_irBuffer = ir;
}
std::shared_ptr<std::vector<std::complex<sample_t>>> FFTConvolver::getImpulseResponse()
{
return m_irBuffer;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Fader.h"
AUD_NAMESPACE_BEGIN
Fader::Fader(std::shared_ptr<ISound> sound, FadeType type, double start, double length) :
Effect(sound),
m_type(type),
m_start(start),
m_length(length)
{
}
FadeType Fader::getType() const
{
return m_type;
}
double Fader::getStart() const
{
return m_start;
}
double Fader::getLength() const
{
return m_length;
}
std::shared_ptr<IReader> Fader::createReader()
{
return std::shared_ptr<IReader>(new FaderReader(getReader(), m_type, m_start, m_length));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/FaderReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
FaderReader::FaderReader(std::shared_ptr<IReader> reader, FadeType type, double start, double length) :
EffectReader(reader),
m_type(type),
m_start(start),
m_length(length)
{
}
void FaderReader::read(int& length, bool& eos, sample_t* buffer)
{
int position = m_reader->getPosition();
Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
m_reader->read(length, eos, buffer);
if((position + length) / specs.rate <= m_start)
{
if(m_type != FADE_OUT)
{
std::memset(buffer, 0, length * samplesize);
}
}
else if(position / specs.rate >= m_start+m_length)
{
if(m_type == FADE_OUT)
{
std::memset(buffer, 0, length * samplesize);
}
}
else
{
float volume = 1.0f;
for(int i = 0; i < length * specs.channels; i++)
{
if(i % specs.channels == 0)
{
volume = float((((position + i) / specs.rate) - m_start) / m_length);
if(volume > 1.0f)
volume = 1.0f;
else if(volume < 0.0f)
volume = 0.0f;
if(m_type == FADE_OUT)
volume = 1.0f - volume;
}
buffer[i] = buffer[i] * volume;
}
}
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,122 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/HRTF.h"
#include "Exception.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
HRTF::HRTF() :
HRTF(std::make_shared<FFTPlan>(0.0))
{
}
HRTF::HRTF(std::shared_ptr<FFTPlan> plan) :
m_plan(plan)
{
m_specs.channels = CHANNELS_INVALID;
m_specs.rate = 0;
m_empty = true;
}
bool HRTF::addImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse, float azimuth, float elevation)
{
Specs spec = impulseResponse->getSpecs();
azimuth = std::fmod(azimuth, 360);
if(azimuth < 0)
azimuth += 360;
if((spec.channels != CHANNELS_MONO) || (spec.rate != m_specs.rate && m_specs.rate > 0.0))
return false;
m_hrtfs[elevation][azimuth] = std::make_shared<ImpulseResponse>(impulseResponse, m_plan);
m_specs.channels = CHANNELS_MONO;
m_specs.rate = spec.rate;
m_empty = false;
return true;
}
std::pair<std::shared_ptr<ImpulseResponse>, std::shared_ptr<ImpulseResponse>> HRTF::getImpulseResponse(float &azimuth, float &elevation)
{
if(m_hrtfs.empty())
return std::make_pair(nullptr, nullptr);
azimuth = std::fmod(azimuth, 360);
if(azimuth < 0)
azimuth += 360;
std::shared_ptr<ImpulseResponse> R, L;
float az = 0, el = 0, dif=0, minDif=360;
for(auto elem : m_hrtfs)
{
dif = std::fabs(elevation - elem.first);
if(dif < minDif)
{
minDif = dif;
el = elem.first;
}
}
elevation = el;
dif = 0;
minDif = 360;
for(auto elem : m_hrtfs[elevation])
{
dif = std::fabs(azimuth - elem.first);
if(dif < minDif)
{
minDif = dif;
az = elem.first;
R = elem.second;
}
}
azimuth = az;
float azL = 360 - azimuth;
if(azL == 360)
azL = 0;
auto iter = m_hrtfs[elevation].find(azL);
if(iter != m_hrtfs[elevation].end())
L = iter->second;
else
{
dif = 0;
minDif = 360;
for(auto elem : m_hrtfs[elevation])
{
dif = std::fabs(azL - elem.first);
if(dif < minDif)
{
minDif = dif;
L = elem.second;
}
}
}
return std::make_pair(L, R);
}
Specs HRTF::getSpecs()
{
return m_specs;
}
bool HRTF::isEmpty()
{
return m_empty;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,89 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/HRTFLoader.h"
#include "file/File.h"
#include "Exception.h"
#include <dirent.h>
#include <exception>
AUD_NAMESPACE_BEGIN
std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
loadHRTFs(hrtfs, 'L', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
loadHRTFs(hrtfs, 'R', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
loadHRTFs(hrtfs, 'L', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
loadHRTFs(hrtfs, 'R', fileExtension, path);
return hrtfs;
}
void HRTFLoader::loadHRTFs(std::shared_ptr<HRTF> hrtfs, char ear, const std::string& fileExtension, const std::string& path)
{
std::string readpath = path;
if(path == "")
readpath = ".";
DIR* dir = opendir(path.c_str());
if(!dir)
return;
float azim, elev;
while(dirent* entry = readdir(dir))
{
std::string filename = entry->d_name;
if(filename.front() == ear && filename.length() >= fileExtension.length() && filename.substr(filename.length() - fileExtension.length()) == fileExtension)
{
try
{
elev = std::stof(filename.substr(1, filename.find("e") - 1));
azim = std::stof(filename.substr(filename.find("e") + 1, filename.find("a") - filename.find("e") - 1));
if(ear == 'L')
azim = 360 - azim;
}
catch(...)
{
AUD_THROW(FileException, "The HRTF name doesn't follow the naming scheme: " + filename);
}
hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>(readpath + "/" + filename)), azim, elev);
}
}
closedir(dir);
return;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/HRTFLoader.h"
#include "file/File.h"
#include "Exception.h"
#include <windows.h>
#include <exception>
AUD_NAMESPACE_BEGIN
std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
loadHRTFs(hrtfs, 'L', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(std::shared_ptr<FFTPlan> plan, const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
loadHRTFs(hrtfs, 'R', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadLeftHRTFs(const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
loadHRTFs(hrtfs, 'L', fileExtension, path);
return hrtfs;
}
std::shared_ptr<HRTF> HRTFLoader::loadRightHRTFs(const std::string& fileExtension, const std::string& path)
{
std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>());
loadHRTFs(hrtfs, 'R', fileExtension, path);
return hrtfs;
}
void HRTFLoader::loadHRTFs(std::shared_ptr<HRTF> hrtfs, char ear, const std::string& fileExtension, const std::string& path)
{
std::string readpath = path;
if(path == "")
readpath = ".";
WIN32_FIND_DATA entry;
bool found_file = true;
std::string search = readpath + "\\*";
HANDLE dir = FindFirstFile(search.c_str(), &entry);
if(dir == INVALID_HANDLE_VALUE)
return;
float azim, elev;
while(found_file)
{
std::string filename = entry.cFileName;
if(filename.front() == ear && filename.length() >= fileExtension.length() && filename.substr(filename.length() - fileExtension.length()) == fileExtension)
{
try
{
elev = std::stof(filename.substr(1, filename.find("e") - 1));
azim = std::stof(filename.substr(filename.find("e") + 1, filename.find("a") - filename.find("e") - 1));
if(ear == 'L')
azim = 360 - azim;
}
catch(...)
{
AUD_THROW(FileException, "The HRTF name doesn't follow the naming scheme: " + filename);
}
hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>(readpath + "/" + filename)), azim, elev);
}
found_file = FindNextFile(dir, &entry);
}
FindClose(dir);
return;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Highpass.h"
#include "fx/IIRFilterReader.h"
#include "fx/HighpassCalculator.h"
AUD_NAMESPACE_BEGIN
Highpass::Highpass(std::shared_ptr<ISound> sound, float frequency, float Q) :
DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new HighpassCalculator(frequency, Q)))
{
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/HighpassCalculator.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
HighpassCalculator::HighpassCalculator(float frequency, float Q) :
m_frequency(frequency),
m_Q(Q)
{
}
void HighpassCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
{
float w0 = 2.0 * M_PI * (SampleRate)m_frequency / rate;
float alpha = (float)(std::sin(w0) / (2.0 * (double)m_Q));
float norm = 1 + alpha;
float c = std::cos(w0);
a.push_back(1);
a.push_back(-2 * c / norm);
a.push_back((1 - alpha) / norm);
b.push_back((1 + c) / (2 * norm));
b.push_back((-1 - c) / norm);
b.push_back(b[0]);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/IIRFilter.h"
#include "fx/IIRFilterReader.h"
AUD_NAMESPACE_BEGIN
IIRFilter::IIRFilter(std::shared_ptr<ISound> sound, const std::vector<float>& b, const std::vector<float>& a) :
Effect(sound), m_a(a), m_b(b)
{
}
std::shared_ptr<IReader> IIRFilter::createReader()
{
return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), m_b, m_a));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/IIRFilterReader.h"
AUD_NAMESPACE_BEGIN
IIRFilterReader::IIRFilterReader(std::shared_ptr<IReader> reader, const std::vector<float>& b, const std::vector<float>& a) :
BaseIIRFilterReader(reader, b.size(), a.size()), m_a(a), m_b(b)
{
if(m_a.empty() == false)
{
for(int i = 1; i < m_a.size(); i++)
m_a[i] /= m_a[0];
for(int i = 0; i < m_b.size(); i++)
m_b[i] /= m_a[0];
m_a[0] = 1;
}
}
sample_t IIRFilterReader::filter()
{
sample_t out = 0;
for(int i = 1; i < m_a.size(); i++)
out -= y(-i) * m_a[i];
for(int i = 0; i < m_b.size(); i++)
out += x(-i) * m_b[i];
return out;
}
void IIRFilterReader::setCoefficients(const std::vector<float>& b, const std::vector<float>& a)
{
setLengths(b.size(), a.size());
m_a = a;
m_b = b;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,97 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ImpulseResponse.h"
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
AUD_NAMESPACE_BEGIN
ImpulseResponse::ImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse) :
ImpulseResponse(impulseResponse, std::make_shared<FFTPlan>(0.0))
{
}
ImpulseResponse::ImpulseResponse(std::shared_ptr<StreamBuffer> impulseResponse, std::shared_ptr<FFTPlan> plan)
{
auto reader = impulseResponse->createReader();
m_length = reader->getLength();
processImpulseResponse(impulseResponse->createReader(), plan);
}
Specs ImpulseResponse::getSpecs()
{
return m_specs;
}
int ImpulseResponse::getLength()
{
return m_length;
}
std::shared_ptr<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>> ImpulseResponse::getChannel(int n)
{
return m_processedIR[n];
}
void ImpulseResponse::processImpulseResponse(std::shared_ptr<IReader> reader, std::shared_ptr<FFTPlan> plan)
{
m_specs.channels = reader->getSpecs().channels;
m_specs.rate = reader->getSpecs().rate;
int N = plan->getSize();
bool eos = false;
int length = reader->getLength();
sample_t* buffer = (sample_t*)std::malloc(length * m_specs.channels * sizeof(sample_t));
int numParts = std::ceil((float)length / (plan->getSize() / 2));
for(int i = 0; i < m_specs.channels; i++)
{
m_processedIR.push_back(std::make_shared<std::vector<std::shared_ptr<std::vector<std::complex<sample_t>>>>>());
for(int j = 0; j < numParts; j++)
(*m_processedIR[i]).push_back(std::make_shared<std::vector<std::complex<sample_t>>>((N / 2) + 1));
}
length += reader->getSpecs().rate;
reader->read(length, eos, buffer);
void* bufferFFT = plan->getBuffer();
for(int i = 0; i < m_specs.channels; i++)
{
int partStart = 0;
for(int h = 0; h < numParts; h++)
{
int k = 0;
int len = std::min(partStart + ((N / 2)*m_specs.channels), length*m_specs.channels);
std::memset(bufferFFT, 0, ((N / 2) + 1) * 2 * sizeof(fftwf_complex));
for(int j = partStart; j < len; j += m_specs.channels)
{
((float*)bufferFFT)[k] = buffer[j + i];
k++;
}
plan->FFT(bufferFFT);
for(int j = 0; j < (N / 2) + 1; j++)
{
(*(*m_processedIR[i])[h])[j] = reinterpret_cast<std::complex<sample_t>*>(bufferFFT)[j];
}
partStart += N / 2 * m_specs.channels;
}
}
plan->freeBuffer(bufferFFT);
std::free(buffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Limiter.h"
#include "fx/LimiterReader.h"
AUD_NAMESPACE_BEGIN
Limiter::Limiter(std::shared_ptr<ISound> sound,
double start, double end) :
Effect(sound),
m_start(start),
m_end(end)
{
}
double Limiter::getStart() const
{
return m_start;
}
double Limiter::getEnd() const
{
return m_end;
}
std::shared_ptr<IReader> Limiter::createReader()
{
return std::shared_ptr<IReader>(new LimiterReader(getReader(), m_start, m_end));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/LimiterReader.h"
#include "util/Buffer.h"
#include <algorithm>
AUD_NAMESPACE_BEGIN
LimiterReader::LimiterReader(std::shared_ptr<IReader> reader, double start, double end) :
EffectReader(reader),
m_start(start),
m_end(end)
{
if(m_start > 0)
{
Specs specs = m_reader->getSpecs();
Specs specs2;
if(m_reader->isSeekable())
m_reader->seek(m_start * specs.rate);
else
{
// skip first m_start samples by reading them
int length = AUD_DEFAULT_BUFFER_SIZE;
Buffer buffer(AUD_DEFAULT_BUFFER_SIZE * AUD_SAMPLE_SIZE(specs));
bool eos = false;
for(int len = m_start * specs.rate;
length > 0 && !eos;
len -= length)
{
if(len < AUD_DEFAULT_BUFFER_SIZE)
length = len;
m_reader->read(length, eos, buffer.getBuffer());
specs2 = m_reader->getSpecs();
if(specs2.rate != specs.rate)
{
len = len * specs2.rate / specs.rate;
specs.rate = specs2.rate;
}
if(specs2.channels != specs.channels)
{
specs = specs2;
buffer.assureSize(AUD_DEFAULT_BUFFER_SIZE * AUD_SAMPLE_SIZE(specs));
}
}
}
}
}
void LimiterReader::seek(int position)
{
m_reader->seek(position + m_start * m_reader->getSpecs().rate);
}
int LimiterReader::getLength() const
{
int len = m_reader->getLength();
SampleRate rate = m_reader->getSpecs().rate;
if(len < 0 || (len > m_end * rate && m_end >= 0))
len = m_end * rate;
return len - m_start * rate;
}
int LimiterReader::getPosition() const
{
int pos = m_reader->getPosition();
SampleRate rate = m_reader->getSpecs().rate;
return std::min(pos, int(m_end * rate)) - m_start * rate;
}
void LimiterReader::read(int& length, bool& eos, sample_t* buffer)
{
eos = false;
if(m_end >= 0)
{
int position = m_reader->getPosition();
SampleRate rate = m_reader->getSpecs().rate;
if(position + length > m_end * rate)
{
length = m_end * rate - position;
eos = true;
}
if(position < int(m_start * rate))
{
int len2 = length;
for(int len = int(m_start * rate) - position;
len2 == length && !eos;
len -= length)
{
if(len < length)
len2 = len;
m_reader->read(len2, eos, buffer);
position += len2;
}
if(position < m_start * rate)
{
length = 0;
return;
}
}
if(length < 0)
{
length = 0;
return;
}
}
if(eos)
{
m_reader->read(length, eos, buffer);
eos = true;
}
else
m_reader->read(length, eos, buffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Loop.h"
#include "fx/LoopReader.h"
AUD_NAMESPACE_BEGIN
Loop::Loop(std::shared_ptr<ISound> sound, int loop) :
Effect(sound),
m_loop(loop)
{
}
int Loop::getLoop() const
{
return m_loop;
}
std::shared_ptr<IReader> Loop::createReader()
{
return std::shared_ptr<IReader>(new LoopReader(getReader(), m_loop));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,91 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/LoopReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
LoopReader::LoopReader(std::shared_ptr<IReader> reader, int loop) :
EffectReader(reader), m_count(loop), m_left(loop)
{
}
void LoopReader::seek(int position)
{
int len = m_reader->getLength();
if(len < 0)
m_reader->seek(position);
else
{
if(m_count >= 0)
{
m_left = m_count - (position / len);
if(m_left < 0)
m_left = 0;
}
m_reader->seek(position % len);
}
}
int LoopReader::getLength() const
{
if(m_count < 0)
return -1;
return m_reader->getLength() * m_count;
}
int LoopReader::getPosition() const
{
return m_reader->getPosition() * (m_count < 0 ? 1 : m_count);
}
void LoopReader::read(int& length, bool& eos, sample_t* buffer)
{
const Specs specs = m_reader->getSpecs();
int len = length;
m_reader->read(length, eos, buffer);
if(length < len && eos && m_left)
{
int pos = length;
length = len;
while(pos < length && eos && m_left)
{
if(m_left > 0)
m_left--;
m_reader->seek(0);
len = length - pos;
m_reader->read(len, eos, buffer + pos * specs.channels);
// prevent endless loop
if(!len)
break;
pos += len;
}
length = pos;
}
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Lowpass.h"
#include "fx/LowpassCalculator.h"
AUD_NAMESPACE_BEGIN
Lowpass::Lowpass(std::shared_ptr<ISound> sound, float frequency, float Q) :
DynamicIIRFilter(sound, std::shared_ptr<IDynamicIIRFilterCalculator>(new LowpassCalculator(frequency, Q)))
{
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/LowpassCalculator.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
LowpassCalculator::LowpassCalculator(float frequency, float Q) :
m_frequency(frequency),
m_Q(Q)
{
}
void LowpassCalculator::recalculateCoefficients(SampleRate rate, std::vector<float> &b, std::vector<float> &a)
{
float w0 = 2 * M_PI * m_frequency / rate;
float alpha = std::sin(w0) / (2 * m_Q);
float norm = 1 + alpha;
float c = std::cos(w0);
a.push_back(1);
a.push_back(-2 * c / norm);
a.push_back((1 - alpha) / norm);
b.push_back((1 - c) / (2 * norm));
b.push_back((1 - c) / norm);
b.push_back(b[0]);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Modulator.h"
#include "fx/ModulatorReader.h"
AUD_NAMESPACE_BEGIN
Modulator::Modulator(std::shared_ptr<ISound> sound1, std::shared_ptr<ISound> sound2) :
m_sound1(sound1), m_sound2(sound2)
{
}
std::shared_ptr<IReader> Modulator::createReader()
{
std::shared_ptr<IReader> reader1 = m_sound1->createReader();
std::shared_ptr<IReader> reader2 = m_sound2->createReader();
return std::shared_ptr<IReader>(new ModulatorReader(reader1, reader2));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ModulatorReader.h"
#include "Exception.h"
#include <algorithm>
#include <cstring>
AUD_NAMESPACE_BEGIN
ModulatorReader::ModulatorReader(std::shared_ptr<IReader> reader1, std::shared_ptr<IReader> reader2) :
m_reader1(reader1), m_reader2(reader2)
{
}
ModulatorReader::~ModulatorReader()
{
}
bool ModulatorReader::isSeekable() const
{
return m_reader1->isSeekable() && m_reader2->isSeekable();
}
void ModulatorReader::seek(int position)
{
m_reader1->seek(position);
m_reader2->seek(position);
}
int ModulatorReader::getLength() const
{
int len1 = m_reader1->getLength();
int len2 = m_reader2->getLength();
if((len1 < 0) || (len2 < 0))
return -1;
return std::max(len1, len2);
}
int ModulatorReader::getPosition() const
{
int pos1 = m_reader1->getPosition();
int pos2 = m_reader2->getPosition();
return std::max(pos1, pos2);
}
Specs ModulatorReader::getSpecs() const
{
return m_reader1->getSpecs();
}
void ModulatorReader::read(int& length, bool& eos, sample_t* buffer)
{
Specs specs = m_reader1->getSpecs();
Specs s2 = m_reader2->getSpecs();
if(!AUD_COMPARE_SPECS(specs, s2))
AUD_THROW(StateException, "Two readers with different specifiactions cannot be modulated.");
int samplesize = AUD_SAMPLE_SIZE(specs);
m_buffer.assureSize(length * samplesize);
int len1 = length;
m_reader1->read(len1, eos, buffer);
if(len1 < length)
std::memset(buffer + len1 * specs.channels, 0, (length - len1) * samplesize);
int len2 = length;
bool eos2;
sample_t* buf = m_buffer.getBuffer();
m_reader2->read(len2, eos2, buf);
for(int i = 0; i < len2 * specs.channels; i++)
buffer[i] *= buf[i];
length = std::max(len1, len2);
eos &= eos2;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/MutableReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
MutableReader::MutableReader(std::shared_ptr<ISound> sound) :
m_sound(sound)
{
m_reader = m_sound->createReader();
}
bool MutableReader::isSeekable() const
{
return m_reader->isSeekable();
}
void MutableReader::seek(int position)
{
if(position < m_reader->getPosition())
{
m_reader = m_sound->createReader();
}
else
m_reader->seek(position);
}
int MutableReader::getLength() const
{
return m_reader->getLength();
}
int MutableReader::getPosition() const
{
return m_reader->getPosition();
}
Specs MutableReader::getSpecs() const
{
return m_reader->getSpecs();
}
void MutableReader::read(int& length, bool& eos, sample_t* buffer)
{
m_reader->read(length, eos, buffer);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/MutableSound.h"
#include "fx/MutableReader.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
MutableSound::MutableSound(std::shared_ptr<ISound> sound) :
m_sound(sound)
{
}
std::shared_ptr<IReader> MutableSound::createReader()
{
return std::make_shared<MutableReader>(m_sound);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Pitch.h"
#include "fx/PitchReader.h"
AUD_NAMESPACE_BEGIN
Pitch::Pitch(std::shared_ptr<ISound> sound, float pitch) :
Effect(sound),
m_pitch(pitch)
{
}
std::shared_ptr<IReader> Pitch::createReader()
{
return std::shared_ptr<IReader>(new PitchReader(getReader(), m_pitch));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/PitchReader.h"
AUD_NAMESPACE_BEGIN
PitchReader::PitchReader(std::shared_ptr<IReader> reader, float pitch) :
EffectReader(reader), m_pitch(pitch)
{
}
Specs PitchReader::getSpecs() const
{
Specs specs = m_reader->getSpecs();
specs.rate *= m_pitch;
return specs;
}
float PitchReader::getPitch() const
{
return m_pitch;
}
void PitchReader::setPitch(float pitch)
{
if(pitch > 0.0f)
m_pitch = pitch;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,144 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/PlaybackCategory.h"
#include "fx/VolumeSound.h"
AUD_NAMESPACE_BEGIN
struct HandleData {
unsigned int id;
PlaybackCategory* category;
};
PlaybackCategory::PlaybackCategory(std::shared_ptr<IDevice> device) :
m_currentID(0), m_device(device), m_status(STATUS_PLAYING), m_volumeStorage(std::make_shared<VolumeStorage>(1.0f))
{
}
PlaybackCategory::~PlaybackCategory()
{
stop();
}
std::shared_ptr<IHandle> PlaybackCategory::play(std::shared_ptr<ISound> sound)
{
std::shared_ptr<ISound> vs(std::make_shared<VolumeSound>(sound, m_volumeStorage));
m_device->lock();
auto handle = m_device->play(vs);
if(handle == nullptr)
return nullptr;
switch (m_status)
{
case STATUS_PAUSED:
handle->pause();
break;
default:
m_status = STATUS_PLAYING;
};
m_handles[m_currentID] = handle;
HandleData* data = new HandleData;
data->category = this;
data->id = m_currentID;
handle->setStopCallback(cleanHandleCallback, data);
m_device->unlock();
m_currentID++;
return handle;
}
void PlaybackCategory::resume()
{
m_device->lock();
for(auto i = m_handles.begin(); i != m_handles.end();)
{
if(i->second->getStatus() == STATUS_INVALID)
i = m_handles.erase(i);
else
{
i->second->resume();
i++;
}
}
m_device->unlock();
m_status = STATUS_PLAYING;
}
void PlaybackCategory::pause()
{
m_device->lock();
for(auto i = m_handles.begin(); i != m_handles.end();)
{
if(i->second->getStatus() == STATUS_INVALID)
i = m_handles.erase(i);
else
{
i->second->pause();
i++;
}
}
m_device->unlock();
m_status = STATUS_PAUSED;
}
float PlaybackCategory::getVolume()
{
return m_volumeStorage->getVolume();
}
void PlaybackCategory::setVolume(float volume)
{
m_volumeStorage->setVolume(volume);
}
void PlaybackCategory::stop()
{
m_device->lock();
for(auto i = m_handles.begin(); i != m_handles.end();)
{
i->second->stop();
if(i->second->getStatus() == STATUS_INVALID)
i = m_handles.erase(i);
else
i++;
}
m_device->unlock();
m_status = STATUS_STOPPED;
}
std::shared_ptr<VolumeStorage> PlaybackCategory::getSharedVolume()
{
return m_volumeStorage;
}
void PlaybackCategory::cleanHandles()
{
for(auto i = m_handles.begin(); i != m_handles.end();)
{
if(i->second->getStatus() == STATUS_INVALID)
i = m_handles.erase(i);
else
i++;
}
}
void PlaybackCategory::cleanHandleCallback(void* data)
{
auto dat = reinterpret_cast<HandleData*>(data);
dat->category->m_handles.erase(dat->id);
delete dat;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,186 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/PlaybackManager.h"
#include "fx/VolumeSound.h"
#include <stdexcept>
AUD_NAMESPACE_BEGIN
PlaybackManager::PlaybackManager(std::shared_ptr<IDevice> device) :
m_device(device), m_currentKey(0)
{
}
unsigned int PlaybackManager::addCategory(std::shared_ptr<PlaybackCategory> category)
{
bool flag = true;
unsigned int k = -1;
do {
auto iter = m_categories.find(m_currentKey);
if(iter == m_categories.end())
{
m_categories[m_currentKey] = category;
k = m_currentKey;
m_currentKey++;
flag = false;
}
else
m_currentKey++;
} while(flag);
return k;
}
unsigned int PlaybackManager::addCategory(float volume)
{
std::shared_ptr<PlaybackCategory> category = std::make_shared<PlaybackCategory>(m_device);
category->setVolume(volume);
bool flag = true;
unsigned int k = -1;
do {
auto iter = m_categories.find(m_currentKey);
if(iter == m_categories.end())
{
m_categories[m_currentKey] = category;
k = m_currentKey;
m_currentKey++;
flag = false;
}
else
m_currentKey++;
} while(flag);
return k;
}
std::shared_ptr<IHandle> PlaybackManager::play(std::shared_ptr<ISound> sound, unsigned int catKey)
{
auto iter = m_categories.find(catKey);
std::shared_ptr<PlaybackCategory> category;
if(iter != m_categories.end())
{
category = iter->second;
}
else
{
category = std::make_shared<PlaybackCategory>(m_device);
m_categories[catKey] = category;
}
return category->play(sound);
}
bool PlaybackManager::resume(unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
iter->second->resume();
return true;
}
else
{
return false;
}
}
bool PlaybackManager::pause(unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
iter->second->pause();
return true;
}
else
{
return false;
}
}
float PlaybackManager::getVolume(unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
return iter->second->getVolume();
}
else
{
return -1.0;
}
}
bool PlaybackManager::setVolume(float volume, unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
iter->second->setVolume(volume);
return true;
}
else
{
return false;
}
}
bool PlaybackManager::stop(unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
iter->second->stop();
return true;
}
else
{
return false;
}
}
void PlaybackManager::clean()
{
for(auto cat : m_categories)
cat.second->cleanHandles();
}
bool PlaybackManager::clean(unsigned int catKey)
{
auto iter = m_categories.find(catKey);
if(iter != m_categories.end())
{
iter->second->cleanHandles();
return true;
}
else
{
return false;
}
}
std::shared_ptr<IDevice> PlaybackManager::getDevice()
{
return m_device;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Reverse.h"
#include "fx/ReverseReader.h"
AUD_NAMESPACE_BEGIN
Reverse::Reverse(std::shared_ptr<ISound> sound) :
Effect(sound)
{
}
std::shared_ptr<IReader> Reverse::createReader()
{
return std::shared_ptr<IReader>(new ReverseReader(getReader()));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/ReverseReader.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
ReverseReader::ReverseReader(std::shared_ptr<IReader> reader) :
EffectReader(reader),
m_length(reader->getLength()),
m_position(0)
{
if(m_length < 0 || !reader->isSeekable())
AUD_THROW(StateException, "A reader has to be seekable and have finite length to be reversible.");
}
void ReverseReader::seek(int position)
{
m_position = position;
}
int ReverseReader::getLength() const
{
return m_length;
}
int ReverseReader::getPosition() const
{
return m_position;
}
void ReverseReader::read(int& length, bool& eos, sample_t* buffer)
{
// first correct the length
if(m_position + length > m_length)
length = m_length - m_position;
if(length <= 0)
{
length = 0;
eos = true;
return;
}
const Specs specs = getSpecs();
const int samplesize = AUD_SAMPLE_SIZE(specs);
sample_t temp[CHANNEL_MAX];
int len = length;
// read from reader
m_reader->seek(m_length - m_position - len);
m_reader->read(len, eos, buffer);
// set null if reader didn't give enough data
if(len < length)
std::memset(buffer, 0, (length - len) * samplesize);
// copy the samples reverted
for(int i = 0; i < length / 2; i++)
{
std::memcpy(temp, buffer + (len - 1 - i) * specs.channels, samplesize);
std::memcpy(buffer + (len - 1 - i) * specs.channels, buffer + i * specs.channels, samplesize);
std::memcpy(buffer + i * specs.channels, temp, samplesize);
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/SoundList.h"
#include "Exception.h"
#include <cstring>
#include <cstdlib>
#include <chrono>
AUD_NAMESPACE_BEGIN
SoundList::SoundList(bool random) :
m_random(random)
{
std::srand(time(NULL));
}
SoundList::SoundList(std::vector<std::shared_ptr<ISound>>& list, bool random) :
m_list(list), m_random(random)
{
std::srand(time(NULL));
}
std::shared_ptr<IReader> SoundList::createReader()
{
if(m_list.size() > 0)
{
m_mutex.lock();
if(!m_random){
m_index++;
if(m_index >= m_list.size())
m_index = 0;
}
else
{
int temp;
do{
temp = std::rand() % m_list.size();
} while(temp == m_index && m_list.size()>1);
m_index = temp;
}
auto reader = m_list[m_index]->createReader();
m_mutex.unlock();
return reader;
}
else
AUD_THROW(FileException, "The sound list is empty");
}
void SoundList::addSound(std::shared_ptr<ISound> sound)
{
m_list.push_back(sound);
}
void SoundList::setRandomMode(bool random)
{
m_random = random;
}
bool SoundList::getRandomMode()
{
return m_random;
}
int SoundList::getSize()
{
return m_list.size();
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Source.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
Source::Source(float azimuth, float elevation, float distance) :
m_elevation(elevation), m_distance(distance)
{
azimuth = std::fmod(azimuth, 360);
if(azimuth < 0)
azimuth += 360;
m_azimuth = azimuth;
}
float Source::getAzimuth()
{
return m_azimuth;
}
float Source::getElevation()
{
return m_elevation;
}
float Source::getDistance()
{
return m_distance;
}
float Source::getVolume()
{
float volume = 1.0f - m_distance;
if(volume < 0.0f)
volume = 0.0f;
return volume;
}
void Source::setAzimuth(float azimuth)
{
azimuth = std::fmod(azimuth, 360);
if(azimuth < 0)
azimuth += 360;
m_azimuth = azimuth;
}
void Source::setElevation(float elevation)
{
m_elevation = elevation;
}
void Source::setDistance(float distance)
{
m_distance = distance;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Sum.h"
#include "fx/IIRFilterReader.h"
AUD_NAMESPACE_BEGIN
Sum::Sum(std::shared_ptr<ISound> sound) :
Effect(sound)
{
}
std::shared_ptr<IReader> Sum::createReader()
{
std::vector<float> a, b;
a.push_back(1);
a.push_back(-1);
b.push_back(1);
return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), b, a));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Threshold.h"
#include "fx/CallbackIIRFilterReader.h"
AUD_NAMESPACE_BEGIN
sample_t Threshold::thresholdFilter(CallbackIIRFilterReader* reader, float* threshold)
{
float in = reader->x(0);
if(in >= *threshold)
return 1;
else if(in <= -*threshold)
return -1;
else
return 0;
}
void Threshold::endThresholdFilter(float* threshold)
{
delete threshold;
}
Threshold::Threshold(std::shared_ptr<ISound> sound, float threshold) :
Effect(sound),
m_threshold(threshold)
{
}
float Threshold::getThreshold() const
{
return m_threshold;
}
std::shared_ptr<IReader> Threshold::createReader()
{
return std::shared_ptr<IReader>(new CallbackIIRFilterReader(getReader(), 1, 0, doFilterIIR(thresholdFilter), endFilterIIR(endThresholdFilter), new float(m_threshold)));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/TimeStretchPitchScale.h"
#include "fx/TimeStretchPitchScaleReader.h"
AUD_NAMESPACE_BEGIN
TimeStretchPitchScale::TimeStretchPitchScale(std::shared_ptr<ISound> sound, double timeRatio, double pitchScale, StretcherQuality quality, bool preserveFormant) :
Effect(sound), m_timeRatio(timeRatio), m_pitchScale(pitchScale), m_quality(quality), m_preserveFormant(preserveFormant)
{
}
std::shared_ptr<IReader> TimeStretchPitchScale::createReader()
{
return std::shared_ptr<IReader>(new TimeStretchPitchScaleReader(getReader(), m_timeRatio, m_pitchScale, m_quality, m_preserveFormant));
}
double TimeStretchPitchScale::getTimeRatio() const
{
return m_timeRatio;
}
double TimeStretchPitchScale::getPitchScale() const
{
return m_pitchScale;
}
bool TimeStretchPitchScale::getPreserveFormant() const
{
return m_preserveFormant;
}
StretcherQuality TimeStretchPitchScale::getStretcherQuality() const
{
return m_quality;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,205 @@
/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/TimeStretchPitchScaleReader.h"
#include <cstring>
#include "Exception.h"
#include "IReader.h"
#include "util/Buffer.h"
using namespace RubberBand;
AUD_NAMESPACE_BEGIN
void TimeStretchPitchScaleReader::reset()
{
auto startPad{m_stretcher->getPreferredStartPad()};
m_samplesToDrop = m_stretcher->getStartDelay();
m_deinterleaved[0].assureSize(startPad * sizeof(sample_t));
std::memset(m_deinterleaved[0].getBuffer(), 0, startPad * sizeof(sample_t));
for(auto& channel : m_channelData)
channel = m_deinterleaved[0].getBuffer();
m_stretcher->process(m_channelData.data(), startPad, m_finishedReader);
}
TimeStretchPitchScaleReader::TimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, double timeRatio, double pitchScale, StretcherQuality quality, bool preserveFormant) :
EffectReader(reader), m_position(0), m_finishedReader(false), m_deinterleaved(reader->getSpecs().channels), m_channelData(reader->getSpecs().channels)
{
if (pitchScale < 1.0 / 256.0 || pitchScale > 256.0)
AUD_THROW(StateException, "The pitch scale must be between 1/256 and 256");
if (timeRatio < 1.0 / 256.0 || timeRatio > 256.0)
AUD_THROW(StateException, "The time-stretch ratio must be between 1/256 and 256");
RubberBandStretcher::Options options = RubberBandStretcher::OptionProcessRealTime | RubberBandStretcher::OptionEngineFiner | RubberBandStretcher::OptionChannelsTogether;
switch(quality)
{
case StretcherQuality::HIGH:
options |= RubberBandStretcher::OptionPitchHighQuality;
break;
case StretcherQuality::FAST:
options |= RubberBandStretcher::OptionPitchHighSpeed;
options |= RubberBandStretcher::OptionWindowShort;
break;
case StretcherQuality::CONSISTENT:
options |= RubberBandStretcher::OptionPitchHighConsistency;
break;
default:
break;
}
options |= preserveFormant ? RubberBandStretcher::OptionFormantPreserved : RubberBandStretcher::OptionFormantShifted;
m_stretcher = std::make_unique<RubberBandStretcher>(m_reader->getSpecs().rate, m_reader->getSpecs().channels, options, timeRatio, pitchScale);
reset();
}
void TimeStretchPitchScaleReader::read(int& length, bool& eos, sample_t* buffer)
{
if(length == 0)
return;
int samplesize = AUD_SAMPLE_SIZE(m_reader->getSpecs());
int channels = m_reader->getSpecs().channels;
int samplesRead = 0;
eos = false;
while(samplesRead < length)
{
int len = m_stretcher->getSamplesRequired();
if(!m_finishedReader && len != 0)
{
m_buffer.assureSize(len * samplesize);
sample_t* buf = m_buffer.getBuffer();
m_reader->read(len, m_finishedReader, buf);
// Deinterleave the input reader buffer for processing
for(int channel = 0; channel < channels; channel++)
{
m_deinterleaved[channel].assureSize(len * sizeof(sample_t));
sample_t* channelBuf = m_deinterleaved[channel].getBuffer();
for(int i = 0; i < len; i++)
{
channelBuf[i] = buf[i * channels + channel];
}
m_channelData[channel] = channelBuf;
}
m_stretcher->process(m_channelData.data(), len, m_finishedReader);
}
int available = m_stretcher->available();
if(available == -1)
{
eos = true;
break;
}
if(available == 0)
continue;
available = std::min(m_samplesToDrop ? m_samplesToDrop : length - samplesRead, available);
for(int channel = 0; channel < channels; channel++)
{
m_deinterleaved[channel].assureSize(available * sizeof(sample_t));
m_channelData[channel] = m_deinterleaved[channel].getBuffer();
}
m_stretcher->retrieve(m_channelData.data(), available);
if(m_samplesToDrop)
{
m_samplesToDrop -= available;
}
else
{
// Interleave the retrieved data into the buffer
for(int channel = 0; channel < channels; channel++)
{
sample_t* outputBuf = m_deinterleaved[channel].getBuffer();
for(int i = 0; i < available; i++)
{
buffer[(samplesRead + i) * channels + channel] = outputBuf[i];
}
}
samplesRead += available;
}
}
length = samplesRead;
m_position += length;
eos = m_stretcher->available() == -1;
}
double TimeStretchPitchScaleReader::getTimeRatio() const
{
return m_stretcher->getTimeRatio();
}
void TimeStretchPitchScaleReader::setTimeRatio(double timeRatio)
{
if(timeRatio >= 1.0 / 256.0 && timeRatio <= 256.0)
{
m_stretcher->setTimeRatio(timeRatio);
}
}
double TimeStretchPitchScaleReader::getPitchScale() const
{
return m_stretcher->getPitchScale();
}
void TimeStretchPitchScaleReader::setPitchScale(double pitchScale)
{
if(pitchScale >= 1.0 / 256.0 && pitchScale <= 256.0)
{
m_stretcher->setPitchScale(pitchScale);
}
}
void TimeStretchPitchScaleReader::seek(int position)
{
m_reader->seek(int(position / getTimeRatio()));
m_finishedReader = false;
m_stretcher->reset();
reset();
m_position = position;
}
int TimeStretchPitchScaleReader::getLength() const
{
return m_reader->getLength() * getTimeRatio();
}
int TimeStretchPitchScaleReader::getPosition() const
{
return m_position;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/Volume.h"
#include "fx/IIRFilterReader.h"
AUD_NAMESPACE_BEGIN
Volume::Volume(std::shared_ptr<ISound> sound, float volume) :
Effect(sound),
m_volume(volume)
{
}
float Volume::getVolume() const
{
return m_volume;
}
std::shared_ptr<IReader> Volume::createReader()
{
std::vector<float> a, b;
a.push_back(1);
b.push_back(m_volume);
return std::shared_ptr<IReader>(new IIRFilterReader(getReader(), b, a));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/VolumeReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
VolumeReader::VolumeReader(std::shared_ptr<IReader> reader, std::shared_ptr<VolumeStorage> volumeStorage) :
m_reader(reader), m_volumeStorage(volumeStorage)
{
}
bool VolumeReader::isSeekable() const
{
return m_reader->isSeekable();
}
void VolumeReader::seek(int position)
{
m_reader->seek(position);
}
int VolumeReader::getLength() const
{
return m_reader->getLength();
}
int VolumeReader::getPosition() const
{
return m_reader->getPosition();
}
Specs VolumeReader::getSpecs() const
{
return m_reader->getSpecs();
}
void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
{
m_reader->read(length, eos, buffer);
for(int i = 0; i < length * m_reader->getSpecs().channels; i++)
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/VolumeSound.h"
#include "fx/VolumeReader.h"
#include "Exception.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
VolumeSound::VolumeSound(std::shared_ptr<ISound> sound, std::shared_ptr<VolumeStorage> volumeStorage) :
m_sound(sound), m_volumeStorage(volumeStorage)
{
}
std::shared_ptr<IReader> VolumeSound::createReader()
{
return std::make_shared<VolumeReader>(m_sound->createReader(), m_volumeStorage);
}
std::shared_ptr<VolumeStorage> VolumeSound::getSharedVolume()
{
return m_volumeStorage;
}
void VolumeSound::setSharedVolume(std::shared_ptr<VolumeStorage> volumeStorage)
{
m_volumeStorage = volumeStorage;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright 2015-2016 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/VolumeStorage.h"
AUD_NAMESPACE_BEGIN
VolumeStorage::VolumeStorage() :
m_volume(1.0f)
{
}
VolumeStorage::VolumeStorage(float volume) :
m_volume(volume)
{
}
float VolumeStorage::getVolume()
{
return m_volume;
}
void VolumeStorage::setVolume(float volume)
{
m_volume = volume;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/Sawtooth.h"
#include "generator/SawtoothReader.h"
AUD_NAMESPACE_BEGIN
Sawtooth::Sawtooth(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_sampleRate(sampleRate)
{
}
float Sawtooth::getFrequency() const
{
return m_frequency;
}
std::shared_ptr<IReader> Sawtooth::createReader()
{
return std::shared_ptr<IReader>(new SawtoothReader(m_frequency, m_sampleRate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/SawtoothReader.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
SawtoothReader::SawtoothReader(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_position(0),
m_sample(0),
m_sampleRate(sampleRate)
{
}
void SawtoothReader::setFrequency(float frequency)
{
m_frequency = frequency;
}
bool SawtoothReader::isSeekable() const
{
return true;
}
void SawtoothReader::seek(int position)
{
m_position = position;
m_sample = std::fmod(m_position * m_frequency / (float)m_sampleRate + 1.0f, 2.0f) - 1.0f;
}
int SawtoothReader::getLength() const
{
return -1;
}
int SawtoothReader::getPosition() const
{
return m_position;
}
Specs SawtoothReader::getSpecs() const
{
Specs specs;
specs.rate = m_sampleRate;
specs.channels = CHANNELS_MONO;
return specs;
}
void SawtoothReader::read(int& length, bool& eos, sample_t* buffer)
{
float k = 2.0 * m_frequency / m_sampleRate;
for(int i = 0; i < length; i++)
{
m_sample += k;
if(m_sample >= 1.0f)
m_sample -= std::floor(m_sample) + 1.0f;
buffer[i] = m_sample;
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/Silence.h"
#include "generator/SilenceReader.h"
AUD_NAMESPACE_BEGIN
Silence::Silence(SampleRate sampleRate) :
m_sampleRate(sampleRate)
{
}
std::shared_ptr<IReader> Silence::createReader()
{
return std::shared_ptr<IReader>(new SilenceReader(m_sampleRate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/SilenceReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
SilenceReader::SilenceReader(SampleRate sampleRate) :
m_position(0),
m_sampleRate(sampleRate)
{
}
bool SilenceReader::isSeekable() const
{
return true;
}
void SilenceReader::seek(int position)
{
m_position = position;
}
int SilenceReader::getLength() const
{
return -1;
}
int SilenceReader::getPosition() const
{
return m_position;
}
Specs SilenceReader::getSpecs() const
{
Specs specs;
specs.rate = m_sampleRate;
specs.channels = CHANNELS_MONO;
return specs;
}
void SilenceReader::read(int& length, bool& eos, sample_t* buffer)
{
std::memset(buffer, 0, length * sizeof(sample_t));
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/Sine.h"
#include "generator/SineReader.h"
AUD_NAMESPACE_BEGIN
Sine::Sine(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_sampleRate(sampleRate)
{
}
float Sine::getFrequency() const
{
return m_frequency;
}
std::shared_ptr<IReader> Sine::createReader()
{
return std::shared_ptr<IReader>(new SineReader(m_frequency, m_sampleRate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,75 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/SineReader.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
SineReader::SineReader(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_position(0),
m_sampleRate(sampleRate)
{
}
void SineReader::setFrequency(float frequency)
{
m_frequency = frequency;
}
bool SineReader::isSeekable() const
{
return true;
}
void SineReader::seek(int position)
{
m_position = position;
}
int SineReader::getLength() const
{
return -1;
}
int SineReader::getPosition() const
{
return m_position;
}
Specs SineReader::getSpecs() const
{
Specs specs;
specs.rate = m_sampleRate;
specs.channels = CHANNELS_MONO;
return specs;
}
void SineReader::read(int& length, bool& eos, sample_t* buffer)
{
// fill with sine data
for(int i = 0; i < length; i++)
{
buffer[i] = std::sin((m_position + i) * 2 * M_PI * m_frequency / m_sampleRate);
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/Square.h"
#include "generator/SquareReader.h"
AUD_NAMESPACE_BEGIN
Square::Square(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_sampleRate(sampleRate)
{
}
float Square::getFrequency() const
{
return m_frequency;
}
std::shared_ptr<IReader> Square::createReader()
{
return std::shared_ptr<IReader>(new SquareReader(m_frequency, m_sampleRate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/SquareReader.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
SquareReader::SquareReader(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_position(0),
m_sample(0),
m_sampleRate(sampleRate)
{
}
void SquareReader::setFrequency(float frequency)
{
m_frequency = frequency;
}
bool SquareReader::isSeekable() const
{
return true;
}
void SquareReader::seek(int position)
{
m_position = position;
m_sample = std::fmod(m_position * m_frequency / (float)m_sampleRate, 2.0f);
}
int SquareReader::getLength() const
{
return -1;
}
int SquareReader::getPosition() const
{
return m_position;
}
Specs SquareReader::getSpecs() const
{
Specs specs;
specs.rate = m_sampleRate;
specs.channels = CHANNELS_MONO;
return specs;
}
void SquareReader::read(int& length, bool& eos, sample_t* buffer)
{
float k = 2.0 * m_frequency / m_sampleRate;
for(int i = 0; i < length; i++)
{
m_sample += k;
if(m_sample >= 2.0f)
m_sample = std::fmod(m_sample, 2.0f);
buffer[i] = (m_sample < 1.0f) * 2.0f - 1.0f;
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/Triangle.h"
#include "generator/TriangleReader.h"
AUD_NAMESPACE_BEGIN
Triangle::Triangle(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_sampleRate(sampleRate)
{
}
float Triangle::getFrequency() const
{
return m_frequency;
}
std::shared_ptr<IReader> Triangle::createReader()
{
return std::shared_ptr<IReader>(new TriangleReader(m_frequency, m_sampleRate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "generator/TriangleReader.h"
#include <cmath>
AUD_NAMESPACE_BEGIN
TriangleReader::TriangleReader(float frequency, SampleRate sampleRate) :
m_frequency(frequency),
m_position(0),
m_sample(0.5f),
m_sampleRate(sampleRate)
{
}
void TriangleReader::setFrequency(float frequency)
{
m_frequency = frequency;
}
bool TriangleReader::isSeekable() const
{
return true;
}
void TriangleReader::seek(int position)
{
m_position = position;
m_sample = std::fmod(m_position * m_frequency / (float)m_sampleRate + 1.5f, 2.0f) - 1.0f;
}
int TriangleReader::getLength() const
{
return -1;
}
int TriangleReader::getPosition() const
{
return m_position;
}
Specs TriangleReader::getSpecs() const
{
Specs specs;
specs.rate = m_sampleRate;
specs.channels = CHANNELS_MONO;
return specs;
}
void TriangleReader::read(int& length, bool& eos, sample_t* buffer)
{
float k = 2.0 * m_frequency / m_sampleRate;
for(int i = 0; i < length; i++)
{
m_sample += k;
if(m_sample >= 1.0f)
m_sample -= std::floor(m_sample) + 1.0f;
buffer[i] = std::fabs(m_sample) * 2.0f - 1.0f;
}
m_position += length;
eos = false;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "plugin/PluginManager.h"
#include <dlfcn.h>
#include <dirent.h>
AUD_NAMESPACE_BEGIN
std::unordered_map<std::string, void*> PluginManager::m_plugins;
void* PluginManager::openLibrary(const std::string& path)
{
return dlopen(path.c_str(), RTLD_LAZY);
}
void *PluginManager::lookupLibrary(void *handle, const std::string &name)
{
return dlsym(handle, name.c_str());
}
void PluginManager::closeLibrary(void *handle)
{
dlclose(handle);
}
bool PluginManager::loadPlugin(const std::string& path)
{
void* handle = openLibrary(path);
if (!handle)
return false;
void (*registerPlugin)() = (void (*)())lookupLibrary(handle, "registerPlugin");
const char* (*getName)() = (const char* (*)())lookupLibrary(handle, "getName");
if(!registerPlugin || !getName)
{
closeLibrary(handle);
return false;
}
registerPlugin();
m_plugins[getName()] = handle;
return true;
}
#define STATIC_PLUGIN_CLASS(name) class name { public: static void registerPlugin(); };
#define STATIC_PLUGIN_REGISTER(name) name::registerPlugin();
@STATIC_PLUGIN_CLASSES@
void PluginManager::loadPlugins(const std::string& path)
{
@STATIC_PLUGIN_REGISTERS@
std::string readpath = path;
if(path == "")
readpath = "@DEFAULT_PLUGIN_PATH@";
DIR* dir = opendir(readpath.c_str());
if(!dir)
return;
while(dirent* entry = readdir(dir))
{
const std::string filename = entry->d_name;
#ifdef __APPLE__
const std::string end = ".dylib";
#else
const std::string end = ".so";
#endif
if(filename.length() >= end.length() && filename.substr(filename.length() - end.length()) == end)
{
if(!loadPlugin(readpath + "/" + filename + ".@AUDASPACE_VERSION@"))
loadPlugin(readpath + "/" + filename);
}
}
closedir(dir);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,101 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "plugin/PluginManager.h"
#include <windows.h>
AUD_NAMESPACE_BEGIN
std::unordered_map<std::string, void*> PluginManager::m_plugins;
void* PluginManager::openLibrary(const std::string& path)
{
return reinterpret_cast<void*>(LoadLibrary(path.c_str()));
}
void* PluginManager::lookupLibrary(void *handle, const std::string &name)
{
return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle), name.c_str()));
}
void PluginManager::closeLibrary(void *handle)
{
FreeLibrary(reinterpret_cast<HMODULE>(handle));
}
bool PluginManager::loadPlugin(const std::string& path)
{
void* handle = openLibrary(path);
if (!handle)
return false;
void (*registerPlugin)() = (void (*)())lookupLibrary(handle, "registerPlugin");
const char* (*getName)() = (const char* (*)())lookupLibrary(handle, "getName");
if(!registerPlugin || !getName)
{
closeLibrary(handle);
return false;
}
registerPlugin();
m_plugins[getName()] = handle;
return true;
}
#define STATIC_PLUGIN_CLASS(name) class name { public: static void registerPlugin(); };
#define STATIC_PLUGIN_REGISTER(name) name::registerPlugin();
@STATIC_PLUGIN_CLASSES@
void PluginManager::loadPlugins(const std::string& path)
{
@STATIC_PLUGIN_REGISTERS@
std::string readpath = path;
if(path == "")
readpath = "@DEFAULT_PLUGIN_PATH@";
WIN32_FIND_DATA entry;
bool found_file = true;
std::string search = readpath + "\\*";
HANDLE dir = FindFirstFile(search.c_str(), &entry);
if(dir == INVALID_HANDLE_VALUE)
return;
while(found_file)
{
const std::string filename = entry.cFileName;
const std::string end = ".dll";
if(filename.length() >= end.length() && filename.substr(filename.length() - end.length()) == end)
{
loadPlugin(readpath + "/" + filename);
}
found_file = FindNextFile(dir, &entry);
}
FindClose(dir);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/ChannelMapper.h"
#include "respec/ChannelMapperReader.h"
#include <cstring>
AUD_NAMESPACE_BEGIN
ChannelMapper::ChannelMapper(std::shared_ptr<ISound> sound, DeviceSpecs specs) :
SpecsChanger(sound, specs)
{
}
std::shared_ptr<IReader> ChannelMapper::createReader()
{
std::shared_ptr<IReader> reader = getReader();
return std::shared_ptr<IReader>(new ChannelMapperReader(reader, m_specs.channels));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,388 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/ChannelMapperReader.h"
#include <algorithm>
#include <cmath>
#include <limits>
AUD_NAMESPACE_BEGIN
ChannelMapperReader::ChannelMapperReader(std::shared_ptr<IReader> reader,
Channels channels) :
EffectReader(reader), m_target_channels(channels),
m_source_channels(CHANNELS_INVALID), m_mapping(nullptr), m_map_size(0), m_mono_angle(0)
{
}
ChannelMapperReader::~ChannelMapperReader()
{
delete[] m_mapping;
}
Channels ChannelMapperReader::getSourceChannels() const
{
return m_reader->getSpecs().channels;
}
Channels ChannelMapperReader::getChannels() const
{
return m_target_channels;
}
void ChannelMapperReader::setChannels(Channels channels)
{
m_target_channels = channels;
calculateMapping();
}
float ChannelMapperReader::getMapping(int source, int target)
{
Channels source_channels = m_reader->getSpecs().channels;
if(source_channels != m_source_channels)
{
m_source_channels = source_channels;
calculateMapping();
}
if(source < 0 || source >= source_channels || target < 0 || target >= m_target_channels)
return std::numeric_limits<float>::quiet_NaN();
return m_mapping[target * source_channels + source];
}
void ChannelMapperReader::setMonoAngle(float angle)
{
if(angle != angle)
angle = 0;
m_mono_angle = angle;
if(m_source_channels == CHANNELS_MONO)
calculateMapping();
}
float ChannelMapperReader::angleDistance(float alpha, float beta)
{
alpha = beta - alpha;
if(alpha > M_PI)
alpha -= 2 * M_PI;
if(alpha < -M_PI)
alpha += 2 * M_PI;
return alpha;
}
void ChannelMapperReader::calculateMapping()
{
if(m_map_size < m_source_channels * m_target_channels)
{
delete[] m_mapping;
m_mapping = new float[m_source_channels * m_target_channels];
m_map_size = m_source_channels * m_target_channels;
}
for(int i = 0; i < m_source_channels * m_target_channels; i++)
m_mapping[i] = 0;
const Channels source_channel_count = std::min(m_source_channels, CHANNELS_SURROUND71);
const Channels target_channel_count = std::min(m_target_channels, CHANNELS_SURROUND71);
const Channel* source_channels = CHANNEL_MAPS[source_channel_count - 1];
const Channel* target_channels = CHANNEL_MAPS[target_channel_count - 1];
int lfe = -1;
for(int i = 0; i < target_channel_count; i++)
{
if(target_channels[i] == CHANNEL_LFE)
{
lfe = i;
break;
}
}
const float* source_angles = CHANNEL_ANGLES[source_channel_count - 1];
const float* target_angles = CHANNEL_ANGLES[target_channel_count - 1];
if(source_channel_count == CHANNELS_MONO)
source_angles = &m_mono_angle;
int channel_left, channel_right;
float angle_left, angle_right, angle;
for(int i = 0; i < source_channel_count; i++)
{
if(source_channels[i] == CHANNEL_LFE)
{
if(lfe != -1)
m_mapping[lfe * m_source_channels + i] = 1;
continue;
}
channel_left = channel_right = -1;
angle_left = -2 * M_PI;
angle_right = 2 * M_PI;
for(int j = 0; j < target_channel_count; j++)
{
if(j == lfe)
continue;
angle = angleDistance(source_angles[i], target_angles[j]);
if(angle < 0)
{
if(angle > angle_left)
{
angle_left = angle;
channel_left = j;
}
}
else
{
if(angle < angle_right)
{
angle_right = angle;
channel_right = j;
}
}
}
angle = angle_right - angle_left;
if(channel_right == -1 || angle == 0)
{
m_mapping[channel_left * m_source_channels + i] = 1;
}
else if(channel_left == -1)
{
m_mapping[channel_right * m_source_channels + i] = 1;
}
else
{
m_mapping[channel_left * m_source_channels + i] = std::cos(M_PI_2 * angle_left / angle);
m_mapping[channel_right * m_source_channels + i] = std::cos(M_PI_2 * angle_right / angle);
}
}
}
Specs ChannelMapperReader::getSpecs() const
{
Specs specs = m_reader->getSpecs();
specs.channels = m_target_channels;
return specs;
}
void ChannelMapperReader::read(int& length, bool& eos, sample_t* buffer)
{
Channels channels = m_reader->getSpecs().channels;
if(channels != m_source_channels)
{
m_source_channels = channels;
calculateMapping();
}
if(m_source_channels == m_target_channels)
{
m_reader->read(length, eos, buffer);
return;
}
m_buffer.assureSize(length * channels * sizeof(sample_t));
sample_t* in = m_buffer.getBuffer();
m_reader->read(length, eos, in);
sample_t sum;
for(int i = 0; i < length; i++)
{
for(int j = 0; j < m_target_channels; j++)
{
sum = 0;
for(int k = 0; k < m_source_channels; k++)
sum += m_mapping[j * m_source_channels + k] * in[i * m_source_channels + k];
buffer[i * m_target_channels + j] = sum;
}
}
}
const Channel ChannelMapperReader::MONO_MAP[] =
{
CHANNEL_FRONT_CENTER
};
const Channel ChannelMapperReader::STEREO_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT
};
const Channel ChannelMapperReader::STEREO_LFE_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_LFE
};
const Channel ChannelMapperReader::SURROUND4_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_REAR_LEFT,
CHANNEL_REAR_RIGHT
};
const Channel ChannelMapperReader::SURROUND5_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER,
CHANNEL_REAR_LEFT,
CHANNEL_REAR_RIGHT
};
const Channel ChannelMapperReader::SURROUND51_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER,
CHANNEL_LFE,
CHANNEL_REAR_LEFT,
CHANNEL_REAR_RIGHT
};
const Channel ChannelMapperReader::SURROUND61_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER,
CHANNEL_LFE,
CHANNEL_REAR_CENTER,
CHANNEL_REAR_LEFT,
CHANNEL_REAR_RIGHT
};
const Channel ChannelMapperReader::SURROUND71_MAP[] =
{
CHANNEL_FRONT_LEFT,
CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER,
CHANNEL_LFE,
CHANNEL_REAR_LEFT,
CHANNEL_REAR_RIGHT,
CHANNEL_SIDE_LEFT,
CHANNEL_SIDE_RIGHT
};
const Channel* ChannelMapperReader::CHANNEL_MAPS[] =
{
ChannelMapperReader::MONO_MAP,
ChannelMapperReader::STEREO_MAP,
ChannelMapperReader::STEREO_LFE_MAP,
ChannelMapperReader::SURROUND4_MAP,
ChannelMapperReader::SURROUND5_MAP,
ChannelMapperReader::SURROUND51_MAP,
ChannelMapperReader::SURROUND61_MAP,
ChannelMapperReader::SURROUND71_MAP
};
constexpr float deg2rad(double angle)
{
return float(angle * M_PI / 180.0);
}
const float ChannelMapperReader::MONO_ANGLES[] =
{
deg2rad(0.0)
};
const float ChannelMapperReader::STEREO_ANGLES[] =
{
deg2rad(-90.0),
deg2rad( 90.0)
};
const float ChannelMapperReader::STEREO_LFE_ANGLES[] =
{
deg2rad(-90.0),
deg2rad( 90.0),
deg2rad( 0.0)
};
const float ChannelMapperReader::SURROUND4_ANGLES[] =
{
deg2rad( -45.0),
deg2rad( 45.0),
deg2rad(-135.0),
deg2rad( 135.0)
};
const float ChannelMapperReader::SURROUND5_ANGLES[] =
{
deg2rad( -30.0),
deg2rad( 30.0),
deg2rad( 0.0),
deg2rad(-110.0),
deg2rad( 110.0)
};
const float ChannelMapperReader::SURROUND51_ANGLES[] =
{
deg2rad( -30.0),
deg2rad( 30.0),
deg2rad( 0.0),
deg2rad( 0.0),
deg2rad(-110.0),
deg2rad( 110.0)
};
const float ChannelMapperReader::SURROUND61_ANGLES[] =
{
deg2rad( -30.0),
deg2rad( 30.0),
deg2rad( 0.0),
deg2rad( 0.0),
deg2rad( 180.0),
deg2rad(-110.0),
deg2rad( 110.0)
};
const float ChannelMapperReader::SURROUND71_ANGLES[] =
{
deg2rad( -30.0),
deg2rad( 30.0),
deg2rad( 0.0),
deg2rad( 0.0),
deg2rad(-110.0),
deg2rad( 110.0),
deg2rad(-150.0),
deg2rad( 150.0)
};
const float* ChannelMapperReader::CHANNEL_ANGLES[] =
{
ChannelMapperReader::MONO_ANGLES,
ChannelMapperReader::STEREO_ANGLES,
ChannelMapperReader::STEREO_LFE_ANGLES,
ChannelMapperReader::SURROUND4_ANGLES,
ChannelMapperReader::SURROUND5_ANGLES,
ChannelMapperReader::SURROUND51_ANGLES,
ChannelMapperReader::SURROUND61_ANGLES,
ChannelMapperReader::SURROUND71_ANGLES
};
AUD_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/Converter.h"
#include "respec/ConverterReader.h"
AUD_NAMESPACE_BEGIN
Converter::Converter(std::shared_ptr<ISound> sound,
DeviceSpecs specs) :
SpecsChanger(sound, specs)
{
}
std::shared_ptr<IReader> Converter::createReader()
{
std::shared_ptr<IReader> reader = getReader();
if(m_specs.format != FORMAT_FLOAT32)
reader = std::shared_ptr<IReader>(new ConverterReader(reader, m_specs));
return reader;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,464 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/ConverterFunctions.h"
#include <stdint.h>
#define U8_0 0x80
#define S16_MAX ((int16_t)0x7FFF)
#define S16_MIN ((int16_t)0x8000)
#define S16_FLT 32767.0f
#define S32_MAX ((int32_t)0x7FFFFFFF)
#define S32_MIN ((int32_t)0x80000000)
#define S32_FLT 2147483647.0f
#define FLT_MAX 1.0f
#define FLT_MIN -1.0f
AUD_NAMESPACE_BEGIN
void convert_u8_s16(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = (((int16_t)source[i]) - U8_0) << 8;
}
void convert_u8_s24_be(data_t* target, data_t* source, int length)
{
for(int i = length - 1; i >= 0; i--)
{
target[i*3] = source[i] - U8_0;
target[i*3+1] = 0;
target[i*3+2] = 0;
}
}
void convert_u8_s24_le(data_t* target, data_t* source, int length)
{
for(int i = length - 1; i >= 0; i--)
{
target[i*3+2] = source[i] - U8_0;
target[i*3+1] = 0;
target[i*3] = 0;
}
}
void convert_u8_s32(data_t* target, data_t* source, int length)
{
int32_t* t = (int32_t*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = (((int32_t)source[i]) - U8_0) << 24;
}
void convert_u8_float(data_t* target, data_t* source, int length)
{
float* t = (float*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = (((int32_t)source[i]) - U8_0) / ((float)U8_0);
}
void convert_u8_double(data_t* target, data_t* source, int length)
{
double* t = (double*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = (((int32_t)source[i]) - U8_0) / ((double)U8_0);
}
void convert_s16_u8(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
for(int i = 0; i < length; i++)
target[i] = (unsigned char)((s[i] >> 8) + U8_0);
}
void convert_s16_s24_be(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
int16_t t;
for(int i = length - 1; i >= 0; i--)
{
t = s[i];
target[i*3] = t >> 8 & 0xFF;
target[i*3+1] = t & 0xFF;
target[i*3+2] = 0;
}
}
void convert_s16_s24_le(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
int16_t t;
for(int i = length - 1; i >= 0; i--)
{
t = s[i];
target[i*3+2] = t >> 8 & 0xFF;
target[i*3+1] = t & 0xFF;
target[i*3] = 0;
}
}
void convert_s16_s32(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
int32_t* t = (int32_t*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = ((int32_t)s[i]) << 16;
}
void convert_s16_float(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
float* t = (float*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = s[i] / S16_FLT;
}
void convert_s16_double(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
double* t = (double*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = s[i] / S16_FLT;
}
void convert_s24_u8_be(data_t* target, data_t* source, int length)
{
for(int i = 0; i < length; i++)
target[i] = source[i*3] ^ U8_0;
}
void convert_s24_u8_le(data_t* target, data_t* source, int length)
{
for(int i = 0; i < length; i++)
target[i] = source[i*3+2] ^ U8_0;
}
void convert_s24_s16_be(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
for(int i = 0; i < length; i++)
t[i] = source[i*3] << 8 | source[i*3+1];
}
void convert_s24_s16_le(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
for(int i = 0; i < length; i++)
t[i] = source[i*3+2] << 8 | source[i*3+1];
}
void convert_s24_s24(data_t* target, data_t* source, int length)
{
std::memcpy(target, source, length * 3);
}
void convert_s24_s32_be(data_t* target, data_t* source, int length)
{
int32_t* t = (int32_t*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
}
void convert_s24_s32_le(data_t* target, data_t* source, int length)
{
int32_t* t = (int32_t*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
}
void convert_s24_float_be(data_t* target, data_t* source, int length)
{
float* t = (float*) target;
int32_t s;
for(int i = length - 1; i >= 0; i--)
{
s = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
t[i] = s / S32_FLT;
}
}
void convert_s24_float_le(data_t* target, data_t* source, int length)
{
float* t = (float*) target;
int32_t s;
for(int i = length - 1; i >= 0; i--)
{
s = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
t[i] = s / S32_FLT;
}
}
void convert_s24_double_be(data_t* target, data_t* source, int length)
{
double* t = (double*) target;
int32_t s;
for(int i = length - 1; i >= 0; i--)
{
s = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
t[i] = s / S32_FLT;
}
}
void convert_s24_double_le(data_t* target, data_t* source, int length)
{
double* t = (double*) target;
int32_t s;
for(int i = length - 1; i >= 0; i--)
{
s = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
t[i] = s / S32_FLT;
}
}
void convert_s32_u8(data_t* target, data_t* source, int length)
{
int16_t* s = (int16_t*) source;
for(int i = 0; i < length; i++)
target[i] = (unsigned char)((s[i] >> 24) + U8_0);
}
void convert_s32_s16(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
int32_t* s = (int32_t*) source;
for(int i = 0; i < length; i++)
t[i] = s[i] >> 16;
}
void convert_s32_s24_be(data_t* target, data_t* source, int length)
{
int32_t* s = (int32_t*) source;
int32_t t;
for(int i = 0; i < length; i++)
{
t = s[i];
target[i*3] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3+2] = t >> 8 & 0xFF;
}
}
void convert_s32_s24_le(data_t* target, data_t* source, int length)
{
int32_t* s = (int32_t*) source;
int32_t t;
for(int i = 0; i < length; i++)
{
t = s[i];
target[i*3+2] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3] = t >> 8 & 0xFF;
}
}
void convert_s32_float(data_t* target, data_t* source, int length)
{
int32_t* s = (int32_t*) source;
float* t = (float*) target;
for(int i = 0; i < length; i++)
t[i] = s[i] / S32_FLT;
}
void convert_s32_double(data_t* target, data_t* source, int length)
{
int32_t* s = (int32_t*) source;
double* t = (double*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = s[i] / S32_FLT;
}
void convert_float_u8(data_t* target, data_t* source, int length)
{
float* s = (float*) source;
float t;
for(int i = 0; i < length; i++)
{
t = s[i] + FLT_MAX;
if(t <= 0.0f)
target[i] = 0;
else if(t >= 2.0f)
target[i] = 255;
else
target[i] = (unsigned char)(t*127);
}
}
void convert_float_s16(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
float* s = (float*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t[i] = S16_MIN;
else if(s[i] >= FLT_MAX)
t[i] = S16_MAX;
else
t[i] = (int16_t)(s[i] * S16_MAX);
}
}
void convert_float_s24_be(data_t* target, data_t* source, int length)
{
int32_t t;
float* s = (float*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t = S32_MIN;
else if(s[i] >= FLT_MAX)
t = S32_MAX;
else
t = (int32_t)(s[i]*S32_MAX);
target[i*3] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3+2] = t >> 8 & 0xFF;
}
}
void convert_float_s24_le(data_t* target, data_t* source, int length)
{
int32_t t;
float* s = (float*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t = S32_MIN;
else if(s[i] >= FLT_MAX)
t = S32_MAX;
else
t = (int32_t)(s[i]*S32_MAX);
target[i*3+2] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3] = t >> 8 & 0xFF;
}
}
void convert_float_s32(data_t* target, data_t* source, int length)
{
int32_t* t = (int32_t*) target;
float* s = (float*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t[i] = S32_MIN;
else if(s[i] >= FLT_MAX)
t[i] = S32_MAX;
else
t[i] = (int32_t)(s[i]*S32_MAX);
}
}
void convert_float_double(data_t* target, data_t* source, int length)
{
float* s = (float*) source;
double* t = (double*) target;
for(int i = length - 1; i >= 0; i--)
t[i] = s[i];
}
void convert_double_u8(data_t* target, data_t* source, int length)
{
double* s = (double*) source;
double t;
for(int i = 0; i < length; i++)
{
t = s[i] + FLT_MAX;
if(t <= 0.0)
target[i] = 0;
else if(t >= 2.0)
target[i] = 255;
else
target[i] = (unsigned char)(t*127);
}
}
void convert_double_s16(data_t* target, data_t* source, int length)
{
int16_t* t = (int16_t*) target;
double* s = (double*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t[i] = S16_MIN;
else if(s[i] >= FLT_MAX)
t[i] = S16_MAX;
else
t[i] = (int16_t)(s[i]*S16_MAX);
}
}
void convert_double_s24_be(data_t* target, data_t* source, int length)
{
int32_t t;
double* s = (double*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t = S32_MIN;
else if(s[i] >= FLT_MAX)
t = S32_MAX;
else
t = (int32_t)(s[i]*S32_MAX);
target[i*3] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3+2] = t >> 8 & 0xFF;
}
}
void convert_double_s24_le(data_t* target, data_t* source, int length)
{
int32_t t;
double* s = (double*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t = S32_MIN;
else if(s[i] >= FLT_MAX)
t = S32_MAX;
else
t = (int32_t)(s[i]*S32_MAX);
target[i*3+2] = t >> 24 & 0xFF;
target[i*3+1] = t >> 16 & 0xFF;
target[i*3] = t >> 8 & 0xFF;
}
}
void convert_double_s32(data_t* target, data_t* source, int length)
{
int32_t* t = (int32_t*) target;
double* s = (double*) source;
for(int i = 0; i < length; i++)
{
if(s[i] <= FLT_MIN)
t[i] = S32_MIN;
else if(s[i] >= FLT_MAX)
t[i] = S32_MAX;
else
t[i] = (int32_t)(s[i]*S32_MAX);
}
}
void convert_double_float(data_t* target, data_t* source, int length)
{
double* s = (double*) source;
float* t = (float*) target;
for(int i = 0; i < length; i++)
t[i] = s[i];
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/ConverterReader.h"
AUD_NAMESPACE_BEGIN
ConverterReader::ConverterReader(std::shared_ptr<IReader> reader,
DeviceSpecs specs) :
EffectReader(reader),
m_format(specs.format)
{
switch(m_format)
{
case FORMAT_U8:
m_convert = convert_float_u8;
break;
case FORMAT_S16:
m_convert = convert_float_s16;
break;
case FORMAT_S24:
#ifdef __BIG_ENDIAN__
m_convert = convert_float_s24_be;
#else
m_convert = convert_float_s24_le;
#endif
break;
case FORMAT_S32:
m_convert = convert_float_s32;
break;
case FORMAT_FLOAT32:
m_convert = convert_copy<float>;
break;
case FORMAT_FLOAT64:
m_convert = convert_float_double;
break;
default:
break;
}
}
void ConverterReader::read(int& length, bool& eos, sample_t* buffer)
{
Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
m_buffer.assureSize(length * samplesize);
m_reader->read(length, eos, m_buffer.getBuffer());
m_convert((data_t*)buffer, (data_t*)m_buffer.getBuffer(),
length * specs.channels);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/JOSResample.h"
#include "respec/JOSResampleReader.h"
AUD_NAMESPACE_BEGIN
JOSResample::JOSResample(std::shared_ptr<ISound> sound, DeviceSpecs specs, ResampleQuality quality) :
SpecsChanger(sound, specs), m_quality(quality)
{
}
std::shared_ptr<IReader> JOSResample::createReader()
{
return std::shared_ptr<IReader>(new JOSResampleReader(getReader(), m_specs.rate, m_quality));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,446 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/JOSResampleReader.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#if defined(__x86_64__) || defined(_M_X64) || defined(__SSE2__)
#include <immintrin.h>
static inline int lrint_impl(double x)
{
return _mm_cvtsd_si32(_mm_load_sd(&x));
}
#else
static inline int lrint_impl(double x)
{
return lrint(x);
}
#endif
#define RATE_MAX 256
#define SHIFT_BITS 12
#define double_to_fp(x) (lrint_impl(x * double(1 << SHIFT_BITS)))
#define int_to_fp(x) (x << SHIFT_BITS)
#define fp_to_int(x) (x >> SHIFT_BITS)
#define fp_to_double(x) (x * 1.0/(1 << SHIFT_BITS))
#define fp_rest(x) (x & ((1 << SHIFT_BITS) - 1))
#define fp_rest_to_double(x) fp_to_double(fp_rest(x))
AUD_NAMESPACE_BEGIN
JOSResampleReader::JOSResampleReader(std::shared_ptr<IReader> reader, SampleRate rate, ResampleQuality quality) :
ResampleReader(reader, rate),
m_channels(CHANNELS_INVALID),
m_n(0),
m_P(0),
m_cache_valid(0),
m_last_factor(0)
{
switch(quality)
{
case ResampleQuality::LOW:
m_len = m_len_low;
m_L = m_L_low;
m_coeff = m_coeff_low;
break;
case ResampleQuality::MEDIUM:
m_len = m_len_medium;
m_L = m_L_medium;
m_coeff = m_coeff_medium;
break;
case ResampleQuality::HIGH:
m_len = m_len_high;
m_L = m_L_high;
m_coeff = m_coeff_high;
break;
default:
m_len = m_len_low;
m_L = m_L_low;
m_coeff = m_coeff_low;
}
}
void JOSResampleReader::reset()
{
m_cache_valid = 0;
m_n = 0;
m_P = 0;
m_last_factor = 0;
}
void JOSResampleReader::updateBuffer(int size, double factor, int samplesize)
{
unsigned int len;
double num_samples = double(m_len) / double(m_L);
// first calculate what length we need right now
if(factor >= 1)
len = std::ceil(num_samples);
else
len = (unsigned int)(std::ceil(num_samples / factor));
// then check if afterwards the length is enough for the maximum rate
if(len + size < num_samples * RATE_MAX)
len = num_samples * RATE_MAX - size;
if(m_n > len)
{
sample_t* buf = m_buffer.getBuffer();
len = m_n - len;
std::memmove(buf, buf + len * m_channels, (m_cache_valid - len) * samplesize);
m_n -= len;
m_cache_valid -= len;
}
m_buffer.assureSize((m_cache_valid + size) * samplesize, true);
}
template<typename T>
void JOSResampleReader::resample(double target_factor, int length, sample_t* buffer)
{
const sample_t* buf = m_buffer.getBuffer();
unsigned int P, l;
int end, i;
double eta, v, f_increment, factor;
m_sums.assureSize(m_channels * sizeof(double));
double* sums = reinterpret_cast<double*>(m_sums.getBuffer());
const sample_t* data;
const float* coeff = m_coeff;
unsigned int P_increment;
for(unsigned int t = 0; t < length; t++)
{
factor = (m_last_factor * (length - t - 1) + target_factor * (t + 1)) / length;
std::memset(sums, 0, sizeof(double) * m_channels);
if(factor >= 1)
{
P = double_to_fp(m_P * m_L);
end = std::floor(m_len / double(m_L) - m_P) - 1;
if(m_n < end)
end = m_n;
data = buf + (m_n - end) * m_channels;
l = fp_to_int(P);
eta = fp_rest_to_double(P);
l += m_L * end;
for(i = 0; i <= end; i++)
{
v = coeff[l] + eta * (coeff[l+1] - coeff[l]);
l -= m_L;
T::left(m_channels, sums, data, v);
}
P = int_to_fp(m_L) - P;
end = std::floor((m_len - 1) / double(m_L) + m_P) - 1;
if(m_cache_valid - int(m_n) - 2 < end)
end = m_cache_valid - int(m_n) - 2;
data = buf + (m_n + 2 + end) * m_channels - 1;
l = fp_to_int(P);
eta = fp_rest_to_double(P);
l += m_L * end;
for(i = 0; i <= end; i++)
{
v = coeff[l] + eta * (coeff[l+1] - coeff[l]);
l -= m_L;
T::right(m_channels, sums, data, v);
}
for(int channel = 0; channel < m_channels; channel++)
{
*buffer = sums[channel];
buffer++;
}
}
else
{
f_increment = factor * m_L;
P_increment = double_to_fp(f_increment);
P = double_to_fp(m_P * f_increment);
end = (int_to_fp(m_len) - P) / P_increment - 1;
if(m_n < end)
end = m_n;
P += P_increment * end;
data = buf + (m_n - end) * m_channels;
l = fp_to_int(P);
for(i = 0; i <= end; i++)
{
eta = fp_rest_to_double(P);
v = coeff[l] + eta * (coeff[l+1] - coeff[l]);
P -= P_increment;
l = fp_to_int(P);
T::left(m_channels, sums, data, v);
}
P = 0 - P;
end = (int_to_fp(m_len) - P) / P_increment - 1;
if(m_cache_valid - int(m_n) - 2 < end)
end = m_cache_valid - int(m_n) - 2;
P += P_increment * end;
data = buf + (m_n + 2 + end) * m_channels - 1;
l = fp_to_int(P);
for(i = 0; i <= end; i++)
{
eta = fp_rest_to_double(P);
v = coeff[l] + eta * (coeff[l+1] - coeff[l]);
P -= P_increment;
l = fp_to_int(P);
T::right(m_channels, sums, data, v);
}
for(int channel = 0; channel < m_channels; channel++)
{
*buffer = factor * sums[channel];
buffer++;
}
}
m_P += std::fmod(1.0 / factor, 1.0);
m_n += std::floor(1.0 / factor);
while(m_P >= 1.0)
{
m_P -= 1.0;
m_n++;
}
}
}
void JOSResampleReader::resample_generic(double target_factor, int length, sample_t* buffer)
{
struct OpGeneric
{
static void left(int channel_count, double *sums, const sample_t*& data, double v)
{
int channel = 0;
do
{
sums[channel] += *data * v;
channel++;
data++;
} while(channel < channel_count);
}
static void right(int channel_count, double* sums, const sample_t*& data, double v)
{
int channel = channel_count;
do
{
channel--;
sums[channel] += *data * v;
data--;
} while(channel);
}
};
resample<OpGeneric>(target_factor, length, buffer);
}
void JOSResampleReader::resample_mono(double target_factor, int length, sample_t* buffer)
{
struct OpMono
{
static void left(int channel_count, double* sums, const sample_t*& data, double v)
{
*sums += *data * v;
data++;
}
static void right(int channel_count, double* sums, const sample_t*& data, double v)
{
*sums += *data * v;
data--;
}
};
resample<OpMono>(target_factor, length, buffer);
}
void JOSResampleReader::resample_stereo(double target_factor, int length, sample_t* buffer)
{
struct OpStereo
{
static void left(int channel_count, double* sums, const sample_t*& data, double v)
{
sums[0] += data[0] * v;
sums[1] += data[1] * v;
data += 2;
}
static void right(int channel_count, double* sums, const sample_t*& data, double v)
{
data -= 2;
sums[0] += data[1] * v;
sums[1] += data[2] * v;
}
};
resample<OpStereo>(target_factor, length, buffer);
}
void JOSResampleReader::seek(int position)
{
position = std::floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
m_reader->seek(position);
reset();
}
int JOSResampleReader::getLength() const
{
return std::floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
}
int JOSResampleReader::getPosition() const
{
return std::floor((m_reader->getPosition() + double(m_P)) * m_rate / m_reader->getSpecs().rate);
}
Specs JOSResampleReader::getSpecs() const
{
Specs specs = m_reader->getSpecs();
specs.rate = m_rate;
return specs;
}
void JOSResampleReader::read(int& length, bool& eos, sample_t* buffer)
{
if(length == 0)
return;
Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
double target_factor = double(m_rate) / double(specs.rate);
eos = false;
int len;
double num_samples = double(m_len) / double(m_L);
// check for channels changed
if(specs.channels != m_channels)
{
m_channels = specs.channels;
reset();
switch(m_channels)
{
case CHANNELS_MONO:
m_resample = &JOSResampleReader::resample_mono;
break;
case CHANNELS_STEREO:
m_resample = &JOSResampleReader::resample_stereo;
break;
default:
m_resample = &JOSResampleReader::resample_generic;
break;
}
}
if(m_last_factor == 0)
m_last_factor = target_factor;
if(target_factor == 1 && m_last_factor == 1 && (m_P == 0))
{
// can read directly!
len = length - (m_cache_valid - m_n);
updateBuffer(len, target_factor, samplesize);
sample_t* buf = m_buffer.getBuffer();
m_reader->read(len, eos, buf + m_cache_valid * m_channels);
m_cache_valid += len;
length = m_cache_valid - m_n;
if(length > 0)
{
std::memcpy(buffer, buf + m_n * m_channels, length * samplesize);
m_n += length;
}
return;
}
// use minimum for the following calculations
double factor = std::min(target_factor, m_last_factor);
if(factor >= 1)
len = (int(m_n) - m_cache_valid) + int(std::ceil(length / factor)) + std::ceil(num_samples);
else
len = (int(m_n) - m_cache_valid) + int(std::ceil(length / factor) + std::ceil(num_samples / factor));
if(len > 0)
{
int should = len;
updateBuffer(len, factor, samplesize);
m_reader->read(len, eos, m_buffer.getBuffer() + m_cache_valid * m_channels);
m_cache_valid += len;
if(len < should)
{
if(len == 0 && eos)
length = 0;
else
{
// use maximum for the following calculations
factor = std::max(target_factor, m_last_factor);
if(eos)
{
// end of stream, let's check how many more samples we can produce
len = std::floor((m_cache_valid - m_n) * factor);
if(len < length)
length = len;
}
else
{
// not enough data available yet, so we recalculate how many samples we can calculate
if(factor >= 1)
len = std::floor((num_samples + m_cache_valid - m_n) * factor);
else
len = std::floor((num_samples * factor + m_cache_valid - m_n) * factor);
if(len < length)
length = len;
}
}
}
}
(this->*m_resample)(target_factor, length, buffer);
m_last_factor = target_factor;
if(m_n > m_cache_valid)
{
m_n = m_cache_valid;
}
eos = eos && ((m_n == m_cache_valid) || (length == 0));
}
AUD_NAMESPACE_END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,275 @@
/*******************************************************************************
* Copyright 2009-2023 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/JOSResampleReader.h"
// sinc filter coefficients, Nz = 16, L = 128, freq = 0.834068, Kaiser Window B = 10
AUD_NAMESPACE_BEGIN
const int JOSResampleReader::m_len_low = 2455;
const int JOSResampleReader::m_L_low = 128;
const float JOSResampleReader::m_coeff_low[m_len_low + 1] = {
8.340675360e-01f, 8.340086260e-01f, 8.338319113e-01f, 8.335374374e-01f, 8.331252804e-01f, 8.325955465e-01f, 8.319483724e-01f, 8.311839250e-01f, 8.303024016e-01f, 8.293040294e-01f,
8.281890659e-01f, 8.269577985e-01f, 8.256105446e-01f, 8.241476514e-01f, 8.225694958e-01f, 8.208764844e-01f, 8.190690531e-01f, 8.171476673e-01f, 8.151128215e-01f, 8.129650394e-01f,
8.107048733e-01f, 8.083329044e-01f, 8.058497425e-01f, 8.032560255e-01f, 8.005524197e-01f, 7.977396190e-01f, 7.948183455e-01f, 7.917893483e-01f, 7.886534040e-01f, 7.854113162e-01f,
7.820639153e-01f, 7.786120581e-01f, 7.750566278e-01f, 7.713985334e-01f, 7.676387098e-01f, 7.637781170e-01f, 7.598177404e-01f, 7.557585901e-01f, 7.516017006e-01f, 7.473481306e-01f,
7.429989628e-01f, 7.385553031e-01f, 7.340182809e-01f, 7.293890482e-01f, 7.246687795e-01f, 7.198586714e-01f, 7.149599422e-01f, 7.099738317e-01f, 7.049016004e-01f, 6.997445297e-01f,
6.945039210e-01f, 6.891810954e-01f, 6.837773936e-01f, 6.782941751e-01f, 6.727328182e-01f, 6.670947189e-01f, 6.613812914e-01f, 6.555939668e-01f, 6.497341931e-01f, 6.438034349e-01f,
6.378031726e-01f, 6.317349019e-01f, 6.256001340e-01f, 6.194003941e-01f, 6.131372220e-01f, 6.068121709e-01f, 6.004268072e-01f, 5.939827100e-01f, 5.874814706e-01f, 5.809246921e-01f,
5.743139887e-01f, 5.676509855e-01f, 5.609373179e-01f, 5.541746308e-01f, 5.473645787e-01f, 5.405088246e-01f, 5.336090401e-01f, 5.266669041e-01f, 5.196841033e-01f, 5.126623308e-01f,
5.056032861e-01f, 4.985086742e-01f, 4.913802058e-01f, 4.842195959e-01f, 4.770285640e-01f, 4.698088330e-01f, 4.625621292e-01f, 4.552901816e-01f, 4.479947212e-01f, 4.406774808e-01f,
4.333401942e-01f, 4.259845960e-01f, 4.186124207e-01f, 4.112254026e-01f, 4.038252749e-01f, 3.964137695e-01f, 3.889926163e-01f, 3.815635430e-01f, 3.741282740e-01f, 3.666885305e-01f,
3.592460298e-01f, 3.518024845e-01f, 3.443596025e-01f, 3.369190863e-01f, 3.294826322e-01f, 3.220519305e-01f, 3.146286642e-01f, 3.072145092e-01f, 2.998111334e-01f, 2.924201965e-01f,
2.850433492e-01f, 2.776822332e-01f, 2.703384802e-01f, 2.630137118e-01f, 2.557095391e-01f, 2.484275618e-01f, 2.411693682e-01f, 2.339365347e-01f, 2.267306252e-01f, 2.195531905e-01f,
2.124057684e-01f, 2.052898829e-01f, 1.982070438e-01f, 1.911587464e-01f, 1.841464709e-01f, 1.771716824e-01f, 1.702358299e-01f, 1.633403466e-01f, 1.564866489e-01f, 1.496761364e-01f,
1.429101914e-01f, 1.361901786e-01f, 1.295174446e-01f, 1.228933176e-01f, 1.163191072e-01f, 1.097961040e-01f, 1.033255791e-01f, 9.690878384e-02f, 9.054694972e-02f, 8.424128778e-02f,
7.799298847e-02f, 7.180322128e-02f, 6.567313448e-02f, 5.960385485e-02f, 5.359648739e-02f, 4.765211504e-02f, 4.177179845e-02f, 3.595657571e-02f, 3.020746213e-02f, 2.452544995e-02f,
1.891150820e-02f, 1.336658241e-02f, 7.891594418e-03f, 2.487442186e-03f, -2.845000411e-03f, -8.104883769e-03f, -1.329138273e-02f, -1.840369674e-02f, -2.344105004e-02f, -2.840269178e-02f,
-3.328789619e-02f, -3.809596272e-02f, -4.282621612e-02f, -4.747800662e-02f, -5.205071001e-02f, -5.654372772e-02f, -6.095648694e-02f, -6.528844073e-02f, -6.953906802e-02f, -7.370787373e-02f,
-7.779438884e-02f, -8.179817038e-02f, -8.571880154e-02f, -8.955589165e-02f, -9.330907621e-02f, -9.697801694e-02f, -1.005624018e-01f, -1.040619447e-01f, -1.074763862e-01f, -1.108054927e-01f,
-1.140490566e-01f, -1.172068969e-01f, -1.202788582e-01f, -1.232648112e-01f, -1.261646528e-01f, -1.289783055e-01f, -1.317057177e-01f, -1.343468635e-01f, -1.369017425e-01f, -1.393703800e-01f,
-1.417528266e-01f, -1.440491581e-01f, -1.462594757e-01f, -1.483839054e-01f, -1.504225980e-01f, -1.523757294e-01f, -1.542434996e-01f, -1.560261333e-01f, -1.577238794e-01f, -1.593370108e-01f,
-1.608658242e-01f, -1.623106400e-01f, -1.636718021e-01f, -1.649496777e-01f, -1.661446569e-01f, -1.672571527e-01f, -1.682876007e-01f, -1.692364587e-01f, -1.701042067e-01f, -1.708913467e-01f,
-1.715984020e-01f, -1.722259174e-01f, -1.727744588e-01f, -1.732446127e-01f, -1.736369864e-01f, -1.739522071e-01f, -1.741909221e-01f, -1.743537984e-01f, -1.744415220e-01f, -1.744547983e-01f,
-1.743943513e-01f, -1.742609231e-01f, -1.740552741e-01f, -1.737781826e-01f, -1.734304438e-01f, -1.730128704e-01f, -1.725262917e-01f, -1.719715531e-01f, -1.713495164e-01f, -1.706610587e-01f,
-1.699070727e-01f, -1.690884657e-01f, -1.682061600e-01f, -1.672610916e-01f, -1.662542107e-01f, -1.651864808e-01f, -1.640588783e-01f, -1.628723926e-01f, -1.616280250e-01f, -1.603267891e-01f,
-1.589697097e-01f, -1.575578229e-01f, -1.560921753e-01f, -1.545738241e-01f, -1.530038362e-01f, -1.513832882e-01f, -1.497132655e-01f, -1.479948625e-01f, -1.462291818e-01f, -1.444173339e-01f,
-1.425604367e-01f, -1.406596153e-01f, -1.387160013e-01f, -1.367307328e-01f, -1.347049534e-01f, -1.326398125e-01f, -1.305364641e-01f, -1.283960672e-01f, -1.262197847e-01f, -1.240087834e-01f,
-1.217642334e-01f, -1.194873077e-01f, -1.171791822e-01f, -1.148410344e-01f, -1.124740438e-01f, -1.100793913e-01f, -1.076582586e-01f, -1.052118278e-01f, -1.027412812e-01f, -1.002478010e-01f,
-9.773256819e-02f, -9.519676317e-02f, -9.264156458e-02f, -9.006814922e-02f, -8.747769162e-02f, -8.487136363e-02f, -8.225033404e-02f, -7.961576821e-02f, -7.696882766e-02f, -7.431066972e-02f,
-7.164244715e-02f, -6.896530775e-02f, -6.628039401e-02f, -6.358884275e-02f, -6.089178474e-02f, -5.819034435e-02f, -5.548563919e-02f, -5.277877979e-02f, -5.007086921e-02f, -4.736300275e-02f,
-4.465626755e-02f, -4.195174230e-02f, -3.925049692e-02f, -3.655359221e-02f, -3.386207952e-02f, -3.117700047e-02f, -2.849938664e-02f, -2.583025921e-02f, -2.317062874e-02f, -2.052149482e-02f,
-1.788384579e-02f, -1.525865848e-02f, -1.264689789e-02f, -1.004951695e-02f, -7.467456264e-03f, -4.901643800e-03f, -2.352994671e-03f, 1.775891258e-04f, 2.689218953e-03f, 5.181019775e-03f,
7.652130387e-03f, 1.010170364e-02f, 1.252890668e-02f, 1.493292112e-02f, 1.731294330e-02f, 1.966818445e-02f, 2.199787092e-02f, 2.430124433e-02f, 2.657756179e-02f, 2.882609604e-02f,
3.104613567e-02f, 3.323698523e-02f, 3.539796542e-02f, 3.752841324e-02f, 3.962768211e-02f, 4.169514205e-02f, 4.373017976e-02f, 4.573219878e-02f, 4.770061960e-02f, 4.963487977e-02f,
5.153443398e-02f, 5.339875422e-02f, 5.522732978e-02f, 5.701966743e-02f, 5.877529142e-02f, 6.049374359e-02f, 6.217458343e-02f, 6.381738813e-02f, 6.542175263e-02f, 6.698728967e-02f,
6.851362982e-02f, 7.000042150e-02f, 7.144733103e-02f, 7.285404264e-02f, 7.422025846e-02f, 7.554569853e-02f, 7.683010081e-02f, 7.807322118e-02f, 7.927483339e-02f, 8.043472904e-02f,
8.155271759e-02f, 8.262862630e-02f, 8.366230017e-02f, 8.465360192e-02f, 8.560241191e-02f, 8.650862813e-02f, 8.737216606e-02f, 8.819295865e-02f, 8.897095621e-02f, 8.970612636e-02f,
9.039845391e-02f, 9.104794075e-02f, 9.165460580e-02f, 9.221848484e-02f, 9.273963044e-02f, 9.321811182e-02f, 9.365401471e-02f, 9.404744127e-02f, 9.439850988e-02f, 9.470735506e-02f,
9.497412730e-02f, 9.519899289e-02f, 9.538213378e-02f, 9.552374743e-02f, 9.562404661e-02f, 9.568325925e-02f, 9.570162826e-02f, 9.567941134e-02f, 9.561688078e-02f, 9.551432332e-02f,
9.537203988e-02f, 9.519034542e-02f, 9.496956871e-02f, 9.471005212e-02f, 9.441215142e-02f, 9.407623554e-02f, 9.370268637e-02f, 9.329189854e-02f, 9.284427915e-02f, 9.236024760e-02f,
9.184023532e-02f, 9.128468551e-02f, 9.069405295e-02f, 9.006880371e-02f, 8.940941493e-02f, 8.871637454e-02f, 8.799018106e-02f, 8.723134327e-02f, 8.644038002e-02f, 8.561781990e-02f,
8.476420106e-02f, 8.388007085e-02f, 8.296598562e-02f, 8.202251044e-02f, 8.105021879e-02f, 8.004969233e-02f, 7.902152059e-02f, 7.796630071e-02f, 7.688463715e-02f, 7.577714145e-02f,
7.464443188e-02f, 7.348713320e-02f, 7.230587637e-02f, 7.110129827e-02f, 6.987404141e-02f, 6.862475362e-02f, 6.735408781e-02f, 6.606270164e-02f, 6.475125724e-02f, 6.342042097e-02f,
6.207086305e-02f, 6.070325734e-02f, 5.931828101e-02f, 5.791661428e-02f, 5.649894012e-02f, 5.506594396e-02f, 5.361831341e-02f, 5.215673796e-02f, 5.068190873e-02f, 4.919451813e-02f,
4.769525964e-02f, 4.618482747e-02f, 4.466391632e-02f, 4.313322107e-02f, 4.159343654e-02f, 4.004525715e-02f, 3.848937674e-02f, 3.692648818e-02f, 3.535728319e-02f, 3.378245204e-02f,
3.220268326e-02f, 3.061866340e-02f, 2.903107678e-02f, 2.744060518e-02f, 2.584792761e-02f, 2.425372007e-02f, 2.265865525e-02f, 2.106340233e-02f, 1.946862670e-02f, 1.787498970e-02f,
1.628314842e-02f, 1.469375542e-02f, 1.310745851e-02f, 1.152490053e-02f, 9.946719066e-03f, 8.373546295e-03f, 6.806008703e-03f, 5.244726891e-03f, 3.690315348e-03f, 2.143382242e-03f,
6.045292037e-04f, -9.256488754e-04f, -2.446564049e-03f, -3.957635514e-03f, -5.458289806e-03f, -6.947960994e-03f, -8.426090862e-03f, -9.892129097e-03f, -1.134553347e-02f, -1.278577000e-02f,
-1.421231315e-02f, -1.562464596e-02f, -1.702226024e-02f, -1.840465671e-02f, -1.977134515e-02f, -2.112184458e-02f, -2.245568338e-02f, -2.377239941e-02f, -2.507154019e-02f, -2.635266303e-02f,
-2.761533509e-02f, -2.885913361e-02f, -3.008364591e-02f, -3.128846961e-02f, -3.247321267e-02f, -3.363749351e-02f, -3.478094111e-02f, -3.590319513e-02f, -3.700390594e-02f, -3.808273477e-02f,
-3.913935375e-02f, -4.017344600e-02f, -4.118470568e-02f, -4.217283808e-02f, -4.313755969e-02f, -4.407859821e-02f, -4.499569263e-02f, -4.588859329e-02f, -4.675706190e-02f, -4.760087157e-02f,
-4.841980688e-02f, -4.921366385e-02f, -4.998225002e-02f, -5.072538441e-02f, -5.144289759e-02f, -5.213463166e-02f, -5.280044024e-02f, -5.344018849e-02f, -5.405375310e-02f, -5.464102226e-02f,
-5.520189569e-02f, -5.573628457e-02f, -5.624411154e-02f, -5.672531067e-02f, -5.717982742e-02f, -5.760761861e-02f, -5.800865239e-02f, -5.838290814e-02f, -5.873037650e-02f, -5.905105923e-02f,
-5.934496922e-02f, -5.961213039e-02f, -5.985257762e-02f, -6.006635671e-02f, -6.025352426e-02f, -6.041414762e-02f, -6.054830480e-02f, -6.065608438e-02f, -6.073758540e-02f, -6.079291731e-02f,
-6.082219983e-02f, -6.082556284e-02f, -6.080314633e-02f, -6.075510022e-02f, -6.068158430e-02f, -6.058276808e-02f, -6.045883067e-02f, -6.030996070e-02f, -6.013635612e-02f, -5.993822414e-02f,
-5.971578105e-02f, -5.946925209e-02f, -5.919887134e-02f, -5.890488155e-02f, -5.858753399e-02f, -5.824708832e-02f, -5.788381245e-02f, -5.749798234e-02f, -5.708988189e-02f, -5.665980276e-02f,
-5.620804421e-02f, -5.573491296e-02f, -5.524072299e-02f, -5.472579539e-02f, -5.419045818e-02f, -5.363504618e-02f, -5.305990075e-02f, -5.246536973e-02f, -5.185180715e-02f, -5.121957313e-02f,
-5.056903367e-02f, -4.990056046e-02f, -4.921453072e-02f, -4.851132699e-02f, -4.779133696e-02f, -4.705495329e-02f, -4.630257340e-02f, -4.553459930e-02f, -4.475143739e-02f, -4.395349825e-02f,
-4.314119650e-02f, -4.231495057e-02f, -4.147518249e-02f, -4.062231775e-02f, -3.975678505e-02f, -3.887901616e-02f, -3.798944566e-02f, -3.708851081e-02f, -3.617665132e-02f, -3.525430915e-02f,
-3.432192833e-02f, -3.337995477e-02f, -3.242883605e-02f, -3.146902123e-02f, -3.050096066e-02f, -2.952510577e-02f, -2.854190892e-02f, -2.755182314e-02f, -2.655530202e-02f, -2.555279943e-02f,
-2.454476939e-02f, -2.353166588e-02f, -2.251394262e-02f, -2.149205290e-02f, -2.046644940e-02f, -1.943758397e-02f, -1.840590751e-02f, -1.737186972e-02f, -1.633591896e-02f, -1.529850207e-02f,
-1.426006415e-02f, -1.322104844e-02f, -1.218189612e-02f, -1.114304610e-02f, -1.010493492e-02f, -9.067996527e-03f, -8.032662132e-03f, -6.999360026e-03f, -5.968515431e-03f, -4.940550333e-03f,
-3.915883321e-03f, -2.894929432e-03f, -1.878099995e-03f, -8.658024758e-04f, 1.415596690e-04f, 1.143587144e-03f, 2.139884957e-03f, 3.130062569e-03f, 4.113734024e-03f, 5.090518098e-03f,
6.060038428e-03f, 7.021923644e-03f, 7.975807504e-03f, 8.921329017e-03f, 9.858132569e-03f, 1.078586804e-02f, 1.170419094e-02f, 1.261276249e-02f, 1.351124977e-02f, 1.439932581e-02f,
1.527666972e-02f, 1.614296673e-02f, 1.699790839e-02f, 1.784119258e-02f, 1.867252364e-02f, 1.949161247e-02f, 2.029817659e-02f, 2.109194026e-02f, 2.187263454e-02f, 2.263999735e-02f,
2.339377360e-02f, 2.413371520e-02f, 2.485958117e-02f, 2.557113769e-02f, 2.626815817e-02f, 2.695042329e-02f, 2.761772107e-02f, 2.826984694e-02f, 2.890660373e-02f, 2.952780179e-02f,
3.013325897e-02f, 3.072280071e-02f, 3.129626003e-02f, 3.185347757e-02f, 3.239430166e-02f, 3.291858829e-02f, 3.342620117e-02f, 3.391701173e-02f, 3.439089914e-02f, 3.484775032e-02f,
3.528745994e-02f, 3.570993047e-02f, 3.611507210e-02f, 3.650280283e-02f, 3.687304838e-02f, 3.722574227e-02f, 3.756082573e-02f, 3.787824771e-02f, 3.817796491e-02f, 3.845994168e-02f,
3.872415007e-02f, 3.897056975e-02f, 3.919918800e-02f, 3.940999968e-02f, 3.960300721e-02f, 3.977822049e-02f, 3.993565688e-02f, 4.007534117e-02f, 4.019730552e-02f, 4.030158939e-02f,
4.038823952e-02f, 4.045730985e-02f, 4.050886147e-02f, 4.054296258e-02f, 4.055968836e-02f, 4.055912098e-02f, 4.054134950e-02f, 4.050646977e-02f, 4.045458441e-02f, 4.038580266e-02f,
4.030024040e-02f, 4.019801998e-02f, 4.007927016e-02f, 3.994412604e-02f, 3.979272899e-02f, 3.962522649e-02f, 3.944177211e-02f, 3.924252536e-02f, 3.902765163e-02f, 3.879732207e-02f,
3.855171352e-02f, 3.829100835e-02f, 3.801539440e-02f, 3.772506487e-02f, 3.742021820e-02f, 3.710105796e-02f, 3.676779274e-02f, 3.642063603e-02f, 3.605980615e-02f, 3.568552605e-02f,
3.529802327e-02f, 3.489752978e-02f, 3.448428187e-02f, 3.405852003e-02f, 3.362048884e-02f, 3.317043681e-02f, 3.270861629e-02f, 3.223528332e-02f, 3.175069754e-02f, 3.125512201e-02f,
3.074882313e-02f, 3.023207048e-02f, 2.970513668e-02f, 2.916829733e-02f, 2.862183077e-02f, 2.806601804e-02f, 2.750114271e-02f, 2.692749074e-02f, 2.634535036e-02f, 2.575501195e-02f,
2.515676788e-02f, 2.455091237e-02f, 2.393774140e-02f, 2.331755254e-02f, 2.269064482e-02f, 2.205731860e-02f, 2.141787545e-02f, 2.077261799e-02f, 2.012184978e-02f, 1.946587517e-02f,
1.880499916e-02f, 1.813952732e-02f, 1.746976558e-02f, 1.679602016e-02f, 1.611859741e-02f, 1.543780367e-02f, 1.475394519e-02f, 1.406732793e-02f, 1.337825750e-02f, 1.268703897e-02f,
1.199397680e-02f, 1.129937467e-02f, 1.060353537e-02f, 9.906760706e-03f, 9.209351318e-03f, 8.511606604e-03f, 7.813824583e-03f, 7.116301778e-03f, 6.419333097e-03f, 5.723211713e-03f,
5.028228955e-03f, 4.334674187e-03f, 3.642834699e-03f, 2.952995594e-03f, 2.265439678e-03f, 1.580447350e-03f, 8.982964989e-04f, 2.192623934e-04f, -4.563824188e-04f, -1.128368214e-03f,
-1.796428193e-03f, -2.460298580e-03f, -3.119718718e-03f, -3.774431168e-03f, -4.424181796e-03f, -5.068719870e-03f, -5.707798147e-03f, -6.341172962e-03f, -6.968604310e-03f, -7.589855934e-03f,
-8.204695405e-03f, -8.812894202e-03f, -9.414227788e-03f, -1.000847569e-02f, -1.059542156e-02f, -1.117485327e-02f, -1.174656295e-02f, -1.231034708e-02f, -1.286600655e-02f, -1.341334671e-02f,
-1.395217745e-02f, -1.448231324e-02f, -1.500357318e-02f, -1.551578110e-02f, -1.601876555e-02f, -1.651235989e-02f, -1.699640232e-02f, -1.747073593e-02f, -1.793520873e-02f, -1.838967373e-02f,
-1.883398891e-02f, -1.926801733e-02f, -1.969162711e-02f, -2.010469147e-02f, -2.050708877e-02f, -2.089870255e-02f, -2.127942151e-02f, -2.164913957e-02f, -2.200775587e-02f, -2.235517480e-02f,
-2.269130599e-02f, -2.301606437e-02f, -2.332937011e-02f, -2.363114870e-02f, -2.392133089e-02f, -2.419985275e-02f, -2.446665562e-02f, -2.472168617e-02f, -2.496489630e-02f, -2.519624326e-02f,
-2.541568952e-02f, -2.562320285e-02f, -2.581875624e-02f, -2.600232793e-02f, -2.617390140e-02f, -2.633346529e-02f, -2.648101343e-02f, -2.661654483e-02f, -2.674006360e-02f, -2.685157896e-02f,
-2.695110520e-02f, -2.703866166e-02f, -2.711427266e-02f, -2.717796751e-02f, -2.722978046e-02f, -2.726975063e-02f, -2.729792201e-02f, -2.731434339e-02f, -2.731906832e-02f, -2.731215506e-02f,
-2.729366657e-02f, -2.726367039e-02f, -2.722223863e-02f, -2.716944792e-02f, -2.710537936e-02f, -2.703011840e-02f, -2.694375488e-02f, -2.684638289e-02f, -2.673810074e-02f, -2.661901089e-02f,
-2.648921990e-02f, -2.634883835e-02f, -2.619798076e-02f, -2.603676554e-02f, -2.586531493e-02f, -2.568375489e-02f, -2.549221506e-02f, -2.529082869e-02f, -2.507973253e-02f, -2.485906677e-02f,
-2.462897499e-02f, -2.438960404e-02f, -2.414110399e-02f, -2.388362803e-02f, -2.361733240e-02f, -2.334237630e-02f, -2.305892182e-02f, -2.276713383e-02f, -2.246717992e-02f, -2.215923033e-02f,
-2.184345779e-02f, -2.152003754e-02f, -2.118914714e-02f, -2.085096645e-02f, -2.050567751e-02f, -2.015346447e-02f, -1.979451348e-02f, -1.942901262e-02f, -1.905715178e-02f, -1.867912262e-02f,
-1.829511842e-02f, -1.790533403e-02f, -1.750996576e-02f, -1.710921129e-02f, -1.670326961e-02f, -1.629234086e-02f, -1.587662631e-02f, -1.545632821e-02f, -1.503164974e-02f, -1.460279490e-02f,
-1.416996843e-02f, -1.373337569e-02f, -1.329322261e-02f, -1.284971556e-02f, -1.240306127e-02f, -1.195346677e-02f, -1.150113927e-02f, -1.104628605e-02f, -1.058911443e-02f, -1.012983162e-02f,
-9.668644671e-03f, -9.205760380e-03f, -8.741385190e-03f, -8.275725108e-03f, -7.808985628e-03f, -7.341371634e-03f, -6.873087321e-03f, -6.404336112e-03f, -5.935320569e-03f, -5.466242317e-03f,
-4.997301958e-03f, -4.528698990e-03f, -4.060631732e-03f, -3.593297236e-03f, -3.126891220e-03f, -2.661607980e-03f, -2.197640322e-03f, -1.735179484e-03f, -1.274415058e-03f, -8.155349253e-04f,
-3.587251773e-04f, 9.582995142e-05f, 5.479481540e-04f, 9.974491193e-04f, 1.444154599e-03f, 1.887888474e-03f, 2.328476817e-03f, 2.765747962e-03f, 3.199532556e-03f, 3.629663631e-03f,
4.055976657e-03f, 4.478309598e-03f, 4.896502978e-03f, 5.310399925e-03f, 5.719846234e-03f, 6.124690414e-03f, 6.524783741e-03f, 6.919980310e-03f, 7.310137077e-03f, 7.695113911e-03f,
8.074773638e-03f, 8.448982084e-03f, 8.817608116e-03f, 9.180523686e-03f, 9.537603865e-03f, 9.888726886e-03f, 1.023377418e-02f, 1.057263039e-02f, 1.090518345e-02f, 1.123132457e-02f,
1.155094829e-02f, 1.186395249e-02f, 1.217023844e-02f, 1.246971082e-02f, 1.276227770e-02f, 1.304785065e-02f, 1.332634467e-02f, 1.359767826e-02f, 1.386177341e-02f, 1.411855565e-02f,
1.436795404e-02f, 1.460990116e-02f, 1.484433317e-02f, 1.507118978e-02f, 1.529041427e-02f, 1.550195352e-02f, 1.570575796e-02f, 1.590178162e-02f, 1.608998211e-02f, 1.627032063e-02f,
1.644276195e-02f, 1.660727443e-02f, 1.676382999e-02f, 1.691240414e-02f, 1.705297592e-02f, 1.718552793e-02f, 1.731004632e-02f, 1.742652075e-02f, 1.753494439e-02f, 1.763531391e-02f,
1.772762946e-02f, 1.781189465e-02f, 1.788811652e-02f, 1.795630554e-02f, 1.801647558e-02f, 1.806864385e-02f, 1.811283096e-02f, 1.814906080e-02f, 1.817736056e-02f, 1.819776071e-02f,
1.821029493e-02f, 1.821500012e-02f, 1.821191634e-02f, 1.820108678e-02f, 1.818255775e-02f, 1.815637861e-02f, 1.812260172e-02f, 1.808128248e-02f, 1.803247918e-02f, 1.797625307e-02f,
1.791266822e-02f, 1.784179156e-02f, 1.776369275e-02f, 1.767844424e-02f, 1.758612111e-02f, 1.748680113e-02f, 1.738056463e-02f, 1.726749450e-02f, 1.714767611e-02f, 1.702119729e-02f,
1.688814826e-02f, 1.674862157e-02f, 1.660271208e-02f, 1.645051687e-02f, 1.629213521e-02f, 1.612766849e-02f, 1.595722018e-02f, 1.578089576e-02f, 1.559880269e-02f, 1.541105031e-02f,
1.521774981e-02f, 1.501901418e-02f, 1.481495812e-02f, 1.460569803e-02f, 1.439135190e-02f, 1.417203927e-02f, 1.394788119e-02f, 1.371900012e-02f, 1.348551990e-02f, 1.324756569e-02f,
1.300526389e-02f, 1.275874208e-02f, 1.250812898e-02f, 1.225355436e-02f, 1.199514900e-02f, 1.173304463e-02f, 1.146737384e-02f, 1.119827005e-02f, 1.092586741e-02f, 1.065030080e-02f,
1.037170571e-02f, 1.009021818e-02f, 9.805974783e-03f, 9.519112526e-03f, 9.229768795e-03f, 8.938081301e-03f, 8.644188012e-03f, 8.348227095e-03f, 8.050336853e-03f, 7.750655666e-03f,
7.449321932e-03f, 7.146474002e-03f, 6.842250127e-03f, 6.536788391e-03f, 6.230226659e-03f, 5.922702516e-03f, 5.614353207e-03f, 5.305315582e-03f, 4.995726037e-03f, 4.685720460e-03f,
4.375434170e-03f, 4.065001866e-03f, 3.754557573e-03f, 3.444234581e-03f, 3.134165397e-03f, 2.824481690e-03f, 2.515314240e-03f, 2.206792882e-03f, 1.899046461e-03f, 1.592202775e-03f,
1.286388530e-03f, 9.817292888e-04f, 6.783494245e-04f, 3.763720713e-04f, 7.591907869e-05f, -2.228890345e-04f, -5.199331250e-04f, -8.150954692e-04f, -1.108259807e-03f, -1.399311383e-03f,
-1.688136989e-03f, -1.974625006e-03f, -2.258665439e-03f, -2.540149963e-03f, -2.818971955e-03f, -3.095026533e-03f, -3.368210592e-03f, -3.638422839e-03f, -3.905563826e-03f, -4.169535987e-03f,
-4.430243662e-03f, -4.687593137e-03f, -4.941492669e-03f, -5.191852513e-03f, -5.438584957e-03f, -5.681604341e-03f, -5.920827090e-03f, -6.156171731e-03f, -6.387558926e-03f, -6.614911485e-03f,
-6.838154395e-03f, -7.057214839e-03f, -7.272022211e-03f, -7.482508139e-03f, -7.688606504e-03f, -7.890253449e-03f, -8.087387402e-03f, -8.279949084e-03f, -8.467881525e-03f, -8.651130079e-03f,
-8.829642427e-03f, -9.003368593e-03f, -9.172260951e-03f, -9.336274233e-03f, -9.495365534e-03f, -9.649494319e-03f, -9.798622427e-03f, -9.942714075e-03f, -1.008173586e-02f, -1.021565675e-02f,
-1.034444812e-02f, -1.046808369e-02f, -1.058653959e-02f, -1.069979431e-02f, -1.080782870e-02f, -1.091062600e-02f, -1.100817181e-02f, -1.110045406e-02f, -1.118746304e-02f, -1.126919138e-02f,
-1.134563404e-02f, -1.141678828e-02f, -1.148265367e-02f, -1.154323209e-02f, -1.159852767e-02f, -1.164854681e-02f, -1.169329818e-02f, -1.173279266e-02f, -1.176704334e-02f, -1.179606551e-02f,
-1.181987666e-02f, -1.183849639e-02f, -1.185194649e-02f, -1.186025082e-02f, -1.186343535e-02f, -1.186152813e-02f, -1.185455923e-02f, -1.184256076e-02f, -1.182556682e-02f, -1.180361347e-02f,
-1.177673873e-02f, -1.174498251e-02f, -1.170838664e-02f, -1.166699477e-02f, -1.162085240e-02f, -1.157000682e-02f, -1.151450709e-02f, -1.145440400e-02f, -1.138975006e-02f, -1.132059942e-02f,
-1.124700789e-02f, -1.116903289e-02f, -1.108673338e-02f, -1.100016989e-02f, -1.090940441e-02f, -1.081450044e-02f, -1.071552288e-02f, -1.061253801e-02f, -1.050561350e-02f, -1.039481831e-02f,
-1.028022269e-02f, -1.016189813e-02f, -1.003991732e-02f, -9.914354127e-03f, -9.785283532e-03f, -9.652781607e-03f, -9.516925470e-03f, -9.377793250e-03f, -9.235464042e-03f, -9.090017867e-03f,
-8.941535636e-03f, -8.790099106e-03f, -8.635790842e-03f, -8.478694172e-03f, -8.318893152e-03f, -8.156472520e-03f, -7.991517658e-03f, -7.824114551e-03f, -7.654349743e-03f, -7.482310301e-03f,
-7.308083768e-03f, -7.131758128e-03f, -6.953421760e-03f, -6.773163400e-03f, -6.591072099e-03f, -6.407237184e-03f, -6.221748213e-03f, -6.034694942e-03f, -5.846167276e-03f, -5.656255234e-03f,
-5.465048911e-03f, -5.272638430e-03f, -5.079113913e-03f, -4.884565431e-03f, -4.689082975e-03f, -4.492756410e-03f, -4.295675437e-03f, -4.097929560e-03f, -3.899608042e-03f, -3.700799871e-03f,
-3.501593721e-03f, -3.302077915e-03f, -3.102340391e-03f, -2.902468661e-03f, -2.702549781e-03f, -2.502670311e-03f, -2.302916282e-03f, -2.103373160e-03f, -1.904125815e-03f, -1.705258484e-03f,
-1.506854739e-03f, -1.308997457e-03f, -1.111768782e-03f, -9.152500997e-04f, -7.195220014e-04f, -5.246642566e-04f, -3.307557813e-04f, -1.378746090e-04f, 5.390213843e-05f, 2.444982788e-04f,
4.338385978e-04f, 6.218488759e-04f, 8.084559154e-04f, 9.935875659e-04f, 1.177172750e-03f, 1.359141488e-03f, 1.539424923e-03f, 1.717955341e-03f, 1.894666200e-03f, 2.069492144e-03f,
2.242369034e-03f, 2.413233959e-03f, 2.582025266e-03f, 2.748682570e-03f, 2.913146782e-03f, 3.075360119e-03f, 3.235266129e-03f, 3.392809701e-03f, 3.547937086e-03f, 3.700595911e-03f,
3.850735193e-03f, 3.998305353e-03f, 4.143258230e-03f, 4.285547095e-03f, 4.425126661e-03f, 4.561953092e-03f, 4.695984021e-03f, 4.827178551e-03f, 4.955497270e-03f, 5.080902256e-03f,
5.203357088e-03f, 5.322826851e-03f, 5.439278141e-03f, 5.552679073e-03f, 5.662999284e-03f, 5.770209939e-03f, 5.874283733e-03f, 5.975194894e-03f, 6.072919186e-03f, 6.167433909e-03f,
6.258717899e-03f, 6.346751532e-03f, 6.431516720e-03f, 6.512996907e-03f, 6.591177076e-03f, 6.666043735e-03f, 6.737584922e-03f, 6.805790199e-03f, 6.870650644e-03f, 6.932158851e-03f,
6.990308919e-03f, 7.045096449e-03f, 7.096518534e-03f, 7.144573756e-03f, 7.189262171e-03f, 7.230585305e-03f, 7.268546141e-03f, 7.303149114e-03f, 7.334400093e-03f, 7.362306374e-03f,
7.386876669e-03f, 7.408121092e-03f, 7.426051143e-03f, 7.440679700e-03f, 7.452021001e-03f, 7.460090632e-03f, 7.464905510e-03f, 7.466483867e-03f, 7.464845236e-03f, 7.460010432e-03f,
7.452001538e-03f, 7.440841883e-03f, 7.426556031e-03f, 7.409169754e-03f, 7.388710021e-03f, 7.365204973e-03f, 7.338683907e-03f, 7.309177254e-03f, 7.276716561e-03f, 7.241334465e-03f,
7.203064680e-03f, 7.161941968e-03f, 7.118002120e-03f, 7.071281936e-03f, 7.021819199e-03f, 6.969652654e-03f, 6.914821987e-03f, 6.857367795e-03f, 6.797331571e-03f, 6.734755675e-03f,
6.669683311e-03f, 6.602158502e-03f, 6.532226066e-03f, 6.459931595e-03f, 6.385321422e-03f, 6.308442604e-03f, 6.229342892e-03f, 6.148070708e-03f, 6.064675116e-03f, 5.979205802e-03f,
5.891713044e-03f, 5.802247686e-03f, 5.710861115e-03f, 5.617605232e-03f, 5.522532427e-03f, 5.425695553e-03f, 5.327147902e-03f, 5.226943172e-03f, 5.125135449e-03f, 5.021779175e-03f,
4.916929125e-03f, 4.810640378e-03f, 4.702968292e-03f, 4.593968479e-03f, 4.483696779e-03f, 4.372209230e-03f, 4.259562046e-03f, 4.145811591e-03f, 4.031014350e-03f, 3.915226907e-03f,
3.798505918e-03f, 3.680908082e-03f, 3.562490124e-03f, 3.443308761e-03f, 3.323420682e-03f, 3.202882522e-03f, 3.081750836e-03f, 2.960082079e-03f, 2.837932575e-03f, 2.715358499e-03f,
2.592415847e-03f, 2.469160421e-03f, 2.345647797e-03f, 2.221933306e-03f, 2.098072011e-03f, 1.974118685e-03f, 1.850127785e-03f, 1.726153435e-03f, 1.602249400e-03f, 1.478469067e-03f,
1.354865425e-03f, 1.231491038e-03f, 1.108398033e-03f, 9.856380731e-04f, 8.632623400e-04f, 7.413215153e-04f, 6.198657603e-04f, 4.989446971e-04f, 3.786073905e-04f, 2.589023299e-04f,
1.398774111e-04f, 2.157991938e-05f, -9.594348750e-05f, -2.126467961e-04f, -3.284846535e-04f, -4.434123828e-04f, -5.573859987e-04f, -6.703622229e-04f, -7.822984977e-04f, -8.931530012e-04f,
-1.002884660e-03f, -1.111453165e-03f, -1.218818979e-03f, -1.324943356e-03f, -1.429788347e-03f, -1.533316817e-03f, -1.635492452e-03f, -1.736279772e-03f, -1.835644139e-03f, -1.933551770e-03f,
-2.029969746e-03f, -2.124866016e-03f, -2.218209413e-03f, -2.309969656e-03f, -2.400117361e-03f, -2.488624048e-03f, -2.575462143e-03f, -2.660604994e-03f, -2.744026865e-03f, -2.825702950e-03f,
-2.905609376e-03f, -2.983723205e-03f, -3.060022439e-03f, -3.134486027e-03f, -3.207093862e-03f, -3.277826789e-03f, -3.346666604e-03f, -3.413596058e-03f, -3.478598857e-03f, -3.541659662e-03f,
-3.602764093e-03f, -3.661898724e-03f, -3.719051089e-03f, -3.774209673e-03f, -3.827363920e-03f, -3.878504224e-03f, -3.927621929e-03f, -3.974709330e-03f, -4.019759664e-03f, -4.062767113e-03f,
-4.103726796e-03f, -4.142634766e-03f, -4.179488005e-03f, -4.214284423e-03f, -4.247022845e-03f, -4.277703016e-03f, -4.306325583e-03f, -4.332892098e-03f, -4.357405008e-03f, -4.379867647e-03f,
-4.400284230e-03f, -4.418659844e-03f, -4.435000441e-03f, -4.449312829e-03f, -4.461604665e-03f, -4.471884441e-03f, -4.480161479e-03f, -4.486445923e-03f, -4.490748722e-03f, -4.493081627e-03f,
-4.493457174e-03f, -4.491888678e-03f, -4.488390221e-03f, -4.482976638e-03f, -4.475663508e-03f, -4.466467140e-03f, -4.455404562e-03f, -4.442493510e-03f, -4.427752410e-03f, -4.411200373e-03f,
-4.392857175e-03f, -4.372743246e-03f, -4.350879658e-03f, -4.327288110e-03f, -4.301990913e-03f, -4.275010977e-03f, -4.246371798e-03f, -4.216097441e-03f, -4.184212527e-03f, -4.150742217e-03f,
-4.115712199e-03f, -4.079148672e-03f, -4.041078329e-03f, -4.001528346e-03f, -3.960526361e-03f, -3.918100463e-03f, -3.874279176e-03f, -3.829091441e-03f, -3.782566601e-03f, -3.734734386e-03f,
-3.685624897e-03f, -3.635268590e-03f, -3.583696257e-03f, -3.530939016e-03f, -3.477028289e-03f, -3.421995791e-03f, -3.365873508e-03f, -3.308693686e-03f, -3.250488813e-03f, -3.191291600e-03f,
-3.131134972e-03f, -3.070052042e-03f, -3.008076105e-03f, -2.945240615e-03f, -2.881579170e-03f, -2.817125499e-03f, -2.751913444e-03f, -2.685976942e-03f, -2.619350013e-03f, -2.552066743e-03f,
-2.484161268e-03f, -2.415667756e-03f, -2.346620397e-03f, -2.277053381e-03f, -2.207000890e-03f, -2.136497075e-03f, -2.065576048e-03f, -1.994271861e-03f, -1.922618496e-03f, -1.850649848e-03f,
-1.778399710e-03f, -1.705901761e-03f, -1.633189549e-03f, -1.560296477e-03f, -1.487255793e-03f, -1.414100570e-03f, -1.340863698e-03f, -1.267577868e-03f, -1.194275559e-03f, -1.120989025e-03f,
-1.047750283e-03f, -9.745910968e-04f, -9.015429712e-04f, -8.286371336e-04f, -7.559045249e-04f, -6.833757869e-04f, -6.110812510e-04f, -5.390509267e-04f, -4.673144903e-04f, -3.959012741e-04f,
-3.248402558e-04f, -2.541600480e-04f, -1.838888878e-04f, -1.140546271e-04f, -4.468472254e-05f, 2.419377358e-05f, 9.255422288e-05f, 1.603704097e-04f, 2.276165499e-04f, 2.942672994e-04f,
3.602977621e-04f, 4.256834981e-04f, 4.904005315e-04f, 5.544253575e-04f, 6.177349495e-04f, 6.803067666e-04f, 7.421187596e-04f, 8.031493774e-04f, 8.633775735e-04f, 9.227828114e-04f,
9.813450703e-04f, 1.039044851e-03f, 1.095863178e-03f, 1.151781610e-03f, 1.206782237e-03f, 1.260847692e-03f, 1.313961148e-03f, 1.366106326e-03f, 1.417267498e-03f, 1.467429487e-03f,
1.516577675e-03f, 1.564697999e-03f, 1.611776960e-03f, 1.657801619e-03f, 1.702759604e-03f, 1.746639107e-03f, 1.789428887e-03f, 1.831118272e-03f, 1.871697160e-03f, 1.911156014e-03f,
1.949485869e-03f, 1.986678329e-03f, 2.022725566e-03f, 2.057620320e-03f, 2.091355898e-03f, 2.123926172e-03f, 2.155325581e-03f, 2.185549124e-03f, 2.214592363e-03f, 2.242451417e-03f,
2.269122963e-03f, 2.294604232e-03f, 2.318893004e-03f, 2.341987609e-03f, 2.363886920e-03f, 2.384590352e-03f, 2.404097858e-03f, 2.422409923e-03f, 2.439527562e-03f, 2.455452314e-03f,
2.470186240e-03f, 2.483731914e-03f, 2.496092422e-03f, 2.507271355e-03f, 2.517272804e-03f, 2.526101353e-03f, 2.533762078e-03f, 2.540260533e-03f, 2.545602752e-03f, 2.549795237e-03f,
2.552844955e-03f, 2.554759330e-03f, 2.555546236e-03f, 2.555213990e-03f, 2.553771347e-03f, 2.551227489e-03f, 2.547592022e-03f, 2.542874964e-03f, 2.537086741e-03f, 2.530238177e-03f,
2.522340488e-03f, 2.513405272e-03f, 2.503444503e-03f, 2.492470518e-03f, 2.480496018e-03f, 2.467534048e-03f, 2.453597998e-03f, 2.438701589e-03f, 2.422858867e-03f, 2.406084191e-03f,
2.388392227e-03f, 2.369797940e-03f, 2.350316581e-03f, 2.329963680e-03f, 2.308755038e-03f, 2.286706717e-03f, 2.263835030e-03f, 2.240156531e-03f, 2.215688008e-03f, 2.190446472e-03f,
2.164449149e-03f, 2.137713469e-03f, 2.110257055e-03f, 2.082097719e-03f, 2.053253448e-03f, 2.023742395e-03f, 1.993582870e-03f, 1.962793331e-03f, 1.931392375e-03f, 1.899398727e-03f,
1.866831231e-03f, 1.833708840e-03f, 1.800050610e-03f, 1.765875684e-03f, 1.731203289e-03f, 1.696052723e-03f, 1.660443349e-03f, 1.624394581e-03f, 1.587925878e-03f, 1.551056734e-03f,
1.513806671e-03f, 1.476195225e-03f, 1.438241941e-03f, 1.399966365e-03f, 1.361388030e-03f, 1.322526452e-03f, 1.283401121e-03f, 1.244031488e-03f, 1.204436963e-03f, 1.164636898e-03f,
1.124650590e-03f, 1.084497260e-03f, 1.044196057e-03f, 1.003766039e-03f, 9.632261729e-04f, 9.225953234e-04f, 8.818922452e-04f, 8.411355758e-04f, 8.003438281e-04f, 7.595353823e-04f,
7.187284795e-04f, 6.779412139e-04f, 6.371915256e-04f, 5.964971942e-04f, 5.558758316e-04f, 5.153448754e-04f, 4.749215822e-04f, 4.346230215e-04f, 3.944660692e-04f, 3.544674015e-04f,
3.146434886e-04f, 2.750105896e-04f, 2.355847457e-04f, 1.963817757e-04f, 1.574172698e-04f, 1.187065847e-04f, 8.026483832e-05f, 4.210690478e-05f, 4.247409714e-06f, -3.329927451e-05f,
-7.051903330e-05f, -1.073980142e-04f, -1.439226311e-04f, -1.800795685e-04f, -2.158557848e-04f, -2.512385170e-04f, -2.862152833e-04f, -3.207738872e-04f, -3.549024207e-04f, -3.885892670e-04f,
-4.218231039e-04f, -4.545929064e-04f, -4.868879492e-04f, -5.186978096e-04f, -5.500123693e-04f, -5.808218168e-04f, -6.111166496e-04f, -6.408876757e-04f, -6.701260154e-04f, -6.988231029e-04f,
-7.269706874e-04f, -7.545608348e-04f, -7.815859282e-04f, -8.080386691e-04f, -8.339120783e-04f, -8.591994961e-04f, -8.838945828e-04f, -9.079913193e-04f, -9.314840070e-04f, -9.543672678e-04f,
-9.766360438e-04f, -9.982855973e-04f, -1.019311510e-03f, -1.039709683e-03f, -1.059476335e-03f, -1.078608003e-03f, -1.097101539e-03f, -1.114954111e-03f, -1.132163201e-03f, -1.148726603e-03f,
-1.164642422e-03f, -1.179909071e-03f, -1.194525273e-03f, -1.208490054e-03f, -1.221802743e-03f, -1.234462973e-03f, -1.246470672e-03f, -1.257826067e-03f, -1.268529677e-03f, -1.278582313e-03f,
-1.287985075e-03f, -1.296739346e-03f, -1.304846792e-03f, -1.312309360e-03f, -1.319129271e-03f, -1.325309020e-03f, -1.330851370e-03f, -1.335759349e-03f, -1.340036250e-03f, -1.343685621e-03f,
-1.346711267e-03f, -1.349117241e-03f, -1.350907847e-03f, -1.352087626e-03f, -1.352661362e-03f, -1.352634071e-03f, -1.352010999e-03f, -1.350797619e-03f, -1.348999625e-03f, -1.346622925e-03f,
-1.343673642e-03f, -1.340158106e-03f, -1.336082850e-03f, -1.331454603e-03f, -1.326280289e-03f, -1.320567022e-03f, -1.314322096e-03f, -1.307552986e-03f, -1.300267341e-03f, -1.292472978e-03f,
-1.284177877e-03f, -1.275390177e-03f, -1.266118171e-03f, -1.256370299e-03f, -1.246155147e-03f, -1.235481434e-03f, -1.224358018e-03f, -1.212793878e-03f, -1.200798121e-03f, -1.188379967e-03f,
-1.175548749e-03f, -1.162313907e-03f, -1.148684982e-03f, -1.134671610e-03f, -1.120283519e-03f, -1.105530521e-03f, -1.090422509e-03f, -1.074969449e-03f, -1.059181380e-03f, -1.043068401e-03f,
-1.026640674e-03f, -1.009908411e-03f, -9.928818764e-04f, -9.755713750e-04f, -9.579872515e-04f, -9.401398832e-04f, -9.220396756e-04f, -9.036970571e-04f, -8.851224742e-04f, -8.663263863e-04f,
-8.473192607e-04f, -8.281115678e-04f, -8.087137763e-04f, -7.891363482e-04f, -7.693897339e-04f, -7.494843677e-04f, -7.294306631e-04f, -7.092390079e-04f, -6.889197599e-04f, -6.684832419e-04f,
-6.479397380e-04f, -6.272994882e-04f, -6.065726848e-04f, -5.857694678e-04f, -5.648999205e-04f, -5.439740656e-04f, -5.230018608e-04f, -5.019931951e-04f, -4.809578845e-04f, -4.599056681e-04f,
-4.388462044e-04f, -4.177890676e-04f, -3.967437435e-04f, -3.757196263e-04f, -3.547260150e-04f, -3.337721094e-04f, -3.128670075e-04f, -2.920197015e-04f, -2.712390750e-04f, -2.505338997e-04f,
-2.299128320e-04f, -2.093844106e-04f, -1.889570532e-04f, -1.686390535e-04f, -1.484385789e-04f, -1.283636676e-04f, -1.084222258e-04f, -8.862202577e-05f, -6.897070277e-05f, -4.947575319e-05f,
-3.014453212e-05f, -1.098425124e-05f, 7.998023237e-06f, 2.679537259e-05f, 4.540102745e-05f, 6.380836958e-05f, 8.201093367e-05f, 1.000024089e-04f, 1.177766404e-04f, 1.353276310e-04f,
1.526495422e-04f, 1.697366958e-04f, 1.865835749e-04f, 2.031848250e-04f, 2.195352551e-04f, 2.356298385e-04f, 2.514637138e-04f, 2.670321857e-04f, 2.823307254e-04f, 2.973549714e-04f,
3.121007300e-04f, 3.265639755e-04f, 3.407408511e-04f, 3.546276682e-04f, 3.682209076e-04f, 3.815172188e-04f, 3.945134205e-04f, 4.072065003e-04f, 4.195936146e-04f, 4.316720881e-04f,
4.434394141e-04f, 4.548932536e-04f, 4.660314350e-04f, 4.768519534e-04f, 4.873529703e-04f, 4.975328127e-04f, 5.073899723e-04f, 5.169231048e-04f, 5.261310289e-04f, 5.350127255e-04f,
5.435673362e-04f, 5.517941629e-04f, 5.596926660e-04f, 5.672624633e-04f, 5.745033291e-04f, 5.814151921e-04f, 5.879981349e-04f, 5.942523915e-04f, 6.001783466e-04f, 6.057765335e-04f,
6.110476326e-04f, 6.159924697e-04f, 6.206120142e-04f, 6.249073772e-04f, 6.288798098e-04f, 6.325307010e-04f, 6.358615759e-04f, 6.388740935e-04f, 6.415700448e-04f, 6.439513505e-04f,
6.460200591e-04f, 6.477783444e-04f, 6.492285038e-04f, 6.503729553e-04f, 6.512142356e-04f, 6.517549980e-04f, 6.519980096e-04f, 6.519461488e-04f, 6.516024036e-04f, 6.509698682e-04f,
6.500517411e-04f, 6.488513225e-04f, 6.473720116e-04f, 6.456173039e-04f, 6.435907892e-04f, 6.412961483e-04f, 6.387371507e-04f, 6.359176518e-04f, 6.328415907e-04f, 6.295129868e-04f,
6.259359375e-04f, 6.221146157e-04f, 6.180532664e-04f, 6.137562048e-04f, 6.092278130e-04f, 6.044725374e-04f, 5.994948860e-04f, 5.942994257e-04f, 5.888907793e-04f, 5.832736232e-04f,
5.774526842e-04f, 5.714327368e-04f, 5.652186008e-04f, 5.588151382e-04f, 5.522272507e-04f, 5.454598768e-04f, 5.385179891e-04f, 5.314065917e-04f, 5.241307175e-04f, 5.166954253e-04f,
5.091057973e-04f, 5.013669366e-04f, 4.934839641e-04f, 4.854620164e-04f, 4.773062426e-04f, 4.690218024e-04f, 4.606138630e-04f, 4.520875968e-04f, 4.434481786e-04f, 4.347007835e-04f,
4.258505841e-04f, 4.169027483e-04f, 4.078624366e-04f, 3.987347999e-04f, 3.895249770e-04f, 3.802380925e-04f, 3.708792540e-04f, 3.614535504e-04f, 3.519660494e-04f, 3.424217950e-04f,
3.328258057e-04f, 3.231830724e-04f, 3.134985559e-04f, 3.037771851e-04f, 2.940238550e-04f, 2.842434242e-04f, 2.744407139e-04f, 2.646205049e-04f, 2.547875364e-04f, 2.449465038e-04f,
2.351020572e-04f, 2.252587994e-04f, 2.154212842e-04f, 2.055940145e-04f, 1.957814413e-04f, 1.859879613e-04f, 1.762179158e-04f, 1.664755893e-04f, 1.567652075e-04f, 1.470909363e-04f,
1.374568803e-04f, 1.278670813e-04f, 1.183255172e-04f, 1.088361008e-04f, 9.940267807e-05f, 9.002902776e-05f, 8.071885966e-05f, 7.147581376e-05f, 6.230345923e-05f, 5.320529333e-05f,
4.418474059e-05f, 3.524515179e-05f, 2.638980320e-05f, 1.762189572e-05f, 8.944554141e-06f, 3.608264200e-07f, -8.126316992e-06f, -1.651398378e-05f, -2.479936033e-05f, -3.297971229e-05f,
-4.105238505e-05f, -4.901480420e-05f, -5.686447591e-05f, -6.459898732e-05f, -7.221600683e-05f, -7.971328440e-05f, -8.708865176e-05f, -9.434002260e-05f, -1.014653927e-04f, -1.084628402e-04f,
-1.153305252e-04f, -1.220666904e-04f, -1.286696606e-04f, -1.351378429e-04f, -1.414697264e-04f, -1.476638823e-04f, -1.537189635e-04f, -1.596337044e-04f, -1.654069209e-04f, -1.710375098e-04f,
-1.765244486e-04f, -1.818667949e-04f, -1.870636866e-04f, -1.921143409e-04f, -1.970180538e-04f, -2.017741999e-04f, -2.063822320e-04f, -2.108416799e-04f, -2.151521503e-04f, -2.193133260e-04f,
-2.233249653e-04f, -2.271869010e-04f, -2.308990403e-04f, -2.344613633e-04f, -2.378739228e-04f, -2.411368429e-04f, -2.442503189e-04f, -2.472146158e-04f, -2.500300676e-04f, -2.526970764e-04f,
-2.552161116e-04f, -2.575877086e-04f, -2.598124682e-04f, -2.618910551e-04f, -2.638241975e-04f, -2.656126853e-04f, -2.672573697e-04f, -2.687591616e-04f, -2.701190310e-04f, -2.713380052e-04f,
-2.724171683e-04f, -2.733576595e-04f, -2.741606726e-04f, -2.748274539e-04f, -2.753593017e-04f, -2.757575649e-04f, -2.760236418e-04f, -2.761589784e-04f, -2.761650679e-04f, -2.760434489e-04f,
-2.757957044e-04f, -2.754234601e-04f, -2.749283839e-04f, -2.743121836e-04f, -2.735766064e-04f, -2.727234373e-04f, -2.717544976e-04f, -2.706716441e-04f, -2.694767670e-04f, -2.681717894e-04f,
-2.667586653e-04f, -2.652393789e-04f, -2.636159426e-04f, -2.618903962e-04f, -2.600648053e-04f, -2.581412601e-04f, -2.561218741e-04f, -2.540087826e-04f, -2.518041415e-04f, -2.495101260e-04f,
-2.471289294e-04f, -2.446627613e-04f, -2.421138472e-04f, -2.394844262e-04f, -2.367767505e-04f, -2.339930837e-04f, -2.311356997e-04f, -2.282068813e-04f, -2.252089192e-04f, -2.221441104e-04f,
-2.190147574e-04f, -2.158231667e-04f, -2.125716475e-04f, -2.092625109e-04f, -2.058980682e-04f, -2.024806303e-04f, -1.990125060e-04f, -1.954960013e-04f, -1.919334180e-04f, -1.883270527e-04f,
-1.846791957e-04f, -1.809921299e-04f, -1.772681296e-04f, -1.735094597e-04f, -1.697183746e-04f, -1.658971170e-04f, -1.620479172e-04f, -1.581729919e-04f, -1.542745431e-04f, -1.503547576e-04f,
-1.464158058e-04f, -1.424598408e-04f, -1.384889974e-04f, -1.345053917e-04f, -1.305111195e-04f, -1.265082562e-04f, -1.224988556e-04f, -1.184849493e-04f, -1.144685456e-04f, -1.104516293e-04f,
-1.064361604e-04f, -1.024240738e-04f, -9.841727849e-05f, -9.441765685e-05f, -9.042706406e-05f, -8.644732744e-05f, -8.248024590e-05f, -7.852758935e-05f, -7.459109811e-05f, -7.067248246e-05f,
-6.677342203e-05f, -6.289556540e-05f, -5.904052959e-05f, -5.520989960e-05f, -5.140522804e-05f, -4.762803470e-05f, -4.387980617e-05f, -4.016199546e-05f, -3.647602174e-05f, -3.282326994e-05f,
-2.920509052e-05f, -2.562279916e-05f, -2.207767654e-05f, -1.857096810e-05f, -1.510388381e-05f, -1.167759804e-05f, -8.293249350e-06f, -4.951940350e-06f, -1.654737597e-06f, 1.597328525e-06f,
4.803263881e-06f, 7.962110648e-06f, 1.107294736e-05f, 1.413488894e-05f, 1.714708667e-05f, 2.010872824e-05f, 2.301903763e-05f, 2.587727512e-05f, 2.868273722e-05f, 3.143475653e-05f,
3.413270168e-05f, 3.677597718e-05f, 3.936402328e-05f, 4.189631583e-05f, 4.437236606e-05f, 4.679172045e-05f, 4.915396045e-05f, 5.145870230e-05f, 5.370559679e-05f, 5.589432897e-05f,
5.802461790e-05f, 6.009621637e-05f, 6.210891058e-05f, 6.406251985e-05f, 6.595689624e-05f, 6.779192428e-05f, 6.956752056e-05f, 7.128363337e-05f, 7.294024234e-05f, 7.453735803e-05f,
7.607502154e-05f, 7.755330405e-05f, 7.897230646e-05f, 8.033215892e-05f, 8.163302036e-05f, 8.287507807e-05f, 8.405854720e-05f, 8.518367033e-05f, 8.625071692e-05f, 8.725998288e-05f,
8.821179002e-05f, 8.910648556e-05f, 8.994444163e-05f, 9.072605472e-05f, 9.145174516e-05f, 9.212195658e-05f, 9.273715536e-05f, 9.329783012e-05f, 9.380449111e-05f, 9.425766969e-05f,
9.465791777e-05f, 9.500580723e-05f, 9.530192933e-05f, 9.554689418e-05f, 9.574133013e-05f, 9.588588322e-05f, 9.598121657e-05f, 9.602800981e-05f, 9.602695848e-05f, 9.597877349e-05f,
9.588418047e-05f, 9.574391922e-05f, 9.555874313e-05f, 9.532941855e-05f, 9.505672426e-05f, 9.474145083e-05f, 9.438440006e-05f, 9.398638441e-05f, 9.354822637e-05f, 9.307075794e-05f,
9.255482000e-05f, 9.200126176e-05f, 9.141094019e-05f, 9.078471942e-05f, 9.012347022e-05f, 8.942806939e-05f, 8.869939924e-05f, 8.793834701e-05f, 8.714580431e-05f, 8.632266662e-05f,
8.546983271e-05f, 8.458820411e-05f, 8.367868458e-05f, 8.274217961e-05f, 8.177959586e-05f, 8.079184068e-05f, 7.977982159e-05f, 7.874444578e-05f, 7.768661963e-05f, 7.660724819e-05f,
7.550723476e-05f, 7.438748036e-05f, 7.324888328e-05f, 7.209233865e-05f, 7.091873796e-05f, 6.972896865e-05f, 6.852391365e-05f, 6.730445094e-05f, 6.607145319e-05f, 6.482578732e-05f,
6.356831407e-05f, 6.229988768e-05f, 6.102135543e-05f, 5.973355734e-05f, 5.843732575e-05f, 5.713348499e-05f, 5.582285105e-05f, 5.450623121e-05f, 5.318442374e-05f, 5.185821756e-05f,
5.052839196e-05f, 4.919571629e-05f, 4.786094965e-05f, 4.652484066e-05f, 4.518812713e-05f, 4.385153586e-05f, 4.251578234e-05f, 4.118157056e-05f, 3.984959273e-05f, 3.852052909e-05f,
3.719504771e-05f, 3.587380425e-05f, 3.455744180e-05f, 3.324659070e-05f, 3.194186835e-05f, 3.064387906e-05f, 2.935321390e-05f, 2.807045056e-05f, 2.679615319e-05f, 2.553087233e-05f,
2.427514476e-05f, 2.302949337e-05f, 2.179442715e-05f, 2.057044100e-05f, 1.935801575e-05f, 1.815761802e-05f, 1.696970021e-05f, 1.579470044e-05f, 1.463304247e-05f, 1.348513575e-05f,
1.235137531e-05f, 1.123214182e-05f, 1.012780154e-05f, 9.038706330e-06f, 7.965193684e-06f, 6.907586728e-06f, 5.866194255e-06f, 4.841310764e-06f, 3.833216503e-06f, 2.842177519e-06f,
1.868445716e-06f, 9.122589295e-07f, -2.615900858e-08f, -9.465981827e-07f, -1.848862507e-06f, -2.732769630e-06f, -3.598150832e-06f, -4.444850917e-06f, -5.272728097e-06f, -6.081653872e-06f,
-6.871512899e-06f, -7.642202862e-06f, -8.393634332e-06f, -9.125730619e-06f, -9.838427626e-06f, -1.053167369e-05f, -1.120542942e-05f, -1.185966753e-05f, -1.249437268e-05f, -1.310954128e-05f,
-1.370518132e-05f, -1.428131221e-05f, -1.483796452e-05f, -1.537517989e-05f, -1.589301073e-05f, -1.639152010e-05f, -1.687078145e-05f, -1.733087846e-05f, -1.777190479e-05f, -1.819396389e-05f,
-1.859716877e-05f, -1.898164179e-05f, -1.934751444e-05f, -1.969492712e-05f, -2.002402890e-05f, -2.033497728e-05f, -2.062793802e-05f, -2.090308484e-05f, -2.116059923e-05f, -2.140067018e-05f,
-2.162349399e-05f, -2.182927400e-05f, -2.201822037e-05f, -2.219054982e-05f, -2.234648542e-05f, -2.248625633e-05f, -2.261009757e-05f, -2.271824978e-05f, -2.281095898e-05f, -2.288847634e-05f,
-2.295105790e-05f, -2.299896441e-05f, -2.303246101e-05f, -2.305181705e-05f, -2.305730582e-05f, -2.304920434e-05f, -2.302779311e-05f, -2.299335588e-05f, -2.294617942e-05f, -2.288655331e-05f,
-2.281476967e-05f, -2.273112298e-05f, -2.263590982e-05f, -2.252942867e-05f, -2.241197967e-05f, -2.228386443e-05f, -2.214538578e-05f, -2.199684761e-05f, -2.183855459e-05f, -2.167081201e-05f,
-2.149392557e-05f, -2.130820115e-05f, -2.111394467e-05f, -2.091146180e-05f, -2.070105788e-05f, -2.048303762e-05f, -2.025770499e-05f, -2.002536302e-05f, -1.978631358e-05f, -1.954085726e-05f,
-1.928929316e-05f, -1.903191873e-05f, -1.876902961e-05f, -1.850091945e-05f, -1.822787978e-05f, -1.795019983e-05f, -1.766816639e-05f, -1.738206365e-05f, -1.709217309e-05f, -1.679877329e-05f,
-1.650213984e-05f, -1.620254520e-05f, -1.590025854e-05f, -1.559554566e-05f, -1.528866884e-05f, -1.497988675e-05f, -1.466945431e-05f, -1.435762262e-05f, -1.404463883e-05f, -1.373074603e-05f,
-1.341618320e-05f, -1.310118507e-05f, -1.278598210e-05f, -1.247080031e-05f, -1.215586127e-05f, -1.184138203e-05f, -1.152757498e-05f, -1.121464786e-05f, -1.090280369e-05f, -1.059224065e-05f,
-1.028315211e-05f, -9.975726524e-06f, -9.670147411e-06f, -9.366593307e-06f, -9.065237732e-06f, -8.766249151e-06f, -8.469790953e-06f, -8.176021421e-06f, -7.885093711e-06f, -7.597155839e-06f,
-7.312350661e-06f, -7.030815871e-06f, -6.752683989e-06f, -6.478082358e-06f, -6.207133152e-06f, -5.939953373e-06f, -5.676654863e-06f, -5.417344314e-06f, -5.162123286e-06f, -4.911088220e-06f,
-4.664330463e-06f, -4.421936292e-06f, -4.183986942e-06f, -3.950558636e-06f, -3.721722618e-06f, -3.497545191e-06f, -3.278087756e-06f, -3.063406857e-06f, -2.853554220e-06f, -2.648576807e-06f,
-2.448516863e-06f, -2.253411969e-06f, -2.063295098e-06f, -1.878194673e-06f, -1.698134627e-06f, -1.523134463e-06f, -1.353209320e-06f, -1.188370042e-06f, -1.028623241e-06f, -8.739713713e-07f,
-7.244128008e-07f, -5.799418844e-07f, -4.405490400e-07f, -3.062208261e-07f, -1.769400201e-07f, -5.268569926e-08f
};
AUD_NAMESPACE_END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/LinearResample.h"
#include "respec/LinearResampleReader.h"
AUD_NAMESPACE_BEGIN
LinearResample::LinearResample(std::shared_ptr<ISound> sound, DeviceSpecs specs) :
SpecsChanger(sound, specs)
{
}
std::shared_ptr<IReader> LinearResample::createReader()
{
return std::shared_ptr<IReader>(new LinearResampleReader(getReader(), m_specs.rate));
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,174 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/LinearResampleReader.h"
#include <cmath>
#include <cstring>
AUD_NAMESPACE_BEGIN
LinearResampleReader::LinearResampleReader(std::shared_ptr<IReader> reader, SampleRate rate) :
ResampleReader(reader, rate),
m_channels(reader->getSpecs().channels),
m_cache_pos(0),
m_cache_ok(false)
{
Specs specs = { rate, m_channels };
m_cache.resize(2 * AUD_SAMPLE_SIZE(specs));
}
void LinearResampleReader::seek(int position)
{
position = std::floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
m_reader->seek(position);
m_cache_ok = false;
m_cache_pos = 0;
}
int LinearResampleReader::getLength() const
{
return std::floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
}
int LinearResampleReader::getPosition() const
{
return std::floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 1 : 0))
* m_rate / m_reader->getSpecs().rate);
}
Specs LinearResampleReader::getSpecs() const
{
Specs specs = m_reader->getSpecs();
specs.rate = m_rate;
return specs;
}
void LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
{
if(length == 0)
return;
Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
int size = length;
float factor = m_rate / m_reader->getSpecs().rate;
float spos = 0.0f;
sample_t low, high;
eos = false;
// check for channels changed
if(specs.channels != m_channels)
{
m_cache.resize(2 * samplesize);
m_channels = specs.channels;
m_cache_ok = false;
}
if(factor == 1 && (!m_cache_ok || m_cache_pos == 1))
{
// can read directly!
m_reader->read(length, eos, buffer);
if(length > 0)
{
std::memcpy(m_cache.getBuffer() + m_channels, buffer + m_channels * (length - 1), samplesize);
m_cache_pos = 1;
m_cache_ok = true;
}
return;
}
int len;
sample_t* buf;
if(m_cache_ok)
{
int need = std::ceil(length / factor + m_cache_pos) - 1;
len = need;
m_buffer.assureSize((len + 2) * samplesize);
buf = m_buffer.getBuffer();
std::memcpy(buf, m_cache.getBuffer(), 2 * samplesize);
m_reader->read(len, eos, buf + 2 * m_channels);
if(len < need)
length = std::floor((len + 1 - m_cache_pos) * factor);
}
else
{
m_cache_pos = 1 - 1 / factor;
int need = std::ceil(length / factor + m_cache_pos);
len = need;
m_buffer.assureSize((len + 1) * samplesize);
buf = m_buffer.getBuffer();
std::memset(buf, 0, samplesize);
m_reader->read(len, eos, buf + m_channels);
if(len == 0)
{
length = 0;
return;
}
if(len < need)
{
length = std::floor((len - m_cache_pos) * factor);
}
m_cache_ok = true;
}
if(length == 0)
return;
for(int channel = 0; channel < m_channels; channel++)
{
for(int i = 0; i < length; i++)
{
spos = (i + 1) / factor + m_cache_pos;
low = buf[(int)std::floor(spos) * m_channels + channel];
high = buf[(int)std::ceil(spos) * m_channels + channel];
buffer[i * m_channels + channel] = low + (spos - std::floor(spos)) * (high - low);
}
}
if(std::floor(spos) == spos)
{
std::memcpy(m_cache.getBuffer() + m_channels, buf + int(std::floor(spos)) * m_channels, samplesize);
m_cache_pos = 1;
}
else
{
std::memcpy(m_cache.getBuffer(), buf + int(std::floor(spos)) * m_channels, 2 * samplesize);
m_cache_pos = spos - std::floor(spos);
}
eos &= length < size;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,118 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/Mixer.h"
#include <algorithm>
#include <cstring>
AUD_NAMESPACE_BEGIN
Mixer::Mixer(DeviceSpecs specs)
{
setSpecs(specs);
}
DeviceSpecs Mixer::getSpecs() const
{
return m_specs;
}
void Mixer::setSpecs(Specs specs)
{
m_specs.specs = specs;
}
void Mixer::setSpecs(DeviceSpecs specs)
{
m_specs = specs;
switch(m_specs.format)
{
case FORMAT_U8:
m_convert = convert_float_u8;
break;
case FORMAT_S16:
m_convert = convert_float_s16;
break;
case FORMAT_S24:
#ifdef __BIG_ENDIAN__
m_convert = convert_float_s24_be;
#else
m_convert = convert_float_s24_le;
#endif
break;
case FORMAT_S32:
m_convert = convert_float_s32;
break;
case FORMAT_FLOAT32:
m_convert = convert_copy<float>;
break;
case FORMAT_FLOAT64:
m_convert = convert_float_double;
break;
default:
break;
}
}
void Mixer::clear(int length)
{
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
m_length = length;
std::memset(m_buffer.getBuffer(), 0, length * AUD_SAMPLE_SIZE(m_specs));
}
void Mixer::mix(sample_t* buffer, int start, int length, float volume)
{
sample_t* out = m_buffer.getBuffer();
length = (std::min(m_length, length + start) - start) * m_specs.channels;
start *= m_specs.channels;
for(int i = 0; i < length; i++)
out[i + start] += buffer[i] * volume;
}
void Mixer::mix(sample_t* buffer, int start, int length, float volume_to, float volume_from)
{
sample_t* out = m_buffer.getBuffer();
length = (std::min(m_length, length + start) - start);
for(int i = 0; i < length; i++)
{
float volume = volume_from * (1.0f - i / float(length)) + volume_to * (i / float(length));
for(int c = 0; c < m_specs.channels; c++)
out[(i + start) * m_specs.channels + c] += buffer[i * m_specs.channels + c] * volume;
}
}
void Mixer::read(data_t* buffer, float volume)
{
sample_t* out = m_buffer.getBuffer();
for(int i = 0; i < m_length * m_specs.channels; i++)
out[i] *= volume;
m_convert(buffer, (data_t*) out, m_length * m_specs.channels);
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/ResampleReader.h"
AUD_NAMESPACE_BEGIN
ResampleReader::ResampleReader(std::shared_ptr<IReader> reader, SampleRate rate) :
EffectReader(reader), m_rate(rate)
{
}
void ResampleReader::setRate(SampleRate rate)
{
m_rate = rate;
}
SampleRate ResampleReader::getRate()
{
return m_rate;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "respec/SpecsChanger.h"
AUD_NAMESPACE_BEGIN
std::shared_ptr<IReader> SpecsChanger::getReader() const
{
return m_sound->createReader();
}
SpecsChanger::SpecsChanger(std::shared_ptr<ISound> sound,
DeviceSpecs specs) :
m_specs(specs), m_sound(sound)
{
}
DeviceSpecs SpecsChanger::getSpecs() const
{
return m_specs;
}
std::shared_ptr<ISound> SpecsChanger::getSound() const
{
return m_sound;
}
AUD_NAMESPACE_END

View File

@@ -0,0 +1,121 @@
#!/usr/bin/python
################################################################################
# Copyright 2009-2023 Jörg Müller
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
# high quality: sinc filter coefficients, Nz = 136, L = 2304, freq = 0.963904, Kaiser Window B = 16
# medium quality: sinc filter coefficients, Nz = 42, L = 500, freq = 0.916636, Kaiser Window B = 12
# low quality: sinc filter coefficients, Nz = 16, L = 128, freq = 0.834068, Kaiser Window B = 10
import numpy as np
import scipy
L = 2304
Nz = 136
B = 16
freq = Nz / (Nz + B / np.pi)
print(f'// sinc filter coefficients, Nz = {Nz}, L = {L}, freq = {freq:.6f}, Kaiser Window B = {B}')
Nz = Nz / freq
a = freq * np.sinc(freq * np.arange(0, Nz, 1/L))
M = len(a)*2-1
b = scipy.signal.windows.kaiser(M, B)
b = b[len(a)-1:]
y = a * b
# print filter coefficients from y
if False:
print(f'AUD_NAMESPACE_BEGIN')
print(f'const int JOSResampleReader::m_len_PRESET = {int(L*Nz)};')
print(f'const int JOSResampleReader::m_L_PRESET = {L};')
print(f'const float JOSResampleReader::m_coeff_PRESET[m_len_PRESET + 1] = {{')
for idx, val in enumerate(y):
print(f'{val:.9e}f', end=', ')
if (idx + 1) % 10 == 0:
print("\n", end='')
print(f'}};')
print(f'AUD_NAMESPACE_END')
# visualize filter
import matplotlib.pyplot as plt
mid = len(y)
res = np.concatenate([y[:0:-1], y])
f1 = L
f2 = 1
Fs1 = L
Fs2 = 2
area = mid - 1
t = (np.arange(1, area*2+1) - area) / (Fs1 * f2)
plt.figure()
plt.plot(t, res[mid - area:mid + area])
plt.xlim([t[0], t[-1]])
plt.ylim(np.array([np.min(res), np.max(res)]) * 1.05)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('Response')
fftres = np.fft.fft(res / f1)
f = np.arange(len(fftres)) * Fs2 * f1 / len(fftres)
plt.figure()
plt.plot(f, np.log10(np.abs(fftres))*20)
plt.xlim([0, Fs2])
plt.ylim([-200, 0])
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude [dB]')
plt.title('Magnitude')
plt.figure()
plt.plot(f, np.log10(np.abs(fftres)/np.abs(fftres[0]))*20)
plt.xlim(np.array([0, Fs2/2])*1.1)
plt.ylim([-3, 1.5])
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude [dB]')
plt.title('Passband')
plt.figure()
plt.plot(f, np.log10(np.abs(fftres)/np.abs(fftres[0]))*20)
plt.xlim(np.array([0.8, 1.1])*Fs2/2)
plt.ylim([-100, 6])
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude [dB]')
plt.title('Transition')
phi = np.angle(fftres);
phi -= (phi > np.pi / 2) * np.pi;
phi += (phi < -np.pi / 2) * np.pi;
plt.figure()
plt.plot(f, phi * 180 / np.pi)
plt.xlim([0, Fs2/2])
plt.ylim([-180, 180])
plt.xlabel('Frequency [Hz]')
plt.ylabel('Phase [deg]')
plt.title('Phase')
plt.show()

Some files were not shown because too many files have changed in this diff Show More