From 74c3d05faa2e2c849a7b01ff70297611a5594fcc Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 3 May 2022 11:33:27 +0100 Subject: [PATCH] PoC: Enhance/choices param (#108) * Add ChoiceT parameter type * Add `select` control to `BufStatsClient` to road test `ChoicesParam` * Choices params: Don't use a set because it breaks ordering * SpectralShape: Add select param --- include/clients/common/ParameterTypes.hpp | 43 +++++++++++++++++++++- include/clients/nrt/BufStatsClient.hpp | 23 ++++++++++-- include/clients/rt/SpectralShapeClient.hpp | 26 +++++++++---- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/include/clients/common/ParameterTypes.hpp b/include/clients/common/ParameterTypes.hpp index 378ceaedb..90704ccd2 100644 --- a/include/clients/common/ParameterTypes.hpp +++ b/include/clients/common/ParameterTypes.hpp @@ -15,11 +15,12 @@ under the European Union’s Horizon 2020 research and innovation programme #include "Result.hpp" #include "../../data/FluidIndex.hpp" #include +#include #include #include #include #include - +#include namespace fluid { namespace client { @@ -126,6 +127,37 @@ struct EnumT : ParamTypeBase }; +struct ChoicesT: ParamTypeBase +{ + using type = std::bitset<16>; + + + template + constexpr ChoicesT(const char* name, const char* displayName, + const char (&... string)[N]) + : ParamTypeBase(name, displayName), strings{string...}, fixedSize(1), + numOptions(sizeof...(N)), defaultValue((1 << numOptions) - 1) + { + static_assert(sizeof...(N) > 0, "Fluid Param: No choice strings supplied!"); + static_assert(sizeof...(N) <= 16, + "Fluid Param: : Maximum 16 things in an choice param"); + } + const char* strings[16]; // unilateral descision klaxon: if you have more than + // 16 things in an Enum, you need to rethink + const index fixedSize; + const index numOptions; + const type defaultValue; + + index lookup(std::string name) + { + static std::vector lookupTable(strings, strings + numOptions); + + auto pos = std::find(lookupTable.begin(), lookupTable.end(), name); + return pos != lookupTable.end() ? std::distance(lookupTable.begin(), pos) + : -1; + } +}; + // can I avoid making this constexpr and thus using std::string? Let's see; struct StringT : ParamTypeBase { @@ -492,6 +524,15 @@ EnumParam(const char* name, const char* displayName, std::make_tuple(EnumT::EnumConstraint()), IsFixed{}}; } +template , size_t... N> +constexpr ParamSpec +ChoicesParam(const char* name, const char* displayName, const char (&... strings)[N]) +{ + return {ChoicesT(name, displayName, strings...), std::make_tuple(), + Fixed{}}; +} + + template , size_t N, typename... Constraints> constexpr ParamSpec FloatArrayParam(const char* name, const char* displayName, diff --git a/include/clients/nrt/BufStatsClient.hpp b/include/clients/nrt/BufStatsClient.hpp index e7432eb87..f85ff14ae 100644 --- a/include/clients/nrt/BufStatsClient.hpp +++ b/include/clients/nrt/BufStatsClient.hpp @@ -28,6 +28,7 @@ enum BufferStatsParamIndex { kStartChan, kNumChans, kStats, + kSelect, kNumDerivatives, kLow, kMiddle, @@ -43,6 +44,7 @@ constexpr auto BufStatsParams = defineParameters( LongParam("startChan", "Start Channel", 0, Min(0)), LongParam("numChans", "Number of Channels", -1), BufferParam("stats", "Stats Buffer"), + ChoicesParam("select","Selection of Statistics","mean","std","skew","kurtosis","low","mid","high"), LongParam("numDerivs", "Number of Derivatives", 0, Min(0), Max(2)), FloatParam("low", "Low Percentile", 0, Min(0), Max(100), UpperLimit()), @@ -124,7 +126,9 @@ class BufferStatsClient : public FluidBaseClient, if (numFrames <= get()) return {Result::Status::kError, "Not enough frames"}; - index outputSize = processor.numStats() * (get() + 1); + index outputSize = get().count() * (get() + 1); + index processorOutputSize = processor.numStats() * (get() + 1); + Result resizeResult = dest.resize(outputSize, numChannels, source.sampleRate()); @@ -159,14 +163,27 @@ class BufferStatsClient : public FluidBaseClient, } } FluidTensor tmp(numChannels, numFrames); - FluidTensor result(numChannels, outputSize); + FluidTensor result(numChannels, processorOutputSize); for (int i = 0; i < numChannels; i++) { tmp.row(i) <<= source.samps(get(), numFrames, get() + i); } processor.process(tmp, result, get(), weights); - for (int i = 0; i < numChannels; i++) { dest.samps(i) <<= result.row(i); } + + auto selection = get(); + + for (index i = 0; i < numChannels; ++i) + { + auto outputChannel = dest.samps(i); + auto resultChannel = result.row(i); + for(index j = 0, k = 0; j < processorOutputSize; ++j) + { + if(selection[j % 7]) + outputChannel(k++) = resultChannel(j); + } + } + return processingResult; } }; diff --git a/include/clients/rt/SpectralShapeClient.hpp b/include/clients/rt/SpectralShapeClient.hpp index 4cc758d7e..8b0c16d1f 100644 --- a/include/clients/rt/SpectralShapeClient.hpp +++ b/include/clients/rt/SpectralShapeClient.hpp @@ -27,6 +27,7 @@ namespace spectralshape { using algorithm::SpectralShape; enum SpectralShapeParamIndex { + kSelect, kMinFreq, kMaxFreq, kRollOffPercent, @@ -37,6 +38,7 @@ enum SpectralShapeParamIndex { }; constexpr auto SpectralShapeParams = defineParameters( + ChoicesParam("select","Selection of Features","centroid","spread","skew","kurtosis","rolloff","flatness","crest"), FloatParam("minFreq", "Low Frequency Bound", 0, Min(0)), FloatParam("maxFreq", "High Frequency Bound", -1, Min(-1)), FloatParam("rolloffPercent", "Rolloff Percent", 95, Min(0), Max(100)), @@ -70,12 +72,13 @@ class SpectralShapeClient : public FluidBaseClient, } SpectralShapeClient(ParamSetViewType& p) - : mParams(p), mSTFTBufferedProcess(get(), 1, 0) + : mParams(p), mSTFTBufferedProcess(get(), 1, 0), + mMaxOutputSize{asSigned(get().count())} { audioChannelsIn(1); - controlChannelsOut({1,7}); + controlChannelsOut({1,mMaxOutputSize}); setInputLabels({"audio input"}); - setOutputLabels({"centroid, spread, skewness, kurtosis, rolloff, flatness, crest factor"}); + setOutputLabels({"spectral features"}); mDescriptors = FluidTensor(7); } @@ -101,10 +104,17 @@ class SpectralShapeClient : public FluidBaseClient, get(), get(), get() == 1, get() == 1); }); - - // for (int i = 0; i < 7; ++i) - // output[asUnsigned(i)](0) = static_cast(mDescriptors(i)); - output[0] <<= mDescriptors; + + auto selection = get(); + index numSelected = asSigned(selection.count()); + index numOuts = std::min(mMaxOutputSize,numSelected); + for(index i = 0, j = 0 ; i < 7 && j < numOuts; ++i) + { + if(selection[asUnsigned(i)]) output[0](j++) = static_cast(mDescriptors(i)); + } + if(mMaxOutputSize > numSelected) + for(index i = (mMaxOutputSize - numSelected); i < mMaxOutputSize; ++i) + output[0](i) = 0; } index latency() { return get().winSize(); } @@ -123,6 +133,8 @@ class SpectralShapeClient : public FluidBaseClient, SpectralShape mAlgorithm; FluidTensor mMagnitude; FluidTensor mDescriptors; + + index mMaxOutputSize; }; } // namespace spectralshape