Announcing the Phone quark

Hi all,

I have built a quark to controll stuff in SC with TouchOSC Mk1 and your phone’s builtin accelerometer, unimanigatively named Phone. The documentation is still a bit sparse, but I will unleash this on my students next week, so I’d be really, really happy if 1) someone could be bothered testing it on their systems. I am particularly interested in what happens on a Windows computer and/or android phone, as I don’t have one to test with, and 2) even better if somebody finds this useful for their own work!

The quark is here: Kenneth Flak / Phone · GitLab and contains two classes: Phone and PhoneDeltaTrig. Phone takes care of the data, PhoneDeltaTrig triggers a function based on the data processed by the Phone object.

1 Like

Here is a few examples on how to use the quark:

// for this to work, we need to connect the computer and 
// the phone on the same network, and point TouchOSC to the
// computer on port 55555
//
// First, create the Phone object that we need, then bind it to
// the variable ~phone
~phone = Phone.new(\iPhone, 55555);

// Check if you get any data by evaluating the .trace method
// You should get a barrage of values in your post window
~phone.trace(true);
// stop posting data 
~phone.trace(false);

// now, let's make the phone trigger something.
// at first, just post the delta-value:
~deltaTriggerTest = PhoneDeltaTrig.new(
    phone: ~phone,
    threshold: 0.01,
    speedlim: 0.5,
    function: {|dt, minAmp, maxAmp|
        dt.postln;
    }
).play;

// adjust the threshold to make it less trigger-happy
~deltaTriggerTest.threshold = 0.05;
~deltaTriggerTest.free;

// Let's make some sound:
s.boot;


(
~deltaTrigSine = PhoneDeltaTrig.new(
    phone: ~phone,
    threshold: 0.05,
    speedlim: 0.5,
    minAmp: -50.dbamp,
    maxAmp: -10.dbamp,
    function:{|dt, minAmp, maxAmp|
        {
            // let the amount of movement energy determine the 
            // attack and release times: stronger impulses
            // give a shorter attack and a longer release
            var attack = dt.linlin(0.0, 1.0, 0.5, 0.0);
            var release = dt.linlin(0.0, 1.0, 1, 3);

            // Trigger a sine wave, where the frequency is 
            // determined by the angle of the phone's y axis
            SinOsc.ar(~phone.y.linexp(0.0, 1.0, 220, 880) ! 2)
            // ... and the amplitude is determined by the amount
            // of movement energy
            * dt.linlin(0.0, 1.0, minAmp, maxAmp)
            * EnvGen.kr(Env.perc(attack, 1, release), doneAction: 2);
        }.play;
    }
).play;
)

~deltaTrigSine.free;

// Using the phone as a continuous controller.
(
SynthDef(\sine, {
	var sig, env, lag;
    lag = \lag.kr(0.1);
	env = EnvGen.kr(
        Env.asr(
            \attack.kr(0.1), 
            1.0, 
            \release.kr(0.9)
        ), 
        \gate.kr(1), 
        doneAction: 2
    );
	sig = SinOsc.ar(\freq.kr(440, lag)) 
        * \amp.kr(0.2, lag) 
        * env;
	sig = Pan2.ar(sig, \pan.kr(0));
	Out.ar(0, sig);
}).add;

Pdef(\phoneCC,{
    Pmono(
        \sine,
        \dur, 0.1,
        \lag, Pkey(\dur),
        \freq, Pfunc{
            ~phone.y.linlin(0.0, 1.0, 220, 880)
        },
        \db, Pfunc{ 
            ~phone.x.linlin(0.0, 1.0, -70, -6)
        },
    )
}).play;
)

Pdef(\phoneCC).stop;

I tried it and data transmission works, the Pdef part also works, but the ~deltaTrigSine part doesn’t.

The specifics:
OS: Windows 10
Phone: Fairphone with Android 10
SuperCollider version: 3.12.0

Here’s the error message I get with the ~deltaTrigSine part:

ERROR: Message 'y' not understood.
RECEIVER:
   nil
ARGS:
PATH: C:/[...]/2021-09-10_kflak-phone-test.scd

PROTECTED CALL STACK:
	Meta_MethodError:new	000002146A6E3AC0
		arg this = DoesNotUnderstandError
		arg what = nil
		arg receiver = nil
	Meta_DoesNotUnderstandError:new	000002146A6E59C0
		arg this = DoesNotUnderstandError
		arg receiver = nil
		arg selector = y
		arg args = [  ]
	Object:doesNotUnderstand	000002146A053980
		arg this = nil
		arg selector = y
		arg args = nil
	a FunctionDef	000002146DE5DA38
		sourceCode = "<an open Function>"
		var attack = 0.4660223642985
		var release = 1.135910542806
	SynthDef:buildUgenGraph	000002146BE96A40
		arg this = SynthDef:temp__8
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = [ ControlName  P 0 i_out scalar 0 ]
	a FunctionDef	000002146B5D0C40
		sourceCode = "<an open Function>"
		arg i_out = an OutputProxy
		var result = nil
		var rate = nil
		var env = nil
	SynthDef:buildUgenGraph	000002146BE96A40
		arg this = SynthDef:temp__8
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = nil
	a FunctionDef	000002146BE95080
		sourceCode = "<an open Function>"
	Function:prTry	000002146A9D3EC0
		arg this = a Function
		var result = nil
		var thread = a Routine
		var next = nil
		var wasInProtectedFunc = false
	
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil:handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Object:throw
		arg this = <instance of DoesNotUnderstandError>
	Function:protect
		arg this = <instance of Function>
		arg handler = <instance of Function>
		var result = <instance of DoesNotUnderstandError>
	SynthDef:build
		arg this = <instance of SynthDef>
		arg ugenGraphFunc = <instance of Function>
		arg rates = nil
		arg prependArgs = nil
	Function:play
		arg this = <instance of Function>
		arg target = <instance of Group>
		arg outbus = 0
		arg fadeTime = 0.02
		arg addAction = 'addToHead'
		arg args = nil
		var def = nil
		var synth = nil
		var server = <instance of Server>
		var bytes = nil
		var synthMsg = nil
	< FunctionDef in Method PhoneDeltaTrig:prCreateTask >
		var dt = 0.067955271402995
	Float:do
		arg this = inf
		arg function = <instance of Function>
		var i = 25.0
	Routine:prStart
		arg this = <instance of Routine>
		arg inval = 1183.0
^^ The preceding error dump is for ERROR: Message 'y' not understood.
RECEIVER: nil

Hi @emergent, and thanks a lot for testing!!!

I think the error happens because I swapped p for ~phone in most of the code, but forgot to do so in that one place. I have corrected it now, so if you have a moment, then it would be great if you could check if it works!

Now everything works fine!

1 Like

Great! Thanks again :slight_smile: