Playing around circle buffers following a conversation with @rodrigo.constanzo. The goal is to detect and analyze events at different timelscales and derive metrics (onset density, aproximate tempo, trend, and variation) from them.
In the code below, I expect the FluidBufAmpSlice.kr
to perform an analysis and populate the ~indices
Buffer when I give it a \t_trig
message. What actually happens is that the ~indices remains empty. Additionally, the server will occasionally crash and exit when I examine the empty ~indices
. I have tried variations with PlayBuf and different Buf Slicer objects.
Am I misunderstanding how the .kr
version of FluidBufAmpSlice
is supposed to work?
~record = Buffer.alloc(s,s.sampleRate * 1);
~indices = Buffer(s);
(
a = { |t_trig,buf,indices|
var input = SoundIn.ar(0);
var sig = RecordBuf.ar(input, buf, loop: 1);
FluidBufAmpSlice.kr(source: buf, indices: indices, fastRampUp: 3, fastRampDown: 383, slowRampUp: 2205, slowRampDown: 2205, onThreshold: 16, offThreshold: 4.66665, floor: -55, minSliceLength: 1323, highPassFreq: 2000, trig: t_trig);
}.play(args: [\buf, ~record, \indices, ~indices]);
);
~record.plot;
a.set(\t_trig, 1);
~indices;
~indices.getn(1, {|msg| msg.postln});
a.free;
1 Like
( // Allocate Buffers
~record = Buffer.alloc(s,s.sampleRate * 1);
~indices = Dictionary.new;
~indices[\AmpSlice] = Dictionary.new;
~indices[\AmpSlice][\Indices] = Buffer(s);
~indices[\AmpSlice][\Stats] = Buffer(s);
~indices[\OnsetSlice] = Dictionary.new;
~indices[\OnsetSlice][\Indices] = Dictionary.new;
~indices[\OnsetSlice][\Stats] = Buffer(s);
~stats = Buffer(s);
~deltas = { |myArray|
var deltas = Array.newClear(myArray.size - 1);
myArray.doAdjacentPairs { arg a, b, index;
deltas[index] = b - a;
};
deltas;
};
);
( // Synth
a = { |source,indices,stats,t_trig|
var input = SoundIn.ar(0);
var sig = RecordBuf.ar(input, source, loop: 1);
var phasor = Phasor.ar(0, BufRateScale.kr(source), 0, BufFrames.kr(source)).poll(Trig1.ar(t_trig,SampleDur.ir));
var gate = (phasor < 1);
BufWr.ar(input,source,phasor);
FluidBufToKr.kr(stats,numFrames:7);
SendReply.ar((phasor < 1), '/analyzeBuffer', [source, indices, stats]);
}.play(args: [
\source, ~record,
\indices, ~indices[\AmpSlice][\Indices],
\stats, ~indices[\AmpSlice][\Stats]
]);
);
( // Callback
OSCFunc({|msg|
var source = s.cachedBufferAt(msg[3].asInteger);
var indices = s.cachedBufferAt(msg[4].asInteger);
var stats = s.cachedBufferAt(msg[5].asInteger);
msg.postln;
FluidBufOnsetSlice.process(s,source,indices:indices,action:{
arg features;
FluidBufStats.process(s, features, stats: stats, action: { |msg| msg.postln });
// [ 22528.0, 8704.0, 0.0, 1.0, 13824.0, 13824.0, 31232.0 ]
});
},'/analyzeBuffer');
);
Is there a smart/idiomatic way to get the deltas into a buffer?
staying on the server, that is not super smooth but a FluidBufCompose ninja could do it.
Imagine you have a buffer that has 4 indices:
10 20 30 40
you could compose @numframes (length - 1) to itself offsetted. Now this is power ninja use
//fake source buffer
b = Buffer.loadCollection(s,(1..4) * 10)
//destivation for deltas
c = Buffer(s)
c.zero
// copy the left part of the subtractions (20,30,40)
FluidBufCompose.process(s,b,startFrame: 1,numFrames: b.numFrames - 1, gain: 1,destination: c, destGain: 1)
// adds a negative copy of an offset version of the array (-10,-20,-30)
FluidBufCompose.process(s,b,startFrame: 0,numFrames: b.numFrames - 1, gain: -1,destination: c, destGain: 1)
// voilà
c.getn(0,c.numFrames,{|x|x.postln})
Now you could run that as kr as bufcompose has that too.