I’ve made a quark for helping make realtime interactive systems, where the interaction isn’t happening in code, but coming from a performer, or otherwise over OSC.
This project is a culmination of the past few years of my PhD making works for live audiovisual + performer works. I hope to have some art available to share in the next few months.
In such work, OSC maps are used to defined relationship between visual and audio, human and computer, etc. Each map is a relationship between elements; JX, seeks to allow these relationship to be mutated and combined as objects in there own right.
Hopefully someone might find this useful?!
run Quarks.install("https://github.com/JordanHendersonMusic/JX-supercollider.git")
to check it out.
The documentation is limited right now, but there is one tutorial guide (a copy of the github page) under Libraries>JX. It is probably full of spelling and grammatical mistakes as I haven’t had a chance to double check it yet.
There is a lot more info on Github, but here are some highlight:
Synth owned resources
Busses are given as examples, but buffers also exist.
s.waitForBoot {
var from = JXSynthDef('/from', {
JXOut.ar(\out, SinOsc.ar(2));
});
var to = JXSynthDef('/to', {
JXIn.ar(\in, 1)
})
.connect( from[\out] -> \in );
}
flexible connections
// Many 2 one connections
.connect(
from[\outA] -> \in
from[\outB] -> \in,
from[\outC] -> \in,
);
// or like this
.connect( from[\outA, \outB, \outC] -> \in );
// one to many...
.connect( from[\outA] -> [\inA, \inB] );
// many to many - creates 6 connections
.connect( from[\outA, \outB, \outC] -> [\inA, \inB] );
// with a scaling function
.connect( from[\outA] -> _.exprange(200, 400) -> \freq );
importing files as functions
main.scd
JXAssertOpenedFromDirectory("/home/user/my_project_dir");
s.waitForBoot {
var generators = JXImport.cwd("noises.scd").(
\groupName: '/noises'
);
var outputter = JXSynthDef('/out', {
JXIn.ar(\in, 2, JXReduce.mean, JXReshape.circular).poll
})
.connect( generators[\out] -> \in );
outputter.getResource(\in).bus.scope;
}
noise.scd
{ |groupName|
JXGroup(groupName, { |self|
var pink = JXSynthDef('/pink', {
JXOut.ar(\out, PinkNoise.ar(0.1!4))
});
var white = JXSynthDef('/white', {
JXOut.ar(\out, WhiteNoise.ar(0.3!4))
});
var sum = JXSynthDef('/sum', {
var in = JXIn.ar(\in, 2);
JXOut.ar(\out, in);
})
.connect(
pink[\out] -> \in,
white[\out] -> \in
);
// makes \out available from outside the group
// all other resources are encapsulated
self.forwardResource( sum[\out] -> \out );
});
}
osc maps between sources and sinks
JXSynthDef('/src', {
var sig = ....;
// an internal osc source of data
JXOscSrc.kr('/amp', Amplitude.kr(sig, 0.3, 0.1) )
});
JXSynthDef('/sink', {
// an internal osc sink for data
var amp = JXOscSink.kr('/amp', 1);
...
});
var mapAmaker = JXOscMapMk({ |srcs|
JXOscMap((
'/sink/amp' : srcs['/src/amp'] * LFNoise2.kr(2),
'/beep/amp' : -10.dbamp,
'/some/other/sink/for/data' : srcs['/some/data/src']
))
});
JXOscMapperSynth({
var srcs = JXOscStore.getMapSources();
var mapa = mapAmaker.makeMap(srcs)
JXOscMapOutput.kr(mapa);
});
JXOscRelay.init(sendingRate: 120);
mutating and combining osc maps
JXOscMapperSynth({|src|
var a = mapAmk.makeMap(src);
var b = mapBmk.makeMap(src);
var c = mapCmk.makeMap(src);
var d = mapDmk.makeMap(src);
// linearly interpolate between maps
var lerp = JXOscMapLinSelectX(MouseX.kr(0, 3), a, b, c, d);
JXOscMapOutput.kr(lerp);
});
composing osc maps
var mapCmaker = JXOscMapMk({ |srcs|
var a = mapAmaker.makeMap(srcs);
var b = mapBmaker.makeMap(srcs);
// control other osc maps with osc data.
JXOscMapLinSelectX(srcs['/beep/out/amp'], a, b)
<+/> // when similar keys exist, take their mean.
JXOscMap(( '/beep/freq' : LFNoise0.kr(0.1) ))
});