/* 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 Jan 9, 2007
*/
package net.sf.nmedit.jsynth.clavia.nordmodular.utils;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collection;
import javax.xml.parsers.ParserConfigurationException;
import net.sf.nmedit.jnmprotocol2.DeleteCableMessage;
import net.sf.nmedit.jnmprotocol2.DeleteModuleMessage;
import net.sf.nmedit.jnmprotocol2.KnobAssignmentMessage;
import net.sf.nmedit.jnmprotocol2.MidiCtrlAssignmentMessage;
import net.sf.nmedit.jnmprotocol2.MidiException;
import net.sf.nmedit.jnmprotocol2.MidiMessage;
import net.sf.nmedit.jnmprotocol2.MorphAssignmentMessage;
import net.sf.nmedit.jnmprotocol2.MorphRangeChangeMessage;
import net.sf.nmedit.jnmprotocol2.MoveModuleMessage;
import net.sf.nmedit.jnmprotocol2.NewCableMessage;
import net.sf.nmedit.jnmprotocol2.NewModuleMessage;
import net.sf.nmedit.jnmprotocol2.ParameterMessage;
import net.sf.nmedit.jnmprotocol2.ParameterSelectMessage;
import net.sf.nmedit.jnmprotocol2.PatchListEntry;
import net.sf.nmedit.jnmprotocol2.PatchListMessage;
import net.sf.nmedit.jnmprotocol2.PatchMessage;
import net.sf.nmedit.jnmprotocol2.SetModuleTitleMessage;
import net.sf.nmedit.jpatch.PConnector;
import net.sf.nmedit.jpatch.PModule;
import net.sf.nmedit.jpatch.PModuleContainer;
import net.sf.nmedit.jpatch.PParameter;
import net.sf.nmedit.jpatch.clavia.nordmodular.Format;
import net.sf.nmedit.jpatch.clavia.nordmodular.NM1ModuleDescriptions;
import net.sf.nmedit.jpatch.clavia.nordmodular.NMPatch;
import net.sf.nmedit.jpatch.clavia.nordmodular.VoiceArea;
import net.sf.nmedit.jpatch.clavia.nordmodular.parser.ErrorHandler;
import net.sf.nmedit.jpatch.clavia.nordmodular.parser.Helper;
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.jpatch.clavia.nordmodular.parser.PatchExporter;
import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PatchFileWriter;
import net.sf.nmedit.jsynth.SynthException;
import net.sf.nmedit.jtheme.util.RelativeClassLoader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
public class NmUtils
{
public static NM1ModuleDescriptions parseModuleDescriptions()
throws ParserConfigurationException, SAXException, IOException, URISyntaxException
{
NmUtils instance = new NmUtils();
final String file = "/module-descriptions/modules.xml";
NM1ModuleDescriptions descriptions;
URL resource = instance.getClass().getResource(file);
InputStream in = new BufferedInputStream(resource.openStream());
try
{
descriptions = NM1ModuleDescriptions.parse(RelativeClassLoader.fromPath(NmUtils.class.getClassLoader(),
resource),in);
}
finally
{
in.close();
}
return descriptions;
}
public static SynthException transformException(Throwable e)
{
if (e instanceof SynthException)
return (SynthException) e;
SynthException se = new SynthException();
se.initCause(e);
return se;
}
/*
public static String getPatchBankLocation(int section, int position)
{
return Integer.toString(((section+1)*100)+(position+1));
}*/
/*
public static MidiMessage createMorphRangeMessage(PParameter parameter, int span, int direction)
{
MorphRangeMessage msg = new MorphRangeMessage();
PModule module = parameter.getParentComponent();
PModuleContainer va = module.getParentComponent();
int section = va.getComponentIndex();
int moduleIndex = module.getComponentIndex();
int parameterIndex = parameter.getComponentIndex();
msg.setMessage(section, moduleIndex, parameterIndex, span, direction);
return msg;
}
*/
public static MidiMessage createMidiCtrlAssignmentMessage(PParameter parameter, int prevMidiCtrl, int midiCtrl,
int slot, int pid)
{
MidiCtrlAssignmentMessage msg = new MidiCtrlAssignmentMessage();
PModule module = parameter.getParentComponent();
PModuleContainer va = module.getParentComponent();
int section = va.getComponentIndex();
int moduleIndex = module.getComponentIndex();
int parameterIndex = Helper.index(parameter);
msg.assign(slot, pid, prevMidiCtrl, midiCtrl, section, moduleIndex, parameterIndex);
return msg;
}
public static MidiMessage createMorphAssignmentMessage(PParameter parameter, int morph,
int slot, int pid)
{
MorphAssignmentMessage msg = new MorphAssignmentMessage();
PModule module = parameter.getParentComponent();
PModuleContainer va = module.getParentComponent();
int section = va.getComponentIndex();
int moduleIndex = module.getComponentIndex();
int parameterIndex = Helper.index(parameter);
msg.setMorphAssignment(slot, pid, section, moduleIndex, parameterIndex, morph);
return msg;
}
public static MidiMessage createKnobAssignmentMessage(PParameter parameter, int prevKnob, int knob,
int slot, int pid)
{
KnobAssignmentMessage msg = new KnobAssignmentMessage();
PModule module = parameter.getParentComponent();
PModuleContainer va = module.getParentComponent();
int section = va.getComponentIndex();
int moduleIndex = module.getComponentIndex();
int parameterIndex = Helper.index(parameter);
msg.assign(slot, pid, prevKnob, knob, section, moduleIndex, parameterIndex);
return msg;
}
public static MidiMessage createMidiCtrlDeAssignmentMessage(int cc, int slot, int pid)
{
MidiCtrlAssignmentMessage msg = new MidiCtrlAssignmentMessage();
msg.deassign(slot, pid, cc);
return msg;
}
public static MidiMessage createKnobDeAssignmentMessage(int knob, int slot, int pid)
{
KnobAssignmentMessage msg = new KnobAssignmentMessage();
msg.deassign(slot, pid, knob);
return msg;
}
public static MidiMessage createNewModuleMessage(int pid, PModule module, int slotId) throws MidiException
{
NewModuleMessage msg = new NewModuleMessage();
msg.setPid(pid);
msg.setSlot(slotId);
// get data
int section = module.getParentComponent().getComponentIndex();
String name = module.getName();
if (name == null)
name = "";
// set data
msg.newModule
(
Helper.index(module), // module id
section,
module.getComponentIndex(),
module.getInternalX(),
module.getInternalY(),
name,
Helper.paramValues(module, "parameter"),
Helper.paramValues(module, "custom")
);
/* System.out.println(msg);
System.out.println(Helper.index(module));
System.out.println(section);
System.out.println(module.getComponentIndex());
System.out.println(module.getInternalX());
System.out.println(module.getInternalY());
System.out.println(name);
*/
return msg;
}
public static MidiMessage createDeleteModuleMessage( int pid, PModule module, int moduleIndex )
{
return createDeleteModuleMessage(pid, module.getParentComponent().getComponentIndex(), moduleIndex);
}
public static MidiMessage createDeleteModuleMessage( int pid, int polyVoiceArea, int moduleIndex )
{
DeleteModuleMessage msg = new DeleteModuleMessage();
// get data
int section = polyVoiceArea;
// set data
msg.deleteModule( section, moduleIndex );
return msg;
}
public static MidiMessage createDeleteCableMessage( VoiceArea va, PConnector a, PConnector b, int slotId, int pId )
{
// get message instance
DeleteCableMessage msg = new DeleteCableMessage();
msg.setSlot(slotId);
msg.setPid(pId);
// get data
PConnector src = a;
PConnector dst = b;
if (dst.isOutput())
{
src = b; // swap
dst = a;
}
// set data
msg.deleteCable
(
getVoiceAreaId(va),
dst.getParentComponent().getComponentIndex(),
Format.getOutputID(dst.isOutput()),
Helper.index(dst),
src.getParentComponent().getComponentIndex(),
Format.getOutputID(src.isOutput()),
Helper.index(src)
);
return msg;
}
public static MidiMessage createNewCableMessage( VoiceArea va, PConnector a, PConnector b, int slotId, int pId )
{
// get message instance
NewCableMessage msg = new NewCableMessage();
msg.setSlot(slotId);
msg.setPid(pId);
// get data
PConnector src = a;
PConnector dst = b;
if (dst.isOutput())
{
src = b; // swap
dst = a;
}
int color = src.getSignalType().getId();
// set data
msg.newCable
(
getVoiceAreaId(va),
color,
dst.getParentComponent().getComponentIndex(),
Format.getOutputID(dst.isOutput()),
Helper.index(dst),
src.getParentComponent().getComponentIndex(),
Format.getOutputID(src.isOutput()),
Helper.index(src)
);
return msg;
}
public static MidiMessage createMoveModuleMessage( PModule module, int slotId, int pId )
{
// get message instance
MoveModuleMessage msg = new MoveModuleMessage();
msg.setSlot(slotId);
msg.setPid(pId);
// set data
msg.moveModule
(
getVoiceAreaId(module),
module.getComponentIndex(),
module.getInternalX(),
module.getInternalY()
);
return msg;
}
public static MidiMessage createSelectParameterMessage( PParameter parameter, int slotId, int pId )
{
// get message instance
ParameterSelectMessage msg = new ParameterSelectMessage();
// get data
PModule module = parameter.getParentComponent();
// set data
msg.select(slotId, pId,
getVoiceAreaId(module),
module.getComponentIndex(), Helper.index(parameter));
return msg;
}
public static MidiMessage createParameterChangedMessage( PParameter parameter, int slotId, int pId )
{
// get message instance
ParameterMessage msg = new ParameterMessage();
msg.setSlot(slotId);
msg.setPid(pId);
// get data
PModule module = parameter.getParentComponent();
// set data
msg.parameterChanged(
getVoiceAreaId(module),
module.getComponentIndex(),
Helper.index(parameter),
parameter.getValue());
return msg;
}
public static MidiMessage createMorphRangeChangeMessage( PParameter parameter, int slotId, int pId )
{
// get message instance
MorphRangeChangeMessage msg = new MorphRangeChangeMessage();
// get data
PModule module = parameter.getParentComponent();
// set data
msg.setMorphRange(slotId, pId,
getVoiceAreaId(module),
module.getComponentIndex(),
Helper.index(parameter),
Math.abs(parameter.getValue()),
parameter.getValue()<0?0:1);
return msg;
}
public static MidiMessage createSetModuleTitleMessage(PModule module, String title, int slot, int pid)
{
SetModuleTitleMessage msg = new SetModuleTitleMessage();
msg.setTitle(slot, pid, getVoiceAreaId(module), module.getComponentIndex(), title);
return msg;
}
public static int getVoiceAreaId(VoiceArea voiceArea)
{
return Format.getVoiceAreaID(voiceArea.isPolyVoiceArea());
}
public static int getVoiceAreaId(PModule module)
{
return module.getParentComponent().getComponentIndex();
}
public static String[] getPatchNames(PatchListMessage msg)
{
Collection<PatchListEntry> entries = msg.getEntries();
String[] names = new String[entries.size()];
int index = 0;
for (PatchListEntry e : entries)
names[index++] = e.getName();
return names;
}
public static PatchMessage[] createPatchMessages(NMPatch patch, int slotId) throws MidiException
{
Patch2BitstreamBuilder builder = new Patch2BitstreamBuilder(patch);
return builder.createMessages(slotId);
}
public static Charset getPatchFileCharset()
{
return Charset.forName("ISO-8859-1");
}
public static PatchMessage[] createPatchSettingsMessages(NMPatch patch, int slotId) throws MidiException
{
Patch2BitstreamBuilder builder = new Patch2BitstreamBuilder(patch);
builder.setHeaderOnly(true);
// TODO PatchMessage not working yet, sectionsEnded must be != 1
return builder.createMessages(slotId);
}
public static NMPatch parsePatch(NM1ModuleDescriptions modules, InputStream source)
throws ParseException
{
PParser parser = new PParser(new ParserErrorHandler());
parser.setSource(source);
PatchBuilder builder = new PatchBuilder(parser, modules);
parser.setContentHandler(builder);
parser.parse();
NMPatch patch = builder.getPatch();
// todo enable history
return patch;
}
public static PatchBuilder parsePatchMessage(PatchMessage message, NM1ModuleDescriptions modules) throws ParseException
{
PatchBuilder patchBuilder = new PatchBuilder(new ParserErrorHandler(), modules);
patchBuilder.beginDocument();
parsePatchMessage(message, patchBuilder);
return patchBuilder;
}
public static void parsePatchMessage(PatchMessage message, PatchBuilder patchBuilder) throws ParseException
{
BitstreamPatchParser bsParser = new BitstreamPatchParser();
bsParser.transcode(message.getPatchStream(), patchBuilder);
}
public static boolean writePatchSavely(NMPatch patch, File file)
{
try
{
writePatch(patch, file);
return true;
}
catch (Exception e)
{
Log log = LogFactory.getLog(NmUtils.class);
if (log.isErrorEnabled())
log.error("could not write patch "+patch+" to file "+file, e);
return false;
}
}
public static void writePatch(NMPatch patch, File file)
throws IOException, ParseException
{
FileOutputStream out = new FileOutputStream(file);
try
{
writePatch(patch, out);
}
finally
{
out.flush();
out.close();
}
}
public static void writePatch(NMPatch patch, OutputStream out)
throws IOException, ParseException
{
Writer writer =
new BufferedWriter(new OutputStreamWriter(out, getPatchFileCharset()));
try
{
(new PatchExporter()).export(patch, new PatchFileWriter(writer));
}
finally
{
writer.flush();
writer.close();
}
}
/*
private String int2str(int[] array)
{
StringBuffer sb = new StringBuffer("{");
for (int i=0;i<array.length;i++)
{
sb.append(Integer.toString(array[i]));
if (i<array.length-1)
sb.append(',');
}
sb.append('}');
return sb.toString();
}*/
public static class ParserErrorHandler implements ErrorHandler
{
public void warning( ParseException e ) throws ParseException
{
// ignore
}
public void error( ParseException e ) throws ParseException
{
throw e;
}
public void fatal( ParseException e ) throws ParseException
{
throw e;
}
}
public static String getPatchNameFromfileName(File file)
{
return getPatchNameFromfileName(file.getName());
}
public static String getPatchNameFromfileName(String fileName)
{
String s = fileName;
int pos = s.lastIndexOf(File.separatorChar);
if (pos >= 0)
s = s.substring(pos+1);
pos = s.lastIndexOf('.');
if (pos>=0 && s.toLowerCase().endsWith(".pch"))
s = s.substring(0, pos);
return s;
}
}