import/export samples with nodes (both node files and copy/paste)
parent
f7f5e15070
commit
47591ea3d1
|
@ -1,6 +1,7 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
using namespace Xybrid::Data;
|
using namespace Xybrid::Data;
|
||||||
|
|
||||||
|
#include "data/project.h"
|
||||||
#include "data/graph.h"
|
#include "data/graph.h"
|
||||||
#include "data/porttypes.h"
|
#include "data/porttypes.h"
|
||||||
|
|
||||||
|
@ -15,6 +16,8 @@ using namespace Xybrid::Audio;
|
||||||
#include "util/strings.h"
|
#include "util/strings.h"
|
||||||
#include "util/ycombinator.h"
|
#include "util/ycombinator.h"
|
||||||
|
|
||||||
|
#include "uisocket.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -108,6 +111,8 @@ std::shared_ptr<Node> Node::fromCbor(const QCborValue& m, std::shared_ptr<Graph>
|
||||||
QCborMap Node::multiToCbor(std::vector<std::shared_ptr<Node>>& v) {
|
QCborMap Node::multiToCbor(std::vector<std::shared_ptr<Node>>& v) {
|
||||||
QCborMap m;
|
QCborMap m;
|
||||||
|
|
||||||
|
Sample::startExport();
|
||||||
|
|
||||||
std::unordered_map<Node*, int> indices;
|
std::unordered_map<Node*, int> indices;
|
||||||
{ /* nodes */ } {
|
{ /* nodes */ } {
|
||||||
QCborArray nm;
|
QCborArray nm;
|
||||||
|
@ -120,6 +125,13 @@ QCborMap Node::multiToCbor(std::vector<std::shared_ptr<Node>>& v) {
|
||||||
m[qs("nodes")] = nm;
|
m[qs("nodes")] = nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exported samples
|
||||||
|
if (auto v = Sample::finishExport(); !v.empty()) {
|
||||||
|
QCborMap smp;
|
||||||
|
for (auto s : v) smp[QCborValue(s->uuid)] = s->toCbor();
|
||||||
|
m[qs("samples")] = smp;
|
||||||
|
}
|
||||||
|
|
||||||
{ /* connections */ } {
|
{ /* connections */ } {
|
||||||
QCborArray cm;
|
QCborArray cm;
|
||||||
|
|
||||||
|
@ -176,6 +188,19 @@ std::vector<std::shared_ptr<Node>> Node::multiFromCbor(const QCborMap& m, std::s
|
||||||
center.setY(static_cast<int>(c.at(1).toInteger()));
|
center.setY(static_cast<int>(c.at(1).toInteger()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ /* exported samples */ } {
|
||||||
|
QCborMap smp = m.value("samples").toMap();
|
||||||
|
auto project = parent->project;
|
||||||
|
for (auto it = smp.constBegin(), end = smp.constEnd(); it != end; ++it) {
|
||||||
|
auto uuid = it.key().toUuid();
|
||||||
|
if (project->samples.find(uuid) != project->samples.end()) continue; // we already have this; next
|
||||||
|
auto s = Sample::fromCbor(it.value(), uuid);
|
||||||
|
s->project = project;
|
||||||
|
project->samples.insert(s->uuid, s);
|
||||||
|
}
|
||||||
|
emit project->socket->updatePatternLists();
|
||||||
|
}
|
||||||
|
|
||||||
{ /* nodes */ } {
|
{ /* nodes */ } {
|
||||||
QCborArray n = m.value("nodes").toArray();
|
QCborArray n = m.value("nodes").toArray();
|
||||||
v.reserve(static_cast<size_t>(n.size()));
|
v.reserve(static_cast<size_t>(n.size()));
|
||||||
|
|
|
@ -154,3 +154,30 @@ std::shared_ptr<Sample> Sample::fromFile(QString fileName) {
|
||||||
|
|
||||||
return smp;
|
return smp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool exporting = false;
|
||||||
|
std::unordered_map<Sample*, bool> exportMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sample::startExport() {
|
||||||
|
exporting = true;
|
||||||
|
exportMap.reserve(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Sample>> Sample::finishExport() {
|
||||||
|
std::vector<std::shared_ptr<Sample>> v;
|
||||||
|
if (exporting) {
|
||||||
|
exporting = false;
|
||||||
|
v.reserve(exportMap.size());
|
||||||
|
for (auto it : exportMap) v.push_back(it.first->shared_from_this());
|
||||||
|
exportMap.clear();
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sample::markForExport() {
|
||||||
|
if (exporting) {
|
||||||
|
exportMap[this] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,5 +49,9 @@ namespace Xybrid::Data {
|
||||||
|
|
||||||
static std::shared_ptr<Sample> fromFile(QString);
|
static std::shared_ptr<Sample> fromFile(QString);
|
||||||
|
|
||||||
|
static void startExport();
|
||||||
|
static std::vector<std::shared_ptr<Sample>> finishExport();
|
||||||
|
void markForExport();
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,10 +267,19 @@ bool FileOps::saveNode(std::shared_ptr<Node> node, QString fileName) {
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QFile::WriteOnly)) return false;
|
if (!file.open(QFile::WriteOnly)) return false;
|
||||||
|
|
||||||
|
Sample::startExport();
|
||||||
|
|
||||||
// we handle header and let the node handle the rest of its conversion
|
// we handle header and let the node handle the rest of its conversion
|
||||||
QCborArray root;
|
QCborArray root;
|
||||||
root << "xybrid:node" << XYBRID_VERSION << node->toCbor();
|
root << "xybrid:node" << XYBRID_VERSION << node->toCbor();
|
||||||
|
|
||||||
|
// and write in any exported samples
|
||||||
|
if (auto v = Sample::finishExport(); !v.empty()) {
|
||||||
|
QCborMap smp;
|
||||||
|
for (auto s : v) smp[QCborValue(s->uuid)] = s->toCbor();
|
||||||
|
root << smp;
|
||||||
|
}
|
||||||
|
|
||||||
// write out
|
// write out
|
||||||
QCborStreamWriter w(&file);
|
QCborStreamWriter w(&file);
|
||||||
root.toCborValue().toCbor(w);
|
root.toCborValue().toCbor(w);
|
||||||
|
@ -296,6 +305,19 @@ std::shared_ptr<Node> FileOps::loadNode(QString fileName, std::shared_ptr<Graph>
|
||||||
if (auto v = root.at(1); !v.isInteger() || v.toInteger() > XYBRID_VERSION) return nullptr; // invalid version or too new
|
if (auto v = root.at(1); !v.isInteger() || v.toInteger() > XYBRID_VERSION) return nullptr; // invalid version or too new
|
||||||
if (!root.at(2).isMap()) return nullptr; // so close, but... nope
|
if (!root.at(2).isMap()) return nullptr; // so close, but... nope
|
||||||
|
|
||||||
|
if (root.at(3).isMap()) { // node file has samples, load in any we don't already have
|
||||||
|
auto smp = root.at(3).toMap();
|
||||||
|
auto project = parent->project;
|
||||||
|
for (auto it = smp.constBegin(), end = smp.constEnd(); it != end; ++it) {
|
||||||
|
auto uuid = it.key().toUuid();
|
||||||
|
if (project->samples.find(uuid) != project->samples.end()) continue; // we already have this; next
|
||||||
|
auto s = Sample::fromCbor(it.value(), uuid);
|
||||||
|
s->project = project;
|
||||||
|
project->samples.insert(s->uuid, s);
|
||||||
|
}
|
||||||
|
emit project->socket->updatePatternLists();
|
||||||
|
}
|
||||||
|
|
||||||
return Node::fromCbor(root.at(2), parent); // let Node handle the rest
|
return Node::fromCbor(root.at(2), parent); // let Node handle the rest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ namespace {
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::MainWindow) {
|
ui(new Ui::MainWindow) {
|
||||||
|
socket = new UISocket(); // create this first
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
// remove tab containing system widgets
|
// remove tab containing system widgets
|
||||||
|
@ -337,7 +338,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up signaling from project to UI
|
// Set up signaling from project to UI
|
||||||
socket = new UISocket();
|
|
||||||
socket->setParent(this);
|
socket->setParent(this);
|
||||||
socket->window = this;
|
socket->window = this;
|
||||||
socket->undoStack = undoStack;
|
socket->undoStack = undoStack;
|
||||||
|
|
|
@ -53,6 +53,8 @@ namespace Xybrid {
|
||||||
|
|
||||||
void playbackPosition(int seq, int row);
|
void playbackPosition(int seq, int row);
|
||||||
|
|
||||||
|
inline UISocket* uiSocket() { return socket; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent*) override;
|
void closeEvent(QCloseEvent*) override;
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
|
@ -130,7 +130,6 @@ void BeatPad::release() { core.release(); }
|
||||||
void BeatPad::process() { core.process(this); }
|
void BeatPad::process() { core.process(this); }
|
||||||
|
|
||||||
void BeatPad::saveData(QCborMap& m) const {
|
void BeatPad::saveData(QCborMap& m) const {
|
||||||
// TODO: mark samples for inclusion in export
|
|
||||||
QCborMap cm;
|
QCborMap cm;
|
||||||
for (auto c : cfg) {
|
for (auto c : cfg) {
|
||||||
if (auto smp = c.second->smp.lock(); smp) {
|
if (auto smp = c.second->smp.lock(); smp) {
|
||||||
|
@ -139,6 +138,7 @@ void BeatPad::saveData(QCborMap& m) const {
|
||||||
e[qs("start")] = static_cast<qint64>(c.second->start);
|
e[qs("start")] = static_cast<qint64>(c.second->start);
|
||||||
e[qs("end")] = static_cast<qint64>(c.second->end);
|
e[qs("end")] = static_cast<qint64>(c.second->end);
|
||||||
cm[c.first] = e;
|
cm[c.first] = e;
|
||||||
|
smp->markForExport();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m[qs("notecfg")] = cm;
|
m[qs("notecfg")] = cm;
|
||||||
|
|
|
@ -6,6 +6,8 @@ using Xybrid::Data::Project;
|
||||||
using Xybrid::Data::Pattern;
|
using Xybrid::Data::Pattern;
|
||||||
using Xybrid::Data::Sample;
|
using Xybrid::Data::Sample;
|
||||||
|
|
||||||
|
#include "uisocket.h"
|
||||||
|
|
||||||
#include "editing/projectcommands.h"
|
#include "editing/projectcommands.h"
|
||||||
#include "editing/patterncommands.h"
|
#include "editing/patterncommands.h"
|
||||||
using namespace Xybrid::Editing;
|
using namespace Xybrid::Editing;
|
||||||
|
@ -48,6 +50,8 @@ SampleListModel::SampleListModel(QObject* parent, MainWindow* window) : QAbstrac
|
||||||
menu->popup(view->mapToGlobal(pt));
|
menu->popup(view->mapToGlobal(pt));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(window->uiSocket(), &UISocket::updatePatternLists, this, [this] { refresh(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Sample> SampleListModel::itemAt(const QModelIndex& ind) {
|
std::shared_ptr<Sample> SampleListModel::itemAt(const QModelIndex& ind) {
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace Xybrid {
|
||||||
void patternUpdated(Data::Pattern* pattern);
|
void patternUpdated(Data::Pattern* pattern);
|
||||||
void rowUpdated(Data::Pattern* pattern, int channel, int row);
|
void rowUpdated(Data::Pattern* pattern, int channel, int row);
|
||||||
|
|
||||||
|
void sampleListUpdated();
|
||||||
|
|
||||||
void openGraph(Data::Graph*);
|
void openGraph(Data::Graph*);
|
||||||
void openNodeUI(Data::Node*);
|
void openNodeUI(Data::Node*);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue