Showing preview only (388K chars total). Download the full file or copy to clipboard to get everything.
Repository: ffd8/xyscope
Branch: main
Commit: 74e0947c6584
Files: 57
Total size: 366.8 KB
Directory structure:
gitextract_zbh9fj9i/
├── .gitignore
├── README.md
├── changelog.txt
├── examples/
│ ├── 1_getting_started/
│ │ ├── basic_drawing/
│ │ │ └── basic_drawing.pde
│ │ ├── calibration/
│ │ │ └── calibration.pde
│ │ ├── clock/
│ │ │ └── clock.pde
│ │ ├── custom_soundcard/
│ │ │ └── custom_soundcard.pde
│ │ ├── lissapong/
│ │ │ └── lissapong.pde
│ │ └── template/
│ │ └── template.pde
│ ├── 2_shapes/
│ │ ├── a_walkthrough_primatives/
│ │ │ └── a_walkthrough_primatives.pde
│ │ ├── additive_synth_shapes/
│ │ │ └── additive_synth_shapes.pde
│ │ ├── lissajous/
│ │ │ └── lissajous.pde
│ │ ├── paramless_shapes/
│ │ │ └── paramless_shapes.pde
│ │ ├── sphere/
│ │ │ └── sphere.pde
│ │ └── torus/
│ │ └── torus.pde
│ ├── 3_typography/
│ │ ├── hershey_fonts/
│ │ │ └── hershey_fonts.pde
│ │ └── scopewriter/
│ │ └── scopewriter.pde
│ ├── 4_inputs/
│ │ ├── fonts/
│ │ │ └── fonts.pde
│ │ ├── kinect/
│ │ │ └── kinect.pde
│ │ ├── obj/
│ │ │ └── obj.pde
│ │ ├── svg/
│ │ │ └── svg.pde
│ │ ├── syphon/
│ │ │ └── syphon.pde
│ │ ├── video/
│ │ │ └── video.pde
│ │ ├── webcam/
│ │ │ └── webcam.pde
│ │ └── webcam_processing4/
│ │ └── webcam_processing4.pde
│ ├── 5_displays/
│ │ ├── laser/
│ │ │ └── laser.pde
│ │ └── vectrex/
│ │ └── vectrex.pde
│ ├── 6_outputs/
│ │ ├── audio_recorder/
│ │ │ └── audio_recorder.pde
│ │ └── osc_wavetables/
│ │ └── osc_wavetables.pde
│ ├── 7_custom_waves/
│ │ ├── customWaves_drawingXYZ/
│ │ │ └── customWaves_drawingXYZ.pde
│ │ ├── customWaves_noiseXY/
│ │ │ └── customWaves_noiseXY.pde
│ │ └── setWaveforms_noise/
│ │ └── setWaveforms_noise.pde
│ ├── 8_music/
│ │ ├── MidiScope/
│ │ │ └── MidiScope.pde
│ │ ├── audio_filters/
│ │ │ └── audio_filters.pde
│ │ └── freq_keyboard_notes/
│ │ └── freq_keyboard_notes.pde
│ └── 9_misc/
│ ├── freq_amp_modulation/
│ │ └── freq_amp_modulation.pde
│ └── multiscopes_class/
│ └── multiscopes_class.pde
├── license.txt
├── resources/
│ ├── README.md
│ ├── build.properties
│ ├── build.xml
│ ├── code/
│ │ ├── ExampleTaglet.java
│ │ ├── ant-contrib-1.0b3.jar
│ │ └── doc.sh
│ ├── library.properties
│ └── stylesheet.css
├── src/
│ └── xyscope/
│ ├── XYWavetable.java
│ └── XYscope.java
└── web/
├── includes/
│ ├── css/
│ │ └── styles.css
│ └── js/
│ ├── highlight/
│ │ ├── a11y-dark.css
│ │ ├── a11y-light.css
│ │ ├── docco.css
│ │ ├── github.css
│ │ └── highlight.pack.js
│ ├── render.js
│ └── stmd.js
└── index.html
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
distribution
data
lib
test
.DS_Store
.project
.classpath
tmp
/bin/
_sandbox
examples_removed
.settings
================================================
FILE: README.md
================================================
# XYscope
v 3.0.0
cc [teddavis.org](https://teddavis.org) 2017 – 2023
Processing library to render vector graphics on vector displays.
XYscope converts the coordinates of primative shapes (point, line, rect, ellipse, vertex, box, sphere, torus...)to audio waveforms (oscillators with custom wavetables) which are sent to an analog display, revealing their graphics. This process of generating real-time audio from vector drawings is built upon the amazing Minim library. Vector graphics shine on a vector display and now we can view our generative works like never before! Tested on MacOS, Windows, Linux (RPi!).
[teddavis.org/xyscope](http://www.teddavis.org/xyscope)
[github.com/ffd8/xyscope](https://github.com/ffd8/xyscope)
## Table of Contents
- [Installation](#installation)
- [Audio Interfaces](#audio-interfaces)
- [Vector Displays](#vector-displays)
- [Getting Started](#getting-started)
- [Additive Synthesis](#additive-synthesis)
- [References](#references)
- [Extras ](#extras)
## Installation
Add via Processing's Library Manager:
- Sketch menu » Import Library... » Add Library... (v4 Manage Libraries...)
- Search for 'XYscope' and click `Install`.
- Search for 'Minim' and click `Install`.
This library relies on and is infinitely thankful for [Minim](https://github.com/ddf/Minim)!
Search for and add the following libraries for various examples:
[Geomerative](https://github.com/rikrd/geomerative), [OpenCV for Processing](https://github.com/atduskgreg/opencv-processing), [openkinect](https://github.com/shiffman/OpenKinect-for-Processing), [video](https://github.com/processing/processing-video), [syphon](https://github.com/Syphon/Processing)
Add manually, [download latest release](https://github.com/ffd8/xyscope/releases/latest) and expand into `~/Processing/libraries`:
## Audio Interfaces
*< $5*
At the very least you can use your computer's headphone jack with an [`1/8" to RCA`](https://duckduckgo.com/?q=1%2F8%22+to+RCA&t=h_&iax=images&ia=images) cable. However you'll soon want to get a [DC-Coupled](https://www.expert-sleepers.co.uk/siwacompatibility.html) audio interface for a cleaner and more stable visual (not wobbling/centering constantly).
*< $20*
For workshops I like to use some variant of the 48Khz [Delock 61645](https://www.delock.com/produkt/61645/merkmale.html) or 96Khz [Delock 63926](https://www.delock.com/produkt/63926/merkmale.html) – you'll find the same chip under many different brands and casings. For modern laptops, there's also a very compact 96Khz [Delock USB-C](https://www.delock.com/produkt/66304/merkmale.html) version.
*> $150+*
Many of us in the community found the [MOTU Ultralite Mk3 Hybrid](https://motu.com/products/motuaudio/ultralite-mk3) (or newer versions) to be an ideal audio interface. Price varies from used to new. It offers, 10-channels of DC-Coupled 196Khz output, which is useful to drive multiple oscilloscopes or RGB lasers (X, Y, R, G, B).
### List
Check which interface is plugged in and how to reference it.
```
xy.getMixerInfo(); // lists available audio devices
```
### Select
By default XYscope uses the system settings audio-output, however we can specify a custom sound card (Digital Analog Converter – DAC) and sample rate.
```
xy = new XYscope(this); // system settings soundcard
xy = new XYscope(this, "MOTU 1_2"); // specify a soundcard/channel to use
xy = new XYscope(this, 96000); // custom sample rate ( > finer detail if card supports)
xy = new XYscope(this, "MOTU 1_2", 96000); // custom soundcard, custom sample rate
```
Or select a previous XYscope instance as the output for additive-synthesis:
```
xy2 = new XYscope(this, xy.outXY); // send 2nd instance to 1st
```
### Aggregate Device
If you have a multi-channel DAC, we need to create multiple 2ch stereo pairs, since Processing/Minim can't handel multi-channel devices. Especially useful with a great DAC like the MOTU Ultralite Mk3 Hybrid (or newer), offering 10ch of DC-Coupled outputs, so one could control 5 oscillscopes at once! Have only tested using MacOS:
- Press `CMD + Spacebar` (opens Spotlight Search)
- Type `Audio Midi Setup`, press `ENTER`
- Click `+` in lower left, select `Create Aggregate Device`
- Tick checkbox of your multi-channel audio device
- Click `Configure Speakers...` in lower right
- Set configuration to `Stereo`, select channels desired
- Rename to something like: `MOTU 1_2`
- Repeat above for each stereo pair, ie, `MOTU 3_4`, `MOTU 5_6`...
- They can now be selected by name when initializing XYscope!
### Multi-Channel Output Device
Within `Audio Midi Setup`, you can `Create Multi-Output Device` to send your output to multiple devices, ie. [Blackhole](https://existential.audio/blackhole/) + DAC + Speakers, so you can view it [virtually](https://www.oscilloscopemusic.com/software/oscilloscope/), on analog device, and hear it.
- Press `CMD + Spacebar` (opens Spotlight Search)
- Type `Audio Midi Setup`, press `ENTER`
- Click `+` in lower left, select `Create Multi-Channel Device`
- Tick checkbox of best device first, then select additional
- Set sample rate to highest available, 48000 or 96000+
- Rename for clarity, ie `DAC + SPEAKERS` or `BLACKHOLE + SPEAKERS`.
## Vector Displays
Now we need a vector display to see our glowing output!
### Virtual
[Oscilloscope](https://www.oscilloscopemusic.com/software/oscilloscope/) by Hansi Raber (adopting [m1el's woscope](http://m1el.github.io/woscope-how/) 'physical rendering') is a fantastic way to see your XYscope drawings while on the go without a physical device. You'll want to install [Blackhole](https://existential.audio/blackhole/) (MacOS) or [VB-CABLE](https://vb-audio.com/Cable/index.htm) (Windows) to re-route your system audio to a virtual source for Oscilloscope to render it.
### Analog Oscilloscope
This is what we really want! They have a Cathode-ray Tube (CRT) that is the magic behind this obsession. You'll find them for ~$50 used on auction websites – be sure it has 2-channels (z-axis input is a bonus) and that they show images of a sharp working beam. You'll need a few [`RCA to BNC`](https://duckduckgo.com/?q=RCA+to+BNC&t=h_&iar=images&iax=images&ia=images) adaptors to interface with it. Have fun playing with all the knobs to put it into `XY Mode` so that the 2-channels drive the beam X/Y (Horizontal/Vertical).
### X-Y Monitor
Similar to an analog oscilloscope, but usually has a larger display and reduced controls for X-Y (+Z) input, leaving away many of the features on an oscilloscope we won't use. They're more rare, expensive, but great if you stumble upon one. Don't confuse these with a 'vector monitor' which is used for TV broadcast and won't draw X-Y coordinates.
### Vectrex
A vector-graphics video game system of the 1980s, these amazing 9" displays can be [very carefully modified](http://users.sussex.ac.uk/~ad207/adweb/assets/vectrexminijackinputmod2014.pdf) (**CAREFUL - at own risk**) to override (on-demand) the videogame control of the monitor's XYZ inputs. It's ideal to use [switching jacks](https://www.youtube.com/watch?v=q3sKZA2r7qk) so videogames still works when cables are unplugged. You'll also want to apply the [SPOT KILLER MOD](https://www.facebook.com/groups/vectorsynthesis/posts/832237263652516/), but BE SURE to apply an appropriately high-voltage rated switch, so it can be toggled on and off.
XYscope has a special mode when using a Vectrex for the aspect ratio. See example `vextrex` within `5_displays`, but the main notes are:
```
/* within setup() */
xy.vectrex(90); // -90/90 for landscape, 0 for portrait
// optionally z-axis for blanking
xy.z("MOTU 3-4"); // use custom 3rd channel for z-axis
//xy.zRange(.5, 0); // set min/max values for beam on/off
```
### Laser
Once you want something bigger than most screens, you'll want to move to an RGB Laser. They're BIG and BRIGHT, but also much slower and more dangerous! It's slower because it mechanically moves galvos/mirrors for the X-Y and dangerous, because, LASERS! Nevertheless, they can be controlled via the ILDA analog input, for which I've developed an easy to build [dac_ilda adaptor](https://github.com/ffd8/dac_ilda). To control a laser, you'll need a DAC (sound card) with a minimum of 5-channels, for sending `X, Y, R, G, B` signals. See example `laser` within `5_displays`, but the main notes are:
```
/* within setup() */
// only stereo pairs in processing, so it's broken to R, GB
// incase 2nd channel of R pair is useful for blanking/etc.
xy.laser("MOTU 3-4", "MOTU 5-6"); //xy.laser(mixerR, mixerGB);
/* within setup() or draw() */
// RGB waveforms have own freq, so we can them out of sync
xy.strokeFreq(50.05, 50.1, 50.2);
xy.strokeDash(8); // optional dashes in the RGB stroke
xy.stroke(0, 255, 255); // set RGB stroke before shapes (0-255)
xy.limitPath(0); // avoid drawing any forms beyond view
```
## Getting Started
Our basic template for an XYscope sketch involves:
```
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup(){
size(512, 512); // window size, optionally add P3D
xy = new XYscope(this, ""); // define XYscope instance, "custom_dac" optional
xy.getMixerInfo(); // lists all audio devices
}
void draw(){
background(0);
xy.clearWaves(); // clear waves from previous drawing
// draw shapes here
xy.circle(width/2, height/2, width); // it all began with a circle....
xy.buildWaves(); // build shapes to audio waves
xy.drawAll();
}
```
## Additive Synthesis
Something very unique to this workflow is sending multiple audio signals to the oscilloscope, which interfer and modulate one another. As these waves combine, their amp and freq determine its influence on other waves. Key is having different frequencies and amplitudes to modulate off one another. The lower the frequency, the more it will push other waves around. The lower the amp, the less influence it has on the additive waveform. We can simply open two sketches, both being sent to the same sound card to see this in action, however we can also achieve it within a single sketch.
```
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy, xy2; // create 2x XYscope instances
void setup() {
size(512, 512); // declares size of output window
xy = new XYscope(this);
xy2 = new XYscope(this, xy.outXY); // patch 2nd instance to 1st output
}
void draw() {
background(0);
// set main shapes
xy.clearWaves();
xy.circle(width/2, height/2, width/2);
xy.buildWaves();
xy.drawPath(0, 255, 255); // custom stroke color
xy.drawXY(); // displays combined output
// additive synth on 2nd instance of XYscope
xy2.clearWaves();
xy2.freq(mouseX); // without speakers, test really high freqs!
//xy2.amp(.2); // experiment with high freq, low amp modulation
xy2.circle(width/2, height/2, mouseY);
xy2.buildWaves();
xy2.drawPath(255, 255, 0); // custom stroke color
}
```
Additional tips:
- No need to stop at just 2, add as many as needed!
- Ratio between freqs is crucial, diff of +/- .1 animates things.
- Really low frequencies animate shapes over that path.
- Really high frequencies display shape made of 2nd shape.
- Play with position of 2nd shape, from center to corners.
## References
XYscope is a class, so after an instance has been defined to a variable, we'll use that prefix in front of every function listed below, ie: `xy.ellipse()`. This enables us to have multiple XYscope instances running parallel, which will reveal wild and crazy audio/visuals. All examples below use `xy` as the instance prefix.
- [Initialize XYscope](#initialize-xyscope)
- [Z-axis](#z-axis)
* [z()](#z())
* [zAuto()](#zauto())
- [Audio Interface Settings](#audio-interface-settings)
* [getMixerInfo()](#getmixerinfo())
* [sampleRate()](#samplerate())
* [bufferSize()](#buffersize())
- [Waves](#waves)
* [resetWaves()](#resetwaves())
* [clearWaves()](#clearwaves())
* [buildWaves()](#buildwaves())
* [buildX()](#buildx())
* [buildY()](#buildy())
* [buildZ()](#buildz())
* [waveSize()](#wavesize())
* [setWaveforms()](#setwaveforms())
- [Points](#points)
* [wavePoints()](#wavepoints())
* [steps()](#steps())
* [limitPoints()](#limitpoints())
* [limitPath()](#limitpath())
- [Record Audio](#record-audio)
* [recorderBegin()](#recorderbegin())
* [recorderEnd()](#recorderend())
- [Primitive Shapes](#primitive-shapes)
* [point()](#point())
* [line()](#line())
* [square()](#square())
* [rect()](#rect())
* [circle()](#circle())
* [ellipse()](#ellipse())
* [complex shape](#complex-shape)
* [lissajous()](#lissajous())
* [box()](#box())
* [sphere()](#sphere())
* [ellipsoid()](#ellipsoid())
* [torus()](#torus())
- [Text](#text)
* [text()](#text())
* [textPaths()](#textpaths())
* [textFont()](#textfont())
* [textSize()](#textsize())
* [textLeading()](#textleading())
* [textAlign()](#textalign())
* [textWidth()](#textwidth())
- [Modulation](#modulation)
* [freq()](#freq())
* [amp()](#amp())
* [pan()](#pan())
- [Vectrex](#vectrex)
- [Laser](#laser)
- [Rendering](#rendering)
- [Vars](#vars)
---
### Initialize XYscope
```
xy = new XYscope(this); // system audio settings
xy = new XYscope(this, "custom_dac"); // custom audio card
xy = new XYscope(this, xy_instance.outXY); // another XYscope out
xy = new XYscope(this, sampleRate); // default sampleRate is 41000
xy = new XYscope(this, "custom_dac", sampleRate); // default sampleRate is 41000
xy = new XYscope(this, "custom_dac", sampleRate, bufferSize); // default bufferSize is 512
```
---
### Z-axis
#### z()
```
xy.z("custom_dac"); // set audio out for z-axis (blanking)
xy.z("custom_dac", sampleRate); // add custom sampleRate
```
#### zAuto()
```
// somewhat deprecated.. may return
xy.zAuto(); // get setting for using z-axis
xy.zAuto(boolean); // set auto use of z-axis
```
---
### Audio Interface Settings
#### getMixerInfo()
```
xy.getMixerInfo(); // list connected audio interfaces
```
#### sampleRate()
```
xy.sampleRate(); // get current sampleRate, default 41000
xy.sampleRate(newRate); // set new sampleRate (int)
```
#### bufferSize()
```
xy.bufferSize(); // get current bufferSize, default 512
xy.bufferSize(newSize); // set new bufferSize (int)
```
---
### Waves
#### resetWaves()
```
xy.resetWaves(); // fix any sync issues with phase of waves
```
#### clearWaves()
```
xy.clearWaves(); // clear wavetables from any previous drawing
```
#### buildWaves()
```
xy.buildWaves(); // compile drawn shapes into new wavetables/audio
xy.buildWaves(-1); // draw in v1 style
xy.buildWaves(-2); // draw in v2 style
xy.buildWaves(-3); // draw in v3 style
```
#### buildX()
```
xy.buildX(newWave); // build wavetableX with float[] array
```
#### buildY()
```
xy.buildY(newWave); // build wavetableY with float[] array
```
#### buildZ()
```
xy.buildZ(newWave); // build wavetableZ with float[] array
```
#### waveSize()
```
xy.waveSize(); // get current size of wavetables
xy.waveSize(newSize); // set new wavetable size, default is 512
```
#### setWaveforms()
```
xy.setWaveforms(wfX, wfY, wfZ); // set wavetables with float[] arrays
```
---
### Points
#### wavePoints()
```
xy.wavePoints(); // get PVector ArrayList of all drawn coordinates (0.0 – 1.0)
```
#### steps()
```
xy.steps(); // get current steps between points, default 24
xy.steps(newVal); // set step multiplier, segments, between points
```
#### limitPoints()
```
xy.limitPoints(); // get number of limited drawing points
xy.limitPoints(newLimit); // set new limit of points for drawing
```
#### limitPath()
```
xy.limitPath(); // get current limit of drawn path
xy.limitPath(newLimit); // avoid drawn vectors beyond border edges (px)
```
---
### Record Audio
Easily save your drawings as .wav audio files! Just use a keyPress to initiate starting and stopping the recording (see demo). Recording uses our set sampleRate.
#### recorderBegin()
```
xy.recorderBegin(); // will name file "XYscope_timestamp.wav"
xy.recorderBegin("customName"); // set name, timestamp added
```
#### recorderEnd()
```
xy.recorderEnd(); // complete recording
```
---
### Primitive Shapes
Most primitives from Processing have been ported, so you only need to add `xy.` in front of them! They can also be used without parameters, for quickly testing.
#### point()
```
xy.point();
xy.point(x, y);
xy.point(x, y, z);
```
#### line()
```
xy.line();
xy.line(x1, y1, x2, y2);
xy.line(x1, y1, z1, x2, y2, z2);
```
#### square()
```
xy.rectMode(); // default CORNER, CENTER to draw center out
xy.square();
xy.square(x, y, w);
```
#### rect()
```
xy.rectMode(); // default CORNER, CENTER to draw center out
xy.rect();
xy.rect(x, y, w);
xy.rect(x, y, w, h);
```
#### circle()
```
xy.ellipseDetail(); // get current facets of ellipse
xy.ellipseDetail(newVal); // set new count of facets, default 30
xy.circle();
xy.circle(x, y, w);
```
#### ellipse()
```
xy.ellipseDetail(); // get current facets of ellipse
xy.ellipseDetail(newVal); // set new count of facets, default 30
xy.ellipse();
xy.ellipse(x, y, w);
xy.ellipse(x, y, w, h);
```
#### complex shape
```
xy.beginShape();
xy.vertex();
xy.vertex(x, y);
xy.vertex(x, y, z); // if in P3D mode
// ...
xy.endShape();
xy.endShape(CLOSE); // closes form
```
#### lissajous()
```
xy.lissajous();
xy.lissajous(x, y, radius, ratioA, ratioB, phase, resolution);
```
#### box()
```
xy.box();
xy.box(size);
xy.box(rx, ryz);
xy.box(rx, ry, rz);
```
#### sphere()
```
xy.sphere();
xy.sphere(size);
xy.sphere(size, detailXY); // default 24
xy.sphere(size, detailX, detailY); // default 24, 24
```
#### ellipsoid()
```
xy.ellipsoid();
xy.ellipsoid(rx, ry, rz);
xy.ellipsoid(rx, ry, rz, detailXY); // default 24
xy.ellipsoid(rx, ry, rz, detailX, detailY); // default 24, 24
```
#### torus()
```
xy.torus();
xy.torus(radius, tubeRadius);
xy.torus(radius, tubeRadius, detailXY); // default 24
xy.torus(radius, tubeRadius, detailX, detailY); // default 24, 24
```
---
### Text
#### text()
```
xy.text(); // paramless text drawing
xy.text("string", x, y); // use '\n' for multi-line text
```
#### textPaths()
Use coordinates of Hershey text for manipulating type!
```
xy.textPaths("string", x, y); // return 2D Array of PVector coords
```
#### textFont()
```
println(xy.fonts); // print list of avilable Hershey fonts
xy.textFont("fontname"); // set active Hershey font
```
#### textSize()
```
xy.textSize(); // get current textSize
xy.textSize(newSize); // set new textSize
```
#### textLeading()
```
xy.textLeading(); // get current textLeading
xy.textLeading(newSize); // set new textLeading
```
#### textAlign()
```
xy.textAlign(hAlign); // Horz: LEFT (default) / CENTER / RIGHT
xy.textAlign(hAlign, vAlign); // Vert options: TOP / CENTER / BOTTOM
```
#### textWidth()
```
xy.textWidth(int); // from 32 characters, get width of char
xy.textWidth("string"); // get width of text for positioning
```
---
### Modulation
#### freq()
Frequency of oscillators
```
// get
xy.freq(); // get PVector (.x, .y, .z) of freqs
xy.freq().x; // get frequency of x oscillator
// set
xy.freq(freqXY); // default is 50.0
xy.freq(freqX, freqY); // set x, y frequencies
xy.freq(freqX, freqY, freqZ); // set x, y, z frequencies
xy.freq(PVector freqXYZ); // set as PVector
xy.resetWaves(); // occasionally needed if they slip out of phase
```
#### amp()
Amplitude of oscillators
```
// get
xy.amp(); // get PVector (.x, .y, .z) of amps
xy.amp().x; // get amplitude of x oscillator
// set
xy.amp(ampXY); // default is 1.0
xy.amp(ampX, ampY); // set x, y to specific amplitudes
xy.amp(ampX, ampY, ampZ); // set x, y, z to specific amplitudes
xy.amp(PVector ampXYZ); // set as PVector
```
#### pan()
Optionally swap the hard pan of XY rather than physical cables
```
xy.pan(leftPan, rightPan); // default is -1.0, 1.0
```
---
### Vectrex
```
xy.vectrex(0); // 0 for portrait, -90/90 for landscape orientation
xy.vectrex(vw, vh, vamp, vrot); // custom width, height, amp, rotation
xy.vectrexRatio(); // get current ratio
xy.vectrexRatio(newRatio); // set new ratio, default is .82
```
---
### Laser
```
xy.laser("dac_Red", "dac_GreenBlue"); // custom 2ch pairs for R, GB
// be cautious of laser galvos, can help smooth graphics
xy.laserLPF(); // get value of laser's LowPassFilter
xy.laserLPF(newLPF); // set mew value of LowPassFilter (0.1 – 20000.0)
// avoid dangerous hotspot, only draw laser if shape is big enough
xy.spotKiller(); // get current min size of drawing for laser
xy.spotKiller(newVal); // set min drawing size to prevent laser hotspot
xy.stroke(r, g, b); // set RGB laser stroke color
xy.stroke(PVector rgb); // set as PVector
xy.strokeFreq(); // get laser RGB channel frequencies
xy.strokeFreq(freqRGB); // set laser RGB freq as group
xy.strokeFreq(freqR, freqG, freqB); // set laser R, G, B separately
xy.strokeFreq(PVector freqRGB); // set as PVector
// some lasers ignore values below __ when setting colors,
// use this to set lowest point when color mixing
xy.strokeMin(); // get curret min RGB values for laser stroke
xy.strokeMin(minR, minG, minB); // set new min values (0.0 - 255.0)
xy.strokeMin(PVector minPV); // set new min as PVector
xy.strokeWB(wbR, wbG, wbB); // set values needed for white light
xy.strokeWB(PVector wbRGB); // set values as PVector
xy.strokeDash(); // get current dash setting
xy.strokeDash(sdRGB); // set laser dash count for RGB strokes
xy.strokeDash(sdR, sdG, sdB); // set dashes per R, G, B
xy.strokeDash(PVector sdRGB); // set as PVector
```
---
### Rendering
```
xy.drawAll(); // all views below
xy.drawPath(); // shapes being drawn
xy.drawPoints(); // points along paths of drawing
xy.drawWaveform(); // drawing as oscillator's waveform
xy.drawWave(); // waveform over time at frequency
xy.drawXY(); // simulated xy-mode oscilloscope
xy.debugView(); // check if debugView active
xy.debugView(boolean); // compare drawXY() to drawWaveform()
```
### Vars
Lastly, many variables within XYscope are public for your vector hacking needs.
```
shapes; // XYShapeList, processed by buildWaves()
minim, minimZ; // instances of Minim
recorder; // instance for audio recording
outXY, outZ; // AudioOutput (used to patch for additive-synth)
sumXY, sumZ; // Summer for patching filters
waveX, waveY, waveZ; // Oscil for each XYZ oscillators
tableX, tableY, tableZ; // XYWavetable, applied to oscillator
shapeX, shapeY, shapeZ; // float[] used for wavetables
fonts; // list of Hershey fonts
minimR, minimBG; // instances of Minim
waveR, waveG, waveB; // Oscil for each RGB oscillators
tableR, tableG, tableB; // XYWavetable, applied to oscillator
shapeR, shapeG, shapeB; // float[] used for wavetables
```
## Extras
### Contributing
Found a bug, missing feature, and/or created a project with XYscope? Let me know!
Create an [issue on GitHub](https://github.com/ffd8/xyscope/issues).
### License
This project is licensed under the LGPL License - see [LICENSE.md](https://github.com/ffd8/xyscope/blob/master/license.txt) for details.
### Shoutouts
* [Just Van Rossum](http://dailydrawbot.tumblr.com), the enlightening conversation on my X-Y attempts.
* [Stefanie Bräuer](https://stefaniebraeuer.ch/), feeding the obsession with crucial theory + context.
* [Hansi Raber](https://asdfg.me), java meta insights + finding external WaveTable bug!
* [Processing Library Template](https://github.com/processing/processing-library-template)
================================================
FILE: changelog.txt
================================================
+ new
* changed
- removed
////////////////////////////////////////////////////////////
XYScope 3.0.0 (REV 5) - 21.02.2023
+ NEWER & IMPROVEDER buildWaves() technique (added -3, to those who like previous)
+ Added Hershey Fonts (single line) w/ many functions (textFont, textSize, textAlign, textPaths, textWidth, textLeading, multi-line text, ...)
+ Added circle() + square() to match p5/Processing
+ Added steps() for multiplier of segments between points
+ resetWaves() alias of waveReset(), to keep style of clearWaves() and buildWaves()
+ XYZ WaveTables are public to grab values for other usage
+ pan(left, right) to swap pans of channels incase cables physically swapped
+ box(), sphere(), ellipsoid(), torus() 3D primitives added
+ lissajous(), to draw such forms
+ primitives can be called without params for quick test, ie xy.circle()
+ audio recorder, to save visuals as .wav!
+ lots of new demos, sharing tricks/tips from past years playing with it
+ newly designed references as tutorial website
* ellipse() + rect() now work with 3 params like Processing
* ellipse()/circle() fixed connecting point
* point() fixed
* more functions accept float for random/sin play
* limitPath() improved to only draw necessary vector points
* endShape() now has CLOSE
* drawXY(), drawPath(), drawAudio(), accept r,g,b values for custom coloring
* ellipseDetail() abs() for negative numbers
////////////////////////////////////////////////////////////
XYScope 2.2.0 (REV 4) - 20.12.2018
+ NEW & IMPROVED buildWaves() technique (added -2, to those who like previous)
+ Fixed Minim WaveTable bug that caused crash since REV 2 (thanks Hansi Raber!)
+ limitPath() only draw if shape within border from edges
+ Laser: RGB Laser compatibility (using 2x stereo audio pairs for RGB control)
+ Laser: stroke() to control RGB color
+ Laser: strokeFreq() to control RGB frequencies
+ Laser: strokeDash() to add dashes to RGB waves
+ Laser: spotKiller() to only draw if image bigger than spotKiller() size (default 20)
+ Laser: laserLPF() default low-pass-filter is 10k hz, use laserLPF() to customize
+ Examples: added xtra_obj + xtra_video + xtra_laser
* minor vertex() code changes
* minor changes to examples
////////////////////////////////////////////////////////////
XYScope 2.1.0 (REV 3) - 25.07.2018
+ Vectrex compatibility (custom aspect ratio and +/- 90° rotation)
+ Vectrex example
* BuildWaves + drawXY to work with Vectrex mode
////////////////////////////////////////////////////////////
XYScope 2.0.0 (REV 2) - 08.05.2018
Added/dropped/refactored enough features to need 2.0
+ Brand new drawing to waveform technique (smoother)! Prefer old way? use buildWaves(-1)
If points matches buffer (1024), previously technique is used to maintain speed.
+ debugView(), for seeing drawWaveform() to drawXY() relationship (thanks Hansi3D!)
+ waveSize() function for dynamically changing wavetable size
+ XYscope instance for custom sample rates (41000, 48000, 96000, 192000, etc)
+ waveReset() now public incase time-step of oscillators slip when changing freq()
* Technique for adding z-axis,
* Refactored audio out, so minim filters (lowpass) can be used, see xtra_filters example
* Minor bugs in drawWaveform() rendering
* Drawings collect as a shapesList vs arrayList, clever suggestion by Hansi3D
* Stopped performing waveReset() on freq change, which preventing nice beam walk-around
- XYscope instance with z-axis, now has dedicated function
- XYscope instance with int for mixerID, can change too often, select mixer by name
- addPoint(), just use point()
- wavePoints(set), new structure doesn't allow, use custom buildWaves()
- sortPoints(), was a rough test, do within sketch instead
- freqX(), freqY(), freqZ(), ampX(), ampY(), ampZ()
now combined into freq(), amp() for 1 + optional 2, 3 values
////////////////////////////////////////////////////////////
XYScope 1.0.2 (REV 1) - 11.09.2017
+ audioMix as instance output, enabling additive-synthesis
////////////////////////////////////////////////////////////
XYScope 1.0.1 (REV 1) - 91.08.2017
+ xtra_syphon example, similar to webcam, load syphon textures
////////////////////////////////////////////////////////////
XYScope 1.0.0 (REV 1) - 21.06.2017
XYscope enters the world!
+ Everything
================================================
FILE: examples/1_getting_started/basic_drawing/basic_drawing.pde
================================================
/*
basic_drawing
Draw to the scope by throwing more and more lines, clearing on demand
cc teddavis.org 2017-23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
xy = new XYscope(this); // define XYscope instance
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
xy.buildWaves(); // build audio from shapes
xy.drawAll(); // draw all analytics
}
void mouseDragged() {
// add point based on width/height
xy.line(mouseX, mouseY, pmouseX, pmouseY);
}
void keyPressed() {
if (keyCode == 8) { // DELETE
xy.clearWaves(); // clear waves similar to background
}
}
================================================
FILE: examples/1_getting_started/calibration/calibration.pde
================================================
/*
calibration
circle + square + lines to help center/adjust oscilloscpe display
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
xy = new XYscope(this); // define XYscope instance
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
xy.clearWaves(); // clear waves similar to background
pushMatrix();
translate(width/2, height/2);
pushMatrix();
rotate(radians(180));
xy.circle(0, 0, width);
popMatrix();
xy.rectMode(CENTER);
xy.rect(0, 0, width);
xy.line(-width/2, 0, width/2, 0);
xy.line(0, height/2, 0, -height/2);
popMatrix();
xy.buildWaves(); // build audio from shapes
xy.drawAll(); // draw all analytics
}
================================================
FILE: examples/1_getting_started/clock/clock.pde
================================================
/*
clock
cc teddavis.org 2018-23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
float sec = 0;
void setup() {
size(512, 512);
xy = new XYscope(this); // define XYscope instance
//xy.getMixerInfo(); // lists all audio devices
sec = map(second(), 0, 60, 0, 360);
}
void draw() {
background(0);
xy.freq(second());
//xy.freq(sec%360/6); // smooth ramp
xy.ellipseDetail(24);
// clear waves like refreshing background
xy.clearWaves();
// draw clock face
xy.ellipse(width/2, height/2, width, width);
pushMatrix();
translate(width/2, height/2);
for (int i=0; i < 12; i++) {
rotate(radians(360/12));
xy.line(0, height*.49, 0, height*.4);
}
popMatrix();
//second
float s = map(second(), 0, 60, 0, 360);
sec += .1;//24/millis()/1000;
pushMatrix();
translate(width/2, height/2);
rotate(radians(s)); // sec for smooth
xy.line(0, -height*.35, 0, 0);
popMatrix();
//minute
float m = map(minute(), 0, 60, 0, 360);
pushMatrix();
translate(width/2, height/2);
rotate(radians(m));
xy.line(0, -height*.25, 0, 0);
popMatrix();
//hour
float h = map(hour(), 0, 24, 0, 360);
pushMatrix();
translate(width/2, height/2);
rotate(radians(h));
xy.line(0, -height*.15, 0, 0);
popMatrix();
// build audio from shapes
xy.buildWaves();
// draw all analytics
xy.drawAll();
}
================================================
FILE: examples/1_getting_started/custom_soundcard/custom_soundcard.pde
================================================
/*
custom_soundcard
Most AC-Coupled DACs will wiggle towards the center.
For 'better' results, find a DC-coupled DAC.
http://www.expert-sleepers.co.uk/siwacompatibility.html
+ cheapo $20 solution:
https://www.delock.com/produkt/61645/merkmale.html
https://www.youtube.com/live/VjRTLviVBxo?feature=share&t=2491
cc teddavis.org 2017-23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
xy = new XYscope(this); // init XYscope with default sound out
xy.getMixerInfo(); // list available sound cards
//xy = new XYscope(this, 0); // select by port
//xy = new XYscope(this, "BlackHole 2ch"); // select by name
//xy = new XYscope(this, "BlackHole 2ch", 48000); // custom card + sampeRate
}
void draw() {
background(0);
xy.clearWaves(); // clear waves like refreshing background
xy.rectMode(CENTER);
xy.rect(mouseX, mouseY, width/4, width/4);
xy.buildWaves(); // build audio from shapes
xy.drawAll(); // draw all analytics
}
================================================
FILE: examples/1_getting_started/lissapong/lissapong.pde
================================================
/*
lissapong
Let the epic crt battle over lissajous begin!
mouseY, move user paddle
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
boolean autoPlay = true, gameover = true, initScore = false, demoMode = true;
PVector c, p;
float cx = 1, cy = 2, s = 30, f = 10.5, paddleW = 10, paddleH = 150;
int gameTimer = 0, score1 = 0, score2 = 0, winner = 0;
void setup() {
size(512, 512);
xy = new XYscope(this);
xy.rectMode(CENTER);
pongReset();
}
void draw() {
background(0);
xy.clearWaves();
// render scores
float s1 = 25;
float s2 = 25;
if (winner == -1) {
s1 += sin(frameCount*.5)*20;
} else if (winner == 1) {
s2 += sin(frameCount*.5)*20;
}
xy.textSize(s1);
xy.text(score1, 50, 50);
xy.textSize(s2);
xy.text(score2, width-50, 50);
// gameplay vs gameover
if (!gameover) {
pongUpdate();
xy.lissajous(c.x, c.y, s, cx, cy, frameCount, 60);
float ly = c.y + (noise(frameCount*.023)*height-c.y)*c.x/width;
xy.rect(paddleW/2, ly, paddleW, paddleH);
float ry = c.y + (noise(frameCount*.02)*height-c.y)*(1 - c.x/width);
if (!autoPlay) {
ry = p.y;
}
xy.rect(width-paddleW/2, ry, paddleW, paddleH);
if (frameCount%30==0 && autoPlay) {
demoMode = !demoMode;
}
if (demoMode && autoPlay) {
xy.textSize(15);
xy.textAlign(CENTER, CENTER);
xy.text("CLICK TO PLAY", width/2, 50);
}
} else {
pushMatrix();
xy.textSize(40 + sin(frameCount*.05)*20);
xy.textAlign(CENTER, CENTER);
translate(width/2, height/2);
rotate(radians(cos(frameCount*.01)*15));
xy.text("GAME OVER", 0, 0);
popMatrix();
}
xy.buildWaves();
xy.drawXY();
xy.drawWaveform();
}
void mousePressed() {
if (gameover) {
pongReset();
}
if (autoPlay) {
autoPlay = false;
pongReset();
}
}
void pongReset() {
gameover = false;
c = new PVector(width/2, height/2);
p = new PVector(0, c.y);
cx = 1;
cy = 2;
xy.freq(cx * cy * 10);
f = 10.5;
gameTimer = 0;
score1 = 0;
score2 = 0;
winner = 0;
paddleH = 150;
demoMode = true;
}
void pongUpdate() {
p.y = mouseY;
c.x += cx;
c.y += cy;
if (!autoPlay && (abs(c.y-p.y) > (paddleH/2 + s) && c.x >= (width-paddleW/2-s)) ) {
println(abs(c.y - p.y) + " / "+ (paddleH/2 + s));
gameover = true;
if (score1 >= score2) {
winner = -1;
} else {
winner = 1;
}
xy.freq(random(4, 20));
xy.resetWaves();
}
if ((c.x > (width-paddleW/2-s) || c.x < (s-paddleW))) {
changeX();
changeY();
xy.freq(cx*cy);
xy.resetWaves();
cx *= -1;
initScore = true;
if (paddleH > paddleW) {
paddleH--;
}
}
if (c.y > height-s/2 || c.y < s/2) {
cy *= -1;
}
if (cy == height-s/2) {
cy -= s/2;
} else if (cy == s/2) {
cy += s/2;
}
gameTimer++;
}
void changeX() {
float fx = ceil(random(1, 10));
if (c.x < s)
fx *=-1;
if (fx > 0) {
score2++;
} else {
score1++;
}
cx = fx;
}
void changeY() {
float fy = ceil(random(1, 10));
if (!autoPlay && c.x > width/2) {
fy = abs(c.y - p.y)/10;
}
if (c.y > height-s/2) {
fy *=-1;
}
cy = fy;
}
================================================
FILE: examples/1_getting_started/template/template.pde
================================================
/*
template
Recommended template for Processing when working with XYscope often.
Save into ~/Documents/Processing/templates/Java/ (as `sketch.pde`)
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup(){
size(512, 512); // window size, optionally add P3D
xy = new XYscope(this, ""); // define XYscope instance, "custom_dac" optional
xy.getMixerInfo(); // lists all audio devices
}
void draw(){
background(0);
xy.clearWaves(); // clear waves from previous drawing
// draw shapes here
xy.circle(width/2, height/2, width); // it all began with a circle....
xy.buildWaves(); // build shapes to audio waves
xy.drawWaveform();
xy.drawXY();
}
================================================
FILE: examples/2_shapes/a_walkthrough_primatives/a_walkthrough_primatives.pde
================================================
/*
a_walkthrough_primatives
demo-run of available shapes
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
int shapeSel = 0;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default sound out
xy = new XYscope(this);
}
void draw() {
background(0);
xy.limitPath(0); // limit drawing any points outside of view
xy.steps(100); // interpolated points between points
// clear waves like refreshing background
xy.clearWaves();
if (frameCount%240==0) {
shapeSel++;
}
pushMatrix();
translate(width/2, height/2);
// use most primative shapes with class instance infront
switch(shapeSel%10) {
case 0:
xy.freq(1);
xy.point(random(-width/2, width/2), random(-height/2, height/2));
break;
case 1:
xy.freq(12);
for (int i=0; i<4; i++) {
pushMatrix();
rotate(radians(frameCount*i*.2));
float lineLen = sin(frameCount*.01 + i*1)*width/2;
xy.line(0, -lineLen, 0, lineLen);
popMatrix();
}
break;
case 2:
float efreq = frameCount*.1%30;//sin(frameCount*.005)*30;
xy.freq(25);
for (int i=0; i < 3; i++) {
pushMatrix();
rotate(radians(i*120+frameCount*.1));
translate(width/4, 0);
xy.ellipseDetail(noise(i*2+frameCount*.01)*12);
xy.ellipse(0, 0, width/4);
popMatrix();
}
break;
case 3:
xy.freq(50);
xy.rectMode(CENTER);
pushMatrix();
rotateY(radians(frameCount));
xy.rect(0, 0, width/2, height/2);
rotateX(radians(frameCount));
xy.rect(0, 0, width/3, height/3);
popMatrix();
break;
case 4:
xy.freq(75);
//randomSeed(1);
pushMatrix();
rotateY(radians(frameCount/3));
xy.beginShape();
for (int i=0; i < 10; i++) {
float d = width/2;
xy.vertex(noise(i*5+frameCount*.001)*d*2 - d, noise(i*20+frameCount*.003)*d*2 - d, noise(i*10+frameCount*.002)*d*2 - d);
}
xy.endShape(CLOSE);
popMatrix();
break;
case 5:
xy.freq(50);
xy.lissajous(0, 0, height/2, 1, 2, frameCount, 180);
break;
case 6:
xy.freq(50);
pushMatrix();
rotateY(radians(frameCount));
rotateX(radians(frameCount/2));
float bsize = width/2;
xy.box(sin(frameCount*.01)*bsize, bsize, cos(frameCount*.01)*bsize);
popMatrix();
break;
case 7:
pushMatrix();
rotateY(radians(frameCount));
xy.sphere(width/2.5, floor(noise(frameCount*.01)*24), floor(noise(10+frameCount*.011)*24));
popMatrix();
break;
case 8:
pushMatrix();
rotateY(radians(frameCount));
xy.torus(width/4, width/6, floor(noise(frameCount*.01)*12), floor(noise(10+frameCount*.011)*24));
popMatrix();
break;
case 9:
xy.freq(8);
xy.textAlign(CENTER, CENTER);
xy.textSize(50 + sin(frameCount*.025)*25);
pushMatrix();
xy.text("XYscope", 0, sin(frameCount*.05)*height/3);
popMatrix();
break;
}
popMatrix();
// build audio from shapes
xy.buildWaves();
// draw analytics
xy.drawWaveform();
xy.drawXY();
}
void keyPressed() {
if (key == ' ') {
shapeSel++;
}
}
================================================
FILE: examples/2_shapes/additive_synth_shapes/additive_synth_shapes.pde
================================================
/*
additive-synth shapes
an amazing aspect of vector graphics,
is sending multiple shapes on the same audio = additive synth!
create wild forms, animation, effects, through various freq/amp play.
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy, xy2; // create 2x XYscope instances
void setup() {
size(512, 512); // declares size of output window
xy = new XYscope(this);
xy2 = new XYscope(this, xy.outXY); // patch 2nd instance to 1st output
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
xy.clearWaves();
xy.circle(width/2, height/2, width/2);
xy.buildWaves();
xy.drawPath(0, 255, 255); // custom stroke color
xy.drawXY();
// additive synth on 2nd instance of XYscope
xy2.clearWaves();
xy2.freq(mouseX); // without speakers, test really high freqs!
//xy2.amp(.2); // experiment with high freq, low amp modulation
//xy2.circle(width/2, height/2, mouseY);
xy2.circle(mouseX, mouseY, 50);
//xy2.line(width/2, height/2, mouseX, mouseY);
//xy2.lissajous(width/2, height/2, mouseY/2, 1, 2, frameCount, 180);
xy2.buildWaves();
xy2.drawPath(255, 255, 0); // custom stroke color
}
================================================
FILE: examples/2_shapes/lissajous/lissajous.pde
================================================
/*
shapes_lissajous
Sometimes you just want some lissajous curves!
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
background(0);
// initialize custom local minim
xy = new XYscope(this);
}
void draw() {
background(0);
xy.clearWaves(); // clear waves
int res = 180;
if(mousePressed){
res = mouseX/2;
println("resolution: " + res);
}
// xy.lissajous(xPos, yPos, radius, ratioA, ratioB, phase, resolution);
xy.lissajous(width*.25, height*.25, height/4.5, 1, 1, frameCount, res);
xy.lissajous(width*.75, height*.25, height/4.5, 1, 2, frameCount, res);
xy.lissajous(width*.25, height*.75, height/4.5, 1, 3, frameCount, res);
xy.lissajous(width*.75, height*.75, height/4.5, 1, 4, frameCount, res);
xy.buildWaves(); // build waves
xy.drawAll(); // draw analytics
}
================================================
FILE: examples/2_shapes/paramless_shapes/paramless_shapes.pde
================================================
/*
paramless shapes
incase you're quickly testing/sketching,
you can create primatives without values
cc teddavis.org 2023
*/
import xyscope.*;
XYscope xy;
import ddf.minim.*;
void setup() {
size(512, 512, P3D); // declares size of output window
xy = new XYscope(this);
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
if (frameCount%60==0) {
xy.freq(random(-100, 100));
xy.resetWaves(); // helps if slipping out of phase from freq changes
}
xy.clearWaves();
switch(floor(frameCount*.1)%10) {
case 0:
xy.line();
break;
case 1:
xy.rectMode(CENTER);
xy.rect();
break;
case 2:
xy.square();
break;
case 3:
xy.circle();
break;
case 4:
xy.ellipse();
break;
case 5:
xy.lissajous();
break;
case 6:
xy.textAlign(CENTER, CENTER);
xy.textSize(80);
xy.text();
break;
case 7:
pushMatrix();
translate(width/2, height/2);
xy.box();
popMatrix();
break;
case 8:
pushMatrix();
translate(width/2, height/2);
xy.sphere();
popMatrix();
break;
case 9:
pushMatrix();
translate(width/2, height/2);
xy.torus();
popMatrix();
break;
}
xy.buildWaves();
xy.drawXY();
}
================================================
FILE: examples/2_shapes/sphere/sphere.pde
================================================
/*
sphere
mouseX/Y, adjust detailX, detailY
SHIFT + mouseDragged, freq based on distance from initial click
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
int pmx = 0, pmy = 0;
void setup() {
size(512, 512, P3D); // declares size of output window
xy = new XYscope(this);
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
xy.clearWaves();
//xy.resetWaves();
if (keyPressed && keyCode == 16) { // SHIFT
float freq = dist(mouseX, mouseY, pmx, pmy);
xy.freq(freq);
}
// draw shapes here
pushMatrix();
translate(width/2, height/2);
rotateY(radians(frameCount/3));
rotateX(radians(frameCount/2));
xy.sphere(width*.4, mouseX/5, mouseY/5); // xy.sphere(size, xVert, yVert)
popMatrix();
xy.buildWaves();
xy.drawXY();
}
void mousePressed() {
pmx = mouseX;
pmy = mouseY;
}
================================================
FILE: examples/2_shapes/torus/torus.pde
================================================
/*
shape_torus
Based upon Ira Greenbergs Toroid example
https://processing.org/examples/toroid.html
- mouseX » adjust dx
- mouseY » adjust dy
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// initial detailX, detailY values
int dx = 12, dy = 12;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default sound out
xy = new XYscope(this);
}
void draw() {
background(0);
xy.clearWaves(); // clear waves
//center and spin toroid
pushMatrix();
translate(width/2, height/2, -100);
rotateX(radians(frameCount/2));
rotateY(radians(frameCount));
rotateZ(radians(frameCount/3));
if (mousePressed) {
dx = (int)map(mouseX, 0, width, 1, 50);
dy = (int)map(mouseY, 0, height, 1, 50);
}
xy.torus(height/3, height/6, dx, dy);
popMatrix();
xy.buildWaves(); // build audio from shapes
xy.drawAll(); // draw all analytics
}
================================================
FILE: examples/3_typography/hershey_fonts/hershey_fonts.pde
================================================
/*
text_hershey_fonts
draw single-line text with hershey fonts!
lots of functions to learn from below
big thanks for hershey font lib: https://github.com/ixd-hof/HersheyFont
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
String txt = "XYscope";
void setup() {
size(512, 512, P3D);
xy = new XYscope(this);
// list all available fonts
println("Available Hershey Fonts:\n" + join(xy.fonts, ", ")); // list available fonts
// set random font
//xy.textFont(xy.fonts[floor(random(xy.fonts.length))]);
}
void draw() {
background(0);
xy.clearWaves();
xy.steps(50); // set segment multiplier
// draw text
xy.textSize(50);
xy.textAlign(CENTER, CENTER);
xy.text(txt, width/2, height*.25);
// draw text per character
float xoff = -xy.textWidth(txt)/2.5;
for (int i=0; i<txt.length(); i++) {
push();
translate(width/2+xoff, height*.5);
rotateX(radians(i*15+frameCount));
xy.text(txt.charAt(i)+"", 0, 0);
pop();
xoff += xy.textWidth(txt.charAt(i));
}
// get and draw paths of text
PVector[][] textPaths = xy.textPaths(txt, width/2, floor(height*.75));
for (int i = 0; i < textPaths.length; i++) {
xy.beginShape();
for (int j = 0; j < textPaths[i].length; j++) {
float offset = 10;
xy.vertex(textPaths[i][j].x+sin(j*.2+frameCount*.05)*offset, textPaths[i][j].y);
}
xy.endShape();
}
xy.buildWaves();
xy.drawWaveform(); // wavetable
xy.drawXY(); // scope viewer
}
================================================
FILE: examples/3_typography/scopewriter/scopewriter.pde
================================================
/*
scopewriter
use your oscilloscope as a word processor
with additive synth (add-synth) drawing to animate + distort it
DEL, clear last char
SHIFT + DEL, clear whole text
CTRL, generate new freq of add-synth
mouseDragged, draw shape for add-synth (use + to center drawing)
doubleCLick, clear add-synth drawing
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy, xy2; // create XYscope instance
String txtString = "XYscope";
boolean shifted = false;
int doubleClicker = 0;
void setup() {
size(512, 512);
xy = new XYscope(this);
//xy.getMixerInfo(); // lists all audio devices
xy.textAlign(LEFT, TOP);
xy.textSize(30);
xy.freq(40);
// add-synth instance of XYscope
xy2 = new XYscope(this, xy.outXY);
xy2.freq(39.7);
xy2.line(width/2, height/2, width/2+50, height/2+50);
}
void draw() {
background(0);
xy.clearWaves();
// draw shapes here
xy.text(txtString, 10, 0);
xy.buildWaves(); // build main waves
xy2.buildWaves(); // build add-synth waves
xy.drawXY(); // draw main XY visuals
xy2.drawPath(); // draw add-synth path
// grid to help center add-synth drawing
noFill();
pushMatrix();
translate(width/2, height/2);
stroke(0, 255, 255);
line(0, -100, 0, 100);
line(-100, 0, 100, 0);
popMatrix();
}
void keyPressed() {
//println(keyCode);
// scopewriter logic
if (keyCode == 8) {
xy.clearWaves();
if (shifted) {
txtString = "";
} else {
if (txtString.length() > 0) {
txtString = txtString.substring(0, txtString.length()-1);
}
}
} else if (keyCode == 10) {
txtString += "\r";
} else if (keyCode != 27 && keyCode != 0 && keyCode != 65406 && keyCode != 9 && keyCode != 16 && keyCode != 20 && keyCode != 17 && keyCode != 18 && keyCode != 157 && keyCode != 37 && keyCode != 38 && keyCode != 39 && keyCode != 40) {
if (xy.textWidth(txtString + key) > width) {
String[] t = split(txtString, " ");
if (key == ' ') {
txtString += "\r";
return;
} else if (t.length == 1) {
txtString += "\r";
} else {
txtString = txtString.replaceAll(" (?=[^ ]*$)", "\n");
}
}
txtString += key+"";
}
// change freq of add-synth
if (keyCode == 17) {
xy2.freq(floor(random(25))*5+.5);
println(xy2.freq().x);
}
if (keyCode == 16) {
shifted = true;
}
}
void keyReleased() {
if (keyCode == 16) {
shifted = false;
}
}
void mouseDragged() {
// draw add-synth shape
xy2.line(mouseX, mouseY, pmouseX, pmouseY);
}
void mousePressed() {
// double-clicker
if (millis()- doubleClicker < 500) {
xy2.clearWaves();
}
doubleClicker = millis();
}
================================================
FILE: examples/4_inputs/fonts/fonts.pde
================================================
/*
fonts
Let's draw type on the scope!
ANYKEY - type out
DELETE - clear text
» Requires Geomerative library
cc teddavis.org 2017
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// geomerative is required to generate text points
import geomerative.*;
RShape grp;
RPoint[][] pointPaths;
// store our text to draw
String txtString = "XYscope";
String fontName = "FreeSans.ttf";
void setup() {
size(512, 512);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
// initialize Geomerative
RG.init(this);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
// render type with Geomerative
grp = RG.getText(txtString, fontName, width/2, CENTER);
grp.centerIn(g, 30);
RG.setPolygonizer(RG.UNIFORMSTEP);
RG.setPolygonizerStep(10);
pointPaths = grp.getPointsInPaths();
pushMatrix();
translate(width/2, height/2);
if (pointPaths != null) { // only draw if we have points
for (int i = 0; i < pointPaths.length; i++) {
xy.beginShape();
for (int j=0; j < pointPaths[i].length; j++) {
xy.vertex(pointPaths[i][j].x, pointPaths[i][j].y);
}
xy.endShape();
}
}
popMatrix();
// build audio from shapes
xy.buildWaves();
// draw Wave + XY analytics
xy.drawWave();
xy.drawXY();
}
void keyPressed() {
if (keyCode == 8) {
xy.clearWaves();
txtString = "";
} else if (keyCode != 16 && keyCode != 17 && keyCode != 18 && keyCode != 157 && keyCode != 37 && keyCode != 38 && keyCode != 39 && keyCode != 40) {
txtString += key+"";
}
}
================================================
FILE: examples/4_inputs/kinect/kinect.pde
================================================
/*
kinect
Turn the kinect depth image into a nice silhouette!
» Requires OpenCV for Processing + openkinect libraries
cc teddavis.org 2017
*/
/* PREFS */
int kinectVer = 1; // 1 = xbox 360 vs 2 = xbox one
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// libs required for point sorting (efficient drawing)
import java.util.Collections;
import java.util.Comparator;
// libs + settings for kinect
import org.openkinect.freenect.*;
import org.openkinect.processing.*;
Kinect kinect;
Kinect2 kinect2;
// Depth image
PImage depthImg;
// Which pixels do we care about?
int minDepth = 60;
int maxDepth = 960;
// What is the kinect's angle
float angle;
//opencv + settings
import gab.opencv.*;
import java.awt.*;
OpenCV opencv;
ArrayList<Contour> contours;
int thres = 30;
int cutoff = 100;
void setup() {
size(512, 512);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
// pick kinect version (1 works great)
if (kinectVer == 1) {
kinect = new Kinect(this);
kinect.initDepth();
angle = kinect.getTilt();
depthImg = new PImage(kinect.width, kinect.height);
} else if (kinectVer == 2) {
kinect2 = new Kinect2(this);
kinect2.initDepth();
kinect2.initDevice();
depthImg = new PImage(kinect2.depthWidth, kinect2.depthHeight);
}
// initialize OpenCV (used to convert webcam to single line)
opencv = new OpenCV(this, depthImg.width, depthImg.height);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
// kinect depth data
int[] rawDepth = {};
if (kinectVer == 1) {
rawDepth = kinect.getRawDepth();
} else if (kinectVer == 2) {
rawDepth = kinect2.getRawDepth();
}
// create b/w threshold image from depth data
for (int i=0; i < rawDepth.length; i++) {
if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
depthImg.pixels[i] = color(255);
} else {
depthImg.pixels[i] = color(0);
}
}
// draw the thresholded image
depthImg.updatePixels();
//image(depthImg, 0, 0);
// process threshold to single line
opencv.loadImage(depthImg);
opencv.dilate();
opencv.flip(OpenCV.HORIZONTAL);
contours = opencv.findContours(true, false);
// sort group of lines for effeciant drawing
Collections.sort(contours, new MyComparator());
// draw shapes on scope
for (Contour contour : contours) {
if (contours.size() > 0) {
contour.setPolygonApproximationFactor(1);
xy.beginShape();
for (PVector point : contour.getPolygonApproximation().getPoints()) {
xy.vertex(point.x, point.y);
}
xy.endShape();
}
}
// build audio from shapes
if(contours.size() > 0)
xy.buildWaves();
// draw Path + XY analytics
xy.drawXY();
xy.drawPath();
}
// used for sorting points
class MyComparator implements Comparator<Contour> {
@Override
public int compare(Contour o1, Contour o2) {
if (o1.numPoints() > o2.numPoints()) {
return -1;
} else if (o1.numPoints() < o2.numPoints()) {
return 1;
}
return 0;
}
}
================================================
FILE: examples/4_inputs/obj/obj.pde
================================================
/*
obj
Import and render 3D obj files!
cc teddavis.org 2018
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// obj file instance
PShape obj;
public void setup() {
size(512, 512, P3D);
// load 3D obj file
obj = loadShape("teapot.obj");
// initialize XYscope
xy = new XYscope(this);
}
public void draw() {
background(0);
// modulate freq to make beats out of shapes!?
if(mousePressed){
xy.freq(map(mouseX, 0, width, 0, 50));
}
// clear XYscope waves
xy.clearWaves();
pushMatrix();
translate(width/2, height/2);
scale(2);
rotateZ(PI);
rotateY(radians(frameCount));
// break 3D obj into its pieces
int children = obj.getChildCount();
// render vertices in XYscope
xy.beginShape();
for (int i = 0; i < children; i++) {
PShape child = obj.getChild(i);
int total = child.getVertexCount();
for (int j = 0; j < total; j++) {
PVector v = child.getVertex(j);
xy.vertex(v.x, v.y, v.z);
}
}
xy.endShape();
// generate waveform
xy.buildWaves();
popMatrix();
// draw waveform + xy simulation
xy.drawWaveform();
xy.drawXY();
}
================================================
FILE: examples/4_inputs/svg/svg.pde
================================================
/*
svg
import any existing vector graphic as an SVG!
» Requires Geomerative library
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// geomerative is required to generate svg points
import geomerative.*;
RShape svg;
RPoint[][] pointPaths;
void setup() {
size(512, 512, P3D);
// initialize XYscope [with default/custom sound out]
xy = new XYscope(this, "");
// initialize Geomerative
RG.init(this);
svg = RG.loadShape("oscilloscope.svg");
svg.centerIn(g, 30);
pointPaths = svg.getPointsInPaths();
}
void draw() {
background(0);
xy.clearWaves(); // clear waves like refreshing background
pushMatrix();
translate(width/2, height/2);
rotateY(radians(frameCount/2));
if (pointPaths != null) { // only draw if we have points
for (int i = 0; i < pointPaths.length; i++) {
pushMatrix();
translate(0, 0, sin(i*5 + frameCount*.02)*100);
xy.beginShape();
for (int j=0; j < pointPaths[i].length; j++) {
xy.vertex(pointPaths[i][j].x, pointPaths[i][j].y);
}
xy.endShape();
popMatrix();
}
}
popMatrix();
xy.buildWaves(); // build audio from shapes
// draw Wave + XY analytics
xy.drawWave();
xy.drawXY();
}
================================================
FILE: examples/4_inputs/syphon/syphon.pde
================================================
/*
syphon
Images from any syphon source on the scope!
mouseX - threshold
mouseY - threshold distance
» Requires OpenCV for Processing + Syphon libraries
cc teddavis.org + jankenpopp.com 2017
*/
//PREFS
int threshold = 138;
float thresholdDist = 43;
int cutoff = 91; // limit min size contour
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// syphon is required for passing imagery
import codeanticode.syphon.*;
SyphonClient client;
PImage imgs; // syphon client
PImage imgo; // syphon resize
PImage imgf; // syphon threshold
// libs required for point sorting (efficient drawing)
import java.util.Collections;
import java.util.Comparator;
//opencv
import gab.opencv.*;
import java.awt.*;
OpenCV opencv;
ArrayList<Contour> contours;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
// initialize syphon client
client = new SyphonClient(this);
// initialize OpenCV (used to convert syphon to single line)
opencv = new OpenCV(this, width, height);
}
void draw() {
background(0);
// only up date when sypon sends new image
if (client.newFrame()) {
imgs = client.getImage(imgs);
}
if (imgs != null) {
imgf = imgs.get();
if (imgf.width > imgf.height) {
imgf.resize(width, 0);
} else {
imgf.resize(0, height);
}
imgo = imgf.get();
// clear waves like refreshing background
xy.clearWaves();
// adjust threshold of image for selective lines
if (mousePressed) {
threshold = floor(map(mouseX, 0, width, 0, 255));
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
// replace variable defaults at top if you find better ones
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
}
// convert syphon to high contrast threshold
for (int i=0; i<imgf.width*imgf.height; i++) {
if (brightness(imgf.pixels[i]) > threshold && brightness(imgf.pixels[i]) < threshold+thresholdDist) {
imgf.pixels[i] = color(200); // White
} else {
imgf.pixels[i] = color(0); // Black
}
}
// process threshold to single line
opencv.loadImage(imgf);
opencv.dilate();
opencv.erode();
// display syphon original, threshold, opencv images – w/ keys 1, 2, 3
if (keyPressed) {
if (key == '1')
image(imgo, 0, 0);
if (key == '2')
image(imgf, 0, 0);
if (key == '3') {
PImage otemp = opencv.getSnapshot();
image(otemp, 0, 0);
}
}
contours = opencv.findContours(true, false);
// sort group of lines for effeciant drawing
Collections.sort(contours, new MyComparator());
// draw shapes on scope
for (Contour contour : contours) {
if (contours.size() > 0) {
contour.setPolygonApproximationFactor(1);
if (contour.numPoints() > cutoff) {
xy.beginShape();
for (PVector point : contour.getPolygonApproximation().getPoints()) {
xy.vertex(point.x, point.y);
}
xy.endShape();
}
}
}
// build audio from shapes
xy.buildWaves();
}
// draw XY analytics
xy.drawXY();
}
// used for sorting points
class MyComparator implements Comparator<Contour> {
@Override
public int compare(Contour o1, Contour o2) {
if (o1.numPoints() > o2.numPoints()) {
return -1;
} else if (o1.numPoints() < o2.numPoints()) {
return 1;
}
return 0;
}
}
================================================
FILE: examples/4_inputs/video/video.pde
================================================
/*
video
Import and render videos in XYscope
mouseX - threshold
mouseY - threshold distance
keys 1, 2, 3 - view original, threshold, opencv image
** some strange behavior with Processing 4+...
» Requires OpenCV for Processing + Video libraries
cc teddavis.org 2018
*/
//PREFS
String moviePath = "BigBuckBunny_320x180_trim.mp4";
int threshold = 108;
float thresholdDist = 80;
int cutoff = 91; // limit min size contour
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// video library and instance
import processing.video.*;
Movie movie;
// OpenCV imagesteps
PImage imgResize; // movie resize
PImage imgThres; // movie threshold
// libs required for point sorting (efficient drawing)
import java.util.Collections;
import java.util.Comparator;
//opencv
import gab.opencv.*;
import java.awt.*;
OpenCV opencv;
ArrayList<Contour> contours;
void setup() {
size(512, 512);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
// initialize video
movie = new Movie(this, moviePath);
movie.play();
movie.loop();
movie.volume(0);
// initialize OpenCV (used to convert syphon to single line)
opencv = new OpenCV(this, width, height);
}
void draw() {
background(0);
if (movie.available() == true) {
movie.read();
}
if (movie != null) {
// clear waves like refreshing background
xy.clearWaves();
// resize movie to fit canvas
imgResize = movie.get();
if (imgResize.width > imgResize.height) {
imgResize.resize(width, 0);
} else {
imgResize.resize(0, height);
}
imgThres = imgResize.get();
// adjust threshold of image for selective lines
if (mousePressed) {
threshold = floor(map(mouseX, 0, width, 0, 255));
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
// replace variable defaults at top if video needs specific ones
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
}
// convert video to high contrast threshold
for (int i=0; i<imgThres.width*imgThres.height; i++) {
if (brightness(imgThres.pixels[i]) > threshold && brightness(imgThres.pixels[i]) < threshold+thresholdDist) {
imgThres.pixels[i] = color(255); // White
} else {
imgThres.pixels[i] = color(0); // Black
}
}
// process threshold to single line
opencv.loadImage(imgThres);
opencv.dilate();
opencv.erode();
contours = opencv.findContours(true, false);
// display video original, threshold, opencv images – w/ keys 1, 2, 3
if (keyPressed) {
if (key == '1')
image(imgResize, 0, 0);
if (key == '2')
image(imgThres, 0, 0);
if (key == '3') {
PImage otemp = opencv.getSnapshot();
image(otemp, 0, 0);
}
}
// sort group of lines for effeciant drawing
Collections.sort(contours, new MyComparator());
// draw shapes on scope
for (Contour contour : contours) {
if (contours.size() > 0) {
contour.setPolygonApproximationFactor(1);
if (contour.numPoints() > cutoff) {
xy.beginShape();
for (PVector point : contour.getPolygonApproximation().getPoints()) {
xy.vertex(point.x, point.y);
}
xy.endShape();
}
}
}
// build audio from shapes
xy.buildWaves();
}
// draw XY analytics
xy.drawXY();
}
// used for sorting points
class MyComparator implements Comparator<Contour> {
@Override
public int compare(Contour o1, Contour o2) {
if (o1.numPoints() > o2.numPoints()) {
return -1;
} else if (o1.numPoints() < o2.numPoints()) {
return 1;
}
return 0;
}
}
================================================
FILE: examples/4_inputs/webcam/webcam.pde
================================================
/*
webcam
You via your webcam on the scope!
mouseX - threshold
mouseY - threshold distance
» Requires OpenCV for Processing + Video libraries
cc teddavis.org 2017 – 2023
*/
//PREFS
int threshold = 65;
float thresholdDist = 115;
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// video is required for webcam
import processing.video.*;
Capture video;
// libs required for point sorting (efficient drawing)
import java.util.Collections;
import java.util.Comparator;
//opencv
import gab.opencv.*;
import java.awt.*;
OpenCV opencv;
ArrayList<Contour> contours;
int cutoff = 91;
PImage p;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
// initialize video capture
video = new Capture(this, 640, 480);
video.start();
p = new PImage(video.width, video.height);
// initialize OpenCV (used to convert webcam to single line)
opencv = new OpenCV(this, p.width, p.height);
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
// clear waves like refreshing background
xy.clearWaves();
// adjust threshold of image for selective lines
if (mousePressed) {
threshold = floor(map(mouseX, 0, width, 0, 255));
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
// replace variable defaults at top if you find better ones
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
}
// convert video to high contrast threshold
video.loadPixels();
if (video.pixels.length == 0) {
return;
}
for (int i=0; i<p.width*p.height; i++) {
if (brightness(video.pixels[i]) > threshold && brightness(video.pixels[i]) < threshold+thresholdDist) {
p.pixels[i] = color(0); // White
} else {
p.pixels[i] = color(255); // Black
}
p.updatePixels();
}
// process threshold to single line
opencv.loadImage(p);
opencv.flip(OpenCV.HORIZONTAL);
opencv.dilate();
contours = opencv.findContours(true, false);
// display video original, threshold, opencv images – w/ keys 1, 2, 3
if (keyPressed) {
pushMatrix();
if (key == '1') {
scale(-1, 1);
image(video, -video.width, 0);
}
if (key == '2') {
scale(-1, 1);
image(p, -p.width, 0);
}
if (key == '3') {
PImage otemp = opencv.getSnapshot();
image(otemp, 0, 0);
}
popMatrix();
}
// sort group of lines for effeciant drawing
Collections.sort(contours, new MyComparator());
// draw shapes on scope
for (Contour contour : contours) {
if (contours.size() > 0) {
contour.setPolygonApproximationFactor(1);
if (contour.numPoints() > cutoff) {
xy.beginShape();
for (PVector point : contour.getPolygonApproximation().getPoints()) {
xy.vertex(point.x, point.y);
}
xy.endShape();
}
}
}
// build audio from shapes
xy.buildWaves();
// draw XY analytics
xy.drawXY();
}
// used for sorting points
class MyComparator implements Comparator<Contour> {
@Override
public int compare(Contour o1, Contour o2) {
if (o1.numPoints() > o2.numPoints()) {
return -1;
} else if (o1.numPoints() < o2.numPoints()) {
return 1;
}
return 0;
}
}
================================================
FILE: examples/4_inputs/webcam_processing4/webcam_processing4.pde
================================================
/*
webcam processing4
You via your webcam on the scope!
mouseX - threshold
mouseY - threshold distance
* Updated version solving hiccups with Processing4 + Apple Silicon
» Requires 'OpenCV for Processing' + 'Video Library for Processing 4' libraries
cc teddavis.org 2017 – 23
*/
//PREFS
int threshold = 65;
float thresholdDist = 115;
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// video is required for webcam
import processing.video.*;
Capture video;
// libs required for point sorting (efficient drawing)
import java.util.Collections;
import java.util.Comparator;
//opencv
import gab.opencv.*;
import java.awt.*;
OpenCV opencv;
ArrayList<Contour> contours;
int cutoff = 91;
PImage p;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "");
xy.limitPath(2); // remove box around whole thing
// initialize video capture
video = new Capture(this, 640, 480);
video.start();
image(video, 0, 0);
p = new PImage(video.width, video.height);
// initialize OpenCV (used to convert webcam to single line)
opencv = new OpenCV(this, p.width, p.height);
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
// clear waves like refreshing background
xy.clearWaves();
// adjust threshold of image for selective lines
if (mousePressed) {
threshold = floor(map(mouseX, 0, width, 0, 255));
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
// replace variable defaults at top if you find better ones
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
}
// convert video to high contrast threshold
video.loadPixels();
if (video.pixels.length == 0) {
return;
}
for (int i=0; i<p.width*p.height; i++) {
if (brightness(video.pixels[i]) > threshold && brightness(video.pixels[i]) < threshold+thresholdDist) {
p.pixels[i] = color(0); // White
} else {
p.pixels[i] = color(255); // Black
}
}
p.updatePixels();
// process threshold to single line
opencv.loadImage(p);
opencv.flip(OpenCV.HORIZONTAL);
opencv.dilate();
contours = opencv.findContours(true, false);
// display video original, threshold, opencv images – w/ keys 1, 2, 3
if (keyPressed) {
pushMatrix();
if (key == '1') {
scale(-1, 1);
image(video, -video.width, 0);
}
if (key == '2') {
scale(-1, 1);
image(p, -p.width, 0);
}
if (key == '3') {
PImage otemp = opencv.getSnapshot();
image(otemp, 0, 0);
}
popMatrix();
}
// sort group of lines for effeciant drawing
Collections.sort(contours, new MyComparator());
// draw shapes on scope
for (Contour contour : contours) {
if (contours.size() > 0) {
contour.setPolygonApproximationFactor(1);
if (contour.numPoints() > cutoff) {
xy.beginShape();
for (PVector point : contour.getPolygonApproximation().getPoints()) {
xy.vertex(point.x, point.y);
}
xy.endShape();
}
}
}
// build audio from shapes
xy.buildWaves();
// draw XY analytics
xy.drawXY();
}
// used for sorting points
class MyComparator implements Comparator<Contour> {
@Override
public int compare(Contour o1, Contour o2) {
if (o1.numPoints() > o2.numPoints()) {
return -1;
} else if (o1.numPoints() < o2.numPoints()) {
return 1;
}
return 0;
}
}
================================================
FILE: examples/5_displays/laser/laser.pde
================================================
/*
laser
Guide to driving RGB laser with XYscope.
cc teddavis.org 2018 – 23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(640, 480, P3D);
background(0);
// initialize XYscope with default/custom sound out
xy = new XYscope(this, "MOTU 1-2");
// only stereo pairs allowed in processing, so it's broken to R, GB
// incase 2nd channel of R pair is useful for blanking/etc.
xy.laser("MOTU 3-4", "MOTU 5-6"); //xy.laser(mixerR, mixerGB);
// RGB waveforms have own freq, so we can them out of sync
xy.strokeFreq(50.05, 50.1, 50.2);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
xy.limitPath(0); // avoid drawing any forms beyond view
xy.strokeDash(8); // optional dashes in the RGB stroke
if (mousePressed) {
// set low-pass filter of laser
float newLPF = map(mouseX, 0, width, 1, 10000);
xy.laserLPF(newLPF);
// limit number of points it can draw with
xy.limitPoints(floor(map(mouseY, 0, height, 0, 100)));
}
pushMatrix();
translate(width/2, height/2);
rotateY(radians(frameCount*.2));
float s = height*.25;
xy.stroke(0, 255, 255); // set RGB stroke before shapes (0-255)
xy.ellipse(-s, 0, s, s);
// rotating for infinity movement
rotateY(radians(frameCount*.2));
xy.stroke(255, 0, 255);
rotate(radians(180)); // match ellipse startings points
rotateX(radians(180)); // match ellipse startings points
xy.ellipse(-s, 0, s, s);
popMatrix();
// build audio from shapes
xy.buildWaves();
// draw RGB Waveforms + XY simulation
xy.drawRGB();
//xy.drawWaveform();
xy.drawXY();
}
================================================
FILE: examples/5_displays/vectrex/vectrex.pde
================================================
/*
vectrex
Basics settings for using a modded Vectrex monitor.
cc teddavis.org 2018
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
// initialize XYscope with default sound out
xy = new XYscope(this, "");
// set XYscope into Vectrex aspect-ratio mode
xy.vectrex(90); // 90 for landscape, 0 for portrait
/*
If the SPOT-KILLER MOD was applied (z/brightness is always on),
this auto sets the brightness (from way turned down) when the sketch runs.
*/
//xy.z("MOTU 3-4"); // use custom 3rd channel audio device
//xy.zRange(.5, 0);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
// set detail of vertex ellipse
xy.ellipseDetail(30);
// draw two primative shapes, testing boundry of screen
xy.rect(0, 0, width, height);
float s = map(mouseX, 0, width, -height/2, height/2);
xy.ellipse(width/2, height/2, s, s);
// build audio from shapes
xy.buildWaves();
// draw all analytics
xy.drawAll();
}
================================================
FILE: examples/6_outputs/audio_recorder/audio_recorder.pde
================================================
/*
audio recorder
Export your XYscope as .wav audio files!
just use: xy.recorderBegin(filename) + xy.recorderEnd()
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512, P3D); // declares size of output window
xy = new XYscope(this, 48000); // use desired sampleRate
//xy.getMixerInfo(); // lists all audio devices
}
void draw() {
background(0);
xy.clearWaves();
push();
translate(width/2, height/2);
rotateY(radians(frameCount/2));
rotateZ(radians(frameCount/2));
xy.box(height/2);
float off = width/5;
translate(random(-off, off), random(-off, off), random(-off, off));
xy.sphere(random(50));
pop();
xy.buildWaves();
xy.drawAll();
}
void keyPressed() {
if (key == 'r') {
if (xy.recorder != null && xy.recorder.isRecording()) {
xy.recorderEnd();
} else {
xy.recorderBegin("box-spheres"); // leave blank for "XYscope"
}
}
}
================================================
FILE: examples/6_outputs/osc_wavetables/osc_wavetables.pde
================================================
/*
osc wavetables
transport your XYscope custom wavetables via OSC to other tools
to visual forms drawn, add effects, pass into custom oscillators.
format: [x1, y1, z1], [x2, y2, z2], ...];
+ import /data/P5L_xyscope-osc_wavetables.json to offline P5LIVE for demo
* not working for your tool of choice? join discussion:
https://github.com/ffd8/xyscope/issues/5
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
import java.util.Arrays; // needed for 2D Array to string
// OSC code
import oscP5.*;
import netP5.*;
OscP5 oscP5;
NetAddress myRemoteLocation;
float fc = 0;
void setup() {
size(512, 512, P3D); // declares size of output window
xy = new XYscope(this); // define XYscope instance
//xy.getMixerInfo(); // lists all audio devices
/* start oscP5, sending outgoing messages */
oscP5 = new OscP5(this, 12001); // receiving port
myRemoteLocation = new NetAddress("127.0.0.1", 12000); // sending port
}
void draw() {
background(0);
xy.clearWaves();
xy.limitPath(0);
xy.steps(20);
pushMatrix();
translate(width/2, height/2);
rotateX(radians(-frameCount));
rotateY(radians(-frameCount/2));
xy.textSize(72);
xy.textAlign(CENTER, CENTER);
xy.text("XYscope", 0, 0);
xy.textSize(32);
float tw = xy.textWidth("XYscope");
fc += mouseX;
for (int i=0; i<3; i++) {
pushMatrix();
rotateX(radians(-fc+i*50));
translate(map(i, 0, 3, -tw, tw), -height*.1, height*.1);
xy.text("OSC", 0, 0);
popMatrix();
}
popMatrix();
xy.buildWaves();
xy.drawAll();
sendWaves(); // send OSC message of waves [x1, y1, z1], [x2, y2, z2], ...];
}
void sendWaves() {
float[][] getWaves = new float[xy.tableX.size()][3];
for (int i=0; i < xy.tableX.size(); i++) {
getWaves[i][0] = xy.tableX.get(i);
getWaves[i][1] = xy.tableY.get(i);
}
//System.out.println(Arrays.deepToString(getWaves));
String xyWavetables = Arrays.deepToString(getWaves);
OscMessage myMessage = new OscMessage("/XYscope");
myMessage.add(xyWavetables); /* add an int to the osc message */
// /* send the message */
oscP5.send(myMessage, myRemoteLocation);
}
void keyPressed() {
// optionally only send on demand, disable within draw()
if (keyCode == 32) {
sendWaves();
}
}
================================================
FILE: examples/7_custom_waves/customWaves_drawingXYZ/customWaves_drawingXYZ.pde
================================================
/*
customWaves_drawing
Test out our sound cards by manually drawing the wave form.
Very useful for testing just the z-axis blanking parallel to another sketch
DELETE - resets waveforms
cc teddavis.org 2017
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// setup local waveforms
float[] x, y, z;
int dragDist = 14;
int dragRegion = 0;
void setup() {
size(400, 600, P3D);
background(0);
// initialize XYscope with custom outXY
// left blank so it runs, but fill in with your audio card
xy = new XYscope(this, "");
// custom z
xy.z("");
// initialize waves
resetWaves();
}
void draw() {
background(0);
// display text and color boxes
displayInfo();
// build each wave custom from our local waveform
xy.buildX(x);
xy.buildY(y);
xy.buildZ(z);
// draw waveform analytics
xy.drawWaveform();
}
void mousePressed() {
// only draw in region clicked on
if (mouseY > height*.125 && mouseY < height*.375) {
dragRegion = 1;
} else if (mouseY > height*.375 && mouseY < height*.625) {
dragRegion = 2;
} else if (mouseY > height*.625 && mouseY < height*.875) {
dragRegion = 3;
}
}
void mouseReleased() {
// release custom region
dragRegion = 0;
}
void mouseDragged() {
// modify waveform based on drawing
for (int i=0; i < x.length; i++) {
int mappedX = floor(map(mouseX, 0, width, 0, x.length));
if (abs(i-mappedX) < dragDist) {
if (mouseY > height*.125 && mouseY < height*.375 && dragRegion == 1) {
float mappedY = map(mouseY, height*.375, height*.125, 0, 1);
x[i] = mappedY;
} else if (mouseY > height*.375 && mouseY < height*.625 && dragRegion == 2) {
float mappedY = map(mouseY, height*.375, height*.625, 0, 1);
z[i] = mappedY;
} else if (mouseY > height*.625 && mouseY < height*.875 && dragRegion == 3) {
float mappedY = map(mouseY, height*.625, height*.875, 0, 1);
y[i] = mappedY;
}
}
}
}
void keyPressed() {
// reset waves on DELETE
if (keyCode == 8) { // DELETE
resetWaves();
}
}
void resetWaves() {
x = new float[xy.waveSize()];
y = new float[xy.waveSize()];
z = new float[xy.waveSize()];
for (int i=0; i < x.length; i++) {
x[i] = .5;
y[i] = .5;
z[i] = .5;
}
}
void displayInfo() {
noStroke();
fill(255, 0, 0, 50);
rect(0, height*.125, width, height*.25);
fill(0, 255, 0, 50);
rect(0, height*.375, width, height*.25);
fill(0, 0, 255, 50);
rect(0, height*.625, width, height*.25);
fill(255, 0, 0);
text("X - LEFT/HORIZONTAL", 5, height*.125, width, 100);
fill(0, 255, 0);
text("Z - BLANKING", 5, height*.375, width, 100);
fill(0, 0, 255);
text("Y - RIGHT/VERTICAL", 5, height*.625, width, 100);
}
================================================
FILE: examples/7_custom_waves/customWaves_noiseXY/customWaves_noiseXY.pde
================================================
/*
customWaves_buildXY
You don't have to use primitive forms,
you can also generate the waveforms by your own code and logic.
cc teddavis.org 2017-23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
float[] yWave, xWave;
void setup() {
size(512, 512);
background(0);
// initialize custom local minim
xy = new XYscope(this);
// function below to build waves
genNoiseWave();
}
void draw() {
background(0);
// draw analytics
xy.drawAll();
}
void keyPressed() {
// refresh noise with spacebar
if (keyCode == 32) {
genNoiseWave();
}
}
void genNoiseWave() {
// set new noiseSeed
noiseSeed(frameCount);
// get bufferSize() of output
println(xy.waveSize());
// initialize array for storing values
yWave = new float[xy.waveSize()];
xWave = new float[xy.waveSize()];
float nx = random(1);
float ny = random(1);
// add noise walker to waveform
for (int i=0; i<yWave.length; i++) {
xWave[i] = noise(nx)*1;
yWave[i] = noise(ny)*1;
nx+=.01;
ny+=.011;
}
// build each XY waveform with array of 0.0 – 1.0 values
xy.buildX(xWave);
xy.buildY(yWave);
}
================================================
FILE: examples/7_custom_waves/setWaveforms_noise/setWaveforms_noise.pde
================================================
/*
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512); // declares size of output window
xy = new XYscope(this);
xy.getMixerInfo(); // lists all audio devices
genWaveforms();
}
void draw() {
background(0);
// build using custom waveforms
genWaveforms();
xy.drawWaveform();
xy.drawXY();
}
void genWaveforms() {
float[] waveX = new float[xy.bufferSize()];
float[] waveY = new float[xy.bufferSize()];
for (int i=0; i<waveX.length; i++) {
waveX[i] = sin(i*TWO_PI/512);//map(i, 0, waveX.length, -1, 1);
waveY[i] = -.5 + noise(frameCount*.015+i*TWO_PI/512);
}
// set waveform with arrays of -1.0 to 1.0 values
xy.setWaveforms(waveX, waveY); // optionally set waveZ too
}
================================================
FILE: examples/8_music/MidiScope/MidiScope.pde
================================================
/*
MidiScope
use a MIDI file to set the freq of any XYscope graphics!
cc teddavis.org 2019-23
*/
String midiTrack = "teapot.MID"; // filename in /data folder
int midiTranspose = -3; // shift key of midi track
float midiBPM = 91;
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
import ddf.minim.ugens.*; // freq from pitch
// MIDI code at bottom
PShape obj;
void setup() {
size(512, 512, P3D);
xy = new XYscope(this);
setupMidi(midiTrack);
obj = loadShape("teapot.obj");
}
void draw() {
background(0);
// 3D teapot!
xy.clearWaves();
pushMatrix();
translate(width/2, height/2);
scale(2);
rotateZ(PI);
rotateY(radians(frameCount+ xy.freq().x));
// break 3D obj into its pieces
int children = obj.getChildCount();
// render vertices in XYscope
xy.beginShape();
for (int i = 0; i < children; i++) {
PShape child = obj.getChild(i);
int total = child.getVertexCount();
for (int j = 0; j < total; j++) {
PVector v = child.getVertex(j);
xy.vertex(v.x, v.y, v.z);
}
}
xy.endShape();
popMatrix();
xy.buildWaves();
xy.drawXY();
xy.drawWaveform();
}
void mouseDragged() {
xy.point(mouseX, mouseY);
}
void keyPressed() {
if (keyCode == 8) { // DELETE
xy.clearWaves();
}
}
// MIDI details
import javax.sound.midi.*;
Sequencer sequencer;
Sequence sequence;
class MidiReceiver implements Receiver {
void close() { }
void send( MidiMessage msg, long timeStamp ) {
if ( msg instanceof ShortMessage ) {
ShortMessage sm = (ShortMessage)msg;
if ( sm.getCommand() == ShortMessage.NOTE_ON ) {
int note = sm.getData1();
int vel = sm.getData2();
//xy.amp(map(vel, 0, 127, 0, 1));
xy.freq(Frequency.ofMidiNote(note + (midiTranspose * 12)).asHz());
xy.resetWaves();
}
}
}
}
void setupMidi(String midiFile) {
// load midi
try {
sequencer = MidiSystem.getSequencer( false );
sequencer.open();
sequence = MidiSystem.getSequence( createInput( midiFile ) );
sequencer.setSequence( sequence );
sequencer.setTempoInBPM( midiBPM );
sequencer.getTransmitter().setReceiver( new MidiReceiver() );
sequencer.setLoopCount( Sequencer.LOOP_CONTINUOUSLY );
sequencer.start();
} catch( MidiUnavailableException ex ) {
// no sequencer
println( "No default sequencer, sorry bud." );
} catch( InvalidMidiDataException ex ) {
// oops, the file was bad
println( "The midi file was hosed or not a midi file, sorry bud." );
} catch( IOException ex ) {
println( "Had a problem accessing the midi file, sorry bud." );
}
}
================================================
FILE: examples/8_music/audio_filters/audio_filters.pde
================================================
/*
xtra_filters
Use minim ugens audio filters.
Click and drag mouse to adjust moog filter
cc teddavis.org 2018-23
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// extra libs are required for filtering
import ddf.minim.ugens.*;
MoogFilter moog;
Flanger flange;
Delay myDelay;
ADSR adsr;
void setup() {
size(512, 512, P3D);
// initialize XYscope with default sound out
xy = new XYscope(this);
moog = new MoogFilter( 1200, 0.75 );
moog.setChannelCount(2);
myDelay = new Delay( 0.4, 0.5, false, false );
myDelay.setChannelCount(2);
flange = new Flanger( 0, // delay length in milliseconds ( clamped to [0,100] )
0.2f, // lfo rate in Hz ( clamped at low end to 0.001 )
1.0f, // delay depth in milliseconds ( minimum of 0 )
0.5f, // amount of feedback ( clamped to [0,1] )
0.0f, // amount of dry signal ( clamped to [0,1] )
0.5f // amount of wet signal ( clamped to [0,1] )
);
flange.setChannelCount(2);
//patch/unpatch moog
xy.sumXY.unpatch(xy.outXY);
xy.sumXY.patch(moog).patch(xy.outXY);
//patch/unpatch delay
//xy.sumXY.unpatch(xy.outXY);
//xy.sumXY.patch(myDelay).patch(xy.outXY);
//patch/unpatch flange
//xy.sumXY.unpatch(xy.outXY);
//xy.sumXY.patch(flange).patch(xy.outXY);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
// grid of squares
int grid = 4;
for (int i=0; i < grid; i++) {
for (int j=0; j < grid; j++) {
//xy.rect(i*width/grid, j*height/grid, width/grid, height/grid);
}
}
pushMatrix();
translate(width/2, height/2);
rotateY(radians(frameCount/2));
xy.box(width/2);
popMatrix();
// enable for delay demo
//xy.rect(mouseX, mouseY, 200, 200);
// adjust moog filter
if (mousePressed) {
float freq = constrain( map(mouseX, 0, width, 2, 12000), 2, 12000);
float rez = constrain( map(mouseY, height, 0, 0, 1), 0, 1);
println("freq: "+freq+" / rez: "+rez);
moog.frequency.setLastValue(freq);
moog.resonance.setLastValue(rez);
}
// build audio from shapes
xy.buildWaves();
// draw all analytics
xy.drawAll();
}
void keyPressed() {
if ( key == '1' ) moog.type = MoogFilter.Type.LP;
if ( key == '2' ) moog.type = MoogFilter.Type.HP;
if ( key == '3' ) moog.type = MoogFilter.Type.BP;
}
================================================
FILE: examples/8_music/freq_keyboard_notes/freq_keyboard_notes.pde
================================================
/*
freq_keyboard_notes
Use your keyboard (A, B, C, D, E, F, G + 1, 2, 3, 4, 5, 6, 7..)
to play musical pitches of your graphics!
cc teddavis.org 2023
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// ugens to convert pitch to freq
import ddf.minim.ugens.*;
String keyLetter = "A", keyOctave = "3";
void setup() {
size(512, 512);
// initialize XYscope with default sound out
xy = new XYscope(this);
}
void draw() {
background(0);
xy.clearWaves(); // clear waves
keyboardNotes(); // use keyboard to set note pitch (freq)
xy.ellipse(width/2, width/2, width/2, width/2);
xy.buildWaves(); // build audio from shapes
xy.drawAll(); // draw all analytics
}
void keyboardNotes() {
if (keyPressed) {
if (key == 'a' || key == 'b' || key == 'c' || key == 'd' || key == 'e' || key == 'f' || key == 'g') {
keyLetter = (key+"").toUpperCase();
}
if (key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6' || key == '7' || key == '8' || key == '9' || key == '0') {
keyOctave = key + "";
}
xy.freq(Frequency.ofPitch(keyLetter+keyOctave).asHz());
}
}
================================================
FILE: examples/9_misc/freq_amp_modulation/freq_amp_modulation.pde
================================================
/*
freq_amp_modulation
Basic modulation of amp + freq of waves
Wild effects can be had by changing in unique ways
cc teddavis.org 2017
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
void setup() {
size(512, 512);
// initialize XYscope with default sound out
xy = new XYscope(this);
}
void draw() {
background(0);
// clear waves like refreshing background
xy.clearWaves();
// modulate amp with mouseX left - right
xy.amp(norm(mouseY, height, 0));
// modulate just one value for fun scaling
// xy.ampX(norm(mouseX, 0, width));
// xy.ampY(norm(mouseX, 0, width));
// modulate freq with mouseY up - down
xy.freq(map(mouseX, 0, width, 0, 440));
// draw house
drawHouse();
// build audio from shapes
xy.buildWaves();
// draw all analytics
xy.drawAll();
}
void drawHouse() {
pushMatrix();
translate(width*.5, height*.75);
float scl = 2;
xy.beginShape();
xy.vertex(-width*.1*scl, 0);
xy.vertex(width*.1*scl, 0);
xy.vertex(width*.1*scl, -height*.2*scl);
xy.vertex(0, -height*.3*scl);
xy.vertex(-width*.1*scl, -height*.2*scl);
xy.vertex(-width*.1*scl, 0);
xy.vertex(-width*.05*scl, 0);
xy.vertex(-width*.05*scl, -height*.1*scl);
xy.vertex(-width*.0*scl, -height*.1*scl);
xy.vertex(-width*.0*scl, 0);
xy.endShape();
popMatrix();
}
================================================
FILE: examples/9_misc/multiscopes_class/multiscopes_class.pde
================================================
/*
multiscopes_class
Control as many oscilloscopes as you have audio card outputs.
Create Aggregate devices in Utilities » Audio/Midi
for pairs of stereo devices from multi-channel DAC
cc teddavis.org 2017
*/
import ddf.minim.*; // minim req to gen audio
import xyscope.*; // import XYscope
XYscope xy; // create XYscope instance
// how many scopes, audio channels to drive?
int scopeCount = 4;
// replace with your own aggregate device names
//String[] mixerName = {"MK3_12", "MK3_34", "MK3_56", "MK3_78"};
String[] mixerName = {"", "", "", ""};
// custom class below
ScopeDraw[] sd = new ScopeDraw[scopeCount];
void setup() {
size(512, 512);
background(0);
// initiate class instances (
// XYscope is within class
for (int i=0; i<sd.length; i++) {
sd[i] = new ScopeDraw(this, mixerName[i]);
}
}
void draw() {
background(0);
// run each class in draw
for (int i=0; i<sd.length; i++) {
sd[i].display();
}
}
void keyPressed() {
// pass keyPressed into class
for (int i=0; i<sd.length; i++) {
sd[i].checkKey(keyCode);
}
}
class ScopeDraw {
// create instance of XYscope
XYscope xy;
float x, y, s, v;
// tell class it's parent, needed for XYscope + mixer
ScopeDraw(PApplet theParent, String scopeID) {
// initialize XYscope with custom sound out
xy = new XYscope(theParent, scopeID);
v = random(1, 10);
s = floor(random(10, 100));
x = -s;
y = height/2-s/2;
}
void display() {
// clear waves like refreshing background
xy.clearWaves();
x += v;
if (x > width) {
x = -s;
v = random(1, 10);
}
xy.rect(x, y, s, s);
// build audio from shapes
xy.buildWaves();
// draw just two analytics
xy.drawWave();
xy.drawXY();
}
// process keyPressed
void checkKey(int keyC) {
if (keyC == 38) { // UP
xy.freq(xy.freq().x+.5);
} else if (keyC == 40) { // DOWN
xy.freq(xy.freq().x-.5);
}
}
}
================================================
FILE: license.txt
================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
================================================
FILE: resources/README.md
================================================
## How to install ##library.name##
### Install with the Contribution Manager
Add contributed Libraries by selecting the menu item _Sketch_ → _Import Library..._ → _Add Library..._ This will open the Contribution Manager, where you can browse for ##library.name##, or any other Library you want to install.
Not all available Libraries have been converted to show up in this menu. If a Library isn't there, it will need to be installed manually by following the instructions below.
### Manual Install
Contributed Libraries may be downloaded separately and manually placed within the `libraries` folder of your Processing sketchbook. To find (and change) the Processing sketchbook location on your computer, open the Preferences window from the Processing application (PDE) and look for the "Sketchbook location" item at the top.
By default the following locations are used for your sketchbook folder:
* For Mac users, the sketchbook folder is located inside `~/Documents/Processing`
* For Windows users, the sketchbook folder is located inside `My Documents/Processing`
Download ##library.name## from ##library.url##
Unzip and copy the contributed Library's folder into the `libraries` folder in the Processing sketchbook. You will need to create this `libraries` folder if it does not exist.
The folder structure for Library ##library.name## should be as follows:
```
Processing
libraries
##library.name##
examples
library
##library.name##.jar
reference
src
```
Some folders like `examples` or `src` might be missing. After Library ##library.name## has been successfully installed, restart the Processing application.
### Troubleshooting
If you're having trouble, have a look at the [Processing Wiki](https://github.com/processing/processing/wiki/How-to-Install-a-Contributed-Library) for more information, or contact the author [##author.name##](##author.url##).
================================================
FILE: resources/build.properties
================================================
# Create a Library for the Processing open source programming language and
# environment (http://processing.org/)
#
# Customize the build properties to make the ant-build-process work for your
# environment. How? Please read the comments below.
#
# The default properties are set for OS X. Please refer to comments for Windows
# settings.
# Where is your Processing sketchbook located?
# If you are not sure, check the sketchbook location in your Processing
# application preferences.
# ${user.home} points the compiler to your home directory.
# For windows the default path to your sketchbook would be
# ${user.home}/My Documents/Processing (make adjustments below)
#sketchbook.location=${user.home}/My Documents/Processing
sketchbook.location=${user.home}/Documents/Processing
# Where are the jar files located that are required for compiling your Library
# such as e.g. core.jar?
# By default the local classpath location points to folder libs inside Eclipse's
# workspace (by default found in your home directory).
# For Windows, the default path would be
# ${user.home}/Documents/workspace/libs (make adjustments below)
# For OS X,the following path will direct you into Processing's application
# package, in case you put Processing inside your Applications folder.
classpath.local.location=lib
#classpath.local.location=/Applications/Processing_3_3_2.app/Contents/Java/core/library
#${user.home}/Documents/workspace/
# Add all jar files that are required for compiling your project to the local
# and project classpath. Use a comma as delimiter. These jar files must be
# inside your classpath.local.location folder.
classpath.local.include=core.jar
# Add Processing's libraries folder to the classpath.
# If you don't need to include the libraries folder to your classpath, comment
# out the following line.
#classpath.libraries.location=${sketchbook.location}/libraries
classpath.libraries.location=
# Set the java version that should be used to compile your Library.
java.target.version=17
# Set the description of the Ant build.xml file.
ant.description=Processing Library Ant build file.
# Give your Library a name. The name must not contain spaces or special
# characters.
project.name=XYscope
# The name as the user will see it. This can contain spaces and special
# characters.
project.prettyName=XYscope
# Use 'normal' or 'fast' as value for project.compile.
# 'fast' will only compile the project into your sketchbook.
# 'normal' will compile the distribution including the javadoc-reference and all
# web-files (the compile process here takes longer).
# All files compiled with project.compile=normal are stored in the distribution
# folder.
project.compile=normal
# Set your name and URL, used for the web page and properties file.
author.name=Ted Davis
author.url=https://www.teddavis.org
# Set the web page for your Library.
# This is NOT a direct link to where to download it.
library.url=https://teddavis.org/xyscope
# Set the category (or categories) of your Library from the following list:
# "3D" "Animation" "Compilations" "Data"
# "Fabrication" "Geometry" "GUI" "Hardware"
# "I/O" "Language" "Math" "Simulation"
# "Sound" "Utilities" "Typography" "Video & Vision"
#
# If a value other than those listed is used, your Library will listed as
# "Other". Many categories must be comma-separated.
library.categories=Animation, Sound, Hardware
# A short sentence (or fragment) to summarize the Library's function. This will
# be shown from inside the PDE when the Library is being installed. Avoid
# repeating the name of your Library here. Also, avoid saying anything redundant
# like mentioning that it's a Library. This should start with a capitalized
# letter, and end with a period.
library.sentence= XYScope is a library for Processing to render graphics on a vector display (oscilloscope, laser) by converting them to audio.
# Additional information suitable for the Processing website. The value of
# 'sentence' always will be prepended, so you should start by writing the
# second sentence here. If your Library only works on certain operating systems,
# mention it here.
library.paragraph= This includes most primitive shapes (point, line, rect, ellipse, vertex, box, sphere, torus...) by converting those points to waveforms (oscillators with custom wavetables) and generating audio in real time using the Minim library. Vector graphics shine on a vector display and now you can view your generative works like never before! Tested on MacOS 10.9+ / Windows / Linux (RPi!).
library.acknowledgements= Acknowledgements:<br><a href="http://dailydrawbot.tumblr.com" target="_blank">Just Van Rossum</a> for the enlightening conversation on my X-Y attempts.<br><a href="https://stefaniebraeuer.ch/" target="_blank">Stefanie Bruer</a> for feeding the obsession with crucial theory + context.<br><a href="https://asdfg.me" target="_blank">Hansi Raber</a> for Java meta insights + finding external WaveTable bug!
# Set the source code repository for your project.
# We recommend Bitbucket (https://bitbucket.org) or GitHub (https://github.com).
source.host=GitHub
source.url=https://github.com/ffd8/xyscope
source.repository=https://github.com/ffd8/xyscope.git
# The current version of your Library.
# This number must be parsable as an int. It increments once with each release.
# This is used to compare different versions of the same Library, and check if
# an update is available.
library.version=5
# The version as the user will see it.
library.prettyVersion=3.0.0
# The min and max revision of Processing compatible with your Library.
# Note that these fields use the revision and not the version of Processing,
# parsable as an int. For example, the revision number for 2.2.1 is 227.
# You can find the revision numbers in the change log: https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
# Only use maxRevision (or minRevision), when your Library is known to
# break in a later (or earlier) release. Otherwise, use the default value 0.
compatible.minRevision=0
compatible.maxRevision=0
# The platforms and Processing version that the Library has been tested
# against. This information is only used in the generated webpage.
tested.platform=MacOS, Windows, Linux
tested.processingVersion=3.3.7
# Additional information for the generated webpage.
library.copyright=(cc) 2017-23
library.dependencies=Minim + (Geomerative, OpenCV, openkinect, Video for xtra_ examples)
library.keywords=oscilloscope, x-y mode, laser, vectrex, vector, vector display, vector monitor, vector graphics
# Include javadoc references into your project's javadocs.
#javadoc.java.href=http://docs.oracle.com/javase/7/docs/api/
javadoc.java.href=http://docs.oracle.com/javase/8/docs/api/
javadoc.processing.href=http://processing.github.io/processing-javadocs/core/
================================================
FILE: resources/build.xml
================================================
<project name="Processing Library" default="clean" basedir="../">
<!--
Properties for your project should be set and modified in the
build.properties file (located in the same folder as this build.xml file).
THIS FILE SHOULD NOT BE EDITED, unless you know what you are doing.
If you have recommendations for improvements, please let Elie know
at prisonerjohn@gmail.com
-->
<property file="./resources/build.properties" />
<description>
${ant.description}
</description>
<property name="line" value="------------------------------------------------------------------------------------------------" />
<condition property="is.normal">
<equals arg1="${project.compile}" arg2="normal" />
</condition>
<!-- set the OS properties -->
<condition property="is.mac">
<os family="mac" />
</condition>
<condition property="is.windows">
<os family="windows" />
</condition>
<condition property="is.unix">
<os family="unix" />
</condition>
<property name="project.jar.name" value="${project.name}.jar"/>
<property name="project.src" location="src"/>
<property name="project.tmp" location="tmp"/>
<property name="project.web" location="web"/>
<property name="project.data" location="data"/>
<property name="project.lib" location="lib"/>
<property name="project.bin" location="bin"/>
<property name="project.bin.data" location="${project.bin}/data"/>
<property name="project.examples" location="examples"/>
<property name="project.reference" location="reference"/>
<property name="project.dist" location="distribution"/>
<property name="project.dist.version" location="distribution/${project.name}-${library.version}"/>
<property name="project.changesource" location="changelog.txt"/>
<property name="project.changedest" location="${project.dist.version}/changelog.txt"/>
<property name="install.source" location="resources/README.md"/>
<property name="install.destination" location="${project.dist.version}/README.md"/>
<property name="libprops.source" location="resources/library.properties"/>
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="./resources/code/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<path id="classpath">
<fileset dir="${classpath.local.location}" includes="${classpath.local.include}" />
<fileset dir="${classpath.libraries.location}" includes="**/*.jar" />
<fileset dir="${project.lib}" includes="**/*.jar" />
</path>
<!-- Create the time stamp -->
<tstamp>
<format property="date" pattern="MM/dd/yyyy" offset="0" unit="hour"/>
</tstamp>
<target name="init">
<echo>${line}
Building the Processing Library ${project.name} ${library.version}
${line}
src path ${project.src}
bin path ${project.bin}
classpath.local ${classpath.local.location}
sketchbook ${sketchbook.location}
java version ${java.target.version}
${line}
</echo>
<mkdir dir="${project.bin}"/>
</target>
<target name="library.init" depends="init">
<echo message="init library ..." />
</target>
<target name="library.run" depends="library.init">
<echo message="building library ..." />
<antcall target="generate.structure"><param name="folder" value="library"/></antcall>
<antcall target="generate.source" />
<antcall target="compile" />
<antcall target="generate.jar"><param name="folder" value="library"/></antcall>
<antcall target="generate.javadoc" />
<antcall target="generate.libprops" />
<antcall target="copyToSketchbook"><param name="folder" value="libraries"/></antcall>
<antcall target="generate.distribution" />
<antcall target="generate.install.library" />
<antcall target="generate.project.changelog" />
<antcall target="generate.web" />
<antcall target="generate.zip" />
<delete dir="${project.tmp}"/>
</target>
<target name="generate.libprops" if="is.normal">
<property name="libprops.destination" location="${project.tmp}/${project.name}/library.properties"/>
<copy file="${libprops.source}" tofile="${libprops.destination}" />
<antcall target="parse.file"><param name="file" value="${libprops.destination}"/></antcall>
</target>
<target name="copyToSketchbook">
<echo message="copying files to the ${folder} folder in your sketchbook." />
<!-- copy the jar file to processing's sketchbook libraries folder -->
<delete dir="${sketchbook.location}/${folder}/${project.name}" />
<mkdir dir="${sketchbook.location}/${folder}/${project.name}" />
<copy todir="${sketchbook.location}/${folder}/${project.name}">
<fileset dir="${project.tmp}/${project.name}"/>
</copy>
</target>
<target name="compile">
<javac srcdir="${project.tmp}/${project.name}/src" destdir="${project.bin}" source="${java.target.version}" target="${java.target.version}" includeantruntime="false">
<classpath>
<path refid="classpath"/>
</classpath>
<compilerarg value="-Xlint"/>
</javac>
<copy todir="${project.bin.data}">
<fileset dir="${project.data}" excludes="README" />
</copy>
</target>
<target name="generate.jar">
<jar jarfile="${project.tmp}/${project.name}/${folder}/${project.jar.name}" basedir="${project.bin}"/>
</target>
<target name="generate.structure">
<delete dir="${project.tmp}" />
<mkdir dir="${project.tmp}" />
<mkdir dir="${project.tmp}/${project.name}" />
<mkdir dir="${project.tmp}/${project.name}/${folder}" />
<mkdir dir="${project.tmp}/${project.name}/examples" />
<mkdir dir="${project.tmp}/${project.name}/reference" />
<mkdir dir="${project.tmp}/${project.name}/src" />
<copy todir="${project.tmp}/${project.name}/examples">
<fileset dir="${project.examples}">
<exclude name="**/*README*"/>
</fileset>
</copy>
<copy todir="${project.tmp}/${project.name}/src">
<fileset dir="${project.src}"/>
</copy>
<copy todir="${project.tmp}/${project.name}/${folder}">
<fileset dir="${project.lib}" excludes="README core.jar jsminim.jar minim.jar" />
</copy>
</target>
<target name="generate.source" if="is.normal">
<antcall target="generate.source.win"/>
<antcall target="generate.source.nix"/>
</target>
<!-- These two targets are pretty much the same, except for the delimiter (can't find a better way of doing this) -->
<target name="generate.source.win" if="is.windows">
<echo message="generating source (windows) ..."/>
<path id="src.contents"><fileset dir="${project.tmp}/${project.name}/src" includes="**/*.java" /></path>
<property name="src.list" refid="src.contents" />
<foreach list="${src.list}" param="file" target="parse.file" delimiter=";" />
</target>
<target name="generate.source.nix" unless="is.windows">
<echo message="generating source (mac/linux) ..."/>
<path id="src.contents"><fileset dir="${project.tmp}/${project.name}/src" includes="**/*.java" /></path>
<property name="src.list" refid="src.contents" />
<foreach list="${src.list}" param="file" target="parse.file" delimiter=":" />
</target>
<target name="generate.distribution" if="is.normal">
<mkdir dir="${project.dist}"/>
<delete dir="${project.dist.version}"/>
<mkdir dir="${project.dist.version}" />
<mkdir dir="${project.dist.version}/${project.name}" />
<move file="${project.tmp}/${project.name}" toDir="${project.dist.version}" />
</target>
<target name="generate.javadoc" if="is.normal">
<!-- create the java reference of the Library -->
<javadoc bottom="Processing Library ${project.name} by ${author.name}. ${library.copyright}"
classpath="${classpath.local.location}/core.jar;{project.bin}"
destdir="${project.tmp}/${project.name}/reference"
verbose="false"
stylesheetfile="resources/stylesheet.css"
doctitle="Javadocs: ${project.name}"
public="true" version="false"
windowtitle="Javadocs: ${project.name}">
<link href="${javadoc.java.href}" />
<link href="${javadoc.processing.href}" />
<!-- <taglet name="ExampleTaglet" path="resources/code" /> -->
<fileset dir="${project.tmp}/${project.name}/src" defaultexcludes="yes">
<!-- add packages to be added to reference. -->
<include name="**/*"/>
</fileset>
</javadoc>
</target>
<target name="generate.web" if="is.normal">
<mkdir dir="${project.dist.version}/web" />
<copy todir="${project.dist.version}/web/reference">
<fileset dir="${project.dist.version}/${project.name}/reference" />
</copy>
<copy todir="${project.dist.version}/web/examples">
<fileset dir="${project.dist.version}/${project.name}/examples" />
</copy>
<copy todir="${project.dist.version}/web">
<fileset dir="${project.web}" />
</copy>
<copy todir="${project.dist.version}/reference">
<fileset dir="${project.web}" />
</copy>
<antcall target="parse.file"><param name="file" value="${project.dist.version}/web/index.html"/></antcall>
<antcall target="processExamples" />
<replaceregexp file="${project.dist.version}/web/index.html" match="##examples##" replace="" flags="g" />
</target>
<!-- find and replace ##placeholder## keywords in a file -->
<target name="parse.file">
<echo message="${file}" />
<replaceregexp file="${file}" match="##date##" replace="${date}" flags="g" />
<replaceregexp file="${file}" match="##copyright##" replace="${library.copyright}" flags="g" />
<replaceregexp file="${file}" match="##author##" replace="${author.name} ${author.url}" flags="g" />
<replaceregexp file="${file}" match="##author.name##" replace="${author.name}" flags="g" />
<replaceregexp file="${file}" match="##author.url##" replace="${author.url}" flags="g" />
<replaceregexp file="${file}" match="##library.name##" replace="${project.prettyName}" flags="g" />
<replaceregexp file="${file}" match="##project.name##" replace="${project.name}" flags="g" />
<replaceregexp file="${file}" match="##library.version##" replace="${library.version}" flags="g" />
<replaceregexp file="${file}" match="##library.prettyVersion##" replace="${library.prettyVersion}" flags="g" />
<replaceregexp file="${file}" match="##compatible.minRevision##" replace="${compatible.minRevision}" flags="g" />
<replaceregexp file="${file}" match="##compatible.maxRevision##" replace="${compatible.maxRevision}" flags="g" />
<replaceregexp file="${file}" match="##library.url##" replace="${library.url}" flags="g" />
<replaceregexp file="${file}" match="##library.categories##" replace="${library.categories}" flags="g" />
<replaceregexp file="${file}" match="##library.sentence##" replace="${library.sentence}" flags="g" />
<replaceregexp file="${file}" match="##library.paragraph##" replace="${library.paragraph}" flags="g" />
<replaceregexp file="${file}" match="##library.acknowledgements##" replace="${library.acknowledgements}" flags="g" />
<replaceregexp file="${file}" match="##library.keywords##" replace="${library.keywords}" flags="g" />
<replaceregexp file="${file}" match="##library.dependencies##" replace="${library.dependencies}" flags="g" />
<replaceregexp file="${file}" match="##source.host##" replace="${source.host}" flags="g" />
<replaceregexp file="${file}" match="##source.url##" replace="${source.url}" flags="g" />
<replaceregexp file="${file}" match="##source.repository##" replace="${source.repository}" flags="g" />
<replaceregexp file="${file}" match="##tested.platform##" replace="${tested.platform}" flags="g" />
<replaceregexp file="${file}" match="##tested.processingVersion##" replace="${tested.processingVersion}" flags="g" />
</target>
<target name="generate.install.library" if="is.normal">
<copy file="${install.source}" tofile="${install.destination}" />
<antcall target="parse.file"><param name="file" value="${install.destination}"/></antcall>
</target>
<target name="generate.project.changelog" if="is.normal">
<copy file="${project.changesource}" tofile="${project.changedest}" />
<antcall target="parse.file"><param name="file" value="${project.changedest}"/></antcall>
</target>
<target name="generate.zip" if="is.normal">
<!-- zip the distribution of the Library -->
<move todir="${project.dist.version}/tmp/${project.name}">
<fileset dir="${project.dist.version}/${project.name}" />
</move>
<copy file="${project.dist.version}/tmp/${project.name}/library.properties" tofile="${project.dist.version}/web/download/${project.name}.txt" />
<zip destfile="${project.dist.version}/${project.name}.zip"
basedir="${project.dist.version}/tmp"
excludes="**/.DS_Store"
/>
<move file="${project.dist.version}/${project.name}.zip" todir="${project.dist.version}/web/download" />
<copy file="${project.dist.version}/web/download/${project.name}.zip" tofile="${project.dist.version}/web/download/${project.name}-${library.version}.zip" />
<copy file="${project.dist.version}/web/download/${project.name}.txt" tofile="${project.dist.version}/web/download/${project.name}-${library.version}.txt" />
<move todir="${project.dist.version}">
<fileset dir="${project.dist.version}/web" />
</move>
<delete dir="${project.dist.version}/tmp" />
</target>
<!-- parsing the examples folder -->
<target name="processExamples">
<dirset id="examples.contents" dir="${project.examples}" excludes="*/*"/>
<property name="examples.list" refid="examples.contents"/>
<foreach list="${examples.list}" target="addExamples" param="exampleDir" delimiter=";">
</foreach>
</target>
<target name="addExamples">
<echo>${exampleDir}</echo>
<propertyregex property="pde"
input="${exampleDir}"
regexp="^.*\/(.*)$"
select="\1"
casesensitive="false"
defaultValue="${exampleDir}" />
<propertyregex property="data"
input="${exampleDir}"
regexp="data$"
select="true"
casesensitive="false"
defaultValue="false" />
<if>
<equals arg1="${data}" arg2="false" />
<then>
<replaceregexp file="${project.dist.version}/web/index.html"
match="(##examples##)"
replace="<li><a href="examples/${exampleDir}/${pde}.pde">${exampleDir}</a></li> \1"
flags="g" />
</then>
<else>
<echo message="Data folder, attention." />
</else>
</if>
</target>
<target name="clean" depends="library.run">
<delete dir="${project.bin}"/>
<delete dir="${project.tmp}"/>
<echo>
${line}
Name ${project.name}
Version ${library.prettyVersion} (${library.version})
Compiled ${project.compile}
Sketchbook ${sketchbook.location}
${line}
done, finished.
${line}
</echo>
</target>
</project>
================================================
FILE: resources/code/ExampleTaglet.java
================================================
/*
* Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* -Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
* DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
* RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
* ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
* FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
* SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
* THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that Software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*/
import com.sun.tools.doclets.Taglet;
import com.sun.javadoc.*;
import java.util.Map;
import java.io.*;
/**
* A sample Taglet representing @example. This tag can be used in any kind of
* {@link com.sun.javadoc.Doc}. It is not an inline tag. The text is displayed
* in yellow to remind the developer to perform a task. For
* example, "@example Hello" would be shown as:
* <DL>
* <DT>
* <B>To Do:</B>
* <DD><table cellpadding=2 cellspacing=0><tr><td bgcolor="yellow">Fix this!
* </td></tr></table></DD>
* </DL>
*
* @author Jamie Ho
* @since 1.4
*/
public class ExampleTaglet implements Taglet {
private static final String NAME = "example";
private static final String HEADER = "example To Do:";
/**
* Return the name of this custom tag.
*/
public String getName() {
return NAME;
}
/**
* Will return true since <code>@example</code>
* can be used in field documentation.
* @return true since <code>@example</code>
* can be used in field documentation and false
* otherwise.
*/
public boolean inField() {
return true;
}
/**
* Will return true since <code>@example</code>
* can be used in constructor documentation.
* @return true since <code>@example</code>
* can be used in constructor documentation and false
* otherwise.
*/
public boolean inConstructor() {
return true;
}
/**
* Will return true since <code>@example</code>
* can be used in method documentation.
* @return true since <code>@example</code>
* can be used in method documentation and false
* otherwise.
*/
public boolean inMethod() {
return true;
}
/**
* Will return true since <code>@example</code>
* can be used in method documentation.
* @return true since <code>@example</code>
* can be used in overview documentation and false
* otherwise.
*/
public boolean inOverview() {
return true;
}
/**
* Will return true since <code>@example</code>
* can be used in package documentation.
* @return true since <code>@example</code>
* can be used in package documentation and false
* otherwise.
*/
public boolean inPackage() {
return true;
}
/**
* Will return true since <code>@example</code>
* can be used in type documentation (classes or interfaces).
* @return true since <code>@example</code>
* can be used in type documentation and false
* otherwise.
*/
public boolean inType() {
return true;
}
/**
* Will return false since <code>@example</code>
* is not an inline tag.
* @return false since <code>@example</code>
* is not an inline tag.
*/
public boolean isInlineTag() {
return false;
}
/**
* Register this Taglet.
* @param tagletMap the map to register this tag to.
*/
public static void register(Map tagletMap) {
ExampleTaglet tag = new ExampleTaglet();
Taglet t = (Taglet) tagletMap.get(tag.getName());
if (t != null) {
tagletMap.remove(tag.getName());
}
tagletMap.put(tag.getName(), tag);
}
/**
* Given the <code>Tag</code> representation of this custom
* tag, return its string representation.
* @param tag the <code>Tag</code> representation of this custom tag.
*/
public String toString(Tag tag) {
return createHTML(readFile(tag.text()));
}
/**
* Given an array of <code>Tag</code>s representing this custom
* tag, return its string representation.
* @param tags the array of <code>Tag</code>s representing of this custom tag.
*/
public String toString(Tag[] tags) {
if (tags.length == 0) {
return null;
}
return createHTML(readFile(tags[0].text()));
}
String createHTML(String theString) {
if(theString!=null) {
String dd = "<script type=\"text/javascript\">\n" +
"<!--\n"+
"document.getElementsByTagName('html')[0].className = 'isjs';" +
"function toggle(dt) { var display, dd=dt; do{ dd = dd.nextSibling } while(dd.tagName!='DD'); toOpen =!dd.style.display;" +
"dd.style.display = toOpen? 'block':''; dt.getElementsByTagName('span')[0].innerHTML = toOpen? '-':'+' ; }\n" +
"-->\n</script>";
return dd+"\n<div id=\"test\" class=\"toggleList\">" +
"<dl><dt onclick=\"toggle(this);\"><span>+</span>Example</dt>" +
"<dd><pre>"+theString+"</pre>" +
"</dd></dl></div>";
}
return "";
}
/**
* check if the examples directory exists and return the example as given in the tag.
* @param theExample the name of the example
*/
String readFile(String theExample) {
String record = "";
String myResult = "";
int recCount = 0;
String myDir = "../examples";
File file=new File(myDir);
if(file.exists()==false) {
myDir = "./examples";
}
try {
FileReader fr = new FileReader(myDir+"/"+theExample+"/"+theExample+".pde");
BufferedReader br = new BufferedReader(fr);
record = new String();
while ((record = br.readLine()) != null) {
myResult += record+"\n";
}
} catch (IOException e) {
System.out.println(e);
return null;
}
return myResult;
}
}
================================================
FILE: resources/code/doc.sh
================================================
# a shell script to create a java documentation
# for a processing Library.
#
# make changes to the variables below so they
# fit the structure of your Library
# the package name of your Library
package=template;
# source folder location
src=../src;
# the destination folder of your documentation
dest=../documentation;
# compile the java documentation
javadoc -d $dest -stylesheetfile ./stylesheet.css -sourcepath ${src} ${package}
================================================
FILE: resources/library.properties
================================================
# More on this file here: https://github.com/processing/processing/wiki/Library-Basics
# UTF-8 supported.
# The name of your Library as you want it formatted.
name = ##library.name##
# List of authors. Links can be provided using the syntax [author name](url).
authors = [##author.name##](##author.url##)
# A web page for your Library, NOT a direct link to where to download it.
url = ##library.url##
# The category (or categories) of your Library, must be from the following list:
# "3D" "Animation" "Compilations" "Data"
# "Fabrication" "Geometry" "GUI" "Hardware"
# "I/O" "Language" "Math" "Simulation"
# "Sound" "Utilities" "Typography" "Video & Vision"
#
# If a value other than those listed is used, your Library will listed as
# "Other". Many categories must be comma-separated.
categories = ##library.categories##
# A short sentence (or fragment) to summarize the Library's function. This will
# be shown from inside the PDE when the Library is being installed. Avoid
# repeating the name of your Library here. Also, avoid saying anything redundant
# like mentioning that it's a Library. This should start with a capitalized
# letter, and end with a period.
sentence = ##library.sentence##
# Additional information suitable for the Processing website. The value of
# 'sentence' always will be prepended, so you should start by writing the
# second sentence here. If your Library only works on certain operating systems,
# mention it here.
paragraph = ##library.paragraph##
# Links in the 'sentence' and 'paragraph' attributes can be inserted using the
# same syntax as for authors.
# That is, [here is a link to Processing](http://processing.org/)
# A version number that increments once with each release. This is used to
# compare different versions of the same Library, and check if an update is
# available. You should think of it as a counter, counting the total number of
# releases you've had.
version = ##library.version## # This must be parsable as an int
# The version as the user will see it. If blank, the version attribute will be
# used here. This should be a single word, with no spaces.
prettyVersion = ##library.prettyVersion## # This is treated as a String
# The min and max revision of Processing compatible with your Library.
# Note that these fields use the revision and not the version of Processing,
# parsable as an int. For example, the revision number for 2.2.1 is 227.
# You can find the revision numbers in the change log: https://raw.githubusercontent.com/processing/processing/master/build/shared/revisions.txt
# Only use maxRevision (or minRevision), when your Library is known to
# break in a later (or earlier) release. Otherwise, use the default value 0.
minRevision = ##compatible.minRevision##
maxRevision = ##compatible.maxRevision##
================================================
FILE: resources/stylesheet.css
================================================
/* Javadoc style sheet */
/*
Overall document style
*/
@import url('resources/fonts/dejavu.css');
body {
background-color:#ffffff;
color:#353833;
font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
font-size:14px;
margin:0;
}
a:link, a:visited {
text-decoration:none;
color:#4A6782;
}
a:hover, a:focus {
text-decoration:none;
color:#bb7a2a;
}
a:active {
text-decoration:none;
color:#4A6782;
}
a[name] {
color:#353833;
}
a[name]:hover {
text-decoration:none;
color:#353833;
}
pre {
font-family:'DejaVu Sans Mono', monospace;
font-size:14px;
}
h1 {
font-size:20px;
}
h2 {
font-size:18px;
}
h3 {
font-size:16px;
font-style:italic;
}
h4 {
font-size:13px;
}
h5 {
font-size:12px;
}
h6 {
font-size:11px;
}
ul {
list-style-type:disc;
}
code, tt {
font-family:'DejaVu Sans Mono', monospace;
font-size:14px;
padding-top:4px;
margin-top:8px;
line-height:1.4em;
}
dt code {
font-family:'DejaVu Sans Mono', monospace;
font-size:14px;
padding-top:4px;
}
table tr td dt code {
font-family:'DejaVu Sans Mono', monospace;
font-size:14px;
vertical-align:top;
padding-top:4px;
}
sup {
font-size:8px;
}
/*
Document title and Copyright styles
*/
.clear {
clear:both;
height:0px;
overflow:hidden;
}
.aboutLanguage {
float:right;
padding:0px 21px;
font-size:11px;
z-index:200;
margin-top:-9px;
}
.legalCopy {
margin-left:.5em;
}
.bar a, .bar a:link, .bar a:visited, .bar a:active {
color:#FFFFFF;
text-decoration:none;
}
.bar a:hover, .bar a:focus {
color:#bb7a2a;
}
.tab {
background-color:#0066FF;
color:#ffffff;
padding:8px;
width:5em;
font-weight:bold;
}
/*
Navigation bar styles
*/
.bar {
background-color:#4D7A97;
color:#FFFFFF;
padding:.8em .5em .4em .8em;
height:auto;/*height:1.8em;*/
font-size:11px;
margin:0;
}
.topNav {
background-color:#4D7A97;
color:#FFFFFF;
float:left;
padding:0;
width:100%;
clear:right;
height:2.8em;
padding-top:10px;
overflow:hidden;
font-size:12px;
}
.bottomNav {
margin-top:10px;
background-color:#4D7A97;
color:#FFFFFF;
float:left;
padding:0;
width:100%;
clear:right;
height:2.8em;
padding-top:10px;
overflow:hidden;
font-size:12px;
}
.subNav {
background-color:#dee3e9;
float:left;
width:100%;
overflow:hidden;
font-size:12px;
}
.subNav div {
clear:left;
float:left;
padding:0 0 5px 6px;
text-transform:uppercase;
}
ul.navList, ul.subNavList {
float:left;
margin:0 25px 0 0;
padding:0;
}
ul.navList li{
list-style:none;
float:left;
padding: 5px 6px;
text-transform:uppercase;
}
ul.subNavList li{
list-style:none;
float:left;
}
.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
color:#FFFFFF;
text-decoration:none;
text-transform:uppercase;
}
.topNav a:hover, .bottomNav a:hover {
text-decoration:none;
color:#bb7a2a;
text-transform:uppercase;
}
.navBarCell1Rev {
background-color:#F8981D;
color:#253441;
margin: auto 5px;
}
.skipNav {
position:absolute;
top:auto;
left:-9999px;
overflow:hidden;
}
/*
Page header and footer styles
*/
.header, .footer {
clear:both;
margin:0 20px;
padding:5px 0 0 0;
}
.indexHeader {
margin:10px;
position:relative;
}
.indexHeader span{
margin-right:15px;
}
.indexHeader h1 {
font-size:13px;
}
.title {
color:#2c4557;
margin:10px 0;
}
.subTitle {
margin:5px 0 0 0;
}
.header ul {
margin:0 0 15px 0;
padding:0;
}
.footer ul {
margin:20px 0 5px 0;
}
.header ul li, .footer ul li {
list-style:none;
font-size:13px;
}
/*
Heading styles
*/
div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
background-color:#dee3e9;
border:1px solid #d0d9e0;
margin:0 0 6px -8px;
padding:7px 5px;
}
ul.blockList ul.blockList ul.blockList li.blockList h3 {
background-color:#dee3e9;
border:1px solid #d0d9e0;
margin:0 0 6px -8px;
padding:7px 5px;
}
ul.blockList ul.blockList li.blockList h3 {
padding:0;
margin:15px 0;
}
ul.blockList li.blockList h2 {
padding:0px 0 20px 0;
}
/*
Page layout container styles
*/
.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
clear:both;
padding:10px 20px;
position:relative;
}
.indexContainer {
margin:10px;
position:relative;
font-size:12px;
}
.indexContainer h2 {
font-size:13px;
padding:0 0 3px 0;
}
.indexContainer ul {
margin:0;
padding:0;
}
.indexContainer ul li {
list-style:none;
padding-top:2px;
}
.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
font-size:12px;
font-weight:bold;
margin:10px 0 0 0;
color:#4E4E4E;
}
.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
margin:5px 0 10px 0px;
font-size:14px;
font-family:'DejaVu Sans Mono',monospace;
}
.serializedFormContainer dl.nameValue dt {
margin-left:1px;
font-size:1.1em;
display:inline;
font-weight:bold;
}
.serializedFormContainer dl.nameValue dd {
margin:0 0 0 1px;
font-size:1.1em;
display:inline;
}
/*
List styles
*/
ul.horizontal li {
display:inline;
font-size:0.9em;
}
ul.inheritance {
margin:0;
padding:0;
}
ul.inheritance li {
display:inline;
list-style:none;
}
ul.inheritance li ul.inheritance {
margin-left:15px;
padding-left:15px;
padding-top:1px;
}
ul.blockList, ul.blockListLast {
margin:10px 0 10px 0;
padding:0;
}
ul.blockList li.blockList, ul.blockListLast li.blockList {
list-style:none;
margin-bottom:15px;
line-height:1.4;
}
ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
padding:0px 20px 5px 10px;
border:1px solid #ededed;
background-color:#f8f8f8;
}
ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
padding:0 0 5px 8px;
background-color:#ffffff;
border:none;
}
ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
margin-left:0;
padding-left:0;
padding-bottom:15px;
border:none;
}
ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
list-style:none;
border-bottom:none;
padding-bottom:0;
}
table tr td dl, table tr td dl dt, table tr td dl dd {
margin-top:0;
margin-bottom:1px;
}
/*
Table styles
*/
.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary {
width:100%;
border-left:1px solid #EEE;
border-right:1px solid #EEE;
border-bottom:1px solid #EEE;
}
.overviewSummary, .memberSummary {
padding:0px;
}
.overviewSummary caption, .memberSummary caption, .typeSummary caption,
.useSummary caption, .constantsSummary caption, .deprecatedSummary caption {
position:relative;
text-align:left;
background-repeat:no-repeat;
color:#253441;
font-weight:bold;
clear:none;
overflow:hidden;
padding:0px;
padding-top:10px;
padding-left:1px;
margin:0px;
white-space:pre;
}
.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,
.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link,
.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,
.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,
.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,
.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,
.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,
.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited {
color:#FFFFFF;
}
.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,
.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span {
white-space:nowrap;
padding-top:5px;
padding-left:12px;
padding-right:12px;
padding-bottom:7px;
display:inline-block;
float:left;
background-color:#F8981D;
border: none;
height:16px;
}
.memberSummary caption span.activeTableTab span {
white-space:nowrap;
padding-top:5px;
padding-left:12px;
padding-right:12px;
margin-right:3px;
display:inline-block;
float:left;
background-color:#F8981D;
height:16px;
}
.memberSummary caption span.tableTab span {
white-space:nowrap;
padding-top:5px;
padding-left:12px;
padding-right:12px;
margin-right:3px;
display:inline-block;
float:left;
background-color:#4D7A97;
height:16px;
}
.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab {
padding-top:0px;
padding-left:0px;
padding-right:0px;
background-image:none;
float:none;
display:inline;
}
.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,
.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd {
display:none;
width:5px;
position:relative;
float:left;
background-color:#F8981D;
}
.memberSummary .activeTableTab .tabEnd {
display:none;
width:5px;
margin-right:3px;
position:relative;
float:left;
background-color:#F8981D;
}
.memberSummary .tableTab .tabEnd {
display:none;
width:5px;
margin-right:3px;
position:relative;
background-color:#4D7A97;
float:left;
}
.overviewSummary td, .memberSummary td, .typeSummary td,
.useSummary td, .constantsSummary td, .deprecatedSummary td {
text-align:left;
padding:0px 0px 12px 10px;
}
th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th,
td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{
vertical-align:top;
padding-right:0px;
padding-top:8px;
padding-bottom:3px;
}
th.colFirst, th.colLast, th.colOne, .constantsSummary th {
background:#dee3e9;
text-align:left;
padding:8px 3px 3px 7px;
}
td.colFirst, th.colFirst {
white-space:nowrap;
font-size:13px;
}
td.colLast, th.colLast {
font-size:13px;
}
td.colOne, th.colOne {
font-size:13px;
}
.overviewSummary td.colFirst, .overviewSummary th.colFirst,
.useSummary td.colFirst, .useSummary th.colFirst,
.overviewSummary td.colOne, .overviewSummary th.colOne,
.memberSummary td.colFirst, .memberSummary th.colFirst,
.memberSummary td.colOne, .memberSummary th.colOne,
.typeSummary td.colFirst{
width:25%;
vertical-align:top;
}
td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
font-weight:bold;
}
.tableSubHeadingColor {
background-color:#EEEEFF;
}
.altColor {
background-color:#FFFFFF;
}
.rowColor {
background-color:#EEEEEF;
}
/*
Content styles
*/
.description pre {
margin-top:0;
}
.deprecatedContent {
margin:0;
padding:10px 0;
}
.docSummary {
padding:0;
}
ul.blockList ul.blockList ul.blockList li.blockList h3 {
font-style:normal;
}
div.block {
font-size:14px;
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
}
td.colLast div {
padding-top:0px;
}
td.colLast a {
padding-bottom:3px;
}
/*
Formatting effect styles
*/
.sourceLineNo {
color:green;
padding:0 30px 0 0;
}
h1.hidden {
visibility:hidden;
overflow:hidden;
font-size:10px;
}
.block {
display:block;
margin:3px 10px 2px 0px;
color:#474747;
}
.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink,
.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel,
.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink {
font-weight:bold;
}
.deprecationComment, .emphasizedPhrase, .interfaceName {
font-style:italic;
}
div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
div.block div.block span.interfaceName {
font-style:normal;
}
div.contentContainer ul.blockList li.blockList h2{
padding-bottom:0px;
}
================================================
FILE: src/xyscope/XYWavetable.java
================================================
package xyscope;
/*
* Special update to Minim Waveform class by Hansi Raber (Sep 2018),
* fixing an array out of bounds bug when changing waveform quickly.
* */
import java.util.Random;
import ddf.minim.ugens.Waveform;
/**
* Wavetable wraps a float array of any size and lets you sample the array using
* a normalized value [0,1]. This means that if you have an array that is 2048
* samples long, then value(0.5) will give you the 1024th sample. You will most
* often use Wavetables as the Waveform in an Oscil, but other uses are also
* possible. Additionally, Wavetable provides a set of methods for transforming
* the samples it contains.
*
* @example Synthesis/WavetableMethods
*
* @related Waveform
* @related Waves
* @related WavetableGenerator
*
* @author Mark Godfrey <mark.godfrey@gatech.edu>
*/
public class XYWavetable implements Waveform
{
private float[] waveform;
/**
* Construct a Wavetable that contains <code>size</code> entries.
*
* @param size
* int: the number of samples the Wavetable should contain
*
* @related Wavetable
*/
public XYWavetable(int size)
{
waveform = new float[size];
}
/**
* Construct a Wavetable that will use <code>waveform</code> as the float
* array to sample from. This <em>will not</em> copy <code>waveform</code>,
* it will use it directly.
*
* @param waveform
* float[]: the float array this Wavetable will sample
*
* @related Wavetable
*/
public XYWavetable(float[] waveform)
{
this.waveform = waveform;
}
/**
* Make a new Wavetable that has the same waveform values as
* <code>wavetable</code>. This will <em>copy</em> the values from the
* provided Wavetable into this Wavetable's waveform.
*
* @param wavetable
* Wavetable: the Wavetable to copy
*
* @related Wavetable
*/
public XYWavetable(XYWavetable wavetable)
{
waveform = new float[wavetable.waveform.length];
System.arraycopy( wavetable.waveform, 0, waveform, 0, waveform.length );
}
/**
* Sets this Wavetable's waveform to the one provided. This
* <em>will not</em> copy the values from the provided waveform, it will use
* the waveform directly.
*
* @param waveform
* float[]: the new sample data
*
* @related Wavetable
*/
public void setWaveform(float[] waveform)
{
this.waveform = waveform;
}
/**
* Returns the value of the i<sup>th</sup> entry in this Wavetable's
* waveform. This is equivalent to getWaveform()[i].
*
* @shortdesc Returns the value of the i<sup>th</sup> entry in this Wavetable's
* waveform.
*
* @param i
* int: the index of the sample to return
*
* @return float: the value of the sample at i
*
* @related Wavetable
*/
public float get(int i)
{
return waveform[i];
}
/**
* Sample the Wavetable using a value in the range [0,1]. For instance, if
* the Wavetable has 1024 values in its float array, then calling value(0.5)
* will return the 512th value in the array. If the result is that it needs
* say the 456.65th value, this will interpolate between the surrounding
* values.
*
* @shortdesc Sample the Wavetable using a value in the range [0,1].
*
* @example Synthesis/WavetableMethods
*
* @param at
* float: a value in the range [0, 1]
*
* @return float: this Wavetable sampled at the requested interval
*
* @related Wavetable
*/
public float value(float at)
{
float[] wave = this.waveform; // create local waveform for thread safe
if(wave.length==0) return 0;
float whichSample = wave.length * (((at%1)+1)%1);
// linearly interpolate between the two samples we want.
int lowSamp = ((int)whichSample)%wave.length;
int hiSamp = (lowSamp + 1)%wave.length;
float rem = whichSample - lowSamp;
return wave[lowSamp] + rem
* ( wave[hiSamp] - wave[lowSamp] );
}
/**
* Returns the underlying waveform, <em>not</em> a copy of it.
*
* @return float[]: the float array managed by this Wavetable
*
* @related Wavetable
*/
public float[] getWaveform()
{
return waveform;
}
/**
* Sets the i<sup>th</sup> entry of the underlying waveform to
* <code>value</code>. This is equivalent to:
* <p>
* <code>getWaveform()[i] = value;</code>
*
* @param i
* int: the index of the sample to set
* @param value
* float: the new sample value
*
* @related Wavetable
*/
public void set(int i, float value)
{
waveform[i] = value;
}
/**
* Returns the length of the underlying waveform. This is equivalent to:
* <p>
* <code>getWaveform().length</code>
*
* @return int: the length of the underlying float array
*
* @related Wavetable
*/
public int size()
{
return waveform.length;
}
/**
* Multiplies each value of the underlying waveform by <code>scale</code>.
*
* @param scale
* float: the amount to scale the Wavetable with
*
* @related Wavetable
*/
public void scale(float scale)
{
for ( int i = 0; i < waveform.length; i++ )
{
waveform[i] *= scale;
}
}
/**
* Apply a DC offset to this Wavetable. In other words, add
* <code>amount</code> to every sample.
*
* @param amount
* float: the amount to add to every sample in the table
*
* @related Wavetable
*/
public void offset(float amount)
{
for ( int i = 0; i < waveform.length; ++i )
{
waveform[i] += amount;
}
}
/**
* Normalizes the Wavetable by finding the largest amplitude in the table
* and scaling the table by the inverse of that amount. The result is that
* the largest value in the table will now have an amplitude of 1 and
* everything else is scaled proportionally.
*
* @example Synthesis/WavetableMethods
*
* @related Wavetable
*/
public void normalize()
{
float max = Float.MIN_VALUE;
for ( int i = 0; i < waveform.length; i++ )
{
if ( Math.abs( waveform[i] ) > max )
max = Math.abs( waveform[i] );
}
scale( 1 / max );
}
/**
* Flips the table around 0. Equivalent to <code>flip(0)</code>.
*
* @see #flip(float)
* @related flip ( )
* @related Wavetable
*/
public void invert()
{
flip( 0 );
}
/**
* Flip the values in the table around a particular value. For example, if
* you flip around 2, values greater than 2 will become less than two by the
* same amount and values less than 2 will become greater than 2 by the same
* amount. 3 -> 1, 0 -> 4, etc.
*
* @shortdesc Flip the values in the table around a particular value.
*
* @example Synthesis/WavetableMethods
*
* @param in
* float: the value to flip the table around
*
* @related Wavetable
*/
public void flip(float in)
{
for ( int i = 0; i < waveform.length; i++ )
{
if ( waveform[i] > in )
waveform[i] = in - ( waveform[i] - in );
else
waveform[i] = in + ( in - waveform[i] );
}
}
/**
* Adds Gaussian noise to the waveform.
*
* @example Synthesis/WavetableMethods
*
* @param sigma
* float: the amount to scale the random values by, in effect how
* "loud" the added noise will be.
*
* @related Wavetable
*/
public void addNoise(float sigma)
{
Random rgen = new Random();
for ( int i = 0; i < waveform.length; i++ )
{
waveform[i] += ( (float)rgen.nextGaussian() ) * sigma;
}
}
/**
* Inverts all values in the table that are less than zero. -1 -> 1, -0.2 -> 0.2, etc.
*
* @example Synthesis/WavetableMethods
*
* @related Wavetable
*/
public void rectify()
{
for ( int i = 0; i < waveform.length; i++ )
{
if ( waveform[i] < 0 )
waveform[i] *= -1;
}
}
/**
* Smooth out the values in the table by using a moving average window.
*
* @example Synthesis/WavetableMethods
*
* @param windowLength
* int: how many samples large the window should be
*
* @related Wavetable
*/
public void smooth(int windowLength)
{
if ( windowLength < 1 )
return;
float[] temp = (float[])waveform.clone();
for ( int i = windowLength; i < waveform.length; i++ )
{
float avg = 0;
for ( int j = i - windowLength; j <= i; j++ )
{
avg += temp[j] / windowLength;
}
waveform[i] = avg;
}
}
/**
* Warping works by choosing a point in the waveform, the warpPoint, and
* then specifying where it should move to, the warpTarget. Both values
* should be normalized (i.e. in the range [0,1]). What will happen is that
* the waveform data in front of and behind the warpPoint will be squashed
* or stretch to fill the space defined by where the warpTarget is. For
* instance, if you took Waves.SQUARE and called warp( 0.5, 0.2 ), you would
* wind up with a square wave with a 20 percent duty cycle, the same as
* using Waves.square( 0.2 ). This is because the crossover point of a
* square wave is halfway through and warping it such that the crossover is
* moved to 20% through the waveform is equivalent to changing the duty
* cycle. Or course, much more interesting things happen when warping a more
* complex waveform, such as one returned by the Waves.randomNHarms method,
* especially if it is warped more than once.
*
* @shortdesc Warping works by choosing a point in the waveform, the
* warpPoint, and then specifying where it should move to, the
* warpTarget.
*
* @example Synthesis/WavetableMethods
*
* @param warpPoint
* float: the point in the wave for to be moved, expressed as a
* normalized value.
* @param warpTarget
* float: the point in the wave to move the warpPoint to,
* expressed as a normalized value.
*
* @related Wavetable
*/
public void warp(float warpPoint, float warpTarget)
{
float[] newWave = new float[waveform.length];
for ( int s = 0; s < newWave.length; ++s )
{
float lookup = (float)s / newWave.length;
if ( lookup <= warpTarget )
{
// normalize look up to [0,warpTarget], expand to [0,warpPoint]
lookup = ( lookup / warpTarget ) * warpPoint;
}
else
{
// map (warpTarget,1] to (warpPoint,1]
lookup = warpPoint + ( 1 - ( 1 - lookup ) / ( 1 - warpTarget ) ) * ( 1 - warpPoint );
}
newWave[s] = value( lookup );
}
waveform = newWave;
}
}
================================================
FILE: src/xyscope/XYscope.java
================================================
/*
* cc ted davis 2017-23
*/
package xyscope;
import processing.core.*;
import static processing.core.PApplet.*;
import java.util.ArrayList;
// minim
import ddf.minim.*;
import ddf.minim.ugens.*;
import javax.sound.sampled.*;
/**
* Render vector graphics on a vector display (oscilloscope
* X-Y mode, laser) by converting them to audio .
*
*/
public class XYscope {
// myParent is a reference to the parent sketch
PApplet myParent;
/**
* Collection of current shapes rendered by buildWaves().
*/
public XYShapeList shapes = new XYShapeList();
// minim
public Minim minim, minimZ;
public AudioRecorder recorder;
/**
* minim AudioOutput, for customizing audio out.
*/
public AudioOutput outXY, outZ;
/**
* minim Summer, for customizing patching filters.
*/
public Summer sumXY, sumZ;
/**
* minim Oscil, for customizing XYZ oscillators.
*/
public Oscil waveX, waveY, waveZ;
/**
* minim Wavetable, for customizing XYZ oscillators.
*/
public XYWavetable tableX, tableY, tableZ;
Pan panX = new Pan(-1);
Pan panY = new Pan(1);
Mixer.Info[] mixerInfo;
float initAmp = 1.0f;
PVector amp = new PVector(initAmp, initAmp, initAmp);
float initFreq = 50f; // 43.065
PVector freq = new PVector(initFreq, initFreq, initFreq);
// Mixing audio channels
AudioOutput mixXY;
boolean useMix = false;
int sampleRate = 44100; // def 44100
int bufferSize = 512; // def 1024
String mixerName = "";
int waveSizeVal = bufferSize;
int waveSizeValOG = waveSizeVal;
int maxPoints = waveSizeValOG;
public float[] shapeX = new float[waveSizeVal];
public float[] shapeY = new float[waveSizeVal];
public float[] shapeZ = new float[waveSizeVal];
float[] shapePreX = new float[waveSizeVal];
float[] shapePreY = new float[waveSizeVal];
float[] shapePreZ = new float[waveSizeVal];
boolean debugWave = false;
int debugSize = 10;
boolean busy = false;
boolean useLimitPoints = false;
int limitPointsVal = waveSizeValOG;
int ellipseDetail = 30;
boolean useEase = false;
float easeVal = .1f;
boolean useZ = false;
boolean useSmooth = false;
int smoothVal = 12;
boolean useLimitPath = false;
float limitVal = 1;
float zaxisMax = 1f;
float zaxisMin = -1f;
int zoffset = 1;
// TYPE VARS
String hershey_font[];
int hheight = 21;
float hleading = 30f;
float hfactor = 1;
int textAlignX = 37;
int textAlignY = 101;
/**
* List of built-in Hershey Fonts available
*/
public String[] fonts = {"astrology", "cursive", "cyrilc_1", "cyrillic", "futural", "futuram", "gothgbt", "gothgrt", "gothiceng", "gothicger", "gothicita", "gothitt", "greek", "greekc", "greeks", "japanese", "markers", "mathlow", "mathupp", "meteorology", "music", "rowmand", "rowmans", "rowmant", "scriptc", "scripts", "symbolic", "timesg", "timesi", "timesib", "timesr", "timesrb"};
// VECTREX VARS
boolean useVectrex = false;
float vectrexAmp = .82f;
float vectrexAmpInit = .6f;
int vectrexRotation = 0;
int vectrexWidth = 310;
int vectrexHeight = 410;
// LASER VARS
boolean useLaser = false;
public Minim minimR, minimBG;
/**
* minim Oscil, for customizing Laser RGB oscillators.
*/
public Oscil waveR, waveG, waveB;
public XYWavetable tableR, tableG, tableB;
Pan panR = new Pan(1);
Pan panG = new Pan(-1);
Pan panB = new Pan(1);
public AudioOutput outR, outGB;
public float[] shapeR = new float[waveSizeVal];
public float[] shapeG = new float[waveSizeVal];
public float[] shapeB = new float[waveSizeVal];
private XYShape RGBshape = new XYShape();
PVector lsFreq = new PVector(initFreq, initFreq, initFreq);
PVector lsWB = new PVector(250, 220, 90);
PVector lsMin = new PVector(0, 0, 0);
PVector lsDash = new PVector(1, 1, 1);
MoogFilter moog;
float laserLPFVal = 10000.0f;
float laserCutoffVal = 20f;
int xyWidth, xyHeight;
/**
* Initialize library in setup(), use default system audio out setting.
*
* @param theParent
* PApplet to apply to, typically 'this'
*/
public XYscope(PApplet theParent) {
myParent = theParent;
welcome();
initMinim();
setOutput();
}
/**
* Initialize instance of XYscope and patch to an already existing signal.
*
* @param theParent
* PApplet to apply to, typically 'this'
* @param outMix
* AudioOutput to merge instance and of XYscope to
*/
public XYscope(PApplet theParent, AudioOutput outMix) {
myParent = theParent;
welcome();
initMinim();
setWaveTable(outMix);
useMix = true;
}
/**
* Initialize library in setup(), custom soundcard by String for XY.
*
* @param theParent
* PApplet to apply to, typically 'this'
* @param xyMixer
* Name of custom sound mixer to use for XY.
*/
public XYscope(PApplet theParent, String xyMixer) {
myParent = theParent;
welcome();
getMixerInfo();
initMinim();
setMixer(xyMixer);
setOutput();
}
/**
* Initialize library in setup(), using default soundcard and set custom
* sample rate (44100, 192000).
*
* @param theParent
* PApplet to apply to, typically 'this'
* @param sampleR
* Sample rate for soundcard (44100, 48000, 96000, 192000).
*/
public XYscope(PApplet theParent, int sampleR) {
myParent = theParent;
welcome();
initMinim();
sampleRate = sampleR;
setOutput();
}
/**
* Initialize library in setup(), custom soundcard by string for XY and set
* custom sample rate (44100, 192000).
*
* @param theParent
* PApplet to apply to, typically 'this'
* @param xyMixer
* Name of custom sound mixer to use for XY.
* @param sampleR
* Sample rate for soundcard (44100, 48000, 96000, 192000).
*/
public XYscope(PApplet theParent, String xyMixer, int sampleR) {
myParent = theParent;
welcome();
getMixerInfo();
initMinim();
setMixer(xyMixer);
sampleRate = sampleR;
setOutput();
}
/**
* Initialize library in setup(), custom soundcard by string for XY and set
* custom sample rate (44100, 192000).
*
* @param theParent
* PApplet to apply to, typically 'this'
* @param xyMixer
* Name of custom sound mixer to use for XY.
* @param sampleRateVal
* Sample rate for soundcard (44100, 48000, 96000, 192000).
* @param bufferSizeVal
* Size of buffer/latency for cpu/soundcard (128, 256, 512, 1024, 2048).
*/
public XYscope(PApplet theParent, String xyMixer, int sampleRateVal, int bufferSizeVal) {
myParent = theParent;
welcome();
getMixerInfo();
initMinim();
setMixer(xyMixer);
sampleRate = sampleRateVal;
bufferSize = bufferSizeVal;
setOutput();
}
private void welcome() {
System.out.println("XYscope 3.0.0 - https://teddavis.org/xyscope");
xyWidth = myParent.width;
xyHeight = myParent.height;
initText();
}
private void initText() {
textFont("meteorology");
}
/**
* Lists all audio input/output options available
*/
public void getMixerInfo() {
mixerInfo = AudioSystem.getMixerInfo();
for (int i = 0; i < mixerInfo.length; i++) {
println(i + " = " + mixerInfo[i].getName());
}
}
private static Mixer getMixerByName(String toFind) {
for (Mixer.Info info : AudioSystem.getMixerInfo()) {
if (toFind.equals(info.getName())) {
return AudioSystem.getMixer(info);
}
}
return null;
}
private void initMinim() {
minim = new Minim(myParent);
minimZ = new Minim(myParent);
minimR = new Minim(myParent);
minimBG = new Minim(myParent);
}
// *** add mixer() as getter and setter?? add bufferSize as initial option param
private void setMixer(String xyMixer) {
getMixerInfo();
Mixer mixer = getMixerByName(xyMixer);
minim.setOutputMixer(mixer);
}
private void setOutput() {
outXY = minim.getLineOut(Minim.STEREO, bufferSize, sampleRate);
setWaveTable();
}
public int sampleRate() {
return sampleRate;
}
public void sampleRate(int sampleRateVal) {
sampleRate = sampleRateVal;
setOutput();
}
public int bufferSize() {
return outXY.bufferSize();
}
public void bufferSize(int bufferSizeVal) {
if(bufferSizeVal > 16) {
bufferSize = bufferSizeVal;
}
setOutput();
}
private void setWaveTable() {
sumXY = new Summer();
sumXY.setChannelCount(2);
tableX = new XYWavetable(2);
waveX = new Oscil(freq.x, amp.x, tableX);
tableX.setWaveform(shapeX);
waveX.patch(panX).patch(sumXY);
tableY = new XYWavetable(2);
waveY = new Oscil(freq.y, amp.y, tableY);
tableY.setWaveform(shapeY);
waveY.patch(panY).patch(sumXY);
waveReset();
sumXY.patch(outXY);
}
private void setWaveTable(AudioOutput outMix) {
tableX = new XYWavetable(2);
waveX = new Oscil(freq.x, amp.x, tableX);
tableX.setWaveform(shapeX);
waveX.patch(panX).patch(outMix);
tableY = new XYWavetable(2);
waveY = new Oscil(freq.y, amp.y, tableY);
tableY.setWaveform(shapeY);
waveY.patch(panY).patch(outMix);
mixXY = outMix;
waveReset();
}
private void setWaveTableZ() {
if (useZ) {
tableZ = new XYWavetable(2);
waveZ = new Oscil(freq.z, amp.z, tableZ);
tableZ.setWaveform(shapeZ);
waveZ.patch(outZ); // need pan?? or gets full amp to both channels?
waveReset();
sumXY.unpatch(outXY);
sumXY.patch(outXY);
}
}
/**
* Reset time-step used by XYZ oscillators if they slip when changing
* frequencies.
*
*/
public void waveReset() {
waveX.reset();
waveY.reset();
if (useZ)
waveZ.reset();
}
/**
* Reset time-step used by XYZ oscillators if they slip when changing
* frequencies.
*
*/
public void resetWaves() {
waveReset();
}
/**
* Patch z-axis to custom soundcard by String. Note: Auto z-axis has been
* disabled until solved, until then, one can manually buildZ()
*
* @param zMixer
* Name of custom sound mixer to use for Z.
*/
public void z(String zMixer) {
Mixer mixerZ = getMixerByName(zMixer);
minimZ.setOutputMixer(mixerZ);
outZ = minimZ.getLineOut(Minim.STEREO, waveSizeValOG);
useZ = true;
setWaveTableZ();
}
/**
* Patch z-axis to custom soundcard by String and set custom sample rate
* (44100, 192000). Note: Auto z-axis has been disabled until solved, until
* then, one can manually buildZ()
*
* @param zMixer
* Name of custom sound mixer to use for Z.
*
* @param sampleR
* Sample rate for soundcard (44100, 48000, 192000).
*
*/
public void z(String zMixer, int sampleR) {
Mixer mixerZ = getMixerByName(zMixer);
minimZ.setOutputMixer(mixerZ);
outZ = minimZ.getLineOut(Minim.STEREO, waveSizeValOG, sampleR);
useZ = true;
setWaveTableZ();
}
/**
* Check if z-axis waveform is being automatically drawn from added shapes.
*
* @return boolean
*/
public boolean zAuto() {
return useZ;
}
/**
* Enabled by default for automatic generation of z-axis waveform based on
* added shapes. Disable if creating your own waveform (used for blanking,
* dotted line, etc. Note: Only works if using a second audio output channel
*
* @param zAutoBool
* true/false for generating z waveform
*/
public void zAuto(boolean zAutoBool) {
useZ = zAutoBool;
}
/**
* Get ArrayList of all coordinates used for vector drawing as an ArrayList
* of PVector's.
*
* @return ArrayList of PVector
*/
public ArrayList<PVector> wavePoints() {
return shapes.getPoints();
}
/**
* Get min and max values for z-axis output as two value array.
*
* @return array containing [zaxisMin, zaxisMax]
*/
public float[] zRange() {
float[] zRangeFloat = { zaxisMin, zaxisMax };
return zRangeFloat;
}
/**
* Set min and max values for z-axis output. Necessary for any inverted
* z-axis devices.
* <p>
* default is zMin: 1, zMax: -1
*
* @param zMin
* float between -1 to 1
* @param zMax
* float between -1 to 1
*/
public void zRange(float zMin, float zMax) {
zaxisMin = zMin;
zaxisMax = zMax;
}
/**
* Returns current value for limiting drawing by number of points.
*
* @return limitVal
*/
public float limitPoints(){
return limitPointsVal;
}
/**
* Limit drawing by number of points
*
* @param newLimitPointsVal int for limiting number of points
*/
public void limitPoints(int newLimitPointsVal){
if(newLimitPointsVal == 0){
useLimitPoints = false;
}else{
limitPointsVal = abs(newLimitPointsVal);
useLimitPoints = true;
}
}
/**
* Returns current value for border that limits rendering to edges of screen.
*
* @return limitVal
*/
public float limitPath(){
return limitVal;
}
/**
* Only render points within specified border from the edge
*
* @param newLimitVal float for border limit from edges
*/
public void limitPath(float newLimitVal){
limitVal = newLimitVal;
useLimitPath = true;
}
/**
* Use XYscope on a modded Vectrex monitor for XYZ input. This will automatically adjust the canvas and amplitude settings to match the ratio of the Vectrex.
*
*/
public void vectrex(){
vectrex(vectrexWidth, vectrexHeight, vectrexAmpInit, vectrexRotation);
}
/**
* Use XYscope on a modded Vectrex monitor for XYZ input. This will automatically adjust the canvas and amplitude settings to match the ratio of the Vectrex. You can customize the rotation of the monitor +/- 90° if landscape oriented.
*
* @param vrot
* int for degrees of rotation, 90 or -90
*/
public void vectrex(int vrot){
if(vrot == 90){
vectrexRotation = vrot;
vectrex(vectrexHeight, vectrexWidth, vectrexAmpInit, vectrexRotation);
}else if(vrot == -90){
vectrexRotation = vrot;
vectrex(vectrexHeight, vectrexWidth, vectrexAmpInit, vectrexRotation);
}else {
vectrexRotation = 0;
vectrex(vectrexWidth, vectrexHeight, vectrexAmpInit, vectrexRotation);
}
}
/**
* Use XYscope on a modded Vectrex monitor for XYZ input. Set custom width, height, initial amplitude scaling and rotation/orientation.
*
* @param vw
* int for width of canvas, default is 330
* @param vh
* int for height of canvas, default is 410
* @param vamp
* float for initial amplitude adjustment of signal to screen (0.0 - 1.0), default is .6
* @param vrot
* int for degrees of rotation, 90 or -90, default is 0
*/
public void vectrex(int vw, int vh, float vamp, int vrot){
useVectrex = true;
vectrexRotation = vrot;
myParent.getSurface().setResizable(true);
myParent.getSurface().setSize(vw, vh);
xyWidth = vw;
xyHeight = vh;
vectrexAmpInit = vamp;
amp(vectrexAmpInit);
}
/**
* Get current amplitude difference used for ratio of Vectrex.
*
* @return float
*/
public float vectrexRatio(){
return vectrexAmp;
}
/**
* Set current amplitude difference used for ratio of Vectrex.
*
* @param vectrexAmpVal
* float for amplitude difference (0.0 - 1.0), default is .82
*/
public void vectrexRatio(float vectrexAmpVal){
vectrexAmp = constrain(vectrexAmpVal, 0f, 1f);
amp(vectrexAmpInit);
}
/**
* Activate use of Laser's RGB by assigning 3 additional (2x stereo pairs) audio channels for controlling the RGB modulation.
*
* @param inR
* String for name of audio channel for Red
* @param inBG
* String for name of audio channel for Blue/Green
*/
public void laser(String inR, String inBG){
Mixer mixerR = getMixerByName(inR);
Mixer mixerBG = getMixerByName(inBG);
minimR.setOutputMixer(mixerR);
minimBG.setOutputMixer(mixerBG);
outR = minimR.getLineOut(Minim.STEREO, waveSizeValOG);
outGB = minimBG.getLineOut(Minim.STEREO, waveSizeValOG);
setWaveTableRGB();
useLaser = true;
//LPF
moog = new MoogFilter( laserLPFVal, 0f );
moog.setChannelCount(2);
sumXY.unpatch(outXY);
sumXY.patch(moog).patch(outXY);
}
private void setWaveTableRGB() {
tableR = new XYWavetable(2);
waveR = new Oscil(freq.x, amp.x, tableR);
tableR.setWaveform(shapeR);
waveR.patch(panR).patch(outR);
tableG = new XYWavetable(2);
waveG = new Oscil(freq.x, amp.x, tableG);
tableG.setWaveform(shapeG);
waveG.patch(panG).patch(outGB);
tableB = new XYWavetable(2);
waveB = new Oscil(freq.x, amp.x, tableB);
tableB.setWaveform(shapeB);
waveB.patch(panB).patch(outGB);
}
/**
* Returns current frequency of Laser's low-pass-filter (LPF).
*
* @return float
*/
public float laserLPF(){
return laserLPFVal;
}
/**
* Set new frequency for Laser's low-pass-filter (LPF) as float. Be careful to stay within range that's safe for your Galvos.
*
* @param newLaserLPFVal
* float between 0.1 - 20000.0
*/
public void laserLPF(float newLaserLPFVal){
laserLPFVal = constrain(newLaserLPFVal, .1f, 20000f);
moog.frequency.setLastValue(laserLPFVal);
}
/**
* Returns current value spot-killer (minimum size of drawing for laser).
*
* @return float
*/
public float spotKiller(){
return laserCutoffVal;
}
/**
* Set new value for spotKiller (won't draw if XY shape is smaller than provided value).
*
* @param newLaserCutoffVal
* float
*/
public void spotKiller(float newLaserCutoffVal){
laserCutoffVal = abs(newLaserCutoffVal);
}
/**
* Returns current minimum values set for RGB laser.
*
* @return PVector
*/
public PVector strokeMin(){
return lsMin;
}
/**
* Set new minimum values for RGB laser, as 3 floats.
*
* @param minR
* value between 0.0 - 255.0
* @param minG
* value between 0.0 - 255.0
* @param minB
* value between 0.0 - 255.0
*/
public void strokeMin(float minR, float minG, float minB){
strokeMin(new PVector(minR, minG, minB));
}
/**
* Set new minimum values for RGB laser, as PVector.
*
* @param minPV
* PVector with 3 values between 0.0 - 255.0
*/
public void strokeMin(PVector minPV){
lsMin = new PVector(minPV.x, minPV.y, minPV.z);
}
/**
* Returns current white balance (mixture for white) settings for RGB laser.
*
* @return PVector
*/
public PVector strokeWB(){
return lsWB;
}
/**
* Set white balance (mixture for white) for RGB laser, as 3 floats.
*
* @param wbR
* value between 0.0 - 255.0
* @param wbG
* value between 0.0 - 255.0
* @param wbB
* value between 0.0 - 255.0
*/
public void strokeWB(float wbR, float wbG, float wbB){
strokeWB(new PVector(wbR, wbG, wbB));
}
/**
* Set white balance (mixture for white) for RGB laser, as PVector.
*
* @param wbPV
* PVector with 3 values between 0.0 - 255.0
*/
public void strokeWB(PVector wbPV){
lsWB = new PVector(wbPV.x, wbPV.y, wbPV.z);
}
/**
* Returns current dashes used for RGB waves of laser.
*
* @return PVector
*/
public PVector strokeDash(){
return lsDash;
}
/**
* Set same number of dashes for RGB laser.
*
* @param newDash
* int
*/
public void strokeDash(int newDash){
strokeDash(new PVector(newDash, newDash, newDash));
}
/**
* Set seperate number of dashes per color for RGB laser.
*
* @param newDashR
* int
* @param newDashG
* int
* @param newDashB
* int
*/
public void strokeDash(int newDashR, int newDashG, int newDashB){
strokeDash(new PVector(newDashR, newDashG, newDashB));
}
/**
* Set dashes for RGB laser, as PVector.
*
* @param newDash
* PVector with 3 values
*/
public void strokeDash(PVector newDash){
lsDash = new PVector(newDash.x, newDash.y, newDash.z);
}
/**
* Set stroke for RGB laser, as 3 floats.
*
* @param r
* float from 0.0 – 255.0
* @param g
* float from 0.0 – 255.0
* @param b
* float from 0.0 – 255.0
*/
public void stroke(float r, float g, float b){
stroke(new PVector(r, g, b));
}
/**
* Set stroke for RGB laser, as PVector.
*
* @param newDash
* PVector with 3 values, from 0.0 – 255.0
*/
public void stroke(PVector rgb){
float mr = 0f;
float mg = 0f;
float mb = 0f;
if(rgb.x > 0f)
mr = map(rgb.x, 0f, 255f, (lsMin.x/255f), 1f);
if(rgb.y > 0f)
mg = map(rgb.y, 0f, 255f, (lsMin.y/255f), 1f);
if(rgb.z > 0f)
mb = map(rgb.z, 0f, 255f, (lsMin.z/255f), 1f);
if(rgb.x == 255f && rgb.y == 255f && rgb.z == 255f){
mr = lsWB.x / 255f;
mg = lsWB.y / 255f;
mb = lsWB.z / 255f;
}
RGBshape.add(new PVector(mr, mg, mb));
}
/**
* Get current frequency for R, G, B oscillators for laser as a PVector.
*
* @return PVector
*/
public PVector strokeFreq() {
return lsFreq;
}
/**
* Set new frequency for all RGB oscillators of laser together as single float.
*
* @param newFreq
* float
*/
public void strokeFreq(float newFreq) {
lsFreq = new PVector(newFreq, newFreq, newFreq);
strokeFreq(lsFreq);
}
/**
* Set new frequency for all R + G + B oscillators of laser.
*
* @param newFreqR
* float
* @param newFreqG
* float
* @param newFreqB
* float
*/
public void strokeFreq(float newFreqR, float newFreqG, float newFreqB) {
lsFreq = new PVector(newFreqR, newFreqG, newFreqB);
strokeFreq(lsFreq);
}
/**
* Set new frequency for each RGB oscillator of laser separately using a PVector.
*
* @param newFreq
* PVector
*/
public void strokeFreq(PVector newFreq) {
lsFreq = newFreq;
waveR.setFrequency(lsFreq.x);
waveG.setFrequency(lsFreq.y);
waveB.setFrequency(lsFreq.z);
}
/**
* Get current amplitude setting of XY oscillators.
*
* @return float
*/
public PVector amp() {
return amp;
}
/**
* Set new amplitude for both XYZ oscillators as float.
*
* @param newAmp
* value between 0.0 - 1.0
*/
public void amp(float newAmp) {
amp.x = constrain(newAmp, 0f, 1f);
amp.y = constrain(newAmp, 0f, 1f);
if(useVectrex){
amp.x *= vectrexAmp;
}
waveX.setAmplitude(amp.x);
waveY.setAmplitude(amp.y);
if (useZ) {
amp.z = constrain(newAmp, 0f, 1f);
waveZ.setAmplitude(amp.z);
}
}
/**
* Set new amplitude for both X + Y oscillators as float.
*
* @param newAmpX
* value between 0.0 - 1.0
* @param newAmpY
* value between 0.0 - 1.0
*/
public void amp(float newAmpX, float newAmpY) {
amp.x = constrain(newAmpX, 0f, 1f);
if(useVectrex)
amp.x *= vectrexAmp;
amp.y = constrain(newAmpY, 0f, 1f);
waveX.setAmplitude(amp.x);
waveY.setAmplitude(amp.y);
}
/**
* Set new amplitude for both X + Y + Z oscillators as float.
*
* @param newAmpX
* value between 0.0 - 1.0
* @param newAmpY
* value between 0.0 - 1.0
* @param newAmpZ
* value between 0.0 - 1.0
*/
public void amp(float newAmpX, float newAmpY, float newAmpZ) {
amp.x = constrain(newAmpX, 0f, 1f);
if(useVectrex)
amp.x *= vectrexAmp;
amp.y = constrain(newAmpY, 0f, 1f);
waveX.setAmplitude(amp.x);
waveY.setAmplitude(amp.y);
if (useZ) {
amp.z = constrain(newAmpZ, 0f, 1f);
waveZ.setAmplitude(amp.z);
}
}
/**
* Set new amplitude for each XYZ oscillator separately using a PVector for
* the values.
*
* @param newAmp
* PVector of values between 0.0 - 1.0
*/
public void amp(PVector newAmp) {
float tempX = constrain(newAmp.x, 0f, 1f);
if(useVectrex)
tempX *= vectrexAmp;
float tempY = constrain(newAmp.y, 0f, 1f);
waveX.setAmplitude(tempX);
waveY.setAmplitude(tempY);
if (useZ) {
float tempZ = constrain(newAmp.z, 0f, 1f);
waveZ.setAmplitude(tempZ);
}
}
/**
* Get current frequency for X, Y, Z oscillators as a PVector.
*
* @return PVector
*/
public PVector freq() {
return freq;
}
/**
* Set new frequency for all XYZ oscillators together as single float.
*
* @param newFreq
* float
*/
public void freq(float newFreq) {
freq = new PVector(newFreq, newFreq, newFreq);
waveX.setFrequency(freq.x);
waveY.setFrequency(freq.y);
if (useZ)
waveZ.setFrequency(freq.z);
}
/**
* Set new frequency for all X + Y oscillators.
*
* @param newFreqX
* float
* @param newFreqY
* float
*/
public void freq(float newFreqX, float newFreqY) {
freq.x = newFreqX;
freq.y = newFreqY;
waveX.setFrequency(freq.x);
waveY.setFrequency(freq.y);
}
/**
* Set new frequency for all X + Y + Z oscillators.
*
* @param newFreqX
* float
* @param newFreqY
* float
* @param newFreqZ
* float
*/
public void freq(float newFreqX, float newFreqY, float newFreqZ) {
freq.x = newFreqX;
freq.y = newFreqY;
waveX.setFrequency(freq.x);
waveY.setFrequency(freq.y);
if (useZ) {
freq.z = newFreqZ;
waveZ.setFrequency(freq.z);
}
}
/**
* Set new frequency for each XYZ oscillator separately using a PVector for
* the values.
*
* @param newFreq
* PVector
*/
public void freq(PVector newFreq) {
freq = newFreq;
waveX.setFrequency(freq.x);
waveY.setFrequency(freq.y);
if (useZ)
waveZ.setFrequency(freq.z);
}
/**
* Adjust the (x, y) panning, mainly useful if swapping cables digitally. Default (-1.0, 1.0)
*
* @param panXVal
* float - pan for x/left channel
* @param panYVal
* float - pan for y/right channel */
public void pan(float panXVal, float panYVal) {
panX.setPan(panXVal);
panY.setPan(panYVal);
}
/**
* Enable/Disable easing transitions from one set of buildWaves() to the
* next. Default is false. Deprecated in v2.0+
*
* @param easeBool
* true/false
*/
public void ease(boolean easeBool) {
useEase = easeBool;
}
/**
* Check if easing between each frame of buildWaves() is enabled.
* Deprecated in v2.0+
*
* @return boolean
*/
public boolean ease() {
return useEase;
}
/**
* Returns current easeAmount, 0.0 - 1.0. Deprecated in v2.0+
*
* @return float
*/
public float easeAmount() {
return easeVal;
}
/**
* Set new easing value for speed between buildWave() transitions. Deprecated in v2.0+
*
* @param newEaseValue
* float between 0.0 - 1.0
*/
public void easeAmount(float newEaseValue) {
easeVal = newEaseValue;
}
/**
* Enable/Disable debug view for comparing waveform to shape.
*
* @param debugBool
* true/false
*/
public void debugView(boolean debugBool) {
debugWave = debugBool;
}
/**
* Check if debugView is active.
*
* @return boolean
*/
public boolean debugView() {
return debugWave;
}
/**
* Get size of wavetables. By default, it's the same as the
* outXY.bufferSize()
*
* @return newSize
* int
*/
public int waveSize() {
return waveSizeVal;
}
/**
* Set custom size for wavetables. By default, it's the same as the
* outXY.bufferSize()
*
* @param newSize
* int
*/
public void waveSize(int newSize) {
waveSizeVal = newSize;
shapeY = new float[waveSizeVal];
shapeX = new float[waveSizeVal];
// shapeZ = new float[waveSizeVal];
shapePreY = new float[waveSizeVal];
shapePreX = new float[waveSizeVal];
// shapePreZ = new float[waveSizeVal];
tableX.setWaveform(shapeX);
tableY.setWaveform(shapeY);
// if (useZ)
// tableZ.setWaveform(shapeZ);
}
/**
* Clears the waveforms from previous buildWaves(). Useful to call at top of
* draw(), similar to using background() to clear the slate before building
* the waveforms at the bottom of your draw with buildWaves().
*/
public void clearWaves() {
if(!busy){
for (int i = 0; i < shapeX.length; i++) {
shapePreX[i] = 0;
shapePreY[i] = 0;
}
if (useZ) {
for (int i = 0; i < shapeZ.length; i++) {
shapePreZ[i] = zaxisMin;
}
}
shapes = new XYShapeList();
currentShape = null;
if(useLaser)
RGBshape = new XYShape();
}
}
private double lerp(double start, double end, double amt) {
return start + (end-start)*amt;
}
public void buildWavesTest(ArrayList<PVector> wc) {
if(wc.size() > 128) {
waveSize(floor((wc.size())/2)*2);
}
// waveSize(1024);
float[] mfx = new float[wc.size()];
float[] mfy = new float[wc.size()];
for(int i=0; i<wc.size();i++) {
PVector tc = wc.get(i);
mfx[i] = map(tc.x, 0f, 1f, -1f, 1f);
mfy[i] = map(tc.y, 0f, 1f, 1f, -1f);
}
tableX.setWaveform(mfx);
tableY.setWaveform(mfy);
}
/**
* Generate the XY oscillator waveforms from all added shapes for sending
* audio to vector display. Call this after drawing any primitive shapes.
* New Rendering mode in place, if old dots style is preferred, use
* buildWaves(-1).
*
* @param bwm int for buildWaves mode
*/
public void buildWaves(int bwm) {
if(bwm == 0) { // waveform gen v4 mar 2020... 23
if (shapes.size() > 0) {
double wave_size = shapes.getPoints().size()*stepsSize;
double total_dist = shapes.getDistance();
double tot = 0.0;
ArrayList<PVector> wave_col = new ArrayList<PVector>();
for (int i=0; i < shapes.size(); i++) {
double shapeDist = shapes.get(i).getDistance();
ArrayList<PVector> pv = shapes.get(i);
for (int j=0; j < pv.size()-1; j++) { // what about point?
PVector p1 = pv.get(j);
PVector p2 = pv.get(j+1);
double line_dist = dist(p1.x, p1.y, p2.x, p2.y);
tot += line_dist;
double sec_per = Math.round(1+line_dist / total_dist * wave_size);
double steps = 1.0 / sec_per;
for (int k=0; k <= sec_per; k++) {
PVector seg = PVector.lerp(p1, p2, (float)((float)k*steps));
wave_col.add(seg);
}
}
}
float[] mfx = new float[waveSize()];
float[] mfy = new float[waveSize()];
float[] mfz = new float[waveSize()];
for(int i=0; i<waveSize();i++) {
int waveIndex = floor(map(i, 0, waveSize(), 0, wave_col.size()));
PVector tc = wave_col.get(waveIndex);
mfx[i] = tc.x * 2f - 1f;
mfy[i] = tc.y * -2f + 1f;
mfz[i] = zaxisMax;
// *** double check if z works w/ shape on.off..
if(tc.z == 1f)
mfz[i] = zaxisMin;
// *** test vectrex
float tfxx = mfx[i];
float tfyy = mfy[i];
if(useVectrex){
if(vectrexRotation == 90){
mfx[i] = tfyy;
mfy[i] = tfxx*-1;
}else if(vectrexRotation == -90){
mfx[i] = tfyy*-1;
mfy[i] = tfxx;
}else if(vectrexRotation == 0){
mfx[i] = tfxx*-1;
mfy[i] = tfyy*-1;
}
}
}
setWaveforms(mfx, mfy, mfz);
if(useLaser){
buildLaser();
}
}else {
emptyWave();
}
} else if(bwm == -3){ // waveform gen v3 sep 2018
if (shapes.size() > 0) {
XYWavetable mx = new XYWavetable(2);
XYWavetable my = new XYWavetable(2);
XYWavetable mz = new XYWavetable(2);
float[] mfx = new float[0];
float[] mfy = new float[0];
float[] mfz = new float[0];
for (XYShape shape : shapes) {
XYWavetable tx = new XYWavetable(2);
XYWavetable ty = new XYWavetable(2);
XYWavetable tz = new XYWavetable(2);
float[] tfx = new float[shape.size()];
float[] tfy = new float[shape.size()];
float[] tfz = new float[shape.size()];
for (int i = 0; i < shape.size(); i++) {
if(i < tfx.length){
PVector tc = shape.get(i);
tfx[i] = map(tc.x, 0f, 1f, -1f, 1f);
tfy[i] = map(tc.y, 0f, 1f, 1f, -1f);
tfz[i] = zaxisMin;
if(tc.z == 1f)
tfz[i] = zaxisMax;
float tfxx = tfx[i];
float tfyy = tfy[i];
if(useVectrex){
if(vectrexRotation == 90){
tfx[i] = tfyy;
tfy[i] = tfxx*-1;
}else if(vectrexRotation == -90){
tfx[i] = tfyy*-1;
tfy[i] = tfxx;
}else if(vectrexRotation == 0){
tfx[i] = tfxx*-1;
tfy[i] = tfyy*-1;
}
}
}
}
tx.setWaveform(tfx);
ty.setWaveform(tfy);
tz.setWaveform(tfz);
mfx = concat(mfx, tx.getWaveform());
mfy = concat(mfy, ty.getWaveform());
mfz = concat(mfz, tz.getWaveform());
}
setWaveforms(mfx, mfy, mfz);
if(useLaser){
buildLaser();
}
}else{
emptyWave();
}
} else if (bwm == -2) { // waveform gen v2 may 2018
if (shapes.size() > 0) {
if (shapes.totalSize() < waveSizeValOG) {
if (waveSize() != shapes.totalSize()) {
waveSize(shapes.totalSize());
}
int SID = 0;
if (waveSize() == shapes.totalSize()) {
for (XYShape shape : shapes) {
for (int i = 0; i < shape.size(); i++) {
shapePreX[SID] = map(shape.get(i).x, 0f, 1f, -1f, 1f);
shapePreY[SID] = map(shape.get(i).y, 0f, 1f, 1f, -1f);
SID++;
}
}
}
} else {
if (waveSize() != waveSizeValOG)
waveSize(waveSizeValOG);
ArrayList<PVector> ts = shapes.getPoints();
for (int i = 0; i < shapeX.length; i++) {
int ptsSel = (int) Math.floor(map(i, 0f, shapeX.length, 0, ts.size()));
shapePreX[i] = map(ts.get(ptsSel).x, 0f, 1f, -1f, 1f);
shapePreY[i] = map(ts.get(ptsSel).y, 0f, 1f, 1f, -1f);
}
}
} else {
waveSize(1);
shapePreX[0] = 0f;
shapePreY[0] = 0f;
}
} else if (bwm == -1) { // waveform gen v1 jul 2017
if (waveSize() != waveSizeValOG)
waveSize(waveSizeValOG);
if (shapes.size() > 0) {
ArrayList<PVector> ts = shapes.getPoints();
for (int i = 0; i < shapeX.length; i++) {
int ptsSel = (int) Math.floor(map(i, 0f, shapeX.length, 0, ts.size()));
shapePreX[i] = map(ts.get(ptsSel).x, 0f, 1f, -1f, 1f);
shapePreY[i] = map(ts.get(ptsSel).y, 0f, 1f, 1f, -1f);
}
}
}
if(bwm == -1 || bwm == -2){
// easing
if (useEase) {
easeWaves();
} else {
for (int i = 0; i < shapePreX.length; i++) {
shapeX[i] = shapePreX[i];
shapeY[i] = shapePreY[i];
if(useVectrex){
if(vectrexRotation == 90){
shapeX[i] = shapePreY[i];
shapeY[i] = shapePreX[i]*-1;
}else if(vectrexRotation == -90){
shapeX[i] = shapePreY[i]*-1;
shapeY[i] = shapePreX[i];
}else if(vectrexRotation == 0){
shapeX[i] = shapePreX[i]*-1;
shapeY[i] = shapePreY[i]*-1;
}
}
if (useZ)
shapeZ[i] = shapePreZ[i];
}
if (useZ) {
for (int i = 0; i < shapePreZ.length; i++) {
shapeZ[i] = shapePreZ[i];
}
}
}
// smooth
if (useSmooth) {
tableX.smooth(smoothVal);
tableY.smooth(smoothVal);
}
}
}
public void setWaveforms(float[] mfx, float[] mfy) {
float[] mfz = new float[0];
setWaveforms(mfx, mfy, mfz);
}
public void setWaveforms(float[] mfx, float[] mfy, float[] mfz) {
// limit points
if(useLimitPoints && (mfx.length > limitPointsVal || mfy.length > limitPointsVal)){
float[] lx = new float[limitPointsVal];
float[] ly = new float[limitPointsVal];
float[] lz = new float[limitPointsVal];
for(int i=0; i < limitPointsVal; i++){
int mfxSel = floor(map(i, 0, limitPointsVal, 0, mfx.length));
int mfySel = floor(map(i, 0, limitPointsVal, 0, mfy.length));
int mfzSel = floor(map(i, 0, limitPointsVal, 0, mfz.length));
lx[i] = mfx[mfxSel];
ly[i] = mfy[mfySel];
lz[i] = mfz[mfzSel];
}
tableX.setWaveform(lx);
tableY.setWaveform(ly);
if(useZ)
tableZ.setWaveform(lz);
}else{
tableX.setWaveform(mfx);
tableY.setWaveform(mfy);
if(useZ)
tableZ.setWaveform(mfz);
}
}
private void emptyWave() {
tableX.setWaveform(new float[0]);
tableY.setWaveform(new float[0]);
if(useZ)
tableZ.setWaveform(new float[0]);
if(useLaser){
tableR.setWaveform(new float[0]);
tableG.setWaveform(new float[0]);
tableB.setWaveform(new float[0]);
}
}
// *** remove??
public void warpWave(int mx, int pmx) {
float warpPoint = constrain( (float)pmx / myParent.width, 0, 1 );
float warpTarget = constrain( (float)mx / myParent.width, 0, 1 );
tableX.warp( warpPoint, warpTarget );
tableY.warp( warpPoint, warpTarget );
}
private void buildLaser() {
// spotkiller checkSize
boolean checkSize = false;
AudioOutput tempXY = outXY;
for (int i = 0; i < tempXY.bufferSize() - 1; i++) {
float lAudio = abs(tempXY.left.get(i) * (float) xyWidth / 2);
float rAudio = abs(tempXY.right.get(i) * (float) xyHeight / 2);
if(lAudio > laserCutoffVal || rAudio > laserCutoffVal)
checkSize = true;
}
if(checkSize){
if(RGBshape.size() > 0){
buildColorWave(tableR, "
gitextract_zbh9fj9i/
├── .gitignore
├── README.md
├── changelog.txt
├── examples/
│ ├── 1_getting_started/
│ │ ├── basic_drawing/
│ │ │ └── basic_drawing.pde
│ │ ├── calibration/
│ │ │ └── calibration.pde
│ │ ├── clock/
│ │ │ └── clock.pde
│ │ ├── custom_soundcard/
│ │ │ └── custom_soundcard.pde
│ │ ├── lissapong/
│ │ │ └── lissapong.pde
│ │ └── template/
│ │ └── template.pde
│ ├── 2_shapes/
│ │ ├── a_walkthrough_primatives/
│ │ │ └── a_walkthrough_primatives.pde
│ │ ├── additive_synth_shapes/
│ │ │ └── additive_synth_shapes.pde
│ │ ├── lissajous/
│ │ │ └── lissajous.pde
│ │ ├── paramless_shapes/
│ │ │ └── paramless_shapes.pde
│ │ ├── sphere/
│ │ │ └── sphere.pde
│ │ └── torus/
│ │ └── torus.pde
│ ├── 3_typography/
│ │ ├── hershey_fonts/
│ │ │ └── hershey_fonts.pde
│ │ └── scopewriter/
│ │ └── scopewriter.pde
│ ├── 4_inputs/
│ │ ├── fonts/
│ │ │ └── fonts.pde
│ │ ├── kinect/
│ │ │ └── kinect.pde
│ │ ├── obj/
│ │ │ └── obj.pde
│ │ ├── svg/
│ │ │ └── svg.pde
│ │ ├── syphon/
│ │ │ └── syphon.pde
│ │ ├── video/
│ │ │ └── video.pde
│ │ ├── webcam/
│ │ │ └── webcam.pde
│ │ └── webcam_processing4/
│ │ └── webcam_processing4.pde
│ ├── 5_displays/
│ │ ├── laser/
│ │ │ └── laser.pde
│ │ └── vectrex/
│ │ └── vectrex.pde
│ ├── 6_outputs/
│ │ ├── audio_recorder/
│ │ │ └── audio_recorder.pde
│ │ └── osc_wavetables/
│ │ └── osc_wavetables.pde
│ ├── 7_custom_waves/
│ │ ├── customWaves_drawingXYZ/
│ │ │ └── customWaves_drawingXYZ.pde
│ │ ├── customWaves_noiseXY/
│ │ │ └── customWaves_noiseXY.pde
│ │ └── setWaveforms_noise/
│ │ └── setWaveforms_noise.pde
│ ├── 8_music/
│ │ ├── MidiScope/
│ │ │ └── MidiScope.pde
│ │ ├── audio_filters/
│ │ │ └── audio_filters.pde
│ │ └── freq_keyboard_notes/
│ │ └── freq_keyboard_notes.pde
│ └── 9_misc/
│ ├── freq_amp_modulation/
│ │ └── freq_amp_modulation.pde
│ └── multiscopes_class/
│ └── multiscopes_class.pde
├── license.txt
├── resources/
│ ├── README.md
│ ├── build.properties
│ ├── build.xml
│ ├── code/
│ │ ├── ExampleTaglet.java
│ │ ├── ant-contrib-1.0b3.jar
│ │ └── doc.sh
│ ├── library.properties
│ └── stylesheet.css
├── src/
│ └── xyscope/
│ ├── XYWavetable.java
│ └── XYscope.java
└── web/
├── includes/
│ ├── css/
│ │ └── styles.css
│ └── js/
│ ├── highlight/
│ │ ├── a11y-dark.css
│ │ ├── a11y-light.css
│ │ ├── docco.css
│ │ ├── github.css
│ │ └── highlight.pack.js
│ ├── render.js
│ └── stmd.js
└── index.html
SYMBOL INDEX (277 symbols across 6 files)
FILE: resources/code/ExampleTaglet.java
class ExampleTaglet (line 59) | public class ExampleTaglet implements Taglet {
method getName (line 67) | public String getName() {
method inField (line 78) | public boolean inField() {
method inConstructor (line 89) | public boolean inConstructor() {
method inMethod (line 100) | public boolean inMethod() {
method inOverview (line 111) | public boolean inOverview() {
method inPackage (line 122) | public boolean inPackage() {
method inType (line 133) | public boolean inType() {
method isInlineTag (line 144) | public boolean isInlineTag() {
method register (line 152) | public static void register(Map tagletMap) {
method toString (line 166) | public String toString(Tag tag) {
method toString (line 176) | public String toString(Tag[] tags) {
method createHTML (line 185) | String createHTML(String theString) {
method readFile (line 207) | String readFile(String theExample) {
FILE: src/xyscope/XYWavetable.java
class XYWavetable (line 28) | public class XYWavetable implements Waveform
method XYWavetable (line 41) | public XYWavetable(int size)
method XYWavetable (line 56) | public XYWavetable(float[] waveform)
method XYWavetable (line 71) | public XYWavetable(XYWavetable wavetable)
method setWaveform (line 87) | public void setWaveform(float[] waveform)
method get (line 106) | public float get(int i)
method value (line 129) | public float value(float at)
method getWaveform (line 152) | public float[] getWaveform()
method set (line 170) | public void set(int i, float value)
method size (line 184) | public int size()
method scale (line 197) | public void scale(float scale)
method offset (line 214) | public void offset(float amount)
method normalize (line 232) | public void normalize()
method invert (line 250) | public void invert()
method flip (line 270) | public void flip(float in)
method addNoise (line 292) | public void addNoise(float sigma)
method rectify (line 308) | public void rectify()
method smooth (line 327) | public void smooth(int windowLength)
method warp (line 373) | public void warp(float warpPoint, float warpTarget)
FILE: src/xyscope/XYscope.java
class XYscope (line 23) | public class XYscope {
method XYscope (line 164) | public XYscope(PApplet theParent) {
method XYscope (line 179) | public XYscope(PApplet theParent, AudioOutput outMix) {
method XYscope (line 195) | public XYscope(PApplet theParent, String xyMixer) {
method XYscope (line 213) | public XYscope(PApplet theParent, int sampleR) {
method XYscope (line 232) | public XYscope(PApplet theParent, String xyMixer, int sampleR) {
method XYscope (line 255) | public XYscope(PApplet theParent, String xyMixer, int sampleRateVal, i...
method welcome (line 266) | private void welcome() {
method initText (line 273) | private void initText() {
method getMixerInfo (line 280) | public void getMixerInfo() {
method getMixerByName (line 287) | private static Mixer getMixerByName(String toFind) {
method initMinim (line 296) | private void initMinim() {
method setMixer (line 305) | private void setMixer(String xyMixer) {
method setOutput (line 311) | private void setOutput() {
method sampleRate (line 316) | public int sampleRate() {
method sampleRate (line 320) | public void sampleRate(int sampleRateVal) {
method bufferSize (line 325) | public int bufferSize() {
method bufferSize (line 329) | public void bufferSize(int bufferSizeVal) {
method setWaveTable (line 336) | private void setWaveTable() {
method setWaveTable (line 355) | private void setWaveTable(AudioOutput outMix) {
method setWaveTableZ (line 371) | private void setWaveTableZ() {
method waveReset (line 389) | public void waveReset() {
method resetWaves (line 401) | public void resetWaves() {
method z (line 412) | public void z(String zMixer) {
method z (line 432) | public void z(String zMixer, int sampleR) {
method zAuto (line 445) | public boolean zAuto() {
method zAuto (line 457) | public void zAuto(boolean zAutoBool) {
method wavePoints (line 467) | public ArrayList<PVector> wavePoints() {
method zRange (line 476) | public float[] zRange() {
method zRange (line 492) | public void zRange(float zMin, float zMax) {
method limitPoints (line 502) | public float limitPoints(){
method limitPoints (line 511) | public void limitPoints(int newLimitPointsVal){
method limitPath (line 526) | public float limitPath(){
method limitPath (line 535) | public void limitPath(float newLimitVal){
method vectrex (line 544) | public void vectrex(){
method vectrex (line 554) | public void vectrex(int vrot){
method vectrex (line 579) | public void vectrex(int vw, int vh, float vamp, int vrot){
method vectrexRatio (line 596) | public float vectrexRatio(){
method vectrexRatio (line 607) | public void vectrexRatio(float vectrexAmpVal){
method laser (line 620) | public void laser(String inR, String inBG){
method setWaveTableRGB (line 637) | private void setWaveTableRGB() {
method laserLPF (line 659) | public float laserLPF(){
method laserLPF (line 669) | public void laserLPF(float newLaserLPFVal){
method spotKiller (line 679) | public float spotKiller(){
method spotKiller (line 689) | public void spotKiller(float newLaserCutoffVal){
method strokeMin (line 698) | public PVector strokeMin(){
method strokeMin (line 712) | public void strokeMin(float minR, float minG, float minB){
method strokeMin (line 722) | public void strokeMin(PVector minPV){
method strokeWB (line 731) | public PVector strokeWB(){
method strokeWB (line 745) | public void strokeWB(float wbR, float wbG, float wbB){
method strokeWB (line 755) | public void strokeWB(PVector wbPV){
method strokeDash (line 764) | public PVector strokeDash(){
method strokeDash (line 774) | public void strokeDash(int newDash){
method strokeDash (line 788) | public void strokeDash(int newDashR, int newDashG, int newDashB){
method strokeDash (line 798) | public void strokeDash(PVector newDash){
method stroke (line 812) | public void stroke(float r, float g, float b){
method stroke (line 822) | public void stroke(PVector rgb){
method strokeFreq (line 846) | public PVector strokeFreq() {
method strokeFreq (line 856) | public void strokeFreq(float newFreq) {
method strokeFreq (line 871) | public void strokeFreq(float newFreqR, float newFreqG, float newFreqB) {
method strokeFreq (line 882) | public void strokeFreq(PVector newFreq) {
method amp (line 894) | public PVector amp() {
method amp (line 904) | public void amp(float newAmp) {
method amp (line 927) | public void amp(float newAmpX, float newAmpY) {
method amp (line 946) | public void amp(float newAmpX, float newAmpY, float newAmpZ) {
method amp (line 966) | public void amp(PVector newAmp) {
method freq (line 984) | public PVector freq() {
method freq (line 994) | public void freq(float newFreq) {
method freq (line 1010) | public void freq(float newFreqX, float newFreqY) {
method freq (line 1027) | public void freq(float newFreqX, float newFreqY, float newFreqZ) {
method freq (line 1045) | public void freq(PVector newFreq) {
method pan (line 1060) | public void pan(float panXVal, float panYVal) {
method ease (line 1072) | public void ease(boolean easeBool) {
method ease (line 1082) | public boolean ease() {
method easeAmount (line 1091) | public float easeAmount() {
method easeAmount (line 1101) | public void easeAmount(float newEaseValue) {
method debugView (line 1111) | public void debugView(boolean debugBool) {
method debugView (line 1120) | public boolean debugView() {
method waveSize (line 1131) | public int waveSize() {
method waveSize (line 1142) | public void waveSize(int newSize) {
method clearWaves (line 1161) | public void clearWaves() {
method lerp (line 1183) | private double lerp(double start, double end, double amt) {
method buildWavesTest (line 1187) | public void buildWavesTest(ArrayList<PVector> wc) {
method buildWaves (line 1211) | public void buildWaves(int bwm) {
method setWaveforms (line 1426) | public void setWaveforms(float[] mfx, float[] mfy) {
method setWaveforms (line 1431) | public void setWaveforms(float[] mfx, float[] mfy, float[] mfz) {
method emptyWave (line 1457) | private void emptyWave() {
method warpWave (line 1471) | public void warpWave(int mx, int pmx) {
method buildLaser (line 1478) | private void buildLaser() {
method buildColorWave (line 1509) | private void buildColorWave(XYWavetable tableTemp, String RGBval, int ...
method buildWaves (line 1540) | public void buildWaves() {
method buildX (line 1554) | public void buildX(float[] newWave) {
method buildY (line 1577) | public void buildY(float[] newWave) {
method buildZ (line 1600) | public void buildZ(float[] newWave) {
method easeWaves (line 1615) | private void easeWaves(float[] sShape, float[] tShape) {
method easeWaves (line 1623) | private void easeWaves() {
method smoothWaves (line 1638) | public boolean smoothWaves() {
method smoothWaves (line 1649) | public void smoothWaves(boolean smoothWavesBool) {
method smoothWavesAmount (line 1662) | public int smoothWavesAmount() {
method smoothWavesAmount (line 1675) | public void smoothWavesAmount(int swAmount) {
method drawAll (line 1689) | public void drawAll() {
method drawPath (line 1697) | public void drawPath() {
method drawPath (line 1705) | public void drawPath(float r, float g, float b) {
method drawPoints (line 1723) | public void drawPoints() {
method drawPoints (line 1731) | public void drawPoints(float r, float g, float b) {
method drawXY (line 1748) | public void drawXY() {
method drawXY (line 1755) | public void drawXY(float r, float g, float b) {
method drawWaveform (line 1806) | public void drawWaveform(){
method drawWaveform (line 1818) | public void drawWaveform(float lr, float lg, float lb, float rr, float...
method drawRGB (line 1881) | public void drawRGB(){
method drawWave (line 1922) | public void drawWave() {
method ellipseDetail (line 1975) | public int ellipseDetail() {
method ellipseDetail (line 1985) | public void ellipseDetail(int newED) {
method ellipseDetail (line 1995) | public void ellipseDetail(float newED) {
method rectMode (line 2007) | public void rectMode(int rectModeVal) {
method steps (line 2021) | public int steps() {
method steps (line 2031) | public void steps(float newSteps) {
method point (line 2036) | public void point() {
method point (line 2049) | public void point(float x, float y) {
method point (line 2063) | public void point(float x, float y, float z) {
method line (line 2068) | public void line() {
method line (line 2086) | public void line(float x1, float y1, float x2, float y2) {
method line (line 2106) | public void line(float x1, float y1, float z1, float x2, float y2, flo...
method square (line 2114) | public void square() {
method square (line 2135) | public void square(float x, float y, float e) {
method rect (line 2144) | public void rect() {
method rect (line 2165) | public void rect(float x, float y, float w) {
method rect (line 2184) | public void rect(float x, float y, float w, float h) {
method vertexRect (line 2192) | private void vertexRect(float x1, float y1, float w1, float h1) {
method circle (line 2205) | public void circle() {
method ellipse (line 2209) | public void ellipse() {
method circle (line 2223) | public void circle(float x, float y, float e) {
method ellipse (line 2237) | public void ellipse(float x, float y, float d) {
method ellipse (line 2252) | public void ellipse(float x, float y, float w, float h) {
method vertexEllipse (line 2259) | private void vertexEllipse(float cx, float cy, float rx, float ry) {
method lissajous (line 2282) | public void lissajous(){
method lissajous (line 2298) | public void lissajous(float xPos, float yPos, float radius, float rati...
method box (line 2310) | public void box() {
method box (line 2323) | public void box(float size) {
method box (line 2337) | public void box(float rx, float ryz) {
method box (line 2353) | public void box(float rxt, float ryt, float rzt) {
method sphere (line 2402) | public void sphere() {
method ellipsoid (line 2406) | public void ellipsoid() {
method sphere (line 2419) | public void sphere(float rs) {
method sphere (line 2433) | public void sphere(float rs, int dxy) {
method sphere (line 2448) | public void sphere(float rs, int dx, int dy) {
method ellipsoid (line 2463) | public void ellipsoid(float rx, float ry, float rz) {
method ellipsoid (line 2479) | public void ellipsoid(float rx, float ry, float rz, int dxy) {
method ellipsoid (line 2496) | public void ellipsoid(float rxt, float ryt, float rzt, int dx, int dy) {
method torus (line 2563) | public void torus() {
method torus (line 2567) | public void torus(float radius, float tubeRadius) {
method torus (line 2571) | public void torus(float radius, float tubeRadius, int dxy) {
method torus (line 2586) | public void torus(float radius, float tubeRadius, int dx, int dy) {
method beginShape (line 2631) | public void beginShape() {
method vertex (line 2636) | public void vertex() {
method curveVertex (line 2640) | public void curveVertex() {
method curveVertex (line 2655) | public void curveVertex(float x, float y) {
method curveVertex (line 2671) | public void curveVertex(float x, float y, float z) {
method vertex (line 2684) | public void vertex(float x, float y) {
method vertex (line 2698) | public void vertex(float x, float y, float z) {
method vertex (line 2710) | public void vertex(PVector p) {
method vertex (line 2718) | private void vertex(PVector p, boolean mode3D) {
method vertexAdd (line 2722) | private void vertexAdd(PVector p, boolean mode3D) {
method endShape (line 2760) | public void endShape(int close) {
method endShape (line 2786) | public void endShape() {
method recorderBegin (line 2802) | public void recorderBegin() {
method recorderBegin (line 2806) | public void recorderBegin(String filename) {
method recorderEnd (line 2813) | public void recorderEnd() {
method contains (line 2827) | private boolean contains(String[] arr, String val) {
method textFont (line 2842) | public void textFont(String fontName) {
method textSize (line 2866) | public float textSize(){
method textSize (line 2876) | public void textSize(float fontSize){
method textLeading (line 2885) | public float textLeading(){
method textLeading (line 2895) | public void textLeading(float leading){
method textAlign (line 2905) | public void textAlign(int taX) {
method textAlign (line 2917) | public void textAlign(int taX, int taY) {
method text (line 2927) | public void text() {
method text (line 2931) | public void text(float s, float x, float y) {
method text (line 2934) | public void text(int s, float x, float y) {
method text (line 2949) | public void text(String s, float x, float y) {
method textParse (line 2974) | public void textParse(String s, float x, float y) {
method textWidth (line 3015) | public float textWidth(int c) {
method textWidth (line 3035) | public float textWidth(String s) {
method textWidthParse (line 3048) | float textWidthParse(String s) {
method textPaths (line 3076) | public PVector[][] textPaths(String s, float x, float y) {
method textPathsParse (line 3110) | void textPathsParse(String s, float x, float y, ArrayList<ArrayList<PV...
method draw_character (line 3153) | private void draw_character(int c) {
method hershey2coord (line 3177) | private int hershey2coord(char c) {
class XYShapeList (line 3183) | public class XYShapeList extends ArrayList<XYShape> {
method getDistance (line 3191) | public double getDistance() {
method totalSize (line 3205) | public int totalSize() {
method getPoints (line 3221) | public ArrayList<PVector> getPoints() {
class XYShape (line 3232) | public class XYShape extends ArrayList<PVector> {
method getDistance (line 3234) | public double getDistance() {
FILE: web/includes/js/highlight/highlight.pack.js
function e (line 6) | function e(n){Object.freeze(n);var t="function"==typeof n;return Object....
function n (line 6) | function n(e){return e.replace(/&/g,"&").replace(/</g,"<").replac...
function t (line 6) | function t(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n...
function r (line 6) | function r(e){return e.nodeName.toLowerCase()}
function l (line 6) | function l(){return e.length&&t.length?e[0].offset!==t[0].offset?e[0].of...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){let n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){e.children&&(e.children.every(e=>"string"==typeof ...
function c (line 6) | function c(e){s+="<"+r(e)+[].map.call(e.attributes,(function(e){return" ...
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){let t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new o(this,this.options).value()}
method finalize (line 6) | finalize(){}
function u (line 6) | function u(e){s+="</"+r(e)+">"}
function d (line 6) | function d(e){("start"===e.event?c:u)(e.node)}
class o (line 6) | class o{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e...
method constructor (line 6) | constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(...
method addText (line 6) | addText(e){this.buffer+=n(e)}
method openNode (line 6) | openNode(e){if(!s(e))return;let n=e.kind;e.sublanguage||(n=`${this.cla...
method closeNode (line 6) | closeNode(e){s(e)&&(this.buffer+=i)}
method span (line 6) | span(e){this.buffer+=`<span class="${e}">`}
method value (line 6) | value(){return this.buffer}
class l (line 6) | class l{constructor(){this.rootNode={children:[]},this.stack=[this.rootN...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){let n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){e.children&&(e.children.every(e=>"string"==typeof ...
class c (line 6) | class c extends l{constructor(e){super(),this.options=e}addKeyword(e,n){...
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){let t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new o(this,this.options).value()}
method finalize (line 6) | finalize(){}
function u (line 6) | function u(e){return e&&e.source||e}
function R (line 6) | function R(e,n){return n?+n:(t=e,E.includes(t.toLowerCase())?0:1);var t}
function h (line 6) | function h(e){return g.noHighlightRe.test(e)}
function f (line 6) | function f(e,n,t,r){var a={code:n,language:e};T("before:highlight",a);va...
function p (line 6) | function p(e,n,r,i){var s=n;function l(e,n){var t=v.case_insensitive?n[0...
function m (line 6) | function m(e,n){n=n||g.languages||Object.keys(a);var t=function(e){const...
function b (line 6) | function b(e){return g.tabReplace||g.useBR?e.replace(l,(function(e,n){re...
function v (line 6) | function v(e){var n,t,r,a,s,o=function(e){var n,t=e.className+" ";if(t+=...
function x (line 6) | function x(){if(!x.called){x.called=!0;var e=document.querySelectorAll("...
function M (line 6) | function M(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]}
function k (line 6) | function k(e){var n=M(e);return n&&!n.disableAutodetect}
function T (line 6) | function T(e,n){var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}
FILE: web/includes/js/render.js
function display (line 24) | function display(xhr) {
FILE: web/includes/js/stmd.js
function InlineParser (line 720) | function InlineParser(){
function DocParser (line 1361) | function DocParser(){
function HtmlRenderer (line 1515) | function HtmlRenderer(){
Condensed preview — 57 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (404K chars).
[
{
"path": ".gitignore",
"chars": 103,
"preview": "distribution\ndata\nlib\ntest\n.DS_Store\n.project\n.classpath\ntmp\n/bin/\n_sandbox\nexamples_removed\n.settings\n"
},
{
"path": "README.md",
"chars": 23448,
"preview": "# XYscope\nv 3.0.0 \ncc [teddavis.org](https://teddavis.org) 2017 – 2023\n\nProcessing library to render vector graphics on"
},
{
"path": "changelog.txt",
"chars": 4282,
"preview": "+ new\n* changed\n- removed\n\n////////////////////////////////////////////////////////////\nXYScope 3.0.0 (REV 5) - 21.02.20"
},
{
"path": "examples/1_getting_started/basic_drawing/basic_drawing.pde",
"chars": 738,
"preview": "/* \n basic_drawing\n Draw to the scope by throwing more and more lines, clearing on demand\n cc teddavis.org 2017-23\n */\n\n"
},
{
"path": "examples/1_getting_started/calibration/calibration.pde",
"chars": 822,
"preview": "/*\n calibration\n circle + square + lines to help center/adjust oscilloscpe display\n cc teddavis.org 2023\n */\n\nimport ddf"
},
{
"path": "examples/1_getting_started/clock/clock.pde",
"chars": 1440,
"preview": "/*\n clock\n cc teddavis.org 2018-23\n */\n\nimport ddf.minim.*; // minim req to gen audio\nimport xyscope.*; // import XYsc"
},
{
"path": "examples/1_getting_started/custom_soundcard/custom_soundcard.pde",
"chars": 1076,
"preview": "/*\n custom_soundcard\n Most AC-Coupled DACs will wiggle towards the center.\n For 'better' results, find a DC-coupled DAC."
},
{
"path": "examples/1_getting_started/lissapong/lissapong.pde",
"chars": 3272,
"preview": "/*\n lissapong\n Let the epic crt battle over lissajous begin!\n mouseY, move user paddle\n cc teddavis.org 2023\n */\n\nimport"
},
{
"path": "examples/1_getting_started/template/template.pde",
"chars": 796,
"preview": "/*\n template\n Recommended template for Processing when working with XYscope often.\n Save into ~/Documents/Processing/"
},
{
"path": "examples/2_shapes/a_walkthrough_primatives/a_walkthrough_primatives.pde",
"chars": 3037,
"preview": "/*\n a_walkthrough_primatives\n demo-run of available shapes\n cc teddavis.org 2023\n */\n\nimport ddf.minim.*; // minim req t"
},
{
"path": "examples/2_shapes/additive_synth_shapes/additive_synth_shapes.pde",
"chars": 1240,
"preview": "/*\n additive-synth shapes\n an amazing aspect of vector graphics, \n is sending multiple shapes on the same audio = add"
},
{
"path": "examples/2_shapes/lissajous/lissajous.pde",
"chars": 952,
"preview": "/*\n shapes_lissajous\n Sometimes you just want some lissajous curves!\n cc teddavis.org 2023\n */\n\nimport ddf.minim.*; // m"
},
{
"path": "examples/2_shapes/paramless_shapes/paramless_shapes.pde",
"chars": 1259,
"preview": "/*\n paramless shapes\n incase you're quickly testing/sketching,\n you can create primatives without values\n cc teddavis.or"
},
{
"path": "examples/2_shapes/sphere/sphere.pde",
"chars": 938,
"preview": "/*\n sphere\n mouseX/Y, adjust detailX, detailY\n SHIFT + mouseDragged, freq based on distance from initial click\n*/\n\nim"
},
{
"path": "examples/2_shapes/torus/torus.pde",
"chars": 985,
"preview": "/*\n shape_torus\n Based upon Ira Greenbergs Toroid example\n https://processing.org/examples/toroid.html\n - mouseX » adjus"
},
{
"path": "examples/3_typography/hershey_fonts/hershey_fonts.pde",
"chars": 1573,
"preview": "/*\n text_hershey_fonts\n draw single-line text with hershey fonts!\n lots of functions to learn from below\n big thanks for"
},
{
"path": "examples/3_typography/scopewriter/scopewriter.pde",
"chars": 2741,
"preview": "/*\n scopewriter\n use your oscilloscope as a word processor\n with additive synth (add-synth) drawing to animate + distort"
},
{
"path": "examples/4_inputs/fonts/fonts.pde",
"chars": 1695,
"preview": "/* \n fonts\n Let's draw type on the scope! \n ANYKEY - type out\n DELETE - clear text\n\n » Requires Geomerative library\n cc "
},
{
"path": "examples/4_inputs/kinect/kinect.pde",
"chars": 3166,
"preview": "/* \n kinect\n Turn the kinect depth image into a nice silhouette! \n \n » Requires OpenCV for Processing + openkinect libra"
},
{
"path": "examples/4_inputs/obj/obj.pde",
"chars": 1210,
"preview": "/* \n obj\n Import and render 3D obj files!\n \n cc teddavis.org 2018\n */\n \nimport ddf.minim.*; // minim req to gen audio\ni"
},
{
"path": "examples/4_inputs/svg/svg.pde",
"chars": 1312,
"preview": "/*\n svg\n import any existing vector graphic as an SVG!\n » Requires Geomerative library\n \n cc teddavis.org 2023\n */\n\nimpo"
},
{
"path": "examples/4_inputs/syphon/syphon.pde",
"chars": 3576,
"preview": "/* \n syphon\n Images from any syphon source on the scope! \n mouseX - threshold\n mouseY - threshold distance\n \n » Requires"
},
{
"path": "examples/4_inputs/video/video.pde",
"chars": 3781,
"preview": "/* \n video\n Import and render videos in XYscope\n \n mouseX - threshold\n mouseY - threshold distance\n keys 1, 2, 3 - view "
},
{
"path": "examples/4_inputs/webcam/webcam.pde",
"chars": 3354,
"preview": "/* \n webcam\n You via your webcam on the scope! \n mouseX - threshold\n mouseY - threshold distance\n \n » Requires OpenCV fo"
},
{
"path": "examples/4_inputs/webcam_processing4/webcam_processing4.pde",
"chars": 3525,
"preview": "/*\n webcam processing4\n You via your webcam on the scope!\n mouseX - threshold\n mouseY - threshold distance\n \n * Updated "
},
{
"path": "examples/5_displays/laser/laser.pde",
"chars": 1727,
"preview": "/*\n laser\n Guide to driving RGB laser with XYscope.\n cc teddavis.org 2018 – 23\n */\n\nimport ddf.minim.*; // minim req to "
},
{
"path": "examples/5_displays/vectrex/vectrex.pde",
"chars": 1113,
"preview": "/*\n vectrex\n Basics settings for using a modded Vectrex monitor.\n cc teddavis.org 2018\n */\n\nimport ddf.minim.*; // minim"
},
{
"path": "examples/6_outputs/audio_recorder/audio_recorder.pde",
"chars": 1027,
"preview": "/*\n audio recorder\n Export your XYscope as .wav audio files!\n just use: xy.recorderBegin(filename) + xy.recorderEnd()\n c"
},
{
"path": "examples/6_outputs/osc_wavetables/osc_wavetables.pde",
"chars": 2358,
"preview": "/*\n osc wavetables\n transport your XYscope custom wavetables via OSC to other tools\n to visual forms drawn, add effects,"
},
{
"path": "examples/7_custom_waves/customWaves_drawingXYZ/customWaves_drawingXYZ.pde",
"chars": 2814,
"preview": "/* \n customWaves_drawing\n Test out our sound cards by manually drawing the wave form.\n Very useful for testing just the "
},
{
"path": "examples/7_custom_waves/customWaves_noiseXY/customWaves_noiseXY.pde",
"chars": 1212,
"preview": "/*\n customWaves_buildXY\n You don't have to use primitive forms,\n you can also generate the waveforms by your own code an"
},
{
"path": "examples/7_custom_waves/setWaveforms_noise/setWaveforms_noise.pde",
"chars": 829,
"preview": "/*\n\n*/\n\nimport ddf.minim.*; // minim req to gen audio\nimport xyscope.*; // import XYscope\nXYscope xy; // creat"
},
{
"path": "examples/8_music/MidiScope/MidiScope.pde",
"chars": 2699,
"preview": "/*\n MidiScope\n use a MIDI file to set the freq of any XYscope graphics!\n cc teddavis.org 2019-23\n*/\n\nString midiTrack"
},
{
"path": "examples/8_music/audio_filters/audio_filters.pde",
"chars": 2391,
"preview": "/*\n xtra_filters\n Use minim ugens audio filters.\n Click and drag mouse to adjust moog filter\n cc teddavis.org 2018-23\n "
},
{
"path": "examples/8_music/freq_keyboard_notes/freq_keyboard_notes.pde",
"chars": 1213,
"preview": "/*\n freq_keyboard_notes\n Use your keyboard (A, B, C, D, E, F, G + 1, 2, 3, 4, 5, 6, 7..)\n to play musical pitches of you"
},
{
"path": "examples/9_misc/freq_amp_modulation/freq_amp_modulation.pde",
"chars": 1396,
"preview": "/* \n freq_amp_modulation\n Basic modulation of amp + freq of waves\n Wild effects can be had by changing in unique ways\n c"
},
{
"path": "examples/9_misc/multiscopes_class/multiscopes_class.pde",
"chars": 1971,
"preview": "/* \n multiscopes_class\n Control as many oscilloscopes as you have audio card outputs.\n Create Aggregate devices in Utili"
},
{
"path": "license.txt",
"chars": 7638,
"preview": "\t\t GNU LESSER GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software"
},
{
"path": "resources/README.md",
"chars": 1933,
"preview": "## How to install ##library.name##\n\n### Install with the Contribution Manager\n\nAdd contributed Libraries by selecting th"
},
{
"path": "resources/build.properties",
"chars": 7008,
"preview": "# Create a Library for the Processing open source programming language and \n# environment (http://processing.org/)\n#\n# C"
},
{
"path": "resources/build.xml",
"chars": 15266,
"preview": "<project name=\"Processing Library\" default=\"clean\" basedir=\"../\">\n\n \n<!--\t\n\t\tProperties for your project should be se"
},
{
"path": "resources/code/ExampleTaglet.java",
"chars": 7214,
"preview": "/*\n * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.\n *\n * Redistribution and use in source and binary form"
},
{
"path": "resources/code/doc.sh",
"chars": 442,
"preview": "# a shell script to create a java documentation \n# for a processing Library. \n# \n# make changes to the variables below s"
},
{
"path": "resources/library.properties",
"chars": 2922,
"preview": "# More on this file here: https://github.com/processing/processing/wiki/Library-Basics\n# UTF-8 supported.\n\n# The name of"
},
{
"path": "resources/stylesheet.css",
"chars": 12841,
"preview": "/* Javadoc style sheet */\n/*\nOverall document style\n*/\n\n@import url('resources/fonts/dejavu.css');\n\nbody {\n backgroun"
},
{
"path": "src/xyscope/XYWavetable.java",
"chars": 10333,
"preview": "package xyscope;\n/*\n * Special update to Minim Waveform class by Hansi Raber (Sep 2018),\n * fixing an array out of bound"
},
{
"path": "src/xyscope/XYscope.java",
"chars": 81027,
"preview": "/*\n * cc ted davis 2017-23\n */\n\npackage xyscope;\n\nimport processing.core.*;\nimport static processing.core.PApplet.*;\n\nim"
},
{
"path": "web/includes/css/styles.css",
"chars": 1493,
"preview": "@font-face {\n font-family: 'roboto_mono';\n src: url('../fonts/robotomono-regular-webfont.woff2') format('woff2'),\n ur"
},
{
"path": "web/includes/js/highlight/a11y-dark.css",
"chars": 1447,
"preview": "/* a11y-dark theme */\n/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/mast"
},
{
"path": "web/includes/js/highlight/a11y-light.css",
"chars": 1448,
"preview": "/* a11y-light theme */\n/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/mas"
},
{
"path": "web/includes/js/highlight/docco.css",
"chars": 1141,
"preview": "/*\nDocco style used in http://jashkenas.github.com/docco/ converted by Simon Madine (@thingsinjars)\n*/\n\n.hljs {\n displa"
},
{
"path": "web/includes/js/highlight/github.css",
"chars": 1148,
"preview": "/*\n\ngithub.com style (c) Vasily Polovnyov <vast@whiteants.net>\n\n*/\n\n.hljs {\n display: block;\n overflow-x: auto;\n padd"
},
{
"path": "web/includes/js/highlight/highlight.pack.js",
"chars": 22540,
"preview": "/*\n Highlight.js 10.0.1 (33af2ea5)\n License: BSD-3-Clause\n Copyright (c) 2006-2020, Ivan Sagalaev\n*/\n!function(e,n){\""
},
{
"path": "web/includes/js/render.js",
"chars": 2107,
"preview": "(function () {\n var file = file || \"README.md?\"+Math.floor(Math.random(9999));\n var reader = new stmd.DocParser();\n v"
},
{
"path": "web/includes/js/stmd.js",
"chars": 46695,
"preview": "// stmd.js - CommonMark in javascript\n// Copyright (C) 2014 John MacFarlane\n// License: BSD3.\n\n// Basic usage:\n//\n// var"
},
{
"path": "web/index.html",
"chars": 59924,
"preview": "<html lang=\"en\"><head>\n\t<meta charset=\"utf-8\">\n\t<title>XYscope</title>\n\t<link rel=\"stylesheet\" href=\"includes/css/styles"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the ffd8/xyscope GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 57 files (366.8 KB), approximately 116.5k tokens, and a symbol index with 277 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.