FOSDEM'20: Rust when it makes sense
Benedict R. Gaster /
@cuberoo_
my pronouns are he/him/they or xe/xim/xir
stop ! #x 10 ! #y 10 ! #size 3
pad ! #x 10 ! #y 10 ! #size 3 ! #address "/stop/"
stop ! #x 167 ! #y 20 ! #size 25
<>
play ! #v1 (162 ,32) ! #v2 (142 ,20) ! #v3 (142 ,45)
<>
record ! #x 209 ! #y 32 ! #r 12
interface =
stop ! #x 167 ! #y 20 ! #size 25
<>
play ! #v1 (162 ,32) ! #v2 (142 ,20) ! #v3 (142 ,45)
<>
record ! #x 209 ! #y 32 ! #r 12
pad :: "x":!Int -> "y":!Int -> "size":!Int -> "address":!Text -> Controller
toggle :: "x":!Int -> "y":!Int -> "size":!Int -> "address":!Text -> Controller
horzSlider :: "x" :! Int -> "y" :! Int -> "width" :! Int -> "height" :! Int ->
"min" :! Int -> "max" :! Int -> "address" :! Text -> Controller
vertSlider :: "x" :! Int -> "y" :! Int -> "width" :! Int -> "height" :! Int ->
"min" :! Int -> "max" :! Int -> "address" :! Text -> Controller
ciPad :: "x":!Int -> "y":!Int -> "r":!Int -> "address":!Text -> Controller
endless :: "cx" :! Int -> "cy" :! Int -> "or" :! Int -> "ir" :! Int ->
"address" :! Text -> Controller
rect 167 20 25 25 # itype ipad # iaddress "/stop/"
rect :: "x":!Int -> "y":!Int -> "width":!Int -> "height":!Int -> Controller
circle :: "x" :! Int -> "y" :! Int -> "r" :! Int -> Controller
polygon :: "points" :! [(Int,Int)] -> Controller
<svg xmlns="http://www.w3.org/2000/svg" height="140mm" viewBox="0 0 240 140"
width="240mm" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.11.1"
interface_device="sensel">
<rect interface_osc_address="/play" height="25" interface_type="pad"
width="25" x="167" y="20"/>
<polygon interface_osc_address="/play" points="162 32 142 20 142 45 162 32"
interface_type="pad"/>
<circle interface_osc_address="/record" interface_type="pad" cy="32" r="12"
cx="209"/>
<svg/>
{"controllers" : [ {
"type_id" : "pad", "id" : 1, "rgb" : "rgb(217,137,188)",
"args" : [ 100 ], "address" : "/midicc" }, ... ],
"buffer" : [ [
1,1,1,0,2,2,2,0,3,3,3,0,4,4,4,
1,1,1,0,2,2,2,0,3,3,3,0,4,4,4,
1,1,1,0,2,2,2,0,3,3,3,0,4,4,4,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8,
5,5,5,0,6,6,6,0,7,7,7,0,8,8,8, ] ], "interface" : "lightpad" }
Pressure based touch sensor, with 20,000 pressure sensors
C driver API for communicating over USB
Pressure based touch sensor, with 15x15 matrix of bright RGB LEDS
Programmable with (C like) Littlefoot DSL
Faust (Functional Audio Stream) is a functional programming language for sound synthesis and audio processing
import("stdfaust.lib");
vol = hslider("volume [unit:dB]", 0, -96, 0, 0.1) : ba.db2linear : si.smoo ;
freq = hslider("freq [unit:Hz]", 1000, 20, 24000, 1);
process = vgroup("Oscillator", os.osc(freq) * vol);
class mydsp : public dsp {
private:
FAUSTFLOAT fHslider0;
float fRec0[2];
int fSamplingFreq;
float fConst0;
FAUSTFLOAT fHslider1;
float fRec2[2];
public:
...
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
FAUSTFLOAT* output0 = outputs[0];
float fSlow0 = (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fHslider0))));
float fSlow1 = (fConst0 * float(fHslider1));
for (int i = 0; (i < count); i = (i + 1)) {
fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
fRec2[0] = (fSlow1 + (fRec2[1] - std::floor((fSlow1 + fRec2[1]))));
output0[i] = FAUSTFLOAT((fRec0[0] * ftbl0mydspSIG0[int((65536.0f * fRec2[0]))]));
fRec0[1] = fRec0[0];
fRec2[1] = fRec2[0];
}
}
}
pub struct mydsp {
fDummy: f32,
fHslider0: f32,
fRec0: [f32;2],
fSamplingFreq: i32,
fConst0: f32,
fHslider1: f32,
fRec2: [f32;2],
}
impl mydsp {
...
pub fn compute(&mut self, count: i32, inputs: &[&[f32]], outputs: &mut[&mut[f32]]) {
let mut fSlow0: f32 = (0.00100000005 * f32::powf(10.0, (0.0500000007 * (self.fHslider0 as f32))));
let mut fSlow1: f32 = (self.fConst0 * (self.fHslider1 as f32));
for i in 0..count {
self.fRec0[0] = (fSlow0 + (0.999000013 * self.fRec0[1]));
self.fRec2[0] = (fSlow1 + (self.fRec2[1] - f32::floor((fSlow1 + self.fRec2[1]))));
outputs[0][i as usize] = ((self.fRec0[0] * unsafe { ftbl0mydspSIG0[((65536.0 * self.fRec2[0]) as i32) as usize] }) as f32);
self.fRec0[1] = self.fRec0[0];
self.fRec2[1] = self.fRec2[0];
}
}
}
pub fn buildUserInterface(&mut self, ui_interface: &mut UI) {
ui_interface.openVerticalBox("Oscillator");
ui_interface.declare(&mut self.fHslider1, "unit", "Hz");
ui_interface.addHorizontalSlider("freq", &mut self.fHslider1, 1000.0, 20.0, 24000.0, 1.0);
ui_interface.declare(&mut self.fHslider0, "unit", "dB");
ui_interface.addHorizontalSlider("volume", &mut self.fHslider0, 0.0, -96.0, 0.0, 0.10000000000000001);
ui_interface.closeBox();
}
Implementation straight forward when supporting Faust's UI widgets, but assumes a conventional UI is directly changing parameters
pub fn set_freq(&mut self, v: f32) {
self.fHslider1 = v;
}
Modified faust2rust to support custom setters, and getters.
All of this work was original developed on OS X, without any real thought about portability! But we've now ported it to the Raspberry Pi and Windows, with not much more work than cargo build!