/**
* Copyright (C) 2011-2013 Michael Vogt <michu@neophob.com>
*
* This file is part of PixelController.
*
* PixelController 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 3 of the License, or
* (at your option) any later version.
*
* PixelController 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 PixelController. If not, see <http://www.gnu.org/licenses/>.
*/
package com.neophob.sematrix.core.glue;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.apache.commons.lang3.StringUtils;
import com.neophob.sematrix.core.color.ColorSet;
import com.neophob.sematrix.core.effect.Effect;
import com.neophob.sematrix.core.effect.Effect.EffectName;
import com.neophob.sematrix.core.effect.PixelControllerEffect;
import com.neophob.sematrix.core.fader.Fader.FaderName;
import com.neophob.sematrix.core.fader.IFader;
import com.neophob.sematrix.core.fader.PixelControllerFader;
import com.neophob.sematrix.core.generator.Generator;
import com.neophob.sematrix.core.generator.Generator.GeneratorName;
import com.neophob.sematrix.core.generator.PixelControllerGenerator;
import com.neophob.sematrix.core.glue.helper.InitHelper;
import com.neophob.sematrix.core.jmx.PixelControllerStatus;
import com.neophob.sematrix.core.jmx.TimeMeasureItemGlobal;
import com.neophob.sematrix.core.listener.MessageProcessor;
import com.neophob.sematrix.core.mixer.Mixer;
import com.neophob.sematrix.core.mixer.Mixer.MixerName;
import com.neophob.sematrix.core.mixer.PixelControllerMixer;
import com.neophob.sematrix.core.osc.PixelControllerOscServer;
import com.neophob.sematrix.core.output.IOutput;
import com.neophob.sematrix.core.output.PixelControllerOutput;
import com.neophob.sematrix.core.properties.ApplicationConfigurationHelper;
import com.neophob.sematrix.core.properties.ConfigConstant;
import com.neophob.sematrix.core.properties.ValidCommands;
import com.neophob.sematrix.core.resize.PixelControllerResize;
import com.neophob.sematrix.core.resize.Resize.ResizeName;
import com.neophob.sematrix.core.sound.ISound;
import com.neophob.sematrix.core.sound.SoundDummy;
import com.neophob.sematrix.core.sound.SoundMinim;
/**
* The Class Collector.
*/
public class Collector extends Observable {
private static final Logger LOG = Logger.getLogger(Collector.class.getName());
/** The Constant EMPTY_CHAR. */
private static final String EMPTY_CHAR = " ";
/** The Constant NR_OF_PRESENT_SLOTS. */
public static final int NR_OF_PRESET_SLOTS = 144;
/** The singleton instance. */
private static Collector instance = new Collector();
/** The random mode. */
private boolean randomMode = false;
/** The random mode. */
private boolean randomPresetMode = false;
/** The initialized. */
private boolean initialized;
/** The matrix. */
private MatrixData matrix;
/** all input elements. */
private List<Visual> allVisuals;
/** fx to screen mapping. */
private List<OutputMapping> ioMapping;
/** The nr of screens. */
private int nrOfScreens;
/** The fps. */
private int fps;
/** The current visual. */
private int currentVisual;
/** The current output. */
private int currentOutput;
/** present settings. */
private int selectedPreset;
/** The present. */
private List<PresetSettings> presets;
/** The pixel controller generator. */
private PixelControllerGenerator pixelControllerGenerator;
/** The pixel controller mixer. */
private PixelControllerMixer pixelControllerMixer;
/** The pixel controller effect. */
private PixelControllerEffect pixelControllerEffect;
/** The pixel controller resize. */
private PixelControllerResize pixelControllerResize;
/** The pixel controller output. */
private PixelControllerOutput pixelControllerOutput;
/** The pixel controller shuffler select. */
private PixelControllerShufflerSelect pixelControllerShufflerSelect;
private PixelControllerFader pixelControllerFader;
private PixelControllerOscServer oscServer;
private ApplicationConfigurationHelper ph;
/** The is loading present. */
private boolean isLoadingPresent=false;
private PixelControllerStatus pixConStat;
private List<ColorSet> colorSets;
/** The random mode. */
private boolean inPauseMode = false;
private boolean internalVisualsVisible = true;
private IOutput output;
private ISound sound;
private FileUtils fileUtils;
/**
* Instantiates a new collector.
*/
private Collector() {
allVisuals = new CopyOnWriteArrayList<Visual>();
this.nrOfScreens = 0;
ioMapping = new CopyOnWriteArrayList<OutputMapping>();
initialized=false;
selectedPreset=0;
presets = PresetSettings.initializePresetSettings(NR_OF_PRESET_SLOTS);
pixelControllerShufflerSelect = new PixelControllerShufflerSelect();
pixelControllerShufflerSelect.initAll();
}
/**
* initialize the collector.
*
* @param papplet the PApplet
* @param ph the PropertiesHelper
*/
public synchronized void init(FileUtils fileUtils, ApplicationConfigurationHelper ph) {
LOG.log(Level.INFO, "Initialize collector");
if (initialized) {
return;
}
this.fileUtils = fileUtils;
this.nrOfScreens = ph.getNrOfScreens();
this.ph = ph;
this.fps = ph.parseFps();
this.colorSets = InitHelper.getColorPalettes(fileUtils);
//choose sound implementation
if (ph.isAudioAware()) {
try {
sound = new SoundMinim(ph.getSoundSilenceThreshold());
} catch (Exception e) {
LOG.log(Level.WARNING, "FAILED TO INITIALIZE SOUND INSTANCE. Disable sound input.");
} catch (Error e) {
LOG.log(Level.WARNING, "FAILED TO INITIALIZE SOUND INSTANCE (Error). Disable sound input.", e);
}
}
if (sound==null) {
sound = new SoundDummy();
}
//create the device with specific size
this.matrix = new MatrixData(ph.getDeviceXResolution(), ph.getDeviceYResolution());
pixelControllerResize = new PixelControllerResize();
pixelControllerResize.initAll();
//create generators
pixelControllerGenerator = new PixelControllerGenerator(ph, fileUtils, matrix, this.fps,
sound, pixelControllerResize.getResize(ResizeName.PIXEL_RESIZE));
pixelControllerGenerator.initAll();
pixelControllerEffect = new PixelControllerEffect(matrix, sound);
pixelControllerEffect.initAll();
pixelControllerMixer = new PixelControllerMixer(matrix, sound);
pixelControllerMixer.initAll();
pixelControllerFader = new PixelControllerFader(ph, matrix, this.fps);
//create visuals
int additionalVisuals = 1+ph.getNrOfAdditionalVisuals();
LOG.log(Level.INFO, "Initialize "+(nrOfScreens+additionalVisuals)+" Visuals");
try {
Generator genPassThru = pixelControllerGenerator.getGenerator(GeneratorName.PASSTHRU);
Effect effPassThru = pixelControllerEffect.getEffect(EffectName.PASSTHRU);
Mixer mixPassThru = pixelControllerMixer.getMixer(MixerName.PASSTHRU);
for (int i=1; i<nrOfScreens+additionalVisuals+1; i++) {
Generator g = pixelControllerGenerator.getGenerator(
GeneratorName.values()[ i%(GeneratorName.values().length) ]
);
if (g==null) {
//its possible we select an inactive generator, in this case just ignore it...
additionalVisuals++;
LOG.log(Level.INFO, "Ignore null Visual, take next...");
} else {
allVisuals.add(new Visual(g, genPassThru, effPassThru, effPassThru, mixPassThru, colorSets.get(0)));
}
}
} catch (IndexOutOfBoundsException e) {
LOG.log(Level.SEVERE, "Failed to initialize Visual, maybe missing palette files?\n");
throw new IllegalArgumentException("Failed to initialize Visuals, maybe missing palette files?");
}
LOG.log(Level.INFO, "Initialize output");
pixelControllerOutput = new PixelControllerOutput();
pixelControllerOutput.initAll();
this.presets = fileUtils.loadPresents(NR_OF_PRESET_SLOTS);
//create an empty mapping
ioMapping.clear();
for (int n=0; n<nrOfScreens; n++) {
ioMapping.add(new OutputMapping(pixelControllerFader.getVisualFader(FaderName.SWITCH), n));
}
pixConStat = new PixelControllerStatus(this, fps);
initialized=true;
}
/**
* start tcp and osc server
*
* @param papplet
* @param ph
*/
public synchronized void initDaemons(ApplicationConfigurationHelper ph) {
//Start OSC Server (OSC Interface)
try {
int listeningOscPort = Integer.parseInt(ph.getProperty(ConfigConstant.NET_OSC_LISTENING_PORT, "9876") );
oscServer = new PixelControllerOscServer(listeningOscPort);
oscServer.startServer();
//register osc server in the statistic class
this.pixConStat.setOscServerStatistics(oscServer);
} catch (Exception e) {
LOG.log(Level.SEVERE, "failed to start OSC Server", e);
}
}
/**
* update the whole system:
* -generators
* -effects
* -outputs
*
* update the generators, if the sound is
* louder, update faster.
*/
public void updateSystem() {
//do not update system if presents are loading
if (isLoadingPresent()) {
return;
}
//update the current value of frames per second
/* if (papplet!=null) {
pixConStat.setCurrentFps(papplet.frameRate);
pixConStat.setFrameCount(papplet.frameCount);
}*/
long l = System.currentTimeMillis();
//update generator depending on the input sound
pixelControllerGenerator.update();
pixConStat.trackTime(TimeMeasureItemGlobal.GENERATOR, System.currentTimeMillis()-l);
l = System.currentTimeMillis();
pixelControllerEffect.update();
pixConStat.trackTime(TimeMeasureItemGlobal.EFFECT, System.currentTimeMillis()-l);
l = System.currentTimeMillis();
pixelControllerOutput.update();
pixConStat.trackTime(TimeMeasureItemGlobal.OUTPUT_SCHEDULE, System.currentTimeMillis()-l);
//cleanup faders
l = System.currentTimeMillis();
for (OutputMapping om: ioMapping) {
IFader fader = om.getFader();
if (fader!=null && fader.isStarted() && fader.isDone()) {
//fading is finished, cleanup
fader.cleanUp();
if (fader.getScreenOutput()>=0) {
mapInputToScreen(fader.getScreenOutput(), fader.getNewVisual());
LOG.log(Level.INFO, "Cleanup {0}, new visual: {1}, output screen: {2}",
new Object[] { fader.getFaderName(), fader.getNewVisual(), fader.getScreenOutput() });
} else {
LOG.log(Level.INFO, "Cleanup preset {0}, new visual: {1}",
new Object[] { fader.getFaderName(), fader.getNewVisual() });
}
}
}
pixConStat.trackTime(TimeMeasureItemGlobal.FADER, System.currentTimeMillis()-l);
if (randomMode) {
Shuffler.shuffleStuff(sound);
} else if (randomPresetMode) {
Shuffler.randomPresentModeShuffler(sound);
}
}
/**
* Gets the single instance of Collector.
*
* @return single instance of Collector
*/
public static Collector getInstance() {
return instance;
}
/**
* Gets the nr of screens.
*
* @return the nr of screens
*/
public int getNrOfScreens() {
return nrOfScreens;
}
private void saveImage(Visual v, String filename, int[] data) {
try {
int w = v.getGenerator1().getInternalBufferXSize();
int h = v.getGenerator1().getInternalBufferYSize();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
bi.setRGB(0, 0, w, h, data, 0, w);
File outputfile = new File(filename);
ImageIO.write(bi, "png", outputfile);
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to save screenshot "+filename, e);
}
}
/**
* create screenshot
*/
public void saveScreenshot() {
int ofs=0;
int frames = pixelControllerGenerator.getFrames();
String suffix = ".png";
File f = new File("screenshot"+File.separator);
if (!f.exists()) {
LOG.log(Level.INFO, "Create directory "+f.getAbsolutePath());
boolean result = f.mkdir();
LOG.log(Level.INFO, "Result: "+result);
}
for (Visual v: allVisuals) {
String prefix = "screenshot"+File.separator+frames+"-"+ofs+"-";
ColorSet cs = v.getColorSet();
saveImage(v, prefix+"gen1"+suffix, cs.convertToColorSetImage(v.getGenerator1().internalBuffer));
saveImage(v, prefix+"gen2"+suffix, cs.convertToColorSetImage(v.getGenerator2().internalBuffer));
saveImage(v, prefix+"fx1"+suffix, cs.convertToColorSetImage(v.getEffect1Buffer()));
saveImage(v, prefix+"fx2"+suffix, cs.convertToColorSetImage(v.getEffect2Buffer()));
saveImage(v, prefix+"mix"+suffix, v.getMixerBuffer());
ofs++;
}
}
/**
* which fx for screenOutput?.
*
* @param screenOutput the screen output
* @return fx nr.
*/
public int getFxInputForScreen(int screenOutput) {
return ioMapping.get(screenOutput).getVisualId();
}
/**
* define which fx is shown on which screen, without fading.
*
* @param screenOutput which screen nr
* @param visualInput which visual
*/
public void mapInputToScreen(int screenOutput, int visualInput) {
OutputMapping o = ioMapping.get(screenOutput);
o.setVisualId(visualInput);
ioMapping.set(screenOutput, o);
}
/**
* get all screens with a specific visual
* used for crossfading.
*
* @param oldVisual the old visual
* @return the all screens with visual
*/
public List<Integer> getAllScreensWithVisual(int oldVisual) {
List<Integer> ret = new ArrayList<Integer>();
int ofs=0;
for (OutputMapping o: ioMapping) {
if (o.getVisualId()==oldVisual) {
ret.add(ofs);
}
ofs++;
}
return ret;
}
/**
* Gets the fps.
*
* @return the fps
*/
public int getFps() {
return fps;
}
/**
* Checks if is random mode.
*
* @return true, if is random mode
*/
public boolean isRandomMode() {
return randomMode;
}
/**
* Sets the random mode.
*
* @param randomMode the new random mode
*/
public void setRandomMode(boolean randomMode) {
this.randomMode = randomMode;
}
public boolean isRandomPresetMode() {
return randomPresetMode;
}
public void setRandomPresetMode(boolean randomPresetMode) {
this.randomPresetMode = randomPresetMode;
}
public void savePresets() {
fileUtils.savePresents(presets);
}
/**
* load a saved preset.
*
* @param preset the new current status
*/
public void setCurrentStatus(List<String> preset) {
LOG.log(Level.FINEST, "--------------");
long start=System.currentTimeMillis();
setLoadingPresent(true);
for (String s: preset) {
s = StringUtils.trim(s);
s = StringUtils.removeEnd(s, ";");
LOG.log(Level.FINEST, "LOAD PRESET: "+s);
MessageProcessor.processMsg(StringUtils.split(s, ' '), false, null);
}
setLoadingPresent(false);
long needed=System.currentTimeMillis()-start;
LOG.log(Level.INFO, "Preset loaded in "+needed+"ms");
}
/**
* get current state of visuals/outputs
* as string list - used to save current settings.
*
* @return the current status
*/
public List<String> getCurrentStatus() {
List<String> ret = new ArrayList<String>();
//get visual status
int n=0;
for (Visual v: allVisuals) {
ret.add(ValidCommands.CURRENT_VISUAL +EMPTY_CHAR+n++);
ret.add(ValidCommands.CHANGE_GENERATOR_A+EMPTY_CHAR+v.getGenerator1Idx());
ret.add(ValidCommands.CHANGE_GENERATOR_B+EMPTY_CHAR+v.getGenerator2Idx());
ret.add(ValidCommands.CHANGE_EFFECT_A+EMPTY_CHAR+v.getEffect1Idx());
ret.add(ValidCommands.CHANGE_EFFECT_B+EMPTY_CHAR+v.getEffect2Idx());
ret.add(ValidCommands.CHANGE_MIXER+EMPTY_CHAR+v.getMixerIdx());
ret.add(ValidCommands.CURRENT_COLORSET+EMPTY_CHAR+v.getColorSet().getName());
}
//get output status
int ofs=0;
for (OutputMapping om: ioMapping) {
ret.add(ValidCommands.CURRENT_OUTPUT +EMPTY_CHAR+ofs);
ret.add(ValidCommands.CHANGE_OUTPUT_FADER+EMPTY_CHAR+om.getFader().getId());
ret.add(ValidCommands.CHANGE_OUTPUT_VISUAL+EMPTY_CHAR+om.getVisualId());
ofs++;
}
//add element status
ret.addAll(pixelControllerEffect.getCurrentState());
ret.addAll(pixelControllerGenerator.getCurrentState());
ret.addAll(pixelControllerShufflerSelect.getCurrentState());
ret.add(ValidCommands.CHANGE_PRESET +EMPTY_CHAR+selectedPreset);
if (inPauseMode) {
ret.add(ValidCommands.FREEZE+EMPTY_CHAR);
}
return ret;
}
/*
* MATRIX ======================================================
*/
/**
* Gets the matrix.
*
* @return the matrix
*/
public MatrixData getMatrix() {
return matrix;
}
/**
* Sets the matrix.
*
* @param matrix the new matrix
*/
public void setMatrix(MatrixData matrix) {
this.matrix = matrix;
}
/*
* VISUAL ======================================================
*/
/**
* Adds the visual.
*
* @param visual the visual
*/
public void addVisual(Visual visual) {
allVisuals.add(visual);
}
/**
* Gets the all visuals.
*
* @return the all visuals
*/
public List<Visual> getAllVisuals() {
return allVisuals;
}
/**
* Gets the visual.
*
* @param index the index
* @return the visual
*/
public Visual getVisual(int index) {
if (index>=0 && index<allVisuals.size()) {
return allVisuals.get(index);
}
return allVisuals.get(0);
}
/**
* Sets the all visuals.
*
* @param allVisuals the new all visuals
*/
public void setAllVisuals(List<Visual> allVisuals) {
this.allVisuals = allVisuals;
}
/*
* PRESENT ======================================================
*/
/**
* Gets the selected present.
*
* @return the selected present
*/
public int getSelectedPreset() {
return selectedPreset;
}
/**
* Sets the selected present.
*
* @param selectedPresent the new selected present
*/
public void setSelectedPreset(int selectedPreset) {
this.selectedPreset = selectedPreset;
}
/**
* Gets the present.
*
* @return the present
*/
public List<PresetSettings> getPresets() {
return presets;
}
/**
* Sets the present.
*
* @param present the new present
*/
public void setPresets(List<PresetSettings> preset) {
this.presets = preset;
}
/*
* OUTPUT MAPPING ======================================================
*/
/**
* Gets the all output mappings.
*
* @return the all output mappings
*/
public List<OutputMapping> getAllOutputMappings() {
return ioMapping;
}
/**
* Gets the output mappings.
*
* @param index the index
* @return the output mappings
*/
public OutputMapping getOutputMappings(int index) {
return ioMapping.get(index);
}
/**
* Gets the current visual.
*
* @return the current visual
*/
public int getCurrentVisual() {
return currentVisual;
}
/**
* Sets the current visual.
*
* @param currentVisual the new current visual
*/
public void setCurrentVisual(int currentVisual) {
if (currentVisual >= 0 && currentVisual < allVisuals.size()) {
this.currentVisual = currentVisual;
}
}
/**
*
* @return
*/
public int getCurrentOutput() {
return currentOutput;
}
/**
*
* @param currentOutput
*/
public void setCurrentOutput(int currentOutput) {
if (currentOutput >= 0 && currentOutput < ioMapping.size()) {
this.currentOutput = currentOutput;
}
}
/**
* Checks if is loading present.
*
* @return true, if is loading present
*/
public synchronized boolean isLoadingPresent() {
return isLoadingPresent;
}
/**
* Sets the loading present.
*
* @param isLoadingPresent the new loading present
*/
public synchronized void setLoadingPresent(boolean isLoadingPresent) {
this.isLoadingPresent = isLoadingPresent;
}
/**
* Gets the shuffler select.
*
* @param ofs the ofs
* @return the shuffler select
*/
public boolean getShufflerSelect(ShufflerOffset ofs) {
return pixelControllerShufflerSelect.getShufflerSelect(ofs);
}
/**
* Gets the pixel controller shuffler select.
*
* @return the pixel controller shuffler select
*/
public PixelControllerShufflerSelect getPixelControllerShufflerSelect() {
return pixelControllerShufflerSelect;
}
/**
* Gets the pixel controller mixer.
*
* @return the pixel controller mixer
*/
public PixelControllerMixer getPixelControllerMixer() {
return pixelControllerMixer;
}
/**
* Gets the pixel controller effect.
*
* @return the pixel controller effect
*/
public PixelControllerEffect getPixelControllerEffect() {
return pixelControllerEffect;
}
/**
* Gets the pixel controller generator.
*
* @return the pixel controller generator
*/
public PixelControllerGenerator getPixelControllerGenerator() {
return pixelControllerGenerator;
}
/**
* Gets the pixel controller resize.
*
* @return the pixel controller resize
*/
public PixelControllerResize getPixelControllerResize() {
return pixelControllerResize;
}
/**
* Gets the pixel controller output.
*
* @return the pixel controller output
*/
public PixelControllerOutput getPixelControllerOutput() {
return pixelControllerOutput;
}
/**
*
* @return
*/
public PixelControllerFader getPixelControllerFader() {
return pixelControllerFader;
}
/**
* @return the ph
*/
public ApplicationConfigurationHelper getPh() {
return ph;
}
/**
*
* @return
*/
public int getFrames() {
return pixelControllerGenerator.getFrames();
}
/**
*
* @return
*/
public PixelControllerStatus getPixConStat() {
return pixConStat;
}
/**
*
* @return
*/
public List<ColorSet> getColorSets() {
return colorSets;
}
/**
*
* @param colorSets
*/
public void setColorSets(List<ColorSet> colorSets) {
this.colorSets = colorSets;
}
/**
*
*/
public void togglePauseMode() {
if (inPauseMode) {
inPauseMode=false;
} else {
inPauseMode=true;
}
}
/**
*
*/
public void toggleInternalVisual() {
if (internalVisualsVisible) {
internalVisualsVisible=false;
} else {
internalVisualsVisible=true;
}
}
public boolean isInternalVisualsVisible() {
return internalVisualsVisible;
}
/**
*
* @return
*/
public boolean isInPauseMode() {
return inPauseMode;
}
/**
* @param output the output to set
*/
public void setOutput(IOutput output) {
this.output = output;
}
/**
*
* @return
*/
public String getOutputDeviceName() {
if (this.output==null) {
return "";
}
return output.getType().toString();
}
/**
*
* @return
*/
public Boolean isOutputDeviceConnected() {
if (this.output==null || !this.output.isSupportConnectionState()) {
return null;
}
return this.output.isSupportConnectionState() && this.output.isConnected();
}
/**
*
* @return
*/
public IOutput getOutputDevice() {
return this.output;
}
/**
* sound implementation
* @return
*/
public ISound getSound() {
return sound;
}
private List<String> getGuiState() {
List<String> ret = new ArrayList<String>();
Visual v = allVisuals.get(currentVisual);
ret.add(ValidCommands.CURRENT_VISUAL +EMPTY_CHAR+currentVisual);
ret.add(ValidCommands.CHANGE_GENERATOR_A+EMPTY_CHAR+v.getGenerator1Idx());
ret.add(ValidCommands.CHANGE_GENERATOR_B+EMPTY_CHAR+v.getGenerator2Idx());
ret.add(ValidCommands.CHANGE_EFFECT_A+EMPTY_CHAR+v.getEffect1Idx());
ret.add(ValidCommands.CHANGE_EFFECT_B+EMPTY_CHAR+v.getEffect2Idx());
ret.add(ValidCommands.CHANGE_MIXER+EMPTY_CHAR+v.getMixerIdx());
ret.add(ValidCommands.CURRENT_COLORSET+EMPTY_CHAR+v.getColorSet().getName());
//get output status
int ofs=0;
for (OutputMapping om: ioMapping) {
ret.add(ValidCommands.CURRENT_OUTPUT +EMPTY_CHAR+ofs);
ret.add(ValidCommands.CHANGE_OUTPUT_FADER+EMPTY_CHAR+om.getFader().getId());
ret.add(ValidCommands.CHANGE_OUTPUT_VISUAL+EMPTY_CHAR+om.getVisualId());
ofs++;
}
ret.addAll(pixelControllerEffect.getCurrentState());
ret.addAll(pixelControllerGenerator.getCurrentState());
ret.addAll(pixelControllerShufflerSelect.getCurrentState());
ret.add(ValidCommands.CHANGE_PRESET +EMPTY_CHAR+selectedPreset);
ret.add(ValidCommands.FREEZE+EMPTY_CHAR+inPauseMode);
return ret;
}
/**
*
*/
public void notifyGuiUpdate() {
setChanged();
notifyObservers(getGuiState());
}
}