Tap Tempo, ToobAmp v1.1.72

This commit is contained in:
Robin E. R. Davies
2026-01-10 10:41:20 -05:00
parent 6e1657933b
commit fdeb1fef5e
49 changed files with 397 additions and 94 deletions
+104 -10
View File
@@ -188,13 +188,15 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
{
pLv2Effect->SetAudioSidechainBuffer(i, this->pedalboardInputBuffers[i]);
}
else
else
{
// just use the first output buffer for all sidechain inputs.
pLv2Effect->SetAudioSidechainBuffer(i, this->pedalboardInputBuffers[0]);
}
}
} else if (item.sideChainInputId() != -1) {
}
else if (item.sideChainInputId() != -1)
{
IEffect *pSideChainInput = GetEffect(item.sideChainInputId());
if (pSideChainInput)
@@ -205,13 +207,15 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
{
pLv2Effect->SetAudioSidechainBuffer(i, pSideChainInput->GetAudioOutputBuffer(i));
}
else
else
{
// just use the first output buffer for all sidechain inputs.
pLv2Effect->SetAudioSidechainBuffer(i, pSideChainInput->GetAudioOutputBuffer(0));
}
}
} else {
}
else
{
throw std::runtime_error("Internal error: Sidechain input IEffect not found.");
}
}
@@ -418,11 +422,14 @@ void Lv2Pedalboard::PrepareMidiMap(const PedalboardItem &pedalboardItem)
{
mapping.mappingType = MidiControlType::Select;
}
else if (binding.bindingType() == BINDING_TYPE_TAP_TEMPO) {
mapping.mappingType = MidiControlType::TapTempo;
}
else
{
mapping.mappingType = MidiControlType::Dial;
}
if (binding.bindingType() == BINDING_TYPE_NOTE)
if (binding.bindingType() == BINDING_TYPE_NOTE || binding.bindingType() == BINDING_TYPE_TAP_TEMPO)
{
mapping.key = 0x9000 | binding.note(); // i.e. midi note on.
}
@@ -539,6 +546,8 @@ bool Lv2Pedalboard::Run(float **inputBuffers, float **outputBuffers, uint32_t sa
outputBuffers[c][i] = this->pedalboardOutputBuffers[c][i] * volume;
}
}
this->currentFrameOffset += samples;
return true;
}
@@ -715,14 +724,17 @@ void Lv2Pedalboard::GatherPatchProperties(RealtimePatchPropertyRequest *pParamet
}
}
void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
void *callbackHandle,
MidiCallbackFn *pfnCallback)
void Lv2Pedalboard::OnMidiMessage(
const MidiEvent&event,
void *callbackHandle,
MidiCallbackFn *pfnCallback)
{
if (midiMappings.size() == 0)
return;
size_t size = event.size;
const uint8_t *message = event.buffer;
if (size < 2)
return;
uint8_t cmd = message[0];
@@ -791,7 +803,7 @@ void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
for (int i = min; i < midiMappings.size(); ++i)
{
auto &mapping = midiMappings[i];
MidiMapping &mapping = midiMappings[i];
if (mapping.key != searchKey)
break;
@@ -914,6 +926,11 @@ void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
}
break;
}
case MidiControlType::TapTempo:
{
handleTapTempo(value, event.timeStamp, mapping, callbackHandle, pfnCallback);
break;
}
case MidiControlType::None:
default:
break;
@@ -921,4 +938,81 @@ void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
}
}
}
}
}
void Lv2Pedalboard::handleTapTempo(uint8_t value, const MidiTimestamp& timestamp, MidiMapping &mapping, void *callbackHandle, MidiCallbackFn *pfnSetControlCallback)
{
if (value != 0) // only on note on
{
if (!mapping.lastTapTimestamp.isEmpty())
{
double seconds = timestamp.timeDiff(mapping.lastTapTimestamp);
if (seconds > 60.0/450.0) // debounce check. (~= 450bpm)
{
auto units = mapping.pPortInfo->units();
float controlValue = -1;
switch (units)
{
case Units::bpm:
{
controlValue = 60.0f / (float)seconds;
break;
}
case Units::hz:
{
controlValue = 1.0f / (float)seconds;
break;
}
case Units::s:
{
controlValue = (float)(seconds);
break;
}
case Units::ms:
{
controlValue = (float)(seconds * 1000.0);
break;
}
default:
{
controlValue = -1;
}
}
if (mapping.pPortInfo->min_value() < mapping.pPortInfo->max_value())
{
if (controlValue < mapping.pPortInfo->min_value())
{
controlValue = -1;
}
else if (controlValue > mapping.pPortInfo->max_value())
{
controlValue = -1;
}
}
else
{
if (controlValue > mapping.pPortInfo->min_value())
{
controlValue = -1;
}
else if (controlValue < mapping.pPortInfo->max_value())
{
controlValue = -1;
}
}
if (controlValue != -1)
{
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
if (pEffect->IsLv2Effect())
{
Lv2Effect *pLv2Effect = dynamic_cast<Lv2Effect *>(pEffect);
pEffect->SetControl(mapping.controlIndex, controlValue);
pfnSetControlCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), controlValue);
}
}
}
}
mapping.lastTapTimestamp = timestamp;
}
}