add gain to beatpad, layoutgadget panel flag, nodeuiscene improvements

master
zetaPRIME 2021-11-12 22:26:13 -05:00
parent d0db5a6b4d
commit affb86d76a
7 changed files with 58 additions and 11 deletions

13
notes
View File

@ -32,15 +32,22 @@ parameters {
TODO {
immediate frontburner {
- standardized "draw panel" function in nodeobject
- ^ use in both default draw and quicklevel
- add per-sample gain to BeatPad
- node scene constructor for layoutgadget
- ^ use in beatpad
distortion effect
single-selection sampler
add ,XX support to global tempo
}
buffer helper akin to what quicklevel does {
keeps a buffer length, running averages, etc.
can lerp across tick for speed
useful for level reading, waveform output, compression/sidechaining etc.
}
solo gadget {
interprets incoming commands as monophonic with portamento
probably not super useful for tracked things but good for playing live

View File

@ -19,6 +19,7 @@ using namespace Xybrid::Audio;
#include "ui/waveformpreviewwidget.h"
#include "ui/patchboard/nodeobject.h"
#include "ui/gadgets/layoutgadget.h"
#include "ui/gadgets/knobgadget.h"
#include "ui/gadgets/selectorgadget.h"
#include "ui/gadgets/sampleselectorgadget.h"
@ -111,7 +112,7 @@ void BeatPad::init() {
auto out = NodeLib::resamp(smp.get(), sp, rate);
(*p)[i] += out.gainBalance(0, note.pan) * note.ampMult();
(*p)[i] += out.gainBalance(data.config->gain, note.pan) * note.ampMult();
data.sampleTime += 1;
}
};
@ -129,6 +130,7 @@ void BeatPad::saveData(QCborMap& m) const {
e[qs("sample")] = QCborValue(smp->uuid);
e[qs("start")] = static_cast<qint64>(c.second->start);
e[qs("end")] = static_cast<qint64>(c.second->end);
e[qs("gain")] = c.second->gain;
cm[c.first] = e;
smp->markForExport();
}
@ -145,6 +147,7 @@ void BeatPad::loadData(const QCborMap& m) {
c->smp = f.value();
c->start = cm.value("start").toInteger(-1);
c->end = cm.value("end").toInteger(-1);
c->gain = cm.value("gain").toDouble(0.0);
cfg[static_cast<int16_t>(ce.first.toInteger())] = c;
}
}
@ -172,10 +175,11 @@ void BeatPad::initUI(NodeUIScene* scene) {
};
auto state = scene->makeStateObject<UIState>();
// init layout
auto ol = (new LayoutGadget(scene, true))->setPanel(true);
// set up gadgets
auto noteSelector = new SelectorGadget();
scene->addItem(noteSelector);
noteSelector->setPos(0, 0);
auto noteSelector = new SelectorGadget(ol);
noteSelector->setWidth(320);
noteSelector->fGetList = [=] {
@ -206,11 +210,12 @@ void BeatPad::initUI(NodeUIScene* scene) {
}
};
auto sampleSelector = new SampleSelectorGadget(project);
scene->addItem(sampleSelector);
sampleSelector->setPos(0, 28);
auto sampleSelector = new SampleSelectorGadget(project, ol);
sampleSelector->setSize(320, 96);
auto r1 = (new LayoutGadget(ol))->setMetrics(0, -1, 0.0);
auto gain = (new KnobGadget(r1))->setRange(-60, 12, .1)->setLabel("Gain")->setTextFunc([](double d) { return QString("%1dB").arg(d); });
// create functions now that all UI elements exist to be referenced
state->selectNote = [=](int16_t n) {
if (auto f = cfg.find(n); f != cfg.end()) state->cfg = f->second;
@ -218,6 +223,7 @@ void BeatPad::initUI(NodeUIScene* scene) {
state->note = n;
auto smp = state->cfg->smp.lock();
sampleSelector->setSample(smp);
gain->bind(state->cfg->gain);
noteSelector->setEntry({n, qs("%1 %2").arg(Util::noteName(n)).arg(smp ? smp->name.section('/', -1, -1) : "")}, false);
};
@ -230,6 +236,8 @@ void BeatPad::initUI(NodeUIScene* scene) {
noteSelector->setEntry({n, qs("%1 %2").arg(Util::noteName(n)).arg(smp ? smp->name : "")}, false);
};
//ol->updateGeometry();
// hook up relevantsignals
QObject::connect(scene, &NodeUIScene::notePreview, [=](int16_t note) { state->selectNote(note); });
QObject::connect(noteSelector, &SelectorGadget::onSelect, [=](auto e) { state->selectNote(e.first); });

View File

@ -11,6 +11,8 @@ namespace Xybrid::Instruments {
std::weak_ptr<Data::Sample> smp = std::weak_ptr<Data::Sample>();
ptrdiff_t start = -1;
ptrdiff_t end = -1;
double gain = 0.0;
};
struct NoteData {

View File

@ -2,6 +2,7 @@
using Xybrid::UI::LayoutGadget;
#include "ui/patchboard/nodeobject.h"
#include "ui/patchboard/nodeuiscene.h"
namespace Xybrid::UI {
class LayoutSpacerGadget : public Gadget {
@ -51,6 +52,13 @@ LayoutGadget::LayoutGadget(NodeObject* parent, bool vertical) : LayoutGadget(par
});
}
LayoutGadget::LayoutGadget(NodeUIScene* parent, bool vertical) : LayoutGadget(static_cast<QGraphicsItem*>(nullptr), vertical) {
QObject::connect(parent, &NodeUIScene::finalized, this, [this] {
updateGeometry();
});
parent->addItem(this);
}
LayoutGadget* LayoutGadget::addSpacer() { new LayoutSpacerGadget(this); return this; }
void LayoutGadget::updateGeometry() {
@ -74,3 +82,7 @@ void LayoutGadget::updateGeometry() {
}
QRectF LayoutGadget::boundingRect() const { return { QPointF(), size }; }
void LayoutGadget::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt, QWidget*) {
if (drawPanel) NodeObject::drawPanel(painter, opt, boundingRect().adjusted(-panelMargin, -panelMargin, panelMargin, panelMargin));
}

View File

@ -4,6 +4,7 @@
namespace Xybrid::UI {
class NodeObject;
class NodeUIScene;
class LayoutGadget : public Gadget {
QSizeF size;
@ -19,9 +20,12 @@ namespace Xybrid::UI {
qreal bias = 0.5;
bool vertical = false;
bool drawPanel = false;
qreal panelMargin = 6;
LayoutGadget(QGraphicsItem* parent = nullptr, bool vertical = false);
LayoutGadget(NodeObject* parent, bool vertical = false);
LayoutGadget(NodeUIScene* parent, bool vertical = false);
~LayoutGadget() override = default;
inline LayoutGadget* setMetrics(qreal margin = -1, qreal spacing = -1, qreal bias = -1) {
@ -30,11 +34,17 @@ namespace Xybrid::UI {
if (bias >= 0) this->bias = std::clamp(bias, 0.0, 1.0);
return this;
}
inline LayoutGadget* setPanel(bool draw, qreal margin = 6) {
drawPanel = draw;
panelMargin = margin;
return this;
}
LayoutGadget* addSpacer();
void updateGeometry() override;
QRectF boundingRect() const override;
void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override;
};
}

View File

@ -29,7 +29,14 @@ NodeUIScene::NodeUIScene(QGraphicsView* v, const std::shared_ptr<Xybrid::Data::N
connect(view->horizontalScrollBar(), &QScrollBar::rangeChanged, this, &NodeUIScene::queueResize);
connect(view->verticalScrollBar(), &QScrollBar::rangeChanged, this, &NodeUIScene::queueResize);
autoResize();
// force full redraw to eliminate graphical glitches
connect(this, &QGraphicsScene::changed, this, [this] { update(); });
// queue up final setup in event loop; this should happen after code surrounding creation but before display
QMetaObject::invokeMethod(this, [this] {
emit finalized(); // emit before display
autoResize();
}, Qt::QueuedConnection);
}
NodeUIScene::~NodeUIScene() {

View File

@ -45,6 +45,7 @@ namespace Xybrid::UI {
template<typename T> inline T* makeStateObject() { auto o = std::make_shared<T>(); stateObject = o; return o.get(); }
signals:
void finalized();
void notePreview(int16_t);
};