Make host audio meters independent from each other
This commit is contained in:
parent
5e9b50dbea
commit
6c82749f2a
1 changed files with 197 additions and 125 deletions
|
|
@ -36,11 +36,6 @@ struct HostAudio : TerminalModule {
|
||||||
dsp::RCFilter dcFilters[numIO];
|
dsp::RCFilter dcFilters[numIO];
|
||||||
bool dcFilterEnabled = (numIO == 2);
|
bool dcFilterEnabled = (numIO == 2);
|
||||||
|
|
||||||
// for stereo meter
|
|
||||||
volatile bool resetMeters = true;
|
|
||||||
float gainMeterL = 0.0f;
|
|
||||||
float gainMeterR = 0.0f;
|
|
||||||
|
|
||||||
HostAudio()
|
HostAudio()
|
||||||
: pcontext(static_cast<CardinalPluginContext*>(APP)),
|
: pcontext(static_cast<CardinalPluginContext*>(APP)),
|
||||||
numParams(numIO == 2 ? 1 : 0),
|
numParams(numIO == 2 ? 1 : 0),
|
||||||
|
|
@ -63,13 +58,10 @@ struct HostAudio : TerminalModule {
|
||||||
void onReset() override
|
void onReset() override
|
||||||
{
|
{
|
||||||
dcFilterEnabled = (numIO == 2);
|
dcFilterEnabled = (numIO == 2);
|
||||||
resetMeters = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSampleRateChange(const SampleRateChangeEvent& e) override
|
void onSampleRateChange(const SampleRateChangeEvent& e) override
|
||||||
{
|
{
|
||||||
resetMeters = true;
|
|
||||||
|
|
||||||
for (int i=0; i<numIO; ++i)
|
for (int i=0; i<numIO; ++i)
|
||||||
dcFilters[i].setCutoffFreq(10.f * e.sampleTime);
|
dcFilters[i].setCutoffFreq(10.f * e.sampleTime);
|
||||||
}
|
}
|
||||||
|
|
@ -103,74 +95,6 @@ struct HostAudio : TerminalModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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<numInputs; ++i)
|
|
||||||
{
|
|
||||||
float v = inputs[i].getVoltageSum() * 0.1f;
|
|
||||||
|
|
||||||
// Apply DC filter
|
|
||||||
if (dcFilterEnabled)
|
|
||||||
{
|
|
||||||
dcFilters[i].process(v);
|
|
||||||
v = dcFilters[i].highpass();
|
|
||||||
}
|
|
||||||
|
|
||||||
dataOuts[i][k] += clamp(v * gain, -1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numInputs == 2)
|
|
||||||
{
|
|
||||||
const bool connected = inputs[1].isConnected();
|
|
||||||
|
|
||||||
if (! connected)
|
|
||||||
dataOuts[1][k] += valueL;
|
|
||||||
|
|
||||||
if (dataFrame == blockFrames)
|
|
||||||
{
|
|
||||||
if (resetMeters)
|
|
||||||
gainMeterL = gainMeterR = 0.0f;
|
|
||||||
|
|
||||||
gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat(dataOuts[0], blockFrames));
|
|
||||||
|
|
||||||
if (connected)
|
|
||||||
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat(dataOuts[1], blockFrames));
|
|
||||||
else
|
|
||||||
gainMeterR = gainMeterL;
|
|
||||||
|
|
||||||
resetMeters = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json_t* dataToJson() override
|
json_t* dataToJson() override
|
||||||
{
|
{
|
||||||
json_t* const rootJ = json_object();
|
json_t* const rootJ = json_object();
|
||||||
|
|
@ -189,28 +113,139 @@ struct HostAudio : TerminalModule {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int numIO>
|
struct HostAudio2 : HostAudio<2> {
|
||||||
struct HostAudioNanoMeter : NanoMeter {
|
// for stereo meter
|
||||||
HostAudio<numIO>* const module;
|
int internalDataFrame = 0;
|
||||||
|
float internalDataBuffer[2][128];
|
||||||
|
volatile bool resetMeters = true;
|
||||||
|
float gainMeterL = 0.0f;
|
||||||
|
float gainMeterR = 0.0f;
|
||||||
|
|
||||||
HostAudioNanoMeter(HostAudio<numIO>* const m)
|
HostAudio2()
|
||||||
: module(m)
|
: 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;
|
return;
|
||||||
|
|
||||||
// Only fetch new values once DSP side is updated
|
float** const dataOuts = pcontext->dataOuts;
|
||||||
gainMeterL = module->gainMeterL;
|
|
||||||
gainMeterR = module->gainMeterR;
|
// gain (stereo variant only)
|
||||||
module->resetMeters = true;
|
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<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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<int numIO>
|
template<int numIO>
|
||||||
struct HostAudioWidget : ModuleWidgetWith8HP {
|
struct HostAudioWidget : ModuleWidgetWith8HP {
|
||||||
HostAudio<numIO>* const module;
|
HostAudio<numIO>* const module;
|
||||||
|
|
@ -228,41 +263,6 @@ struct HostAudioWidget : ModuleWidgetWith8HP {
|
||||||
createAndAddInput(i);
|
createAndAddInput(i);
|
||||||
createAndAddOutput(i);
|
createAndAddOutput(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<numIO; ++i)
|
|
||||||
{
|
|
||||||
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 {
|
void appendContextMenu(Menu* const menu) override {
|
||||||
|
|
@ -273,7 +273,79 @@ struct HostAudioWidget : ModuleWidgetWith8HP {
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
Model* modelHostAudio2 = createModel<HostAudio<2>, HostAudioWidget<2>>("HostAudio2");
|
struct HostAudioNanoMeter : NanoMeter {
|
||||||
Model* modelHostAudio8 = createModel<HostAudio<8>, HostAudioWidget<8>>("HostAudio8");
|
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<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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<char>('0'+i+1),'\0'};
|
||||||
|
drawTextLine(args.vg, i, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWidgetWith8HP::draw(args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Model* modelHostAudio2 = createModel<HostAudio2, HostAudioWidget2>("HostAudio2");
|
||||||
|
Model* modelHostAudio8 = createModel<HostAudio8, HostAudioWidget8>("HostAudio8");
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue