/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad 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. * * Nomad 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 Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Created on Apr 18, 2006 */ package net.sf.nmedit.jsynth.clavia.nordmodular.utils; import java.util.Collection; import java.util.Iterator; import net.sf.nmedit.jnmprotocol2.PDLData; import net.sf.nmedit.jnmprotocol2.utils.NmCharacter; import net.sf.nmedit.jpatch.clavia.nordmodular.Format; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PContentHandler; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PParser; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.ParseException; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PatchBuilder; import net.sf.nmedit.jpdl2.stream.BitStream; import net.sf.nmedit.jpdl2.PDLException; import net.sf.nmedit.jpdl2.PDLPacket; import net.sf.nmedit.jpdl2.PDLPacketParser; /** * Uses a {@link net.sf.nmedit.jpdl.BitStream} as source and * feeds the {@link net.sf.nmedit.jmisc.nomad.patch.builder.PatchDecoder} with the data. * * @author Christian Schneider */ @SuppressWarnings("unchecked") public class BitstreamPatchParser { private int[] recognizeSections = null; public BitstreamPatchParser() { super(); } public void setRecognizedSections(int ...sections) { this.recognizeSections = sections; } private boolean isSectionRecognized(int id) { if (recognizeSections == null) return true; for (int i=0;i<recognizeSections.length;i++) if (recognizeSections[i]==id) return true; return false; } private int[] data = new int[100]; private int[] getData(int size) { if (data.length<size) data = new int[size]; return data; } public void transcode(BitStream stream, PatchBuilder callback) throws ParseException { PDLPacketParser parser = new PDLPacketParser( PDLData.getPatchDoc() ); PDLPacket packet; try { packet = parser.parse(stream); } catch (PDLException e) { throw new ParseException("Illegal patch format.", e); } do { PDLPacket section = packet.getPacket("section"); PDLPacket sectionData = section.getPacket("data"); transcodeSection(section.getVariable("type"), sectionData, callback); packet = packet.getPacket("next"); } while (packet != null); } private void transcodeSection(int section, PDLPacket sectionData, PatchBuilder callback) throws ParseException { if (!isSectionRecognized(section)) return; switch (section) { // Name section case Format.S_NAME_1: case Format.S_NAME_2: // patch name String patchName = NmCharacter.extractName(sectionData.getPacket("name")); callback.setPatchName(patchName); break; // Header section case Format.S_HEADER: { callback.beginSection(PParser.IHEADER, -1); int[] data = getData(PContentHandler.HEADER_RSIZE); data[Format.HEADER_KEYBOARD_RANGE_MIN]=sectionData.getVariable("krangemin"); data[Format.HEADER_KEYBOARD_RANGE_MAX]=sectionData.getVariable("krangemax"); data[Format.HEADER_VELOCITY_RANGE_MIN]=sectionData.getVariable("vrangemin"); data[Format.HEADER_VELOCITY_RANGE_MAX]=sectionData.getVariable("vrangemax"); data[Format.HEADER_PORTAMENTO_TIME]=sectionData.getVariable("ptime"); data[Format.HEADER_PORTAMENTO] =sectionData.getVariable("portamento"); data[Format.HEADER_CABLE_VISIBILITY_RED]=sectionData.getVariable("red"); data[Format.HEADER_CABLE_VISIBILITY_BLUE]=sectionData.getVariable("blue"); data[Format.HEADER_CABLE_VISIBILITY_YELLOW]=sectionData.getVariable("yellow"); data[Format.HEADER_CABLE_VISIBILITY_GRAY]=sectionData.getVariable("gray"); data[Format.HEADER_CABLE_VISIBILITY_GREEN]=sectionData.getVariable("green"); data[Format.HEADER_CABLE_VISIBILITY_PURPLE]=sectionData.getVariable("purple"); data[Format.HEADER_CABLE_VISIBILITY_WHITE]=sectionData.getVariable("white"); data[Format.HEADER_VOICE_RETRIGGER_POLY]=sectionData.getVariable("pretrigger"); data[Format.HEADER_VOICE_RETRIGGER_COMMON]=sectionData.getVariable("cretrigger"); data[Format.HEADER_BEND_RANGE]=sectionData.getVariable("brange"); data[Format.HEADER_REQUESTED_VOICES]=sectionData.getVariable("voices")+1; data[Format.HEADER_SECTION_SEPARATOR_POSITION]=sectionData.getVariable("sspos"); data[Format.HEADER_OCTAVE_SHIFT]=sectionData.getVariable("octave"); data[Format.HEADER_UNKNOWN1] = Format.HEADER_UNKNOWN1_DEFAULT; data[Format.HEADER_UNKNOWN2] = Format.HEADER_UNKNOWN2_DEFAULT; data[Format.HEADER_UNKNOWN3] = Format.HEADER_UNKNOWN3_DEFAULT; data[Format.HEADER_UNKNOWN4] = Format.HEADER_UNKNOWN4_DEFAULT; callback.header(data); callback.endSection(PParser.IHEADER); } break; // Module section case Format.S_MODULE: { int va = sectionData.getVariable("section"); callback.beginSection(PParser.IMODULEDUMP, va); int[] record = getData(4); for (PDLPacket p : sectionData.getPacketList("modules")) { record[Format.MODULE_DUMP_MODULE_INDEX] = p.getVariable("index"); record[Format.MODULE_DUMP_MODULE_TYPE] = p.getVariable("type"); record[Format.MODULE_DUMP_MODULE_XPOS] = p.getVariable("xpos"); record[Format.MODULE_DUMP_MODULE_YPOS] = p.getVariable("ypos"); callback.moduleDump(record); } callback.endSection(PParser.IMODULEDUMP); } break; // Note section case Format.S_NOTE: { callback.beginSection(PParser.ICURRENTNOTEDUMP, -1); int[] record = getData(3); for (int i=1;i<=2;i++) { PDLPacket note = sectionData.getPacket("note"+i); record[Format.CURRENT_NOTE_DUMP_NOTE] = note.getVariable("value"); record[Format.CURRENT_NOTE_DUMP_ATTACK_VELOCITY] = note.getVariable("attack"); record[Format.CURRENT_NOTE_DUMP_RELEASE_VELOCITY] = note.getVariable("release"); callback.currentNoteDump(record); } for (PDLPacket note: sectionData.getPacketList("notes")) { record[Format.CURRENT_NOTE_DUMP_NOTE] = note.getVariable("value"); record[Format.CURRENT_NOTE_DUMP_ATTACK_VELOCITY] = note.getVariable("attack"); record[Format.CURRENT_NOTE_DUMP_RELEASE_VELOCITY] = note.getVariable("release"); callback.currentNoteDump(record); } callback.endSection(PParser.ICURRENTNOTEDUMP); } break; // Cable section case Format.S_CABLE: { int va = sectionData.getVariable("section"); callback.beginSection(PParser.ICABLEDUMP, va); int[] record = getData(Format.VALUE_COUNT_CABLE_DUMP); for (PDLPacket note: sectionData.getPacketList("cables")) { record[Format.CABLE_DUMP_COLOR]=note.getVariable("color"); record[Format.CABLE_DUMP_MODULE_INDEX_DESTINATION]=note.getVariable("destination"); record[Format.CABLE_DUMP_CONNECTOR_INDEX_DESTINATION]=note.getVariable("input"); record[Format.CABLE_DUMP_CONNECTOR_TYPE_DESTINATION]=Format.VALUE_CABLE_DUMP_INPUT; record[Format.CABLE_DUMP_MODULE_INDEX_SOURCE]=note.getVariable("source"); record[Format.CABLE_DUMP_CONNECTOR_INDEX_SOURCE]=note.getVariable("inputOutput"); record[Format.CABLE_DUMP_CONNECTOR_TYPE_SOURCE]=note.getVariable("type"); callback.cableDump(record); } callback.endSection(PParser.ICABLEDUMP); } break; // Parameter section case Format.S_PARAMETER: { int va = sectionData.getVariable("section"); // TODO handle morph section ??? if (va!=Format.VALUE_SECTION_MORPH) { callback.beginSection(PParser.IPARAMETERDUMP, va); for (PDLPacket modules: sectionData.getPacketList("parameters")) { int module_index = modules.getVariable("index"); int module_type = modules.getVariable("type"); if (section==Format.VALUE_SECTION_MORPH) { //module_type = 0; module_index = 0; } PDLPacket parameters = modules.getPacket("parameters"); Collection<String> param = parameters.getAllVariables(); int [] record = getData(3+param.size()); record[Format.PARAMETER_DUMP_MODULE_INDEX]= module_index; record[Format.PARAMETER_DUMP_MODULE_TYPE]= module_type; // TODO read variable record[Format.PARAMETER_DUMP_PARAMETER_COUNT]= param.size(); // implied Iterator<String> iter = param.iterator(); for (int i=0;i<param.size();i++) { record[Format.PARAMETER_DUMP_PARAMETER_BASE+i] = parameters.getVariable(iter.next()); } callback.parameterDump(record); //param.clear(); } callback.endSection(PParser.IPARAMETERDUMP); } } break; // Morphmap section case Format.S_MORPHMAP: { int[] data = getData(4); // keyboardAssignment callback.beginSection(PParser.IKEYBOARDASSIGNMENT, -1); data[Format.KEYBOARD_ASSIGNMENT_MORPH1] = sectionData.getVariable("keyboard1"); data[Format.KEYBOARD_ASSIGNMENT_MORPH2] = sectionData.getVariable("keyboard2"); data[Format.KEYBOARD_ASSIGNMENT_MORPH3] = sectionData.getVariable("keyboard3"); data[Format.KEYBOARD_ASSIGNMENT_MORPH4] = sectionData.getVariable("keyboard4"); callback.keyboardAssignment(data); callback.endSection(PParser.IKEYBOARDASSIGNMENT); // knob values callback.beginSection(PParser.IMORPHMAPDUMP, -1); data[Format.MORPH_MAP_DUMP_VALUES_MORPH1] = sectionData.getVariable("morph1"); data[Format.MORPH_MAP_DUMP_VALUES_MORPH2] = sectionData.getVariable("morph2"); data[Format.MORPH_MAP_DUMP_VALUES_MORPH3] = sectionData.getVariable("morph3"); data[Format.MORPH_MAP_DUMP_VALUES_MORPH4] = sectionData.getVariable("morph4"); callback.morphMapDumpProlog(data); // parameter assignments data = getData(5); for (PDLPacket p : sectionData.getPacketList("morphs")) { data[Format.MORPH_MAP_DUMP_MORPH_INDEX] = p.getVariable("morph"); data[Format.MORPH_MAP_DUMP_SECTION] = p.getVariable("section"); data[Format.MORPH_MAP_DUMP_MODULE_INDEX] = p.getVariable("module"); data[Format.MORPH_MAP_DUMP_MORPH_RANGE] = p.getVariable("range"); //TODO out of range??? X-127 ??? data[Format.MORPH_MAP_DUMP_PARAMETER_INDEX] = p.getVariable("parameter"); callback.morphMapDump(data); } callback.endSection(PParser.IMORPHMAPDUMP); } break; // Knobmap section case Format.S_KNOBMAP: { callback.beginSection(PParser.IKNOBMAPDUMP, -1); int[] data = getData(4); //new int[5]; for (int i = 0; i < 23; i++) { PDLPacket knob = sectionData.getPacket("knob"+i); boolean assigned = knob.getVariable("assigned")==1; if (assigned) { PDLPacket assignment = knob.getPacketList("assignment")[0]; // .front() data[Format.KNOB_MAP_DUMP_SECTION_INDEX] = assignment.getVariable("section"); data[Format.KNOB_MAP_DUMP_KNOB_INDEX] = i; data[Format.KNOB_MAP_DUMP_MODULE_INDEX] = assignment.getVariable("module"); data[Format.KNOB_MAP_DUMP_PARAMETER_INDEX] = assignment.getVariable("parameter"); callback.knobMapDump(data); } } callback.endSection(PParser.IKNOBMAPDUMP); } break; // Controlmap section case Format.S_CTRLMAP: { callback.beginSection(PParser.ICTRLMAPDUMP, -1); int[] data = getData(4); for (PDLPacket p : sectionData.getPacketList("controls")) { data[Format.CTRL_MAP_DUMP_SECTION_INDEX] = p.getVariable("section"); data[Format.CTRL_MAP_DUMP_MODULE_INDEX] = p.getVariable("module"); data[Format.CTRL_MAP_DUMP_PARAMETER_INDEX] = p.getVariable("parameter"); data[Format.CTRL_MAP_DUMP_CC_INDEX] = p.getVariable("control"); callback.ctrlMapDump(data); } callback.endSection(PParser.ICTRLMAPDUMP); } break; // Custom section case Format.S_CUSTOM: { int va = sectionData.getVariable("section"); callback.beginSection(PParser.ICUSTOMDUMP, va); for (PDLPacket modules: sectionData.getPacketList("customModules")) { int module_index = modules.getVariable("index"); PDLPacket parameters = modules.getPacket("customValues"); Collection<String> param = parameters.getAllVariables(); int[] data = getData(2+param.size()); data[Format.CUSTOM_DUMP_MODULE_INDEX] = module_index; data[Format.CUSTOM_DUMP_PARAMETER_COUNT] = param.size(); Iterator<String> iter = param.iterator(); for (int i=0;i<param.size();i++) data[Format.CUSTOM_DUMP_PARAMETER_BASE+i] = parameters.getVariable(iter.next()); callback.customDump(data); } callback.endSection(PParser.ICUSTOMDUMP); } break; // Namedump section case Format.S_NAMEDUMP: { int va = sectionData.getVariable("section"); callback.beginSection(PParser.INAMEDUMP, va); for (PDLPacket p : sectionData.getPacketList("moduleNames")) { int moduleIndex = p.getVariable("index"); String moduleName = NmCharacter.extractName(p.getPacket("name")); callback.moduleNameDump(moduleIndex, moduleName); } callback.endSection(PParser.INAMEDUMP); } break; } } }