From 2f0c25c421ad8e6bc0fce034f2c4160bd84dad6a Mon Sep 17 00:00:00 2001 From: mrbesen Date: Sun, 19 Dec 2021 15:53:57 +0100 Subject: [PATCH] multi sample buttons --- include/config.h | 13 +++++++-- include/soundbutton.h | 25 ++++++++-------- src/config.cpp | 31 ++++++++++++++++---- src/mainwindow.cpp | 11 +++---- src/soundbutton.cpp | 68 +++++++++++++++++-------------------------- 5 files changed, 80 insertions(+), 68 deletions(-) diff --git a/include/config.h b/include/config.h index 4fa818e..a847be3 100644 --- a/include/config.h +++ b/include/config.h @@ -16,15 +16,22 @@ public: std::vector devices; }; - struct ButtonConfig { - std::string name; + struct SampleConfig { std::string file; - std::string key; uint64_t offset; uint64_t length; float volume; + + bool isValid() const; + }; + + struct ButtonConfig { + std::string name; + std::string key; uint8_t width; // default is 6 + std::vector samples; + bool isValid() const; }; diff --git a/include/soundbutton.h b/include/soundbutton.h index ea51aeb..43b2509 100644 --- a/include/soundbutton.h +++ b/include/soundbutton.h @@ -12,20 +12,20 @@ class SoundButton : public QPushButton Q_OBJECT public: - explicit SoundButton(const std::string& filename, const std::string& name_ = "", const std::string& keycombo = "", QWidget* parent = nullptr); + struct Sample { + std::string file; + uint64_t startms = 0; + uint64_t lengthms = 0; // ignored when length = 0 + float volume = 1.f; + }; + + explicit SoundButton(const std::string& name_ = "", const std::string& keycombo = "", QWidget* parent = nullptr); ~SoundButton(); const std::string& getName() const; - const std::string& getFile() const; const std::string& getKeyCombo() const; - uint64_t getStartMS() const; - uint64_t getLengthMS() const; - float getVolume() const; - - void setStartMS(uint64_t startms); - void setLengthMS(uint64_t lengthms); - void setVolume(float v); + void addSample(Sample& sample); void setHighlighted(bool highlighted); @@ -42,11 +42,10 @@ private: uint64_t id; std::string name; - std::string file; std::string keycombo; - uint64_t startms = 0; - uint64_t lengthms = 0; // ignored when length = 0 - float volume = 1.f; + + uint8_t currentSample = 0; + std::vector samples; bool highlighted = false; bool disabled = false; diff --git a/src/config.cpp b/src/config.cpp index 79f0b2f..3ca8c81 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -40,14 +40,30 @@ void from_json(const json& j, Config::AudioConfig& ac) { readVector(ac.devices, j.value("devices", json::array())); } +void from_json(const json& j, Config::SampleConfig& sc) { + sc.file = j.value("file", ""); + sc.offset = j.value("offset", 0); + sc.length = j.value("length", 0); + sc.volume = j.value("volume", 1.f); +} + void from_json(const json& j, Config::ButtonConfig& bc) { bc.name = j.value("name", ""); - bc.file = j.value("file", ""); bc.key = j.value("key", ""); - bc.offset = j.value("offset", 0); - bc.length = j.value("length", 0); - bc.volume = j.value("volume", 1.f); bc.width = j.value("width", 6); + + // make it possible to volume control all samples from one value + float volume = j.value("value", 1.0); + + if(j.contains("samples")) { + // sample liste + readVector(bc.samples, j["samples"]); + for(Config::SampleConfig& sc : bc.samples) { + sc.volume *= volume; + } + } else if(j.contains("file")) { + bc.samples.push_back(j); // implizit cast + } } void from_json(const json& j, Config::RootConfig& rc) { @@ -64,10 +80,15 @@ void from_json(const json& j, Config::RootConfig& rc) { rc.audioPath = j.value("audioPath", ""); } -bool Config::ButtonConfig::isValid() const { +bool Config::SampleConfig::isValid() const { return !file.empty(); } +bool Config::ButtonConfig::isValid() const { + bool validfound = std::any_of(samples.begin(), samples.end(), [](const SampleConfig& sc){ return sc.isValid(); }); + return !samples.empty() && !name.empty() && validfound; +} + void Config::load() { std::ifstream stream(binaryPath + file); json json; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0ce8e77..5ede1f0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -169,12 +169,13 @@ void MainWindow::loadButtonsFromConfig() { for (const Config::ButtonConfig& bc : line) { if (!bc.isValid()) continue; - SoundButton* sb = new SoundButton(bc.file, bc.name, bc.key); - sb->setStartMS(bc.offset); - sb->setLengthMS(bc.length); - sb->setVolume(bc.volume); + SoundButton* sb = new SoundButton(bc.name, bc.key); + for(const Config::SampleConfig& sc : bc.samples) { + if(!sc.isValid()) continue; - Log::info << "Button: " << bc.name << ": " << bc.file << " " << x << " " << y; + SoundButton::Sample sample = {sc.file, sc.offset, sc.length, sc.volume}; + sb->addSample(sample); + } soundbuttons.push_back(sb); diff --git a/src/soundbutton.cpp b/src/soundbutton.cpp index 8e45f9b..37e15e1 100644 --- a/src/soundbutton.cpp +++ b/src/soundbutton.cpp @@ -8,9 +8,7 @@ uint64_t SoundButton::nextid = 0; -SoundButton::SoundButton(const std::string& filename, const std::string& name_, const std::string& keycombo, QWidget* parent) : QPushButton(parent), id(nextid++), file(filename), keycombo(keycombo) { - name = (name_.empty() ? filename : name_); - +SoundButton::SoundButton(const std::string& name_, const std::string& keycombo, QWidget* parent) : QPushButton(parent), id(nextid++), name(name_), keycombo(keycombo) { QString info = getInfo(); setText(info); setObjectName(QString::fromStdString("soundButton" + std::to_string(id))); @@ -34,36 +32,12 @@ const std::string& SoundButton::getName() const { return name; } -const std::string& SoundButton::getFile() const { - return file; -} - const std::string& SoundButton::getKeyCombo() const { return keycombo; } -uint64_t SoundButton::getStartMS() const { - return startms; -} - -uint64_t SoundButton::getLengthMS() const { - return lengthms; -} - -float SoundButton::getVolume() const { - return volume; -} - -void SoundButton::setStartMS(uint64_t startms_) { - startms = startms_; -} - -void SoundButton::setLengthMS(uint64_t lengthms_) { - lengthms = lengthms_; -} - -void SoundButton::setVolume(float v) { - volume = v; +void SoundButton::addSample(Sample& s) { + samples.push_back(s); } void SoundButton::setHighlighted(bool highlighted_) { @@ -78,33 +52,43 @@ void SoundButton::paintEvent(QPaintEvent* event) { QPainter painter(this); if(highlighted) { QSize s = size(); - QRect rect(HIGHLIGHTBORDEROFFSET, HIGHLIGHTBORDEROFFSET, s.width()-HIGHLIGHTBORDEROFFSET*2, s.height()-HIGHLIGHTBORDEROFFSET*2); + QRect rect(HIGHLIGHTBORDEROFFSET, HIGHLIGHTBORDEROFFSET, s.width() - HIGHLIGHTBORDEROFFSET*2, s.height() - HIGHLIGHTBORDEROFFSET*2); painter.setPen(QPen(Qt::red)); painter.drawRect(rect); } - QString text = ""; + if(samples.size() > 1) { + QString text = QString::fromStdString(std::to_string(currentSample+1) + "/" + std::to_string(samples.size())); - // cancel if nothing to print - if(text.isEmpty()) - return; - - painter.setPen(QPen(Qt::white)); - QPoint textPos(0, painter.fontMetrics().height()); - textPos.rx() = width() - painter.fontMetrics().horizontalAdvance(text) - 6; - painter.drawText(textPos, text); + painter.setPen(QPen(Qt::white)); + QPoint textPos(0, painter.fontMetrics().height()); + textPos.rx() = width() - painter.fontMetrics().horizontalAdvance(text) - 6; + painter.drawText(textPos, text); + } } void SoundButton::play() { if(disabled) return; - uint64_t endms = (lengthms == 0 ? 0 : startms + lengthms); + if(samples.size() == 0) { + Log::error << "Button " << name << " has no sample set"; + setDisabled(); + return; + } + + const Sample& sample = samples.at(currentSample++); + if(currentSample >= samples.size()) + currentSample = 0; + + uint64_t endms = (sample.lengthms == 0 ? 0 : sample.startms + sample.lengthms); try { - Sound::instance().addPlayback(file, volume, startms, endms); + Sound::instance().addPlayback(sample.file, sample.volume, sample.startms, endms); } catch(const std::exception& e) { - Log::error << "Catched Exception when plaing Audio File: " << file; + Log::error << "Catched Exception when plaing Audio File: " << sample.file; setDisabled(); } + + repaint(); } void SoundButton::setDisabled() {