Skip to content

Commit a3cc5a4

Browse files
authored
Merge pull request #2 from ffd8/mixing
added xtra_syphon example + audiomix for multiple instances on same out
2 parents f4f116f + f4e8351 commit a3cc5a4

File tree

3 files changed

+188
-6
lines changed

3 files changed

+188
-6
lines changed

examples/xtra_syphon/xtra_syphon.pde

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
xtra_syphon
3+
Images from any syphon source on the scope!
4+
mouseX - threshold
5+
mouseY - threshold distance
6+
7+
» Requires OpenCV for Processing + Syphon libraries
8+
9+
cc teddavis.org + jankenpopp.com 2017
10+
*/
11+
12+
//PREFS
13+
int threshold = 138;
14+
float thresholdDist = 43;
15+
int cutoff = 91; // limit min size contour
16+
17+
// import and create instance of XYscope
18+
import xyscope.*;
19+
XYscope xy;
20+
21+
// minim is required to generate audio
22+
import ddf.minim.*;
23+
24+
// syphon is required for passing imagery
25+
import codeanticode.syphon.*;
26+
SyphonClient client;
27+
PImage imgs; // syphon client
28+
PImage imgo; // syphon resize
29+
PImage imgf; // syphon threshold
30+
31+
// libs required for point sorting (efficient drawing)
32+
import java.util.Collections;
33+
import java.util.Comparator;
34+
35+
//opencv
36+
import gab.opencv.*;
37+
import java.awt.*;
38+
OpenCV opencv;
39+
ArrayList<Contour> contours;
40+
41+
void setup() {
42+
size(512, 512, P3D);
43+
44+
// initialize XYscope with default/custom sound out
45+
xy = new XYscope(this, "");
46+
47+
// initialize syphon client
48+
client = new SyphonClient(this);
49+
50+
// initialize OpenCV (used to convert syphon to single line)
51+
opencv = new OpenCV(this, width, height);
52+
}
53+
54+
void draw() {
55+
background(0);
56+
57+
// only up date when sypon sends new image
58+
if (client.newFrame()) {
59+
imgs = client.getImage(imgs);
60+
}
61+
if (imgs != null) {
62+
imgf = imgs.get();
63+
if (imgf.width > imgf.height) {
64+
imgf.resize(width, 0);
65+
} else {
66+
imgf.resize(0, height);
67+
}
68+
imgo = imgf.get();
69+
// clear waves like refreshing background
70+
xy.clearWaves();
71+
72+
// adjust threshold of image for selective lines
73+
if (mousePressed) {
74+
threshold = floor(map(mouseX, 0, width, 0, 255));
75+
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
76+
77+
// replace variable defaults at top if you find better ones
78+
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
79+
}
80+
81+
// convert syphon to high contrast threshold
82+
for (int i=0; i<imgf.width*imgf.height; i++) {
83+
if (brightness(imgf.pixels[i]) > threshold && brightness(imgf.pixels[i]) < threshold+thresholdDist) {
84+
imgf.pixels[i] = color(200); // White
85+
} else {
86+
imgf.pixels[i] = color(0); // Black
87+
}
88+
}
89+
90+
// process threshold to single line
91+
opencv.loadImage(imgf);
92+
opencv.dilate();
93+
opencv.erode();
94+
95+
// display syphon original, threshold, opencv images – w/ keys 1, 2, 3
96+
if (keyPressed) {
97+
if (key == '1')
98+
image(imgo, 0, 0);
99+
if (key == '2')
100+
image(imgf, 0, 0);
101+
if (key == '3') {
102+
PImage otemp = opencv.getSnapshot();
103+
image(otemp, 0, 0);
104+
}
105+
}
106+
107+
contours = opencv.findContours(true, false);
108+
109+
// sort group of lines for effeciant drawing
110+
Collections.sort(contours, new MyComparator());
111+
112+
// draw shapes on scope
113+
for (Contour contour : contours) {
114+
if (contours.size() > 0) {
115+
contour.setPolygonApproximationFactor(1);
116+
if (contour.numPoints() > cutoff) {
117+
xy.beginShape();
118+
for (PVector point : contour.getPolygonApproximation().getPoints()) {
119+
xy.vertex(point.x, point.y);
120+
}
121+
xy.endShape();
122+
}
123+
}
124+
}
125+
126+
// build audio from shapes
127+
xy.buildWaves();
128+
}
129+
// draw XY analytics
130+
xy.drawXY();
131+
}
132+
133+
// used for sorting points
134+
class MyComparator implements Comparator<Contour> {
135+
@Override
136+
public int compare(Contour o1, Contour o2) {
137+
if (o1.numPoints() > o2.numPoints()) {
138+
return -1;
139+
} else if (o1.numPoints() < o2.numPoints()) {
140+
return 1;
141+
}
142+
return 0;
143+
}
144+
}

