dev@190: #include "catch/catch.hpp"
dev@191: #include "vamp-client/Loader.h"
dev@191: #include "vamp-client/PluginClient.h"
cannam@213: #include "vamp-client/PiperVampPlugin.h"
dev@191: #include "vamp-support/RequestResponse.h"
dev@191: #include <vector>
dev@190: 
dev@191: using namespace piper_vamp;
dev@191: using namespace piper_vamp::client;
dev@191: using AudioBuffer = std::vector<std::vector<float>>;
dev@190: 
dev@196: // This stub fakes the interaction with a Piper server
dev@191: // Here we only need to implement the configure method 
cannam@213: // due to testing only the initialise implemention of PiperVampPlugin
dev@191: class StubClient : public PluginClient
dev@191: {
dev@191: public:
dev@191:     StubClient(PluginStaticData staticData) : m_staticData(staticData) {}
dev@191:     
dev@191:     ConfigurationResponse
cannam@213:     configure(PiperVampPlugin* plugin,
dev@191:               PluginConfiguration config) override
dev@191:     {
dev@191:         const float scale = plugin->getParameter("framing-scale");
dev@191:         ConfigurationResponse cr;
dev@191:         cr.plugin = plugin;
dev@191:         
dev@194:         // we want to return different framing sizes than config provides
dev@191:         // there isn't really any need to be doing this with a plugin param
dev@194:         cr.framing.blockSize = config.framing.blockSize * scale;
dev@194:         cr.framing.stepSize = config.framing.stepSize * scale;
dev@191:         
dev@191:         // just return some outputs anyway 
dev@191:         // to avoid a failure case we are not testing here.
dev@191:         Vamp::Plugin::OutputDescriptor output;
dev@191:         const auto basic = m_staticData.basicOutputInfo[0];
dev@191:         output.identifier = basic.identifier;
dev@191:         output.name = basic.name;
dev@191:         output.description = basic.description;
dev@191:         cr.outputs = {output};
dev@191:         return cr;                   
dev@191:     }
dev@191:     
dev@191:     Vamp::Plugin::FeatureSet
cannam@213:     process(PiperVampPlugin* /*plugin*/,
dev@191:             AudioBuffer /*channels*/,
dev@191:             Vamp::RealTime /*timestamp*/) override
dev@191:     {
dev@191:         return {};
dev@191:     }
dev@191:     
dev@191:     Vamp::Plugin::FeatureSet
cannam@213:     finish(PiperVampPlugin* /*plugin*/) override
dev@191:     {
dev@191:         return {};
dev@191:     }
dev@191:     
dev@191:     void
cannam@213:     reset(PiperVampPlugin* /*plugin*/, PluginConfiguration /*config*/) override
dev@191:     {}
dev@191: private:
dev@191:     PluginStaticData m_staticData;
dev@191: };
dev@191: 
dev@191: 
dev@191: TEST_CASE("Init plugin with parameter dependent preferred framing sizes") {
dev@194:     const std::size_t initialBlockSize = 1024;
dev@194:     const std::size_t initialStepSize = 512;
dev@191:     PluginConfiguration defaultConfig;
dev@191:     defaultConfig.channelCount = 1;
dev@194:     defaultConfig.framing.blockSize = initialBlockSize;
dev@194:     defaultConfig.framing.stepSize = initialStepSize;
dev@191:     defaultConfig.parameterValues = {{"framing-scale", 1.0}};
dev@191:     
dev@191:     Vamp::PluginBase::ParameterDescriptor stubParam;
dev@191:     stubParam.identifier = "framing-scale";
dev@191:     stubParam.name = "Framing Scale Factor";
dev@191:     stubParam.description = "Scales the preferred framing sizes";
dev@191:     stubParam.maxValue = 2.0; 
dev@191:     
dev@191:     PluginStaticData staticData;
dev@191:     staticData.pluginKey = "stub";
dev@202:     staticData.basic = {"param-init", "Stub", "Testing init"};
dev@191:     staticData.maker = "Lucas Thompson";
dev@191:     staticData.copyright = "GPL";
dev@191:     staticData.pluginVersion = 1;
dev@191:     staticData.category = {"Test"};
dev@191:     staticData.minChannelCount = 1;
dev@191:     staticData.maxChannelCount = 1;
dev@191:     staticData.parameters = {stubParam};
dev@191:     staticData.inputDomain = Vamp::Plugin::InputDomain::TimeDomain;
dev@191:     staticData.basicOutputInfo = {{"output", "NA", "Not real"}};
dev@191: 
dev@191:     StubClient stub {staticData};
dev@191:     
cannam@213:     PiperVampPlugin vampPiperAdapter {
dev@191:         &stub, 
dev@191:         "stub", // plugin key
dev@191:         44100.0, // sample rate
dev@191:         0, // adapter flags, don't care here
dev@191:         staticData, 
dev@191:         defaultConfig 
dev@191:     };
dev@191:     
dev@194:     const auto initWithPreferredFraming = [&]() -> bool {
dev@194:         return vampPiperAdapter.initialise(
dev@191:             1, 
dev@191:             vampPiperAdapter.getPreferredStepSize(), 
dev@191:             vampPiperAdapter.getPreferredBlockSize()
dev@194:         );  
dev@194:     };
dev@194:     
dev@202:     const AudioBuffer monoAudio {
dev@202:         std::vector<float>(vampPiperAdapter.getPreferredBlockSize())
dev@202:     };
dev@202:     const std::vector<const float*> channelPtrs {
dev@202:         monoAudio[0].data()
dev@202:     };
dev@202:     
dev@194:     SECTION("Initialises with default parameters")
dev@194:     {
dev@194:         REQUIRE( initWithPreferredFraming() );   
dev@194:     }
dev@194:     
dev@194:     SECTION("Fails to init when changing framing influencing parameter")
dev@194:     {
dev@194:         const float scalingFactor = 2.0;
dev@194:         vampPiperAdapter.setParameter("framing-scale", scalingFactor);
dev@194:         REQUIRE( initWithPreferredFraming() == false );
dev@194:         const float configuredStepSize = vampPiperAdapter.getPreferredStepSize();
dev@194:         const float configuredBlockSize = vampPiperAdapter.getPreferredBlockSize();
dev@194:         REQUIRE( configuredStepSize == initialStepSize * scalingFactor );
dev@194:         REQUIRE( configuredBlockSize == initialBlockSize * scalingFactor );
dev@194:     }
dev@194:     
dev@194:     SECTION("Cannot process after a failed init call (due to framing)")
dev@194:     {
dev@194:         const float scalingFactor = 2.0;
dev@194:         vampPiperAdapter.setParameter("framing-scale", scalingFactor);
dev@194:         REQUIRE( initWithPreferredFraming() == false );
dev@202:         REQUIRE_THROWS( vampPiperAdapter.process(channelPtrs.data(), {}) );
dev@199:         REQUIRE_THROWS( initWithPreferredFraming() );
dev@194:     }
dev@194:     
dev@194:     SECTION("Can process after correctly initialising framing")
dev@194:     {
dev@194:         const float scalingFactor = 2.0;
dev@194:         vampPiperAdapter.setParameter("framing-scale", scalingFactor);
dev@194:         REQUIRE( initWithPreferredFraming() == false );
dev@194:         REQUIRE( initWithPreferredFraming() );
dev@194:         REQUIRE( vampPiperAdapter.process(channelPtrs.data(), {}).empty() );
dev@194:     }
dev@190: }