Added an AudioSpan and AudioBuffer, to better handle the memory for mono/stereo samples
This commit is contained in:
parent
b1ef2c26bd
commit
c1d2384e09
13 changed files with 204 additions and 139 deletions
|
|
@ -21,7 +21,7 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "StereoSpan.h"
|
#include "AudioSpan.h"
|
||||||
#include "Synth.h"
|
#include "Synth.h"
|
||||||
#include <absl/flags/parse.h>
|
#include <absl/flags/parse.h>
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
|
|
@ -116,13 +116,9 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StereoSpan<float> output {
|
auto leftOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort1, numFrames));
|
||||||
jack_port_get_buffer(outputPort1, numFrames),
|
auto rightOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort2, numFrames));
|
||||||
jack_port_get_buffer(outputPort2, numFrames),
|
synth->renderBlock({ { leftOutput, rightOutput }, numFrames });
|
||||||
numFrames
|
|
||||||
};
|
|
||||||
|
|
||||||
synth->renderBlock(output);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +152,7 @@ static void done(int sig [[maybe_unused]])
|
||||||
std::cout << "Signal received" << '\n';
|
std::cout << "Signal received" << '\n';
|
||||||
shouldClose = true;
|
shouldClose = true;
|
||||||
// if (client != nullptr)
|
// if (client != nullptr)
|
||||||
|
|
||||||
// exit(0);
|
// exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +255,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
while (!shouldClose)
|
while (!shouldClose)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
std::cout << "Closing..." << '\n';
|
std::cout << "Closing..." << '\n';
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,14 @@ public:
|
||||||
buffers[i] = std::make_unique<buffer_type>(numFrames);
|
buffers[i] = std::make_unique<buffer_type>(numFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool resize(size_type newSize)
|
||||||
|
{
|
||||||
|
bool returnedOK = true;
|
||||||
|
for (auto i = 0; i < numChannels; ++i)
|
||||||
|
returnedOK &= buffers[i]->resize(newSize);
|
||||||
|
return returnedOK;
|
||||||
|
}
|
||||||
|
|
||||||
iterator channelWriter(int channelIndex)
|
iterator channelWriter(int channelIndex)
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex < numChannels)
|
ASSERT(channelIndex < numChannels)
|
||||||
|
|
@ -68,7 +76,7 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator channelReader(int channelIndex)
|
const_iterator channelReader(int channelIndex) const
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex < numChannels)
|
ASSERT(channelIndex < numChannels)
|
||||||
if (channelIndex < numChannels)
|
if (channelIndex < numChannels)
|
||||||
|
|
@ -77,7 +85,7 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator channelReaderEnd(int channelIndex)
|
const_iterator channelReaderEnd(int channelIndex) const
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex < numChannels)
|
ASSERT(channelIndex < numChannels)
|
||||||
if (channelIndex < numChannels)
|
if (channelIndex < numChannels)
|
||||||
|
|
@ -86,7 +94,7 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Span<value_type> getSpan(int channelIndex)
|
absl::Span<value_type> getSpan(int channelIndex) const
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex < numChannels)
|
ASSERT(channelIndex < numChannels)
|
||||||
if (channelIndex < numChannels)
|
if (channelIndex < numChannels)
|
||||||
|
|
@ -95,45 +103,45 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Span<const value_type> getConstSpan(int channelIndex)
|
absl::Span<const value_type> getConstSpan(int channelIndex) const
|
||||||
{
|
{
|
||||||
return getSpan(channelIndex);
|
return getSpan(channelIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChannel()
|
void addChannel()
|
||||||
{
|
{
|
||||||
if (numChannels < MaxChannels)
|
if (numChannels < MaxChannels)
|
||||||
buffers[numChannels++] = std::make_unique<buffer_type>(numFrames);
|
buffers[numChannels++] = std::make_unique<buffer_type>(numFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type getNumFrames()
|
size_type getNumFrames() const
|
||||||
{
|
{
|
||||||
return numFrames;
|
return numFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type getNumChannels()
|
int getNumChannels() const
|
||||||
{
|
{
|
||||||
return numChannels;
|
return numChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty()
|
bool empty() const
|
||||||
{
|
{
|
||||||
return numFrames == 0;
|
return numFrames == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& getSample(int channelIndex, size_type frameIndex)
|
Type& getSample(int channelIndex, size_type frameIndex)
|
||||||
{
|
{
|
||||||
// Uhoh
|
// Uhoh
|
||||||
ASSERT(buffers[channelIndex] != nullptr);
|
ASSERT(buffers[channelIndex] != nullptr);
|
||||||
ASSERT(frameIndex < numFrames);
|
ASSERT(frameIndex < numFrames);
|
||||||
|
|
||||||
return *(buffers[channelIndex]->data() + frameIndex);
|
return *(buffers[channelIndex]->data() + frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& operator()(int channelIndex, size_type frameIndex)
|
Type& operator()(int channelIndex, size_type frameIndex)
|
||||||
{
|
{
|
||||||
return getSample(channelIndex, frameIndex);
|
return getSample(channelIndex, frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using buffer_type = Buffer<Type, Alignment>;
|
using buffer_type = Buffer<Type, Alignment>;
|
||||||
|
|
|
||||||
|
|
@ -39,37 +39,48 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioSpan(const std::array<Type*, MaxChannels>& spans, int numChannels, size_type offset, size_type size)
|
||||||
|
: numFrames(size)
|
||||||
|
, numChannels(numChannels)
|
||||||
|
{
|
||||||
|
ASSERT(static_cast<unsigned int>(numChannels) <= MaxChannels);
|
||||||
|
for (auto i = 0; i < numChannels; ++i)
|
||||||
|
this->spans[i] = spans[i] + offset;
|
||||||
|
}
|
||||||
|
|
||||||
AudioSpan(std::initializer_list<Type*> spans, size_type numFrames)
|
AudioSpan(std::initializer_list<Type*> spans, size_type numFrames)
|
||||||
: numFrames(numFrames)
|
: numFrames(numFrames)
|
||||||
, numChannels(spans.size())
|
, numChannels(spans.size())
|
||||||
{
|
{
|
||||||
static_assert(spans.size() <= MaxChannels);
|
ASSERT(spans.size() <= MaxChannels);
|
||||||
for (auto i = 0; i < spans.size(); i++) {
|
auto newSpan = spans.begin();
|
||||||
|
auto thisSpan = this->spans.begin();
|
||||||
|
for (; newSpan < spans.end() && thisSpan < this->spans.end(); thisSpan++, newSpan++) {
|
||||||
// This will not end well...
|
// This will not end well...
|
||||||
ASSERT(spans[i] != nullptr);
|
ASSERT(*newSpan != nullptr);
|
||||||
this->spans[i] = spans[i];
|
*thisSpan = *newSpan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSpan(std::initializer_list<absl::Span<Type>> spans)
|
AudioSpan(std::initializer_list<absl::Span<Type>> spans)
|
||||||
: numChannels(spans.size())
|
: numChannels(spans.size())
|
||||||
{
|
{
|
||||||
static_assert(spans.size() <= MaxChannels);
|
ASSERT(spans.size() <= MaxChannels);
|
||||||
auto size = absl::Span<Type>::npos;
|
auto size = absl::Span<Type>::npos;
|
||||||
for (auto i = 0; i < spans.size(); i++) {
|
auto newSpan = spans.begin();
|
||||||
// This will not end well...
|
auto thisSpan = this->spans.begin();
|
||||||
ASSERT(spans[i] != nullptr);
|
for (; newSpan < spans.end() && thisSpan < this->spans.end(); thisSpan++, newSpan++) {
|
||||||
this->spans[i] = spans[i].data();
|
*thisSpan = newSpan->data();
|
||||||
size = std::min(size, spans[i].size());
|
size = std::min(size, newSpan->size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class U, unsigned int N, unsigned int Alignment, typename = std::enable_if<N <= MaxChannels>>
|
template <class U, unsigned int N, unsigned int Alignment, typename = std::enable_if<N <= MaxChannels>>
|
||||||
AudioSpan(const AudioBuffer<U, N, Alignment>& audioBuffer)
|
AudioSpan(AudioBuffer<U, N, Alignment>& audioBuffer)
|
||||||
: numFrames(audioBuffer.getNumFrames())
|
: numFrames(audioBuffer.getNumFrames())
|
||||||
, numChannels(audioBuffer.getNumChannels())
|
, numChannels(audioBuffer.getNumChannels())
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < N; i++) {
|
for (int i = 0; i < numChannels; i++) {
|
||||||
if constexpr (std::is_const<Type>::value)
|
if constexpr (std::is_const<Type>::value)
|
||||||
this->spans[i] = audioBuffer.channelReader(i);
|
this->spans[i] = audioBuffer.channelReader(i);
|
||||||
else
|
else
|
||||||
|
|
@ -82,7 +93,7 @@ public:
|
||||||
: numFrames(other.getNumFrames())
|
: numFrames(other.getNumFrames())
|
||||||
, numChannels(other.getNumChannels())
|
, numChannels(other.getNumChannels())
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < N; i++) {
|
for (int i = 0; i < numChannels; i++) {
|
||||||
this->spans[i] = other.getChannel(i);
|
this->spans[i] = other.getChannel(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +116,7 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Span<const std::remove_cv<Type>> getConstSpan(int channelIndex)
|
absl::Span<const Type> getConstSpan(int channelIndex)
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex < numChannels);
|
ASSERT(channelIndex < numChannels);
|
||||||
if (channelIndex < numChannels)
|
if (channelIndex < numChannels)
|
||||||
|
|
@ -117,23 +128,23 @@ public:
|
||||||
void fill(Type value) noexcept
|
void fill(Type value) noexcept
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numChannels; ++i)
|
for (int i = 0; i < numChannels; ++i)
|
||||||
::fill<Type>({ getChannel(i), numFrames }, value);
|
::fill<Type>(getSpan(i), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyGain(absl::Span<const Type> gain) noexcept
|
void applyGain(absl::Span<const Type> gain) noexcept
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numChannels; ++i)
|
for (int i = 0; i < numChannels; ++i)
|
||||||
::applyGain<Type>({ getChannel(i), numFrames }, gain);
|
::applyGain<Type>(gain, getSpan(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyGain(Type gain) noexcept
|
void applyGain(Type gain) noexcept
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numChannels; ++i)
|
for (int i = 0; i < numChannels; ++i)
|
||||||
::applyGain<Type>({ getChannel(i), numFrames }, gain);
|
::applyGain<Type>(gain, getSpan(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class U, unsigned int N, typename = std::enable_if<N <= MaxChannels>>
|
template <class U, unsigned int N, typename = std::enable_if<N <= MaxChannels>>
|
||||||
void add(const AudioSpan<U, N>& other)
|
void add(AudioSpan<U, N>& other)
|
||||||
{
|
{
|
||||||
ASSERT(other.getNumChannels() == numChannels);
|
ASSERT(other.getNumChannels() == numChannels);
|
||||||
if (other.getNumChannels() == numChannels) {
|
if (other.getNumChannels() == numChannels) {
|
||||||
|
|
@ -143,7 +154,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class U, unsigned int N, typename = std::enable_if<N <= MaxChannels>>
|
template <class U, unsigned int N, typename = std::enable_if<N <= MaxChannels>>
|
||||||
void copy(const AudioSpan<U, N>& other)
|
void copy(AudioSpan<U, N>& other)
|
||||||
{
|
{
|
||||||
ASSERT(other.getNumChannels() == numChannels);
|
ASSERT(other.getNumChannels() == numChannels);
|
||||||
if (other.getNumChannels() == numChannels) {
|
if (other.getNumChannels() == numChannels) {
|
||||||
|
|
@ -162,6 +173,24 @@ public:
|
||||||
return numChannels;
|
return numChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioSpan<Type> first(size_type length)
|
||||||
|
{
|
||||||
|
ASSERT(length <= numFrames);
|
||||||
|
return { spans, numChannels, 0, length };
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSpan<Type> last(size_type length)
|
||||||
|
{
|
||||||
|
ASSERT(length <= numFrames);
|
||||||
|
return { spans, numChannels, numFrames - length, length };
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioSpan<Type> subspan(size_type offset, size_type length)
|
||||||
|
{
|
||||||
|
ASSERT(length + offset <= numFrames);
|
||||||
|
return { spans, numChannels, offset, length };
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<Type*, MaxChannels> spans;
|
std::array<Type*, MaxChannels> spans;
|
||||||
size_type numFrames { 0 };
|
size_type numFrames { 0 };
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace sfz {
|
||||||
namespace config {
|
namespace config {
|
||||||
constexpr float defaultSampleRate { 48000 };
|
constexpr float defaultSampleRate { 48000 };
|
||||||
constexpr int defaultSamplesPerBlock { 1024 };
|
constexpr int defaultSamplesPerBlock { 1024 };
|
||||||
constexpr int preloadSize { 8192 * 2 };
|
constexpr int preloadSize { 8192 };
|
||||||
constexpr int numChannels { 2 };
|
constexpr int numChannels { 2 };
|
||||||
constexpr int numVoices { 64 };
|
constexpr int numVoices { 64 };
|
||||||
constexpr int numLoadingThreads { 4 };
|
constexpr int numLoadingThreads { 4 };
|
||||||
|
|
|
||||||
|
|
@ -22,26 +22,27 @@
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "FilePool.h"
|
#include "FilePool.h"
|
||||||
|
#include "AudioBuffer.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
#include <sndfile.hh>
|
#include <sndfile.hh>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void readFromFile(SndfileHandle& sndFile, int numFrames, StereoBuffer<T>& output)
|
std::unique_ptr<AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, int numFrames)
|
||||||
{
|
{
|
||||||
|
auto returnedBuffer = std::make_unique<AudioBuffer<T>>(sndFile.channels(), numFrames);
|
||||||
if (sndFile.channels() == 1) {
|
if (sndFile.channels() == 1) {
|
||||||
auto tempReadBuffer = std::make_unique<Buffer<float>>(numFrames);
|
sndFile.readf(returnedBuffer->channelWriter(0), numFrames);
|
||||||
sndFile.readf(tempReadBuffer->data(), numFrames);
|
|
||||||
std::copy(tempReadBuffer->begin(), tempReadBuffer->end(), output.begin(Channel::left));
|
|
||||||
std::copy(tempReadBuffer->begin(), tempReadBuffer->end(), output.begin(Channel::right));
|
|
||||||
} else if (sndFile.channels() == 2) {
|
} else if (sndFile.channels() == 2) {
|
||||||
auto tempReadBuffer = std::make_unique<Buffer<float>>(2 * numFrames);
|
auto tempReadBuffer = std::make_unique<AudioBuffer<float>>(1, 2 * numFrames);
|
||||||
sndFile.readf(tempReadBuffer->data(), numFrames);
|
sndFile.readf(tempReadBuffer->channelWriter(0), numFrames);
|
||||||
output.readInterleaved(*tempReadBuffer);
|
::readInterleaved<float>(tempReadBuffer->getSpan(0), returnedBuffer->getSpan(0), returnedBuffer->getSpan(1));
|
||||||
}
|
}
|
||||||
|
return returnedBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(std::string_view filename) noexcept
|
std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(std::string_view filename) noexcept
|
||||||
|
|
@ -52,12 +53,11 @@ std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(
|
||||||
|
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
if (sndFile.channels() != 1 && sndFile.channels() != 2) {
|
if (sndFile.channels() != 1 && sndFile.channels() != 2) {
|
||||||
DBG("Missing logic for " << sndFile.channels() << ", discarding sample " << filename);
|
DBG("Missing logic for " << sndFile.channels() << " channels, discarding sample " << filename);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInformation returnedValue;
|
FileInformation returnedValue;
|
||||||
returnedValue.numChannels = sndFile.channels();
|
|
||||||
returnedValue.end = static_cast<uint32_t>(sndFile.frames());
|
returnedValue.end = static_cast<uint32_t>(sndFile.frames());
|
||||||
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
|
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
|
||||||
|
|
||||||
|
|
@ -78,8 +78,7 @@ std::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(
|
||||||
if (preloadedData.contains(filename)) {
|
if (preloadedData.contains(filename)) {
|
||||||
returnedValue.preloadedData = preloadedData[filename];
|
returnedValue.preloadedData = preloadedData[filename];
|
||||||
} else {
|
} else {
|
||||||
returnedValue.preloadedData = std::make_shared<StereoBuffer<float>>(preloadedSize);
|
returnedValue.preloadedData = std::shared_ptr<AudioBuffer<float>>(readFromFile<float>(sndFile, preloadedSize));
|
||||||
readFromFile(sndFile, preloadedSize, *returnedValue.preloadedData);
|
|
||||||
preloadedData[filename] = returnedValue.preloadedData;
|
preloadedData[filename] = returnedValue.preloadedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +96,7 @@ void sfz::FilePool::loadingThread() noexcept
|
||||||
{
|
{
|
||||||
FileLoadingInformation fileToLoad {};
|
FileLoadingInformation fileToLoad {};
|
||||||
while (!quitThread) {
|
while (!quitThread) {
|
||||||
if (!loadingQueue.wait_dequeue_timed(fileToLoad, 1ms))
|
if (!loadingQueue.wait_dequeue_timed(fileToLoad, 100ms))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fileToLoad.voice == nullptr) {
|
if (fileToLoad.voice == nullptr) {
|
||||||
|
|
@ -113,8 +112,7 @@ void sfz::FilePool::loadingThread() noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
auto fileLoaded = std::make_unique<StereoBuffer<float>>(fileToLoad.numFrames);
|
auto fileLoaded = std::make_unique<AudioBuffer<float>>(sndFile.channels(), fileToLoad.numFrames);
|
||||||
readFromFile(sndFile, fileToLoad.numFrames, *fileLoaded);
|
fileToLoad.voice->setFileData(readFromFile<float>(sndFile, fileToLoad.numFrames));
|
||||||
fileToLoad.voice->setFileData(std::move(fileLoaded));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include "StereoBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
#include "Voice.h"
|
#include "Voice.h"
|
||||||
#include "readerwriterqueue.h"
|
#include "readerwriterqueue.h"
|
||||||
#include <absl/container/flat_hash_map.h>
|
#include <absl/container/flat_hash_map.h>
|
||||||
|
|
@ -50,12 +50,11 @@ public:
|
||||||
size_t getNumPreloadedSamples() const noexcept { return preloadedData.size(); }
|
size_t getNumPreloadedSamples() const noexcept { return preloadedData.size(); }
|
||||||
|
|
||||||
struct FileInformation {
|
struct FileInformation {
|
||||||
int numChannels { 1 };
|
|
||||||
uint32_t end { Default::sampleEndRange.getEnd() };
|
uint32_t end { Default::sampleEndRange.getEnd() };
|
||||||
uint32_t loopBegin { Default::loopRange.getStart() };
|
uint32_t loopBegin { Default::loopRange.getStart() };
|
||||||
uint32_t loopEnd { Default::loopRange.getEnd() };
|
uint32_t loopEnd { Default::loopRange.getEnd() };
|
||||||
double sampleRate { config::defaultSampleRate };
|
double sampleRate { config::defaultSampleRate };
|
||||||
std::shared_ptr<StereoBuffer<float>> preloadedData;
|
std::shared_ptr<AudioBuffer<float>> preloadedData;
|
||||||
};
|
};
|
||||||
std::optional<FileInformation> getFileInformation(std::string_view filename) noexcept;
|
std::optional<FileInformation> getFileInformation(std::string_view filename) noexcept;
|
||||||
void enqueueLoading(Voice* voice, std::string_view sample, int numFrames) noexcept;
|
void enqueueLoading(Voice* voice, std::string_view sample, int numFrames) noexcept;
|
||||||
|
|
@ -71,7 +70,7 @@ private:
|
||||||
void loadingThread() noexcept;
|
void loadingThread() noexcept;
|
||||||
std::thread fileLoadingThread;
|
std::thread fileLoadingThread;
|
||||||
bool quitThread { false };
|
bool quitThread { false };
|
||||||
absl::flat_hash_map<std::string_view, std::shared_ptr<StereoBuffer<float>>> preloadedData;
|
absl::flat_hash_map<std::string_view, std::shared_ptr<AudioBuffer<float>>> preloadedData;
|
||||||
LEAK_DETECTOR(FilePool);
|
LEAK_DETECTOR(FilePool);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
|
#include "MathHelpers.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
|
|
@ -651,7 +652,10 @@ bool sfz::Region::canUsePreloadedData() const noexcept
|
||||||
|
|
||||||
bool sfz::Region::isStereo() const noexcept
|
bool sfz::Region::isStereo() const noexcept
|
||||||
{
|
{
|
||||||
return this->numChannels == 2;
|
if (isGenerator())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return (this->preloadedData->getNumChannels() == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
#include "EGDescription.h"
|
#include "EGDescription.h"
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "StereoBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
@ -148,9 +148,7 @@ struct Region {
|
||||||
EGDescription filterEG;
|
EGDescription filterEG;
|
||||||
|
|
||||||
double sampleRate { config::defaultSampleRate };
|
double sampleRate { config::defaultSampleRate };
|
||||||
int numChannels { 1 };
|
std::shared_ptr<AudioBuffer<float>> preloadedData { nullptr };
|
||||||
std::shared_ptr<StereoBuffer<float>> preloadedData { nullptr };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool keySwitched { true };
|
bool keySwitched { true };
|
||||||
bool previousKeySwitched { true };
|
bool previousKeySwitched { true };
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,6 @@ bool sfz::Synth::loadSfzFile(const std::filesystem::path& filename)
|
||||||
lastRegion--;
|
lastRegion--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
region->numChannels = fileInformation->numChannels;
|
|
||||||
region->sampleEnd = std::min(region->sampleEnd, fileInformation->end);
|
region->sampleEnd = std::min(region->sampleEnd, fileInformation->end);
|
||||||
region->loopRange.shrinkIfSmaller(fileInformation->loopBegin, fileInformation->loopEnd);
|
region->loopRange.shrinkIfSmaller(fileInformation->loopBegin, fileInformation->loopEnd);
|
||||||
region->preloadedData = fileInformation->preloadedData;
|
region->preloadedData = fileInformation->preloadedData;
|
||||||
|
|
@ -274,11 +272,11 @@ void sfz::Synth::setSampleRate(float sampleRate) noexcept
|
||||||
voice->setSampleRate(sampleRate);
|
voice->setSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Synth::renderBlock(StereoSpan<float> buffer) noexcept
|
void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
ScopedFTZ ftz;
|
ScopedFTZ ftz;
|
||||||
buffer.fill(0.0f);
|
buffer.fill(0.0f);
|
||||||
StereoSpan<float> tempSpan { tempBuffer, buffer.size() };
|
auto tempSpan = AudioSpan<float>(tempBuffer).first(buffer.getNumFrames());
|
||||||
for (auto& voice : voices) {
|
for (auto& voice : voices) {
|
||||||
voice->renderBlock(tempSpan);
|
voice->renderBlock(tempSpan);
|
||||||
buffer.add(tempSpan);
|
buffer.add(tempSpan);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include "Parser.h"
|
#include "Parser.h"
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include "StereoSpan.h"
|
#include "AudioSpan.h"
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
@ -51,7 +51,7 @@ public:
|
||||||
|
|
||||||
void setSamplesPerBlock(int samplesPerBlock) noexcept;
|
void setSamplesPerBlock(int samplesPerBlock) noexcept;
|
||||||
void setSampleRate(float sampleRate) noexcept;
|
void setSampleRate(float sampleRate) noexcept;
|
||||||
void renderBlock(StereoSpan<float> buffer) noexcept;
|
void renderBlock(AudioSpan<float> buffer) noexcept;
|
||||||
void noteOn(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
void noteOn(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
||||||
void noteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
void noteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
||||||
void cc(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept;
|
void cc(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept;
|
||||||
|
|
@ -91,7 +91,7 @@ private:
|
||||||
std::array<RegionPtrVector, 128> noteActivationLists;
|
std::array<RegionPtrVector, 128> noteActivationLists;
|
||||||
std::array<RegionPtrVector, 128> ccActivationLists;
|
std::array<RegionPtrVector, 128> ccActivationLists;
|
||||||
|
|
||||||
StereoBuffer<float> tempBuffer { config::defaultSamplesPerBlock };
|
AudioBuffer<float> tempBuffer { 2, config::defaultSamplesPerBlock };
|
||||||
int samplesPerBlock { config::defaultSamplesPerBlock };
|
int samplesPerBlock { config::defaultSamplesPerBlock };
|
||||||
float sampleRate { config::defaultSampleRate };
|
float sampleRate { config::defaultSampleRate };
|
||||||
|
|
||||||
|
|
|
||||||
107
sfizz/Voice.cpp
107
sfizz/Voice.cpp
|
|
@ -57,7 +57,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
|
||||||
if (region->amplitudeCC)
|
if (region->amplitudeCC)
|
||||||
baseGain *= normalizeCC(ccState[region->amplitudeCC->first]) * normalizePercents(region->amplitudeCC->second);
|
baseGain *= normalizeCC(ccState[region->amplitudeCC->first]) * normalizePercents(region->amplitudeCC->second);
|
||||||
amplitudeEnvelope.reset(baseGain);
|
amplitudeEnvelope.reset(baseGain);
|
||||||
|
|
||||||
sourcePosition = region->getOffset();
|
sourcePosition = region->getOffset();
|
||||||
initialDelay = delay + region->getDelay();
|
initialDelay = delay + region->getDelay();
|
||||||
baseFrequency = midiNoteFrequency(number) * pitchRatio;
|
baseFrequency = midiNoteFrequency(number) * pitchRatio;
|
||||||
|
|
@ -80,8 +80,9 @@ void sfz::Voice::prepareEGEnvelope(int delay, uint8_t velocity) noexcept
|
||||||
normalizePercents(region->amplitudeEG.getStart(ccState, velocity)));
|
normalizePercents(region->amplitudeEG.getStart(ccState, velocity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::setFileData(std::unique_ptr<StereoBuffer<float>> file) noexcept
|
void sfz::Voice::setFileData(std::unique_ptr<AudioBuffer<float>> file) noexcept
|
||||||
{
|
{
|
||||||
|
// DBG("File data set for sample " << region->sample);
|
||||||
fileData = std::move(file);
|
fileData = std::move(file);
|
||||||
dataReady.store(true);
|
dataReady.store(true);
|
||||||
}
|
}
|
||||||
|
|
@ -161,10 +162,9 @@ void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept
|
||||||
indexSpan = absl::MakeSpan(indexBuffer);
|
indexSpan = absl::MakeSpan(indexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::renderBlock(StereoSpan<float> buffer) noexcept
|
void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
const auto numSamples = buffer.size();
|
ASSERT(static_cast<int>(buffer.getNumFrames()) <= samplesPerBlock);
|
||||||
ASSERT(static_cast<int>(numSamples) <= samplesPerBlock);
|
|
||||||
buffer.fill(0.0f);
|
buffer.fill(0.0f);
|
||||||
|
|
||||||
if (state == State::idle || region == nullptr)
|
if (state == State::idle || region == nullptr)
|
||||||
|
|
@ -175,34 +175,59 @@ void sfz::Voice::renderBlock(StereoSpan<float> buffer) noexcept
|
||||||
else
|
else
|
||||||
fillWithData(buffer);
|
fillWithData(buffer);
|
||||||
|
|
||||||
auto envelopeSpan = tempSpan1.first(numSamples);
|
if (region->isStereo())
|
||||||
amplitudeEnvelope.getBlock(envelopeSpan);
|
processStereo(buffer);
|
||||||
buffer.applyGain(envelopeSpan);
|
else
|
||||||
|
processMono(buffer);
|
||||||
egEnvelope.getBlock(envelopeSpan);
|
|
||||||
buffer.applyGain(envelopeSpan);
|
|
||||||
|
|
||||||
if (!egEnvelope.isSmoothing())
|
if (!egEnvelope.isSmoothing())
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::fillWithData(StereoSpan<float> buffer) noexcept
|
void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||||
|
{
|
||||||
|
const auto numSamples = buffer.getNumFrames();
|
||||||
|
auto leftBuffer = buffer.getSpan(0);
|
||||||
|
auto rightBuffer = buffer.getSpan(1);
|
||||||
|
|
||||||
|
auto envelopeSpan = tempSpan1.first(numSamples);
|
||||||
|
amplitudeEnvelope.getBlock(envelopeSpan);
|
||||||
|
::applyGain<float>(envelopeSpan, leftBuffer);
|
||||||
|
|
||||||
|
egEnvelope.getBlock(envelopeSpan);
|
||||||
|
::applyGain<float>(envelopeSpan, leftBuffer);
|
||||||
|
|
||||||
|
::copy<float>(leftBuffer, rightBuffer);
|
||||||
|
}
|
||||||
|
void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
||||||
|
{
|
||||||
|
const auto numSamples = buffer.getNumFrames();
|
||||||
|
auto envelopeSpan = tempSpan1.first(numSamples);
|
||||||
|
|
||||||
|
amplitudeEnvelope.getBlock(envelopeSpan);
|
||||||
|
buffer.applyGain(envelopeSpan);
|
||||||
|
|
||||||
|
egEnvelope.getBlock(envelopeSpan);
|
||||||
|
buffer.applyGain(envelopeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
auto source { [&]() {
|
auto source { [&]() {
|
||||||
if (region->canUsePreloadedData() || !dataReady)
|
if (region->canUsePreloadedData() || !dataReady)
|
||||||
return StereoSpan<const float>(*region->preloadedData);
|
return AudioSpan<const float>(*region->preloadedData);
|
||||||
else
|
else
|
||||||
return StereoSpan<const float>(*fileData);
|
return AudioSpan<const float>(*fileData);
|
||||||
}() };
|
}() };
|
||||||
|
|
||||||
auto indices = indexSpan.first(buffer.size());
|
auto indices = indexSpan.first(buffer.getNumFrames());
|
||||||
auto jumps = tempSpan1.first(buffer.size());
|
auto jumps = tempSpan1.first(buffer.getNumFrames());
|
||||||
auto leftCoeffs = tempSpan1.first(buffer.size());
|
auto leftCoeffs = tempSpan1.first(buffer.getNumFrames());
|
||||||
auto rightCoeffs = tempSpan2.first(buffer.size());
|
auto rightCoeffs = tempSpan2.first(buffer.getNumFrames());
|
||||||
|
|
||||||
::fill<float>(jumps, pitchRatio * speedRatio);
|
::fill<float>(jumps, pitchRatio * speedRatio);
|
||||||
|
|
||||||
if (region->shouldLoop() && region->trueSampleEnd() <= source.size()) {
|
if (region->shouldLoop() && region->trueSampleEnd() <= source.getNumFrames()) {
|
||||||
floatPosition = ::loopingSFZIndex<float, false>(
|
floatPosition = ::loopingSFZIndex<float, false>(
|
||||||
jumps,
|
jumps,
|
||||||
leftCoeffs,
|
leftCoeffs,
|
||||||
|
|
@ -218,32 +243,42 @@ void sfz::Voice::fillWithData(StereoSpan<float> buffer) noexcept
|
||||||
rightCoeffs,
|
rightCoeffs,
|
||||||
indices,
|
indices,
|
||||||
floatPosition,
|
floatPosition,
|
||||||
source.size() - 1);
|
source.getNumFrames() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ind = indices.data();
|
auto ind = indices.data();
|
||||||
auto leftCoeff = leftCoeffs.data();
|
auto leftCoeff = leftCoeffs.data();
|
||||||
auto rightCoeff = rightCoeffs.data();
|
auto rightCoeff = rightCoeffs.data();
|
||||||
auto left = buffer.left().data();
|
auto left = buffer.getChannel(0);
|
||||||
auto right = buffer.right().data();
|
if (source.getNumChannels() == 1) {
|
||||||
while (ind < indices.end()) {
|
while (ind < indices.end()) {
|
||||||
*left = source.left()[*ind] * (*leftCoeff) + source.left()[*ind + 1] * (*rightCoeff);
|
*left = source.getChannel(0)[*ind] * (*leftCoeff) + source.getChannel(0)[*ind + 1] * (*rightCoeff);
|
||||||
*right = source.right()[*ind] * (*leftCoeff) + source.right()[*ind + 1] * (*rightCoeff);
|
left++;
|
||||||
left++;
|
ind++;
|
||||||
right++;
|
leftCoeff++;
|
||||||
ind++;
|
rightCoeff++;
|
||||||
leftCoeff++;
|
}
|
||||||
rightCoeff++;
|
} else {
|
||||||
|
auto right = buffer.getChannel(1);
|
||||||
|
while (ind < indices.end()) {
|
||||||
|
*left = source.getChannel(0)[*ind] * (*leftCoeff) + source.getChannel(0)[*ind + 1] * (*rightCoeff);
|
||||||
|
*right = source.getChannel(1)[*ind] * (*leftCoeff) + source.getChannel(1)[*ind + 1] * (*rightCoeff);
|
||||||
|
left++;
|
||||||
|
right++;
|
||||||
|
ind++;
|
||||||
|
leftCoeff++;
|
||||||
|
rightCoeff++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!region->shouldLoop() && (floatPosition + 1.01) > source.size()) {
|
if (!region->shouldLoop() && (floatPosition + 1.01) > source.getNumFrames()) {
|
||||||
DBG("Releasing " << region->sample);
|
DBG("Releasing " << region->sample);
|
||||||
auto last = std::distance(indices.begin(), absl::c_find(indices, region->trueSampleEnd() - 1));
|
auto last = std::distance(indices.begin(), absl::c_find(indices, region->trueSampleEnd() - 1));
|
||||||
release(last);
|
release(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::fillWithGenerator(StereoSpan<float> buffer) noexcept
|
void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
if (region->sample != "*sine")
|
if (region->sample != "*sine")
|
||||||
return;
|
return;
|
||||||
|
|
@ -251,10 +286,10 @@ void sfz::Voice::fillWithGenerator(StereoSpan<float> buffer) noexcept
|
||||||
float step = baseFrequency * twoPi<float> / sampleRate;
|
float step = baseFrequency * twoPi<float> / sampleRate;
|
||||||
phase = ::linearRamp<float>(tempSpan1, phase, step);
|
phase = ::linearRamp<float>(tempSpan1, phase, step);
|
||||||
|
|
||||||
::sin<float>(tempSpan1.first(buffer.size()), buffer.left());
|
::sin<float>(tempSpan1.first(buffer.getNumFrames()), buffer.getSpan(0));
|
||||||
absl::c_copy(buffer.left(), buffer.right().begin());
|
::copy<float>(buffer.getSpan(0), buffer.getSpan(1));
|
||||||
|
|
||||||
sourcePosition += buffer.size();
|
sourcePosition += buffer.getNumFrames();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sfz::Voice::checkOffGroup(int delay, uint32_t group) noexcept
|
bool sfz::Voice::checkOffGroup(int delay, uint32_t group) noexcept
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "LinearEnvelope.h"
|
#include "LinearEnvelope.h"
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "StereoBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
#include "StereoSpan.h"
|
#include "AudioSpan.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
@ -47,7 +47,7 @@ public:
|
||||||
|
|
||||||
void startVoice(Region* region, int delay, int channel, int number, uint8_t value, TriggerType triggerType) noexcept;
|
void startVoice(Region* region, int delay, int channel, int number, uint8_t value, TriggerType triggerType) noexcept;
|
||||||
|
|
||||||
void setFileData(std::unique_ptr<StereoBuffer<float>> file) noexcept;
|
void setFileData(std::unique_ptr<AudioBuffer<float>> file) noexcept;
|
||||||
void registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
void registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity) noexcept;
|
||||||
void registerCC(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept;
|
void registerCC(int delay, int channel, int ccNumber, uint8_t ccValue) noexcept;
|
||||||
void registerPitchWheel(int delay, int channel, int pitch) noexcept;
|
void registerPitchWheel(int delay, int channel, int pitch) noexcept;
|
||||||
|
|
@ -55,7 +55,7 @@ public:
|
||||||
void registerTempo(int delay, float secondsPerQuarter) noexcept;
|
void registerTempo(int delay, float secondsPerQuarter) noexcept;
|
||||||
bool checkOffGroup(int delay, uint32_t group) noexcept;
|
bool checkOffGroup(int delay, uint32_t group) noexcept;
|
||||||
|
|
||||||
void renderBlock(StereoSpan<float> buffer) noexcept;
|
void renderBlock(AudioSpan<float, 2> buffer) noexcept;
|
||||||
|
|
||||||
bool isFree() const noexcept;
|
bool isFree() const noexcept;
|
||||||
int getTriggerNumber() const noexcept;
|
int getTriggerNumber() const noexcept;
|
||||||
|
|
@ -66,9 +66,11 @@ public:
|
||||||
void reset() noexcept;
|
void reset() noexcept;
|
||||||
void garbageCollect() noexcept;
|
void garbageCollect() noexcept;
|
||||||
private:
|
private:
|
||||||
void fillWithData(StereoSpan<float> buffer) noexcept;
|
void fillWithData(AudioSpan<float> buffer) noexcept;
|
||||||
void fillWithGenerator(StereoSpan<float> buffer) noexcept;
|
void fillWithGenerator(AudioSpan<float> buffer) noexcept;
|
||||||
void prepareEGEnvelope(int delay, uint8_t velocity) noexcept;
|
void prepareEGEnvelope(int delay, uint8_t velocity) noexcept;
|
||||||
|
void processMono(AudioSpan<float> buffer) noexcept;
|
||||||
|
void processStereo(AudioSpan<float> buffer) noexcept;
|
||||||
void release(int delay) noexcept;
|
void release(int delay) noexcept;
|
||||||
Region* region { nullptr };
|
Region* region { nullptr };
|
||||||
|
|
||||||
|
|
@ -96,7 +98,7 @@ private:
|
||||||
uint32_t initialDelay { 0 };
|
uint32_t initialDelay { 0 };
|
||||||
|
|
||||||
std::atomic<bool> dataReady { false };
|
std::atomic<bool> dataReady { false };
|
||||||
std::unique_ptr<StereoBuffer<float>> fileData { nullptr };
|
std::unique_ptr<AudioBuffer<float>> fileData { nullptr };
|
||||||
|
|
||||||
Buffer<float> tempBuffer1;
|
Buffer<float> tempBuffer1;
|
||||||
Buffer<float> tempBuffer2;
|
Buffer<float> tempBuffer2;
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,8 @@ TEST_CASE("[Files] Channels (channels.sfz)")
|
||||||
synth.loadSfzFile(std::filesystem::current_path() / "tests/TestFiles/channels.sfz");
|
synth.loadSfzFile(std::filesystem::current_path() / "tests/TestFiles/channels.sfz");
|
||||||
REQUIRE(synth.getNumRegions() == 2);
|
REQUIRE(synth.getNumRegions() == 2);
|
||||||
REQUIRE(synth.getRegionView(0)->sample == "mono_sample.wav");
|
REQUIRE(synth.getRegionView(0)->sample == "mono_sample.wav");
|
||||||
REQUIRE(synth.getRegionView(0)->numChannels == 1);
|
|
||||||
REQUIRE(!synth.getRegionView(0)->isStereo());
|
REQUIRE(!synth.getRegionView(0)->isStereo());
|
||||||
REQUIRE(synth.getRegionView(1)->sample == "stereo_sample.wav");
|
REQUIRE(synth.getRegionView(1)->sample == "stereo_sample.wav");
|
||||||
REQUIRE(synth.getRegionView(1)->numChannels == 2);
|
|
||||||
REQUIRE(synth.getRegionView(1)->isStereo());
|
REQUIRE(synth.getRegionView(1)->isStereo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue