Browse Source

Make host audio meters independent from each other

tags/22.03
falkTX 3 years ago
parent
commit
6c82749f2a
1 changed files with 163 additions and 91 deletions
  1. +163
    -91
      plugins/Cardinal/src/HostAudio.cpp

+ 163
- 91
plugins/Cardinal/src/HostAudio.cpp View File

@@ -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<CardinalPluginContext*>(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; i<numIO; ++i)
dcFilters[i].setCutoffFreq(10.f * e.sampleTime);
}
@@ -103,7 +95,51 @@ struct HostAudio : TerminalModule {
}
}

void processTerminalOutput(const ProcessArgs&) override
json_t* dataToJson() override
{
json_t* const rootJ = json_object();
DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr);

json_object_set_new(rootJ, "dcFilter", json_boolean(dcFilterEnabled));
return rootJ;
}

void dataFromJson(json_t* const rootJ) override
{
json_t* const dcFilterJ = json_object_get(rootJ, "dcFilter");
DISTRHO_SAFE_ASSERT_RETURN(dcFilterJ != nullptr,);

dcFilterEnabled = json_boolean_value(dcFilterJ);
}
};

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;

HostAudio2()
: HostAudio<2>()
{
std::memset(internalDataBuffer, 0, sizeof(internalDataBuffer));
}

void onReset() override
{
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();

@@ -116,11 +152,15 @@ struct HostAudio : TerminalModule {

float** const dataOuts = pcontext->dataOuts;

// stereo version gain
const float gain = numParams != 0 ? std::pow(params[0].getValue(), 2.f) : 1.0f;
// gain (stereo variant only)
const float gain = std::pow(params[0].getValue(), 2.f);

// left/mono check
const bool in2connected = inputs[1].isConnected();

// read first value, special case for mono mode
// read stereo values
float valueL = inputs[0].getVoltageSum() * 0.1f;
float valueR = inputs[1].getVoltageSum() * 0.1f;

// Apply DC filter
if (dcFilterEnabled)
@@ -132,68 +172,111 @@ struct HostAudio : TerminalModule {
valueL = clamp(valueL * gain, -1.0f, 1.0f);
dataOuts[0][k] += valueL;

// read everything else
for (int i=1; i<numInputs; ++i)
if (in2connected)
{
float v = inputs[i].getVoltageSum() * 0.1f;

// Apply DC filter
if (dcFilterEnabled)
{
dcFilters[i].process(v);
v = dcFilters[i].highpass();
dcFilters[1].process(valueR);
valueR = dcFilters[1].highpass();
}

dataOuts[i][k] += clamp(v * gain, -1.0f, 1.0f);
valueR = clamp(valueR * gain, -1.0f, 1.0f);
dataOuts[1][k] += valueR;
}

if (numInputs == 2)
else
{
const bool connected = inputs[1].isConnected();
valueR = valueL;
dataOuts[1][k] += valueL;
}

if (! connected)
dataOuts[1][k] += valueL;
const int j = internalDataFrame++;
internalDataBuffer[0][j] = valueL;
internalDataBuffer[1][j] = valueR;

if (dataFrame == blockFrames)
{
if (resetMeters)
gainMeterL = gainMeterR = 0.0f;
if (internalDataFrame == 128)
{
internalDataFrame = 0;

gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(dataOuts[0], blockFrames));
if (resetMeters)
gainMeterL = gainMeterR = 0.0f;

if (connected)
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(dataOuts[1], blockFrames));
else
gainMeterR = gainMeterL;
gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(internalDataBuffer[0], 128));

resetMeters = false;
}
if (in2connected)
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(internalDataBuffer[1], 128));
else
gainMeterR = gainMeterL;

resetMeters = false;
}
}
};

json_t* dataToJson() override
struct HostAudio8 : HostAudio<8> {
// no meters in this variant

void processTerminalOutput(const ProcessArgs&) override
{
json_t* const rootJ = json_object();
DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr);
const int blockFrames = pcontext->engine->getBlockFrames();

json_object_set_new(rootJ, "dcFilter", json_boolean(dcFilterEnabled));
return rootJ;
// 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<numInputs; ++i)
{
float v = inputs[i].getVoltageSum() * 0.1f;

if (dcFilterEnabled)
{
dcFilters[i].process(v);
v = dcFilters[i].highpass();
}

dataOuts[i][k] += clamp(v, -1.0f, 1.0f);
}
}

