new effects, fixes & arduino code
This commit is contained in:
parent
683924d18c
commit
a921f38645
11 changed files with 495 additions and 345 deletions
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
47
LED_Panel_arduino/LED_Panel_arduino.ino
Normal file
47
LED_Panel_arduino/LED_Panel_arduino.ino
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <PololuLedStrip.h>
|
||||||
|
|
||||||
|
#define PIN 3
|
||||||
|
PololuLedStrip<PIN> leds;
|
||||||
|
#define LED_COUNT 256
|
||||||
|
#define BAUD 1000000
|
||||||
|
rgb_color colors[LED_COUNT];
|
||||||
|
|
||||||
|
#define BRIGHTNESS 10
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
PololuLedStripBase::interruptFriendly = true;
|
||||||
|
Serial.begin(BAUD);
|
||||||
|
Serial.setTimeout(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// main program
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
byte buf[1];
|
||||||
|
unsigned int c=0;
|
||||||
|
do{
|
||||||
|
c++;
|
||||||
|
|
||||||
|
if(Serial.readBytes(buf, 1) == 0) {
|
||||||
|
for (uint16_t i = 0; i < LED_COUNT; i++){
|
||||||
|
colors[i] = rgb_color(0, 0, 0);
|
||||||
|
}
|
||||||
|
leds.write(colors, LED_COUNT);
|
||||||
|
}
|
||||||
|
}while(buf[0] != 255);
|
||||||
|
|
||||||
|
if(c>1){
|
||||||
|
Serial.print("Invalid Data Bytes: ");
|
||||||
|
Serial.println(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < LED_COUNT; i++)
|
||||||
|
{
|
||||||
|
char col[3];
|
||||||
|
Serial.readBytes(col, 3);
|
||||||
|
colors[i] = rgb_color(col[0], col[1], col[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
leds.write(colors, LED_COUNT);
|
||||||
|
}
|
6
pom.xml
6
pom.xml
|
@ -20,9 +20,9 @@
|
||||||
<version>[2.0.0,3.0.0)</version>
|
<version>[2.0.0,3.0.0)</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.profesorfalken</groupId>
|
<groupId>com.github.oshi</groupId>
|
||||||
<artifactId>jSensors</artifactId>
|
<artifactId>oshi-core</artifactId>
|
||||||
<version>2.2.1</version>
|
<version>5.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.tagtraum</groupId>
|
<groupId>com.tagtraum</groupId>
|
||||||
|
|
|
@ -9,49 +9,53 @@ import java.awt.event.MouseListener;
|
||||||
|
|
||||||
public class EffectManager {
|
public class EffectManager {
|
||||||
|
|
||||||
int activeId=4;
|
int activeId = 4;
|
||||||
private final LEDEffect[] effects = new LEDEffect[]{new TemperatureEffect(), new ClockEffect(), new SineEffect(), new AudioEffect(), new ColorSweep()};
|
private final LEDEffect[] effects = new LEDEffect[]{new ClockEffect(),new AudioVolume(), new TemperatureEffect(), new SineEffect(), new AudioFFT(), new ColorSweep()};
|
||||||
|
|
||||||
public EffectManager(){
|
public EffectManager() {
|
||||||
|
|
||||||
final SystemTray tray = SystemTray.getSystemTray();
|
final SystemTray tray = SystemTray.getSystemTray();
|
||||||
final TrayIcon trayIcon = new TrayIcon(new ImageIcon(getClass().getResource("/icon.png")).getImage(),"LEDEffects");
|
final TrayIcon trayIcon = new TrayIcon(new ImageIcon(getClass().getResource("/icon.png")).getImage(), "LEDEffects");
|
||||||
|
|
||||||
trayIcon.addMouseListener(new MouseListener() {
|
trayIcon.addMouseListener(new MouseListener() {
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
if(e.getButton()!=MouseEvent.BUTTON1)
|
if (e.getButton() != MouseEvent.BUTTON1)
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
getActiveEffect().unload();
|
getActiveEffect().unload();
|
||||||
activeId++;
|
activeId++;
|
||||||
if(activeId==effects.length)
|
if (activeId == effects.length)
|
||||||
activeId=0;
|
activeId = 0;
|
||||||
getActiveEffect().load();
|
getActiveEffect().load();
|
||||||
trayIcon.setToolTip("LEDEffects - " + getActiveEffect().getDescription());
|
trayIcon.setToolTip("LEDEffects - " + getActiveEffect().getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {}
|
public void mousePressed(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {}
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseEntered(MouseEvent e) {}
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseExited(MouseEvent e) {}
|
public void mouseExited(MouseEvent e) {
|
||||||
});
|
}
|
||||||
try {
|
});
|
||||||
tray.add(trayIcon);
|
try {
|
||||||
} catch (AWTException e) {
|
tray.add(trayIcon);
|
||||||
e.printStackTrace();
|
} catch (AWTException e) {
|
||||||
}
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
getActiveEffect().load();
|
getActiveEffect().load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LEDEffect getActiveEffect() {
|
public LEDEffect getActiveEffect() {
|
||||||
return effects[activeId];
|
return effects[activeId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,108 +1,136 @@
|
||||||
package de.zuim.ledcontrol;
|
package de.zuim.ledcontrol;
|
||||||
|
|
||||||
import com.fazecast.jSerialComm.SerialPort;
|
import com.fazecast.jSerialComm.SerialPort;
|
||||||
|
import com.fazecast.jSerialComm.SerialPortDataListener;
|
||||||
|
import com.fazecast.jSerialComm.SerialPortEvent;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.AffineTransformOp;
|
import java.awt.image.AffineTransformOp;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class LEDControl {
|
public class LEDControl {
|
||||||
public static final int WIDTH=16;
|
public static final int WIDTH = 16;
|
||||||
public static final int HEIGHT=16;
|
public static final int HEIGHT = 16;
|
||||||
public static final int LED_NUM = WIDTH*HEIGHT;
|
public static final int LED_NUM = WIDTH * HEIGHT;
|
||||||
public static final int BAUD = 1000000;
|
public static final int BAUD = 1000000;
|
||||||
|
|
||||||
|
|
||||||
private SerialPort port;
|
private SerialPort port;
|
||||||
private byte[][][] leds = new byte[WIDTH][HEIGHT][3];
|
private final byte[][][] leds = new byte[WIDTH][HEIGHT][3];
|
||||||
private EffectManager eff;
|
private final EffectManager eff;
|
||||||
private BufferedImage scaledImage;
|
private BufferedImage scaledImage;
|
||||||
|
|
||||||
public LEDControl(){
|
public LEDControl() {
|
||||||
eff = new EffectManager();
|
eff = new EffectManager();
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> port.closePort()));
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> port.closePort()));
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
|
|
||||||
sendLoop();
|
sendLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLoop(){
|
private void sendLoop() {
|
||||||
long time = System.nanoTime();
|
long time = System.nanoTime();
|
||||||
long iteration = 0;
|
long iteration = 0;
|
||||||
|
|
||||||
while(true){
|
long minTimeDelta = Long.MAX_VALUE,
|
||||||
if(port == null || !port.isOpen()){
|
maxTimeDelta = 0;
|
||||||
sleep(1000);
|
|
||||||
connect();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
long timeDelta = System.nanoTime()-time;
|
while (true) {
|
||||||
time = System.nanoTime();
|
if (port == null || !port.isOpen()) {
|
||||||
|
if (!connect()) {
|
||||||
|
sleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
renderFrame(timeDelta);
|
long timeDelta = System.nanoTime() - time;
|
||||||
|
if(timeDelta > maxTimeDelta)
|
||||||
|
maxTimeDelta = timeDelta;
|
||||||
|
if(timeDelta < minTimeDelta)
|
||||||
|
minTimeDelta = timeDelta;
|
||||||
|
time = System.nanoTime();
|
||||||
|
|
||||||
port.writeBytes(new byte[]{(byte) 255}, 1); //start of new frame
|
renderFrame(timeDelta);
|
||||||
|
|
||||||
for(int x=0;x<WIDTH;x++){
|
port.writeBytes(new byte[]{(byte) 255}, 1); //start of new frame
|
||||||
for(int y=0;y<HEIGHT;y++){
|
|
||||||
int col = scaledImage.getRGB(x,(x%2==1)?leds[0].length-y-1:y);
|
|
||||||
leds[x][y][0] = (byte) Math.min(((col>>16)&0xff),254);
|
|
||||||
leds[x][y][1] = (byte) Math.min((col>>8)&0xff,254);
|
|
||||||
leds[x][y][2] = (byte) Math.min(((col)&0xff),254);
|
|
||||||
port.writeBytes(leds[x][y], 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(10);
|
for (int x = 0; x < WIDTH; x++) {
|
||||||
|
for (int y = 0; y < HEIGHT; y++) {
|
||||||
|
int col = scaledImage.getRGB(x, (x % 2 == 1) ? leds[0].length - y - 1 : y);
|
||||||
|
leds[x][y][0] = (byte) Math.min(((col >> 16) & 0xff), 254);
|
||||||
|
leds[x][y][1] = (byte) Math.min((col >> 8) & 0xff, 254);
|
||||||
|
leds[x][y][2] = (byte) Math.min(((col) & 0xff), 254);
|
||||||
|
port.writeBytes(leds[x][y], 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(iteration%1000==1){
|
sleep(10);
|
||||||
System.out.println("Frametime: "+ (Math.round(timeDelta)/100000)/10.0 + "ms ("+iteration+" Frames)");
|
|
||||||
}
|
|
||||||
iteration++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connect(){
|
if (iteration % 1000 == 1) {
|
||||||
SerialPort[] ports = SerialPort.getCommPorts();
|
System.out.println("Frametime: " + (Math.round(timeDelta) / 100000) / 10.0 + "ms ("+(Math.round(minTimeDelta) / 100000) / 10.0+"ms - "+(Math.round(maxTimeDelta) / 100000) / 10.0+"ms) " + iteration + " Frames");
|
||||||
if(ports.length > 0){
|
minTimeDelta = Long.MAX_VALUE;
|
||||||
port = SerialPort.getCommPorts()[0];
|
maxTimeDelta = 0;
|
||||||
System.out.println("Connect to " + port.getDescriptivePortName()+" "+port.getSystemPortName()+" ");
|
}
|
||||||
port.setComPortParameters(BAUD,8,1,0);
|
iteration++;
|
||||||
port.openPort();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(int ms){
|
private boolean connect() {
|
||||||
try {
|
SerialPort[] ports = SerialPort.getCommPorts();
|
||||||
Thread.sleep(ms);
|
if (ports.length > 0) {
|
||||||
} catch (InterruptedException e) {
|
port = SerialPort.getCommPorts()[0];
|
||||||
e.printStackTrace();
|
System.out.println("Connect to " + port.getDescriptivePortName() + " " + port.getSystemPortName() + " ");
|
||||||
}
|
port.setComPortParameters(BAUD, 8, 1, 0);
|
||||||
}
|
if (port.openPort()) {
|
||||||
|
port.addDataListener(new SerialPortDataListener() {
|
||||||
|
@Override
|
||||||
|
public int getListeningEvents() {
|
||||||
|
return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
private void renderFrame(long timeDelta) {
|
@Override
|
||||||
BufferedImage image = new BufferedImage(16*eff.getActiveEffect().getScale(),16*eff.getActiveEffect().getScale(),BufferedImage.TYPE_INT_ARGB);
|
public void serialEvent(SerialPortEvent event) {
|
||||||
Graphics g = image.getGraphics();
|
System.err.println("Received: " + new String(event.getReceivedData(), StandardCharsets.US_ASCII));
|
||||||
eff.getActiveEffect().render(timeDelta, g);
|
}
|
||||||
g.dispose();
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(eff.getActiveEffect().getScale()==1){
|
return false;
|
||||||
scaledImage = image;
|
}
|
||||||
}else{
|
|
||||||
scaledImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
AffineTransform at = new AffineTransform();
|
|
||||||
at.scale(1.0/eff.getActiveEffect().getScale(), 1.0/eff.getActiveEffect().getScale());
|
|
||||||
AffineTransformOp scaleOp =
|
|
||||||
new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
|
|
||||||
scaledImage = scaleOp.filter(image, scaledImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
private void sleep(int ms) {
|
||||||
new LEDControl();
|
try {
|
||||||
}
|
Thread.sleep(ms);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFrame(long timeDelta) {
|
||||||
|
BufferedImage image = new BufferedImage(16 * eff.getActiveEffect().getScale(), 16 * eff.getActiveEffect().getScale(), BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics g = image.getGraphics();
|
||||||
|
eff.getActiveEffect().render(timeDelta, g);
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
if (eff.getActiveEffect().getScale() == 1) {
|
||||||
|
scaledImage = image;
|
||||||
|
} else {
|
||||||
|
scaledImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
AffineTransform at = new AffineTransform();
|
||||||
|
at.scale(1.0 / eff.getActiveEffect().getScale(), 1.0 / eff.getActiveEffect().getScale());
|
||||||
|
AffineTransformOp scaleOp =
|
||||||
|
new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
|
||||||
|
scaledImage = scaleOp.filter(image, scaledImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new LEDControl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,17 @@ import java.awt.*;
|
||||||
|
|
||||||
public interface LEDEffect {
|
public interface LEDEffect {
|
||||||
|
|
||||||
String getDescription();
|
String getDescription();
|
||||||
default int getScale() {return 1; }
|
|
||||||
default void load() {}
|
default int getScale() {
|
||||||
default void unload() {}
|
return 1;
|
||||||
void render(long timeDelta, Graphics g);
|
}
|
||||||
|
|
||||||
|
default void load() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void unload() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(long timeDelta, Graphics g);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
package de.zuim.ledcontrol.effects;
|
|
||||||
|
|
||||||
import com.tagtraum.jipes.math.FFTFactory;
|
|
||||||
import com.tagtraum.jipes.math.Transform;
|
|
||||||
import de.zuim.ledcontrol.LEDControl;
|
|
||||||
import de.zuim.ledcontrol.LEDEffect;
|
|
||||||
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static de.zuim.ledcontrol.LEDControl.HEIGHT;
|
|
||||||
import static de.zuim.ledcontrol.LEDControl.WIDTH;
|
|
||||||
|
|
||||||
public class AudioEffect implements LEDEffect {
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Audio Effect";
|
|
||||||
}
|
|
||||||
|
|
||||||
final static int BUFFERSIZE = 2048;
|
|
||||||
double[] magnitudes = null;
|
|
||||||
Thread audioThread = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void load() {
|
|
||||||
Runnable audioRunnable = () -> {
|
|
||||||
|
|
||||||
|
|
||||||
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
|
|
||||||
List<Line.Info> availableTargetLines = new ArrayList<>();
|
|
||||||
for (Mixer.Info mixerInfo : mixers){
|
|
||||||
|
|
||||||
Mixer m = AudioSystem.getMixer(mixerInfo);
|
|
||||||
|
|
||||||
Line.Info[] lines = m.getTargetLineInfo();
|
|
||||||
|
|
||||||
for (Line.Info li : lines)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(li instanceof DataLine.Info && mixerInfo.toString().contains("mix"))
|
|
||||||
{
|
|
||||||
m.open();
|
|
||||||
System.out.println("("+availableTargetLines.size()+") Found target line: " + li+" "+mixerInfo + "("+li.getClass()+")");
|
|
||||||
availableTargetLines.add(li);
|
|
||||||
m.close();
|
|
||||||
}
|
|
||||||
} catch (LineUnavailableException e){
|
|
||||||
System.out.println("Line unavailable.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DataLine.Info targetLineInfo = (DataLine.Info) availableTargetLines.get(0);
|
|
||||||
|
|
||||||
System.out.println("SUPPORTED TARGET FORMATS: ");
|
|
||||||
AudioFormat[] formats = (targetLineInfo).getFormats();
|
|
||||||
for(int i=0; i<formats.length;i++)
|
|
||||||
{
|
|
||||||
System.out.println("("+i+")"+formats[i]);
|
|
||||||
}
|
|
||||||
AudioFormat format = formats[2];
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("SELECTED: "+format);
|
|
||||||
|
|
||||||
|
|
||||||
final DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
|
|
||||||
final AudioInputStream audioStream;
|
|
||||||
|
|
||||||
try {
|
|
||||||
TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
|
|
||||||
targetLine.open();
|
|
||||||
targetLine.start();
|
|
||||||
audioStream = new AudioInputStream(targetLine);
|
|
||||||
|
|
||||||
final byte[] buf = new byte[BUFFERSIZE];
|
|
||||||
|
|
||||||
final int numberOfSamples = buf.length / format.getFrameSize();
|
|
||||||
final Transform fft = FFTFactory.getInstance().create(numberOfSamples);
|
|
||||||
while (audioThread != null) {
|
|
||||||
// in real impl, don't just ignore how many bytes you read
|
|
||||||
int read = audioStream.read(buf);
|
|
||||||
// the stream represents each sample as two bytes -> decode
|
|
||||||
|
|
||||||
float[] fbuf = decode(buf,format);
|
|
||||||
|
|
||||||
final float[][] transformed = fft.transform(fbuf);
|
|
||||||
final float[] realPart = transformed[0];
|
|
||||||
final float[] imaginaryPart = transformed[1];
|
|
||||||
magnitudes = toMagnitudes(realPart, imaginaryPart);
|
|
||||||
|
|
||||||
//System.out.println("M"+ Arrays.toString(magnitudes));
|
|
||||||
// do something with magnitudes...
|
|
||||||
int max = 0, avg = 0,min=11111111;
|
|
||||||
for(double m : magnitudes){
|
|
||||||
avg += m;
|
|
||||||
if(m>max)
|
|
||||||
max= (int) m;
|
|
||||||
if(m<min)
|
|
||||||
min= (int) m;
|
|
||||||
}
|
|
||||||
//System.out.println("M"+ max+" "+min+" "+avg/magnitudes.length+ " "+read+" "+magnitudes.length);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
audioThread = new Thread(audioRunnable);
|
|
||||||
audioThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unload() {
|
|
||||||
if(audioThread != null && audioThread.isAlive())
|
|
||||||
audioThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(long timeDelta, Graphics g) {
|
|
||||||
for(int x = 0; x< WIDTH; x++){
|
|
||||||
double val = 0;
|
|
||||||
if(magnitudes != null) {
|
|
||||||
for (int sample = 0; sample < magnitudes.length / WIDTH; sample++) {
|
|
||||||
val += magnitudes[x * (magnitudes.length / WIDTH) + sample];
|
|
||||||
}
|
|
||||||
val /= (double) magnitudes.length / WIDTH;
|
|
||||||
}
|
|
||||||
int y= (int) Math.round(Math.max(0,val-1)/10);
|
|
||||||
g.setColor(new Color(Math.abs(y)+1,2,0));
|
|
||||||
g.drawRect(x,0,1,y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static final float NORMALIZATION_FACTOR_2_BYTES = Short.MAX_VALUE + 1.0f;
|
|
||||||
private static float[] decode(final byte[] buf, final AudioFormat format) {
|
|
||||||
final float[] fbuf = new float[buf.length / format.getFrameSize()];
|
|
||||||
for (int pos = 0; pos < buf.length; pos += format.getFrameSize()) {
|
|
||||||
final int sample = format.isBigEndian()
|
|
||||||
? byteToIntBigEndian(buf, pos, format.getFrameSize())
|
|
||||||
: byteToIntLittleEndian(buf, pos, format.getFrameSize());
|
|
||||||
// normalize to [0,1] (not strictly necessary, but makes things easier)
|
|
||||||
fbuf[pos / format.getFrameSize()] = sample / NORMALIZATION_FACTOR_2_BYTES;
|
|
||||||
}
|
|
||||||
return fbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double[] toMagnitudes(final float[] realPart, final float[] imaginaryPart) {
|
|
||||||
final double[] powers = new double[realPart.length / 2];
|
|
||||||
for (int i = 0; i < powers.length; i++) {
|
|
||||||
powers[i] = Math.sqrt(realPart[i] * realPart[i] + imaginaryPart[i] * imaginaryPart[i]);
|
|
||||||
}
|
|
||||||
return powers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int byteToIntLittleEndian(final byte[] buf, final int offset, final int bytesPerSample) {
|
|
||||||
int sample = 0;
|
|
||||||
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
|
|
||||||
final int aByte = buf[offset + byteIndex] & 0xff;
|
|
||||||
sample += aByte << 8 * (byteIndex);
|
|
||||||
}
|
|
||||||
return sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int byteToIntBigEndian(final byte[] buf, final int offset, final int bytesPerSample) {
|
|
||||||
int sample = 0;
|
|
||||||
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
|
|
||||||
final int aByte = buf[offset + byteIndex] & 0xff;
|
|
||||||
sample += aByte << (8 * (bytesPerSample - byteIndex - 1));
|
|
||||||
}
|
|
||||||
return sample;
|
|
||||||
}
|
|
||||||
}
|
|
193
src/main/java/de/zuim/ledcontrol/effects/AudioFFT.java
Normal file
193
src/main/java/de/zuim/ledcontrol/effects/AudioFFT.java
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
package de.zuim.ledcontrol.effects;
|
||||||
|
|
||||||
|
import com.tagtraum.jipes.math.FFTFactory;
|
||||||
|
import com.tagtraum.jipes.math.Transform;
|
||||||
|
import de.zuim.ledcontrol.LEDControl;
|
||||||
|
import de.zuim.ledcontrol.LEDEffect;
|
||||||
|
|
||||||
|
import javax.sound.sampled.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.zuim.ledcontrol.LEDControl.HEIGHT;
|
||||||
|
import static de.zuim.ledcontrol.LEDControl.WIDTH;
|
||||||
|
|
||||||
|
public class AudioFFT implements LEDEffect {
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Audio FFT";
|
||||||
|
}
|
||||||
|
|
||||||
|
final static int BUFFERSIZE = 2048;
|
||||||
|
float[] fbuf = null;
|
||||||
|
double[] magnitudes = null;
|
||||||
|
Thread audioThread = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
Runnable audioRunnable = () -> {
|
||||||
|
|
||||||
|
|
||||||
|
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
|
||||||
|
List<Line.Info> availableTargetLines = new ArrayList<>();
|
||||||
|
for (Mixer.Info mixerInfo : mixers) {
|
||||||
|
|
||||||
|
Mixer m = AudioSystem.getMixer(mixerInfo);
|
||||||
|
|
||||||
|
Line.Info[] lines = m.getTargetLineInfo();
|
||||||
|
|
||||||
|
for (Line.Info li : lines) {
|
||||||
|
try {
|
||||||
|
if (li instanceof DataLine.Info && mixerInfo.toString().contains("mix")) {
|
||||||
|
m.open();
|
||||||
|
System.out.println("(" + availableTargetLines.size() + ") Found target line: " + li + " " + mixerInfo + "(" + li.getClass() + ")");
|
||||||
|
availableTargetLines.add(li);
|
||||||
|
m.close();
|
||||||
|
}
|
||||||
|
} catch (LineUnavailableException e) {
|
||||||
|
System.out.println("Line unavailable.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataLine.Info targetLineInfo = (DataLine.Info) availableTargetLines.get(0);
|
||||||
|
|
||||||
|
System.out.println("SUPPORTED TARGET FORMATS: ");
|
||||||
|
AudioFormat[] formats = (targetLineInfo).getFormats();
|
||||||
|
for (int i = 0; i < formats.length; i++) {
|
||||||
|
System.out.println("(" + i + ")" + formats[i]);
|
||||||
|
}
|
||||||
|
AudioFormat format = formats[2];
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("SELECTED: " + format);
|
||||||
|
|
||||||
|
|
||||||
|
final DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
|
||||||
|
final AudioInputStream audioStream;
|
||||||
|
|
||||||
|
//verbesserung: https://stackoverflow.com/a/51240462
|
||||||
|
try {
|
||||||
|
TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
|
||||||
|
targetLine.open();
|
||||||
|
targetLine.start();
|
||||||
|
audioStream = new AudioInputStream(targetLine);
|
||||||
|
|
||||||
|
final byte[] buf = new byte[BUFFERSIZE];
|
||||||
|
|
||||||
|
final int numberOfSamples = buf.length / format.getFrameSize();
|
||||||
|
final Transform fft = FFTFactory.getInstance().create(numberOfSamples);
|
||||||
|
while (audioThread != null) {
|
||||||
|
int read = audioStream.read(buf);
|
||||||
|
|
||||||
|
fbuf = decode(buf, format);
|
||||||
|
|
||||||
|
final float[][] transformed = fft.transform(fbuf);
|
||||||
|
final float[] realPart = transformed[0];
|
||||||
|
final float[] imaginaryPart = transformed[1];
|
||||||
|
magnitudes = toMagnitudes(realPart, imaginaryPart);
|
||||||
|
|
||||||
|
//System.out.println("M"+ Arrays.toString(magnitudes));
|
||||||
|
|
||||||
|
int max = 0, avg = 0, min = 11111111;
|
||||||
|
for (double m : magnitudes) {
|
||||||
|
avg += m;
|
||||||
|
if (m > max)
|
||||||
|
max = (int) m;
|
||||||
|
if (m < min)
|
||||||
|
min = (int) m;
|
||||||
|
}
|
||||||
|
//System.out.println("M"+ max+" "+min+" "+avg/magnitudes.length+ " "+read+" "+magnitudes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
audioStream.close();
|
||||||
|
targetLine.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
audioThread = new Thread(audioRunnable);
|
||||||
|
audioThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unload() {
|
||||||
|
if (audioThread != null && audioThread.isAlive())
|
||||||
|
audioThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(long timeDelta, Graphics g) {
|
||||||
|
for (int x = 0; x < WIDTH; x++) {
|
||||||
|
double val = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (magnitudes != null) {
|
||||||
|
double base = Math.exp(Math.log(magnitudes.length/2)/(WIDTH+3));
|
||||||
|
|
||||||
|
int intervalStart = (int) Math.pow(base,x+3),
|
||||||
|
intervalEnd = (int) Math.pow(base,x+4);
|
||||||
|
|
||||||
|
//System.out.println(x+" "+intervalStart+"-"+intervalEnd);
|
||||||
|
|
||||||
|
for(int magPos = intervalStart; magPos < intervalEnd; magPos++){
|
||||||
|
val += magnitudes[magPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
val /= intervalEnd-intervalStart;
|
||||||
|
/*
|
||||||
|
int magnitudesInPixel = (magnitudes.length / WIDTH) / 20;
|
||||||
|
|
||||||
|
for (int sample = 0; sample < magnitudesInPixel; sample++) {
|
||||||
|
val += magnitudes[x * magnitudesInPixel + sample];
|
||||||
|
}
|
||||||
|
val /= (double) magnitudes.length / WIDTH;*/
|
||||||
|
}
|
||||||
|
int y = (int) Math.min(HEIGHT,Math.round(Math.max(1, val+10))/10);
|
||||||
|
g.setColor(new Color(Math.abs(y) + 1, 2, 0));
|
||||||
|
g.drawRect(x, HEIGHT - y, 0, HEIGHT);
|
||||||
|
g.setColor(new Color(Math.abs(y), 0, 0));
|
||||||
|
g.drawRect(x, HEIGHT - y, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float[] decode(final byte[] buf, final AudioFormat format) {
|
||||||
|
final float[] fbuf = new float[buf.length / format.getFrameSize()];
|
||||||
|
for (int pos = 0; pos < buf.length; pos += format.getFrameSize()) {
|
||||||
|
final int sample = format.isBigEndian()
|
||||||
|
? byteToIntBigEndian(buf, pos, format.getFrameSize())
|
||||||
|
: byteToIntLittleEndian(buf, pos, format.getFrameSize());
|
||||||
|
// normalize to [0,1]
|
||||||
|
fbuf[pos / format.getFrameSize()] = sample / (Short.MAX_VALUE + 1.0f);
|
||||||
|
}
|
||||||
|
return fbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double[] toMagnitudes(final float[] realPart, final float[] imaginaryPart) {
|
||||||
|
final double[] powers = new double[realPart.length / 2];
|
||||||
|
for (int i = 0; i < powers.length; i++) {
|
||||||
|
powers[i] = Math.sqrt(realPart[i] * realPart[i] + imaginaryPart[i] * imaginaryPart[i]);
|
||||||
|
}
|
||||||
|
return powers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int byteToIntLittleEndian(final byte[] buf, final int offset, final int bytesPerSample) {
|
||||||
|
int sample = 0;
|
||||||
|
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
|
||||||
|
final int aByte = buf[offset + byteIndex] & 0xff;
|
||||||
|
sample += aByte << 8 * (byteIndex);
|
||||||
|
}
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int byteToIntBigEndian(final byte[] buf, final int offset, final int bytesPerSample) {
|
||||||
|
int sample = 0;
|
||||||
|
for (int byteIndex = 0; byteIndex < bytesPerSample; byteIndex++) {
|
||||||
|
final int aByte = buf[offset + byteIndex] & 0xff;
|
||||||
|
sample += aByte << (8 * (bytesPerSample - byteIndex - 1));
|
||||||
|
}
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
}
|
48
src/main/java/de/zuim/ledcontrol/effects/AudioVolume.java
Normal file
48
src/main/java/de/zuim/ledcontrol/effects/AudioVolume.java
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package de.zuim.ledcontrol.effects;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.zuim.ledcontrol.LEDControl.HEIGHT;
|
||||||
|
import static de.zuim.ledcontrol.LEDControl.WIDTH;
|
||||||
|
|
||||||
|
public class AudioVolume extends AudioFFT {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Audio Volume";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> volHistory = new ArrayList<>();
|
||||||
|
long timeDeltaSum = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(long timeDelta, Graphics g) {
|
||||||
|
timeDeltaSum += timeDelta;
|
||||||
|
|
||||||
|
if (fbuf != null) {
|
||||||
|
float avg = 0;
|
||||||
|
float max = 0;
|
||||||
|
for (float v : fbuf) {
|
||||||
|
avg += Math.abs(v);
|
||||||
|
if (v > max) {
|
||||||
|
max = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avg /= fbuf.length;
|
||||||
|
volHistory.add((int) (5 * avg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (volHistory.size() > WIDTH) {
|
||||||
|
volHistory.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < volHistory.size(); x++) {
|
||||||
|
|
||||||
|
g.setColor(new Color((int) ((Math.abs(volHistory.get(x)) + 1) * ((WIDTH - x) / (float) WIDTH)), 2, 0));
|
||||||
|
g.drawRect(WIDTH - x - 1, HEIGHT - volHistory.get(x), 0, HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,6 @@ public class ClockEffect implements LEDEffect {
|
||||||
SimpleDateFormat formatter2 = new SimpleDateFormat("ss");
|
SimpleDateFormat formatter2 = new SimpleDateFormat("ss");
|
||||||
String text2 = formatter2.format(date);
|
String text2 = formatter2.format(date);
|
||||||
|
|
||||||
g.clearRect(0,0,WIDTH,HEIGHT);
|
|
||||||
g.setFont(font);
|
g.setFont(font);
|
||||||
g.setColor(new Color(0,10-date.getMinutes()/6,date.getMinutes()/6));
|
g.setColor(new Color(0,10-date.getMinutes()/6,date.getMinutes()/6));
|
||||||
posOffset-=(4*getScale()*timeDelta)/1000000000.0;
|
posOffset-=(4*getScale()*timeDelta)/1000000000.0;
|
||||||
|
|
|
@ -1,58 +1,55 @@
|
||||||
package de.zuim.ledcontrol.effects;
|
package de.zuim.ledcontrol.effects;
|
||||||
|
|
||||||
import com.profesorfalken.jsensors.JSensors;
|
import com.tagtraum.jipes.math.FFTFactory;
|
||||||
import com.profesorfalken.jsensors.model.components.Component;
|
import com.tagtraum.jipes.math.Transform;
|
||||||
import com.profesorfalken.jsensors.model.components.Components;
|
|
||||||
import com.profesorfalken.jsensors.model.components.Cpu;
|
|
||||||
import com.profesorfalken.jsensors.model.sensors.Fan;
|
|
||||||
import com.profesorfalken.jsensors.model.sensors.Load;
|
|
||||||
import com.profesorfalken.jsensors.model.sensors.Temperature;
|
|
||||||
import de.zuim.ledcontrol.LEDEffect;
|
import de.zuim.ledcontrol.LEDEffect;
|
||||||
|
import oshi.SystemInfo;
|
||||||
|
import oshi.hardware.*;
|
||||||
|
|
||||||
|
import javax.sound.sampled.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.zuim.ledcontrol.LEDControl.WIDTH;
|
||||||
|
import static java.awt.image.ImageObserver.HEIGHT;
|
||||||
|
|
||||||
|
|
||||||
public class TemperatureEffect implements LEDEffect {
|
public class TemperatureEffect implements LEDEffect {
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return "Temperatur Sensoren";
|
return "Temperatur Sensoren";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
NetworkIF network = null;
|
||||||
public void render(long timeDelta, Graphics g) {
|
CentralProcessor cpu = null;
|
||||||
/*Components components = JSensors.get.components();
|
Sensors sensors = null;
|
||||||
|
|
||||||
List<Component> comps = new ArrayList<>(components.cpus);
|
@Override
|
||||||
comps.addAll(components.disks);
|
public void load() {
|
||||||
comps.addAll(components.gpus);
|
if(sensors == null){
|
||||||
comps.addAll(components.mobos);
|
SystemInfo si = new SystemInfo();
|
||||||
|
HardwareAbstractionLayer hal = si.getHardware();
|
||||||
|
network = hal.getNetworkIFs().get(0);
|
||||||
|
cpu = hal.getProcessor();
|
||||||
|
sensors = hal.getSensors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (comps != null) {
|
private Font font = new Font("Calibri", Font.BOLD, 12*getScale());
|
||||||
for (final Component c : comps) {
|
|
||||||
System.out.println("Found component: " + c.name);
|
|
||||||
if (c.sensors != null) {
|
|
||||||
System.out.println("Sensors: ");
|
|
||||||
|
|
||||||
//Print temperatures
|
@Override
|
||||||
List<Temperature> temps = c.sensors.temperatures;
|
public void render(long timeDelta, Graphics g) {
|
||||||
for (final Temperature temp : temps) {
|
|
||||||
System.out.println(temp.name + ": " + temp.value + " C");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print fan speed
|
String text = "---";
|
||||||
List<Fan> fans = c.sensors.fans;
|
if(sensors!=null){
|
||||||
for (final Fan fan : fans) {
|
text = Math.round(cpu.getSystemLoadAverage(1)[0]*100)+"%\n";
|
||||||
System.out.println(fan.name + ": " + fan.value + " RPM");
|
text+= sensors.getCpuTemperature();
|
||||||
}
|
}
|
||||||
//Print fan speed
|
|
||||||
List<Load> loads = c.sensors.loads;
|
g.setFont(font);
|
||||||
for (final Load load : loads) {
|
g.setColor(new Color(26, 9, 9));
|
||||||
System.out.println(load.name + ": " + load.value + " %");
|
g.drawString(text, 0, 8*getScale());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue