Bpm detection ... Norns | Supercollider | "AutoTrack"

Hi, new “Norns” user here.

enjoying it very much so far … except, I’m trying, but failing to get the “BeatTrack” (or “AutoTrack”) ugen working: AutoTrack | SuperCollider 3.12.2 Help

I was adapting the PlayThrough template and have it/something somewhat, but the tracking (via audio out) is fairly wonky, it seems (I’m trying with some vanilla 4/4 techno); and I can’t seem to poll the tempo value, it’s always stuck at 128 (see the bpm.callback below).

below is my Engine + Lua test file. Any pointers welcome (or hints re alternatives, the output I’m seeing isn’t particularly promising, but chances are I’m doing something wrong. (Fwiw: trying to get this working to extract the BPM of the incoming audio for looping/sync purposes)

engine:

Engine_BeatTrack : CroneEngine {

var bpm_=128;
var <synth;

// this is your constructor. the ‘context’ arg is a CroneAudioContext.
// it provides input and output busses and groups.
// see its implementation for details.

*new { arg context, doneCallback;
^super.new(context, doneCallback);
}

// this is called when the engine is actually loaded by a script.
// you can assume it will be called in a Routine,
// and you can use .sync and .wait methods.
alloc {
//Add SynthDefs
SynthDef(\track_BPM, { | inL, inR, out, bpm_=128 |

  	var trackb, trackh, trackq, tempo;
  	var bsound, hsound, qsound;
  	var source;
  	// read mono
  	source = In.ar(inL);
  	#trackb, trackh, trackq, tempo = AutoTrack.kr(source);

  	bpm_ = tempo;
  	bsound = Pan2.ar(LPF.ar(WhiteNoise.ar * Decay.kr(trackb, 0.05), 1000), 0.0);

  	Out.ar(out, bsound);
  }).add;

  context.server.sync;

  synth = Synth.new(\track_BPM, [
  	\inL, context.in_b[0].index,			
  	\inR, context.in_b[1].index,
  	\out, context.out_b.index,
  	\bpm_, 128],
  context.xg);

// this is how you add “commands”,
// which is how the lua interpreter controls the engine.
// the format string is analogous to an OSC message format string,
// and the ‘msg’ argument contains data.

  this.addPoll("bpm", { bpm_ });

}

free {
// here you should free resources (e.g. Synths, Buffers &c)
// and stop processes (e.g. Routines, Tasks &c)
synth.free;
}

}

lua:

– bpm test

engine.name = ‘BeatTrack’

local audio = require ‘audio’

function init()
print("bpm … ? ")
audio.level_monitor(0)
bpm = poll.set(“bpm”)
bpm.time = 0.5
bpm.callback = function(val)
print(val)
end
bpm:start()
end

Thanks!

you can’t write directly to the interpreter variable bpm_ from within the synthdef. (the synthdef function is executed by the interpreter process sclang; it specifies the structure of a DSP graph, but the graph itself is executed by the audio server process scsynth.)

check out the SC help files on SynthDef, “Client vs Server,” etc.

ways to get values out of the synthdef to the sclang client include:

  • on the server, write them to a control bus with Out.kr; read them from the client with Bus.get or Bus.getSynchronous

  • on the server, generate an OSC message with SendTrig.kr; use OSCdef to respond from the client