void dataFromJson(json_t* const rootJ) override
};

// --------------------------------------------------------------------------------------------------------------------

template<int numIO>
struct HostAudioWidget : ModuleWidgetWith8HP {
HostAudio<numIO>* const module;

HostAudioWidget(HostAudio<numIO>* const m)
: module(m)
{
json_t* const dcFilterJ = json_object_get(rootJ, "dcFilter");
DISTRHO_SAFE_ASSERT_RETURN(dcFilterJ != nullptr,);
setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));

dcFilterEnabled = json_boolean_value(dcFilterJ);
createAndAddScrews();

for (uint i=0; i<numIO; ++i)
{
createAndAddInput(i);
createAndAddOutput(i);
}
}

void appendContextMenu(Menu* const menu) override {
menu->addChild(new MenuSeparator);
menu->addChild(createBoolPtrMenuItem("DC blocker", "", &module->dcFilterEnabled));
}
};

template<int numIO>
// --------------------------------------------------------------------------------------------------------------------

struct HostAudioNanoMeter : NanoMeter {
HostAudio<numIO>* const module;
HostAudio2* const module;

HostAudioNanoMeter(HostAudio<numIO>* const m)
HostAudioNanoMeter(HostAudio2* const m)
: module(m)
{
hasGainKnob = true;
@@ -211,69 +294,58 @@ struct HostAudioNanoMeter : NanoMeter {
}
};

template<int numIO>
struct HostAudioWidget : ModuleWidgetWith8HP {
HostAudio<numIO>* const module;
// --------------------------------------------------------------------------------------------------------------------

HostAudioWidget(HostAudio<numIO>* const m)
: module(m)
struct HostAudioWidget2 : HostAudioWidget<2> {
HostAudioWidget2(HostAudio2* const m)
: HostAudioWidget<2>(m)
{
setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));
// FIXME
const float middleX = box.size.x * 0.5f;
addParam(createParamCentered<NanoKnob>(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);
}

createAndAddScrews();
void draw(const DrawArgs& args) override
{
drawBackground(args.vg);
drawOutputJacksArea(args.vg, 2);
setupTextLines(args.vg);

for (uint i=0; i<numIO; ++i)
{
createAndAddInput(i);
createAndAddOutput(i);
}
drawTextLine(args.vg, 0, "Left/M");
drawTextLine(args.vg, 1, "Right");

if (numIO == 2)
{
// FIXME
const float middleX = box.size.x * 0.5f;
addParam(createParamCentered<NanoKnob>(Vec(middleX, 310.0f), m, 0));

HostAudioNanoMeter<numIO>* const meter = new HostAudioNanoMeter<numIO>(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);
}
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, numIO);
drawOutputJacksArea(args.vg, 8);
setupTextLines(args.vg);

if (numIO == 2)
{
drawTextLine(args.vg, 0, "Left/M");
drawTextLine(args.vg, 1, "Right");
}
else
for (int i=0; i<8; ++i)
{
for (int i=0; i<numIO; ++i)
{
char text[] = {'A','u','d','i','o',' ',static_cast<char>('0'+i+1),'\0'};
drawTextLine(args.vg, i, text);
}
char text[] = {'A','u','d','i','o',' ',static_cast<char>('0'+i+1),'\0'};
drawTextLine(args.vg, i, text);
}

ModuleWidgetWith8HP::draw(args);
}

void appendContextMenu(Menu* const menu) override {
menu->addChild(new MenuSeparator);
menu->addChild(createBoolPtrMenuItem("DC blocker", "", &module->dcFilterEnabled));
}
};

// --------------------------------------------------------------------------------------------------------------------

Model* modelHostAudio2 = createModel<HostAudio<2>, HostAudioWidget<2>>("HostAudio2");
Model* modelHostAudio8 = createModel<HostAudio<8>, HostAudioWidget<8>>("HostAudio8");
Model* modelHostAudio2 = createModel<HostAudio2, HostAudioWidget2>("HostAudio2");
Model* modelHostAudio8 = createModel<HostAudio8, HostAudioWidget8>("HostAudio8");

// --------------------------------------------------------------------------------------------------------------------

Loading…
Cancel
Save