From 6c82749f2a19dac13af79cb4ecff0c6b0a8845d0 Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 7 Mar 2022 10:42:47 +0000 Subject: [PATCH] Make host audio meters independent from each other --- plugins/Cardinal/src/HostAudio.cpp | 322 ++++++++++++++++++----------- 1 file changed, 197 insertions(+), 125 deletions(-) diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index 68459ae..8e12603 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -36,11 +36,6 @@ struct HostAudio : TerminalModule { dsp::RCFilter dcFilters[numIO]; bool dcFilterEnabled = (numIO == 2); - // for stereo meter - volatile bool resetMeters = true; - float gainMeterL = 0.0f; - float gainMeterR = 0.0f; - HostAudio() : pcontext(static_cast(APP)), numParams(numIO == 2 ? 1 : 0), @@ -63,13 +58,10 @@ struct HostAudio : TerminalModule { void onReset() override { dcFilterEnabled = (numIO == 2); - resetMeters = true; } void onSampleRateChange(const SampleRateChangeEvent& e) override { - resetMeters = true; - for (int i=0; iengine->getBlockFrames(); - - // only incremented on output - const int k = dataFrame++; - DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); - - if (isBypassed()) - return; - - float** const dataOuts = pcontext->dataOuts; - - // stereo version gain - const float gain = numParams != 0 ? std::pow(params[0].getValue(), 2.f) : 1.0f; - - // read first value, special case for mono mode - float valueL = inputs[0].getVoltageSum() * 0.1f; - - // Apply DC filter - if (dcFilterEnabled) - { - dcFilters[0].process(valueL); - valueL = dcFilters[0].highpass(); - } - - valueL = clamp(valueL * gain, -1.0f, 1.0f); - dataOuts[0][k] += valueL; - - // read everything else - for (int i=1; i -struct HostAudioNanoMeter : NanoMeter { - HostAudio* const module; +struct HostAudio2 : HostAudio<2> { + // for stereo meter + int internalDataFrame = 0; + float internalDataBuffer[2][128]; + volatile bool resetMeters = true; + float gainMeterL = 0.0f; + float gainMeterR = 0.0f; - HostAudioNanoMeter(HostAudio* const m) - : module(m) + HostAudio2() + : HostAudio<2>() { - hasGainKnob = true; + std::memset(internalDataBuffer, 0, sizeof(internalDataBuffer)); } - void updateMeters() override + void onReset() override { - if (module == nullptr || module->resetMeters) + HostAudio<2>::onReset(); + resetMeters = true; + } + + void onSampleRateChange(const SampleRateChangeEvent& e) override + { + HostAudio<2>::onSampleRateChange(e); + resetMeters = true; + } + + void processTerminalOutput(const ProcessArgs&) + { + const int blockFrames = pcontext->engine->getBlockFrames(); + + // only incremented on output + const int k = dataFrame++; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); + + if (isBypassed()) return; - // Only fetch new values once DSP side is updated - gainMeterL = module->gainMeterL; - gainMeterR = module->gainMeterR; - module->resetMeters = true; + float** const dataOuts = pcontext->dataOuts; + + // gain (stereo variant only) + const float gain = std::pow(params[0].getValue(), 2.f); + + // left/mono check + const bool in2connected = inputs[1].isConnected(); + + // read stereo values + float valueL = inputs[0].getVoltageSum() * 0.1f; + float valueR = inputs[1].getVoltageSum() * 0.1f; + + // Apply DC filter + if (dcFilterEnabled) + { + dcFilters[0].process(valueL); + valueL = dcFilters[0].highpass(); + } + + valueL = clamp(valueL * gain, -1.0f, 1.0f); + dataOuts[0][k] += valueL; + + if (in2connected) + { + if (dcFilterEnabled) + { + dcFilters[1].process(valueR); + valueR = dcFilters[1].highpass(); + } + + valueR = clamp(valueR * gain, -1.0f, 1.0f); + dataOuts[1][k] += valueR; + } + else + { + valueR = valueL; + dataOuts[1][k] += valueL; + } + + const int j = internalDataFrame++; + internalDataBuffer[0][j] = valueL; + internalDataBuffer[1][j] = valueR; + + if (internalDataFrame == 128) + { + internalDataFrame = 0; + + if (resetMeters) + gainMeterL = gainMeterR = 0.0f; + + gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(internalDataBuffer[0], 128)); + + if (in2connected) + gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(internalDataBuffer[1], 128)); + else + gainMeterR = gainMeterL; + + resetMeters = false; + } } }; +struct HostAudio8 : HostAudio<8> { + // no meters in this variant + + void processTerminalOutput(const ProcessArgs&) override + { + const int blockFrames = pcontext->engine->getBlockFrames(); + + // only incremented on output + const int k = dataFrame++; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); + + if (isBypassed()) + return; + + float** const dataOuts = pcontext->dataOuts; + + for (int i=0; i struct HostAudioWidget : ModuleWidgetWith8HP { HostAudio* const module; @@ -228,41 +263,6 @@ struct HostAudioWidget : ModuleWidgetWith8HP { createAndAddInput(i); createAndAddOutput(i); } - - if (numIO == 2) - { - // FIXME - const float middleX = box.size.x * 0.5f; - addParam(createParamCentered(Vec(middleX, 310.0f), m, 0)); - - HostAudioNanoMeter* const meter = new HostAudioNanoMeter(m); - meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2); - meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f); - addChild(meter); - } - } - - void draw(const DrawArgs& args) override - { - drawBackground(args.vg); - drawOutputJacksArea(args.vg, numIO); - setupTextLines(args.vg); - - if (numIO == 2) - { - drawTextLine(args.vg, 0, "Left/M"); - drawTextLine(args.vg, 1, "Right"); - } - else - { - for (int i=0; i('0'+i+1),'\0'}; - drawTextLine(args.vg, i, text); - } - } - - ModuleWidgetWith8HP::draw(args); } void appendContextMenu(Menu* const menu) override { @@ -273,7 +273,79 @@ struct HostAudioWidget : ModuleWidgetWith8HP { // -------------------------------------------------------------------------------------------------------------------- -Model* modelHostAudio2 = createModel, HostAudioWidget<2>>("HostAudio2"); -Model* modelHostAudio8 = createModel, HostAudioWidget<8>>("HostAudio8"); +struct HostAudioNanoMeter : NanoMeter { + HostAudio2* const module; + + HostAudioNanoMeter(HostAudio2* const m) + : module(m) + { + hasGainKnob = true; + } + + void updateMeters() override + { + if (module == nullptr || module->resetMeters) + return; + + // Only fetch new values once DSP side is updated + gainMeterL = module->gainMeterL; + gainMeterR = module->gainMeterR; + module->resetMeters = true; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +struct HostAudioWidget2 : HostAudioWidget<2> { + HostAudioWidget2(HostAudio2* const m) + : HostAudioWidget<2>(m) + { + // FIXME + const float middleX = box.size.x * 0.5f; + addParam(createParamCentered(Vec(middleX, 310.0f), m, 0)); + + HostAudioNanoMeter* const meter = new HostAudioNanoMeter(m); + meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2); + meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f); + addChild(meter); + } + + void draw(const DrawArgs& args) override + { + drawBackground(args.vg); + drawOutputJacksArea(args.vg, 2); + setupTextLines(args.vg); + + drawTextLine(args.vg, 0, "Left/M"); + drawTextLine(args.vg, 1, "Right"); + + ModuleWidgetWith8HP::draw(args); + } +}; + +struct HostAudioWidget8 : HostAudioWidget<8> { + HostAudioWidget8(HostAudio8* const m) + : HostAudioWidget<8>(m) {} + + void draw(const DrawArgs& args) override + { + drawBackground(args.vg); + drawOutputJacksArea(args.vg, 8); + setupTextLines(args.vg); + + for (int i=0; i<8; ++i) + { + char text[] = {'A','u','d','i','o',' ',static_cast('0'+i+1),'\0'}; + drawTextLine(args.vg, i, text); + } + + ModuleWidgetWith8HP::draw(args); + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +Model* modelHostAudio2 = createModel("HostAudio2"); +Model* modelHostAudio8 = createModel("HostAudio8"); // --------------------------------------------------------------------------------------------------------------------