mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-17 00:44:19 +00:00
VST3: Add channel mapping tests
This commit is contained in:
parent
bb2b36a253
commit
fe3d42025b
4 changed files with 550 additions and 0 deletions
|
|
@ -23,6 +23,8 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if JUCE_BSD && ! JUCE_CUSTOM_VST3_SDK
|
||||
#error To build JUCE VST3 plug-ins on BSD you must use an external BSD-compatible VST3 SDK with JUCE_CUSTOM_VST3_SDK=1
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_VST3Headers.h"
|
||||
#include "juce_VST3Common.h"
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class VST3PluginFormatTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
VST3PluginFormatTests()
|
||||
: UnitTest ("VST3 Hosting", UnitTestCategories::audioProcessors)
|
||||
{
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("ChannelMapping for a stereo bus performs no remapping");
|
||||
{
|
||||
ChannelMapping map (AudioChannelSet::stereo());
|
||||
expect (map.size() == 2);
|
||||
expect (map.isActive() == true);
|
||||
|
||||
expect (map.getJuceChannelForVst3Channel (0) == 0); // L -> left
|
||||
expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right
|
||||
}
|
||||
|
||||
beginTest ("ChannelMapping for a 9.1.6 bus remaps the channels appropriately");
|
||||
{
|
||||
ChannelMapping map (AudioChannelSet::create9point1point6());
|
||||
expect (map.size() == 16);
|
||||
expect (map.isActive() == true);
|
||||
|
||||
// VST3 order is:
|
||||
// L
|
||||
// R
|
||||
// C
|
||||
// Lfe
|
||||
// Ls
|
||||
// Rs
|
||||
// Lc
|
||||
// Rc
|
||||
// Sl
|
||||
// Sr
|
||||
// Tfl
|
||||
// Tfr
|
||||
// Trl
|
||||
// Trr
|
||||
// Tsl
|
||||
// Tsr
|
||||
// JUCE order is:
|
||||
// Left
|
||||
// Right
|
||||
// Centre
|
||||
// LFE
|
||||
// Left Surround Side
|
||||
// Right Surround Side
|
||||
// Top Front Left
|
||||
// Top Front Right
|
||||
// Top Rear Left
|
||||
// Top Rear Right
|
||||
// Left Surround Rear
|
||||
// Right Surround Rear
|
||||
// Wide Left
|
||||
// Wide Right
|
||||
// Top Side Left
|
||||
// Top Side Right
|
||||
|
||||
expect (map.getJuceChannelForVst3Channel (0) == 12); // L -> wideLeft
|
||||
expect (map.getJuceChannelForVst3Channel (1) == 13); // R -> wideRight
|
||||
expect (map.getJuceChannelForVst3Channel (2) == 2); // C -> centre
|
||||
expect (map.getJuceChannelForVst3Channel (3) == 3); // Lfe -> LFE
|
||||
expect (map.getJuceChannelForVst3Channel (4) == 10); // Ls -> leftSurroundRear
|
||||
expect (map.getJuceChannelForVst3Channel (5) == 11); // Rs -> rightSurroundRear
|
||||
expect (map.getJuceChannelForVst3Channel (6) == 0); // Lc -> left
|
||||
expect (map.getJuceChannelForVst3Channel (7) == 1); // Rc -> right
|
||||
expect (map.getJuceChannelForVst3Channel (8) == 4); // Sl -> leftSurroundSide
|
||||
expect (map.getJuceChannelForVst3Channel (9) == 5); // Sl -> leftSurroundSide
|
||||
expect (map.getJuceChannelForVst3Channel (10) == 6); // Tfl -> topFrontLeft
|
||||
expect (map.getJuceChannelForVst3Channel (11) == 7); // Tfr -> topFrontRight
|
||||
expect (map.getJuceChannelForVst3Channel (12) == 8); // Trl -> topRearLeft
|
||||
expect (map.getJuceChannelForVst3Channel (13) == 9); // Trr -> topRearRight
|
||||
expect (map.getJuceChannelForVst3Channel (14) == 14); // Tsl -> topSideLeft
|
||||
expect (map.getJuceChannelForVst3Channel (15) == 15); // Tsr -> topSideRight
|
||||
}
|
||||
|
||||
const auto blockSize = 128;
|
||||
|
||||
beginTest ("If the host provides more buses than the plugin knows about, the remapped buffer is silent and uses only internal channels");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (2, blockSize * 2);
|
||||
|
||||
const std::vector<ChannelMapping> emptyBuses;
|
||||
const std::vector<ChannelMapping> stereoBus { ChannelMapping { AudioChannelSet::stereo() } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 2).withBus (testBuffers, 1);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 2).withBus (testBuffers, 1);
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
for (const auto& config : { Config { stereoBus, stereoBus }, Config { emptyBuses, stereoBus }, Config { stereoBus, emptyBuses } })
|
||||
{
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
expect (remapped.getNumChannels() == config.getNumChannels());
|
||||
expect (remapped.getNumSamples() == blockSize);
|
||||
|
||||
for (auto i = 0; i < remapped.getNumChannels(); ++i)
|
||||
expect (allMatch (remapped, i, 0.0f));
|
||||
|
||||
expect (! testBuffers.isClear (0));
|
||||
expect (! testBuffers.isClear (1));
|
||||
expect (! testBuffers.isClear (2));
|
||||
expect (testBuffers.isClear (3));
|
||||
expect (testBuffers.isClear (4));
|
||||
expect (testBuffers.isClear (5));
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("If the host provides fewer buses than the plugin knows about, the remapped buffer is silent and uses only internal channels");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (3, blockSize * 2);
|
||||
|
||||
const std::vector<ChannelMapping> noBus;
|
||||
const std::vector<ChannelMapping> oneBus { ChannelMapping { AudioChannelSet::mono() } };
|
||||
const std::vector<ChannelMapping> twoBuses { ChannelMapping { AudioChannelSet::mono() },
|
||||
ChannelMapping { AudioChannelSet::stereo() } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 1);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 1);
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
for (const auto& config : { Config { noBus, twoBuses },
|
||||
Config { twoBuses, noBus },
|
||||
Config { oneBus, twoBuses },
|
||||
Config { twoBuses, oneBus },
|
||||
Config { twoBuses, twoBuses } })
|
||||
{
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
expect (remapped.getNumChannels() == config.getNumChannels());
|
||||
expect (remapped.getNumSamples() == blockSize);
|
||||
|
||||
for (auto i = 0; i < remapped.getNumChannels(); ++i)
|
||||
expect (allMatch (remapped, i, 0.0f));
|
||||
|
||||
expect (! testBuffers.isClear (0));
|
||||
expect (testBuffers.isClear (1));
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("If the host channel count on any bus is incorrect, the remapped buffer is silent and uses only internal channels");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (3, blockSize * 2);
|
||||
|
||||
const std::vector<ChannelMapping> monoBus { ChannelMapping { AudioChannelSet::mono() } };
|
||||
const std::vector<ChannelMapping> stereoBus { ChannelMapping { AudioChannelSet::stereo() } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 1);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 2);
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
for (const auto& config : { Config { stereoBus, monoBus },
|
||||
Config { stereoBus, stereoBus },
|
||||
Config { monoBus, monoBus } })
|
||||
{
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
expect (remapped.getNumChannels() == config.getNumChannels());
|
||||
expect (remapped.getNumSamples() == blockSize);
|
||||
|
||||
for (auto i = 0; i < remapped.getNumChannels(); ++i)
|
||||
expect (allMatch (remapped, i, 0.0f));
|
||||
|
||||
expect (! testBuffers.isClear (0));
|
||||
expect (testBuffers.isClear (1));
|
||||
expect (testBuffers.isClear (2));
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("A layout with more output channels than input channels leaves unused inputs untouched");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (20, blockSize * 2);
|
||||
|
||||
const Config config { { ChannelMapping { AudioChannelSet::mono() },
|
||||
ChannelMapping { AudioChannelSet::create5point1() } },
|
||||
{ ChannelMapping { AudioChannelSet::stereo() },
|
||||
ChannelMapping { AudioChannelSet::create7point1() } } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 1).withBus (testBuffers, 6);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 2).withBus (testBuffers, 8);
|
||||
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
|
||||
expect (remapped.getNumChannels() == 10);
|
||||
|
||||
// Data from the input channels is copied to the correct channels of the remapped buffer
|
||||
expect (allMatch (remapped, 0, 1.0f));
|
||||
expect (allMatch (remapped, 1, 2.0f));
|
||||
expect (allMatch (remapped, 2, 3.0f));
|
||||
expect (allMatch (remapped, 3, 4.0f));
|
||||
expect (allMatch (remapped, 4, 5.0f));
|
||||
expect (allMatch (remapped, 5, 6.0f));
|
||||
expect (allMatch (remapped, 6, 7.0f));
|
||||
// These channels are output-only, so they keep whatever data was previously on that output channel
|
||||
expect (allMatch (remapped, 7, 17.0f));
|
||||
expect (allMatch (remapped, 8, 14.0f));
|
||||
expect (allMatch (remapped, 9, 15.0f));
|
||||
|
||||
// Channel pointers from the VST3 buffer are used
|
||||
expect (remapped.getReadPointer (0) == testBuffers.get (7));
|
||||
expect (remapped.getReadPointer (1) == testBuffers.get (8));
|
||||
expect (remapped.getReadPointer (2) == testBuffers.get (9));
|
||||
expect (remapped.getReadPointer (3) == testBuffers.get (10));
|
||||
expect (remapped.getReadPointer (4) == testBuffers.get (11));
|
||||
expect (remapped.getReadPointer (5) == testBuffers.get (12));
|
||||
expect (remapped.getReadPointer (6) == testBuffers.get (15)); // JUCE surround side -> VST3 surround side
|
||||
expect (remapped.getReadPointer (7) == testBuffers.get (16)); // JUCE surround side -> VST3 surround side
|
||||
expect (remapped.getReadPointer (8) == testBuffers.get (13)); // JUCE surround rear -> VST3 surround rear
|
||||
expect (remapped.getReadPointer (9) == testBuffers.get (14)); // JUCE surround rear -> VST3 surround rear
|
||||
}
|
||||
|
||||
beginTest ("A layout with more input channels than output channels uses input channels directly in remapped buffer");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (15, blockSize * 2);
|
||||
|
||||
const Config config { { ChannelMapping { AudioChannelSet::create7point1point6() },
|
||||
ChannelMapping { AudioChannelSet::mono() } },
|
||||
{ ChannelMapping { AudioChannelSet::createLCRS() },
|
||||
ChannelMapping { AudioChannelSet::stereo() } } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 14).withBus (testBuffers, 1);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 4) .withBus (testBuffers, 2);
|
||||
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
|
||||
expect (remapped.getNumChannels() == 15);
|
||||
|
||||
// Data from the input channels is copied to the correct channels of the remapped buffer
|
||||
expect (allMatch (remapped, 0, 1.0f));
|
||||
expect (allMatch (remapped, 1, 2.0f));
|
||||
expect (allMatch (remapped, 2, 3.0f));
|
||||
expect (allMatch (remapped, 3, 4.0f));
|
||||
expect (allMatch (remapped, 4, 7.0f));
|
||||
expect (allMatch (remapped, 5, 8.0f));
|
||||
expect (allMatch (remapped, 6, 9.0f));
|
||||
expect (allMatch (remapped, 7, 10.0f));
|
||||
expect (allMatch (remapped, 8, 11.0f));
|
||||
expect (allMatch (remapped, 9, 12.0f));
|
||||
expect (allMatch (remapped, 10, 5.0f));
|
||||
expect (allMatch (remapped, 11, 6.0f));
|
||||
expect (allMatch (remapped, 12, 13.0f));
|
||||
expect (allMatch (remapped, 13, 14.0f));
|
||||
expect (allMatch (remapped, 14, 15.0f));
|
||||
|
||||
// Use output channel pointers for output channels
|
||||
expect (remapped.getReadPointer (0) == testBuffers.get (15));
|
||||
expect (remapped.getReadPointer (1) == testBuffers.get (16));
|
||||
expect (remapped.getReadPointer (2) == testBuffers.get (17));
|
||||
expect (remapped.getReadPointer (3) == testBuffers.get (18));
|
||||
expect (remapped.getReadPointer (4) == testBuffers.get (19));
|
||||
expect (remapped.getReadPointer (5) == testBuffers.get (20));
|
||||
|
||||
// Use input channel pointers for channels with no corresponding output
|
||||
expect (remapped.getReadPointer (6) == testBuffers.get (8));
|
||||
expect (remapped.getReadPointer (7) == testBuffers.get (9));
|
||||
expect (remapped.getReadPointer (8) == testBuffers.get (10));
|
||||
expect (remapped.getReadPointer (9) == testBuffers.get (11));
|
||||
expect (remapped.getReadPointer (10) == testBuffers.get (4));
|
||||
expect (remapped.getReadPointer (11) == testBuffers.get (5));
|
||||
expect (remapped.getReadPointer (12) == testBuffers.get (12));
|
||||
expect (remapped.getReadPointer (13) == testBuffers.get (13));
|
||||
expect (remapped.getReadPointer (14) == testBuffers.get (14));
|
||||
}
|
||||
|
||||
beginTest ("Inactive buses are ignored");
|
||||
{
|
||||
ClientBufferMapperData<float> remapper;
|
||||
remapper.prepare (15, blockSize * 2);
|
||||
|
||||
const Config config { { ChannelMapping { AudioChannelSet::create7point1point6() },
|
||||
ChannelMapping { AudioChannelSet::mono(), false },
|
||||
ChannelMapping { AudioChannelSet::quadraphonic() },
|
||||
ChannelMapping { AudioChannelSet::mono(), false } },
|
||||
{ ChannelMapping { AudioChannelSet::create5point0(), false },
|
||||
ChannelMapping { AudioChannelSet::createLCRS() },
|
||||
ChannelMapping { AudioChannelSet::stereo() } } };
|
||||
|
||||
TestBuffers testBuffers { blockSize };
|
||||
|
||||
// The host doesn't need to provide trailing buses that are inactive
|
||||
auto ins = MultiBusBuffers{}.withBus (testBuffers, 14).withBus (testBuffers, 1).withBus (testBuffers, 4);
|
||||
auto outs = MultiBusBuffers{}.withBus (testBuffers, 5) .withBus (testBuffers, 4).withBus (testBuffers, 2);
|
||||
|
||||
auto data = makeProcessData (blockSize, ins, outs);
|
||||
|
||||
testBuffers.init();
|
||||
const auto remapped = remapper.getMappedBuffer (data, config.ins, config.outs);
|
||||
|
||||
expect (remapped.getNumChannels() == 18);
|
||||
|
||||
// Data from the input channels is copied to the correct channels of the remapped buffer
|
||||
expect (allMatch (remapped, 0, 1.0f));
|
||||
expect (allMatch (remapped, 1, 2.0f));
|
||||
expect (allMatch (remapped, 2, 3.0f));
|
||||
expect (allMatch (remapped, 3, 4.0f));
|
||||
expect (allMatch (remapped, 4, 7.0f));
|
||||
expect (allMatch (remapped, 5, 8.0f));
|
||||
expect (allMatch (remapped, 6, 9.0f));
|
||||
expect (allMatch (remapped, 7, 10.0f));
|
||||
expect (allMatch (remapped, 8, 11.0f));
|
||||
expect (allMatch (remapped, 9, 12.0f));
|
||||
expect (allMatch (remapped, 10, 5.0f));
|
||||
expect (allMatch (remapped, 11, 6.0f));
|
||||
expect (allMatch (remapped, 12, 13.0f));
|
||||
expect (allMatch (remapped, 13, 14.0f));
|
||||
|
||||
expect (allMatch (remapped, 14, 16.0f));
|
||||
expect (allMatch (remapped, 15, 17.0f));
|
||||
expect (allMatch (remapped, 16, 18.0f));
|
||||
expect (allMatch (remapped, 17, 19.0f));
|
||||
|
||||
// Use output channel pointers for output channels
|
||||
expect (remapped.getReadPointer (0) == testBuffers.get (24));
|
||||
expect (remapped.getReadPointer (1) == testBuffers.get (25));
|
||||
expect (remapped.getReadPointer (2) == testBuffers.get (26));
|
||||
expect (remapped.getReadPointer (3) == testBuffers.get (27));
|
||||
expect (remapped.getReadPointer (4) == testBuffers.get (28));
|
||||
expect (remapped.getReadPointer (5) == testBuffers.get (29));
|
||||
|
||||
// Use input channel pointers for channels with no corresponding output
|
||||
expect (remapped.getReadPointer (6) == testBuffers.get (8));
|
||||
expect (remapped.getReadPointer (7) == testBuffers.get (9));
|
||||
expect (remapped.getReadPointer (8) == testBuffers.get (10));
|
||||
expect (remapped.getReadPointer (9) == testBuffers.get (11));
|
||||
expect (remapped.getReadPointer (10) == testBuffers.get (4));
|
||||
expect (remapped.getReadPointer (11) == testBuffers.get (5));
|
||||
expect (remapped.getReadPointer (12) == testBuffers.get (12));
|
||||
expect (remapped.getReadPointer (13) == testBuffers.get (13));
|
||||
|
||||
expect (remapped.getReadPointer (14) == testBuffers.get (15));
|
||||
expect (remapped.getReadPointer (15) == testBuffers.get (16));
|
||||
expect (remapped.getReadPointer (16) == testBuffers.get (17));
|
||||
expect (remapped.getReadPointer (17) == testBuffers.get (18));
|
||||
}
|
||||
|
||||
beginTest ("HostBufferMapper reorders channels correctly");
|
||||
{
|
||||
HostBufferMapper mapper;
|
||||
|
||||
{
|
||||
mapper.prepare ({ ChannelMapping { AudioChannelSet::stereo() },
|
||||
ChannelMapping { AudioChannelSet::create7point1point2() },
|
||||
ChannelMapping { AudioChannelSet::create9point1point6(), false },
|
||||
ChannelMapping { AudioChannelSet::createLCRS() } });
|
||||
AudioBuffer<float> hostBuffer (16, blockSize);
|
||||
const auto* clientBuffers = mapper.getVst3LayoutForJuceBuffer (hostBuffer);
|
||||
|
||||
expect (clientBuffers[0].numChannels == 2);
|
||||
expect (clientBuffers[1].numChannels == 10);
|
||||
// Even though it's disabled, this bus should still have the correct channel count
|
||||
expect (clientBuffers[2].numChannels == 16);
|
||||
expect (clientBuffers[3].numChannels == 4);
|
||||
|
||||
expect (clientBuffers[0].channelBuffers32[0] == hostBuffer.getReadPointer (0));
|
||||
expect (clientBuffers[0].channelBuffers32[1] == hostBuffer.getReadPointer (1));
|
||||
|
||||
expect (clientBuffers[1].channelBuffers32[0] == hostBuffer.getReadPointer (2));
|
||||
expect (clientBuffers[1].channelBuffers32[1] == hostBuffer.getReadPointer (3));
|
||||
expect (clientBuffers[1].channelBuffers32[2] == hostBuffer.getReadPointer (4));
|
||||
expect (clientBuffers[1].channelBuffers32[3] == hostBuffer.getReadPointer (5));
|
||||
expect (clientBuffers[1].channelBuffers32[4] == hostBuffer.getReadPointer (8));
|
||||
expect (clientBuffers[1].channelBuffers32[5] == hostBuffer.getReadPointer (9));
|
||||
expect (clientBuffers[1].channelBuffers32[6] == hostBuffer.getReadPointer (6));
|
||||
expect (clientBuffers[1].channelBuffers32[7] == hostBuffer.getReadPointer (7));
|
||||
expect (clientBuffers[1].channelBuffers32[8] == hostBuffer.getReadPointer (10));
|
||||
expect (clientBuffers[1].channelBuffers32[9] == hostBuffer.getReadPointer (11));
|
||||
|
||||
for (auto i = 0; i < clientBuffers[2].numChannels; ++i)
|
||||
expect (clientBuffers[2].channelBuffers32[i] == nullptr);
|
||||
|
||||
expect (clientBuffers[3].channelBuffers32[0] == hostBuffer.getReadPointer (12));
|
||||
expect (clientBuffers[3].channelBuffers32[1] == hostBuffer.getReadPointer (13));
|
||||
expect (clientBuffers[3].channelBuffers32[2] == hostBuffer.getReadPointer (14));
|
||||
expect (clientBuffers[3].channelBuffers32[3] == hostBuffer.getReadPointer (15));
|
||||
}
|
||||
|
||||
{
|
||||
mapper.prepare ({ ChannelMapping { AudioChannelSet::mono() },
|
||||
ChannelMapping { AudioChannelSet::mono(), false },
|
||||
ChannelMapping { AudioChannelSet::mono() },
|
||||
ChannelMapping { AudioChannelSet::mono(), false } });
|
||||
AudioBuffer<double> hostBuffer (2, blockSize);
|
||||
const auto* clientBuffers = mapper.getVst3LayoutForJuceBuffer (hostBuffer);
|
||||
|
||||
expect (clientBuffers[0].numChannels == 1);
|
||||
expect (clientBuffers[1].numChannels == 1);
|
||||
expect (clientBuffers[2].numChannels == 1);
|
||||
expect (clientBuffers[3].numChannels == 1);
|
||||
|
||||
expect (clientBuffers[0].channelBuffers64[0] == hostBuffer.getReadPointer (0));
|
||||
expect (clientBuffers[1].channelBuffers64[0] == nullptr);
|
||||
expect (clientBuffers[2].channelBuffers64[0] == hostBuffer.getReadPointer (1));
|
||||
expect (clientBuffers[3].channelBuffers64[0] == nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Config
|
||||
{
|
||||
std::vector<ChannelMapping> ins, outs;
|
||||
|
||||
int getNumChannels() const { return countUsedChannels (ins, outs); }
|
||||
};
|
||||
|
||||
struct TestBuffers
|
||||
{
|
||||
explicit TestBuffers (int samples) : numSamples (samples) {}
|
||||
|
||||
void init()
|
||||
{
|
||||
auto index = 1;
|
||||
|
||||
for (auto& channel : buffers)
|
||||
std::fill (channel.begin(), channel.end(), (float) index++);
|
||||
}
|
||||
|
||||
bool allMatch (int channel, float value) const
|
||||
{
|
||||
const auto& buf = buffers[(size_t) channel];
|
||||
return std::all_of (buf.begin(), buf.end(), [&] (auto x) { return x == value; });
|
||||
}
|
||||
|
||||
bool isClear (int channel) const
|
||||
{
|
||||
return allMatch (channel, 0.0f);
|
||||
}
|
||||
|
||||
float* addChannel()
|
||||
{
|
||||
buffers.emplace_back (numSamples);
|
||||
return buffers.back().data();
|
||||
}
|
||||
|
||||
float* get (int channel) { return buffers[(size_t) channel].data(); }
|
||||
const float* get (int channel) const { return buffers[(size_t) channel].data(); }
|
||||
|
||||
std::vector<std::vector<float>> buffers;
|
||||
int numSamples = 0;
|
||||
};
|
||||
|
||||
static bool allMatch (const AudioBuffer<float>& buf, int index, float value)
|
||||
{
|
||||
const auto* ptr = buf.getReadPointer (index);
|
||||
return std::all_of (ptr, ptr + buf.getNumSamples(), [&] (auto x) { return x == value; });
|
||||
}
|
||||
|
||||
struct MultiBusBuffers
|
||||
{
|
||||
std::vector<Steinberg::Vst::AudioBusBuffers> buffers;
|
||||
std::vector<std::vector<float*>> pointerStorage;
|
||||
|
||||
MultiBusBuffers withBus (TestBuffers& storage, int numChannels) &&
|
||||
{
|
||||
MultiBusBuffers result { std::move (buffers), std::move (pointerStorage) };
|
||||
|
||||
std::vector<float*> pointers;
|
||||
|
||||
for (auto i = 0; i < numChannels; ++i)
|
||||
pointers.push_back (storage.addChannel());
|
||||
|
||||
Steinberg::Vst::AudioBusBuffers buffer;
|
||||
buffer.numChannels = (Steinberg::int32) pointers.size();
|
||||
buffer.channelBuffers32 = pointers.data();
|
||||
|
||||
result.buffers.push_back (buffer);
|
||||
result.pointerStorage.push_back (std::move (pointers));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static Steinberg::Vst::ProcessData makeProcessData (int blockSize, MultiBusBuffers& ins, MultiBusBuffers& outs)
|
||||
{
|
||||
Steinberg::Vst::ProcessData result;
|
||||
result.numSamples = blockSize;
|
||||
result.inputs = ins.buffers.data();
|
||||
result.numInputs = (Steinberg::int32) ins.buffers.size();
|
||||
result.outputs = outs.buffers.data();
|
||||
result.numOutputs = (Steinberg::int32) outs.buffers.size();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static VST3PluginFormatTests vst3PluginFormatTests;
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -209,3 +209,7 @@ private:
|
|||
#include "utilities/juce_ParameterAttachments.cpp"
|
||||
#include "utilities/juce_AudioProcessorValueTreeState.cpp"
|
||||
#include "utilities/juce_PluginHostType.cpp"
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
#include "format_types/juce_VST3PluginFormat_test.cpp"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace UnitTestCategories
|
|||
static const String analytics { "Analytics" };
|
||||
static const String audio { "Audio" };
|
||||
static const String audioProcessorParameters { "AudioProcessorParameters" };
|
||||
static const String audioProcessors { "AudioProcessors" };
|
||||
static const String blocks { "Blocks" };
|
||||
static const String compression { "Compression" };
|
||||
static const String containers { "Containers" };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue