package nerdproject;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.ListSelectionEvent;
import org.encog.util.arrayutil.NormalizationAction;
import org.encog.util.arrayutil.NormalizedField;
import com.google.common.collect.Lists;
import com.illposed.osc.AbletonOSCListener;
import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortIn;
import com.illposed.osc.OSCPortOut;
public class LiveController {
private static LiveController instance = null;
private OSCPortIn receiver;
private OSCPortOut sender;
static Logger log = Logger.getLogger(LiveController.class.getName());
private LiveController(InetAddress liveOSCAddress, int liveOSCPort, int listeningPort) {
try {
log.log(Level.INFO, "Listening on port " + listeningPort);
receiver = new OSCPortIn(listeningPort);
sender = new OSCPortOut(liveOSCAddress, liveOSCPort);
log.log(Level.INFO, "Sending to port " + liveOSCPort);
log.log(Level.INFO, "Starting to listen...");
receiver.startListening();
} catch (Exception e) {
log.log(Level.SEVERE, "Error starting Live API");
e.printStackTrace();
}
}
public void playAll() {
this.sendMessage("/live/play");
}
public void stopAll() {
this.sendMessage("/live/stop");
}
/**
*
* @param trackNumber
* @param clipNumber
* @return
*/
public boolean isClipPlaying(int trackNumber, int clipNumber) {
OSCMessage message = this.sendReceive("/live/track/info", null, trackNumber);
TrackInfo trackInfo = new TrackInfo(message.getArguments());
return trackInfo.getClips().get(clipNumber).isPlaying();
}
public List<Device> getDevices(int track) {
OSCMessage devicesMessage = this.sendReceive("/live/devicelist", null, track);
ArrayList<Device> devices = new ArrayList<Device>();
Object[] arguments = devicesMessage.getArguments();
// (int track, int device, str name, ...)
List<List<Object>> pairs = Lists.partition(Arrays.asList(Arrays.copyOfRange(arguments, 1, arguments.length)), 2);
for (List<Object> pair : pairs) {
Device device = new Device((int) arguments[0], (int) pair.get(0), (String) pair.get(1));
devices.add(device);
}
return devices;
}
public List<Device> getMasterDevices() {
OSCMessage devicesMessage = this.sendReceive("/live/master/devicelist", null);
ArrayList<Device> devices = new ArrayList<Device>();
Object[] arguments = devicesMessage.getArguments();
// (int track, int device, str name, ...)
List<List<Object>> pairs = Lists.partition(Arrays.asList(Arrays.copyOfRange(arguments, 0, arguments.length)), 2);
for (List<Object> pair : pairs) {
Device device = new Device(-1, (int) pair.get(0), (String) pair.get(1));
devices.add(device);
}
return devices;
}
public List<DeviceParameter> getMasterDeviceParameters(int deviceNumber) {
// returns: /live/master/device (int device, int parameter int value,
// str name, ...)
OSCMessage message = this.sendReceive("/live/master/device", "/live/master/device", deviceNumber);
ArrayList<DeviceParameter> deviceParameters = new ArrayList<DeviceParameter>();
Object[] arguments = message.getArguments();
List<List<Object>> triples = Lists.partition(Arrays.asList(Arrays.copyOfRange(arguments, 1, arguments.length)), 3);
for (List<Object> triple : triples) {
Object value = triple.get(1);
DeviceParameter deviceParameter;
if (value instanceof Integer) {
deviceParameter = new DeviceParameter(-1, (int) arguments[1], (int) triple.get(0), (int) value,
(String) triple.get(2));
} else {
deviceParameter = new DeviceParameter(-1, (int) arguments[1], (int) triple.get(0), (float) value,
(String) triple.get(2));
}
deviceParameters.add(deviceParameter);
}
return deviceParameters;
}
public List<DeviceParameter> getDeviceParameters(int trackNumber, int deviceNumber) {
// returns (int track, int device, int parameter int value, str name,
// ...)
OSCMessage message = this.sendReceive("/live/device", "/live/device/allparam", trackNumber, deviceNumber);
Object[] arguments = message.getArguments();
ArrayList<DeviceParameter> deviceParameters = new ArrayList<DeviceParameter>();
// triples: (int track, int device, int parameter int value, str name,
// ...)
List<List<Object>> triples = Lists.partition(Arrays.asList(Arrays.copyOfRange(arguments, 2, arguments.length)), 3);
for (List<Object> triple : triples) {
Object value = triple.get(1);
DeviceParameter deviceParameter;
if (value instanceof Integer) {
deviceParameter = new DeviceParameter((int) arguments[0], (int) arguments[1], (int) triple.get(0), (int) value,
(String) triple.get(2));
} else {
deviceParameter = new DeviceParameter((int) arguments[0], (int) arguments[1], (int) triple.get(0), (float) value,
(String) triple.get(2));
}
deviceParameters.add(deviceParameter);
}
return deviceParameters;
}
public void setMasterDeviceParameter(int deviceNumber, int parameterNumber, float value) {
this.sendMessage("/live/master/device", new Object[] { deviceNumber, parameterNumber, value });
}
public void setDeviceParameter(int trackNumber, int deviceNumber, int parameterNumber, float value) {
this.sendMessage("/live/device", new Object[] { trackNumber, deviceNumber, parameterNumber, value });
}
public void setDeviceParameterNormalized(int trackNumber, int deviceNumber, int parameterNumber, float value) {
ParameterRange parameterRange = this.getDeviceParameterRange(trackNumber, deviceNumber, parameterNumber);
double normalizedValue = normalizeParameterInputValue(value, parameterRange);
this.setDeviceParameter(trackNumber, deviceNumber, parameterNumber, (float) normalizedValue);
}
public void setMasterDeviceParameterNormalized(int deviceNumber, int parameterNumber, float value) {
ParameterRange parameterRange = this.getMasterDeviceParameterRange(deviceNumber, parameterNumber);
double normalizedValue = normalizeParameterInputValue(value, parameterRange);
this.setMasterDeviceParameter(deviceNumber, parameterNumber, (float) normalizedValue);
}
protected double normalizeParameterInputValue(float value, ParameterRange parameterRange) {
NormalizedField normalizer = new NormalizedField(NormalizationAction.Normalize, null, 1.0, 0.0, parameterRange.getHigh(),
parameterRange.getLow());
double normalizedValue = normalizer.normalize(value);
return normalizedValue;
}
public DeviceParameter getDeviceParameter(int trackNumber, int deviceNumber, int parameterNumber) {
OSCMessage message = this.sendReceive("/live/device", "/live/device/param", new Object[] { trackNumber, deviceNumber,
parameterNumber });
Object[] m = message.getArguments();
// (track, device, param, p.value, str(p.name)
return new DeviceParameter((int) m[0], (int) m[1], (int) m[2], (float) m[3], (String) m[4]);
}
public float getDeviceParameterValue(int trackNumber, int deviceNumber, int parameterNumber) {
return this.getDeviceParameter(trackNumber, deviceNumber, parameterNumber).getValue();
}
public ParameterRange getMasterDeviceParameterRange(int deviceNumber, int parameterNumber) {
// return /live/master/device/range
OSCMessage message = this.sendReceive("/live/master/device/range", null, new Object[] { deviceNumber, parameterNumber });
// /live/master/device/range ( int device, int/float min, int/float
// max)
Object[] m = message.getArguments();
return new ParameterRange((float) m[2], (float) m[3]);
}
public ParameterRange getDeviceParameterRange(int trackNumber, int deviceNumber, int parameterNumber) {
OSCMessage message = this.sendReceive("/live/device/range", null, new Object[] { trackNumber, deviceNumber,
parameterNumber });
// /live/device/range (int track, int device, int/float min, int/float
// max)
Object[] m = message.getArguments();
return new ParameterRange((float) m[3], (float) m[4]);
}
public void playClip(int trackNumber, int clipNumber) {
this.sendMessage("/live/play/clip", new Object[] { trackNumber, clipNumber });
}
public boolean isMuted(int trackNumber) {
OSCMessage message = this.sendReceive("/live/mute", null, trackNumber);
Object[] arguments = message.getArguments();
Integer muteStatus = (Integer) arguments[1];
return muteStatus == 0 ? false : true;
}
public void muteTrack(int trackNumber) {
this.sendMessage("/live/mute", new Object[] { trackNumber, 1 });
}
public void unMuteTrack(int trackNumber) {
this.sendMessage("/live/mute", new Object[] { trackNumber, 0 });
}
public void toggleMute(int trackNumber) {
boolean isMuted = this.isMuted(trackNumber);
if (isMuted) {
// unmute
this.unMuteTrack(trackNumber);
} else {
// mute
this.muteTrack(trackNumber);
}
}
public void stopTrack(int trackNumber) {
this.sendMessage("/live/stop/track", new Object[] { trackNumber });
}
public void setTrackVolume(int trackNum, float volume) {
this.sendMessage("/live/volume", new Object[] { trackNum, volume });
}
public void setMasterVolume(float volume) {
this.sendMessage("/live/master/volume", new Object[] { volume });
}
public void setSend(int track, int sendNum, float value) {
this.sendMessage("/live/send", new Object[] { track, sendNum, value });
}
public float getSend(int track, int sendNum) {
OSCMessage message = this.sendReceive("/live/send", null, track, sendNum);
// [track, clip, send val]
return (Float) message.getArguments()[2];
}
// ##############################################################
private void sendMessage(String message, Object... params) {
Collection<Object> arrayList = new ArrayList<>();
if (params == null) {
params = new Object[] {};
}
arrayList.addAll(Arrays.asList(params));
OSCMessage oscMessage = new OSCMessage(message, arrayList);
try {
sender.send(oscMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Sends a message and waits for a response to an incoming address. If the
* receiveAddress parameter is null the message is the receive address.
*
* @param message
* @param receiveAddress
* @param params
* @return
*/
private OSCMessage sendReceive(String message, String receiveAddress, Object... params) {
AbletonOSCListener listener = new AbletonOSCListener();
Collection<Object> arrayList = new ArrayList<>();
if (params == null) {
params = new Object[] {};
}
arrayList.addAll(Arrays.asList(params));
if (receiveAddress == null)
receiver.addListener(message, listener);
else
receiver.addListener(receiveAddress, listener);
sendMessage(message, params);
while (!listener.isMessageReceived()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
OSCMessage response = listener.getMessage();
receiver.removeListener(message);
return response;
}
public synchronized static LiveController getInstance() {
if (instance == null) {
System.out.println("Working Directory = " + System.getProperty("user.dir"));
Properties properties = new Properties();
BufferedInputStream stream;
int incommingPort;
int liveOSCPort;
String hostIP;
InetAddress hostAddress;
try {
stream = new BufferedInputStream(new FileInputStream("configuration.properties"));
properties.load(stream);
stream.close();
incommingPort = Integer.valueOf(properties.getProperty("incommingPort"));
liveOSCPort = Integer.valueOf(properties.getProperty("liveOSCPort"));
hostIP = properties.getProperty("hostIP");
if (hostIP == "localhost") {
hostAddress = InetAddress.getLocalHost();
} else {
hostAddress = InetAddress.getByName(hostIP);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException("properties file cannot be read");
}
instance = new LiveController(hostAddress, liveOSCPort, incommingPort);
return instance;
}
return instance;
}
private void printObjectArray(Object[] arr) {
for (Object o : arr)
System.out.println(o);
}
}