/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * projectserialiser.cc * * Sat May 12 10:11:22 CEST 2018 * Copyright 2018 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of DrumGizmo. * * DrumGizmo is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * DrumGizmo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "projectserialiser.h" #include #include #include #include /* MyProject /some/path */ class DomHelper { public: DomHelper(const QDomDocument& doc) : elem(doc.documentElement()) {} DomHelper(const QDomElement& elem) : elem(elem) {} DomHelper operator()(const QString& name) { auto node = elem.namedItem(name); if(!node.isElement()) { std::cout << "No such child-element: '" << name.toStdString() << "'\n"; QDomElement e; return DomHelper(e); } return DomHelper(node.toElement()); } QString operator[](const QString& name) { auto attrs = elem.attributes(); auto node = attrs.namedItem(name); if(!node.isAttr()) { std::cout << "No such attribute: '" << name.toStdString() << "'\n"; return ""; } return node.toAttr().value(); } QString text() { return elem.text(); } // Get child nodes with tag_name or all child nodes if tag_name == "". std::vector children(const QString& tag_name = "") { std::vector children; auto child_nodes = elem.childNodes(); for(int i = 0; i < child_nodes.count(); ++i) { auto node = child_nodes.at(i); if(!node.isElement()) { continue; } auto elem = node.toElement(); if(elem.tagName() == tag_name || tag_name == "") { children.emplace_back(DomHelper(elem)); } } return children; } private: QDomElement elem; }; QString ProjectSerialiser::serialise(const Project& project) { // Ugly hack to ensure the xml attribute order is the same each time a save // or export is performed. qSetGlobalQHashSeed(0); QDomDocument doc; auto header = doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'"); doc.appendChild(header); auto dgedit = doc.createElement("dgedit"); doc.appendChild(dgedit); dgedit.setAttribute("version", "1.0"); auto project_name = doc.createElement("project_name"); project_name.appendChild(doc.createTextNode(project.project_name)); dgedit.appendChild(project_name); auto raw_file_root = doc.createElement("raw_file_root"); raw_file_root.appendChild(doc.createTextNode(project.raw_file_root)); dgedit.appendChild(raw_file_root); auto description = doc.createElement("description"); description.appendChild(doc.createTextNode(project.description)); dgedit.appendChild(description); auto export_path = doc.createElement("export_path"); export_path.appendChild(doc.createTextNode(project.export_path)); dgedit.appendChild(export_path); dgedit.setAttribute("next_id", project.next_id); dgedit.setAttribute("samplerate", project.samplerate); auto channels = doc.createElement("channels"); dgedit.appendChild(channels); for(const auto& c : project.channels) { auto channel = doc.createElement("channel"); channel.setAttribute("id", c.getId()); channel.setAttribute("name", c.getChannelName()); channels.appendChild(channel); } auto instruments = doc.createElement("instruments"); dgedit.appendChild(instruments); for(const auto& i : project.instruments) { auto instrument = doc.createElement("instrument"); instrument.setAttribute("id", (int)i.getId()); 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()); auto prefix = doc.createElement("prefix"); prefix.appendChild(doc.createTextNode(i.getPrefix())); instrument.appendChild(prefix); instruments.appendChild(instrument); auto instrument_name = doc.createElement("instrument_name"); instrument_name.appendChild(doc.createTextNode(i.instrument_name)); instrument.appendChild(instrument_name); auto file_list = doc.createElement("file_list"); instrument.appendChild(file_list); for(const auto& audiofile : i.audio_files) { auto file = doc.createElement("file"); file.appendChild(doc.createTextNode(audiofile.getFile())); file.setAttribute("id", audiofile.getId()); file.setAttribute("name", audiofile.getName()); file.setAttribute("channel_map_id", audiofile.getChannelMapId()); file.setAttribute("master", i.master_file == audiofile.getAbsoluteFile()); file.setAttribute("main", audiofile.getMainChannel() ? "true" : "false"); 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(); } bool ProjectSerialiser::deserialise(const QString& data, Project& project) { // Ugly hack to ensure the xml attribute order is the same each time a save // or export is performed. qSetGlobalQHashSeed(0); QDomDocument doc; if(!doc.setContent(data)) { std::cout << "Could not parse XML\n"; return false; } project.reset(); DomHelper dom(doc); QString version = dom["version"]; if(version != "1.0") { std::cout << "Bad version: '" << version.toStdString() << "'\n"; return false; } project.next_id = dom["next_id"].toInt(); project.samplerate = dom["samplerate"].toDouble(); project.project_name = dom("project_name").text(); project.raw_file_root = dom("raw_file_root").text(); project.description = dom("description").text(); project.export_path = dom("export_path").text(); auto channels = dom("channels").children("channel"); for(auto& channel : channels) { auto id = channel["id"].toInt(); project.channels.emplace_back(Channel(project, id)); auto& ch = project.channels.back(); ch.channel_name = channel["name"]; } auto instruments = dom("instruments").children("instrument"); for(auto& instrument : instruments) { auto id = instrument["id"].toInt(); project.instruments.emplace_back(Instrument(project, id)); auto& instr = project.instruments.back(); instr.instrument_name = instrument("instrument_name").text(); QString master_file; auto files = instrument("file_list").children("file"); for(auto& file : files) { auto id = file["id"].toInt(); instr.audio_files.emplace_back(AudioFile(instr, id)); auto& audiofile = instr.audio_files.back(); audiofile.file = file.text(); audiofile.name = file["name"]; audiofile.channel_map_id = file["channel_map_id"].toInt(); audiofile.main_channel = file["main"] == "true"; if(file["master"] == "1") { master_file = audiofile.getAbsoluteFile(); } } 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(); instr.prefix = instrument("prefix").text(); 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; }