Protection against invalid Channel Router settings.
This commit is contained in:
@@ -39,6 +39,8 @@ PiPedal 2.0 can now be installed as a Progressive Web Application (PWA). This al
|
|||||||
|
|
||||||
- Split controls now support double-tap to reset to a default value. (Other controls already support this feature).
|
- Split controls now support double-tap to reset to a default value. (Other controls already support this feature).
|
||||||
|
|
||||||
|
- Runtime detection and use of AVX extensions for TooB plugins. Reduces CPU use of TooB NAM by 50% on most x86_64/amd64 computers.
|
||||||
|
|
||||||
## PiPedal 1.5.99 Beta
|
## PiPedal 1.5.99 Beta
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
+58
-41
@@ -1189,7 +1189,7 @@ private:
|
|||||||
std::vector<float *> *pOutputBuffers;
|
std::vector<float *> *pOutputBuffers;
|
||||||
pedalboard = this->realtimeActivePedalboard;
|
pedalboard = this->realtimeActivePedalboard;
|
||||||
pInputBuffers = &(audioDriver->MainInputBuffers());
|
pInputBuffers = &(audioDriver->MainInputBuffers());
|
||||||
|
|
||||||
pOutputBuffers = &(audioDriver->MainOutputBuffers());
|
pOutputBuffers = &(audioDriver->MainOutputBuffers());
|
||||||
|
|
||||||
if (pedalboard == nullptr || pInputBuffers->size() == 0 || pOutputBuffers->size() == 0)
|
if (pedalboard == nullptr || pInputBuffers->size() == 0 || pOutputBuffers->size() == 0)
|
||||||
@@ -1255,60 +1255,79 @@ private:
|
|||||||
masterOutputBuffers[outputIx++] = audioDriver->GetDeviceOutputBuffer(nChannel);
|
masterOutputBuffers[outputIx++] = audioDriver->GetDeviceOutputBuffer(nChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void AccumulateVu(float*result, size_t nFrames, float*buffer)
|
inline void AccumulateVu(float *result, size_t nFrames, float *buffer)
|
||||||
{
|
{
|
||||||
float maxVal = *result;
|
float maxVal = *result;
|
||||||
for (size_t i = 0; i < nFrames; ++i)
|
for (size_t i = 0; i < nFrames; ++i)
|
||||||
{
|
{
|
||||||
float v = std::fabs(buffer[i]);
|
float v = std::fabs(buffer[i]);
|
||||||
if (v > maxVal)
|
if (v > maxVal)
|
||||||
{
|
{
|
||||||
maxVal = v;
|
maxVal = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result = maxVal;
|
*result = maxVal;
|
||||||
}
|
}
|
||||||
void AccumulateVuInputs(size_t nFrames,VuUpdateX&vuUpdate, const std::vector<int64_t>&channels)
|
void AccumulateVuInputs(size_t nFrames, VuUpdateX &vuUpdate, const std::vector<int64_t> &channels)
|
||||||
{
|
{
|
||||||
if (channels.size() == 0) return;
|
if (channels.size() == 0)
|
||||||
|
return;
|
||||||
AccumulateVu(&vuUpdate.inputMaxValueL_,nFrames,this->audioDriver->DeviceInputBuffers()[channels[0]]);
|
if (channels[0] == -1) // Indicates invalid channel router settings.
|
||||||
|
|
||||||
if (channels.size() == 2) {
|
|
||||||
AccumulateVu(&vuUpdate.inputMaxValueR_,nFrames,this->audioDriver->DeviceInputBuffers()[channels[1]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void AccumulateVuOutputs(size_t nFrames,VuUpdateX&vuUpdate, const std::vector<int64_t>&channels)
|
|
||||||
{
|
|
||||||
if (channels.size() == 0) return;
|
|
||||||
AccumulateVu(&vuUpdate.outputMaxValueL_,nFrames,this->audioDriver->DeviceOutputBuffers()[channels[0]]);
|
|
||||||
if (channels.size() >= 2) {
|
|
||||||
AccumulateVu(&vuUpdate.outputMaxValueR_,nFrames,this->audioDriver->DeviceOutputBuffers()[channels[1]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void ComputeMasterVus(size_t nFrames) {
|
|
||||||
if (this->realtimeVuBuffers)
|
|
||||||
{
|
{
|
||||||
float** audioBuffers;
|
vuUpdate.inputMaxValueL_ = 0;
|
||||||
|
vuUpdate.inputMaxValueR_ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& vuUpdate: this->realtimeVuBuffers->vuUpdateWorkingData)
|
AccumulateVu(&vuUpdate.inputMaxValueL_, nFrames, this->audioDriver->DeviceInputBuffers()[channels[0]]);
|
||||||
|
|
||||||
|
if (channels.size() == 2)
|
||||||
|
{
|
||||||
|
AccumulateVu(&vuUpdate.inputMaxValueR_, nFrames, this->audioDriver->DeviceInputBuffers()[channels[1]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AccumulateVuOutputs(size_t nFrames, VuUpdateX &vuUpdate, const std::vector<int64_t> &channels)
|
||||||
|
{
|
||||||
|
if (channels.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (channels[0] == -1) // Indicates invalid channel router settings.
|
||||||
|
{
|
||||||
|
vuUpdate.outputMaxValueL_ = 0;
|
||||||
|
vuUpdate.outputMaxValueR_ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccumulateVu(&vuUpdate.outputMaxValueL_, nFrames, this->audioDriver->DeviceOutputBuffers()[channels[0]]);
|
||||||
|
if (channels.size() >= 2)
|
||||||
|
{
|
||||||
|
AccumulateVu(&vuUpdate.outputMaxValueR_, nFrames, this->audioDriver->DeviceOutputBuffers()[channels[1]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ComputeMasterVus(size_t nFrames)
|
||||||
|
{
|
||||||
|
if (this->realtimeVuBuffers)
|
||||||
|
{
|
||||||
|
float **audioBuffers;
|
||||||
|
|
||||||
|
for (auto &vuUpdate : this->realtimeVuBuffers->vuUpdateWorkingData)
|
||||||
{
|
{
|
||||||
if (vuUpdate.instanceId_ < 0)
|
if (vuUpdate.instanceId_ < 0)
|
||||||
{
|
{
|
||||||
switch (vuUpdate.instanceId_)
|
switch (vuUpdate.instanceId_)
|
||||||
{
|
{
|
||||||
case Pedalboard::START_CONTROL_ID:
|
case Pedalboard::START_CONTROL_ID:
|
||||||
AccumulateVuInputs(nFrames, vuUpdate, pHost->GetChannelSelection().mainInputChannels());
|
AccumulateVuInputs(nFrames, vuUpdate, pHost->GetChannelSelection().mainInputChannels());
|
||||||
break;
|
break;
|
||||||
case Pedalboard::END_CONTROL_ID:
|
case Pedalboard::END_CONTROL_ID:
|
||||||
AccumulateVuOutputs(nFrames, vuUpdate, pHost->GetChannelSelection().mainOutputChannels());
|
AccumulateVuOutputs(nFrames, vuUpdate, pHost->GetChannelSelection().mainOutputChannels());
|
||||||
break;
|
break;
|
||||||
case Pedalboard::AUX_START_CONTROL_ID:
|
case Pedalboard::AUX_START_CONTROL_ID:
|
||||||
AccumulateVuInputs(nFrames, vuUpdate, pHost->GetChannelSelection().auxInputChannels());
|
AccumulateVuInputs(nFrames, vuUpdate, pHost->GetChannelSelection().auxInputChannels());
|
||||||
break;
|
break;
|
||||||
case Pedalboard::AUX_END_CONTROL_ID:
|
case Pedalboard::AUX_END_CONTROL_ID:
|
||||||
AccumulateVuOutputs(nFrames, vuUpdate, pHost->GetChannelSelection().auxOutputChannels());
|
AccumulateVuOutputs(nFrames, vuUpdate, pHost->GetChannelSelection().auxOutputChannels());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1905,7 +1924,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void SetBypass(uint64_t instanceId, bool enabled)
|
virtual void SetBypass(uint64_t instanceId, bool enabled)
|
||||||
{
|
{
|
||||||
std::lock_guard guard(mutex);
|
std::lock_guard guard(mutex);
|
||||||
@@ -2067,7 +2085,7 @@ public:
|
|||||||
for (size_t i = 0; i < instanceIds.size(); ++i)
|
for (size_t i = 0; i < instanceIds.size(); ++i)
|
||||||
{
|
{
|
||||||
int64_t instanceId = instanceIds[i];
|
int64_t instanceId = instanceIds[i];
|
||||||
std::shared_ptr<Lv2Pedalboard>& pedalboard = this->currentPedalboard;
|
std::shared_ptr<Lv2Pedalboard> &pedalboard = this->currentPedalboard;
|
||||||
int64_t effectIndex = -1;
|
int64_t effectIndex = -1;
|
||||||
if (pedalboard != nullptr)
|
if (pedalboard != nullptr)
|
||||||
{
|
{
|
||||||
@@ -2091,8 +2109,7 @@ public:
|
|||||||
instanceId == Pedalboard::START_CONTROL_ID ||
|
instanceId == Pedalboard::START_CONTROL_ID ||
|
||||||
instanceId == Pedalboard::END_CONTROL_ID ||
|
instanceId == Pedalboard::END_CONTROL_ID ||
|
||||||
instanceId == Pedalboard::AUX_START_CONTROL_ID ||
|
instanceId == Pedalboard::AUX_START_CONTROL_ID ||
|
||||||
instanceId == Pedalboard::AUX_END_CONTROL_ID
|
instanceId == Pedalboard::AUX_END_CONTROL_ID)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
auto index = GetRealtimeItemIndex(instanceId);
|
auto index = GetRealtimeItemIndex(instanceId);
|
||||||
VuUpdateX v;
|
VuUpdateX v;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#include "ChannelRouterSettings.hpp"
|
#include "ChannelRouterSettings.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ static uint64_t countChannels(const std::vector<int64_t> &channels)
|
|||||||
}
|
}
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ChannelRouterSettings::numberOfAudioInputChannels() const
|
uint64_t ChannelRouterSettings::numberOfAudioInputChannels() const
|
||||||
{
|
{
|
||||||
@@ -71,75 +70,110 @@ uint64_t ChannelRouterSettings::numberOfAudioOutputChannels() const
|
|||||||
return countChannels(mainOutputChannels_);
|
return countChannels(mainOutputChannels_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelSelection::ChannelSelection(ChannelRouterSettings&settings)
|
ChannelSelection::ChannelSelection(ChannelRouterSettings &settings)
|
||||||
: mainInputChannels_(settings.mainInputChannels())
|
: mainInputChannels_(settings.mainInputChannels()), mainOutputChannels_(settings.mainOutputChannels()), auxInputChannels_(settings.auxInputChannels()), auxOutputChannels_(settings.auxOutputChannels())
|
||||||
, mainOutputChannels_(settings.mainOutputChannels())
|
|
||||||
, auxInputChannels_(settings.auxInputChannels())
|
|
||||||
, auxOutputChannels_(settings.auxOutputChannels())
|
|
||||||
{
|
{
|
||||||
normalizeChannelSelection();
|
normalizeChannelSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void normalizeInputChannels(std::vector<int64_t>&channels) {
|
static void normalizeInputChannels(std::vector<int64_t> &channels)
|
||||||
if (channels.size() == 2) {
|
{
|
||||||
if (channels[0] == -1 && channels[1] == -1)
|
if (channels.size() == 2)
|
||||||
|
{
|
||||||
|
if (channels[0] == -1 && channels[1] == -1)
|
||||||
{
|
{
|
||||||
channels.resize(0);
|
channels.resize(0);
|
||||||
} else if (channels[0] == channels[1]) {
|
}
|
||||||
|
else if (channels[0] == channels[1])
|
||||||
|
{
|
||||||
channels.resize(1);
|
channels.resize(1);
|
||||||
} else if (channels[1] == -1) {
|
}
|
||||||
channels.resize(1);} {
|
else if (channels[1] == -1)
|
||||||
|
{
|
||||||
|
channels.resize(1);
|
||||||
|
}
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void normalizeOutputChannels(std::vector<int64_t>&channels) {
|
static void normalizeOutputChannels(std::vector<int64_t> &channels)
|
||||||
|
{
|
||||||
normalizeInputChannels(channels);
|
normalizeInputChannels(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelSelection::normalizeChannelSelection() {
|
void ChannelSelection::normalizeChannelSelection()
|
||||||
|
{
|
||||||
normalizeInputChannels(mainInputChannels_);
|
normalizeInputChannels(mainInputChannels_);
|
||||||
normalizeOutputChannels(mainOutputChannels_);
|
normalizeOutputChannels(mainOutputChannels_);
|
||||||
normalizeInputChannels(auxInputChannels_);
|
normalizeInputChannels(auxInputChannels_);
|
||||||
normalizeOutputChannels(auxOutputChannels_);
|
normalizeOutputChannels(auxOutputChannels_);
|
||||||
|
|
||||||
// If either aux inputs or outputs are zero, don't do ANY aux processing.
|
// If either aux inputs or outputs are zero, don't do ANY aux processing.
|
||||||
if (auxInputChannels_.size() == 0)
|
if (auxInputChannels_.size() == 0)
|
||||||
{
|
{
|
||||||
auxOutputChannels_.resize(0);
|
auxOutputChannels_.resize(0);
|
||||||
} else if (auxOutputChannels_.size() == 0) {
|
}
|
||||||
|
else if (auxOutputChannels_.size() == 0)
|
||||||
|
{
|
||||||
auxInputChannels_.resize(0);
|
auxInputChannels_.resize(0);
|
||||||
}
|
}
|
||||||
// If either main inputs or outputs are empty, add send/receive dummy buffers. (Lv2 plugins shouldn't have to deal with this)
|
// If either main inputs or outputs are empty, add send/receive dummy buffers. (Lv2 plugins shouldn't have to deal with this)
|
||||||
if (mainInputChannels_.size() == 0)
|
if (mainInputChannels_.size() == 0)
|
||||||
{
|
{
|
||||||
mainInputChannels_.resize(1);
|
mainInputChannels_.resize(1);
|
||||||
mainInputChannels_[0] = -1;
|
mainInputChannels_[0] = -1;
|
||||||
}
|
}
|
||||||
if (mainOutputChannels_.size() == 0) {
|
if (mainOutputChannels_.size() == 0)
|
||||||
|
{
|
||||||
mainInputChannels_.resize(1);
|
mainInputChannels_.resize(1);
|
||||||
mainOutputChannels_[0] = -1;
|
mainOutputChannels_[0] = -1;
|
||||||
}
|
}
|
||||||
// Send buffers are what they are. Let the send plugin deal with it.
|
// Send buffers are what they are. Let the send plugin deal with it.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ChannelRouterSettings::ChannelRouterSettings()
|
ChannelRouterSettings::ChannelRouterSettings()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ChannelRouterPresetIndexEntry> ChannelRouterPresetBank::getIndexEntries()
|
std::vector<ChannelRouterPresetIndexEntry> ChannelRouterPresetBank::getIndexEntries()
|
||||||
{
|
{
|
||||||
std::vector<ChannelRouterPresetIndexEntry> result;
|
std::vector<ChannelRouterPresetIndexEntry> result;
|
||||||
for (auto &entry: entries_)
|
for (auto &entry : entries_)
|
||||||
{
|
{
|
||||||
result.push_back(ChannelRouterPresetIndexEntry{entry->id(), entry->name()});
|
result.push_back(ChannelRouterPresetIndexEntry{entry->id(), entry->name()});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HasIllegalChannel(const std::vector<int64_t> &channels)
|
||||||
|
{
|
||||||
|
for (auto c : channels)
|
||||||
|
{
|
||||||
|
if (c < 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelSelection::IsValid() const
|
||||||
|
{
|
||||||
|
if (mainInputChannels_.size() == 0 || mainOutputChannels_.size() == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (HasIllegalChannel(mainInputChannels_) ||
|
||||||
|
HasIllegalChannel(mainOutputChannels_) ||
|
||||||
|
HasIllegalChannel(auxInputChannels_) ||
|
||||||
|
HasIllegalChannel(auxOutputChannels_))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
JSON_MAP_BEGIN(ChannelRouterSettings)
|
JSON_MAP_BEGIN(ChannelRouterSettings)
|
||||||
JSON_MAP_REFERENCE(ChannelRouterSettings, configured)
|
JSON_MAP_REFERENCE(ChannelRouterSettings, configured)
|
||||||
JSON_MAP_REFERENCE(ChannelRouterSettings, changed)
|
JSON_MAP_REFERENCE(ChannelRouterSettings, changed)
|
||||||
@@ -155,7 +189,6 @@ JSON_MAP_REFERENCE(ChannelRouterPresetIndexEntry, id)
|
|||||||
JSON_MAP_REFERENCE(ChannelRouterPresetIndexEntry, name)
|
JSON_MAP_REFERENCE(ChannelRouterPresetIndexEntry, name)
|
||||||
JSON_MAP_END();
|
JSON_MAP_END();
|
||||||
|
|
||||||
|
|
||||||
JSON_MAP_BEGIN(ChannelRouterPresetBankEntry)
|
JSON_MAP_BEGIN(ChannelRouterPresetBankEntry)
|
||||||
JSON_MAP_REFERENCE(ChannelRouterPresetBankEntry, id)
|
JSON_MAP_REFERENCE(ChannelRouterPresetBankEntry, id)
|
||||||
JSON_MAP_REFERENCE(ChannelRouterPresetBankEntry, name)
|
JSON_MAP_REFERENCE(ChannelRouterPresetBankEntry, name)
|
||||||
@@ -167,4 +200,3 @@ JSON_MAP_REFERENCE(ChannelRouterPresetBank, nextId)
|
|||||||
JSON_MAP_REFERENCE(ChannelRouterPresetBank, version)
|
JSON_MAP_REFERENCE(ChannelRouterPresetBank, version)
|
||||||
JSON_MAP_REFERENCE(ChannelRouterPresetBank, entries)
|
JSON_MAP_REFERENCE(ChannelRouterPresetBank, entries)
|
||||||
JSON_MAP_END();
|
JSON_MAP_END();
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ namespace pipedal
|
|||||||
std::vector<int64_t> &auxInputChannels() { return auxInputChannels_; }
|
std::vector<int64_t> &auxInputChannels() { return auxInputChannels_; }
|
||||||
std::vector<int64_t> &auxOutputChannels() { return auxOutputChannels_; }
|
std::vector<int64_t> &auxOutputChannels() { return auxOutputChannels_; }
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
private:
|
private:
|
||||||
void normalizeChannelSelection();
|
void normalizeChannelSelection();
|
||||||
|
|
||||||
|
|||||||
@@ -1576,9 +1576,9 @@ void PiPedalModel::RestartAudio(bool useDummyAudioDriver)
|
|||||||
throw std::runtime_error("Audio configuration not valid.");
|
throw std::runtime_error("Audio configuration not valid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &channelSelection = this->storage.GetChannelSelection();
|
auto channelSelection = this->storage.GetChannelSelection();
|
||||||
|
|
||||||
this->audioHost->Open(jackServerSettings, channelSelection);
|
this->audioHost->Open(jackServerSettings, channelSelection);
|
||||||
|
|
||||||
this->pluginHost.OnConfigurationChanged(jackConfiguration, channelSelection);
|
this->pluginHost.OnConfigurationChanged(jackConfiguration, channelSelection);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user