/* * Copyright (C) 2012 Gyver * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package com.gyver.matrixmover.core; import com.gyver.matrixmover.core.audio.AudioCaptureThread; import com.gyver.matrixmover.core.timer.FadeTimerTask; import com.gyver.matrixmover.fader.BlackFader; import com.gyver.matrixmover.fader.CrossFader; import com.gyver.matrixmover.fader.Fader; import com.gyver.matrixmover.fader.Fader.FaderName; import com.gyver.matrixmover.fader.LinearFader; import com.gyver.matrixmover.fader.WhiteFader; import com.gyver.matrixmover.generator.Generator; import com.gyver.matrixmover.generator.enums.GeneratorName; import com.gyver.matrixmover.gui.Frame; import com.gyver.matrixmover.gui.LedScreen; import com.gyver.matrixmover.gui.MasterPanel; import com.gyver.matrixmover.mapping.OutputMapping; import com.gyver.matrixmover.mapping.PixelRgbMapping; import com.gyver.matrixmover.mixer.Mixer.MixerName; import com.gyver.matrixmover.output.Output; import com.gyver.matrixmover.properties.PropertiesHelper; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Timer; import java.util.logging.Level; import java.util.logging.Logger; /** * This is a singelton. Performs all the calculations. * * @author Gyver */ public class Controller { /** * The left side generator setup */ public static final int LEFT_SIDE = 1; /** * The right side generator setup */ public static final int RIGHT_SIDE = 2; private final float VU_DECAY = 2.5F; private static final Logger LOG = Logger.getLogger(Controller.class.getName()); private static Controller instance = new Controller(); private PropertiesHelper ph = null; private Output output = null; private MatrixData matrixData = null; private LedScreen leftLedScreen = null; private LedScreen rightLedScreen = null; private LedScreen masterLedScreen = null; private VisualSetup leftVisual = null; private VisualSetup rightVisual = null; private Fader fader = null; private int[] leftLedImage = null; private int[] rightLedImage = null; private int[] outputLedImage = null; private int crossfaderValue = 0; private int masterIntensity = 255; private float[] decayedLevel = null; private OutputMapping om = null; private PixelRgbMapping prm = null; private boolean isFading = false; private Timer fadingTimer = null; private AudioCaptureThread act = null; private Thread actThread = null; /** * Instantiates a new controller. */ private Controller() { } /** * Inits a new Controller. * @param ph the PropertiesHelper * @param output The Output to use */ public void initController(PropertiesHelper ph, Output output) { this.ph = ph; this.output = output; matrixData = new MatrixData(ph.getOutputDeviceDimensionWidth(), ph.getOutputDeviceDimensionHeight()); this.decayedLevel = new float[2]; //init and hold the Visuals leftVisual = new VisualSetup(matrixData); rightVisual = new VisualSetup(matrixData); // CrossFader button in Gui is selected in postInit(); fader = new CrossFader(); om = new OutputMapping(matrixData); prm = new PixelRgbMapping(); } /** * Sets the LED-Simulation Screens * @param leftVisual * @param rightVisual * @param masterVisual */ public void setLedScreens(LedScreen leftVisual, LedScreen rightVisual, LedScreen masterVisual) { this.leftLedScreen = leftVisual; this.rightLedScreen = rightVisual; this.masterLedScreen = masterVisual; } /** * Sets the generator "nr" of side "side" for GeneratorName "generator" * @param side the side * @param nr the number of the generator to be set * @param generator the generator to set to */ public void setGenerator(int side, int nr, GeneratorName generator) { if (side == LEFT_SIDE) { LOG.log(Level.FINE, "Generator{0} on left side set to {1}", new Object[]{nr, generator}); leftVisual.setGeneratorFromString(nr, generator.toString()); } else if (side == RIGHT_SIDE) { LOG.log(Level.FINE, "Generator{0} on right side set to {1}", new Object[]{nr, generator}); rightVisual.setGeneratorFromString(nr, generator.toString()); } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } /** * Sets the effect "nr" of side "side" for String "effectString" * @param side the side * @param nr the number of the effect to be set * @param effectString the effect to set to */ public void setEffect(int side, int nr, String effectString) { if (side == LEFT_SIDE) { LOG.log(Level.FINE, "Effect{0} on left side set to {1}", new Object[]{nr, effectString}); leftVisual.setEffectFromString(nr, effectString); } else if (side == RIGHT_SIDE) { LOG.log(Level.FINE, "Effect{0} on right side set to {1}", new Object[]{nr, effectString}); rightVisual.setEffectFromString(nr, effectString); } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } /** * Sets the mixer for side "side" from String "mixerString" * @param side the side * @param mixerName the mixer to be set to */ public void setMixer(int side, int nr, String mixerName) { if (side == LEFT_SIDE) { LOG.log(Level.FINE, "Mixer on left side set to {0}", new Object[]{mixerName}); leftVisual.setMixerFromString(nr, mixerName); } else if (side == RIGHT_SIDE) { LOG.log(Level.FINE, "Mixer on right side set to {0}", new Object[]{mixerName}); rightVisual.setMixerFromString(nr, mixerName); } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } public void setGeneratorIntensity(int side, int nr, int value) { if (side == LEFT_SIDE) { leftVisual.setGeneratorIntensity(nr, value); } else if (side == RIGHT_SIDE) { rightVisual.setGeneratorIntensity(nr, value); } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } public void setCrossfaderValue(int value) { this.crossfaderValue = value; } public void setMasterIntensity(int value) { masterIntensity = value; } public static Controller getControllerInstance() { return instance; } public MatrixData getMatrixData() { return matrixData; } public Generator getGenerator(int side, int nr) { if (side == LEFT_SIDE) { return leftVisual.getGenerator(nr); } else if (side == RIGHT_SIDE) { return rightVisual.getGenerator(nr); } throw new IllegalArgumentException("There is no Generator nr " + nr + " present for side " + side); } // public void sceneSelected(int scene, int side) // if (side == BOTTOM_SIDE) { // LOG.log(Level.FINE, "Scene {0} selected for left side.", scene); // Frame.getFrameInstance().getLeftGeneratorPanel().setButtonActive(leftVisual.getActiveScene(), false); // Frame.getFrameInstance().getLeftGeneratorPanel().setButtonActive(scene, true); // leftVisual.setActiveScene(scene); // Frame.getFrameInstance().setComboBoxesForChangedScene(side, leftVisual.getActiveVisualSetup()); // } else if (side == TOP_SIDE) { // LOG.log(Level.FINE, "Scene {0} selected for right side.", scene); // Frame.getFrameInstance().getRightGeneratorPanel().setButtonActive(rightVisual.getActiveScene(), false); // Frame.getFrameInstance().getRightGeneratorPanel().setButtonActive(scene, true); // rightVisual.setActiveScene(scene); // Frame.getFrameInstance().setComboBoxesForChangedScene(side, rightVisual.getActiveVisualSetup()); // } else { // throw new IllegalArgumentException("Side with ID " + side + " is not existing."); // } // } public void computeLeftVisual() { //get the calculated image leftLedImage = leftVisual.getSceneOutput(); //push it to led-screen leftLedScreen.setPixelImage(leftLedImage); } public void computeRightVisual() { //get the calculated image rightLedImage = rightVisual.getSceneOutput(); //push it to led-screen rightLedScreen.setPixelImage(rightLedImage); } public void computeMasterVisual() { //mix left and right image with fader outputLedImage = fader.fade(leftLedImage, rightLedImage, crossfaderValue); //apply master intensity outputLedImage = applyIntensity(outputLedImage, masterIntensity); //write image to MasterLedScreen masterLedScreen.setPixelImage(outputLedImage); //apply the pixel mapping to the image int[] outputDeviceImage = om.applyMapping(outputLedImage); //apply the rgb mapping // outputDeviceImage = prm.applyMapping(outputDeviceImage); //give image to outputDevice output.update(outputDeviceImage); } private int[] applyIntensity(int[] src, int value) { int[] ret = new int[src.length]; short red, green, blue; int col; float ratio = (value / 255f); for (int i = 0; i < src.length; i++) { col = src[i]; red = (short) (Math.round(((col >> 16) & 255) * ratio)); green = (short) (Math.round(((col >> 8) & 255) * ratio)); blue = (short) (Math.round((col & 255) * ratio)); ret[i] = (red << 16) | (green << 8) | blue; } return ret; } public int getFps() { return ph.getFps(); } public VisualSetup getActiveVisualSetup(int side) { if (side == LEFT_SIDE) { return leftVisual; } else if (side == RIGHT_SIDE) { return rightVisual; } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } public void setVisualSetup(VisualSetup vs, int side) { if (side == LEFT_SIDE) { leftVisual = vs; Frame.getFrameInstance().getLeftGeneratorSetup().setVisualSetup(vs); } else if (side == RIGHT_SIDE) { rightVisual = vs; Frame.getFrameInstance().getRightGeneratorSetup().setVisualSetup(vs); } else { throw new IllegalArgumentException("Side with ID " + side + " is not existing."); } } /** * Do stuff that needs a Gui. */ public void postInit() { MasterPanel masterPanel = Frame.getFrameInstance().getMasterPanel(); masterPanel.setSelectedButton(masterPanel.getTbCross()); om.setMapping(ph.getOutputMapping()); prm.setPixelMode(ph.getOutputPixeMode()); } public void changeFaderMode(FaderName faderName) { if (faderName.compareTo(FaderName.CROSSFADE) == 0) { fader = new CrossFader(); } else if (faderName.compareTo(FaderName.LINEAR) == 0) { fader = new LinearFader(); } else if (faderName.compareTo(FaderName.WHITE) == 0) { fader = new WhiteFader(); } else if (faderName.compareTo(FaderName.BLACK) == 0) { fader = new BlackFader(); } } public void autoFade(int fadeTime) { if (!isFading) { isFading = true; fadingTimer = new Timer(); int currentPosition = Frame.getFrameInstance().getMasterPanel().getSFadePosition().getValue(); int[] fadeSteps = null; float secondsForFading = fadeTime / 1000F; int numberOfFadeSteps = (int) Math.round(ph.getFps() * secondsForFading); if (numberOfFadeSteps < 2) { Frame.getFrameInstance().showWarning("Fadetime is to small. Give it more time!"); isFading = false; return; } fadeSteps = new int[numberOfFadeSteps]; //fade to right side if (currentPosition < 500) { for (int i = 0; i < fadeSteps.length; i++) { fadeSteps[i] = currentPosition + Math.round((1000 - currentPosition) * (i / (float) (fadeSteps.length - 1))); } } else { for (int i = 0; i < fadeSteps.length; i++) { fadeSteps[i] = currentPosition - Math.round(currentPosition * (i / (float) (fadeSteps.length - 1))); } } long millisecondsDelay = 1000 / ph.getFps(); fadingTimer.scheduleAtFixedRate(new FadeTimerTask(this, fadeSteps), 0, millisecondsDelay); } } public void setAudioCapture(AudioCaptureThread act, Thread actThread) { this.act = act; this.actThread = actThread; } public void setIsFading(boolean isFading) { this.isFading = isFading; } public float[] getSpectrum(int bands) { if (act != null) { return act.getSpectrum(bands); } return new float[bands]; } public void shutDown() { if (fadingTimer != null) { fadingTimer.cancel(); fadingTimer.purge(); fadingTimer = null; } } public void updateVuMeter() { float[] newLevel = new float[2]; if (act != null) { newLevel = act.getRmsLevel(); } // decay left channel if (newLevel[0] >= decayedLevel[0]) { decayedLevel[0] = newLevel[0]; } else { decayedLevel[0] -= VU_DECAY; if (newLevel[0] >= decayedLevel[0]) { decayedLevel[0] = newLevel[0]; } } // right channel if (newLevel[1] >= decayedLevel[1]) { decayedLevel[1] = newLevel[1]; } else { decayedLevel[1] -= VU_DECAY; if (newLevel[1] >= decayedLevel[1]) { decayedLevel[1] = newLevel[1]; } } Frame.getFrameInstance().setAudioLevel(decayedLevel); } }