/* 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 */ package net.sf.nmedit.nordmodular; import java.awt.Component; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.sound.midi.MidiDevice; import net.sf.nmedit.jpatch.clavia.nordmodular.NMData; import net.sf.nmedit.jpatch.clavia.nordmodular.NMPatch; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PatchExporter; import net.sf.nmedit.jpatch.clavia.nordmodular.parser.PatchFileWriter; import net.sf.nmedit.jsynth.clavia.nordmodular.NordModular; import net.sf.nmedit.jsynth.midi.MidiDescription; import net.sf.nmedit.jsynth.midi.MidiID; import net.sf.nmedit.jsynth.midi.MidiPlug; import net.sf.nmedit.jtheme.ModulePane; import net.sf.nmedit.nmutils.io.FileUtils; import net.sf.nmedit.nomad.core.JPFUtil; import net.sf.nmedit.nomad.core.Nomad; import net.sf.nmedit.nomad.core.jpf.TempDir; import net.sf.nmedit.nomad.core.menulayout.MLEntry; import net.sf.nmedit.nomad.core.service.Service; import net.sf.nmedit.nomad.core.service.initService.InitService; import net.sf.nmedit.nomad.core.swing.ExtensionFilter; import net.sf.nmedit.nomad.core.swing.document.DefaultDocumentManager; import net.sf.nmedit.nomad.core.swing.document.Document; import net.sf.nmedit.nomad.core.swing.explorer.ExplorerTree; import net.sf.nmedit.nomad.core.swing.explorer.FileContext; import net.sf.nmedit.nomad.core.swing.tabs.JTabbedPane2; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Installer implements InitService { // TempDir temp = new TempDir(this); public Class<? extends Service> getServiceClass() { return InitService.class; } public void init() { installPatches(); readSynthConfiguration(); NMContextData data = NMContextData.sharedInstance(); NMData d = NMData.sharedInstance(); ModulePane pane = ModulePane.getSharedInstance(); pane.setModules(d.getModuleDescriptions()); pane.setTheme(data.getJTContext()); Nomad nomad = Nomad.sharedInstance(); MLEntry mlKnobs = nomad.getMenuLayout().getEntry("nomad.menu.patch.knobs"); DefaultDocumentManager dm = Nomad.sharedInstance().getDocumentManager(); KnobController kc = new KnobController(); dm.addListener(kc); mlKnobs.addActionListener(kc); loadLastSession(); } public void shutdown() { saveCurrentSession(); List<NordModular> synthList = new ArrayList<NordModular>(); JTabbedPane2 tb = Nomad.sharedInstance().getSynthTabbedPane(); for (int i=0;i<tb.getTabCount();i++) { Component c = tb.getComponentAt(i); if (c instanceof NMSynthDeviceContext) { synthList.add(((NMSynthDeviceContext)c).getSynthesizer()); } } storeSynthConfiguration(synthList); } public void installPatches() { File pluginDir = JPFUtil.getPluginDirectory(this); File patches = new File(pluginDir, "patches/"); TempDir tempDir = TempDir.generalTempDir(); File userPatches = tempDir.getTempFile("patches"); if (!userPatches.exists()) FileUtils.copy(patches, userPatches); if (userPatches.exists()) { ExplorerTree explorerTree = Nomad.sharedInstance().getExplorer(); FileContext libraryContext = new FileContext(explorerTree, new ExtensionFilter("Nord Modular Patch", "pch", true), userPatches); libraryContext.setName("Library"); libraryContext.setNailed(true); explorerTree.addRootNode(libraryContext, 0); } } private File getSessionFile(TempDir dir) { return dir.getTempFile("session.properties"); } private void loadLastSession() { TempDir tmpDir = TempDir.forObject(this); File sessionFile = getSessionFile(tmpDir); if (!sessionFile.exists()) return; Properties props = new Properties(); InputStream in; try { in = new BufferedInputStream(new FileInputStream(sessionFile)); try { props.load(in); } finally { in.close(); } } catch (Exception e) { Log log = LogFactory.getLog(getClass()); if (log.isDebugEnabled()) { log.debug("exception while loading session file", e); } e.printStackTrace(); // ignore // delete corrupt session file sessionFile.delete(); return ; } loadSessionFromProperties(tmpDir, props); } private static final String SESSION_PATCHCOUNT = "session.patchcount"; private void loadSessionFromProperties(TempDir tmpDir, Properties props) { String PCountString = props.getProperty(SESSION_PATCHCOUNT); if (PCountString == null) return; int patchcount; try { patchcount = Integer.parseInt(PCountString); } catch (NumberFormatException e) { Log log = LogFactory.getLog(getClass()); if (log.isDebugEnabled()) { log.debug("exception while loading session file", e); } return ; } for (int i=0;i<patchcount;i++) { File sourceFile = null; String keySourceFile = getSourceFileKey(i); String sourceFileString = props.getProperty(keySourceFile); if (sourceFileString != null) sourceFile = new File(sourceFileString); File tmpFile = getPatchTmpFile(tmpDir, i); String title = props.getProperty(getTitleKey(i)); NMPatch patch = tryOpenSessionPatch(tmpFile, sourceFile, title); } } private String getTitleKey(int index) { return "patch."+index+".title"; } private String getSourceFileKey(int index) { return "patch."+index+".sourcefile"; } private File getPatchTmpFile(TempDir tmpDir, int index) { return tmpDir.getTempFile("temp_"+index+".pch"); } private NMPatch tryOpenSessionPatch(File file, File sourceFile, String title) { if (!file.exists()) return null; return NmFileService.openPatch(file, sourceFile, title, false); } private void saveCurrentSession() { DefaultDocumentManager dm = Nomad.sharedInstance().getDocumentManager(); List<NMPatch> patches = new ArrayList<NMPatch>(); for (Document doc : dm.getDocuments()) { if (doc instanceof PatchDocument) { patches.add(((PatchDocument)doc).getPatch()); } } TempDir tmpDir = TempDir.forObject(this); Properties props = new Properties(); int pcount = 0; for (NMPatch patch: patches) { File saveAs = getPatchTmpFile(tmpDir, pcount); try { OutputStream out = new BufferedOutputStream(new FileOutputStream(saveAs)); PatchFileWriter pfw = new PatchFileWriter(out); PatchExporter export = new PatchExporter(); export.export(patch, pfw); out.flush(); out.close(); } catch (Exception e) { Log log = LogFactory.getLog(getClass()); if (log.isDebugEnabled()) { log.debug("exception while storing session file", e); } e.printStackTrace(); continue; } // tmp file written File sourceFile = patch.getFile(); if (sourceFile != null) props.put(getSourceFileKey(pcount), sourceFile.getAbsolutePath()); else { // source file unknown, since patch file contains no title we have to remember it String name = patch.getName(); if (name != null) props.put(getTitleKey(pcount), name); } pcount++; } props.put(SESSION_PATCHCOUNT, String.valueOf(pcount)); File sessionFile = getSessionFile(tmpDir); try { OutputStream out = new BufferedOutputStream(new FileOutputStream(sessionFile)); props.store(out, "generated file - do not edit manually"); out.close(); } catch (Exception e) { Log log = LogFactory.getLog(getClass()); if (log.isDebugEnabled()) { log.debug("exception while storing session file", e); } e.printStackTrace(); // ignore } } private void readSynthConfiguration() { Properties properties = new Properties(); InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(getSynthPropertyFile())); properties.load(in); } catch (IOException e) { // ignore } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } } readSynthConfiguration(properties); } private void readSynthConfiguration(Properties properties) { int count = str2int(properties.getProperty("nordmodular.count"), 0); if (count>100) { count = 10; // just in case the number messed up } if (count <= 0) return ; for (int i=0;i<count;i++) { String prefix = "nordmodular."+i+"."; String name = properties.getProperty(prefix+"name"); MidiDescription in = readMidiInfo(properties, prefix+"midi.in.", true); MidiDescription out = readMidiInfo(properties, prefix+"midi.out.", false); MidiPlug pin = in == null ? null : new MidiPlug(in); MidiPlug pout = out == null ? null : new MidiPlug(out); NewNordModularService.newSynth(name, pin, pout); } } private MidiDescription readMidiInfo(Properties properties, String prefix, boolean input) { int id = str2int(properties.getProperty(prefix+"id"), -1); String name = properties.getProperty(prefix+"name"); String vendor = properties.getProperty(prefix+"vendor"); String version = properties.getProperty(prefix+"version"); String description = properties.getProperty(prefix+"description"); int isInput = str2boolean(properties.getProperty(prefix+"input")); if (isInput < 0 || ((isInput==1)!=input) ) return null; return new MidiDescription(name, vendor, version, description, isInput, id); } private int str2boolean(String value) { try { return Boolean.parseBoolean(value) ? 1 : 0; } catch (NumberFormatException e) { return -1; } } private int str2int(String value, int alt) { if (value == null) return alt; try { return Integer.parseInt(value.trim()); } catch (NumberFormatException e) { return alt; } } private void storeSynthConfiguration(List<NordModular> synthList) { MidiID midiID = new MidiID(); Properties properties = new Properties(); properties.put("nordmodular.count", Integer.toString(synthList.size())); for (int i=0;i<synthList.size();i++) { String prefix = "nordmodular."+i+"."; NordModular synth = synthList.get(i); properties.put(prefix+"name", synth.getName()); putMidiInfo(properties, prefix+"midi.in.", synth.getPCInPort().getPlug(), midiID, true); putMidiInfo(properties, prefix+"midi.out.", synth.getPCOutPort().getPlug(), midiID, false); } OutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(getSynthPropertyFile())); properties.store(out, "generated file, do not edit"); } catch (IOException e) { // ignore } finally { if (out != null) { try { out.close(); } catch (IOException e) { // ignore } } } } private void putMidiInfo(Properties properties, String prefix, MidiPlug plug, MidiID midiID, boolean input) { if (plug == null) return; MidiDevice.Info info = plug.getDeviceInfo(); if (info == null) return; properties.put(prefix+"id", Integer.toString(midiID.getID(info))); properties.put(prefix+"name", info.getName()); properties.put(prefix+"vendor", info.getVendor()); properties.put(prefix+"version", info.getVersion()); properties.put(prefix+"description", info.getDescription()); properties.put(prefix+"input", Boolean.toString(input)); } private File getSynthPropertyFile() { return TempDir.forObject(this).getTempFile("synth.properties"); } }