Skip to content

Instantly share code, notes, and snippets.

@oleics
Last active November 21, 2019 13:48
Show Gist options
  • Save oleics/a4569a39009257a9afbeb26c17c72080 to your computer and use it in GitHub Desktop.
Save oleics/a4569a39009257a9afbeb26c17c72080 to your computer and use it in GitHub Desktop.
Merge multiple Deluge (Synthstrom) songs into one single song
<template>
<div>
Deluge Song Merger
<div v-if="state.error">
{{state.error}}
</div>
<div>
Song Files (eg SONG000.XML and SONG001.XML)
<input type="file" name="files[]" multiple @change="onFileSelect">
</div>
<div v-if="state.files.length > 1">
<div v-for="file in state.files">
{{file.name}}
{{file.size}}
{{file.type}}
</div>
</div>
<div>
Merge into (eg SONG000.XML or SONG001.XML)
<input type="file" name="mergeinto" @change="onMergeintoSelect">
</div>
<button @click="mergeFiles">mergeFiles</button>
<div v-if="state.output">
<a :href="state.outputDataURL" :download="state.outputFilename">save to disk</a>
<textarea class="small w-100" style="min-height:9rem">{{state.output}}</textarea>
</div>
<div class="text-muted">
* Works only for files written by firmware 3.0.0 or above
* Modern browsers required
</div>
</div>
</template>
<script>
module.exports = {
name: 'deluge-song-merger',
data: function() {
return {
state: {
files: [],
mergeInto: null,
error: null,
output: null,
outputDataURL: null,
outputFilename: null
}
};
},
methods: {
onMergeintoSelect: function($event) {
var file = $event.target.files[0];
this.state.error = null;
this.state.mergeInto = null;
readAndParseXMLFile(file).then((file) => {
this.state.mergeInto = file;
}).catch((err) => {
console.error(err.stack||err);
this.state.error = err;
});
},
onFileSelect: function($event) {
this.state.error = null;
this.state.files.splice(0, this.state.files.length);
var files = $event.target.files;
var promises = [];
for(var i = 0, f; f = files[i]; i++) {
promises.push(readAndParseXMLFile(f));
}
Promise.all(promises).then((files) => {
this.state.files.splice.apply(this.state.files, [0, this.state.files.length].concat(files));
}).catch((err) => {
console.error(err.stack||err);
this.state.error = err;
});
},
mergeFiles: function() {
var selectorInstrumentChilds = 'song > instruments > sound, song > instruments > kit';
var selectorInstrumentClips = 'song > sessionClips > instrumentClip';
var selectorSessionClips = 'song > sessionClips';
var selectorInstruments = 'song > instruments';
// collect from state.files
var instrumentChilds = [];
var instrumentClips = [];
var files = this.state.files;
for(var i = 0, f; f = files[i]; i++) {
instrumentChilds.push.apply(instrumentChilds, f.doc.querySelectorAll(selectorInstrumentChilds));
instrumentClips.push.apply(instrumentClips, f.doc.querySelectorAll(selectorInstrumentClips));
}
var mergeInto = this.state.mergeInto.doc;
var instruments = mergeInto.querySelector(selectorInstruments);
var sessionClips = mergeInto.querySelector(selectorSessionClips);
while(instruments.childNodes.length) {
instruments.removeChild(instruments.firstChild);
}
while(sessionClips.childNodes.length) {
sessionClips.removeChild(sessionClips.firstChild);
}
for(var i = 0, len = instrumentChilds.length; i < len; i++) {
instruments.appendChild(instrumentChilds[i]);
}
for(var i = 0, len = instrumentClips.length; i < len; i++) {
sessionClips.appendChild(instrumentClips[i]);
}
// Serialize into XML string
var serializer = new XMLSerializer();
var output = serializer.serializeToString(mergeInto);
this.state.output = output;
this.state.outputDataURL = 'data:text/xml;charset=utf-8,' + encodeURIComponent(output);
this.state.outputFilename = 'SONG.XML';
},
}
}
function readAndParseXMLFile(theFile) {
return new Promise(function(resolve, reject) {
var reader = new FileReader();
reader.onload = (e) => {
var content = e.target.result;
var parser = new DOMParser();
try { // dunno if this actually throws
var doc = parser.parseFromString(content, 'text/xml');
} catch(ex) {
return reject(ex);
}
resolve({
name: theFile.name,
size: theFile.size,
type: theFile.type,
doc: doc,
});
};
reader.readAsText(theFile);
});
}
</script>
@oleics
Copy link
Author

oleics commented Nov 21, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment