forked from MrBesen/soundboard
multi sample buttons
This commit is contained in:
parent
3585f6a538
commit
2f0c25c421
|
@ -16,15 +16,22 @@ public:
|
||||||
std::vector<std::string> devices;
|
std::vector<std::string> devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ButtonConfig {
|
struct SampleConfig {
|
||||||
std::string name;
|
|
||||||
std::string file;
|
std::string file;
|
||||||
std::string key;
|
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint64_t length;
|
uint64_t length;
|
||||||
float volume;
|
float volume;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ButtonConfig {
|
||||||
|
std::string name;
|
||||||
|
std::string key;
|
||||||
uint8_t width; // default is 6
|
uint8_t width; // default is 6
|
||||||
|
|
||||||
|
std::vector<SampleConfig> samples;
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,20 +12,20 @@ class SoundButton : public QPushButton
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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();
|
~SoundButton();
|
||||||
|
|
||||||
const std::string& getName() const;
|
const std::string& getName() const;
|
||||||
const std::string& getFile() const;
|
|
||||||
const std::string& getKeyCombo() const;
|
const std::string& getKeyCombo() const;
|
||||||
|
|
||||||
uint64_t getStartMS() const;
|
void addSample(Sample& sample);
|
||||||
uint64_t getLengthMS() const;
|
|
||||||
float getVolume() const;
|
|
||||||
|
|
||||||
void setStartMS(uint64_t startms);
|
|
||||||
void setLengthMS(uint64_t lengthms);
|
|
||||||
void setVolume(float v);
|
|
||||||
|
|
||||||
void setHighlighted(bool highlighted);
|
void setHighlighted(bool highlighted);
|
||||||
|
|
||||||
|
@ -42,11 +42,10 @@ private:
|
||||||
|
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string file;
|
|
||||||
std::string keycombo;
|
std::string keycombo;
|
||||||
uint64_t startms = 0;
|
|
||||||
uint64_t lengthms = 0; // ignored when length = 0
|
uint8_t currentSample = 0;
|
||||||
float volume = 1.f;
|
std::vector<Sample> samples;
|
||||||
|
|
||||||
bool highlighted = false;
|
bool highlighted = false;
|
||||||
bool disabled = false;
|
bool disabled = false;
|
||||||
|
|
|
@ -40,14 +40,30 @@ void from_json(const json& j, Config::AudioConfig& ac) {
|
||||||
readVector(ac.devices, j.value("devices", json::array()));
|
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) {
|
void from_json(const json& j, Config::ButtonConfig& bc) {
|
||||||
bc.name = j.value("name", "");
|
bc.name = j.value("name", "");
|
||||||
bc.file = j.value("file", "");
|
|
||||||
bc.key = j.value("key", "");
|
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);
|
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) {
|
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", "");
|
rc.audioPath = j.value("audioPath", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Config::ButtonConfig::isValid() const {
|
bool Config::SampleConfig::isValid() const {
|
||||||
return !file.empty();
|
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() {
|
void Config::load() {
|
||||||
std::ifstream stream(binaryPath + file);
|
std::ifstream stream(binaryPath + file);
|
||||||
json json;
|
json json;
|
||||||
|
|
|
@ -169,12 +169,13 @@ void MainWindow::loadButtonsFromConfig() {
|
||||||
for (const Config::ButtonConfig& bc : line) {
|
for (const Config::ButtonConfig& bc : line) {
|
||||||
if (!bc.isValid()) continue;
|
if (!bc.isValid()) continue;
|
||||||
|
|
||||||
SoundButton* sb = new SoundButton(bc.file, bc.name, bc.key);
|
SoundButton* sb = new SoundButton(bc.name, bc.key);
|
||||||
sb->setStartMS(bc.offset);
|
for(const Config::SampleConfig& sc : bc.samples) {
|
||||||
sb->setLengthMS(bc.length);
|
if(!sc.isValid()) continue;
|
||||||
sb->setVolume(bc.volume);
|
|
||||||
|
|
||||||
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);
|
soundbuttons.push_back(sb);
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
uint64_t SoundButton::nextid = 0;
|
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) {
|
SoundButton::SoundButton(const std::string& name_, const std::string& keycombo, QWidget* parent) : QPushButton(parent), id(nextid++), name(name_), keycombo(keycombo) {
|
||||||
name = (name_.empty() ? filename : name_);
|
|
||||||
|
|
||||||
QString info = getInfo();
|
QString info = getInfo();
|
||||||
setText(info);
|
setText(info);
|
||||||
setObjectName(QString::fromStdString("soundButton" + std::to_string(id)));
|
setObjectName(QString::fromStdString("soundButton" + std::to_string(id)));
|
||||||
|
@ -34,36 +32,12 @@ const std::string& SoundButton::getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& SoundButton::getFile() const {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& SoundButton::getKeyCombo() const {
|
const std::string& SoundButton::getKeyCombo() const {
|
||||||
return keycombo;
|
return keycombo;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SoundButton::getStartMS() const {
|
void SoundButton::addSample(Sample& s) {
|
||||||
return startms;
|
samples.push_back(s);
|
||||||
}
|
|
||||||
|
|
||||||
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::setHighlighted(bool highlighted_) {
|
void SoundButton::setHighlighted(bool highlighted_) {
|
||||||
|
@ -78,33 +52,43 @@ void SoundButton::paintEvent(QPaintEvent* event) {
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
if(highlighted) {
|
if(highlighted) {
|
||||||
QSize s = size();
|
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.setPen(QPen(Qt::red));
|
||||||
painter.drawRect(rect);
|
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
|
painter.setPen(QPen(Qt::white));
|
||||||
if(text.isEmpty())
|
QPoint textPos(0, painter.fontMetrics().height());
|
||||||
return;
|
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() {
|
void SoundButton::play() {
|
||||||
if(disabled) return;
|
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 {
|
try {
|
||||||
Sound::instance().addPlayback(file, volume, startms, endms);
|
Sound::instance().addPlayback(sample.file, sample.volume, sample.startms, endms);
|
||||||
} catch(const std::exception& e) {
|
} 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();
|
setDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundButton::setDisabled() {
|
void SoundButton::setDisabled() {
|
||||||
|
|
Loading…
Reference in New Issue