From cb896a4fa1acd9167d3e7ee9f6336a63309eebde Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 24 May 2018 20:44:33 +0200 Subject: Add save/load of selections/regions in instruments. --- src/canvastoolthreshold.cc | 12 +++-- src/canvastoolthreshold.h | 6 ++- src/instrumentwidget.cc | 56 ++++++++++++++++++--- src/instrumentwidget.h | 2 + src/project.cc | 121 +++++++++++++++++++++++++++++++++++++++++++++ src/project.h | 37 ++++++++++++++ src/projectserialiser.cc | 56 ++++++++++++++++++++- src/samplesorter.cc | 3 +- src/samplesorter.h | 7 ++- src/selection.cc | 12 +++++ src/selection.h | 4 ++ src/selectioneditor.cc | 9 +++- src/selectioneditor.h | 6 ++- 13 files changed, 311 insertions(+), 20 deletions(-) diff --git a/src/canvastoolthreshold.cc b/src/canvastoolthreshold.cc index bafee70..a905766 100644 --- a/src/canvastoolthreshold.cc +++ b/src/canvastoolthreshold.cc @@ -28,15 +28,19 @@ #include +#include "project.h" + #define mapX(x) canvas->mapX(x) #define mapY(x) canvas->mapY(x) #define unmapX(x) canvas->unmapX(x) #define unmapY(x) canvas->unmapY(x) -CanvasToolThreshold::CanvasToolThreshold(Canvas* c) +CanvasToolThreshold::CanvasToolThreshold(Canvas* c, Instrument& instrument) + : instrument(instrument) { canvas = c; - threshold = 0.5; + threshold = instrument.getThreshold(); + threshold_is_moving = false; colThreshold = QColor(255, 127, 127); @@ -72,7 +76,7 @@ bool CanvasToolThreshold::mouseMoveEvent(QMouseEvent* event) canvas->update(); emit thresholdChanging(threshold); - + instrument.setThreshold(threshold); return true; } @@ -117,7 +121,7 @@ bool CanvasToolThreshold::mouseReleaseEvent(QMouseEvent* event) canvas->update(); emit thresholdChanged(threshold); - + instrument.setThreshold(threshold); return true; } } diff --git a/src/canvastoolthreshold.h b/src/canvastoolthreshold.h index ddb1a85..936bf68 100644 --- a/src/canvastoolthreshold.h +++ b/src/canvastoolthreshold.h @@ -32,12 +32,14 @@ #include "canvas.h" +class Instrument; + class CanvasToolThreshold : public CanvasTool { Q_OBJECT public: - CanvasToolThreshold(Canvas* canvas); + CanvasToolThreshold(Canvas* canvas, Instrument& instrument); QString name() { return tr("Threshold"); } bool mouseMoveEvent(QMouseEvent* event); @@ -57,4 +59,6 @@ private: QColor colThreshold; QColor colThresholdMoving; + + Instrument& instrument; }; diff --git a/src/instrumentwidget.cc b/src/instrumentwidget.cc index 641f690..f8b4046 100644 --- a/src/instrumentwidget.cc +++ b/src/instrumentwidget.cc @@ -92,7 +92,7 @@ InstrumentWidget::InstrumentWidget(Settings& settings, Instrument& instrument) QToolBar* toolbar = addToolBar(tr("Tools")); listen = new CanvasToolListen(canvaswidget->canvas, player); addTool(toolbar, canvaswidget->canvas, listen); - threshold = new CanvasToolThreshold(canvaswidget->canvas); + threshold = new CanvasToolThreshold(canvaswidget->canvas, instrument); canvaswidget->canvas->tools.push_back(threshold); tool_selections = new CanvasToolSelections(canvaswidget->canvas, selections, selections_preview); @@ -106,7 +106,7 @@ InstrumentWidget::InstrumentWidget(Settings& settings, Instrument& instrument) canvaswidget->canvas, SLOT(update())); addTool(toolbar, canvaswidget->canvas, tool_selections); - sorter = new SampleSorter(selections, selections_preview); + sorter = new SampleSorter(selections, selections_preview, instrument); connect(&selections, SIGNAL(added(sel_id_t)), sorter, SLOT(addSelection(sel_id_t))); connect(&selections_preview, SIGNAL(added(sel_id_t)), @@ -142,6 +142,7 @@ InstrumentWidget::InstrumentWidget(Settings& settings, Instrument& instrument) dockWidget->widget()->setLayout(new QVBoxLayout()); tabs = new QTabWidget(this); + tabs->setMinimumWidth(350); tabs->addTab(createFilesTab(), tr("Files")); generateTabId = tabs->addTab(createGenerateTab(), tr("Generate")); tabs->addTab(createEditTab(), tr("Edit")); @@ -166,6 +167,9 @@ InstrumentWidget::InstrumentWidget(Settings& settings, Instrument& instrument) canvaswidget->yoffset->setValue(MAXVAL/2); canvaswidget->xscale->setValue(0); canvaswidget->xoffset->setValue(0); + + // Update selections according to threshold + tool_selections->thresholdChanged(instrument.getThreshold()); } InstrumentWidget::~InstrumentWidget() @@ -203,12 +207,18 @@ QWidget* InstrumentWidget::createFilesTab() extractor, SLOT(changeName(QString, QString))); l->addWidget(filelist); + if(!instrument.getMasterFile().isEmpty()) + { + loadFile(instrument.getMasterFile()); + } + return w; } QWidget* InstrumentWidget::createEditTab() { - SelectionEditor* se = new SelectionEditor(selections); + selections = instrument.getSelections(); + SelectionEditor* se = new SelectionEditor(selections, instrument); connect(&selections, SIGNAL(added(sel_id_t)), se, SLOT(added(sel_id_t))); connect(&selections, SIGNAL(updated(sel_id_t)), se, SLOT(updated(sel_id_t))); @@ -216,9 +226,19 @@ QWidget* InstrumentWidget::createEditTab() connect(&selections, SIGNAL(activeChanged(sel_id_t)), se, SLOT(activeChanged(sel_id_t))); + connect(&selections, SIGNAL(added(sel_id_t)), this, SLOT(selectionChanged())); + connect(&selections, SIGNAL(updated(sel_id_t)), this, SLOT(selectionChanged())); + connect(&selections, SIGNAL(removed(sel_id_t)), this, SLOT(selectionChanged())); + connect(&selections, SIGNAL(activeChanged(sel_id_t)), this, SLOT(selectionChanged())); + return se; } +void InstrumentWidget::selectionChanged() +{ + instrument.setSelections(selections); +} + static QSlider* createAttribute(QWidget* parent, QString name, int range_from, int range_to) { @@ -281,41 +301,61 @@ QWidget* InstrumentWidget::createGenerateTab() sorter, SLOT(setAttackLength(int))); connect(slider_attacklength, SIGNAL(valueChanged(int)), tool_selections, SLOT(autoCreateSelectionsPreview())); - slider_attacklength->setValue(300); + slider_attacklength->setValue(instrument.getAttackLength()); + connect(slider_attacklength, SIGNAL(valueChanged(int)), + this, SLOT(generateSlidersChanged())); slider_spread = createAttribute(w, tr("Power spread:"), 1, 2000); connect(slider_spread, SIGNAL(valueChanged(int)), sorter, SLOT(setSpreadFactor(int))); connect(slider_spread, SIGNAL(valueChanged(int)), tool_selections, SLOT(autoCreateSelectionsPreview())); - slider_spread->setValue(1000); + slider_spread->setValue(instrument.getPowerSpread()); + connect(slider_spread, SIGNAL(valueChanged(int)), + this, SLOT(generateSlidersChanged())); slider_hold = createAttribute(w, tr("Minimum size (samples):"), 0, 200000); connect(slider_hold, SIGNAL(valueChanged(int)), tool_selections, SLOT(holdChanged(int))); connect(slider_hold, SIGNAL(valueChanged(int)), tool_selections, SLOT(autoCreateSelectionsPreview())); - slider_hold->setValue(100); + slider_hold->setValue(instrument.getMinimumSize()); + connect(slider_hold, SIGNAL(valueChanged(int)), + this, SLOT(generateSlidersChanged())); slider_falloff = createAttribute(w, tr("Falloff:"), 10, 5000); connect(slider_falloff, SIGNAL(valueChanged(int)), tool_selections, SLOT(noiseFloorChanged(int))); connect(slider_falloff, SIGNAL(valueChanged(int)), tool_selections, SLOT(autoCreateSelectionsPreview())); - slider_falloff->setValue(300); + slider_falloff->setValue(instrument.getFalloff()); + connect(slider_falloff, SIGNAL(valueChanged(int)), + this, SLOT(generateSlidersChanged())); slider_fadelength = createAttribute(w, tr("Fadelength:"), 0, 2000); connect(slider_fadelength, SIGNAL(valueChanged(int)), tool_selections, SLOT(fadeoutChanged(int))); connect(slider_fadelength, SIGNAL(valueChanged(int)), tool_selections, SLOT(autoCreateSelectionsPreview())); - slider_fadelength->setValue(666); + slider_fadelength->setValue(instrument.getFadeLength()); + connect(slider_fadelength, SIGNAL(valueChanged(int)), + this, SLOT(generateSlidersChanged())); l->addStretch(); return w; } +void InstrumentWidget::generateSlidersChanged() +{ + Project::RAIIBulkUpdate bulkUpdate(instrument.getProject()); + instrument.setAttackLength(slider_attacklength->value()); + instrument.setPowerSpread(slider_spread->value()); + instrument.setMinimumSize(slider_hold->value()); + instrument.setFalloff(slider_falloff->value()); + instrument.setFadeLength(slider_fadelength->value()); +} + QWidget* InstrumentWidget::createExportTab() { QWidget* w = new QWidget(); diff --git a/src/instrumentwidget.h b/src/instrumentwidget.h index 7a2b40d..2a5b3c5 100644 --- a/src/instrumentwidget.h +++ b/src/instrumentwidget.h @@ -73,6 +73,8 @@ public slots: void playSamples(); void browse(); void tabChanged(int tabid); + void generateSlidersChanged(); + void selectionChanged(); private: QWidget* createFilesTab(); diff --git a/src/project.cc b/src/project.cc index 8a1338c..5c45973 100644 --- a/src/project.cc +++ b/src/project.cc @@ -95,6 +95,127 @@ void Instrument::setFileList(const AudioFileList& file_list) } } +std::size_t Instrument::getAttackLength() const +{ + return attack_length; +} + +void Instrument::setAttackLength(std::size_t attack_length) +{ + if(this->attack_length == attack_length) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->attack_length = attack_length; + } +} + +std::size_t Instrument::getPowerSpread() const +{ + return power_spread; +} + +void Instrument::setPowerSpread(std::size_t power_spread) +{ + if(this->power_spread == power_spread) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->power_spread = power_spread; + } +} + +std::size_t Instrument::getMinimumSize() const +{ + return minimum_size; +} + +void Instrument::setMinimumSize(std::size_t minimum_size) +{ + if(this->minimum_size == minimum_size) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->minimum_size = minimum_size; + } +} + +std::size_t Instrument::getFalloff() const +{ + return falloff; +} + +void Instrument::setFalloff(std::size_t falloff) +{ + if(this->falloff == falloff) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->falloff = falloff; + } +} + +std::size_t Instrument::getFadeLength() const +{ + return fade_length; +} + +void Instrument::setFadeLength(std::size_t fade_length) +{ + if(this->fade_length == fade_length) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->fade_length = fade_length; + } +} + +float Instrument::getThreshold() const +{ + return threshold; +} + +void Instrument::setThreshold(float threshold) +{ + if(this->threshold == threshold) + { + return; + } + + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->threshold = threshold; + } +} + +Selections Instrument::getSelections() const +{ + return selections; +} + +void Instrument::setSelections(const Selections& selections) +{ + { + Project::RAIIBulkUpdate bulkUpdate(project); + this->selections = selections; + } +} + Project& Instrument::getProject() { return project; diff --git a/src/project.h b/src/project.h index 2b172ea..725e936 100644 --- a/src/project.h +++ b/src/project.h @@ -32,6 +32,7 @@ #include #include "audioextractor.h" +#include "selection.h" class Project; @@ -51,6 +52,27 @@ public: AudioFileList getFileList() const; void setFileList(const AudioFileList& file_list); + std::size_t getAttackLength() const; + void setAttackLength(std::size_t attack_length); + + std::size_t getPowerSpread() const; + void setPowerSpread(std::size_t power_spread); + + std::size_t getMinimumSize() const; + void setMinimumSize(std::size_t minimum_size); + + std::size_t getFalloff() const; + void setFalloff(std::size_t falloff); + + std::size_t getFadeLength() const; + void setFadeLength(std::size_t fade_length); + + float getThreshold() const; + void setThreshold(float threshold); + + Selections getSelections() const; + void setSelections(const Selections& selectios); + Project& getProject(); private: @@ -58,9 +80,24 @@ private: int id; QString instrument_name; + + // Files tab QString master_file; AudioFileList file_list; + // Generate tab + std::size_t attack_length{300}; + std::size_t power_spread{1000}; + std::size_t minimum_size{100}; + std::size_t falloff{300}; + std::size_t fade_length{666}; + + // Canvas + float threshold{0.5f}; + + // Edit tab + Selections selections; + Project& project; }; diff --git a/src/projectserialiser.cc b/src/projectserialiser.cc index 44f9ff7..f70e6dd 100644 --- a/src/projectserialiser.cc +++ b/src/projectserialiser.cc @@ -128,6 +128,15 @@ QString ProjectSerialiser::serialise(const Project& project) for(const auto& i : project.instruments) { auto instrument = doc.createElement("instrument"); + + instrument.setAttribute("attack_length", (int)i.getAttackLength()); + instrument.setAttribute("power_spread", (int)i.getPowerSpread()); + instrument.setAttribute("minimum_size", (int)i.getMinimumSize()); + instrument.setAttribute("falloff", (int)i.getFalloff()); + instrument.setAttribute("fade_length", (int)i.getFadeLength()); + + instrument.setAttribute("threshold", i.getThreshold()); + instruments.appendChild(instrument); auto instrument_name = doc.createElement("instrument_name"); @@ -145,6 +154,24 @@ QString ProjectSerialiser::serialise(const Project& project) file.setAttribute("master", i.master_file == f.first); file_list.appendChild(file); } + + auto regions = doc.createElement("regions"); + regions.setAttribute("nextid", i.selections.nextid); + regions.setAttribute("act", i.selections.act); + instrument.appendChild(regions); + + for(auto r = i.selections.sels.begin(); r != i.selections.sels.end(); ++r) + { + auto region = doc.createElement("region"); + region.setAttribute("id", (int)r.key()); + region.setAttribute("from", (int)r.value().from); + region.setAttribute("to", (int)r.value().to); + region.setAttribute("fadein", (int)r.value().fadein); + region.setAttribute("fadeout", (int)r.value().fadeout); + region.setAttribute("energy", r.value().energy); + region.setAttribute("name", r.value().name); + regions.appendChild(region); + } } return doc.toString(); @@ -192,8 +219,33 @@ bool ProjectSerialiser::deserialise(const QString& data, Project& project) } file_list.push_back(qMakePair(file.text(), file["name"])); } - project.instruments.back().file_list = file_list; - project.instruments.back().master_file = master_file; + + instr.file_list = file_list; + instr.master_file = master_file; + + instr.attack_length = instrument["attack_length"].toInt(); + instr.power_spread = instrument["power_spread"].toInt();; + instr.minimum_size = instrument["minimum_size"].toInt(); + instr.falloff = instrument["falloff"].toInt(); + instr.fade_length = instrument["fade_length"].toInt(); + + instr.threshold = instrument["threshold"].toFloat(); + + auto selections = instrument("regions"); + instr.selections.nextid = selections["nextid"].toInt(); + instr.selections.act = selections["act"].toInt(); + + for(auto& selection : selections.children()) + { + Selection s; + s.from = selection["from"].toInt(); + s.to = selection["to"].toInt(); + s.fadein = selection["fadein"].toInt(); + s.fadeout = selection["fadeout"].toInt(); + s.energy = selection["energy"].toFloat(); + s.name = selection["name"]; + instr.selections.sels[selection["id"].toInt()] = s; + } } return true; diff --git a/src/samplesorter.cc b/src/samplesorter.cc index 6158bfa..91bc6b4 100644 --- a/src/samplesorter.cc +++ b/src/samplesorter.cc @@ -36,9 +36,10 @@ #define MAXFLOAT (3.40282347e+38F) #endif -SampleSorter::SampleSorter(Selections& s, Selections& p) +SampleSorter::SampleSorter(Selections& s, Selections& p, Instrument& instrument) : selections(s) , selections_preview(p) + , instrument(instrument) { setMouseTracking(true); diff --git a/src/samplesorter.h b/src/samplesorter.h index fa53a3f..496274d 100644 --- a/src/samplesorter.h +++ b/src/samplesorter.h @@ -30,12 +30,15 @@ #include #include "selection.h" +class Instrument; + class SampleSorter : public QWidget { Q_OBJECT public: - SampleSorter(Selections& selections, Selections& selections_preview); + SampleSorter(Selections& selections, Selections& selections_preview, + Instrument& instrument); public slots: void setWavData(const float* data, size_t size); @@ -78,4 +81,6 @@ private: sel_id_t sel_moving; double spread; + + Instrument& instrument; }; diff --git a/src/selection.cc b/src/selection.cc index 0b93fa2..e18e485 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -33,6 +33,18 @@ Selections::Selections() act = SEL_NONE; } +Selections::Selections(const Selections& other) +{ + *this = other; +} + +void Selections::operator=(const Selections& other) +{ + sels = other.sels; + nextid = other.nextid; + act = other.act; +} + sel_id_t Selections::add(Selection selection) { sel_id_t id = nextid++; diff --git a/src/selection.h b/src/selection.h index 7d4d677..338b381 100644 --- a/src/selection.h +++ b/src/selection.h @@ -60,6 +60,9 @@ class Selections Q_OBJECT public: Selections(); + Selections(const Selections&); + + void operator=(const Selections& other); //! Add a new selection object. The new id is returned. //! Adding a new selections will emit an added signal with the new id. @@ -105,6 +108,7 @@ signals: void activeChanged(sel_id_t id); private: + friend class ProjectSerialiser; QMap sels; sel_id_t nextid; sel_id_t act; diff --git a/src/selectioneditor.cc b/src/selectioneditor.cc index 98c6161..417059d 100644 --- a/src/selectioneditor.cc +++ b/src/selectioneditor.cc @@ -26,11 +26,13 @@ */ #include "selectioneditor.h" +#include "project.h" + #include #include #include -QLineEdit *createWidget(QString name, QWidget* parent) +static QLineEdit *createWidget(QString name, QWidget* parent) { QHBoxLayout* l = new QHBoxLayout(); @@ -47,8 +49,9 @@ QLineEdit *createWidget(QString name, QWidget* parent) return edt; } -SelectionEditor::SelectionEditor(Selections &s) +SelectionEditor::SelectionEditor(Selections &s, Instrument& instrument) : selections(s) + , instrument(instrument) { cur = SEL_NONE; @@ -76,6 +79,8 @@ void SelectionEditor::updateSelection() sel.name = name->text(); selections.update(cur, sel); + + instrument.setSelections(selections); } void SelectionEditor::update() diff --git a/src/selectioneditor.h b/src/selectioneditor.h index feb9200..cdbf2de 100644 --- a/src/selectioneditor.h +++ b/src/selectioneditor.h @@ -31,12 +31,14 @@ #include #include "selection.h" +class Instrument; + class SelectionEditor : public QWidget { Q_OBJECT public: - SelectionEditor(Selections& selections); + SelectionEditor(Selections& selections, Instrument& instrument); public slots: void added(sel_id_t id); @@ -59,4 +61,6 @@ private: QLineEdit* fadeout; QLineEdit* energy; QLineEdit* name; + + Instrument& instrument; }; -- cgit v1.2.3