package nodebox.function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import netP5.UdpClient; import nodebox.graphics.Point; import nodebox.node.NodeContext; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import oscP5.OscMessage; import ddf.minim.analysis.*; import ddf.minim.*; public class DeviceFunctions { public static final FunctionLibrary LIBRARY; static { LIBRARY = JavaLibrary.ofClass("device", DeviceFunctions.class, "mousePosition", "bufferPoints", "receiveOSC", "sendOSC", "audioAnalysis", "audioLogAvg", "audioWave", "beatDetect"); } public static Point mousePosition(NodeContext context) { Point p = (Point) context.getData().get("mouse.position"); if (p != null) { return p; } else { return Point.ZERO; } } public static List<Point> bufferPoints(Point point, long size, final List<Point> previousPoints) { ImmutableList.Builder<Point> newPoints = ImmutableList.builder(); if (previousPoints.size() == size) { newPoints.addAll(Iterables.skip(previousPoints, 1)); } else { newPoints.addAll(previousPoints); } newPoints.add(point); return newPoints.build(); } @SuppressWarnings("unchecked") public static List<Map<String, Object>> receiveOSC(String deviceName, String oscAddressPrefix, String arguments, NodeContext context) { Map<String, List<Object>> oscMessages = (Map<String, List<Object>>) context.getData().get(deviceName + ".messages"); if (oscMessages == null) return ImmutableList.of(); if (oscAddressPrefix.isEmpty()) return ImmutableList.of(); Pattern userPattern = Pattern.compile("(<[a-z0-9-_]+?(?::[ifs]|:string|:int|:float)?>)+"); Matcher upMatcher = userPattern.matcher(oscAddressPrefix); Map<String, String> itemTypeMap = new HashMap<String, String>(); ImmutableList.Builder<String> builder = ImmutableList.builder(); while (upMatcher.find()) { String s = upMatcher.group(0); if (s.startsWith("<") && s.endsWith(">")) s = s.substring(1, s.length() - 1); String[] tokens = s.split(":"); if (tokens.length == 2) { s = tokens[0]; itemTypeMap.put(s, tokens[1].substring(0, 1)); } else itemTypeMap.put(s, "s"); builder.add(s); } ImmutableList<String> messageData = builder.build(); ArrayList<String> argumentNames = new ArrayList<String>(); if (! arguments.isEmpty()) { for (String arg : arguments.split(",")) argumentNames.add(arg.trim()); } String convertedAddressPrefix = upMatcher.replaceAll("(XXXPLHXXX)"); if (! convertedAddressPrefix.endsWith("*")) convertedAddressPrefix = convertedAddressPrefix + "*"; convertedAddressPrefix = convertedAddressPrefix.replaceAll("\\*", ".*?"); convertedAddressPrefix = "^" + convertedAddressPrefix.replaceAll("(XXXPLHXXX)", "[^\\/]*") + "$"; Pattern lookupPattern = Pattern.compile(convertedAddressPrefix); ImmutableList.Builder<Map<String, Object>> b = ImmutableList.builder(); int maxArgs = 0; for (Map.Entry<String, List<Object>> e : oscMessages.entrySet()) { Matcher lpMatcher = lookupPattern.matcher(e.getKey()); if (lpMatcher.find()) maxArgs = Math.max(maxArgs, e.getValue().size()); } int argNamesSize = argumentNames.size(); for (int i = 0 ; i < maxArgs - argNamesSize ; i++) argumentNames.add("Column"); Map<String, Integer> argumentDuplicates = new HashMap<String, Integer>(); for (String arg : argumentNames) { if (argumentDuplicates.containsKey(arg)) argumentDuplicates.put(arg, 1); else argumentDuplicates.put(arg, 0); } ArrayList<String> newArgumentNames = new ArrayList<String>(); for (String arg : argumentNames) { if (argumentDuplicates.get(arg) > 0) { newArgumentNames.add(arg + argumentDuplicates.get(arg)); argumentDuplicates.put(arg, argumentDuplicates.get(arg) + 1); } else newArgumentNames.add(arg); } for (Map.Entry<String, List<Object>> e : oscMessages.entrySet()) { Matcher lpMatcher = lookupPattern.matcher(e.getKey()); if (lpMatcher.find()) { ImmutableMap.Builder<String, Object> mb = ImmutableMap.builder(); mb.put("address", e.getKey()); for (int i = 0; i < lpMatcher.groupCount(); i++) { String msg = messageData.get(i); String msgData = lpMatcher.group(i + 1); if (itemTypeMap.get(msg).equals("s")) { mb.put(msg, msgData); } else if (itemTypeMap.get(msg).equals("i")) { try { mb.put(msg, Integer.parseInt(msgData)); } catch (NumberFormatException nfe) { mb.put(msg, 0); } } else if (itemTypeMap.get(msg).equals("f")) { try { mb.put(msg, Double.parseDouble(msgData)); } catch (NumberFormatException nfe) { mb.put(msg, 0.0d); } } } int i = 0; for (Object o : e.getValue()) { String arg = newArgumentNames.get(i); mb.put(arg, o); i++; } for ( ; i < newArgumentNames.size(); i++) { mb.put(newArgumentNames.get(i), 0); } b.add(mb.build()); } } return b.build(); } public static void sendOSC(String ipAddress, long port, String oscAddress, Iterable<Double> oscArguments) { OscMessage message = new OscMessage(oscAddress); Iterator iterator = oscArguments.iterator(); while (iterator.hasNext()) { message.add(((Double) iterator.next()).floatValue()); } UdpClient c = new UdpClient(ipAddress, (int) port); c.send(message.getBytes()); } public static List<Double> audioAnalysis(String deviceName, String channel, long averages, NodeContext context) { AudioSource source = (AudioSource) context.getData().get(deviceName + ".source"); if (source == null) return ImmutableList.of(); FFT fft = new FFT( source.bufferSize(), source.sampleRate() ); fft.window(FFT.HANN); if (averages > 0) fft.linAverages((int) averages); if (channel.equals("left")) { fft.forward(source.left); } else if (channel.equals("right")) { fft.forward(source.right); } else { fft.forward(source.mix); } ImmutableList.Builder<Double> b = new ImmutableList.Builder<Double>(); if (averages == 0) { for (int i = 0; i < fft.specSize(); i++) b.add((double) fft.getBand(i)); } else { for(int i = 0; i < fft.avgSize(); i++) b.add((double) fft.getAvg(i)); } return b.build(); } public static List<Double> audioLogAvg(String deviceName, String channel, long baseFreq, long bandsPerOctave, NodeContext context) { AudioSource source = (AudioSource) context.getData().get(deviceName + ".source"); if (source == null) return ImmutableList.of(); FFT fft = new FFT( source.bufferSize(), source.sampleRate() ); fft.window(FFT.HANN); fft.logAverages((int) baseFreq, (int) bandsPerOctave); if (channel.equals("left")) { fft.forward(source.left); } else if (channel.equals("right")) { fft.forward(source.right); } else { fft.forward(source.mix); } ImmutableList.Builder<Double> b = new ImmutableList.Builder<Double>(); for(int i = 0; i < fft.avgSize(); i++) b.add((double) fft.getAvg(i)); return b.build(); } public static List<Map<String, Double>> audioWave(String deviceName, NodeContext context) { AudioSource source = (AudioSource) context.getData().get(deviceName + ".source"); if (source == null) return ImmutableList.of(); ImmutableList.Builder<Map<String, Double>> b = ImmutableList.builder(); for (int i = 0; i < source.bufferSize(); i++) { ImmutableMap.Builder<String, Double> mb = ImmutableMap.builder(); mb.put("left", (double) source.left.get(i)); mb.put("right", (double) source.right.get(i)); mb.put("mix", (double) source.mix.get(i)); b.add(mb.build()); } return b.build(); } public static Map<String, Boolean> beatDetect(String deviceName, NodeContext context) { BeatDetect beat = (BeatDetect) context.getData().get(deviceName + ".beat"); if (beat == null) return ImmutableMap.of(); ImmutableMap.Builder<String, Boolean> mb = ImmutableMap.builder(); mb.put("beat", beat.isOnset()); mb.put("kick", beat.isKick()); mb.put("snare", beat.isSnare()); mb.put("hat", beat.isHat()); return mb.build(); } }