Java tutorial
//////////////////////////////////////////////////////////////////////////////// // Copyright 2013 Michael Schmalle - Teoti Graphix, LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License // // Author: Michael Schmalle, Principal Architect // mschmalle at teotigraphix dot com //////////////////////////////////////////////////////////////////////////////// package com.teotigraphix.caustk.library; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.UUID; import org.androidtransfuse.event.EventObserver; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.IOFileFilter; import com.teotigraphix.caustic.core.CausticException; import com.teotigraphix.caustic.core.XMLMemento; import com.teotigraphix.caustic.desktop.RuntimeUtils; import com.teotigraphix.caustk.controller.ICaustkController; import com.teotigraphix.caustk.core.components.SynthComponent; import com.teotigraphix.caustk.library.vo.EffectRackInfo; import com.teotigraphix.caustk.library.vo.MetadataInfo; import com.teotigraphix.caustk.library.vo.MixerPanelInfo; import com.teotigraphix.caustk.library.vo.RackInfo; import com.teotigraphix.caustk.project.IProjectManager; import com.teotigraphix.caustk.project.IProjectManager.OnProjectManagerChange; import com.teotigraphix.caustk.project.IProjectManager.ProjectManagerChangeKind; import com.teotigraphix.caustk.tone.Tone; public class LibraryManager implements ILibraryManager { //-------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------- private LibraryRegistry registry; private ICaustkController controller; private File librariesDirectory; private Library selectedLibrary; //-------------------------------------------------------------------------- // API //-------------------------------------------------------------------------- //---------------------------------- // selectedLibrary //---------------------------------- @Override public Library getSelectedLibrary() { return selectedLibrary; } @Override public void setSelectedLibrary(Library value) { if (value == selectedLibrary) return; selectedLibrary = value; controller.getDispatcher().trigger(new OnLibraryManagerSelectedLibraryChange(selectedLibrary)); } //---------------------------------- // librariesDirectory //---------------------------------- @Override public File getLibrariesDirectory() { return librariesDirectory; } //---------------------------------- // libraries //---------------------------------- @Override public int getLibraryCount() { return registry.getLibraries().size(); } @Override public Collection<Library> getLibraries() { return registry.getLibraries(); } public LibraryManager(ICaustkController controller) { this.controller = controller; File root = controller.getConfiguration().getApplicationRoot(); if (!root.exists()) throw new RuntimeException("Application root not specified"); librariesDirectory = new File(root, "libraries"); if (!librariesDirectory.exists()) librariesDirectory.mkdirs(); registry = new LibraryRegistry(librariesDirectory); controller.getDispatcher().register(OnProjectManagerChange.class, new EventObserver<OnProjectManagerChange>() { @Override public void trigger(OnProjectManagerChange object) { if (object.getKind() == ProjectManagerChangeKind.CREATE) { //onProjectManagerCreateHandler(); } else if (object.getKind() == ProjectManagerChangeKind.LOAD) { onProjectManagerLoadHandler(); } else if (object.getKind() == ProjectManagerChangeKind.SAVE) { onProjectManagerSaveHandler(); } else if (object.getKind() == ProjectManagerChangeKind.EXIT) { onProjectManagerExitHandler(); } } }); } protected void onProjectManagerSaveHandler() { saveSessionProperties(); } protected void onProjectManagerLoadHandler() { load(); String id = controller.getProjectManager().getSessionPreferences().getString("selectedLibrary"); if (id != null) { selectedLibrary = registry.getLibrary(id); } } private void saveSessionProperties() { // if the project has selected a library, save it if (selectedLibrary != null) { controller.getProjectManager().getSessionPreferences().put("selectedLibrary", selectedLibrary.getId()); } } protected void onProjectManagerExitHandler() { registry = new LibraryRegistry(librariesDirectory); selectedLibrary = null; } @Override public Library getLibraryById(UUID id) { return registry.getLibrary(id); } @Override public Library getLibraryByName(String name) { for (Library library : registry.getLibraries()) { if (library.getName().equals(name)) return library; } return null; } public List<LibraryPatch> findPatchesByTag(String tag) { List<LibraryPatch> result = new ArrayList<LibraryPatch>(); for (Library library : registry.getLibraries()) { for (LibraryPatch item : library.getPatches()) { if (item.hasTag(tag)) { result.add(item); } } } return result; } public List<LibraryPhrase> findPhrasesByTag(String tag) { List<LibraryPhrase> result = new ArrayList<LibraryPhrase>(); for (Library library : registry.getLibraries()) { for (LibraryPhrase item : library.getPhrases()) { if (item.hasTag(tag)) { result.add(item); } } } return result; } public List<LibraryScene> findScenesByTag(String tag) { List<LibraryScene> result = new ArrayList<LibraryScene>(); for (Library library : registry.getLibraries()) { for (LibraryScene item : library.getScenes()) { if (item.hasTag(tag)) { result.add(item); } } } return result; } /** * Saves the {@link Library}s to disk using the libraries directory * location. * <p> * Note: This DOES NOT get called from the {@link IProjectManager#save()} * method. The client needs to save a library by calling {@link #save()}. * * @throws IOException */ @Override public void save() throws IOException { for (Library library : registry.getLibraries()) { saveLibrary(library); } } /** * Loads the entire <code>libraries</code> directory into the manager. * <p> * Each sub directory located within the <code>libraries</code> directory * will be created as a {@link Library} instance. */ @Override public void load() { Collection<File> dirs = FileUtils.listFilesAndDirs(librariesDirectory, new IOFileFilter() { @Override public boolean accept(File arg0, String arg1) { return false; } @Override public boolean accept(File arg0) { return false; } }, new IOFileFilter() { @Override public boolean accept(File file, String name) { if (file.getParentFile().getName().equals("libraries")) return true; return false; } @Override public boolean accept(File file) { if (file.getParentFile().getName().equals("libraries")) return true; return false; } }); for (File directory : dirs) { if (directory.equals(librariesDirectory)) continue; loadLibrary(directory.getName()); } } @Override public void importSong(Library library, File causticFile) throws IOException { // //---------------------------------------------------------------------- // // clear the core rack // RackMessage.BLANKRACK.send(controller); // // Rack rack = new Rack(controller.getFactory(), true); // rack.setEngine(controller); // // // load the file into the rack. // try { // rack.loadSong(causticFile.getAbsolutePath()); // } catch (CausticException e) { // e.printStackTrace(); // throw new IOException(e); // } // // // restore the rack // //rack.restore(); // rack.getOutputPanel().restore(); // rack.getMixerPanel().restore(); // rack.getEffectsRack().restore(); // // //loadLibraryPatches(library, rack); // loadLibraryScene(library, causticFile, rack); // loadLibraryPhrases(library, rack); // // // clear the core rack // RackMessage.BLANKRACK.send(controller); } private LibraryScene createDefaultScene() throws CausticException { // RackMessage.BLANKRACK.send(controller); // // Rack rack = new Rack(controller.getFactory(), true); // rack.setEngine(controller); // // // create the default setup // rack.addMachine("SubSynth", MachineType.SUBSYNTH); // rack.addMachine("PCMSynth1", MachineType.PCMSYNTH); // rack.addMachine("PCMSynth2", MachineType.PCMSYNTH); // rack.addMachine("Bassline1", MachineType.BASSLINE); // rack.addMachine("Bassline2", MachineType.BASSLINE); // rack.addMachine("Beatbox", MachineType.BEATBOX); // // //rack.populateMachines(); // rack.getOutputPanel().restore(); // rack.getMixerPanel().restore(); // rack.getEffectsRack().restore(); // // LibraryScene libraryScene = new LibraryScene(); // libraryScene.setId(UUID.randomUUID()); // MetadataInfo metadataInfo = new MetadataInfo(); // metadataInfo.addTag("DefaultScene"); // libraryScene.setMetadataInfo(metadataInfo); // libraryScene.setRackInfo(LibrarySerializerUtils.createRackInfo(rack)); // libraryScene.setMixerInfo(LibrarySerializerUtils.createMixerPanelInfo(controller // .getSoundMixer().getMixerPanel())); // libraryScene.setEffectRackInfo(LibrarySerializerUtils.createEffectRackInfo(controller // .getSoundMixer().getEffectsRack())); // // RackMessage.BLANKRACK.send(controller); // return libraryScene; return null; } @Override public Library createLibrary(String name) throws IOException { File newDirectory = new File(librariesDirectory, name); //if (newDirectory.exists()) // throw new CausticException("Library already exists " + newDirectory.getAbsolutePath()); newDirectory.mkdir(); // create a default scene for every new Library LibraryScene defaultScene = null; try { defaultScene = createDefaultScene(); } catch (CausticException e) { e.printStackTrace(); } Library library = new Library(); library.setId(UUID.randomUUID()); library.setDirectory(newDirectory); library.mkdirs(); registry.addLibrary(library); library.addScene(defaultScene); return library; } @Override public LibraryScene createLibraryScene(MetadataInfo info) { LibraryScene scene = new LibraryScene(); scene.setMetadataInfo(info); scene.setId(null); //-------------------------------------- RackInfo rackInfo = new RackInfo(); XMLMemento memento = XMLMemento.createWriteRoot("rack"); for (int i = 0; i < 6; i++) { Tone tone = controller.getSoundSource().getTone(i); if (tone != null) { // IMemento child = memento.createChild("machine"); // child.putInteger("index", i); // //child.putInteger("active", machine != null ? 1 : 0); // child.putString("id", tone.getId()); // child.putString("type", tone.getType().getValue()); } } rackInfo.setData(memento.toString()); scene.setRackInfo(rackInfo); MixerPanelInfo mixerPanelInfo = LibrarySerializerUtils .createMixerPanelInfo(controller.getSoundMixer().getMixerPanel()); scene.setMixerInfo(mixerPanelInfo); EffectRackInfo effectRackInfo = LibrarySerializerUtils .createEffectRackInfo(controller.getSoundMixer().getEffectsRack()); scene.setEffectRackInfo(effectRackInfo); //TagUtils.addDefaultTags(name, rack, scene); return scene; } // private void loadLibraryScene(Library library, File causticFile, Rack rack) throws IOException { // String name = causticFile.getName().replace(".caustic", ""); // LibraryScene scene = new LibraryScene(); // scene.setMetadataInfo(new MetadataInfo()); // // scene.setId(UUID.randomUUID()); // library.addScene(scene); // // //-------------------------------------- // RackInfo rackInfo = new RackInfo(); // XMLMemento memento = XMLMemento.createWriteRoot("rack"); // for (int i = 0; i < 6; i++) { // IMachine machine = rack.getMachine(i); // LibraryPatch patch = null; // // if (machine != null) { // patch = new LibraryPatch(); // patch.setMachineType(machine.getType()); // patch.setMetadataInfo(new MetadataInfo()); // patch.setId(UUID.randomUUID()); // TagUtils.addDefaultTags(machine, patch); // relocatePresetFile(machine, library, patch); // library.addPatch(patch); // // IMemento child = memento.createChild("machine"); // child.putInteger("index", i); // child.putInteger("active", machine != null ? 1 : 0); // // if (patch != null) // child.putString("patchId", patch.getId().toString()); // // child.putString("id", machine.getId()); // child.putString("type", machine.getType().getValue()); // } // } // // rackInfo.setData(memento.toString()); // // scene.setRackInfo(rackInfo); // // MixerPanelInfo mixerPanelInfo = LibrarySerializerUtils.createMixerPanelInfo(rack); // scene.setMixerInfo(mixerPanelInfo); // // EffectRackInfo effectRackInfo = LibrarySerializerUtils.createEffectRackInfo(rack); // scene.setEffectRackInfo(effectRackInfo); // // TagUtils.addDefaultTags(name, rack, scene); // } // private void loadLibraryPhrases(Library library, Rack rack) { // for (int i = 0; i < 6; i++) { // IMachine machine = rack.getMachine(i); // if (machine != null) { // // String result = PatternSequencerMessage.QUERY_PATTERNS_WITH_DATA.queryString( // controller, i); // // if (result == null) // continue; // // for (String patternName : result.split(" ")) { // int bankIndex = PatternUtils.toBank(patternName); // int patternIndex = PatternUtils.toPattern(patternName); // // // set the current bank and pattern of the machine to query // // the string pattern data // PatternSequencerMessage.BANK.send(controller, i, bankIndex); // PatternSequencerMessage.PATTERN.send(controller, i, patternIndex); // // //---------------------------------------------------------------- // // Load Pattern // //---------------------------------------------------------------- // // // load one phrase per pattern; load ALL patterns // // as caustic machine patterns // int length = (int)PatternSequencerMessage.NUM_MEASURES.query(controller, i); // float tempo = OutputPanelMessage.BPM.query(controller); // String noteData = PatternSequencerMessage.QUERY_NOTE_DATA.queryString( // controller, i); // // LibraryPhrase phrase = new LibraryPhrase(); // phrase.setMetadataInfo(new MetadataInfo()); // phrase.setId(UUID.randomUUID()); // phrase.setLength(length); // phrase.setTempo(tempo); // phrase.setMachineType(machine.getType()); // phrase.setNoteData(noteData); // phrase.setResolution(calculateResolution(noteData)); // TagUtils.addDefaultTags(phrase); // library.addPhrase(phrase); // } // } // } // } private Resolution calculateResolution(String data) { // TODO This is totally inefficient, needs to be lazy loaded // push the notes into the machines sequencer float smallestGate = 1f; String[] notes = data.split("\\|"); for (String noteData : notes) { String[] split = noteData.split(" "); float start = Float.parseFloat(split[0]); float end = Float.parseFloat(split[3]); float gate = end - start; smallestGate = Math.min(smallestGate, gate); } Resolution result = Resolution.SIXTEENTH; if (smallestGate <= Resolution.SIXTYFOURTH.getValue() * 4) result = Resolution.SIXTYFOURTH; else if (smallestGate <= Resolution.THIRTYSECOND.getValue() * 4) result = Resolution.THIRTYSECOND; else if (smallestGate <= Resolution.SIXTEENTH.getValue() * 4) result = Resolution.SIXTEENTH; return result; } protected void relocatePresetFile(Tone tone, Library library, LibraryPatch patch) throws IOException { String id = patch.getId().toString(); tone.getComponent(SynthComponent.class).savePreset(id); File presetFile = RuntimeUtils.getCausticPresetsFile(tone.getToneType().getValue(), id); if (!presetFile.exists()) throw new IOException("Preset file does not exist"); File presetsDirectory = library.getPresetsDirectory(); File destFile = new File(presetsDirectory, presetFile.getName()); FileUtils.copyFile(presetFile, destFile); FileUtils.deleteQuietly(presetFile); } @Override public void saveLibrary(Library library) throws IOException { String data = controller.getSerializeService().toString(library); File file = new File(library.getDirectory(), "library.ctk"); FileUtils.writeStringToFile(file, data); } @Override public Library loadLibrary(String name) { File directory = new File(librariesDirectory, name); File file = new File(directory, "library.ctk"); Library library = controller.getSerializeService().fromFile(file, Library.class); registry.addLibrary(library); controller.getDispatcher().trigger(new OnLibraryManagerLoadComplete(library)); return library; } @Override public void clear() { registry = new LibraryRegistry(librariesDirectory); } @Override public void delete() throws IOException { for (Library library : registry.getLibraries()) { library.delete(); } clear(); } } /* <?xml version="1.0" encoding="UTF-8"?> <mixer> <master eq_bass="0.19565237" eq_high="0.100000024" eq_mid="0.0" id="-1" index="-1" volume="1.1478264"/> <channels> <channel delay_send="0.504348" eq_bass="-0.008696437" eq_high="0.06956482" eq_mid="1.1920929E-7" id="0" index="0" mute="0" pan="0.0" reverb_send="0.05869567" solo="0" stereo_width="0.99609375" volume="1.2782611"/> <channel delay_send="0.5000001" eq_bass="-1.0" eq_high="0.02666676" eq_mid="0.034783125" id="1" index="1" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.0" volume="1.3652176"/> <channel delay_send="0.0" eq_bass="1.0" eq_high="-0.008695722" eq_mid="0.0" id="2" index="2" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.0" volume="1.2782608"/> <channel delay_send="0.52173936" eq_bass="-1.0" eq_high="-2.9802322E-7" eq_mid="-0.026086628" id="3" index="3" mute="0" pan="0.18260896" reverb_send="0.07173912" solo="0" stereo_width="0.0" volume="1.4383385"/> <channel delay_send="0.0" eq_bass="-0.017391145" eq_high="0.38260782" eq_mid="0.0" id="4" index="4" mute="0" pan="0.0" reverb_send="0.07391316" solo="0" stereo_width="0.53269273" volume="1.3913045"/> <channel delay_send="0.0" eq_bass="1.0" eq_high="5.9604645E-7" eq_mid="-0.008694708" id="5" index="5" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.99609375" volume="0.99999934"/> </channels> <delay feedback="0.7565215" stereo="1" time="5"/> <reverb damping="0.0" room="0.9" stereo="1"/> </mixer> <?xml version="1.0" encoding="UTF-8"?> <rack> <machine active="1" id="LOWLEAD" index="0" type="subsynth"/> <machine active="1" id="HIGHLEAD" index="1" type="subsynth"/> <machine active="1" id="BASS" index="2" type="subsynth"/> <machine active="1" id="MELODY" index="3" type="bassline"/> <machine active="1" id="STRINGS" index="4" type="pcmsynth"/> <machine active="1" id="DRUMSIES" index="5" type="beatbox"/> </rack> <?xml version="1.0" encoding="UTF-8"?> <effects> <channel id="LOWLEAD" index="0"> <effect channel="0" depth="0.95" feedback="0.25" rate="0.43333432" type="5" wet="1.0"/> </channel> <channel id="HIGHLEAD" index="1"/> <channel id="BASS" index="2"> <effect attack="0.011313666" channel="2" ratio="1.0" release="0.098769695" sidechain="5" threshold="0.19565232" type="3"/> </channel> <channel id="MELODY" index="3"> <effect channel="3" depth="1" jitter="1.0" rate="0.31891286" type="4" wet="1.0"/> <effect attack="0.005227146" channel="3" ratio="0.7956521" release="0.105373904" sidechain="5" threshold="0.58260775" type="3"/> </channel> <channel id="STRINGS" index="4"> <effect channel="4" depth="0.95" feedback="0.25" rate="0.05869563" type="5" wet="1.0"/> <effect attack="0.066963136" channel="4" ratio="1.0" release="0.03214792" sidechain="5" threshold="0.0" type="3"/> </channel> <channel id="DRUMSIES" index="5"/> </effects> */