I am trying to build an application representing a led matrix (or many of them) which are going to reakt on musik and flash the leds in sync with it.
My gui looks like this:
But after I play a song for a while, flashing the "leds" I get dead pixels like this:
The longer I play, the more dead pixels I get. In my log I am getting this exception:
java.lang.ClassCastException: com.sun.scenario.effect.InnerShadow cannot be cast to com.sun.prism.paint.Paint at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:970) at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:606) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:477) at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:323) at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125) at java.lang.Thread.run(Thread.java:745) java.lang.ClassCastException: com.sun.prism.paint.LinearGradient cannot be cast to com.sun.scenario.effect.Effect at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1034) at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:606) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:477) at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:323) at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125) at java.lang.Thread.run(Thread.java:745) java.lang.ClassCastException: com.sun.scenario.effect.InnerShadow cannot be cast to com.sun.prism.paint.Paint at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:970) at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:606) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:477) at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:323) at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125) at java.lang.Thread.run(Thread.java:745) java.lang.ClassCastException: com.sun.prism.paint.LinearGradient cannot be cast to com.sun.scenario.effect.Effect at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1034) at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:606) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235) at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576) at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053) at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945) at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:477) at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:323) at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125) at java.lang.Thread.run(Thread.java:745)
My code can be found on GITHUB and here bellow. If you like the music played from your computer to the input of your computer (so you can get it from the code) you need to enable "Stereo Mix" on your soundcard if you have that feature, I needed new drivers to make it work. Othervise you can just play music in a microphone.
This is Main.java:
package org.ledalizer;
import ddf.minim.*;
import ddf.minim.analysis.BeatDetect;
import eu.hansolo.enzo.canvasled.Led;
import eu.hansolo.enzo.canvasled.LedBuilder;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.input.DragEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by david on 2015-09-29.
*/
public class Main extends Application {
public static final int MATRIX_HEIGHT = 30,
MATRIX_WIDTH = 5,
MATRIX_COUNT = 3;
MatrixPane[] matrixPanes = new MatrixPane[MATRIX_COUNT];
class MinimInput {
String sketchPath( String fileName ) {
return "";
}
InputStream createInput(String fileName) {
return new InputStream() {
@Override
public int read() throws IOException {
return 0;
}
};
};
}
@Override
public void start(Stage stage) throws Exception {
FlowPane flowPane = new FlowPane(Orientation.HORIZONTAL, 10, 5);
for(int matrixId=0; matrixId < MATRIX_COUNT; matrixId++) {
MatrixPane matrixPane = new MatrixPane(MATRIX_WIDTH, MATRIX_HEIGHT);
matrixPane.addAllLedsEventHandler(MouseDragEvent.MOUSE_DRAG_ENTERED, toggleLedEventHandler);
matrixPane.addAllLedsEventHandler(MouseEvent.MOUSE_PRESSED, toggleLedEventHandler);
matrixPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if(event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
((MatrixPane) event.getSource()).setAllOn();
}
}
}
);
matrixPanes[matrixId] = matrixPane;
flowPane.getChildren().add(matrixPane);
}
Scene scene = new Scene(flowPane);
scene.addEventFilter(MouseEvent.DRAG_DETECTED , new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
scene.startFullDrag();
}
});
stage.setTitle("Ledalizer");
stage.setScene(scene);
stage.show();
Thread th = new Thread(new Runnable() {
@Override
public void run() {
Minim minim = new Minim(new MinimInput());
AudioInput input = minim.getLineIn(Minim.STEREO, 512);
BeatDetect beatDetect = new BeatDetect(512, 44100.0f);
beatDetect.detectMode(BeatDetect.SOUND_ENERGY);
beatDetect.setSensitivity(50);
//BeatListener bl = new BeatListener(beatDetect, input);
/*
FlashPanelTask hatFlash = new FlashPanelTask(matrixPanes[0], 300);
FlashPanelTask snareFlash = new FlashPanelTask(matrixPanes[1], 300);
FlashPanelTask kickFlash = new FlashPanelTask(matrixPanes[2], 300);
*/
/*
Thread hatFlashThread = new Thread(hatFlash);
Thread snareFlashThread = new Thread(snareFlash);
Thread kickFlashThread = new Thread(kickFlash);
*/
int i = 0;
while (true) {
beatDetect.detect(input.mix);
if(beatDetect.isOnset()) {
matrixPanes[0].setAllOn();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
matrixPanes[0].setAllOff();
}
}
}
});
th.start();
}
class FlashPanelTask implements Runnable {
private MatrixPane matrixPane;
private int time;
public FlashPanelTask(MatrixPane matrixPane, int time) {
this.matrixPane = matrixPane;
this.time = time;
}
@Override
public void run() {
matrixPane.setAllOn();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
matrixPane.setAllOff();
}
}
class BeatListener implements AudioListener
{
private BeatDetect beat;
private AudioInput source;
BeatListener(BeatDetect beat, AudioInput source)
{
this.source = source;
this.source.addListener(this);
this.beat = beat;
}
public void samples(float[] samps) {
beat.detect(source.mix);
}
public void samples(float[] sampsL, float[] sampsR) {
beat.detect(source.mix);
}
}
EventHandler toggleLedEventHandler = new EventHandler() {
@Override
public void handle(Event event) {
Object o = event.getSource();
if(o instanceof Led) {
Led l = (Led) o;
l.setOn(!l.isOn());
}
}
};
EventHandler enableLedEventHandler = new EventHandler() {
@Override
public void handle(Event event) {
Object o = event.getSource();
if(o instanceof Led) {
((Led) o).setOn(true);
}
}
};
}
This is MatrixPane.java:
package org.ledalizer;
import eu.hansolo.enzo.canvasled.Led;
import eu.hansolo.enzo.canvasled.LedBuilder;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.layout.BackgroundPosition;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by david on 2015-09-30.
*/
public class MatrixPane extends GridPane {
int matrixId;
int width, height;
Led[][] leds;
List<Led> ledList;
public MatrixPane(int width, int height, int matrixId) {
init(width, height, matrixId);
}
public MatrixPane(int width, int height) {
init(width, height);
}
private void init(int width, int height, int matrixId) {
this.matrixId = matrixId;
init(width, height);
}
private void init(int width, int height) {
this.width = width;
this.height = height;
leds = new Led[width][height];
ledList = new ArrayList<>();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Led led = LedBuilder.create()
.ledColor(Color.LIGHTBLUE)
.frameVisible(true)
.build();
leds[x][y] = led;
ledList.add(led);
this.add(led, x, y);
}
}
}
public void addAllLedsEventHandler(final EventType<? extends Event> eventType,
final EventHandler<? super Event> eventHandler) {
ledList.forEach((led) -> led.addEventHandler(eventType, eventHandler));
}
public void addLedEventHandler(MatrixPoint point, final EventType<Event> eventType,
final EventHandler<? super Event> eventHandler ) {
leds[point.getX()][point.getY()].addEventHandler(eventType, eventHandler);
}
public void setAllColor(Color color) {
setAll(null, color);
}
public void setAllOff() {
setAll(false, null);
}
public void setAllOn() {
setAll(true, null);
}
public void setAll(Boolean on, Color color) {
ledList.forEach(led -> {
setLed(led, on, color);
}
);
}
public void setUpToColor(int limit, Color color) {
setUpTo(limit, null, color);
}
public void setOnUpTo(int limit) {
setUpTo(limit, true, null);
}
public void setOffUpTo(int limit) {
setUpTo(limit, false, null);
}
public void setUpTo(int limit, Boolean on, Color color) {
for(int y=0; y<limit; y++) {
setRow(y, on, color);
}
}
public void setDownToColor(int limit, Color color) {
setDownTo(limit, null, color);
}
public void setOffDownTo(int limit) {
setDownTo(limit, false, null);
}
public void setOnDownTo(int limit) {
setDownTo(limit, true, null);
}
public void setDownTo(int limit, Boolean on, Color color) {
for(int y=limit; y<height; y++) {
setRow(y, on, color);
}
}
public void setRowColor(int y, Color color) {
setRow(y, null, color);
}
public void setRowOn(int y) {
setRow(y, true, null);
}
public void setRowOff(int y) {
setRow(y, false, null);
}
public void setRow(int y, Boolean on, Color color) {
for(int x=0; x<width; x++) {
setLed(x, y, on, color);
}
}
public void setColumnOn(int x) {
setColumn(x, true, null);
}
public void setColumnOff(int x) {
setColumn(x, false, null);
}
public void setColumnColor(int x, Color color) {
setColumn(x, null, color);
}
public void setColumn(int x, Boolean on, Color color) {
for(int y=0; y<height; y++) {
setLed(x, y, on, color);
}
}
public void setRectangleAreaOn(int x1, int y1, int x2, int y2) {
setRectangleArea(x1, y1, x2, y2, true, null);
}
public void setRectangleAreaOff(int x1, int y1, int x2, int y2) {
setRectangleArea(x1, y1, x2, y2, false, null);
}
public void setRectangleAreaColor(int x1, int y1, int x2, int y2, Color color) {
setRectangleArea(x1, y1, x2, y2, null, color);
}
public void setRectangleArea(int x1, int y1, int x2, int y2, Boolean on, Color color) {
int xLow = getLowest(x1, x2);
int xHigh = getHighest(x1, x2);
int yLow = getLowest(y1, y2);
int yHigh = getHighest(y1, y2);
for(int x=xLow; x < xHigh; x++) {
for(int y=yLow; y < yHigh; y++) {
setLed(x, y, on, color);
}
}
}
private int getHighest(int i1, int i2) {
return i1 > i2 ? i1 : i2;
}
private int getLowest(int i1, int i2) {
return i1 < i2 ? i1 : i2;
}
public void setLedColor(int x, int y, Color color) {
setLed(leds[x][y], null, color);
}
public void setLedOff(int x, int y) {
setLed(leds[x][y], false, null);
}
public void setLedOn(int x, int y) {
setLed(leds[x][y], true, null);
}
public void setLed(int x, int y, Boolean on, Color color) {
setLed(leds[x][y], on, color);
}
public void setLedsColor(List<MatrixPoint> points, Color color) {
setLeds(points, null, color);
}
public void setLedsOn(List<MatrixPoint> points) {
setLeds(points, true, null);
}
public void setLedsOff(List<MatrixPoint> points) {
setLeds(points, false, null);
}
public void setLeds(List<MatrixPoint> points, Boolean on, Color color) {
points.forEach(p -> setLed(p.getX(), p.getY(), on, color));
}
public void setLedOn(MatrixPoint point) {
setLed(point.getX(), point.getY(), true, null);
}
private void setLed(Led led, Boolean on, Color color) {
if(on != null) {
led.setOn(on);
}
if(color != null) {
led.setLedColor(color);
}
}
}
And Led.java is from a library called Enzo by Hansolo. It can be found here.
Please be nice to me, this is my first Java FX application and I am not that experienced with desktop guis.
Can anyone point me in the right direction, how can I make this work?
Let me know if there is anything I can do to help you help me.