├── .github └── FUNDING.yml ├── .gitignore ├── EnvelopLX ├── Effects.pde ├── EnvelopLX.pde ├── Model.pde ├── OSC.pde ├── Output.pde ├── Patterns.pde ├── UI.pde ├── Visuals.pde ├── code │ └── LXStudio.jar ├── data │ ├── envelop-logo-graphic-text.png │ ├── envelop-logo-graphic.png │ ├── envelop-logo-inverse-text.png │ ├── envelop-logo-inverse.png │ └── skymaps │ │ ├── AnotherPlanet │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── BlueSky │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── ColdNight │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── ColdSunset │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── DeepDusk │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── EpicPink │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── EpicSunset │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── NightMoon │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ ├── NightSky │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png │ │ └── OvercastLow │ │ ├── 0_Front+Z.png │ │ ├── 1_Back-Z.png │ │ ├── 2_Left+X.png │ │ ├── 3_Right-X.png │ │ ├── 4_Up+Y.png │ │ └── 5_Down-Y.png ├── export │ ├── README.txt │ └── encode.sh ├── lxpattern.js ├── midway.lxp ├── slee-midway-170727.lxp └── slee-midway-180216.lxp ├── LICENSE ├── README.md └── media └── enveloplx-screenshot.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: EnvelopSound 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .lxproject 3 | applet 4 | application.linux32 5 | application.linux64 6 | application.windows32 7 | application.windows64 8 | application.macosx 9 | EnvelopLX/export/20* 10 | 11 | .lxpreferences 12 | -------------------------------------------------------------------------------- /EnvelopLX/Effects.pde: -------------------------------------------------------------------------------- 1 | import java.awt.Color; 2 | 3 | @LXCategory("Texture") 4 | public class Sizzle extends LXEffect { 5 | 6 | public final CompoundParameter amount = new CompoundParameter("Amount", .5) 7 | .setDescription("Intensity of the effect"); 8 | 9 | public final CompoundParameter speed = new CompoundParameter("Speed", .5) 10 | .setDescription("Speed of the effect"); 11 | 12 | private final int[] buffer = new ModelBuffer(lx).getArray(); 13 | 14 | private float base = 0; 15 | 16 | public Sizzle(LX lx) { 17 | super(lx); 18 | addParameter("amount", this.amount); 19 | addParameter("speed", this.speed); 20 | } 21 | 22 | public void run(double deltaMs, double amount) { 23 | double amt = amount * this.amount.getValue(); 24 | if (amt > 0) { 25 | base += deltaMs * .01 * speed.getValuef(); 26 | for (int i = 0; i < this.buffer.length; ++i) { 27 | int val = (int) min(0xff, 500 * noise(i, base)); 28 | this.buffer[i] = 0xff000000 | val | (val << 8) | (val << 16); 29 | } 30 | MultiplyBlend.multiply(this.colors, this.buffer, amt, this.colors); 31 | } 32 | } 33 | } 34 | 35 | @LXCategory("Form") 36 | public static class Strobe extends LXEffect { 37 | 38 | public enum Waveshape { 39 | TRI, 40 | SIN, 41 | SQUARE, 42 | UP, 43 | DOWN 44 | }; 45 | 46 | public final EnumParameter mode = new EnumParameter("Shape", Waveshape.TRI); 47 | 48 | public final CompoundParameter frequency = (CompoundParameter) 49 | new CompoundParameter("Freq", 1, .05, 10).setUnits(LXParameter.Units.HERTZ); 50 | 51 | public final CompoundParameter depth = (CompoundParameter) 52 | new CompoundParameter("Depth", 0.5) 53 | .setDescription("Depth of the strobe effect"); 54 | 55 | private final SawLFO basis = new SawLFO(1, 0, new FunctionalParameter() { 56 | public double getValue() { 57 | return 1000 / frequency.getValue(); 58 | }}); 59 | 60 | public Strobe(LX lx) { 61 | super(lx); 62 | addParameter("mode", this.mode); 63 | addParameter("frequency", this.frequency); 64 | addParameter("depth", this.depth); 65 | startModulator(basis); 66 | } 67 | 68 | @Override 69 | protected void onEnable() { 70 | basis.setBasis(0).start(); 71 | } 72 | 73 | private LXWaveshape getWaveshape() { 74 | switch (this.mode.getEnum()) { 75 | case SIN: return LXWaveshape.SIN; 76 | case TRI: return LXWaveshape.TRI; 77 | case UP: return LXWaveshape.UP; 78 | case DOWN: return LXWaveshape.DOWN; 79 | case SQUARE: return LXWaveshape.SQUARE; 80 | } 81 | return LXWaveshape.SIN; 82 | } 83 | 84 | private final float[] hsb = new float[3]; 85 | 86 | @Override 87 | public void run(double deltaMs, double amount) { 88 | float amt = this.enabledDamped.getValuef() * this.depth.getValuef(); 89 | if (amt > 0) { 90 | float strobef = basis.getValuef(); 91 | strobef = (float) getWaveshape().compute(strobef); 92 | strobef = lerp(1, strobef, amt); 93 | if (strobef < 1) { 94 | if (strobef == 0) { 95 | for (int i = 0; i < colors.length; ++i) { 96 | colors[i] = LXColor.BLACK; 97 | } 98 | } else { 99 | for (int i = 0; i < colors.length; ++i) { 100 | LXColor.RGBtoHSB(colors[i], hsb); 101 | hsb[2] *= strobef; 102 | colors[i] = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]); 103 | } 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | @LXCategory("Color") 111 | public class LSD extends LXEffect { 112 | 113 | public final BoundedParameter scale = new BoundedParameter("Scale", 10, 5, 40); 114 | public final BoundedParameter speed = new BoundedParameter("Speed", 4, 1, 6); 115 | public final BoundedParameter range = new BoundedParameter("Range", 1, .7, 2); 116 | 117 | public LSD(LX lx) { 118 | super(lx); 119 | addParameter(scale); 120 | addParameter(speed); 121 | addParameter(range); 122 | this.enabledDampingAttack.setValue(500); 123 | this.enabledDampingRelease.setValue(500); 124 | } 125 | 126 | final float[] hsb = new float[3]; 127 | 128 | private float accum = 0; 129 | private int equalCount = 0; 130 | private float sign = 1; 131 | 132 | @Override 133 | public void run(double deltaMs, double amount) { 134 | float newAccum = (float) (accum + sign * deltaMs * speed.getValuef() / 4000.); 135 | if (newAccum == accum) { 136 | if (++equalCount >= 5) { 137 | equalCount = 0; 138 | sign = -sign; 139 | newAccum = accum + sign*.01; 140 | } 141 | } 142 | accum = newAccum; 143 | float sf = scale.getValuef() / 1000.; 144 | float rf = range.getValuef(); 145 | for (LXPoint p : model.points) { 146 | LXColor.RGBtoHSB(colors[p.index], hsb); 147 | float h = rf * noise(sf*p.x, sf*p.y, sf*p.z + accum); 148 | int c2 = LX.hsb(h * 360, 100, hsb[2]*100); 149 | if (amount < 1) { 150 | colors[p.index] = LXColor.lerp(colors[p.index], c2, amount); 151 | } else { 152 | colors[p.index] = c2; 153 | } 154 | } 155 | } 156 | } 157 | 158 | public class ArcsOff extends LXEffect { 159 | public ArcsOff(LX lx) { 160 | super(lx); 161 | } 162 | 163 | @Override 164 | public void run(double deltaMs, double amount) { 165 | if (amount > 0) { 166 | for (Arc arc : venue.arcs) { 167 | setColor(arc, #000000); 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /EnvelopLX/EnvelopLX.pde: -------------------------------------------------------------------------------- 1 | /** 2 | * EnvelopLX 3 | * 4 | * An interactive, sound-reactive lighting control system for the 5 | * Envelop spatial audio platform. 6 | * 7 | * https://github.com/EnvelopSound/EnvelopLX 8 | * http://www.envelop.us/ 9 | * 10 | * Copyright 2017- Mark C. Slee 11 | */ 12 | 13 | enum Environment { 14 | MIDWAY, 15 | SATELLITE 16 | } 17 | 18 | // Change this line if you want a different configuration! 19 | Environment environment = Environment.MIDWAY; 20 | LXStudio lx; 21 | Envelop envelop; 22 | EnvelopModel venue; 23 | 24 | final BooleanParameter videoRecording = new BooleanParameter("Recording", false); 25 | String videoRecordingFolder = null; 26 | int videoFrame = 0; 27 | float modifyFrameRate = -1; 28 | 29 | void settings() { 30 | size(1280, 960, P3D); 31 | } 32 | 33 | void setup() { 34 | frameRate(30); 35 | long setupStart = System.nanoTime(); 36 | // LX.logInitTiming(); 37 | venue = getModel(); 38 | try { 39 | lx = new LXStudio(this, venue); 40 | } catch (Exception x) { 41 | x.printStackTrace(); 42 | throw x; 43 | } 44 | 45 | videoRecording.addListener(new LXParameterListener() { 46 | public void onParameterChanged(LXParameter p) { 47 | if (videoRecording.isOn()) { 48 | // Crank CPU try to get more frames out 49 | modifyFrameRate = 60.1; 50 | videoFrame = 0; 51 | videoRecordingFolder = "export/" + new java.text.SimpleDateFormat("yyyy-MM-dd-HH'h'mm'm'ss's'").format(java.util.Calendar.getInstance().getTime()); 52 | } else { 53 | println("Video exported to " + videoRecordingFolder); 54 | modifyFrameRate = 30; 55 | videoRecordingFolder = null; 56 | } 57 | } 58 | }); 59 | 60 | registerMethod("pre", this); 61 | 62 | long setupFinish = System.nanoTime(); 63 | println("Total initialization time: " + ((setupFinish - setupStart) / 1000000) + "ms"); 64 | 65 | } 66 | 67 | public void initialize(LXStudio lx, LXStudio.UI ui) { 68 | envelop = new Envelop(lx, ui); 69 | lx.engine.registerComponent("envelop", envelop); 70 | lx.engine.addLoopTask(envelop); 71 | 72 | // Output drivers 73 | try { 74 | lx.engine.output.gammaCorrection.setValue(1); 75 | lx.engine.output.enabled.setValue(false); 76 | lx.addOutput(getOutput(lx)); 77 | } catch (Exception x) { 78 | throw new RuntimeException(x); 79 | } 80 | 81 | // OSC drivers 82 | try { 83 | lx.engine.osc.receiver(3344).addListener(new EnvelopOscControlListener(lx)); 84 | lx.engine.osc.receiver(3355).addListener(new EnvelopOscSourceListener()); 85 | lx.engine.osc.receiver(3366).addListener(new EnvelopOscMeterListener()); 86 | lx.engine.osc.receiver(3377).addListener(new EnvelopOscListener()); 87 | } catch (SocketException sx) { 88 | throw new RuntimeException(sx); 89 | } 90 | 91 | ui.theme.setPrimaryColor(#008ba0); 92 | ui.theme.setSecondaryColor(#00a08b); 93 | ui.theme.setAttentionColor(#a00044); 94 | ui.theme.setFocusColor(#0094aa); 95 | ui.theme.setSurfaceColor(#cc3300); 96 | 97 | } 98 | 99 | public void onUIReady(LXStudio lx, LXStudio.UI ui) { 100 | envelop.ui.onReady(lx, ui); 101 | } 102 | 103 | void pre() { 104 | envelop.ui.beforeDraw(); 105 | } 106 | 107 | void draw() { 108 | if (this.modifyFrameRate > 0) { 109 | frameRate(this.modifyFrameRate); 110 | this.modifyFrameRate = -1; 111 | } 112 | 113 | lx.ui.preview.depth.setValue(2); 114 | if (videoRecordingFolder != null) { 115 | lx.ui.preview.getGraphics().hint(ENABLE_ASYNC_SAVEFRAME); 116 | lx.ui.preview.getGraphics().save(this.videoRecordingFolder + "/" + String.format("%05d", videoFrame++)); 117 | } 118 | } 119 | 120 | public class Envelop extends LXRunnableComponent { 121 | 122 | // Envelop source sound object meters 123 | public final Source source; 124 | 125 | // Envelop decoded output meters for the columns 126 | public final Decode decode; 127 | 128 | // Envelop-specific UI customizations and objects 129 | public final UI ui; 130 | 131 | public Envelop(LX lx, LXStudio.UI ui) { 132 | super(lx, "Envelop"); 133 | addSubcomponent(this.source = new Source()); 134 | addSubcomponent(this.decode = new Decode()); 135 | source.start(); 136 | decode.start(); 137 | start(); 138 | 139 | this.ui = new UI(); 140 | } 141 | 142 | @Override 143 | public void run(double deltaMs) { 144 | source.loop(deltaMs); 145 | decode.loop(deltaMs); 146 | } 147 | 148 | private final static String KEY_SOURCE = "source"; 149 | private final static String KEY_DECODE = "decode"; 150 | private final static String KEY_UI = "ui"; 151 | 152 | @Override 153 | public void save(LX lx, JsonObject obj) { 154 | super.save(lx, obj); 155 | obj.add(KEY_SOURCE, LXSerializable.Utils.toObject(lx, this.source)); 156 | obj.add(KEY_DECODE, LXSerializable.Utils.toObject(lx, this.decode)); 157 | obj.add(KEY_UI, LXSerializable.Utils.toObject(lx, this.ui)); 158 | } 159 | 160 | @Override 161 | public void load(LX lx, JsonObject obj) { 162 | if (obj.has(KEY_SOURCE)) { 163 | this.source.load(lx, obj.getAsJsonObject(KEY_SOURCE)); 164 | } 165 | if (obj.has(KEY_DECODE)) { 166 | this.decode.load(lx, obj.getAsJsonObject(KEY_DECODE)); 167 | } 168 | if (obj.has(KEY_UI)) { 169 | this.ui.load(lx, obj.getAsJsonObject(KEY_UI)); 170 | } 171 | super.load(lx, obj); 172 | } 173 | 174 | protected abstract class Meter extends LXRunnableComponent { 175 | 176 | private static final double TIMEOUT = 1000; 177 | 178 | private final double[] targets; 179 | private final double[] timeouts; 180 | 181 | public final BoundedParameter gain = (BoundedParameter) 182 | new BoundedParameter("Gain", 0, -24, 24) 183 | .setDescription("Sets the dB gain of the meter") 184 | .setUnits(LXParameter.Units.DECIBELS); 185 | 186 | public final BoundedParameter range = (BoundedParameter) 187 | new BoundedParameter("Range", 24, 6, 96) 188 | .setDescription("Sets the dB range of the meter") 189 | .setUnits(LXParameter.Units.DECIBELS); 190 | 191 | public final BoundedParameter attack = (BoundedParameter) 192 | new BoundedParameter("Attack", 25, 0, 50) 193 | .setDescription("Sets the attack time of the meter response") 194 | .setUnits(LXParameter.Units.MILLISECONDS); 195 | 196 | public final BoundedParameter release = (BoundedParameter) 197 | new BoundedParameter("Release", 50, 0, 500) 198 | .setDescription("Sets the release time of the meter response") 199 | .setUnits(LXParameter.Units.MILLISECONDS); 200 | 201 | protected Meter(String label, int numChannels) { 202 | super(label); 203 | this.targets = new double[numChannels]; 204 | this.timeouts = new double[numChannels]; 205 | addParameter(this.gain); 206 | addParameter(this.range); 207 | addParameter(this.attack); 208 | addParameter(this.release); 209 | } 210 | 211 | public void run(double deltaMs) { 212 | NormalizedParameter[] channels = getChannels(); 213 | for (int i = 0; i < channels.length; ++i) { 214 | this.timeouts[i] += deltaMs; 215 | if (this.timeouts[i] > TIMEOUT) { 216 | this.targets[i] = 0; 217 | } 218 | double target = this.targets[i]; 219 | double value = channels[i].getValue(); 220 | double gain = (target >= value) ? Math.exp(-deltaMs / attack.getValue()) : Math.exp(-deltaMs / release.getValue()); 221 | channels[i].setValue(target + gain * (value - target)); 222 | } 223 | } 224 | 225 | public void setLevel(int index, OscMessage message) { 226 | double gainValue = this.gain.getValue(); 227 | double rangeValue = this.range.getValue(); 228 | this.targets[index] = constrain((float) (1 + (message.getFloat() + gainValue) / rangeValue), 0, 1); 229 | this.timeouts[index] = 0; 230 | } 231 | 232 | public void setLevels(OscMessage message) { 233 | double gainValue = this.gain.getValue(); 234 | double rangeValue = this.range.getValue(); 235 | for (int i = 0; i < this.targets.length; ++i) { 236 | this.targets[i] = constrain((float) (1 + (message.getFloat() + gainValue) / rangeValue), 0, 1); 237 | this.timeouts[i] = 0; 238 | } 239 | } 240 | 241 | protected abstract NormalizedParameter[] getChannels(); 242 | } 243 | 244 | public class Source extends Meter { 245 | public static final int NUM_CHANNELS = 16; 246 | 247 | class Channel extends NormalizedParameter { 248 | 249 | public final int index; 250 | public boolean active; 251 | public final PVector xyz = new PVector(); 252 | 253 | float tx; 254 | float ty; 255 | float tz; 256 | 257 | Channel(int i) { 258 | super("Source-" + (i+1)); 259 | this.index = i+1; 260 | this.active = false; 261 | } 262 | } 263 | 264 | public final Channel[] channels = new Channel[NUM_CHANNELS]; 265 | 266 | Source() { 267 | super("Source", NUM_CHANNELS); 268 | for (int i = 0; i < channels.length; ++i) { 269 | addParameter(channels[i] = new Channel(i)); 270 | } 271 | } 272 | 273 | public NormalizedParameter[] getChannels() { 274 | return this.channels; 275 | } 276 | } 277 | 278 | public class Decode extends Meter { 279 | 280 | public static final int NUM_CHANNELS = 8; 281 | public final NormalizedParameter[] channels = new NormalizedParameter[NUM_CHANNELS]; 282 | 283 | Decode() { 284 | super("Decode", NUM_CHANNELS); 285 | for (int i = 0; i < channels.length; ++i) { 286 | addParameter(channels[i] = new NormalizedParameter("Decode-" + (i+1))); 287 | } 288 | } 289 | 290 | public NormalizedParameter[] getChannels() { 291 | return this.channels; 292 | } 293 | } 294 | 295 | public class UI implements LXSerializable { 296 | public final Camera camera; 297 | 298 | public final List visuals = new ArrayList(); 299 | 300 | private UI() { 301 | this.camera = new Camera(); 302 | addVisual(new UISkybox()); 303 | addVisual(getUIVenue()); 304 | addVisual(new UIOrbs()); 305 | addVisual(new UISoundObjects()); 306 | addVisual(new UIFloatingDiscs()); 307 | } 308 | 309 | protected void beforeDraw() { 310 | for (UIVisual visual : this.visuals) { 311 | if (visual.isVisible()) { 312 | visual.beforeDraw(lx.ui); 313 | } 314 | } 315 | } 316 | 317 | protected void addVisual(UIVisual visual) { 318 | if (this.visuals.contains(visual)) { 319 | throw new IllegalStateException("Cannot add two copies of same visual object: " + visual); 320 | } 321 | this.visuals.add(visual); 322 | } 323 | 324 | public void onReady(LX lx, LXStudio.UI ui) { 325 | ui.leftPane.audio.setVisible(false); 326 | for (UIVisual visual : this.visuals) { 327 | ui.preview.addComponent(visual); 328 | } 329 | 330 | ui.preview.setPhi(PI/32).setMinRadius(2*FEET).setMaxRadius(48*FEET); 331 | new UIEnvelopSource(ui, ui.leftPane.global.getContentWidth()).addToContainer(ui.leftPane.global, 2); 332 | new UIEnvelopDecode(ui, ui.leftPane.global.getContentWidth()).addToContainer(ui.leftPane.global, 3); 333 | new UIVisuals(ui, ui.leftPane.global.getContentWidth()).addToContainer(ui.leftPane.global); 334 | ui.addLoopTask(this.camera); 335 | } 336 | 337 | private static final String KEY_POINTS = "points"; 338 | private static final String KEY_VISUALS = "visuals"; 339 | 340 | @Override 341 | public void save(LX lx, JsonObject obj) { 342 | obj.addProperty(KEY_POINTS, ((LXStudio) lx).ui.preview.pointCloud.isVisible()); 343 | obj.add(KEY_VISUALS, LXSerializable.Utils.toArray(lx, this.visuals)); 344 | } 345 | 346 | @Override 347 | public void load(LX lx, JsonObject obj) { 348 | LXSerializable.Utils.loadBoolean(((LXStudio) lx).ui.preview.pointCloud.visible, obj, KEY_POINTS); 349 | if (obj.has(KEY_VISUALS)) { 350 | JsonArray visualArr = obj.get(KEY_VISUALS).getAsJsonArray(); 351 | for (JsonElement visualElement : visualArr) { 352 | JsonObject visualObj = (JsonObject) visualElement; 353 | String visualClass = visualObj.get(UIVisual.KEY_CLASS).getAsString(); 354 | for (UIVisual visual : this.visuals) { 355 | if (visual.getClass().getName().equals(visualClass)) { 356 | visual.load(lx, visualObj); 357 | } 358 | } 359 | } 360 | } 361 | } 362 | 363 | public class Camera extends LXRunnableComponent { 364 | 365 | public final BoundedParameter phiRange = 366 | new BoundedParameter("Elevation Range", 15, 0, 90) 367 | .setDescription("Sets the maximum range of the camera's elevation rotation"); 368 | 369 | public final BoundedParameter thetaPeriod = 370 | new BoundedParameter("Rotation Speed", .5) 371 | .setDescription("Sets the speed of the camera's horizontal rotation"); 372 | 373 | public final BoundedParameter radiusDepth = 374 | new BoundedParameter("Radial Depth", 20, 0, 30) 375 | .setDescription("Sets the level of the camera radial distance animation"); 376 | 377 | public final BoundedParameter radiusPeriod = 378 | new BoundedParameter("Depth Speed", .5) 379 | .setDescription("Sets the speed of the camera's distance animation"); 380 | 381 | private final SinLFO theta = new SinLFO(-TWO_PI, TWO_PI, new FunctionalParameter() { 382 | public double getValue() { 383 | return lerp(5000000, 200000, thetaPeriod.getValuef()); 384 | } 385 | }); 386 | 387 | private final SinLFO phi = new SinLFO(0, 1, 99000); 388 | 389 | private static final float MIN_RADIUS = 10*FEET; 390 | 391 | private final SinLFO radius = new SinLFO(MIN_RADIUS, new FunctionalParameter() { 392 | public double getValue() { 393 | return MIN_RADIUS + radiusDepth.getValue() * FEET; 394 | } 395 | }, new FunctionalParameter() { 396 | public double getValue() { 397 | return lerp(500000, 10000, radiusPeriod.getValuef()); 398 | } 399 | }); 400 | 401 | 402 | public Camera() { 403 | this.theta.randomBasis().start(); 404 | this.phi.randomBasis().start(); 405 | this.radius.randomBasis().start(); 406 | this.running.addListener(new LXParameterListener() { 407 | public void onParameterChanged(LXParameter p) { 408 | if (running.isOn()) { 409 | PVector eye = lx.ui.preview.getEye(); 410 | theta.setValue(atan2(eye.x, -eye.z)); 411 | phi.setValue(atan2(eye.y, dist(0, 0, eye.x, eye.z))); 412 | radius.setValue(eye.mag()); 413 | } 414 | } 415 | }); 416 | } 417 | 418 | @Override 419 | public void run(double deltaMs) { 420 | this.theta.loop(deltaMs); 421 | this.phi.loop(deltaMs); 422 | this.radius.loop(deltaMs); 423 | float phi = this.phi.getValuef(); 424 | lx.ui.preview.setTheta(this.theta.getValue()); 425 | lx.ui.preview.setPhi(phi * phi * this.phiRange.getValuef() * PI / 180f); 426 | lx.ui.preview.setRadius(this.radius.getValuef()); 427 | } 428 | } 429 | } 430 | 431 | } 432 | -------------------------------------------------------------------------------- /EnvelopLX/Model.pde: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Collections; 3 | import java.util.List; 4 | 5 | final static float INCHES = 1; 6 | final static float FEET = 12*INCHES; 7 | 8 | EnvelopModel getModel() { 9 | switch (environment) { 10 | case SATELLITE: return new Satellite(); 11 | case MIDWAY: return new Midway(); 12 | } 13 | return null; 14 | } 15 | 16 | static abstract class EnvelopModel extends LXModel { 17 | 18 | static abstract class Config { 19 | 20 | static class Rail { 21 | public final PVector position; 22 | public final int numPoints; 23 | public final float pointSpacing; 24 | 25 | Rail(PVector position, int numPoints, float pointSpacing) { 26 | this.position = position; 27 | this.numPoints = numPoints; 28 | this.pointSpacing = pointSpacing; 29 | } 30 | } 31 | 32 | public abstract PVector[] getColumns(); 33 | public abstract float[] getArcs(); 34 | public abstract Rail[] getRails(); 35 | } 36 | 37 | public final List columns; 38 | public final List arcs; 39 | public final List rails; 40 | public final List railPoints; 41 | 42 | protected EnvelopModel(Config config) { 43 | super(new Fixture(config)); 44 | Fixture f = (Fixture) fixtures.get(0); 45 | columns = Collections.unmodifiableList(Arrays.asList(f.columns)); 46 | final Arc[] arcs = new Arc[columns.size() * config.getArcs().length]; 47 | final Rail[] rails = new Rail[columns.size() * config.getRails().length]; 48 | final List railPoints = new ArrayList(); 49 | int a = 0; 50 | int r = 0; 51 | for (Column column : columns) { 52 | for (Arc arc : column.arcs) { 53 | arcs[a++] = arc; 54 | } 55 | for (Rail rail : column.rails) { 56 | rails[r++] = rail; 57 | for (LXPoint p : rail.points) { 58 | railPoints.add(p); 59 | } 60 | } 61 | } 62 | this.arcs = Collections.unmodifiableList(Arrays.asList(arcs)); 63 | this.rails = Collections.unmodifiableList(Arrays.asList(rails)); 64 | this.railPoints = Collections.unmodifiableList(railPoints); 65 | } 66 | 67 | private static class Fixture extends LXAbstractFixture { 68 | 69 | final Column[] columns; 70 | 71 | Fixture(Config config) { 72 | columns = new Column[config.getColumns().length]; 73 | LXTransform transform = new LXTransform(); 74 | int ci = 0; 75 | for (PVector pv : config.getColumns()) { 76 | transform.push(); 77 | transform.translate(pv.x, 0, pv.y); 78 | float theta = atan2(pv.y, pv.x) - HALF_PI; 79 | transform.rotateY(-theta); 80 | addPoints(columns[ci] = new Column(config, ci, transform, theta)); 81 | transform.pop(); 82 | ++ci; 83 | } 84 | } 85 | } 86 | } 87 | 88 | static class Midway extends EnvelopModel { 89 | 90 | final static float WIDTH = 20*FEET + 10.25*INCHES; 91 | final static float DEPTH = 41*FEET + 6*INCHES; 92 | 93 | final static float INNER_OFFSET_X = WIDTH/2. - 1*FEET - 8.75*INCHES; 94 | final static float OUTER_OFFSET_X = WIDTH/2. - 5*FEET - 1.75*INCHES; 95 | final static float INNER_OFFSET_Z = -DEPTH/2. + 15*FEET + 10.75*INCHES; 96 | final static float OUTER_OFFSET_Z = -DEPTH/2. + 7*FEET + 8*INCHES; 97 | 98 | final static float SUB_OFFSET_X = 36*INCHES; 99 | final static float SUB_OFFSET_Z = 20*INCHES; 100 | 101 | final static EnvelopModel.Config CONFIG = new EnvelopModel.Config() { 102 | public PVector[] getColumns() { 103 | return COLUMN_POSITIONS; 104 | } 105 | 106 | public float[] getArcs() { 107 | return ARC_POSITIONS; 108 | } 109 | 110 | public EnvelopModel.Config.Rail[] getRails() { 111 | return RAILS; 112 | } 113 | }; 114 | 115 | final static int NUM_POINTS = 109; 116 | final static float POINT_SPACING = 1.31233596*INCHES; 117 | 118 | final static EnvelopModel.Config.Rail[] RAILS = { 119 | new EnvelopModel.Config.Rail(new PVector(-1, 0, 0), NUM_POINTS, POINT_SPACING), 120 | new EnvelopModel.Config.Rail(new PVector(1, 0, 0), NUM_POINTS, POINT_SPACING) 121 | }; 122 | 123 | final static float[] ARC_POSITIONS = { 1/3.f, 2/3.f }; 124 | 125 | final static PVector[] COLUMN_POSITIONS = { 126 | new PVector(OUTER_OFFSET_X, OUTER_OFFSET_Z, 101), 127 | new PVector(INNER_OFFSET_X, INNER_OFFSET_Z, 102), 128 | new PVector(INNER_OFFSET_X, -INNER_OFFSET_Z, 103), 129 | new PVector(OUTER_OFFSET_X, -OUTER_OFFSET_Z, 104), 130 | new PVector(-OUTER_OFFSET_X, -OUTER_OFFSET_Z, 105), 131 | new PVector(-INNER_OFFSET_X, -INNER_OFFSET_Z, 106), 132 | new PVector(-INNER_OFFSET_X, INNER_OFFSET_Z, 107), 133 | new PVector(-OUTER_OFFSET_X, OUTER_OFFSET_Z, 108) 134 | }; 135 | 136 | final static PVector[] SUB_POSITIONS = { 137 | COLUMN_POSITIONS[0].copy().add(SUB_OFFSET_X, SUB_OFFSET_Z), 138 | COLUMN_POSITIONS[3].copy().add(SUB_OFFSET_X, -SUB_OFFSET_Z), 139 | COLUMN_POSITIONS[4].copy().add(-SUB_OFFSET_X, -SUB_OFFSET_Z), 140 | COLUMN_POSITIONS[7].copy().add(-SUB_OFFSET_X, SUB_OFFSET_Z), 141 | }; 142 | 143 | Midway() { 144 | super(CONFIG); 145 | } 146 | } 147 | 148 | static class Satellite extends EnvelopModel { 149 | 150 | final static float EDGE_LENGTH = 12*FEET; 151 | final static float HALF_EDGE_LENGTH = EDGE_LENGTH / 2; 152 | final static float INCIRCLE_RADIUS = HALF_EDGE_LENGTH + EDGE_LENGTH / sqrt(2); 153 | 154 | final static PVector[] PLATFORM_POSITIONS = { 155 | new PVector( HALF_EDGE_LENGTH, -INCIRCLE_RADIUS, 101), 156 | new PVector( INCIRCLE_RADIUS, -HALF_EDGE_LENGTH, 102), 157 | new PVector( INCIRCLE_RADIUS, HALF_EDGE_LENGTH, 103), 158 | new PVector( HALF_EDGE_LENGTH, INCIRCLE_RADIUS, 104), 159 | new PVector(-HALF_EDGE_LENGTH, INCIRCLE_RADIUS, 105), 160 | new PVector(-INCIRCLE_RADIUS, HALF_EDGE_LENGTH, 106), 161 | new PVector(-INCIRCLE_RADIUS, -HALF_EDGE_LENGTH, 107), 162 | new PVector(-HALF_EDGE_LENGTH, -INCIRCLE_RADIUS, 108) 163 | }; 164 | 165 | final static PVector[] COLUMN_POSITIONS; 166 | static { 167 | float ratio = (INCIRCLE_RADIUS - Column.RADIUS - 6*INCHES) / INCIRCLE_RADIUS; 168 | COLUMN_POSITIONS = new PVector[PLATFORM_POSITIONS.length]; 169 | for (int i = 0; i < PLATFORM_POSITIONS.length; ++i) { 170 | COLUMN_POSITIONS[i] = PLATFORM_POSITIONS[i].copy().mult(ratio); 171 | } 172 | }; 173 | 174 | final static float POINT_SPACING = 1.31233596*INCHES; 175 | 176 | final static EnvelopModel.Config.Rail[] RAILS = { 177 | new EnvelopModel.Config.Rail(new PVector(-1, 0, 0), 108, POINT_SPACING), 178 | new EnvelopModel.Config.Rail(new PVector(0, 0, 1), 100, POINT_SPACING), 179 | new EnvelopModel.Config.Rail(new PVector(1, 0, 0), 108, POINT_SPACING) 180 | }; 181 | 182 | final static float[] ARC_POSITIONS = { }; 183 | 184 | final static EnvelopModel.Config CONFIG = new EnvelopModel.Config() { 185 | public PVector[] getColumns() { 186 | return COLUMN_POSITIONS; 187 | } 188 | 189 | public float[] getArcs() { 190 | return ARC_POSITIONS; 191 | } 192 | 193 | public EnvelopModel.Config.Rail[] getRails() { 194 | return RAILS; 195 | } 196 | }; 197 | 198 | Satellite() { 199 | super(CONFIG); 200 | } 201 | } 202 | 203 | 204 | static class Column extends LXModel { 205 | 206 | final static float SPEAKER_ANGLE = 22./180.*PI; 207 | 208 | final static float HEIGHT = Rail.HEIGHT; 209 | final static float RADIUS = 20*INCHES; 210 | 211 | final int index; 212 | final float azimuth; 213 | 214 | final List arcs; 215 | final List rails; 216 | final List railPoints; 217 | 218 | Column(EnvelopModel.Config config, int index, LXTransform transform, float azimuth) { 219 | super(new Fixture(config, transform)); 220 | this.index = index; 221 | this.azimuth = azimuth; 222 | Fixture f = (Fixture) fixtures.get(0); 223 | this.arcs = Collections.unmodifiableList(Arrays.asList(f.arcs)); 224 | this.rails = Collections.unmodifiableList(Arrays.asList(f.rails)); 225 | List railPoints = new ArrayList(); 226 | for (Rail rail : this.rails) { 227 | for (LXPoint p : rail.points) { 228 | railPoints.add(p); 229 | } 230 | } 231 | this.railPoints = Collections.unmodifiableList(railPoints); 232 | } 233 | 234 | private static class Fixture extends LXAbstractFixture { 235 | final Arc[] arcs; 236 | final Rail[] rails; 237 | 238 | Fixture(EnvelopModel.Config config, LXTransform transform) { 239 | 240 | // Transform begins on the floor at center of column 241 | transform.push(); 242 | 243 | // Rails 244 | this.rails = new Rail[config.getRails().length]; 245 | for (int i = 0; i < config.getRails().length; ++i) { 246 | EnvelopModel.Config.Rail rail = config.getRails()[i]; 247 | transform.translate(RADIUS * rail.position.x, 0, RADIUS * rail.position.z); 248 | addPoints(rails[i] = new Rail(rail, transform)); 249 | transform.translate(-RADIUS * rail.position.x, 0, -RADIUS * rail.position.z); 250 | } 251 | 252 | // Arcs 253 | this.arcs = new Arc[config.getArcs().length]; 254 | for (int i = 0; i < config.getArcs().length; ++i) { 255 | float y = config.getArcs()[i] * HEIGHT; 256 | transform.translate(0, y, 0); 257 | addPoints(arcs[i] = new Arc(transform)); 258 | transform.translate(0, -y, 0); 259 | } 260 | 261 | transform.pop(); 262 | } 263 | } 264 | } 265 | 266 | static class Rail extends LXModel { 267 | 268 | final static int LEFT = 0; 269 | final static int RIGHT = 1; 270 | 271 | final static float HEIGHT = 12*FEET; 272 | 273 | public final float theta; 274 | 275 | Rail(EnvelopModel.Config.Rail rail, LXTransform transform) { 276 | super(new Fixture(rail, transform)); 277 | this.theta = atan2(transform.z(), transform.x()); 278 | } 279 | 280 | private static class Fixture extends LXAbstractFixture { 281 | Fixture(EnvelopModel.Config.Rail rail, LXTransform transform) { 282 | transform.push(); 283 | transform.translate(0, rail.pointSpacing / 2., 0); 284 | for (int i = 0; i < rail.numPoints; ++i) { 285 | addPoint(new LXPoint(transform)); 286 | transform.translate(0, rail.pointSpacing, 0); 287 | } 288 | transform.pop(); 289 | } 290 | } 291 | } 292 | 293 | static class Arc extends LXModel { 294 | 295 | final static float RADIUS = Column.RADIUS; 296 | 297 | final static int BOTTOM = 0; 298 | final static int TOP = 1; 299 | 300 | final static int NUM_POINTS = 34; 301 | final static float POINT_ANGLE = PI / NUM_POINTS; 302 | 303 | Arc(LXTransform transform) { 304 | super(new Fixture(transform)); 305 | } 306 | 307 | private static class Fixture extends LXAbstractFixture { 308 | Fixture(LXTransform transform) { 309 | transform.push(); 310 | transform.rotateY(-POINT_ANGLE / 2.); 311 | for (int i = 0; i < NUM_POINTS; ++i) { 312 | transform.translate(-RADIUS, 0, 0); 313 | addPoint(new LXPoint(transform)); 314 | transform.translate(RADIUS, 0, 0); 315 | transform.rotateY(-POINT_ANGLE); 316 | } 317 | transform.pop(); 318 | } 319 | } 320 | } -------------------------------------------------------------------------------- /EnvelopLX/OSC.pde: -------------------------------------------------------------------------------- 1 | import java.net.InetAddress; 2 | import java.util.Map; 3 | 4 | class EnvelopOscListener implements LXOscListener { 5 | 6 | private int getIndex(OscMessage message) { 7 | String[] parts = message.getAddressPattern().toString().split("/"); 8 | try { 9 | return Integer.valueOf(parts[parts.length - 1]); 10 | } catch (Exception x) { 11 | return -1; 12 | } 13 | } 14 | 15 | public void oscMessage(OscMessage message) { 16 | if (message.matches("/envelop/tempo/beat")) { 17 | lx.tempo.trigger(message.getInt()-1); 18 | } else if (message.matches("/envelop/tempo/bpm")) { 19 | lx.tempo.setBpm(message.getDouble()); 20 | } else if (message.matches("/envelop/meter/decode")) { 21 | envelop.decode.setLevels(message); 22 | } else if (message.hasPrefix("/envelop/meter/source")) { 23 | int index = getIndex(message) - 1; 24 | if (index >= 0 && index < envelop.source.channels.length) { 25 | envelop.source.setLevel(index, message); 26 | } 27 | } else if (message.hasPrefix("/envelop/source")) { 28 | int index = getIndex(message) - 1; 29 | if (index >= 0 && index < envelop.source.channels.length) { 30 | Envelop.Source.Channel channel = envelop.source.channels[index]; 31 | float rx = 0, ry = 0, rz = 0; 32 | String type = message.getString(); 33 | if (type.equals("xyz")) { 34 | rx = message.getFloat(); 35 | ry = message.getFloat(); 36 | rz = message.getFloat(); 37 | } else if (type.equals("aed")) { 38 | float azimuth = message.getFloat() / 180. * PI; 39 | float elevation = message.getFloat() / 180. * PI; 40 | float radius = message.getFloat(); 41 | rx = radius * cos(-azimuth + HALF_PI) * cos(elevation); 42 | ry = radius * sin(-azimuth + HALF_PI) * cos(elevation); 43 | rz = radius * sin(elevation); 44 | } 45 | channel.xyz.set(rx, ry, rz); 46 | channel.active = true; 47 | channel.tx = venue.cx + rx * venue.xRange/2; 48 | channel.ty = venue.cy + rz * venue.yRange/2; 49 | channel.tz = venue.cz + ry * venue.zRange/2; 50 | } 51 | } 52 | } 53 | } 54 | 55 | class EnvelopOscMeterListener implements LXOscListener { 56 | public void oscMessage(OscMessage message) { 57 | if (message.matches("/server/dsp/meter/input")) { 58 | envelop.source.setLevels(message); 59 | } else if (message.matches("/server/dsp/meter/decoded")) { 60 | envelop.decode.setLevels(message); 61 | } else { 62 | println(message); 63 | } 64 | } 65 | } 66 | 67 | class EnvelopOscSourceListener implements LXOscListener { 68 | 69 | public void oscMessage(OscMessage message) { 70 | String[] parts = message.getAddressPattern().toString().split("/"); 71 | if (parts.length == 4) { 72 | if (parts[1].equals("source")) { 73 | try { 74 | int index = Integer.parseInt(parts[2]) - 1; 75 | if (index >= 0 && index < envelop.source.channels.length) { 76 | Envelop.Source.Channel channel = envelop.source.channels[index]; 77 | if (parts[3].equals("active")) { 78 | channel.active = message.getFloat() > 0; 79 | } else if (parts[3].equals("xyz")) { 80 | float rx = message.getFloat(); 81 | float ry = message.getFloat(); 82 | float rz = message.getFloat(); 83 | channel.xyz.set(rx, ry, rz); 84 | channel.tx = venue.cx + rx * venue.xRange/2; 85 | channel.ty = venue.cy + rz * venue.yRange/2; 86 | channel.tz = venue.cz + ry * venue.zRange/2; 87 | } 88 | } else { 89 | println("Invalid source channel message: " + message); 90 | } 91 | } catch (NumberFormatException nfx) {} 92 | } 93 | } 94 | } 95 | } 96 | 97 | static class EnvelopOscControlListener implements LXOscListener { 98 | 99 | private final LX lx; 100 | 101 | private final Map clients = 102 | new HashMap(); 103 | 104 | EnvelopOscControlListener(LX lx) { 105 | this.lx = lx; 106 | } 107 | 108 | public void oscMessage(OscMessage message) { 109 | println("[" + message.getSource() + "] " + message); 110 | EnvelopOscClient client = clients.get(message.getSource()); 111 | if (client == null) { 112 | if (message.matches("/lx/register/envelop")) { 113 | try { 114 | clients.put(message.getSource(), new EnvelopOscClient(lx, message.getSource())); 115 | } catch (SocketException sx) { 116 | sx.printStackTrace(); 117 | } 118 | } 119 | } else { 120 | client.oscMessage(message); 121 | } 122 | } 123 | } 124 | 125 | static class EnvelopOscClient implements LXOscListener { 126 | 127 | private final static int NUM_KNOBS = 12; 128 | private final KnobListener[] knobs = new KnobListener[NUM_KNOBS]; 129 | 130 | private final LX lx; 131 | private final LXOscEngine.Transmitter transmitter; 132 | 133 | EnvelopOscClient(LX lx, InetAddress source) throws SocketException { 134 | this.lx = lx; 135 | this.transmitter = lx.engine.osc.transmitter(source, 3434); 136 | 137 | setupListeners(); 138 | register(); 139 | } 140 | 141 | private class KnobListener implements LXParameterListener { 142 | 143 | private final int index; 144 | private BoundedParameter parameter; 145 | 146 | private KnobListener(int index) { 147 | this.index = index; 148 | } 149 | 150 | void register(BoundedParameter parameter) { 151 | if (this.parameter != null) { 152 | this.parameter.removeListener(this); 153 | } 154 | this.parameter = parameter; 155 | if (this.parameter != null){ 156 | this.parameter.addListener(this); 157 | } 158 | } 159 | 160 | void set(double value) { 161 | if (this.parameter != null) { 162 | this.parameter.setNormalized(value); 163 | } 164 | } 165 | 166 | public void onParameterChanged(LXParameter p) { 167 | sendKnobs(); 168 | } 169 | } 170 | 171 | private void setupListeners() { 172 | // Build knob listener objects 173 | for (int i = 0; i < NUM_KNOBS; ++i) { 174 | this.knobs[i] = new KnobListener(i); 175 | } 176 | 177 | // Register to listen for pattern changes 178 | lx.engine.getChannel(0).addListener(new LXChannel.AbstractListener() { 179 | public void patternDidChange(LXChannel channel, LXPattern pattern) { 180 | int i = 0; 181 | for (LXPattern p : channel.getPatterns()) { 182 | if (p == pattern) { 183 | sendMessage("/lx/pattern/active", i); 184 | break; 185 | } 186 | ++i; 187 | } 188 | registerKnobs(pattern); 189 | sendKnobs(); 190 | } 191 | }); 192 | } 193 | 194 | public void oscMessage(OscMessage message) { 195 | if (message.matches("/lx/register/envelop")) { 196 | register(); 197 | } else if (message.matches("/lx/pattern/index")) { 198 | lx.goIndex(message.get().toInt()); 199 | } else if (message.matches("/lx/pattern/parameter")) { 200 | // TODO(mcslee): sanitize input 201 | knobs[message.getInt()].set(message.getDouble()); 202 | } else if (message.matches("/lx/tempo/bpm")) { 203 | lx.tempo.setBpm(message.getDouble()); 204 | println("Set bpm to: " + lx.tempo.bpm()); 205 | } else if (message.matches("/lx/tempo/tap")) { 206 | lx.tempo.trigger(false); 207 | } 208 | } 209 | 210 | void register() { 211 | sendMessage("/lx/register"); 212 | sendPatterns(); 213 | // registerKnobs(lx.engine.getActivePattern()); 214 | sendKnobs(); 215 | } 216 | 217 | void registerKnobs(LXPattern pattern) { 218 | int i = 0; 219 | for (LXParameter parameter : pattern.getParameters()) { 220 | if (i > NUM_KNOBS) { 221 | break; 222 | } 223 | if (parameter instanceof BoundedParameter) { 224 | knobs[i++].register((BoundedParameter) parameter); 225 | } 226 | } 227 | while (i < NUM_KNOBS) { 228 | knobs[i++].register(null); 229 | } 230 | } 231 | 232 | void sendKnobs() { 233 | OscMessage parameter = new OscMessage("/lx/pattern/parameter/values"); 234 | for (KnobListener knob : this.knobs) { 235 | if (knob.parameter != null) { 236 | parameter.add(knob.parameter.getNormalizedf()); 237 | } else { 238 | parameter.add(-1); 239 | } 240 | } 241 | sendPacket(parameter); 242 | } 243 | 244 | private void sendPatterns() { 245 | //OscMessage message = new OscMessage("/lx/pattern/list"); 246 | //LXPattern activePattern = lx.engine.getPattern(); 247 | //int active = 0, i = 0; 248 | //for (LXPattern pattern : lx.getPatterns()) { 249 | // message.add(pattern.getName()); 250 | // if (pattern == activePattern) { 251 | // active = i; 252 | // } 253 | // ++i; 254 | //} 255 | //sendPacket(message); 256 | //sendMessage("/lx/pattern/active", active); 257 | } 258 | 259 | private void sendMessage(String addressPattern) { 260 | sendPacket(new OscMessage(addressPattern)); 261 | } 262 | 263 | private void sendMessage(String addressPattern, int value) { 264 | sendPacket(new OscMessage(addressPattern).add(value)); 265 | } 266 | 267 | private void sendPacket(OscPacket packet) { 268 | try { 269 | this.transmitter.send(packet); 270 | } catch (IOException iox) { 271 | iox.printStackTrace(); 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /EnvelopLX/Output.pde: -------------------------------------------------------------------------------- 1 | import java.net.SocketException; 2 | 3 | LXOutput getOutput(LX lx) throws IOException { 4 | switch (environment) { 5 | case MIDWAY: 6 | return new MidwayOutput(lx); 7 | case SATELLITE: 8 | return new SatelliteOutput(lx); 9 | } 10 | return null; 11 | } 12 | 13 | class MidwayOutput extends LXDatagramOutput { 14 | MidwayOutput(LX lx) throws IOException { 15 | super(lx); 16 | int columnIp = 201; 17 | for (Column column : venue.columns) { 18 | addDatagram(new DDPDatagram(column).setAddress("192.168.1." + (columnIp++))); 19 | } 20 | } 21 | } 22 | 23 | class SatelliteOutput extends LXDatagramOutput { 24 | SatelliteOutput(LX lx) throws IOException { 25 | super(lx); 26 | int universe = 0; 27 | int columnIp = 1; 28 | for (Column column : venue.columns) { 29 | for (Rail rail : column.rails) { 30 | // Top to bottom 31 | int[] indices = new int[rail.size]; 32 | for (int i = 0; i < indices.length; i++) { 33 | indices[indices.length-1-i] = rail.points[i].index; 34 | } 35 | addDatagram(new ArtNetDatagram(indices, 512, universe++).setAddress("192.168.0." + columnIp)); 36 | } 37 | ++columnIp; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /EnvelopLX/UI.pde: -------------------------------------------------------------------------------- 1 | UIVenue getUIVenue() { 2 | switch (environment) { 3 | case SATELLITE: return new UISatellite(); 4 | case MIDWAY: return new UIMidway(); 5 | } 6 | return null; 7 | } 8 | 9 | public static enum LogoMode { 10 | GRAPHIC_TEXT("envelop-logo-graphic-text.png"), 11 | GRAPHIC("envelop-logo-graphic.png"), 12 | INVERSE_TEXT("envelop-logo-inverse-text.png"), 13 | INVERSE("envelop-logo-inverse.png"), 14 | NONE(null); 15 | 16 | private final String path; 17 | private PImage image; 18 | 19 | private LogoMode(String path) { 20 | this.path = path; 21 | } 22 | 23 | public PImage getImage(UI ui) { 24 | if (this == NONE) { 25 | return null; 26 | } 27 | if (this.image == null) { 28 | this.image = ui.applet.loadImage(this.path); 29 | } 30 | return this.image; 31 | } 32 | 33 | public String toString() { 34 | switch (this) { 35 | case GRAPHIC_TEXT: return "Full"; 36 | case GRAPHIC: return "Logo"; 37 | case INVERSE_TEXT: return "Inv"; 38 | case INVERSE: return "Only"; 39 | }; 40 | return "None"; 41 | } 42 | } 43 | 44 | abstract class UIVenue extends UIVisual { 45 | 46 | final static float BOOTH_SIZE_X = 6*FEET; 47 | final static float BOOTH_SIZE_Y = 40*INCHES; 48 | final static float BOOTH_SIZE_Z = 36*INCHES; 49 | 50 | final static float DEFAULT_LOGO_SIZE = 100*INCHES; 51 | 52 | final static float SPEAKER_SIZE_X = 21*INCHES; 53 | final static float SPEAKER_SIZE_Y = 16*INCHES; 54 | final static float SPEAKER_SIZE_Z = 15*INCHES; 55 | 56 | private PImage logoImage; 57 | 58 | public final BooleanParameter speakersVisible = 59 | new BooleanParameter("Speakers", true) 60 | .setDescription("Whether speakers are visible in the venue simulation"); 61 | 62 | public final BooleanParameter floorVisible = 63 | new BooleanParameter("Floor", true) 64 | .setDescription("Whether floor is visible in the venue simulation"); 65 | 66 | public final EnumParameter logoMode = 67 | new EnumParameter("Logo Mode", LogoMode.GRAPHIC_TEXT) 68 | .setDescription("Which version of the logo to render"); 69 | 70 | public final BoundedParameter logoTint = 71 | new BoundedParameter("Logo Tint", 1) 72 | .setDescription("Brightness of the logo"); 73 | 74 | public final BoundedParameter logoSize = 75 | new BoundedParameter("Logo Size", DEFAULT_LOGO_SIZE, 40*INCHES, 180*INCHES) 76 | .setDescription("Size of the logo"); 77 | 78 | public UIVenue() { 79 | addParameter("speakersVisible", this.speakersVisible); 80 | addParameter("floorVisible", this.floorVisible); 81 | addParameter("logoMode", this.logoMode); 82 | addParameter("logoTint", this.logoTint); 83 | addParameter("logoSize", this.logoSize); 84 | } 85 | 86 | @Override 87 | public void onDraw(UI ui, PGraphics pg) { 88 | pg.stroke(#000000); 89 | pg.fill(#202020); 90 | 91 | if (this.floorVisible.isOn()) { 92 | drawFloor(ui, pg); 93 | } 94 | 95 | // Logo 96 | PImage logo = this.logoMode.getEnum().getImage(ui); 97 | if (logo != null) { 98 | pg.noFill(); 99 | pg.noStroke(); 100 | 101 | pg.beginShape(); 102 | int tint = (int) (255 * this.logoTint.getValue()); 103 | pg.tint(0xff000000 | (tint << 16) | (tint << 8) | (tint)); 104 | pg.texture(logo); 105 | pg.textureMode(NORMAL); 106 | float logoSize = this.logoSize.getValuef(); 107 | pg.vertex(-logoSize, .1, -logoSize, 0, 1); 108 | pg.vertex(logoSize, .1, -logoSize, 1, 1); 109 | pg.vertex(logoSize, .1, logoSize, 1, 0); 110 | pg.vertex(-logoSize, .1, logoSize, 0, 0); 111 | pg.endShape(CLOSE); 112 | pg.tint(0xffffffff); 113 | } 114 | 115 | // Speakers 116 | if (this.speakersVisible.isOn()) { 117 | pg.fill(#000000); 118 | pg.stroke(#202020); 119 | for (Column column : venue.columns) { 120 | pg.translate(column.cx, 0, column.cz); 121 | pg.rotateY(-column.azimuth); 122 | pg.translate(0, 9*INCHES, 0); 123 | pg.rotateX(Column.SPEAKER_ANGLE); 124 | pg.box(SPEAKER_SIZE_X, SPEAKER_SIZE_Y, SPEAKER_SIZE_Z); 125 | pg.rotateX(-Column.SPEAKER_ANGLE); 126 | pg.translate(0, 6*FEET-9*INCHES, 0); 127 | pg.box(SPEAKER_SIZE_X, SPEAKER_SIZE_Y, SPEAKER_SIZE_Z); 128 | pg.translate(0, 11*FEET + 3*INCHES - 6*FEET, 0); 129 | pg.rotateX(-Column.SPEAKER_ANGLE); 130 | pg.box(SPEAKER_SIZE_X, SPEAKER_SIZE_Y, SPEAKER_SIZE_Z); 131 | pg.rotateX(Column.SPEAKER_ANGLE); 132 | pg.rotateY(column.azimuth); 133 | pg.translate(-column.cx, -11*FEET - 3*INCHES, -column.cz); 134 | } 135 | } 136 | } 137 | 138 | protected abstract void drawFloor(UI ui, PGraphics pg); 139 | } 140 | 141 | class UISatellite extends UIVenue { 142 | public void drawFloor(UI ui, PGraphics pg) { 143 | 144 | // Desk 145 | pg.translate(0, BOOTH_SIZE_Y/2, Satellite.INCIRCLE_RADIUS + BOOTH_SIZE_Z/2); 146 | pg.box(BOOTH_SIZE_X, BOOTH_SIZE_Y, BOOTH_SIZE_Z); 147 | pg.translate(0, -BOOTH_SIZE_Y/2, -Satellite.INCIRCLE_RADIUS - BOOTH_SIZE_Z/2); 148 | 149 | pg.beginShape(); 150 | for (PVector v : Satellite.PLATFORM_POSITIONS) { 151 | pg.vertex(v.x, 0, v.y); 152 | } 153 | pg.endShape(CLOSE); 154 | pg.beginShape(QUAD_STRIP); 155 | for (int vi = 0; vi <= Satellite.PLATFORM_POSITIONS.length; ++vi) { 156 | PVector v = Satellite.PLATFORM_POSITIONS[vi % Satellite.PLATFORM_POSITIONS.length]; 157 | pg.vertex(v.x, 0, v.y); 158 | pg.vertex(v.x, -8*INCHES, v.y); 159 | } 160 | pg.endShape(); 161 | } 162 | } 163 | 164 | class UIMidway extends UIVenue { 165 | 166 | @Override 167 | public void onDraw(UI ui, PGraphics pg) { 168 | super.onDraw(ui, pg); 169 | 170 | // Desk 171 | if (this.speakersVisible.isOn()) { 172 | pg.fill(#000000); 173 | pg.stroke(#202020); 174 | pg.translate(0, BOOTH_SIZE_Y/2, Midway.DEPTH/2 - BOOTH_SIZE_Z/2); 175 | pg.box(BOOTH_SIZE_X, BOOTH_SIZE_Y, BOOTH_SIZE_Z); 176 | pg.translate(0, -BOOTH_SIZE_Y/2, -Midway.DEPTH/2 + BOOTH_SIZE_Z/2); 177 | 178 | // Subwoofers 179 | for (PVector pv : Midway.SUB_POSITIONS) { 180 | pg.translate(pv.x, 10*INCHES, pv.y); 181 | pg.rotateY(-QUARTER_PI); 182 | pg.box(29*INCHES, 20*INCHES, 29*INCHES); 183 | pg.rotateY(QUARTER_PI); 184 | pg.translate(-pv.x, -10*INCHES, -pv.y); 185 | } 186 | } 187 | } 188 | 189 | @Override 190 | protected void drawFloor(UI ui, PGraphics pg) { 191 | // Floor 192 | pg.translate(0, -4*INCHES, 0); 193 | pg.box(Midway.WIDTH, 8*INCHES, Midway.DEPTH); 194 | pg.translate(0, 4*INCHES, 0); 195 | } 196 | } 197 | 198 | class UIEnvelopSource extends UICollapsibleSection { 199 | UIEnvelopSource(UI ui, float w) { 200 | super(ui, 0, 0, w, 124); 201 | setTitle("ENVELOP SOURCE"); 202 | new UIEnvelopMeter(ui, envelop.source, 0, 0, getContentWidth(), 60).addToContainer(this); 203 | UIAudio.addGainAndRange(this, 64, envelop.source.gain, envelop.source.range); 204 | UIAudio.addAttackAndRelease(this, 84, envelop.source.attack, envelop.source.release); 205 | } 206 | } 207 | 208 | class UIEnvelopDecode extends UICollapsibleSection { 209 | UIEnvelopDecode(UI ui, float w) { 210 | super(ui, 0, 0, w, 124); 211 | setTitle("ENVELOP DECODE"); 212 | new UIEnvelopMeter(ui, envelop.decode, 0, 0, getContentWidth(), 60).addToContainer(this); 213 | UIAudio.addGainAndRange(this, 64, envelop.decode.gain, envelop.decode.range); 214 | UIAudio.addAttackAndRelease(this, 84, envelop.decode.attack, envelop.decode.release); 215 | } 216 | } 217 | 218 | class UIEnvelopMeter extends UI2dContainer { 219 | 220 | public UIEnvelopMeter(UI ui, Envelop.Meter meter, float x, float y, float w, float h) { 221 | super(x, y, w, h); 222 | setBackgroundColor(ui.theme.getDarkBackgroundColor()); 223 | setBorderColor(ui.theme.getControlBorderColor()); 224 | 225 | NormalizedParameter[] channels = meter.getChannels(); 226 | float bandWidth = ((width-2) - (channels.length-1)) / channels.length; 227 | int xp = 1; 228 | for (int i = 0; i < channels.length; ++i) { 229 | int nextX = Math.round(1 + (bandWidth+1) * (i+1)); 230 | new UIEnvelopChannel(channels[i], xp, 1, nextX-xp-1, this.height-2).addToContainer(this); 231 | xp = nextX; 232 | } 233 | } 234 | 235 | class UIEnvelopChannel extends UI2dComponent implements UIModulationSource { 236 | 237 | private final NormalizedParameter channel; 238 | private float lev = 0; 239 | 240 | UIEnvelopChannel(final NormalizedParameter channel, float x, float y, float w, float h) { 241 | super(x, y, w, h); 242 | this.channel = channel; 243 | addLoopTask(new LXLoopTask() { 244 | public void loop(double deltaMs) { 245 | float l2 = UIEnvelopChannel.this.height * channel.getNormalizedf(); 246 | if (l2 != lev) { 247 | lev = l2; 248 | redraw(); 249 | } 250 | } 251 | }); 252 | } 253 | 254 | public void onDraw(UI ui, PGraphics pg) { 255 | if (lev > 0) { 256 | pg.noStroke(); 257 | pg.fill(ui.theme.getPrimaryColor()); 258 | pg.rect(0, this.height-lev, this.width, lev); 259 | } 260 | } 261 | 262 | public LXNormalizedParameter getModulationSource() { 263 | return this.channel; 264 | } 265 | } 266 | } 267 | 268 | class UIVisuals extends UICollapsibleSection { 269 | 270 | private final Map controls = new HashMap(); 271 | 272 | UIVisuals(final LXStudio.UI ui, float w) { 273 | super(ui, 0, 0, w, 124); 274 | setTitle("VISUALS"); 275 | setLayout(UI2dContainer.Layout.VERTICAL); 276 | setChildMargin(4); 277 | 278 | embellishCameraControls(ui); 279 | 280 | new UIButton(0, 0, w - 8, 16) { 281 | public void onToggle(boolean on) { 282 | if (on) { 283 | getSurface().setSize(1732, 972); 284 | } 285 | } 286 | } 287 | .setMomentary(true) 288 | .setLabel("Set 720p resolution") 289 | .addToContainer(this); 290 | 291 | new UIButton(0, 0, w-8, 16) 292 | .setParameter(videoRecording) 293 | .setActiveColor(ui.theme.getAttentionColor()) 294 | .setLabel("Export Video Frames") 295 | .addToContainer(this); 296 | 297 | for (UIVisual visual : envelop.ui.visuals) { 298 | UI2dContainer control = new UI2dContainer(0, 0, getContentWidth(), 0); 299 | control.setVisible(false); 300 | visual.buildControlUI(ui, control); 301 | this.controls.put(visual, control); 302 | } 303 | 304 | UIVisualList visualList = new UIVisualList(ui, 0, 0, getContentWidth(), 20); 305 | visualList.addToContainer(this); 306 | 307 | for (UIVisual visual : envelop.ui.visuals) { 308 | this.controls.get(visual).addToContainer(this); 309 | } 310 | 311 | } 312 | 313 | private void embellishCameraControls(LXStudio.UI ui) { 314 | UI2dContainer row; 315 | 316 | UI2dContainer camera = ui.leftPane.camera; 317 | float yp = camera.getContentHeight() + 4; 318 | 319 | new UIButton(0, yp, getContentWidth(), 16) 320 | .setParameter(envelop.ui.camera.running) 321 | .setLabel("Animate Camera") 322 | .addToContainer(camera); 323 | 324 | yp += 20; 325 | row = row(camera, null); 326 | row.setY(yp); 327 | 328 | new UIDoubleBox(0, 0, 40, 16) 329 | .setParameter(envelop.ui.camera.thetaPeriod) 330 | .addToContainer(row); 331 | 332 | new UIDoubleBox(0, 0, 40, 16) 333 | .setParameter(envelop.ui.camera.phiRange) 334 | .addToContainer(row); 335 | 336 | new UIDoubleBox(0, 0, 40, 16) 337 | .setParameter(envelop.ui.camera.radiusDepth) 338 | .addToContainer(row); 339 | 340 | new UIDoubleBox(0, 0, 40, 16) 341 | .setParameter(envelop.ui.camera.radiusPeriod) 342 | .addToContainer(row); 343 | 344 | yp += 20; 345 | 346 | new UIButton(0, yp, getContentWidth(), 16) 347 | .setParameter(ui.preview.pointCloud.visible) 348 | .setLabel("Show LED Points") 349 | .addToContainer(camera); 350 | yp += 20; 351 | 352 | camera.setContentHeight(yp); 353 | } 354 | 355 | private UI2dContainer focusedControls = null; 356 | private void focusVisual(UIVisual visual) { 357 | if (this.focusedControls != null) { 358 | this.focusedControls.setVisible(false); 359 | } 360 | this.focusedControls = this.controls.get(visual); 361 | this.focusedControls.setVisible(true); 362 | } 363 | 364 | private UI2dContainer row(UI2dContainer container, String label) { 365 | 366 | if (label != null) { 367 | new UILabel(0, 0, getContentWidth(), 12) 368 | .setLabel(label) 369 | .setTextAlignment(LEFT, CENTER) 370 | .addToContainer(container); 371 | } 372 | 373 | return (UI2dContainer) 374 | new UI2dContainer(0, 0, getContentWidth(), 16) 375 | .setLayout(UI2dContainer.Layout.HORIZONTAL) 376 | .setChildMargin(4) 377 | .addToContainer(container); 378 | } 379 | 380 | class UIVisualList extends UIItemList.BasicList { 381 | public UIVisualList(UI ui, float x, float y, float w, float h) { 382 | super(ui, x, y, w, h); 383 | setShowCheckboxes(true); 384 | for (UIVisual visual : envelop.ui.visuals) { 385 | addItem(new Item(visual)); 386 | } 387 | } 388 | 389 | class Item extends UIItemList.Item { 390 | 391 | public final UIVisual visual; 392 | 393 | public Item(UIVisual visual) { 394 | this.visual = visual; 395 | } 396 | 397 | public boolean isChecked() { 398 | return this.visual.isVisible(); 399 | } 400 | 401 | public String getLabel() { 402 | return this.visual.getName(); 403 | } 404 | 405 | public void onFocus() { 406 | focusVisual(this.visual); 407 | } 408 | 409 | public void onCheck(boolean checked) { 410 | this.visual.setVisible(checked); 411 | } 412 | } 413 | } 414 | } 415 | 416 | -------------------------------------------------------------------------------- /EnvelopLX/Visuals.pde: -------------------------------------------------------------------------------- 1 | import java.util.LinkedHashMap; 2 | 3 | /** 4 | * Abstract class for a visual simulation effect in the preview rendering environment. 5 | * These effects can essentially render anything they like using a 3D PGraphics object, 6 | * but they specifically also have access to the colors of the LED effects as well as 7 | * the source and decoded Envelop audio levels 8 | * 9 | * The core drawing method is onDraw(UI ui, PGraphics pg) - note that all Processing 10 | * drawing calls must go through this explicitly passed pg object, rather than direct 11 | * top-level Processing API calls. 12 | */ 13 | public abstract class UIVisual extends UI3dComponent implements LXSerializable { 14 | 15 | private final Map parameters = new LinkedHashMap(); 16 | 17 | /** 18 | * Default name of a visual is it's class name with UI stripped, but a subclass may 19 | * override to provide a prettier name if desired. 20 | */ 21 | public String getName() { 22 | String className = getClass().getSimpleName(); 23 | if (className.startsWith("UI")) { 24 | className = className.substring(2); 25 | } 26 | return className; 27 | } 28 | 29 | /** 30 | * Subclasses may override to do offscreen-rendering before the actual 31 | * composited draw pass. Note that access to the main pg object is not 32 | * allowed yet. A separate, explicit pg object should be managed and 33 | * used by the visual. 34 | */ 35 | protected void beforeDraw(UI ui) {} 36 | 37 | /** 38 | * Adds a parameter to the visual device. A UI to control the parameter will be generated 39 | * and it will also be saved/restored with this visual component. 40 | */ 41 | protected void addParameter(String path, LXParameter parameter) { 42 | if (this.parameters.containsKey(key)) { 43 | throw new IllegalArgumentException("Cannot add same parameter path: " + path); 44 | } 45 | this.parameters.put(path, parameter); 46 | } 47 | 48 | /** 49 | * Default implementation is provided and should work for the majority of devices, but 50 | * subclasses are free to override this to create their own custom UI if needed. 51 | */ 52 | protected void buildControlUI(UI ui, UI2dContainer controls) { 53 | float yp = 0; 54 | float controlWidth = 80; 55 | float xp = controls.getContentWidth() - controlWidth; 56 | for (LXParameter p : this.parameters.values()) { 57 | UI2dComponent control = null; 58 | if (p instanceof BooleanParameter) { 59 | control = new UIButton(xp, yp, controlWidth, 16).setParameter((BooleanParameter) p).setActiveLabel("On").setInactiveLabel("Off"); 60 | } else if (p instanceof BoundedParameter) { 61 | control = new UIDoubleBox(xp, yp, controlWidth, 16).setParameter((BoundedParameter) p); 62 | } else if (p instanceof DiscreteParameter) { 63 | control = new UIDropMenu(xp, yp, controlWidth, 16, (DiscreteParameter) p); 64 | } 65 | if (control != null) { 66 | new UILabel(0, yp, controls.getContentWidth() - control.getWidth() - 4, 16) 67 | .setLabel(p.getLabel()) 68 | .setPadding(0, 4) 69 | .setFont(ui.theme.getControlFont()) 70 | .setTextAlignment(LEFT, CENTER) 71 | .addToContainer(controls); 72 | control.addToContainer(controls); 73 | yp += 20; 74 | } 75 | } 76 | controls.setContentHeight(max(0, yp - 4)); 77 | } 78 | 79 | private static final String KEY_CLASS = "class"; 80 | private static final String KEY_VISIBLE = "visible"; 81 | 82 | @Override 83 | public void save(LX lx, JsonObject obj) { 84 | obj.addProperty(KEY_CLASS, getClass().getName()); 85 | obj.addProperty(KEY_VISIBLE, this.isVisible()); 86 | for (String path : parameters.keySet()) { 87 | LXParameter parameter = parameters.get(path); 88 | if (parameter instanceof BoundedParameter) { 89 | obj.addProperty(path, parameter.getValue()); 90 | } else if (parameter instanceof BooleanParameter) { 91 | obj.addProperty(path, ((BooleanParameter) parameter).isOn()); 92 | } else if (parameter instanceof DiscreteParameter) { 93 | obj.addProperty(path, ((DiscreteParameter) parameter).getValuei()); 94 | } else { 95 | println("WARNING: UIVisual objects do not support saving this parameter type: " + parameter.getClass()); 96 | } 97 | } 98 | } 99 | 100 | @Override 101 | public void load(LX lx, JsonObject obj) { 102 | LXSerializable.Utils.loadBoolean(this.visible, obj, KEY_VISIBLE); 103 | for (String path : parameters.keySet()) { 104 | if (obj.has(path)) { 105 | LXParameter parameter = parameters.get(path); 106 | JsonElement value = obj.get(path); 107 | if (parameter instanceof BoundedParameter) { 108 | parameter.setValue(value.getAsDouble()); 109 | } else if (parameter instanceof BooleanParameter) { 110 | ((BooleanParameter) parameter).setValue(value.getAsBoolean()); 111 | } else if (parameter instanceof DiscreteParameter) { 112 | parameter.setValue(value.getAsInt()); 113 | } 114 | } 115 | } 116 | } 117 | 118 | } 119 | 120 | class UISoundObjects extends UIVisual { 121 | final PFont objectLabelFont; 122 | 123 | public final BoundedParameter radius = 124 | new BoundedParameter("Radius", 6*INCHES, 2*INCHES, 12*INCHES) 125 | .setDescription("Radius of the sound object spheres"); 126 | 127 | UISoundObjects() { 128 | this.objectLabelFont = loadFont("Arial-Black-24.vlw"); 129 | addParameter("radius", this.radius); 130 | } 131 | 132 | public String getName() { 133 | return "Sound Objects"; 134 | } 135 | 136 | public void onDraw(UI ui, PGraphics pg) { 137 | float radius = this.radius.getValuef(); 138 | for (Envelop.Source.Channel channel : envelop.source.channels) { 139 | if (channel.active) { 140 | float tx = channel.tx; 141 | float ty = channel.ty; 142 | float tz = channel.tz; 143 | pg.directionalLight(40, 40, 40, .5, -.4, 1); 144 | pg.ambientLight(40, 40, 40); 145 | pg.translate(tx, ty, tz); 146 | pg.noStroke(); 147 | pg.fill(0xff00ddff); 148 | pg.sphere(radius); 149 | pg.noLights(); 150 | pg.scale(1, -1); 151 | pg.textAlign(CENTER, CENTER); 152 | pg.textFont(objectLabelFont); 153 | pg.textSize(4); 154 | pg.fill(#00ddff); 155 | pg.text(Integer.toString(channel.index), 0, -1*INCHES, -radius - .1*INCHES); 156 | pg.scale(1, -1); 157 | pg.translate(-tx, -ty, -tz); 158 | } 159 | } 160 | } 161 | } 162 | 163 | class UIOrbs extends UIVisual { 164 | 165 | public final BoundedParameter radius = 166 | new BoundedParameter("Radius", 2*INCHES, 1*INCHES, 8*INCHES) 167 | .setDescription("Maximum radius of the orbs"); 168 | 169 | public UIOrbs() { 170 | addParameter("radius", this.radius); 171 | } 172 | 173 | public void onDraw(UI ui, PGraphics pg) { 174 | int[] colors = lx.getColors(); 175 | float radius = this.radius.getValuef(); 176 | 177 | pg.noStroke(); 178 | pg.sphereDetail(12); 179 | pg.pointLight(255, 255, 255, 0, 0, 0); 180 | pg.ambientLight(64, 64, 64); 181 | pg.directionalLight(128, 128, 128, 1, -1, 1); 182 | for (LXPoint p : venue.railPoints) { 183 | int c = colors[p.index]; 184 | int a = max(0xff & c, 0xff & (c >> 8), 0xff & (c >> 16)); 185 | if (a > 0) { 186 | pg.fill((a << 24) | (c & 0x00ffffff)); 187 | pg.translate(p.x, p.y, p.z); 188 | pg.sphere(a / 255. * radius); 189 | pg.translate(-p.x, -p.y, -p.z); 190 | } 191 | } 192 | pg.noLights(); 193 | 194 | } 195 | } 196 | 197 | class UISkybox extends UIVisual { 198 | 199 | private PImage frontZ; 200 | private PImage backZ; 201 | private PImage leftX; 202 | private PImage rightX; 203 | private PImage downY; 204 | private PImage upY; 205 | 206 | public final ObjectParameter skymap; 207 | 208 | public final BoundedParameter alpha = 209 | new BoundedParameter("Alpha", 1) 210 | .setDescription("The alpha blending level of the skybox, lower to darken"); 211 | 212 | public class Skymap { 213 | 214 | private final String name; 215 | private final File folder; 216 | 217 | Skymap(String name, File folder) { 218 | this.name = name; 219 | this.folder = folder; 220 | } 221 | 222 | public String toString() { 223 | return this.name; 224 | } 225 | } 226 | 227 | private boolean reload = false; 228 | private Skymap currentSkymap; 229 | 230 | public UISkybox() { 231 | File skyboxFolder = saveFile("data/skymaps"); 232 | List skymaps = new ArrayList(); 233 | skymaps.add(new Skymap("None", null)); 234 | if (skyboxFolder.isDirectory()) { 235 | for (File f : skyboxFolder.listFiles()) { 236 | if (f.isDirectory()) { 237 | skymaps.add(new Skymap(f.getName(), f)); 238 | } 239 | } 240 | } 241 | 242 | this.skymap = 243 | new ObjectParameter("Skymap", skymaps.toArray(new Skymap[]{})) 244 | .setDescription("Which skymap should be displayed around the Envelop environment"); 245 | 246 | addParameter("skymap", this.skymap); 247 | addParameter("alpha", this.alpha); 248 | 249 | this.skymap.addListener(new LXParameterListener() { 250 | public void onParameterChanged(LXParameter p) { 251 | reload = true; 252 | } 253 | }); 254 | } 255 | 256 | private static final float SKYBOX_SIZE = 200*FEET; 257 | 258 | public void onDraw(UI ui, PGraphics pg) { 259 | if (reload) { 260 | this.currentSkymap = this.skymap.getObject(); 261 | if (this.currentSkymap.folder != null) { 262 | String path = "data/skymaps/" + this.currentSkymap.folder.getName(); 263 | println("Loading skymap from " + path); 264 | this.frontZ = loadImage(path + "/0_Front+Z.png"); 265 | this.backZ = loadImage(path + "/1_Back-Z.png"); 266 | this.leftX = loadImage(path + "/2_Left+X.png"); 267 | this.rightX = loadImage(path + "/3_Right-X.png"); 268 | this.upY = loadImage(path + "/4_Up+Y.png"); 269 | this.downY = loadImage(path + "/5_Down-Y.png"); 270 | } 271 | reload = false; 272 | } 273 | 274 | if ((this.currentSkymap != null) && (this.currentSkymap.folder != null)) { 275 | int alpha = 0xff & (int) (this.alpha.getValuef() * 255); 276 | pg.pushMatrix(); 277 | pg.noStroke(); 278 | pg.tint(0xff000000 | (alpha << 16) | (alpha << 8) | (alpha)); 279 | pg.textureMode(NORMAL); 280 | drawBoxFace(pg, this.frontZ); 281 | pg.rotateY(-HALF_PI); 282 | drawBoxFace(pg, this.rightX); 283 | pg.rotateY(-HALF_PI); 284 | drawBoxFace(pg, this.backZ); 285 | pg.rotateY(-HALF_PI); 286 | drawBoxFace(pg, this.leftX); 287 | pg.rotateY(-HALF_PI); 288 | pg.rotateX(-HALF_PI); 289 | drawBoxFace(pg, this.upY); 290 | pg.rotateX(PI); 291 | drawBoxFace(pg, this.downY); 292 | pg.popMatrix(); 293 | 294 | pg.tint(0xffffffff); 295 | } 296 | } 297 | 298 | private void drawBoxFace(PGraphics pg, PImage texture) { 299 | pg.beginShape(); 300 | pg.texture(texture); 301 | pg.vertex(-SKYBOX_SIZE, -SKYBOX_SIZE, SKYBOX_SIZE, 0, 1); 302 | pg.vertex(-SKYBOX_SIZE, SKYBOX_SIZE, SKYBOX_SIZE, 0, 0); 303 | pg.vertex(SKYBOX_SIZE, SKYBOX_SIZE, SKYBOX_SIZE, 1, 0); 304 | pg.vertex(SKYBOX_SIZE, -SKYBOX_SIZE, SKYBOX_SIZE, 1, 1); 305 | pg.endShape(); 306 | } 307 | } 308 | 309 | class UIFloatingDiscs extends UIVisual { 310 | 311 | public final BoundedParameter brightness = 312 | new BoundedParameter("Brightness", 150, 255) 313 | .setDescription("Brightness of the light source"); 314 | 315 | public final BoundedParameter tiltRange = 316 | new BoundedParameter("Tilt Range", PI/8, 0, HALF_PI) 317 | .setDescription("Range of modulated tilting"); 318 | 319 | public final BoundedParameter sizeRange = 320 | new BoundedParameter("Size Range", 6*INCHES, 0, 3*FEET) 321 | .setDescription("Range of modulated size change"); 322 | 323 | class Disc { 324 | 325 | final float x; 326 | final float y; 327 | final float z; 328 | final float size; 329 | final float pitch; 330 | final float roll; 331 | 332 | final SinLFO pitchMod = new SinLFO(-1, 1, random(11000, 19000)); 333 | final SinLFO rollMod = new SinLFO(-1, 1, random(11000, 21000)); 334 | final SinLFO xMod = new SinLFO(0, random(1, 3)*FEET, random(9000, 23000)); 335 | final SinLFO zMod = new SinLFO(0, random(1, 3)*FEET, random(9000, 23000)); 336 | final SinLFO sizeMod = new SinLFO(0, 1, random(9000, 23000)); 337 | 338 | Disc() { 339 | float r = venue.rMax + 5*FEET; 340 | float elev = random(0, HALF_PI); 341 | float theta = random(0, TWO_PI); 342 | this.x = r * cos(theta) * cos(elev); 343 | this.z = r * sin(theta) * cos(elev); 344 | this.y = 5*FEET + r * .75 * sin(elev); 345 | 346 | this.pitch = -QUARTER_PI * cos(elev) * cos(theta); 347 | this.roll = QUARTER_PI * cos(elev) * sin(theta); 348 | 349 | this.size = random(1*FEET, 3*FEET); 350 | addLoopTask(this.pitchMod.randomBasis().start()); 351 | addLoopTask(this.rollMod.randomBasis().start()); 352 | addLoopTask(this.xMod.randomBasis().start()); 353 | addLoopTask(this.zMod.randomBasis().start()); 354 | addLoopTask(this.sizeMod.randomBasis().start()); 355 | } 356 | 357 | public void onDraw(UI ui, PGraphics pg) { 358 | float tiltRange = UIFloatingDiscs.this.tiltRange.getValuef(); 359 | float pitch = this.pitch + tiltRange * this.pitchMod.getValuef(); 360 | float roll = this.roll + tiltRange * this.rollMod.getValuef(); 361 | 362 | float x = this.x + this.xMod.getValuef(); 363 | float z = this.z + this.xMod.getValuef(); 364 | 365 | float size = this.size + this.sizeMod.getValuef() * sizeRange.getValuef(); 366 | 367 | pg.translate(x, y, z); 368 | pg.rotateX(HALF_PI); 369 | pg.rotateY(pitch); 370 | pg.rotateX(roll); 371 | pg.ellipseMode(CENTER); 372 | pg.ellipse(0, 0, size, size); 373 | pg.ellipseMode(CORNER); 374 | pg.rotateX(-roll); 375 | pg.rotateY(-pitch); 376 | pg.rotateX(-HALF_PI); 377 | pg.translate(-x, -y, -z); 378 | } 379 | } 380 | 381 | private static final int NUM_PLANES = 240; 382 | private final Disc[] planes; 383 | 384 | public UIFloatingDiscs() { 385 | this.planes = new Disc[NUM_PLANES]; 386 | for (int i = 0; i < this.planes.length; ++i) { 387 | this.planes[i] = new Disc(); 388 | } 389 | addParameter("brightness", this.brightness); 390 | addParameter("tiltRange", this.tiltRange); 391 | addParameter("sizeRange", this.sizeRange); 392 | } 393 | 394 | public String getName() { 395 | return "Floating Discs"; 396 | } 397 | 398 | public void onDraw(UI ui, PGraphics pg) { 399 | float brightness = this.brightness.getValuef(); 400 | pg.pointLight(brightness, brightness, brightness, venue.cx, 0, venue.cz); 401 | pg.directionalLight(brightness/2, brightness/2, brightness/2, 1, -1, 1); 402 | pg.noStroke(); 403 | pg.fill(#ffffff); 404 | for (Disc plane : this.planes) { 405 | plane.onDraw(ui, pg); 406 | } 407 | pg.noLights(); 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /EnvelopLX/code/LXStudio.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/code/LXStudio.jar -------------------------------------------------------------------------------- /EnvelopLX/data/envelop-logo-graphic-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/envelop-logo-graphic-text.png -------------------------------------------------------------------------------- /EnvelopLX/data/envelop-logo-graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/envelop-logo-graphic.png -------------------------------------------------------------------------------- /EnvelopLX/data/envelop-logo-inverse-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/envelop-logo-inverse-text.png -------------------------------------------------------------------------------- /EnvelopLX/data/envelop-logo-inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/envelop-logo-inverse.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/AnotherPlanet/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/AnotherPlanet/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/BlueSky/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/BlueSky/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdNight/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdNight/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/ColdSunset/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/ColdSunset/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/DeepDusk/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/DeepDusk/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicPink/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicPink/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/EpicSunset/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/EpicSunset/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightMoon/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightMoon/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/NightSky/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/NightSky/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/0_Front+Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/0_Front+Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/1_Back-Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/1_Back-Z.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/2_Left+X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/2_Left+X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/3_Right-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/3_Right-X.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/4_Up+Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/4_Up+Y.png -------------------------------------------------------------------------------- /EnvelopLX/data/skymaps/OvercastLow/5_Down-Y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/EnvelopLX/data/skymaps/OvercastLow/5_Down-Y.png -------------------------------------------------------------------------------- /EnvelopLX/export/README.txt: -------------------------------------------------------------------------------- 1 | To Export video files: 2 | - Download ffmpeg for Mac: https://evermeet.cx/ffmpeg/getrelease/zip 3 | - Unzip the file, place "ffmpeg" here in the export folder 4 | - Run EnvelopLX in processing, set resolution to 720 using the button, use the recording toggle to export frames 5 | 6 | After that: 7 | - Open Mac Terminal 8 | - cd ~/Documents/Processing/EnvelopLX/EnvelopLX/export 9 | - ./encode.sh 10 | - Example: ./encode.sh 2020-05-06-18.38.16 11 | - NOTE - Make sure there is no trailing slash! 12 | - Video file will be 2020-05-06-18.38.16.mov 13 | -------------------------------------------------------------------------------- /EnvelopLX/export/encode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./ffmpeg -f image2 -framerate 30 -i $1/%05d.tif -c:v libx264 -preset veryslow -qp 18 -pix_fmt yuv420p $1.mov 3 | -------------------------------------------------------------------------------- /EnvelopLX/lxpattern.js: -------------------------------------------------------------------------------- 1 | var period = new BoundedParameter("Period", 2000, 5000); 2 | var thing1 = new BoundedParameter("Thing1", 2000, 5000); 3 | var thing2 = new BoundedParameter("Thing2", 2000, 5000); 4 | var lfo = new SinLFO(0, 255, period); 5 | 6 | function init() { 7 | startModulator(lfo); 8 | addParameter("period", period); 9 | addParameter("thing1", thing1); 10 | addParameter("thing2", thing2); 11 | } 12 | 13 | function run(deltaMs) { 14 | var lfoVal = lfo.getValue(); 15 | for (var i = 0; i < model.points.length; ++i) { 16 | var point = model.points.get(i); 17 | colors[i] = palette.getColor(point, lfoVal * 100 / 255.); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /EnvelopLX/midway.lxp: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1", 3 | "timestamp": 1518487422981, 4 | "engine": { 5 | "id": 1, 6 | "class": "heronarts.lx.LXEngine", 7 | "modulationColor": -16711697, 8 | "parameters": { 9 | "label": "Engine", 10 | "scene-1": false, 11 | "scene-2": false, 12 | "scene-3": false, 13 | "scene-4": false, 14 | "scene-5": false, 15 | "crossfader": 0.5, 16 | "crossfaderBlendMode": 0, 17 | "speed": 1.0, 18 | "focusedChannel": 3, 19 | "cueA": false, 20 | "cueB": false, 21 | "multithreaded": true, 22 | "channelMultithreaded": false, 23 | "networkMultithreaded": false, 24 | "framesPerSecond": 60.0 25 | }, 26 | "palette": { 27 | "id": 2, 28 | "class": "heronarts.lx.color.LXPalette", 29 | "modulationColor": -7930112, 30 | "parameters": { 31 | "label": "", 32 | "hueMode": 1, 33 | "color/brightness": 100.0, 34 | "color/saturation": 54.90196228027344, 35 | "color/hue": 128.57142639160156, 36 | "period": 120000.0, 37 | "range": 92.09302520751953 38 | } 39 | }, 40 | "channels": [ 41 | { 42 | "id": 233, 43 | "class": "heronarts.lx.LXChannel", 44 | "modulationColor": -65370, 45 | "parameters": { 46 | "label": "Decode", 47 | "arm": false, 48 | "selected": false, 49 | "enabled": true, 50 | "cue": false, 51 | "fader": 0.0, 52 | "crossfadeGroup": 0, 53 | "blendMode": 0, 54 | "midiMonitor": false, 55 | "midiChannel": 16, 56 | "autoCycleEnabled": false, 57 | "autoCycleMode": 0, 58 | "autoCycleTimeSecs": 60.0, 59 | "transitionEnabled": false, 60 | "transitionTimeSecs": 5.0, 61 | "transitionBlendMode": 0 62 | }, 63 | "effects": [], 64 | "clips": [], 65 | "patternIndex": 0, 66 | "patterns": [ 67 | { 68 | "id": 251, 69 | "class": "EnvelopLX$EnvelopDecode", 70 | "modulationColor": -8716544, 71 | "parameters": { 72 | "label": "EnvelopDecode", 73 | "mode": 0.0, 74 | "fade": 23.040680960249787, 75 | "damping": 10.0 76 | }, 77 | "modulation": { 78 | "modulators": [], 79 | "modulations": [], 80 | "triggers": [] 81 | }, 82 | "autoCycleEnabled": true 83 | }, 84 | { 85 | "id": 972, 86 | "class": "EnvelopLX$EnvelopShimmer", 87 | "modulationColor": -16711870, 88 | "parameters": { 89 | "label": "EnvelopShimmer", 90 | "intern": 0.0, 91 | "speed": 2.95511811085808, 92 | "taper": 1.255502511005022 93 | }, 94 | "modulation": { 95 | "modulators": [], 96 | "modulations": [], 97 | "triggers": [] 98 | }, 99 | "autoCycleEnabled": true 100 | } 101 | ] 102 | }, 103 | { 104 | "id": 231, 105 | "class": "heronarts.lx.LXChannel", 106 | "modulationColor": -65512, 107 | "parameters": { 108 | "label": "Objects", 109 | "arm": false, 110 | "selected": false, 111 | "enabled": true, 112 | "cue": false, 113 | "fader": 0.8571428684517741, 114 | "crossfadeGroup": 0, 115 | "blendMode": 0, 116 | "midiMonitor": false, 117 | "midiChannel": 16, 118 | "autoCycleEnabled": false, 119 | "autoCycleMode": 0, 120 | "autoCycleTimeSecs": 60.0, 121 | "transitionEnabled": false, 122 | "transitionTimeSecs": 5.0, 123 | "transitionBlendMode": 0 124 | }, 125 | "effects": [], 126 | "clips": [], 127 | "patternIndex": 0, 128 | "patterns": [ 129 | { 130 | "id": 234, 131 | "class": "EnvelopLX$EnvelopObjects", 132 | "modulationColor": -65311, 133 | "parameters": { 134 | "label": "EnvelopObjects", 135 | "size": 0.0, 136 | "spread": 0.4560000141859053, 137 | "response": 94.79999969154596, 138 | "active-1": true, 139 | "active-2": true, 140 | "active-3": true, 141 | "active-4": true, 142 | "active-5": true, 143 | "active-6": true, 144 | "active-7": true, 145 | "active-8": true, 146 | "active-9": true, 147 | "active-10": true, 148 | "active-11": true, 149 | "active-12": true, 150 | "active-13": true, 151 | "active-14": true, 152 | "active-15": true, 153 | "active-16": true 154 | }, 155 | "modulation": { 156 | "modulators": [], 157 | "modulations": [], 158 | "triggers": [] 159 | }, 160 | "autoCycleEnabled": true 161 | } 162 | ] 163 | }, 164 | { 165 | "id": 27, 166 | "class": "heronarts.lx.LXChannel", 167 | "modulationColor": -16757761, 168 | "parameters": { 169 | "label": "Patterns", 170 | "arm": false, 171 | "selected": false, 172 | "enabled": true, 173 | "cue": false, 174 | "fader": 0.0, 175 | "crossfadeGroup": 0, 176 | "blendMode": 0, 177 | "midiMonitor": false, 178 | "midiChannel": 16, 179 | "autoCycleEnabled": false, 180 | "autoCycleMode": 0, 181 | "autoCycleTimeSecs": 60.0, 182 | "transitionEnabled": false, 183 | "transitionTimeSecs": 5.0, 184 | "transitionBlendMode": 0 185 | }, 186 | "effects": [ 187 | { 188 | "id": 256, 189 | "class": "EnvelopLX$Strobe", 190 | "modulationColor": -11403009, 191 | "parameters": { 192 | "label": "Strobe", 193 | "enabled": false, 194 | "mode": 0, 195 | "frequency": 1.0, 196 | "depth": 0.5 197 | }, 198 | "modulation": { 199 | "modulators": [], 200 | "modulations": [], 201 | "triggers": [] 202 | } 203 | } 204 | ], 205 | "clips": [], 206 | "patternIndex": 5, 207 | "patterns": [ 208 | { 209 | "id": 57, 210 | "class": "EnvelopLX$Noise", 211 | "modulationColor": -7936, 212 | "parameters": { 213 | "label": "Noise", 214 | "scale": 36.94999946281314, 215 | "floor": -1.2399999722838402, 216 | "range": 3.621999939337373, 217 | "xSpeed": 0.0, 218 | "ySpeed": 0.0, 219 | "zSpeed": 1.839999981224537, 220 | "xOffset": 0.0, 221 | "yOffset": 0.0, 222 | "zOffset": 0.0 223 | }, 224 | "modulation": { 225 | "modulators": [], 226 | "modulations": [], 227 | "triggers": [] 228 | }, 229 | "autoCycleEnabled": true 230 | }, 231 | { 232 | "id": 68, 233 | "class": "EnvelopLX$Flash", 234 | "modulationColor": -1900800, 235 | "parameters": { 236 | "label": "Flash", 237 | "brightness": 72.00000062584877, 238 | "attack": 165.78998956553656, 239 | "decay": 623.1199743795398, 240 | "shape": 1.0, 241 | "velocitySensitivity": 0.46000000089406967, 242 | "manual": false, 243 | "midi": true, 244 | "midiFilter": false, 245 | "midiNote": 0 246 | }, 247 | "modulation": { 248 | "modulators": [], 249 | "modulations": [], 250 | "triggers": [] 251 | }, 252 | "autoCycleEnabled": true 253 | }, 254 | { 255 | "id": 74, 256 | "class": "EnvelopLX$Warble", 257 | "modulationColor": -16711825, 258 | "parameters": { 259 | "label": "Warble", 260 | "rate": 0.25, 261 | "size": 50.99999899417162, 262 | "interp": 1.3799999915063381, 263 | "depth": 0.4000000059604645 264 | }, 265 | "modulation": { 266 | "modulators": [], 267 | "modulations": [], 268 | "triggers": [] 269 | }, 270 | "autoCycleEnabled": true 271 | }, 272 | { 273 | "id": 1194, 274 | "class": "EnvelopLX$Bouncing", 275 | "modulationColor": -16711870, 276 | "parameters": { 277 | "label": "Bouncing", 278 | "gravity": -200.0, 279 | "size": 24.0, 280 | "amp": 141.7320556640625 281 | }, 282 | "modulation": { 283 | "modulators": [], 284 | "modulations": [], 285 | "triggers": [] 286 | }, 287 | "autoCycleEnabled": true 288 | }, 289 | { 290 | "id": 1330, 291 | "class": "EnvelopLX$Rings", 292 | "modulationColor": -65280, 293 | "parameters": { 294 | "label": "Rings", 295 | "amplitude": 1.0, 296 | "speed": 10000.0 297 | }, 298 | "modulation": { 299 | "modulators": [], 300 | "modulations": [], 301 | "triggers": [] 302 | }, 303 | "autoCycleEnabled": true 304 | }, 305 | { 306 | "id": 1477, 307 | "class": "EnvelopLX$Swarm", 308 | "modulationColor": -65426, 309 | "parameters": { 310 | "label": "Swarm", 311 | "chunk": 10.0, 312 | "size": 1.0, 313 | "speed": 0.5, 314 | "oscillation": 0.0 315 | }, 316 | "modulation": { 317 | "modulators": [], 318 | "modulations": [], 319 | "triggers": [] 320 | }, 321 | "autoCycleEnabled": true 322 | } 323 | ] 324 | }, 325 | { 326 | "id": 402, 327 | "class": "heronarts.lx.LXChannel", 328 | "modulationColor": -6881025, 329 | "parameters": { 330 | "label": "Kick", 331 | "arm": false, 332 | "selected": true, 333 | "enabled": false, 334 | "cue": false, 335 | "fader": 0.0, 336 | "crossfadeGroup": 0, 337 | "blendMode": 0, 338 | "midiMonitor": true, 339 | "midiChannel": 0, 340 | "autoCycleEnabled": false, 341 | "autoCycleMode": 0, 342 | "autoCycleTimeSecs": 60.0, 343 | "transitionEnabled": false, 344 | "transitionTimeSecs": 5.0, 345 | "transitionBlendMode": 0 346 | }, 347 | "effects": [ 348 | { 349 | "id": 1642, 350 | "class": "heronarts.lx.effect.DesaturationEffect", 351 | "modulationColor": -58624, 352 | "parameters": { 353 | "label": "Desaturation", 354 | "enabled": false, 355 | "amount": 1.0, 356 | "attack": 100.0, 357 | "decay": 180.0 358 | }, 359 | "modulation": { 360 | "modulators": [], 361 | "modulations": [], 362 | "triggers": [] 363 | } 364 | }, 365 | { 366 | "id": 1644, 367 | "class": "EnvelopLX$LSD", 368 | "modulationColor": -16711925, 369 | "parameters": { 370 | "label": "LSD", 371 | "enabled": false, 372 | "Scale": 9.3, 373 | "Speed": 4.1, 374 | "Range": 1.0 375 | }, 376 | "modulation": { 377 | "modulators": [], 378 | "modulations": [], 379 | "triggers": [] 380 | } 381 | } 382 | ], 383 | "clips": [], 384 | "patternIndex": 0, 385 | "patterns": [ 386 | { 387 | "id": 405, 388 | "class": "EnvelopLX$Flash", 389 | "modulationColor": -14745856, 390 | "parameters": { 391 | "label": "Flash", 392 | "brightness": 51.96850393700787, 393 | "attack": 164.2770785541571, 394 | "decay": 3159.799119598239, 395 | "shape": 1.6141732283464567, 396 | "velocitySensitivity": 0.5590551181102362, 397 | "manual": false, 398 | "midi": true, 399 | "midiFilter": false, 400 | "midiNote": 0 401 | }, 402 | "modulation": { 403 | "modulators": [], 404 | "modulations": [], 405 | "triggers": [] 406 | }, 407 | "autoCycleEnabled": true 408 | } 409 | ] 410 | }, 411 | { 412 | "id": 404, 413 | "class": "heronarts.lx.LXChannel", 414 | "modulationColor": -65300, 415 | "parameters": { 416 | "label": "Rain", 417 | "arm": false, 418 | "selected": false, 419 | "enabled": false, 420 | "cue": false, 421 | "fader": 0.0, 422 | "crossfadeGroup": 0, 423 | "blendMode": 0, 424 | "midiMonitor": true, 425 | "midiChannel": 1, 426 | "autoCycleEnabled": false, 427 | "autoCycleMode": 0, 428 | "autoCycleTimeSecs": 60.0, 429 | "transitionEnabled": false, 430 | "transitionTimeSecs": 5.0, 431 | "transitionBlendMode": 0 432 | }, 433 | "effects": [], 434 | "clips": [], 435 | "patternIndex": 0, 436 | "patterns": [ 437 | { 438 | "id": 567, 439 | "class": "EnvelopLX$Raindrops", 440 | "modulationColor": -5701377, 441 | "parameters": { 442 | "label": "Raindrops", 443 | "auto": true, 444 | "gravity": -80.34021708949119, 445 | "size": 1.0, 446 | "rate": 8.899999868124723 447 | }, 448 | "modulation": { 449 | "modulators": [ 450 | { 451 | "id": 2885, 452 | "class": "heronarts.lx.modulator.VariableLFO", 453 | "modulationColor": -16773121, 454 | "parameters": { 455 | "label": "LFO", 456 | "running": true, 457 | "trigger": false, 458 | "loop": true, 459 | "tempoSync": false, 460 | "tempoMultiplier": 5, 461 | "tempoLock": true, 462 | "clockMode": 0, 463 | "periodFast": 1000.0, 464 | "periodSlow": 10000.0, 465 | "wave": 0, 466 | "skew": 0.0, 467 | "shape": 0.0, 468 | "phase": 0.0, 469 | "exp": 0.0 470 | }, 471 | "basis": 0.4770000000001193 472 | }, 473 | { 474 | "id": 3948, 475 | "class": "heronarts.lx.modulator.VariableLFO", 476 | "modulationColor": -22784, 477 | "parameters": { 478 | "label": "LFO 2", 479 | "running": false, 480 | "trigger": false, 481 | "loop": true, 482 | "tempoSync": false, 483 | "tempoMultiplier": 5, 484 | "tempoLock": true, 485 | "clockMode": 0, 486 | "periodFast": 1000.0, 487 | "periodSlow": 10000.0, 488 | "wave": 0, 489 | "skew": 0.0, 490 | "shape": 0.0, 491 | "phase": 0.0, 492 | "exp": 0.0 493 | }, 494 | "basis": 0.0 495 | } 496 | ], 497 | "modulations": [ 498 | { 499 | "source": { 500 | "id": 2885 501 | }, 502 | "target": { 503 | "componentId": 567, 504 | "parameterPath": "size" 505 | }, 506 | "id": 2886, 507 | "class": "heronarts.lx.parameter.LXCompoundModulation", 508 | "modulationColor": -16711729, 509 | "parameters": { 510 | "label": "", 511 | "enabled": true, 512 | "Polarity": 0, 513 | "Range": 0.12000000104308128 514 | } 515 | }, 516 | { 517 | "source": { 518 | "id": 2885 519 | }, 520 | "target": { 521 | "componentId": 567, 522 | "parameterPath": "gravity" 523 | }, 524 | "id": 3717, 525 | "class": "heronarts.lx.parameter.LXCompoundModulation", 526 | "modulationColor": -62464, 527 | "parameters": { 528 | "label": "", 529 | "enabled": true, 530 | "Polarity": 0, 531 | "Range": 0.12000000000000001 532 | } 533 | }, 534 | { 535 | "source": { 536 | "id": 2885 537 | }, 538 | "target": { 539 | "componentId": 567, 540 | "parameterPath": "size" 541 | }, 542 | "id": 3947, 543 | "class": "heronarts.lx.parameter.LXCompoundModulation", 544 | "modulationColor": -16711827, 545 | "parameters": { 546 | "label": "", 547 | "enabled": true, 548 | "Polarity": 0, 549 | "Range": 0.0 550 | } 551 | } 552 | ], 553 | "triggers": [] 554 | }, 555 | "autoCycleEnabled": true 556 | }, 557 | { 558 | "id": 736, 559 | "class": "EnvelopLX$Helix", 560 | "modulationColor": -16711756, 561 | "parameters": { 562 | "label": "Helix", 563 | "rate": 0.25, 564 | "size": 24.0, 565 | "coil": 1.0 566 | }, 567 | "modulation": { 568 | "modulators": [], 569 | "modulations": [], 570 | "triggers": [] 571 | }, 572 | "autoCycleEnabled": true 573 | }, 574 | { 575 | "id": 815, 576 | "class": "EnvelopLX$Warble", 577 | "modulationColor": -16742657, 578 | "parameters": { 579 | "label": "Warble", 580 | "rate": 0.25, 581 | "size": 30.84000227227807, 582 | "interp": 3.0, 583 | "depth": 0.3968999822571876 584 | }, 585 | "modulation": { 586 | "modulators": [], 587 | "modulations": [], 588 | "triggers": [] 589 | }, 590 | "autoCycleEnabled": true 591 | }, 592 | { 593 | "id": 868, 594 | "class": "EnvelopLX$Tron", 595 | "modulationColor": -16711683, 596 | "parameters": { 597 | "label": "Tron", 598 | "period": 150000.0, 599 | "size": 24.0, 600 | "density": 25.0 601 | }, 602 | "modulation": { 603 | "modulators": [], 604 | "modulations": [], 605 | "triggers": [] 606 | }, 607 | "autoCycleEnabled": true 608 | } 609 | ] 610 | }, 611 | { 612 | "id": 4364, 613 | "class": "heronarts.lx.LXChannel", 614 | "modulationColor": -59392, 615 | "parameters": { 616 | "label": "Colors", 617 | "arm": false, 618 | "selected": false, 619 | "enabled": true, 620 | "cue": false, 621 | "fader": 1.0, 622 | "crossfadeGroup": 0, 623 | "blendMode": 1, 624 | "midiMonitor": false, 625 | "midiChannel": 16, 626 | "autoCycleEnabled": false, 627 | "autoCycleMode": 0, 628 | "autoCycleTimeSecs": 60.0, 629 | "transitionEnabled": false, 630 | "transitionTimeSecs": 5.0, 631 | "transitionBlendMode": 0 632 | }, 633 | "effects": [], 634 | "clips": [], 635 | "patternIndex": 0, 636 | "patterns": [ 637 | { 638 | "id": 4365, 639 | "class": "heronarts.lx.pattern.GradientPattern", 640 | "modulationColor": -2948865, 641 | "parameters": { 642 | "label": "Gradient", 643 | "gradient": 215.99998712539673, 644 | "spreadX": 0.03999999910593033, 645 | "spreadY": 1.0, 646 | "spreadZ": 0.0, 647 | "spreadR": 0.0, 648 | "offsetX": 0.0, 649 | "offsetY": -2.2351741790771484E-8, 650 | "offsetZ": 0.0, 651 | "mirror": true 652 | }, 653 | "modulation": { 654 | "modulators": [], 655 | "modulations": [], 656 | "triggers": [] 657 | }, 658 | "autoCycleEnabled": true 659 | } 660 | ] 661 | } 662 | ], 663 | "master": { 664 | "id": 18, 665 | "class": "heronarts.lx.LXMasterChannel", 666 | "modulationColor": -16711731, 667 | "parameters": { 668 | "label": "Master", 669 | "arm": false, 670 | "selected": false 671 | }, 672 | "effects": [ 673 | { 674 | "id": 254, 675 | "class": "heronarts.lx.effect.BlurEffect", 676 | "modulationColor": -65424, 677 | "parameters": { 678 | "label": "Blur", 679 | "enabled": false, 680 | "amount": 0.0 681 | }, 682 | "modulation": { 683 | "modulators": [], 684 | "modulations": [], 685 | "triggers": [] 686 | } 687 | }, 688 | { 689 | "id": 252, 690 | "class": "EnvelopLX$LSD", 691 | "modulationColor": -42752, 692 | "parameters": { 693 | "label": "LSD", 694 | "enabled": false, 695 | "Scale": 10.0, 696 | "Speed": 4.0, 697 | "Range": 1.0 698 | }, 699 | "modulation": { 700 | "modulators": [], 701 | "modulations": [], 702 | "triggers": [] 703 | } 704 | } 705 | ], 706 | "clips": [] 707 | }, 708 | "tempo": { 709 | "id": 25, 710 | "class": "heronarts.lx.Tempo", 711 | "modulationColor": -7339777, 712 | "parameters": { 713 | "label": "", 714 | "clockSource": 0, 715 | "period": 666.6666754969846, 716 | "bpm": 89.9999988079071, 717 | "tap": false, 718 | "nudgeUp": false, 719 | "nudgeDown": false, 720 | "beatsPerMeasure": 4, 721 | "trigger": false, 722 | "enabled": false 723 | } 724 | }, 725 | "audio": { 726 | "id": 20, 727 | "class": "heronarts.lx.audio.LXAudioEngine", 728 | "modulationColor": -65324, 729 | "parameters": { 730 | "label": "Audio", 731 | "enabled": false, 732 | "mode": 0 733 | }, 734 | "meter": { 735 | "id": 23, 736 | "class": "heronarts.lx.audio.GraphicMeter", 737 | "modulationColor": -3211520, 738 | "parameters": { 739 | "label": "Meter", 740 | "running": true, 741 | "trigger": false, 742 | "gain": 0.0, 743 | "range": 48.0, 744 | "attack": 10.0, 745 | "release": 100.0, 746 | "slope": 4.5, 747 | "Band-1": 0.0, 748 | "Band-2": 0.0, 749 | "Band-3": 0.0, 750 | "Band-4": 0.0, 751 | "Band-5": 0.0, 752 | "Band-6": 0.0, 753 | "Band-7": 0.0, 754 | "Band-8": 0.0, 755 | "Band-9": 0.0, 756 | "Band-10": 0.0, 757 | "Band-11": 0.0, 758 | "Band-12": 0.0, 759 | "Band-13": 0.0, 760 | "Band-14": 0.0, 761 | "Band-15": 0.0, 762 | "Band-16": 0.0 763 | } 764 | }, 765 | "input": { 766 | "id": 21, 767 | "class": "heronarts.lx.audio.LXAudioInput", 768 | "modulationColor": -16711833, 769 | "parameters": { 770 | "label": "Audio Input", 771 | "device": 0 772 | } 773 | }, 774 | "output": { 775 | "id": 22, 776 | "class": "heronarts.lx.audio.LXAudioOutput", 777 | "modulationColor": -12976384, 778 | "parameters": { 779 | "label": "Audio Output", 780 | "file": "", 781 | "trigger": false, 782 | "looping": false, 783 | "play": false 784 | } 785 | } 786 | }, 787 | "output": { 788 | "id": 19, 789 | "class": "heronarts.lx.LXEngine$Output", 790 | "modulationColor": -14876417, 791 | "parameters": { 792 | "label": "Output", 793 | "enabled": false, 794 | "mode": 0, 795 | "fps": 0.0, 796 | "gamma": 1, 797 | "brightness": 1.0 798 | } 799 | }, 800 | "components": { 801 | "envelop": { 802 | "id": 29, 803 | "class": "EnvelopLX$Envelop", 804 | "modulationColor": -30720, 805 | "parameters": { 806 | "label": "Envelop", 807 | "running": true, 808 | "trigger": false 809 | }, 810 | "source": { 811 | "id": 30, 812 | "class": "EnvelopLX$Envelop$Source", 813 | "modulationColor": -29184, 814 | "parameters": { 815 | "label": "Source", 816 | "running": true, 817 | "trigger": false, 818 | "Gain": 0.47999998927116394, 819 | "Range": 24.0, 820 | "Attack": 25.0, 821 | "Release": 50.0, 822 | "Source-1": 0.0, 823 | "Source-2": 0.0, 824 | "Source-3": 0.29624823164163966, 825 | "Source-4": 0.28081496592972954, 826 | "Source-5": 0.0, 827 | "Source-6": 0.0, 828 | "Source-7": 0.0, 829 | "Source-8": 0.0, 830 | "Source-9": 0.0, 831 | "Source-10": 0.0, 832 | "Source-11": 0.0, 833 | "Source-12": 0.0, 834 | "Source-13": 0.0, 835 | "Source-14": 0.0, 836 | "Source-15": 0.0, 837 | "Source-16": 0.0 838 | } 839 | }, 840 | "decode": { 841 | "id": 33, 842 | "class": "EnvelopLX$Envelop$Decode", 843 | "modulationColor": -43008, 844 | "parameters": { 845 | "label": "Decode", 846 | "running": true, 847 | "trigger": false, 848 | "Gain": 24.0, 849 | "Range": 24.0, 850 | "Attack": 29.499999899417162, 851 | "Release": 50.0, 852 | "Decode-1": 0.8301280004149362, 853 | "Decode-2": 0.9970798767751432, 854 | "Decode-3": 1.0, 855 | "Decode-4": 1.0, 856 | "Decode-5": 1.0, 857 | "Decode-6": 1.0, 858 | "Decode-7": 1.0, 859 | "Decode-8": 0.7663007212208052 860 | } 861 | } 862 | } 863 | }, 864 | "modulation": { 865 | "modulators": [], 866 | "modulations": [], 867 | "triggers": [] 868 | }, 869 | "osc": { 870 | "id": 24, 871 | "class": "heronarts.lx.osc.LXOscEngine", 872 | "modulationColor": -65507, 873 | "parameters": { 874 | "label": "OSC", 875 | "receiveHost": "0.0.0.0", 876 | "receivePort": 3030, 877 | "receiveActive": true, 878 | "transmitHost": "localhost", 879 | "transmitPort": 3131, 880 | "transmitActive": false 881 | } 882 | }, 883 | "midi": { 884 | "inputs": [], 885 | "surfaces": [], 886 | "mapping": [] 887 | } 888 | }, 889 | "externals": { 890 | "ui": { 891 | "audioExpanded": true, 892 | "paletteExpanded": true, 893 | "cameraExpanded": false, 894 | "clipViewVisible": false, 895 | "modulatorExpanded": {}, 896 | "preview": { 897 | "mode": 0, 898 | "animation": false, 899 | "animationTime": 1000.0, 900 | "projection": 0, 901 | "perspective": 60.0, 902 | "depth": 1.0, 903 | "phiLock": true, 904 | "centerPoint": false, 905 | "camera": { 906 | "active": false, 907 | "radius": 385.4519694688533, 908 | "theta": 0.015000000000000097, 909 | "phi": 0.035174773156642955, 910 | "x": 0.0, 911 | "y": 71.5221939086914, 912 | "z": 0.0 913 | }, 914 | "cue": [ 915 | { 916 | "active": false, 917 | "radius": 385.4519694688533, 918 | "theta": 0.015000000000000097, 919 | "phi": 0.035174773156642955, 920 | "x": 0.0, 921 | "y": 71.5221939086914, 922 | "z": 0.0 923 | }, 924 | { 925 | "active": false, 926 | "radius": 120.0, 927 | "theta": 0.0, 928 | "phi": 0.0, 929 | "x": 0.0, 930 | "y": 0.0, 931 | "z": 0.0 932 | }, 933 | { 934 | "active": false, 935 | "radius": 120.0, 936 | "theta": 0.0, 937 | "phi": 0.0, 938 | "x": 0.0, 939 | "y": 0.0, 940 | "z": 0.0 941 | }, 942 | { 943 | "active": false, 944 | "radius": 120.0, 945 | "theta": 0.0, 946 | "phi": 0.0, 947 | "x": 0.0, 948 | "y": 0.0, 949 | "z": 0.0 950 | }, 951 | { 952 | "active": false, 953 | "radius": 120.0, 954 | "theta": 0.0, 955 | "phi": 0.0, 956 | "x": 0.0, 957 | "y": 0.0, 958 | "z": 0.0 959 | }, 960 | { 961 | "active": false, 962 | "radius": 120.0, 963 | "theta": 0.0, 964 | "phi": 0.0, 965 | "x": 0.0, 966 | "y": 0.0, 967 | "z": 0.0 968 | } 969 | ], 970 | "focus": 0, 971 | "pointCloud": { 972 | "pointSize": 3.0 973 | } 974 | } 975 | } 976 | } 977 | } -------------------------------------------------------------------------------- /EnvelopLX/slee-midway-170727.lxp: -------------------------------------------------------------------------------- 1 | {"version":"0.1","timestamp":1501191707275,"engine":{"id":1,"class":"heronarts.lx.LXEngine","parameters":{"label":"Engine","scene-1":false,"scene-2":false,"scene-3":false,"scene-4":false,"scene-5":false,"crossfader":0.4566929133858268,"crossfaderBlendMode":0,"speed":1.0,"focusedChannel":0,"cueA":false,"cueB":false},"palette":{"id":2,"class":"heronarts.lx.color.LXPalette","parameters":{"label":"","cue":false,"hueMode":0,"color/hue":131.34327697753906,"color/brightness":100.0,"color/saturation":78.82353210449219,"color":-13172900,"period":120000.0,"range":0.0,"spreadX":0.0,"spreadY":53.85826771653541,"spreadZ":0.0,"spreadR":0.0,"offsetX":0.0,"offsetY":-0.08661417322834641,"offsetZ":0.0,"mirror":true}},"channels":[{"id":803,"class":"heronarts.lx.LXChannel","parameters":{"label":"Background","arm":false,"enabled":true,"cue":false,"midiMonitor":false,"midiChannel":16,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":0.8267716535433071,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":true,"transitionTimeSecs":3.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":3,"patterns":[{"id":804,"class":"EnvelopLX$Palette","parameters":{"label":"Palette","level":100.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":7532,"class":"EnvelopLX$Noise","parameters":{"label":"Noise","scale":25.11811023622047,"floor":-1.0866141732283463,"range":1.8456692930281633,"xSpeed":0.0,"ySpeed":0.0,"zSpeed":1.7480314960629917,"xOffset":0.0,"yOffset":0.0,"zOffset":0.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":7467,"class":"EnvelopLX$Tron","parameters":{"label":"Tron","period":173898.1485168808,"size":11.092318184636369,"density":27.00000073760748},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":7519,"class":"EnvelopLX$Swarm","parameters":{"label":"Swarm","chunk":10.0,"size":0.5,"speed":0.06456692892266071,"oscillation":0.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":9958,"class":"EnvelopLX$Bouncing","parameters":{"label":"Bouncing","gravity":-200.0,"size":24.0,"amp":141.7320556640625},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":829,"class":"heronarts.lx.LXChannel","parameters":{"label":"Kick","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":15,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":0.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":830,"class":"EnvelopLX$Flash","parameters":{"label":"Flash","brightness":100.0,"attack":304.52135904271813,"decay":1718.1009362018724,"shape":1.9921259842519685,"velocitySensitivity":0.5,"manual":false,"midi":true,"midiFilter":false,"midiNote":0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":808,"class":"heronarts.lx.LXChannel","parameters":{"label":"Mix","arm":false,"enabled":true,"cue":false,"midiMonitor":false,"midiChannel":16,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":0.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":809,"class":"EnvelopLX$EnvelopObjects","parameters":{"label":"EnvelopObjects","size":0.0,"spread":0.7519999975264071,"response":122.3999975323677,"active-1":true,"active-2":true,"active-3":true,"active-4":true,"active-5":false,"active-6":false,"active-7":true,"active-8":true,"active-9":false,"active-10":false,"active-11":false,"active-12":false,"active-13":false,"active-14":false,"active-15":false,"active-16":false},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":2834,"class":"heronarts.lx.LXChannel","parameters":{"label":"Down","arm":false,"enabled":true,"cue":false,"midiMonitor":false,"midiChannel":16,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":0.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":6142,"class":"EnvelopLX$Raindrops","parameters":{"label":"Raindrops","auto":true,"gravity":-21.751400494926973,"size":5.070866141732283,"rate":21.968503937007874},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":6495,"class":"EnvelopLX$Noise","parameters":{"label":"Noise","scale":15.599999874830244,"floor":-1.5599999651312828,"range":3.2419999481290582,"xSpeed":0.0,"ySpeed":-1.4399999678134918,"zSpeed":0.0,"xOffset":0.0,"yOffset":0.0,"zOffset":0.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":5151,"class":"heronarts.lx.LXChannel","parameters":{"label":"Up","arm":false,"enabled":true,"cue":false,"midiMonitor":false,"midiChannel":16,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":0.18110236220472442,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":true,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":5152,"class":"EnvelopLX$Noise","parameters":{"label":"Noise","scale":19.881889763779526,"floor":-1.1496062992125984,"range":2.8031496072378683,"xSpeed":0.0,"ySpeed":2.1259842519685037,"zSpeed":0.14173228346456668,"xOffset":0.0,"yOffset":0.0,"zOffset":0.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":1138,"class":"heronarts.lx.LXChannel","parameters":{"label":"Bassoon","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":1,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":1.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[{"id":3966,"class":"EnvelopLX$Strobe","parameters":{"label":"Strobe","enabled":true,"mode":1,"frequency":2.890499957602471,"depth":0.15000000782310963},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}],"clips":[],"patternIndex":0,"patterns":[{"id":1440,"class":"EnvelopLX$NotePattern","parameters":{"label":"Note","attack":437.0999370759159,"decay":2834.3563525233903,"size":0.30000000074505806,"pitchBendDepth":0.5,"velocityBrightness":0.5,"velocitySize":0.5,"modBrightness":0.0,"modSize":0.0,"lfoRate":500.0,"position":0.5,"pitchDepth":1.0,"soundObject":0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":1141,"class":"heronarts.lx.LXChannel","parameters":{"label":"Piano","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":2,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":1.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":1699,"class":"EnvelopLX$NotePattern","parameters":{"label":"Note","attack":90.97498885820013,"decay":1062.484846963729,"size":0.110000004991889,"pitchBendDepth":0.5,"velocityBrightness":0.5,"velocitySize":0.5,"modBrightness":0.0,"modSize":0.0,"lfoRate":500.0,"position":0.5,"pitchDepth":1.0,"soundObject":0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":1135,"class":"heronarts.lx.LXChannel","parameters":{"label":"Marimba","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":3,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":1.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":1160,"class":"EnvelopLX$NotePattern","parameters":{"label":"Note","attack":96.14498769607566,"decay":3271.3556847199084,"size":0.20000000298023224,"pitchBendDepth":0.5,"velocityBrightness":0.7699999958276749,"velocitySize":0.5,"modBrightness":0.0,"modSize":0.0,"lfoRate":500.0,"position":0.5,"pitchDepth":1.0,"soundObject":0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":1123,"class":"heronarts.lx.LXChannel","parameters":{"label":"Flash","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":0,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":1.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[{"id":1127,"class":"heronarts.lx.effect.DesaturationEffect","parameters":{"label":"Desaturation","enabled":true,"amount":1.0,"attack":100.0,"decay":100.0},"modulation":{"modulators":[],"modulations":[],"triggers":[]}},{"id":1130,"class":"EnvelopLX$Sizzle","parameters":{"label":"Sizzle","enabled":true,"amount":0.45000000670552254,"speed":0.1699999962002039},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}],"clips":[],"patternIndex":0,"patterns":[{"id":1124,"class":"EnvelopLX$Flash","parameters":{"label":"Flash","brightness":100.0,"attack":165.88497433737263,"decay":1000.0,"shape":1.0,"velocitySensitivity":0.7300000060349703,"manual":false,"midi":true,"midiFilter":true,"midiNote":72},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]},{"id":8639,"class":"heronarts.lx.LXChannel","parameters":{"label":"Blips","arm":false,"enabled":true,"cue":false,"midiMonitor":true,"midiChannel":0,"autoCycleEnabled":false,"autoCycleTimeSecs":60.0,"fader":1.0,"crossfadeGroup":0,"blendMode":0,"transitionEnabled":false,"transitionTimeSecs":5.0,"transitionBlendMode":0},"effects":[],"clips":[],"patternIndex":0,"patterns":[{"id":8640,"class":"EnvelopLX$Blips","parameters":{"label":"Blips","speed":3087.499975692481},"modulation":{"modulators":[],"modulations":[],"triggers":[]}}]}],"master":{"id":18,"class":"heronarts.lx.LXMasterChannel","parameters":{"label":"Master","arm":false},"effects":[],"clips":[]},"audio":{"id":20,"class":"heronarts.lx.audio.LXAudioEngine","parameters":{"label":"Audio","enabled":false},"meter":{"id":21,"class":"heronarts.lx.audio.GraphicMeter","parameters":{"label":"Meter","running":false,"trigger":false,"color/hue":350.3529357910156,"color/brightness":100.0,"color/saturation":100.0,"color":-65495,"gain":0.0,"range":48.0,"attack":10.0,"release":100.0,"slope":4.5,"Band-1":0.0,"Band-2":0.0,"Band-3":0.0,"Band-4":0.0,"Band-5":0.0,"Band-6":0.0,"Band-7":0.0,"Band-8":0.0,"Band-9":0.0,"Band-10":0.0,"Band-11":0.0,"Band-12":0.0,"Band-13":0.0,"Band-14":0.0,"Band-15":0.0,"Band-16":0.0}}},"output":{"id":19,"class":"heronarts.lx.LXEngine$Output","parameters":{"label":"Output","enabled":true,"mode":0,"fps":0.0,"gamma":1,"brightness":1.0}},"components":{"envelop":{"id":29,"class":"EnvelopLX$Envelop","parameters":{"label":"Envelop","running":true,"trigger":false},"source":{"id":30,"class":"EnvelopLX$Envelop$Source","parameters":{"label":"Source","running":true,"trigger":false,"Gain":-0.04535433070865924,"Range":18.047244094488192,"Attack":46.0,"Release":27.559055118110237,"Source-1":0.0,"Source-2":0.0,"Source-3":0.0,"Source-4":0.0,"Source-5":0.0,"Source-6":0.0,"Source-7":0.0,"Source-8":0.0,"Source-9":0.0,"Source-10":0.0,"Source-11":0.0,"Source-12":0.0,"Source-13":0.0,"Source-14":0.0,"Source-15":0.0,"Source-16":0.0}},"decode":{"id":31,"class":"EnvelopLX$Envelop$Decode","parameters":{"label":"Decode","running":true,"trigger":false,"Gain":-3.36,"Range":24.0,"Attack":25.0,"Release":50.0,"Decode-1":0.0,"Decode-2":0.0,"Decode-3":0.0,"Decode-4":0.0,"Decode-5":0.0,"Decode-6":0.0,"Decode-7":0.0,"Decode-8":0.0}}}},"modulation":{"modulators":[],"modulations":[],"triggers":[]},"osc":{"id":22,"class":"heronarts.lx.osc.LXOscEngine","parameters":{"label":"OSC","receiveHost":"0.0.0.0","receivePort":3030,"receiveActive":true,"transmitHost":"localhost","transmitPort":3131,"transmitActive":false}},"midi":{"inputs":[{"name":"CoreMIDI4J - APC40 mkII","channel":false,"control":true,"sync":false},{"name":"CoreMIDI4J - KEYBOARD","channel":true,"control":false,"sync":false}],"surfaces":[{"description":"APC40 mkII"}],"mapping":[{"channel":0,"type":"CONTROL_CHANGE","componentId":2,"parameterPath":"color/saturation","cc":55},{"channel":0,"type":"CONTROL_CHANGE","componentId":2,"parameterPath":"spreadY","cc":54},{"channel":0,"type":"CONTROL_CHANGE","componentId":2,"parameterPath":"offsetY","cc":53},{"channel":0,"type":"CONTROL_CHANGE","componentId":30,"parameterPath":"Gain","cc":48},{"channel":0,"type":"CONTROL_CHANGE","componentId":30,"parameterPath":"Range","cc":49},{"channel":0,"type":"CONTROL_CHANGE","componentId":30,"parameterPath":"Release","cc":50}]}},"externals":{"ui":{"audioExpanded":true,"paletteExpanded":true,"clipViewVisible":false,"modulatorExpanded":{},"preview":{"radius":333.1884460449219,"theta":-6.29704621779581E-16,"phi":0.08317477315664284}}}} -------------------------------------------------------------------------------- /EnvelopLX/slee-midway-180216.lxp: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1", 3 | "timestamp": 1518827348696, 4 | "engine": { 5 | "id": 1, 6 | "class": "heronarts.lx.LXEngine", 7 | "modulationColor": -16711697, 8 | "parameters": { 9 | "label": "Engine", 10 | "scene-1": false, 11 | "scene-2": false, 12 | "scene-3": false, 13 | "scene-4": false, 14 | "scene-5": false, 15 | "crossfader": 1.0, 16 | "crossfaderBlendMode": 0, 17 | "speed": 1.0, 18 | "focusedChannel": 6, 19 | "cueA": false, 20 | "cueB": false, 21 | "multithreaded": true, 22 | "channelMultithreaded": false, 23 | "networkMultithreaded": false, 24 | "framesPerSecond": 60.0 25 | }, 26 | "palette": { 27 | "id": 2, 28 | "class": "heronarts.lx.color.LXPalette", 29 | "modulationColor": -7930112, 30 | "parameters": { 31 | "label": "", 32 | "hueMode": 0, 33 | "color/brightness": 100.0, 34 | "color/saturation": 100.0, 35 | "color/hue": 167.59310496106656, 36 | "period": 120000.0, 37 | "range": 92.09302520751953 38 | } 39 | }, 40 | "channels": [ 41 | { 42 | "id": 233, 43 | "class": "heronarts.lx.LXChannel", 44 | "modulationColor": -65370, 45 | "parameters": { 46 | "label": "Decode", 47 | "arm": false, 48 | "selected": false, 49 | "enabled": true, 50 | "cue": false, 51 | "fader": 0.0, 52 | "crossfadeGroup": 0, 53 | "blendMode": 0, 54 | "midiMonitor": false, 55 | "midiChannel": 16, 56 | "autoCycleEnabled": false, 57 | "autoCycleMode": 0, 58 | "autoCycleTimeSecs": 60.0, 59 | "transitionEnabled": false, 60 | "transitionTimeSecs": 5.0, 61 | "transitionBlendMode": 0 62 | }, 63 | "effects": [], 64 | "clips": [], 65 | "patternIndex": 0, 66 | "patterns": [ 67 | { 68 | "id": 251, 69 | "class": "EnvelopLX$EnvelopDecode", 70 | "modulationColor": -8716544, 71 | "parameters": { 72 | "label": "EnvelopDecode", 73 | "mode": 0.0, 74 | "fade": 23.040680960249787, 75 | "damping": 10.0 76 | }, 77 | "modulation": { 78 | "modulators": [], 79 | "modulations": [], 80 | "triggers": [] 81 | }, 82 | "autoCycleEnabled": true 83 | }, 84 | { 85 | "id": 972, 86 | "class": "EnvelopLX$EnvelopShimmer", 87 | "modulationColor": -16711870, 88 | "parameters": { 89 | "label": "EnvelopShimmer", 90 | "intern": 0.0, 91 | "speed": 2.95511811085808, 92 | "taper": 1.255502511005022 93 | }, 94 | "modulation": { 95 | "modulators": [], 96 | "modulations": [], 97 | "triggers": [] 98 | }, 99 | "autoCycleEnabled": true 100 | } 101 | ] 102 | }, 103 | { 104 | "id": 231, 105 | "class": "heronarts.lx.LXChannel", 106 | "modulationColor": -65512, 107 | "parameters": { 108 | "label": "Objects", 109 | "arm": false, 110 | "selected": false, 111 | "enabled": true, 112 | "cue": false, 113 | "fader": 0.0, 114 | "crossfadeGroup": 0, 115 | "blendMode": 0, 116 | "midiMonitor": false, 117 | "midiChannel": 16, 118 | "autoCycleEnabled": false, 119 | "autoCycleMode": 0, 120 | "autoCycleTimeSecs": 60.0, 121 | "transitionEnabled": false, 122 | "transitionTimeSecs": 5.0, 123 | "transitionBlendMode": 0 124 | }, 125 | "effects": [], 126 | "clips": [], 127 | "patternIndex": 0, 128 | "patterns": [ 129 | { 130 | "id": 234, 131 | "class": "EnvelopLX$EnvelopObjects", 132 | "modulationColor": -65311, 133 | "parameters": { 134 | "label": "EnvelopObjects", 135 | "size": 0.0, 136 | "response": 138.95999870449305, 137 | "spread": 0.5039999950528145, 138 | "active-1": true, 139 | "active-2": true, 140 | "active-3": true, 141 | "active-4": true, 142 | "active-5": true, 143 | "active-6": true, 144 | "active-7": true, 145 | "active-8": true, 146 | "active-9": true, 147 | "active-10": true, 148 | "active-11": true, 149 | "active-12": true, 150 | "active-13": true, 151 | "active-14": true, 152 | "active-15": true, 153 | "active-16": true 154 | }, 155 | "modulation": { 156 | "modulators": [], 157 | "modulations": [], 158 | "triggers": [] 159 | }, 160 | "autoCycleEnabled": true 161 | } 162 | ] 163 | }, 164 | { 165 | "id": 5142, 166 | "class": "heronarts.lx.LXChannel", 167 | "modulationColor": -16729345, 168 | "parameters": { 169 | "label": "Texture", 170 | "arm": false, 171 | "selected": true, 172 | "enabled": true, 173 | "cue": false, 174 | "fader": 1.0, 175 | "crossfadeGroup": 0, 176 | "blendMode": 1, 177 | "midiMonitor": false, 178 | "midiChannel": 16, 179 | "autoCycleEnabled": false, 180 | "autoCycleMode": 0, 181 | "autoCycleTimeSecs": 60.0, 182 | "transitionEnabled": true, 183 | "transitionTimeSecs": 2.0, 184 | "transitionBlendMode": 0 185 | }, 186 | "effects": [], 187 | "clips": [], 188 | "patternIndex": 4, 189 | "patterns": [ 190 | { 191 | "id": 5520, 192 | "class": "heronarts.p3lx.pattern.SolidPattern", 193 | "modulationColor": -65280, 194 | "parameters": { 195 | "label": "Solid", 196 | "color/brightness": 100.0, 197 | "color/saturation": 0.0, 198 | "color/hue": 0.0 199 | }, 200 | "modulation": { 201 | "modulators": [], 202 | "modulations": [], 203 | "triggers": [] 204 | }, 205 | "autoCycleEnabled": true 206 | }, 207 | { 208 | "id": 6235, 209 | "class": "EnvelopLX$Starlight", 210 | "modulationColor": -65297, 211 | "parameters": { 212 | "label": "Starlight", 213 | "speed": 1.0, 214 | "base": 9.291338582677167 215 | }, 216 | "modulation": { 217 | "modulators": [], 218 | "modulations": [], 219 | "triggers": [] 220 | }, 221 | "autoCycleEnabled": true 222 | }, 223 | { 224 | "id": 6287, 225 | "class": "EnvelopLX$Sparkle", 226 | "modulationColor": -16711851, 227 | "parameters": { 228 | "label": "Sparkle" 229 | }, 230 | "modulation": { 231 | "modulators": [], 232 | "modulations": [], 233 | "triggers": [] 234 | }, 235 | "autoCycleEnabled": true 236 | }, 237 | { 238 | "id": 8060, 239 | "class": "EnvelopLX$Jitters", 240 | "modulationColor": -16711702, 241 | "parameters": { 242 | "label": "Jitters", 243 | "period": 1170.1555975464648, 244 | "size": 10.763779527559056, 245 | "contrast": 170.0787401574803 246 | }, 247 | "modulation": { 248 | "modulators": [], 249 | "modulations": [], 250 | "triggers": [] 251 | }, 252 | "autoCycleEnabled": true 253 | }, 254 | { 255 | "id": 18328, 256 | "class": "EnvelopLX$Bugs", 257 | "modulationColor": -10944257, 258 | "parameters": { 259 | "label": "Bugs", 260 | "speed": 19.401574803149607, 261 | "size": 0.11275590662881145 262 | }, 263 | "modulation": { 264 | "modulators": [], 265 | "modulations": [], 266 | "triggers": [] 267 | }, 268 | "autoCycleEnabled": true 269 | } 270 | ] 271 | }, 272 | { 273 | "id": 402, 274 | "class": "heronarts.lx.LXChannel", 275 | "modulationColor": -6881025, 276 | "parameters": { 277 | "label": "Kick", 278 | "arm": false, 279 | "selected": false, 280 | "enabled": true, 281 | "cue": false, 282 | "fader": 0.0, 283 | "crossfadeGroup": 0, 284 | "blendMode": 0, 285 | "midiMonitor": true, 286 | "midiChannel": 0, 287 | "autoCycleEnabled": false, 288 | "autoCycleMode": 0, 289 | "autoCycleTimeSecs": 60.0, 290 | "transitionEnabled": false, 291 | "transitionTimeSecs": 5.0, 292 | "transitionBlendMode": 0 293 | }, 294 | "effects": [], 295 | "clips": [], 296 | "patternIndex": 0, 297 | "patterns": [ 298 | { 299 | "id": 405, 300 | "class": "EnvelopLX$Flash", 301 | "modulationColor": -14745856, 302 | "parameters": { 303 | "label": "Flash", 304 | "brightness": 59.84251968503938, 305 | "attack": 214.5715791431583, 306 | "decay": 2054.312108624217, 307 | "shape": 1.7322834645669292, 308 | "velocitySensitivity": 0.5590551181102362, 309 | "manual": false, 310 | "midi": true, 311 | "midiFilter": false, 312 | "midiNote": 0 313 | }, 314 | "modulation": { 315 | "modulators": [], 316 | "modulations": [], 317 | "triggers": [] 318 | }, 319 | "autoCycleEnabled": true 320 | } 321 | ] 322 | }, 323 | { 324 | "id": 5126, 325 | "class": "heronarts.lx.LXChannel", 326 | "modulationColor": -5898496, 327 | "parameters": { 328 | "label": "Gentle", 329 | "arm": false, 330 | "selected": false, 331 | "enabled": true, 332 | "cue": false, 333 | "fader": 0.0, 334 | "crossfadeGroup": 0, 335 | "blendMode": 0, 336 | "midiMonitor": false, 337 | "midiChannel": 16, 338 | "autoCycleEnabled": false, 339 | "autoCycleMode": 0, 340 | "autoCycleTimeSecs": 60.0, 341 | "transitionEnabled": false, 342 | "transitionTimeSecs": 5.0, 343 | "transitionBlendMode": 0 344 | }, 345 | "effects": [], 346 | "clips": [], 347 | "patternIndex": 2, 348 | "patterns": [ 349 | { 350 | "id": 5127, 351 | "class": "EnvelopLX$Noise", 352 | "modulationColor": -61184, 353 | "parameters": { 354 | "label": "Noise", 355 | "scale": 32.83464566929134, 356 | "floor": -1.968503937007874, 357 | "range": 3.5511811027142004, 358 | "xSpeed": 0.0, 359 | "ySpeed": 2.692913385826772, 360 | "zSpeed": 1.0799999758601189, 361 | "xOffset": 0.5599999874830246, 362 | "yOffset": 0.0, 363 | "zOffset": 0.0 364 | }, 365 | "modulation": { 366 | "modulators": [], 367 | "modulations": [], 368 | "triggers": [] 369 | }, 370 | "autoCycleEnabled": true 371 | }, 372 | { 373 | "id": 11930, 374 | "class": "EnvelopLX$Tron", 375 | "modulationColor": -61952, 376 | "parameters": { 377 | "label": "Tron", 378 | "period": 264353.39754517336, 379 | "size": 47.566148086369935, 380 | "density": 20.500000100582838 381 | }, 382 | "modulation": { 383 | "modulators": [], 384 | "modulations": [], 385 | "triggers": [] 386 | }, 387 | "autoCycleEnabled": true 388 | }, 389 | { 390 | "id": 14567, 391 | "class": "EnvelopLX$Bugs", 392 | "modulationColor": -65284, 393 | "parameters": { 394 | "label": "Bugs", 395 | "speed": 17.673621898605013, 396 | "size": 0.16772125996110707 397 | }, 398 | "modulation": { 399 | "modulators": [], 400 | "modulations": [], 401 | "triggers": [] 402 | }, 403 | "autoCycleEnabled": true 404 | } 405 | ] 406 | }, 407 | { 408 | "id": 5519, 409 | "class": "heronarts.lx.LXChannel", 410 | "modulationColor": -16711794, 411 | "parameters": { 412 | "label": "Rain", 413 | "arm": false, 414 | "selected": false, 415 | "enabled": true, 416 | "cue": false, 417 | "fader": 0.0, 418 | "crossfadeGroup": 0, 419 | "blendMode": 0, 420 | "midiMonitor": false, 421 | "midiChannel": 16, 422 | "autoCycleEnabled": false, 423 | "autoCycleMode": 0, 424 | "autoCycleTimeSecs": 60.0, 425 | "transitionEnabled": false, 426 | "transitionTimeSecs": 5.0, 427 | "transitionBlendMode": 0 428 | }, 429 | "effects": [], 430 | "clips": [], 431 | "patternIndex": 1, 432 | "patterns": [ 433 | { 434 | "id": 5667, 435 | "class": "EnvelopLX$Raindrops", 436 | "modulationColor": -15204608, 437 | "parameters": { 438 | "label": "Rain Down", 439 | "velocity": -9.921259842519685, 440 | "randomVelocity": -26.92913385826772, 441 | "gravity": -1.5352041097782982, 442 | "size": 1.085476342260301, 443 | "randomSize": 3.105004650628199, 444 | "negative": 0.0, 445 | "auto": true, 446 | "rate": 19.399999745190144, 447 | "reverse": false 448 | }, 449 | "modulation": { 450 | "modulators": [], 451 | "modulations": [], 452 | "triggers": [] 453 | }, 454 | "autoCycleEnabled": true 455 | }, 456 | { 457 | "id": 8700, 458 | "class": "EnvelopLX$Raindrops", 459 | "modulationColor": -16711840, 460 | "parameters": { 461 | "label": "Rain Up", 462 | "velocity": -14.399999678134918, 463 | "randomVelocity": -14.399999678134918, 464 | "gravity": -1.1247266746501996, 465 | "size": 4.0, 466 | "randomSize": 1.0, 467 | "negative": 0.0, 468 | "auto": true, 469 | "rate": 25.99999998882413, 470 | "reverse": true 471 | }, 472 | "modulation": { 473 | "modulators": [], 474 | "modulations": [], 475 | "triggers": [] 476 | }, 477 | "autoCycleEnabled": true 478 | }, 479 | { 480 | "id": 6769, 481 | "class": "EnvelopLX$Tron", 482 | "modulationColor": -16748801, 483 | "parameters": { 484 | "label": "Tron", 485 | "period": 257676.75695161024, 486 | "size": 8.440696881393762, 487 | "density": 72.91338582677164 488 | }, 489 | "modulation": { 490 | "modulators": [], 491 | "modulations": [], 492 | "triggers": [] 493 | }, 494 | "autoCycleEnabled": true 495 | } 496 | ] 497 | }, 498 | { 499 | "id": 5877, 500 | "class": "heronarts.lx.LXChannel", 501 | "modulationColor": -3538689, 502 | "parameters": { 503 | "label": "Starlight", 504 | "arm": false, 505 | "selected": false, 506 | "enabled": true, 507 | "cue": false, 508 | "fader": 0.4881889763779528, 509 | "crossfadeGroup": 0, 510 | "blendMode": 0, 511 | "midiMonitor": false, 512 | "midiChannel": 16, 513 | "autoCycleEnabled": false, 514 | "autoCycleMode": 0, 515 | "autoCycleTimeSecs": 60.0, 516 | "transitionEnabled": false, 517 | "transitionTimeSecs": 5.0, 518 | "transitionBlendMode": 0 519 | }, 520 | "effects": [], 521 | "clips": [], 522 | "patternIndex": 3, 523 | "patterns": [ 524 | { 525 | "id": 5894, 526 | "class": "EnvelopLX$Sparkle", 527 | "modulationColor": -10747649, 528 | "parameters": { 529 | "label": "Sparkle" 530 | }, 531 | "modulation": { 532 | "modulators": [], 533 | "modulations": [], 534 | "triggers": [] 535 | }, 536 | "autoCycleEnabled": true 537 | }, 538 | { 539 | "id": 6183, 540 | "class": "EnvelopLX$Starlight", 541 | "modulationColor": -65347, 542 | "parameters": { 543 | "label": "Starlight", 544 | "speed": 0.7550000138580799, 545 | "base": -20.0 546 | }, 547 | "modulation": { 548 | "modulators": [], 549 | "modulations": [], 550 | "triggers": [] 551 | }, 552 | "autoCycleEnabled": true 553 | }, 554 | { 555 | "id": 7511, 556 | "class": "EnvelopLX$Jitters", 557 | "modulationColor": -16711856, 558 | "parameters": { 559 | "label": "Jitters", 560 | "period": 813.7351014849933, 561 | "size": 12.220472440944881, 562 | "contrast": 288.1889763779527 563 | }, 564 | "modulation": { 565 | "modulators": [], 566 | "modulations": [], 567 | "triggers": [] 568 | }, 569 | "autoCycleEnabled": true 570 | }, 571 | { 572 | "id": 9569, 573 | "class": "EnvelopLX$Bugs", 574 | "modulationColor": -65454, 575 | "parameters": { 576 | "label": "Bugs", 577 | "speed": 8.629921259842519, 578 | "size": 0.10000000149011612 579 | }, 580 | "modulation": { 581 | "modulators": [], 582 | "modulations": [], 583 | "triggers": [] 584 | }, 585 | "autoCycleEnabled": true 586 | } 587 | ] 588 | }, 589 | { 590 | "id": 4364, 591 | "class": "heronarts.lx.LXChannel", 592 | "modulationColor": -59392, 593 | "parameters": { 594 | "label": "Colorize", 595 | "arm": false, 596 | "selected": false, 597 | "enabled": true, 598 | "cue": false, 599 | "fader": 1.0, 600 | "crossfadeGroup": 0, 601 | "blendMode": 1, 602 | "midiMonitor": false, 603 | "midiChannel": 16, 604 | "autoCycleEnabled": false, 605 | "autoCycleMode": 0, 606 | "autoCycleTimeSecs": 60.0, 607 | "transitionEnabled": false, 608 | "transitionTimeSecs": 5.0, 609 | "transitionBlendMode": 0 610 | }, 611 | "effects": [], 612 | "clips": [], 613 | "patternIndex": 0, 614 | "patterns": [ 615 | { 616 | "id": 4365, 617 | "class": "heronarts.lx.pattern.GradientPattern", 618 | "modulationColor": -2948865, 619 | "parameters": { 620 | "label": "Gradient", 621 | "gradient": 337.3228346456692, 622 | "spreadX": 1.0, 623 | "spreadY": 0.35433070866141736, 624 | "spreadZ": 1.0, 625 | "spreadR": 0.0, 626 | "offsetX": 0.023622047244094446, 627 | "offsetY": 0.6377952755905512, 628 | "offsetZ": 0.055118110236220375, 629 | "mirror": true 630 | }, 631 | "modulation": { 632 | "modulators": [], 633 | "modulations": [], 634 | "triggers": [] 635 | }, 636 | "autoCycleEnabled": true 637 | } 638 | ] 639 | } 640 | ], 641 | "master": { 642 | "id": 18, 643 | "class": "heronarts.lx.LXMasterChannel", 644 | "modulationColor": -16711731, 645 | "parameters": { 646 | "label": "Master", 647 | "arm": false, 648 | "selected": false 649 | }, 650 | "effects": [ 651 | { 652 | "id": 254, 653 | "class": "heronarts.lx.effect.BlurEffect", 654 | "modulationColor": -65424, 655 | "parameters": { 656 | "label": "Blur", 657 | "enabled": false, 658 | "amount": 0.35000001080334187 659 | }, 660 | "modulation": { 661 | "modulators": [], 662 | "modulations": [], 663 | "triggers": [] 664 | } 665 | }, 666 | { 667 | "id": 252, 668 | "class": "EnvelopLX$LSD", 669 | "modulationColor": -42752, 670 | "parameters": { 671 | "label": "LSD", 672 | "enabled": false, 673 | "Scale": 32.049999767914414, 674 | "Speed": 1.5500000454485416, 675 | "Range": 1.544999976940453 676 | }, 677 | "modulation": { 678 | "modulators": [], 679 | "modulations": [], 680 | "triggers": [] 681 | } 682 | }, 683 | { 684 | "id": 5652, 685 | "class": "EnvelopLX$ArcsOff", 686 | "modulationColor": -65340, 687 | "parameters": { 688 | "label": "ArcsOff", 689 | "enabled": true 690 | }, 691 | "modulation": { 692 | "modulators": [], 693 | "modulations": [], 694 | "triggers": [] 695 | } 696 | } 697 | ], 698 | "clips": [] 699 | }, 700 | "tempo": { 701 | "id": 25, 702 | "class": "heronarts.lx.Tempo", 703 | "modulationColor": -7339777, 704 | "parameters": { 705 | "label": "", 706 | "clockSource": 2, 707 | "period": 560.7476516814929, 708 | "bpm": 107.0000022649765, 709 | "tap": false, 710 | "nudgeUp": false, 711 | "nudgeDown": false, 712 | "beatsPerMeasure": 4, 713 | "trigger": false, 714 | "enabled": true 715 | } 716 | }, 717 | "audio": { 718 | "id": 20, 719 | "class": "heronarts.lx.audio.LXAudioEngine", 720 | "modulationColor": -65324, 721 | "parameters": { 722 | "label": "Audio", 723 | "enabled": false, 724 | "mode": 0 725 | }, 726 | "meter": { 727 | "id": 23, 728 | "class": "heronarts.lx.audio.GraphicMeter", 729 | "modulationColor": -3211520, 730 | "parameters": { 731 | "label": "Meter", 732 | "running": true, 733 | "trigger": false, 734 | "gain": 0.0, 735 | "range": 48.0, 736 | "attack": 10.0, 737 | "release": 100.0, 738 | "slope": 4.5, 739 | "Band-1": 0.0, 740 | "Band-2": 0.0, 741 | "Band-3": 0.0, 742 | "Band-4": 0.0, 743 | "Band-5": 0.0, 744 | "Band-6": 0.0, 745 | "Band-7": 0.0, 746 | "Band-8": 0.0, 747 | "Band-9": 0.0, 748 | "Band-10": 0.0, 749 | "Band-11": 0.0, 750 | "Band-12": 0.0, 751 | "Band-13": 0.0, 752 | "Band-14": 0.0, 753 | "Band-15": 0.0, 754 | "Band-16": 0.0 755 | } 756 | }, 757 | "input": { 758 | "id": 21, 759 | "class": "heronarts.lx.audio.LXAudioInput", 760 | "modulationColor": -16711833, 761 | "parameters": { 762 | "label": "Audio Input", 763 | "device": 0 764 | } 765 | }, 766 | "output": { 767 | "id": 22, 768 | "class": "heronarts.lx.audio.LXAudioOutput", 769 | "modulationColor": -12976384, 770 | "parameters": { 771 | "label": "Audio Output", 772 | "file": "", 773 | "trigger": false, 774 | "looping": false, 775 | "play": false 776 | } 777 | } 778 | }, 779 | "output": { 780 | "id": 19, 781 | "class": "heronarts.lx.LXEngine$Output", 782 | "modulationColor": -14876417, 783 | "parameters": { 784 | "label": "Output", 785 | "enabled": true, 786 | "mode": 0, 787 | "fps": 0.0, 788 | "gamma": 1, 789 | "brightness": 0.5590551181102362 790 | } 791 | }, 792 | "components": { 793 | "envelop": { 794 | "id": 29, 795 | "class": "EnvelopLX$Envelop", 796 | "modulationColor": -30720, 797 | "parameters": { 798 | "label": "Envelop", 799 | "running": true, 800 | "trigger": false 801 | }, 802 | "source": { 803 | "id": 30, 804 | "class": "EnvelopLX$Envelop$Source", 805 | "modulationColor": -29184, 806 | "parameters": { 807 | "label": "Source", 808 | "running": true, 809 | "trigger": false, 810 | "Gain": -8.881889763779528, 811 | "Range": 52.77165354330708, 812 | "Attack": 36.22047244094488, 813 | "Release": 188.9763779527559, 814 | "Source-1": 3.4141126127027116E-245, 815 | "Source-2": 2.1101120067982768E-247, 816 | "Source-3": 8.547292381144878E-90, 817 | "Source-4": 5.5175306206366024E-90, 818 | "Source-5": 3.888804943609765E-11, 819 | "Source-6": 1.6902833018226185E-15, 820 | "Source-7": 2.132231056814402E-42, 821 | "Source-8": 5.6158919542204405E-40, 822 | "Source-9": 3.6485122463176905E-90, 823 | "Source-10": 3.044490310733106E-90, 824 | "Source-11": 0.0, 825 | "Source-12": 0.0, 826 | "Source-13": 0.0, 827 | "Source-14": 0.0, 828 | "Source-15": 0.0, 829 | "Source-16": 0.0 830 | } 831 | }, 832 | "decode": { 833 | "id": 33, 834 | "class": "EnvelopLX$Envelop$Decode", 835 | "modulationColor": -43008, 836 | "parameters": { 837 | "label": "Decode", 838 | "running": true, 839 | "trigger": false, 840 | "Gain": 0.9448818897637778, 841 | "Range": 11.669291338582678, 842 | "Attack": 36.22047244094488, 843 | "Release": 188.9763779527559, 844 | "Decode-1": 9.711935163706723E-64, 845 | "Decode-2": 4.119359291436098E-65, 846 | "Decode-3": 1.5607685791221743E-68, 847 | "Decode-4": 2.37507185099047E-70, 848 | "Decode-5": 6.276921506307395E-74, 849 | "Decode-6": 5.207799251359029E-65, 850 | "Decode-7": 1.2362755071827278E-70, 851 | "Decode-8": 7.185922287025177E-81 852 | } 853 | } 854 | } 855 | }, 856 | "modulation": { 857 | "modulators": [], 858 | "modulations": [], 859 | "triggers": [] 860 | }, 861 | "osc": { 862 | "id": 24, 863 | "class": "heronarts.lx.osc.LXOscEngine", 864 | "modulationColor": -65507, 865 | "parameters": { 866 | "label": "OSC", 867 | "receiveHost": "0.0.0.0", 868 | "receivePort": 3030, 869 | "receiveActive": true, 870 | "transmitHost": "localhost", 871 | "transmitPort": 3131, 872 | "transmitActive": false 873 | } 874 | }, 875 | "midi": { 876 | "inputs": [ 877 | { 878 | "name": "CoreMIDI4J - APC40 mkII", 879 | "channel": false, 880 | "control": true, 881 | "sync": false 882 | }, 883 | { 884 | "name": "CoreMIDI4J - SLIDER/KNOB", 885 | "channel": false, 886 | "control": true, 887 | "sync": false 888 | } 889 | ], 890 | "surfaces": [ 891 | { 892 | "description": "APC40 mkII" 893 | } 894 | ], 895 | "mapping": [ 896 | { 897 | "channel": 0, 898 | "type": "CONTROL_CHANGE", 899 | "componentId": 30, 900 | "parameterPath": "Gain", 901 | "cc": 48 902 | }, 903 | { 904 | "channel": 0, 905 | "type": "CONTROL_CHANGE", 906 | "componentId": 30, 907 | "parameterPath": "Range", 908 | "cc": 49 909 | }, 910 | { 911 | "channel": 0, 912 | "type": "CONTROL_CHANGE", 913 | "componentId": 33, 914 | "parameterPath": "Gain", 915 | "cc": 50 916 | }, 917 | { 918 | "channel": 0, 919 | "type": "CONTROL_CHANGE", 920 | "componentId": 33, 921 | "parameterPath": "Range", 922 | "cc": 51 923 | }, 924 | { 925 | "channel": 0, 926 | "type": "CONTROL_CHANGE", 927 | "componentId": 30, 928 | "parameterPath": "Attack", 929 | "cc": 52 930 | }, 931 | { 932 | "channel": 0, 933 | "type": "CONTROL_CHANGE", 934 | "componentId": 33, 935 | "parameterPath": "Attack", 936 | "cc": 52 937 | }, 938 | { 939 | "channel": 0, 940 | "type": "CONTROL_CHANGE", 941 | "componentId": 30, 942 | "parameterPath": "Release", 943 | "cc": 53 944 | }, 945 | { 946 | "channel": 0, 947 | "type": "CONTROL_CHANGE", 948 | "componentId": 33, 949 | "parameterPath": "Release", 950 | "cc": 53 951 | }, 952 | { 953 | "channel": 0, 954 | "type": "CONTROL_CHANGE", 955 | "componentId": 4365, 956 | "parameterPath": "spreadY", 957 | "cc": 55 958 | }, 959 | { 960 | "channel": 0, 961 | "type": "CONTROL_CHANGE", 962 | "componentId": 4365, 963 | "parameterPath": "spreadX", 964 | "cc": 54 965 | }, 966 | { 967 | "channel": 0, 968 | "type": "CONTROL_CHANGE", 969 | "componentId": 2, 970 | "parameterPath": "color/saturation", 971 | "cc": 13 972 | } 973 | ], 974 | "keyboard": false 975 | } 976 | }, 977 | "externals": { 978 | "ui": { 979 | "audioExpanded": true, 980 | "paletteExpanded": true, 981 | "cameraExpanded": false, 982 | "clipViewVisible": false, 983 | "modulatorExpanded": {}, 984 | "preview": { 985 | "mode": 0, 986 | "animation": false, 987 | "animationTime": 1000.0, 988 | "projection": 0, 989 | "perspective": 60.0, 990 | "depth": 1.0, 991 | "phiLock": true, 992 | "centerPoint": false, 993 | "camera": { 994 | "active": false, 995 | "radius": 361.18578066426204, 996 | "theta": 0.08700000000000015, 997 | "phi": 0.035174773156642414, 998 | "x": 0.0, 999 | "y": 71.5221939086914, 1000 | "z": 0.0 1001 | }, 1002 | "cue": [ 1003 | { 1004 | "active": false, 1005 | "radius": 361.18578066426204, 1006 | "theta": 0.08700000000000015, 1007 | "phi": 0.035174773156642414, 1008 | "x": 0.0, 1009 | "y": 71.5221939086914, 1010 | "z": 0.0 1011 | }, 1012 | { 1013 | "active": false, 1014 | "radius": 120.0, 1015 | "theta": 0.0, 1016 | "phi": 0.0, 1017 | "x": 0.0, 1018 | "y": 0.0, 1019 | "z": 0.0 1020 | }, 1021 | { 1022 | "active": false, 1023 | "radius": 120.0, 1024 | "theta": 0.0, 1025 | "phi": 0.0, 1026 | "x": 0.0, 1027 | "y": 0.0, 1028 | "z": 0.0 1029 | }, 1030 | { 1031 | "active": false, 1032 | "radius": 120.0, 1033 | "theta": 0.0, 1034 | "phi": 0.0, 1035 | "x": 0.0, 1036 | "y": 0.0, 1037 | "z": 0.0 1038 | }, 1039 | { 1040 | "active": false, 1041 | "radius": 120.0, 1042 | "theta": 0.0, 1043 | "phi": 0.0, 1044 | "x": 0.0, 1045 | "y": 0.0, 1046 | "z": 0.0 1047 | }, 1048 | { 1049 | "active": false, 1050 | "radius": 120.0, 1051 | "theta": 0.0, 1052 | "phi": 0.0, 1053 | "x": 0.0, 1054 | "y": 0.0, 1055 | "z": 0.0 1056 | } 1057 | ], 1058 | "focus": 0, 1059 | "pointCloud": { 1060 | "pointSize": 3.0 1061 | } 1062 | } 1063 | } 1064 | } 1065 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013-2018 Mark C. Slee, Heron Arts LLC 2 | 3 | LX STUDIO SOFTWARE LICENSE AND DISTRIBUTION AGREEMENT 4 | 5 | This Software License and Distribution Agreement (the "Agreement") is entered 6 | into by and between Heron Arts LLC, with offices at 7 Heron Street, San 7 | Francisco, CA 94103 ("Heron Arts") and you ("Licensee"). By downloading or 8 | using the Software (as defined below), you agree to the following terms: 9 | 10 | 1. Definitions. 11 | 12 | 1.1. "Application" means a Licensee installation or project that includes the 13 | Software, in object code or executable form only. 14 | 15 | 1.2. "Effective Date" means the date you first obtain a copy of the Software. 16 | 17 | 1.3. "Revenue Limit" means the gross revenue accrued by Licensee in connection 18 | with all Licensee Applications, taken together, for any 12-month period during 19 | the term of this Agreement, with no deductions. 20 | 21 | 1.4. "Software" means the Heron Arts LX software libraries, including all 22 | Updates supplied by Heron Arts under this Agreement. 23 | 24 | 1.5. "Update" means any correction, update, upgrade, patch or other 25 | modification or addition to the Software made available to Licensee by Heron 26 | Arts. 27 | 28 | 2. License. 29 | 30 | 2.1. Grant. Subject to the limitations of this Section 2, Heron Arts hereby 31 | grants to Licensee a nonexclusive, worldwide, non-transferable, 32 | non-sublicenseable license, during the term of this Agreement: (i) to modify 33 | the Software to create Applications that add substantial value to the Software; 34 | (ii) to distribute copies of the Software, in object code form only, only as 35 | part of Applications in accordance with this Section 2; (iii) to use the 36 | Software to run Applications, including to provide a service consisting of 37 | display of the Applications; and (iv) to reproduce copies of the Software, 38 | solely as necessary to exercise the rights granted in clauses (i) through (iv). 39 | Licensee may not sublicense any of these rights or licenses to any third party. 40 | Licensee shall not provide any third party with access to the source code for 41 | the Software without Heron Arts' prior written permission. 42 | 43 | The license granted in this Section 2.1 is subject to a Revenue Limit of 44 | $25,000 and is only valid for Applications that fall within such Revenue Limit. 45 | The license granted herein is royalty free, in consideration of the Revenue 46 | Limit being a condition of the license granted herein. 47 | 48 | 2.2. End User Licensing. If the Application is distributed, provided or sold 49 | pursuant to an agreement between Licensee and an end user, Licensee shall 50 | distribute each copy of the Software with an end user license agreement on the 51 | same licensing terms applicable to the remainder of the Application, but that 52 | is at least as favorable to Heron Arts as this Agreement. 53 | 54 | 2.3. Proprietary Notices. On each Software copy, Licensee shall reproduce all 55 | copyright or other proprietary notices contained on the Software, as provided 56 | by Heron Arts. Licensee shall not alter or remove or in any other way obscure 57 | or hide from display any Heron Arts or LX Studio logo or proprietary notice 58 | from the Application user interface or in the Software. 59 | 60 | 2.4. Third Party Open Source Software. Notwithstanding Section 2.1, Licensee 61 | acknowledges that certain components of the Software may be covered by 62 | so-called "open source" software licenses ("Open Source Components"), which 63 | means any software licenses approved as open source licenses by the Open Source 64 | Initiative or any substantially similar licenses. To the extent required by the 65 | licenses covering Open Source Components, the terms of such licenses will apply 66 | to such Open Source Components in lieu of the terms of this Agreement. To the 67 | extent the terms of the licenses applicable to Open Source Components prohibit 68 | any of the restrictions in this Agreement with respect to such Open Source 69 | Component, such restrictions will not apply to such Open Source Component. To 70 | the extent the terms of the licenses applicable to Open Source Components 71 | require Licensor to make an offer to provide source code or related information 72 | in connection with the Open Source Components, such offer is hereby made. 73 | 74 | 3. Ownership. As between the parties, Heron Arts will retain all right, title, 75 | and interest in the Software, and all intellectual property rights therein. 76 | 77 | 4. Use of Heron Arts Trademarks. Licensee shall state that the Application 78 | includes the Software and may use such applicable trademarks, trade names and 79 | logos of Heron Arts (including the LX Studio trademarks) as required to do so 80 | (collectively, the "Heron Arts Trademarks"). Any and all good will arising from 81 | Licensee's use of the Heron Arts Trademarks will inure solely to the benefit of 82 | Heron Arts. Licensee shall not assert any claim to the Heron Arts Trademarks 83 | (or any confusingly similar mark) or such good will. Licensee shall not 84 | register any Heron Arts Trademark, or any mark confusingly similar to any Heron 85 | Arts Trademark, in any jurisdiction. 86 | 87 | 5. Heron Arts Portfolio. (i) Licensee hereby grants to Heron Arts the right to 88 | publicize Licensee's use of the Software and (ii) Heron Arts may use Licensee's 89 | logo on the LX Studio website in areas naming licensees of the software, and in 90 | LX Studio portfolios or marketing presentations listing licensees of the 91 | Software. 92 | 93 | 6. Term and Termination. 94 | 95 | 6.1. Term. This Agreement will commence on the Effective Date and continue 96 | unless and until terminated as described herein. 97 | 98 | 6.2. Default. If Licensee defaults in the performance of any of its material 99 | obligations hereunder this Agreement and the licenses granted herein will 100 | automatically terminate. 101 | 102 | 6.3. Insolvency. This Agreement and the licenses granted herein will 103 | automatically terminate, (i) upon the institution by Licensee of insolvency, 104 | receivership or bankruptcy proceedings or any other proceedings for the 105 | settlement of its debts, (ii) upon the institution of such proceedings against 106 | Licensee, which are not dismissed or otherwise resolved in its favor within 60 107 | days thereafter, (iii) upon Licensee making a general assignment for the 108 | benefit of creditors, or (iv) upon Licensee's dissolution or ceasing to conduct 109 | business in the ordinary course. 110 | 111 | 6.4. Survival. The parties' rights and obligations of Sections 1, 3, 4, 5, 6.4, 112 | 7, 8 and 9 will survive any termination or expiration of this Agreement. Upon 113 | expiration or termination of this Agreement, all of Licensee's rights and 114 | licenses with respect to the Software will terminate, except each Software end 115 | user license properly granted as part of an Application before the effective 116 | date of termination will survive in accordance with its terms. 117 | 118 | 7. Warranty Disclaimer. 119 | 120 | 7.1. DISCLAIMER. HERON ARTS MAKES NO WARRANTY, EXPRESS, IMPLIED, STATUTORY, OR 121 | OTHERWISE, AND SPECIFICALLY DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, 122 | NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE, WITH RESPECT TO THE 123 | SOFTWARE. 124 | 125 | 8. LIMITATION OF LIABILITY. HERON ARTS'S LIABILITY ARISING OUT OF THIS 126 | AGREEMENT WILL NOT EXCEED $50. HERON ARTS WILL NOT BE LIABLE FOR LOST PROFITS 127 | OR ANY CONSEQUENTIAL, SPECIAL, INCIDENTAL, OR INDIRECT DAMAGES, HOWEVER CAUSED 128 | AND ON ANY THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. LICENSEE 129 | ACKNOWLEDGES THAT THE ROYALTY-FREE NATURE OF THE LICENSE HEREIN IS BASED IN 130 | PART UPON THESE LIMITATIONS, AND THAT THESE LIMITATIONS WILL APPLY 131 | NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. 132 | 133 | 9. General. This Agreement is the entire agreement between the parties on the 134 | subject matter hereof. No amendment or modification hereof will be valid or 135 | binding upon the parties unless made in writing and signed by the duly 136 | authorized representatives of both parties. The relationship of the parties 137 | hereunder is that of independent contractors, and this Agreement will not be 138 | construed to imply that either party is the agent, employee, or joint venturer 139 | of the other. In the event that any provision of this Agreement is held to be 140 | unenforceable, this Agreement will continue in full force and effect and will 141 | be interpreted to reflect the original intent of the parties. This Agreement 142 | will be governed by the laws of the State of California, without regard to its 143 | conflict of laws principles. The parties consent to the personal and exclusive 144 | jurisdiction of courts located in San Francisco, California. Licensee may not 145 | assign this Agreement (by operation of law or otherwise) without the prior 146 | written consent of Heron Arts, and any prohibited assignment will be null and 147 | void. Heron Arts may assign this Agreement without consent in its sole 148 | discretion. This Agreement will be binding upon and will inure to the benefit 149 | of the parties permitted successors and assignees. Waiver by either party of a 150 | breach of any provision of this Agreement or the failure by either party to 151 | exercise any right hereunder will not operate or be construed as a waiver of 152 | any subsequent breach of that right or as a waiver of any other right. 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![EnvelopLX](media/enveloplx-screenshot.png) 2 | 3 | [Envelop](http://envelop.us) is a non-profit organization that amplifies the connective power of music through immersive listening spaces and open source spatial audio software. Three-dimensional experiences of sound and music bring people together, catalyzing shared moments of inspiration, empathy and wonder. 4 | 5 | **EnvelopLX** is an interactive lighting application for [Envelop](http://www.envelop.us/). It runs in Processing using the [LX Studio](https://github.com/heronarts/LXStudio) framework. The system may be controlled directly, or via remote OSC control from [Envelop for Live](https://github.com/EnvelopSound/EnvelopForLive) devices, which can be composed and sequenced within Ableton Live 10. Real-time spatial audio metering and position data can also be used to control animation. 6 | 7 | ***EnvelopLX is free to use — but it takes time, energy, and resources to create and maintain. If you find these tools useful, please consider making a donation to support the Envelop nonprofit organization: https://www.envelop.us/membership-donations*** 8 | 9 | 10 | ## Installation 11 | 12 | First, download and install [Processing 3 →](https://processing.org/download/?processing) 13 | 14 | ### For Users 15 | 16 | - [Download the software →](https://github.com/EnvelopSound/EnvelopLX/archive/master.zip) 17 | - Open EnvelopLX.pde in Processing and run the sketch 18 | 19 | ### For Developers 20 | 21 | Make a clone of the repository in your Processing sketchbook folder. 22 | 23 | ```Shell 24 | $ cd ~/Documents/Processing/ 25 | $ git clone https://github.com/EnvelopSound/EnvelopLX.git 26 | $ cd EnvelopLX 27 | $ git checkout -b 28 | $ open EnvelopLX/EnvelopLX.pde 29 | ``` 30 | 31 | --- 32 | 33 | **BY DOWNLOADING OR USING THE LX STUDIO SOFTWARE OR ANY PART THEREOF, YOU AGREE TO THE TERMS AND CONDITIONS OF THE [LX STUDIO SOFTWARE LICENSE AND DISTRIBUTION AGREEMENT](http://lx.studio/license).** 34 | 35 | Please note that LX Studio is not open-source software. The license grants permission to use this software freely in non-commercial applications. Commercial use is subject to a total annual revenue limit of $25K on any and all projects associated with the software. If this licensing is obstructive to your needs or you are unclear as to whether your desired use case is compliant, contact me to discuss proprietary licensing: mark@heronarts.com 36 | -------------------------------------------------------------------------------- /media/enveloplx-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnvelopSound/EnvelopLX/7a0f9bcd1e1fff8ef91906fde0822a19432025a2/media/enveloplx-screenshot.png --------------------------------------------------------------------------------