examples/xtra_webcam/xtra_webcam.pde

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
xtra_type
3-
Let's draw type on the scope!
2+
xtra_webcam
3+
You via your webcam on the scope!
44
mouseX - threshold
55
mouseY - threshold distance
66
@@ -9,6 +9,10 @@
99
cc teddavis.org 2017
1010
*/
1111

12+
//PREFS
13+
int threshold = 65;
14+
float thresholdDist = 115;
15+
1216
// import and create instance of XYscope
1317
import xyscope.*;
1418
XYscope xy;
@@ -30,8 +34,6 @@ import java.awt.*;
3034
OpenCV opencv;
3135
ArrayList<Contour> contours;
3236
int cutoff = 91;
33-
int threshold = 65;
34-
float thresholdDist = 115;
3537
PImage p;
3638

3739
void setup() {
@@ -61,7 +63,7 @@ void draw() {
6163
thresholdDist = map(mouseY, 0, height, 0, 255-threshold);
6264

6365
// replace variable defaults at top if you find better ones
64-
println(threshold +" / "+ thresholdDist);
66+
println("threshold: "+threshold +" / thresholdDist: "+ thresholdDist);
6567
}
6668

6769
// convert video to high contrast threshold

src/xyscope/XYscope.java

+37-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ public XYscope(PApplet theParent) {
9090
initMinim();
9191
setMixer();
9292
}
93+
94+
/**
95+
* Initialize library in setup(), use default system audio out setting.
96+
*
97+
* @param theParent PApplet to apply to, typically 'this'
98+
* @param outMix AudioOutput to merge instance and of XYscope to
99+
*/
100+
// * @example basic_shapes
101+
102+
public XYscope(PApplet theParent, AudioOutput outMix) {
103+
myParent = theParent;
104+
initMinim();
105+
setWaveTable(outMix);
106+
}
93107

94108
/**
95109
* Initialize library in setup(), custom soundcard by String for XY.
@@ -120,7 +134,6 @@ public XYscope(PApplet theParent, int xyMixer) {
120134
setMixer(xyMixer);
121135
}
122136

123-
124137
/**
125138
* Initialize library in setup(), custom soundcard by String for XY, custom soundcard by String for Z.
126139
* <p>
@@ -262,6 +275,29 @@ private void setWaveTable(){
262275
waveZ.reset();
263276
}
264277
}
278+
279+
private void setWaveTable(AudioOutput outMix){
280+
tableX = Waves.randomNHarms(0);
281+
waveX = new Oscil(freq.x, amp.x, tableX);
282+
tableX.setWaveform(shapeX);
283+
waveX.patch(panX).patch(outMix);
284+
285+
tableY = Waves.randomNHarms(0);
286+
waveY = new Oscil(freq.y, amp.y, tableY);
287+
tableY.setWaveform(shapeY);
288+
waveY.patch(panY).patch(outMix);
289+
290+
waveX.reset();
291+
waveY.reset();
292+
293+
if(zaxis){
294+
tableZ = Waves.randomNHarms(0);
295+
waveZ = new Oscil(freq.z, amp.z, tableZ);
296+
tableZ.setWaveform(shapeZ);
297+
waveZ.patch(outZ); // need pan?? or gets full amp to both channels?
298+
waveZ.reset();
299+
}
300+
}
265301

266302
/**
267303
* Check if z-axis waveform is being automatically drawn from added shapes.

0 commit comments

Comments
 (0)