/* 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 May 25, 2006 */ package net.sf.nmedit.jsynth.clavia.nordmodular.utils; import java.util.ArrayList; import java.util.List; import net.sf.nmedit.jnmprotocol2.MidiException; import net.sf.nmedit.jnmprotocol2.PDLData; import net.sf.nmedit.jnmprotocol2.PatchMessage; import net.sf.nmedit.jpatch.PConnector; import net.sf.nmedit.jpatch.PModule; import net.sf.nmedit.jpatch.PParameter; import net.sf.nmedit.jpatch.clavia.nordmodular.Format; import net.sf.nmedit.jpatch.clavia.nordmodular.Header; import net.sf.nmedit.jpatch.clavia.nordmodular.Knob; import net.sf.nmedit.jpatch.clavia.nordmodular.MidiController; import net.sf.nmedit.jpatch.clavia.nordmodular.MidiControllerSet; import net.sf.nmedit.jpatch.clavia.nordmodular.NMPatch; import net.sf.nmedit.jpatch.clavia.nordmodular.PNMMorphSection; import net.sf.nmedit.jpatch.clavia.nordmodular.VoiceArea; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.Helper; import net.sf.nmedit.jpdl2.PDLException; import net.sf.nmedit.jpdl2.PDLPacketParser; import net.sf.nmedit.jpdl2.stream.BitStream; import net.sf.nmedit.jpdl2.stream.IntStream; public class Patch2BitstreamBuilder { private IntStream intStream; private PDLPacketParser patchParser = new PDLPacketParser( PDLData.getPatchDoc() ); private List<BitStream> sections = new ArrayList<BitStream>(); private final NMPatch patch; private boolean headerOnly = false; private boolean generated = false; public void setHeaderOnly(boolean enable) { this.headerOnly = enable; } public Patch2BitstreamBuilder( NMPatch patch ) { this.patch = patch; intStream = new IntStream(); } public PatchMessage[] createMessages(int slot) throws MidiException { if (!generated) generate(); List<PatchMessage> messages = new ArrayList<PatchMessage>(); for (int i=0;i<sections.size();i++) { messages.add(new PatchMessage(sections.get(i), slot, i, sections.size())); } return messages.toArray(new PatchMessage[messages.size()]); } private void append(int value) { //System.out.print (value+" "); intStream.append(value); } private void append(int ... values) { for (int i=0;i<values.length;i++) { //System.out.print (values[i]+" "); intStream.append(values[i]); } } public BitStream[] getBitStreams() { return sections.toArray(new BitStream[sections.size()]); } public void appendName( String s ) { int limit = Math.min(16, s.length()); for (int i = 0; i < limit; i++) { append((int)s.charAt(i)); } if (limit < 16) append(0); } private void beginSection(int ID) { intStream.append(ID); } private void endSection() { intStream.setPosition(0); try { patchParser.parse(intStream); } catch (PDLException e) { throw new RuntimeException("generate failed"); } BitStream bitStream = patchParser.getBitStream(); bitStream.setPosition(0); sections.add(bitStream); intStream = new IntStream(); } private void generate() { if(generated) return; // Create patch bitstream if (headerOnly) { generateHeader(); return; } // Name section beginSection(Format.S_NAME_1); { String name = patch.getName(); if (name == null) name = ""; appendName(name); } endSection(); // Header section generateHeader(); // Module section moduleSection(patch.getPolyVoiceArea()); moduleSection(patch.getCommonVoiceArea()); // Note section beginSection(Format.S_NOTE); { append(64, 0, 0); append(0); // size append(64, 0, 0);/* Iterator<Note> nIter = patch.getNoteSet().iterator(); Note n = nIter.next(); // TODO append(n.getNoteNumber(), n.getAttackVelocity(), n.getReleaseVelocity()); append(patch.getNoteSet().size()-1); append(n.getNoteNumber(), n.getAttackVelocity(), n.getReleaseVelocity()); while(nIter.hasNext()) { n = nIter.next(); append(n.getNoteNumber(), n.getAttackVelocity(), n.getReleaseVelocity()); }*/ } endSection(); // Cable section cableSection(patch.getPolyVoiceArea()); cableSection(patch.getCommonVoiceArea()); // Parameter section parameterSection(patch.getPolyVoiceArea()); parameterSection(patch.getCommonVoiceArea()); // Morph section beginSection(Format.S_MORPHMAP); { int nknobs = 0; final PNMMorphSection ms = patch.getMorphSection(); for (int i=0;i<ms.getMorphCount();i++) { PParameter m = ms.getMorph(i); append(m.getValue()); nknobs+=ms.getAssignments(i).size(); } for (int i=0;i<ms.getMorphCount();i++) { PParameter m = ms.getMorph(i); append(m.getValue()); } append(nknobs); for (int i=0;i<ms.getMorphCount();i++) { PParameter m = ms.getMorph(i); for (PParameter p : ms.getAssignments(i)) { append(p.getParentComponent().getParentComponent().getComponentIndex()); append(p.getParentComponent().getComponentIndex()); append(Helper.index(p)); append(Helper.index(m)); append(m.getValue()); // ???? m.getRange() ??? } } } endSection(); // Knob section beginSection(Format.S_KNOBMAP); for (int i = 0; i <= 22; i++) { boolean found = false; for (Knob k : patch.getKnobs()) { if (k.getID()==i && k.getParameter()!=null) { found = true; append(1); PParameter a = k.getParameter(); int moduleIndex = patch.getMorphSection().isMorph(a) ? 1 : a.getParentComponent().getComponentIndex(); append(a.getParentComponent().getParentComponent().getComponentIndex()); append(moduleIndex); append(Helper.index(a)); break ; } } if (!found) { append(0); } } endSection(); // Control section beginSection(Format.S_CTRLMAP); { final MidiControllerSet ms = patch.getMidiControllers(); MidiController[] msList = ms.getAssignedControllers(); int size = msList.length; append(size); for (MidiController mc : msList) { append(mc.getControlId()); // CC PParameter a = mc.getParameter(); int moduleIndex = patch.getMorphSection().isMorph(a) ? 1 : a.getParentComponent().getComponentIndex(); append(a.getParentComponent().getParentComponent().getComponentIndex()); append(moduleIndex); append(Helper.index(a)); } } endSection(); // Custom section customSection(patch.getPolyVoiceArea()); customSection(patch.getCommonVoiceArea()); // Module name section moduleNameSection(patch.getPolyVoiceArea()); moduleNameSection(patch.getCommonVoiceArea()); generated = true; } protected void generateHeader() { Header h = patch.getHeader(); beginSection(Format.S_HEADER); append(h.getKeyboardRangeMin()); append(h.getKeyboardRangeMax()); append(h.getVelocityRangeMin()); append(h.getVelocityRangeMax()); append(h.getBendRange()); append(h.getPortamentoTime()); append(h.getPortamento()); append(1); append(h.getRequestedVoices() - 1); append(0); append(h.getSeparatorPosition()); append(h.getOctaveShift()); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_RED)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_BLUE)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_YELLOW)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_GRAY)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_GREEN)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_PURPLE)); append(h.getValue(Format.HEADER_CABLE_VISIBILITY_WHITE)); append(h.getValue(Format.HEADER_VOICE_RETRIGGER_COMMON)); append(h.getValue(Format.HEADER_VOICE_RETRIGGER_POLY)); append(0xF); append(0); endSection(); } private void moduleSection(VoiceArea va) { beginSection(Format.S_MODULE); append(Format.getVoiceAreaID(va.isPolyVoiceArea())); append(va.getModuleCount()); for (PModule m : va) { append(Helper.index(m)); append(m.getComponentIndex()); append(m.getInternalX()); append(m.getInternalY()); } endSection(); } private void cableSection(VoiceArea va) { beginSection(Format.S_CABLE); append(Format.getVoiceAreaID(va.isPolyVoiceArea())); IntStream intStream2 = new IntStream(); int cablecount = 0; for (PModule m : va) { for (int j=m.getConnectorCount()-1;j>=0;j--) { // first connector (dst) triple is always an input // the second (src) triple is either in, or output PConnector dst = m.getConnector(j); PConnector src = dst.getParentConnector(); if (src!=null) { // only src can be an output intStream2.append(//Format.CABLE_DUMP_COLOR src.getSignalType().getId()); intStream2.append(//Format.CABLE_DUMP_MODULE_INDEX_SOURCE, src.getParentComponent().getComponentIndex()); intStream2.append(//Format.CABLE_DUMP_CONNECTOR_INDEX_SOURCE, Helper.index(src)); intStream2.append(//Format.CABLE_DUMP_CONNECTOR_TYPE_SOURCE, Format.getOutputID(src.isOutput())); intStream2.append(//Format.CABLE_DUMP_MODULE_INDEX_DESTINATION, dst.getParentComponent().getComponentIndex()); intStream2.append(//Format.CABLE_DUMP_CONNECTOR_INDEX_DESTINATION Helper.index(dst)); // always input //intStream2.append(//Format.CABLE_DUMP_CONNECTOR_TYPE_DESTINATION, // Format.getOutputID(dst.isOutput())); cablecount++; } } } append(cablecount); // append buffer while (intStream2.isAvailable(1)) append(intStream2.getInt()); endSection(); } private void parameterSection(VoiceArea va) { beginSection(Format.S_PARAMETER); append(Format.getVoiceAreaID(va.isPolyVoiceArea())); int nmodules = 0; for (PModule m : va) { if (Helper.getParameterClassCount(m, "parameter")>0) nmodules++; } append(nmodules); for (PModule m : va) { List<PParameter> plist = Helper.getParametersByClass(m, "parameter"); int size = plist.size(); if (size>0) { append(m.getComponentIndex()); append(Helper.index(m)); for (int i=0;i<size;i++) { append(plist.get(i).getValue()); } } } endSection(); } private void customSection(VoiceArea va) { beginSection(Format.S_CUSTOM); append(Format.getVoiceAreaID(va.isPolyVoiceArea())); int nmodules = 0; for (PModule m : va) { if (Helper.getParameterClassCount(m, "custom")>0) nmodules++; } append(nmodules); for (PModule m : va) { List<PParameter> plist = Helper.getParametersByClass(m, "custom"); int size = plist.size(); if (size>0) { append(m.getComponentIndex()); // not:append(module id); append(size); for (int i=0;i<size;i++) { append(plist.get(i).getValue()); } } } endSection(); } private void moduleNameSection(VoiceArea va) { beginSection(Format.S_NAMEDUMP); append(Format.getVoiceAreaID(va.isPolyVoiceArea())); append(va.getModuleCount()); for (PModule m : va) { append(m.getComponentIndex()); String t = m.getTitle(); appendName(t == null ? "" : t); } endSection(); } }