216 lines
6.6 KiB
C++
216 lines
6.6 KiB
C++
#include "PresetManager.h"
|
|
#include "WarpGraphModel.h"
|
|
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
|
|
bool PresetManager::savePreset(const QString &path, warppipe::Client *client,
|
|
const WarpGraphModel *model) {
|
|
if (!client || !model)
|
|
return false;
|
|
|
|
QJsonArray devicesArray;
|
|
auto nodesResult = client->ListNodes();
|
|
if (nodesResult.ok()) {
|
|
for (const auto &node : nodesResult.value) {
|
|
if (!node.is_virtual)
|
|
continue;
|
|
QJsonObject dev;
|
|
dev["name"] = QString::fromStdString(node.name);
|
|
dev["description"] = QString::fromStdString(node.description);
|
|
dev["media_class"] = QString::fromStdString(node.media_class);
|
|
|
|
auto portsResult = client->ListPorts(node.id);
|
|
int channels = 0;
|
|
if (portsResult.ok()) {
|
|
for (const auto &port : portsResult.value) {
|
|
if (port.is_input)
|
|
++channels;
|
|
}
|
|
if (channels == 0) {
|
|
for (const auto &port : portsResult.value) {
|
|
if (!port.is_input)
|
|
++channels;
|
|
}
|
|
}
|
|
}
|
|
dev["channels"] = channels > 0 ? channels : 2;
|
|
devicesArray.append(dev);
|
|
}
|
|
}
|
|
|
|
QJsonArray routingArray;
|
|
auto linksResult = client->ListLinks();
|
|
if (linksResult.ok() && nodesResult.ok()) {
|
|
std::unordered_map<uint32_t, std::pair<std::string, std::string>> portMap;
|
|
for (const auto &node : nodesResult.value) {
|
|
auto portsResult = client->ListPorts(node.id);
|
|
if (!portsResult.ok())
|
|
continue;
|
|
for (const auto &port : portsResult.value) {
|
|
portMap[port.id.value] = {node.name, port.name};
|
|
}
|
|
}
|
|
|
|
for (const auto &link : linksResult.value) {
|
|
auto outIt = portMap.find(link.output_port.value);
|
|
auto inIt = portMap.find(link.input_port.value);
|
|
if (outIt == portMap.end() || inIt == portMap.end())
|
|
continue;
|
|
QJsonObject route;
|
|
route["out_node"] = QString::fromStdString(outIt->second.first);
|
|
route["out_port"] = QString::fromStdString(outIt->second.second);
|
|
route["in_node"] = QString::fromStdString(inIt->second.first);
|
|
route["in_port"] = QString::fromStdString(inIt->second.second);
|
|
routingArray.append(route);
|
|
}
|
|
}
|
|
|
|
QJsonArray layoutArray;
|
|
for (auto qtId : model->allNodeIds()) {
|
|
const WarpNodeData *data = model->warpNodeData(qtId);
|
|
if (!data)
|
|
continue;
|
|
QPointF pos =
|
|
model->nodeData(qtId, QtNodes::NodeRole::Position).toPointF();
|
|
QJsonObject nodeLayout;
|
|
nodeLayout["name"] = QString::fromStdString(data->info.name);
|
|
nodeLayout["x"] = pos.x();
|
|
nodeLayout["y"] = pos.y();
|
|
layoutArray.append(nodeLayout);
|
|
}
|
|
|
|
QJsonArray volumesArray;
|
|
for (auto qtId : model->allNodeIds()) {
|
|
const WarpNodeData *data = model->warpNodeData(qtId);
|
|
if (!data)
|
|
continue;
|
|
auto vs = model->nodeVolumeState(qtId);
|
|
if (vs.volume != 1.0f || vs.mute) {
|
|
QJsonObject volObj;
|
|
volObj["name"] = QString::fromStdString(data->info.name);
|
|
volObj["volume"] = static_cast<double>(vs.volume);
|
|
volObj["mute"] = vs.mute;
|
|
volumesArray.append(volObj);
|
|
}
|
|
}
|
|
|
|
QJsonObject root;
|
|
root["version"] = 1;
|
|
root["virtual_devices"] = devicesArray;
|
|
root["routing"] = routingArray;
|
|
root["layout"] = layoutArray;
|
|
if (!volumesArray.isEmpty())
|
|
root["volumes"] = volumesArray;
|
|
|
|
QFileInfo fi(path);
|
|
QDir dir = fi.absoluteDir();
|
|
if (!dir.exists())
|
|
dir.mkpath(".");
|
|
|
|
QFile file(path);
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
|
return false;
|
|
file.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
|
|
return true;
|
|
}
|
|
|
|
bool PresetManager::loadPreset(const QString &path, warppipe::Client *client,
|
|
WarpGraphModel *model) {
|
|
if (!client || !model)
|
|
return false;
|
|
|
|
QFile file(path);
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
return false;
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
|
|
if (!doc.isObject())
|
|
return false;
|
|
|
|
QJsonObject root = doc.object();
|
|
int version = root["version"].toInt();
|
|
if (version < 1 || version > 1)
|
|
return false;
|
|
|
|
auto existingNodes = client->ListNodes();
|
|
std::unordered_set<std::string> existingNames;
|
|
if (existingNodes.ok()) {
|
|
for (const auto &node : existingNodes.value) {
|
|
existingNames.insert(node.name);
|
|
}
|
|
}
|
|
|
|
QJsonArray devicesArray = root["virtual_devices"].toArray();
|
|
for (const auto &val : devicesArray) {
|
|
QJsonObject dev = val.toObject();
|
|
std::string name = dev["name"].toString().toStdString();
|
|
std::string mediaClass = dev["media_class"].toString().toStdString();
|
|
int channels = dev["channels"].toInt(2);
|
|
|
|
if (existingNames.count(name))
|
|
continue;
|
|
|
|
warppipe::VirtualNodeOptions opts;
|
|
opts.format.channels = static_cast<uint32_t>(channels);
|
|
|
|
bool isSink = mediaClass == "Audio/Sink" || mediaClass == "Audio/Duplex";
|
|
if (isSink) {
|
|
client->CreateVirtualSink(name, opts);
|
|
} else {
|
|
client->CreateVirtualSource(name, opts);
|
|
}
|
|
}
|
|
|
|
QJsonArray layoutArray = root["layout"].toArray();
|
|
for (const auto &val : layoutArray) {
|
|
QJsonObject obj = val.toObject();
|
|
std::string name = obj["name"].toString().toStdString();
|
|
double x = obj["x"].toDouble();
|
|
double y = obj["y"].toDouble();
|
|
model->setPendingPosition(name, QPointF(x, y));
|
|
}
|
|
|
|
model->refreshFromClient();
|
|
|
|
QJsonArray routingArray = root["routing"].toArray();
|
|
for (const auto &val : routingArray) {
|
|
QJsonObject route = val.toObject();
|
|
std::string outNode = route["out_node"].toString().toStdString();
|
|
std::string outPort = route["out_port"].toString().toStdString();
|
|
std::string inNode = route["in_node"].toString().toStdString();
|
|
std::string inPort = route["in_port"].toString().toStdString();
|
|
|
|
client->CreateLinkByName(outNode, outPort, inNode, inPort,
|
|
warppipe::LinkOptions{.linger = true});
|
|
}
|
|
|
|
model->refreshFromClient();
|
|
|
|
if (root.contains("volumes")) {
|
|
QJsonArray volumesArray = root["volumes"].toArray();
|
|
for (const auto &val : volumesArray) {
|
|
QJsonObject obj = val.toObject();
|
|
std::string name = obj["name"].toString().toStdString();
|
|
float volume = static_cast<float>(obj["volume"].toDouble(1.0));
|
|
bool mute = obj["mute"].toBool(false);
|
|
|
|
for (auto qtId : model->allNodeIds()) {
|
|
const WarpNodeData *data = model->warpNodeData(qtId);
|
|
if (data && data->info.name == name) {
|
|
WarpGraphModel::NodeVolumeState vs;
|
|
vs.volume = volume;
|
|
vs.mute = mute;
|
|
model->setNodeVolumeState(qtId, vs);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|