Rusty Instruments

FOSDEM'20: Rust when it makes sense

Benedict R. Gaster / @cuberoo_
my pronouns are he/him/they or xe/xim/xir

controllers
controllers
controllers
controllers
organelle
bcc basic
6502
C book
C book
haskell logo
C++ book
OpenGL logo
OpenCL logo
npm cabal
C++ book haskell logo
square peg
fosdem
rust
action to sound
mpc interface
system flow diagram
mpc interface
						
							stop ! #x 10 ! #y 10 ! #size 3
						
					
						
								pad ! #x 10 ! #y 10 ! #size 3 ! #address "/stop/"
						
					
Compose controllers to form 'interfaces'
						
							stop ! #x 167 ! #y 20 ! #size 25
							<>
							play ! #v1 (162 ,32) ! #v2 (142 ,20) ! #v3 (142 ,45)
							<>
							record ! #x 209 ! #y 32 ! #r 12
						
					
Define an interface
						
							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
						
					
Domain specific controllers
						
							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
						
					
system flow diagram
						
								rect 167 20 25 25 # itype ipad # iaddress "/stop/"
						
					
SVG Controller Representation
						
							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/>
						
					
system flow diagram
pipeline
lyon

by Nicolas Silva

mpc wireframe
mpc wireframe
system flow diagram
						
							{"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" }
						
					

Sensel Morph

sensel morph

Pressure based touch sensor, with 20,000 pressure sensors
C driver API for communicating over USB

ROLI Lightpad

roli lightpad

Pressure based touch sensor, with 15x15 matrix of bright RGB LEDS
Programmable with (C like) Littlefoot DSL

muses screenshot
fast

Faust (Functional Audio Stream) is a functional programming language for sound synthesis and audio processing

fast
									
							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.

The punch line

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!

More information @project site

muses