First mockup of audio looper (==)

I am trying to add an audio looper to play breakbeats. It works .. meh for now but I'm sure that it'll slowly get better!
This commit is contained in:
2024-05-02 23:28:00 +02:00
parent 775e7efed7
commit b497ca13dc
5 changed files with 175 additions and 27 deletions

View File

@ -51,22 +51,22 @@ Boot {
// Post actions: installing behavior after server boot
Server.default.waitForBoot({
d = ();
// Exceptional Dual Sardine Boot
d.dirt = SuperDirt(2, s);
d.dirt.fileExtensions = ["wav","aif","aiff","aifc","mp3"];
d.dirt.loadSoundFiles("/Users/bubo/Library/Application\ Support/Sardine/SON/*");
d.dirt.loadSoundFiles("/Users/bubo/.config/livecoding/samples/*");
d.dirt.doNotReadYet = true;
d.dirt.start(57120, [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
(
d.d1 = d.dirt.orbits[0]; d.d2 = d.dirt.orbits[1]; d.d3 = d.dirt.orbits[2];
d.d4 = d.dirt.orbits[3]; d.d5 = d.dirt.orbits[4]; d.d6 = d.dirt.orbits[5];
d.d7 = d.dirt.orbits[6]; d.d8 = d.dirt.orbits[7]; d.d9 = d.dirt.orbits[8];
d.d10 = d.dirt.orbits[9]; d.d11 = d.dirt.orbits[10]; d.d12 = d.dirt.orbits[11];
);
d.dirt.soundLibrary.addMIDI(\midi, MIDIOut.newByName("MIDI", "Bus 1"));
d.dirt.soundLibrary.addMIDI(\midi2, MIDIOut.newByName("MIDI", "Bus 2"));
// d = ();
// // Exceptional Dual Sardine Boot
// d.dirt = SuperDirt(2, s);
// d.dirt.fileExtensions = ["wav","aif","aiff","aifc","mp3"];
// d.dirt.loadSoundFiles("/Users/bubo/Library/Application\ Support/Sardine/SON/*");
// d.dirt.loadSoundFiles("/Users/bubo/.config/livecoding/samples/*");
// d.dirt.doNotReadYet = true;
// d.dirt.start(57120, [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
// (
// d.d1 = d.dirt.orbits[0]; d.d2 = d.dirt.orbits[1]; d.d3 = d.dirt.orbits[2];
// d.d4 = d.dirt.orbits[3]; d.d5 = d.dirt.orbits[4]; d.d6 = d.dirt.orbits[5];
// d.d7 = d.dirt.orbits[6]; d.d8 = d.dirt.orbits[7]; d.d9 = d.dirt.orbits[8];
// d.d10 = d.dirt.orbits[9]; d.d11 = d.dirt.orbits[10]; d.d12 = d.dirt.orbits[11];
// );
// d.dirt.soundLibrary.addMIDI(\midi, MIDIOut.newByName("MIDI", "Bus 1"));
// d.dirt.soundLibrary.addMIDI(\midi2, MIDIOut.newByName("MIDI", "Bus 2"));
s.latency = 0.3;
// Resume normal boot sequence
@ -92,8 +92,26 @@ Boot {
Server.default.avgCPU.round(2),
Server.default.peakCPU.round(2)), 40)
}, Server.default);
// This custom event is used for audio looping
Event.addEventType(\buboLoopEvent, {
arg server;
if (~sp.notNil && ~nb.notNil, {
~sp = ~sp ?? 'default';
~nb = ~nb ?? 0;
~buf = Bank(~sp)[~nb % Bank(~sp).paths.size];
if (Bank(~sp).metadata[~nb % Bank(~sp).size][\numChannels] == 1) {
~instrument = \looperMono;
} {
~instrument = \looperStereo;
};
});
~type = \note;
currentEnvironment.play;
});
// This custom event makes it easier to play samples
Event.addEventType(\buboEvent, {
// This is a custom event that makes it easier to play samples
arg server;
if (~sp.notNil && ~nb.notNil, {
~sp = ~sp ?? 'default';

View File

@ -40,34 +40,59 @@
/* Syntax for sending MIDI messages */
>> {
arg pattern;
var quant = this.getQuantFromPattern(pattern);
var fade = this.getFadeFromPattern(pattern);
pattern = EventShortener.findShortcuts(pattern);
pattern = pattern ++ [type: 'midi'];
this[0] = Pbind(*pattern);
this.quant = 4; this.fadeTime = 0.01;
this.quant = quant;
this.fadeTime = fade;
this.play;
^this
}
/* Player-like syntax sugar */
/* Player syntax sugar */
=> {
arg pattern;
var quant = this.getQuantFromPattern(pattern);
var fade = this.getFadeFromPattern(pattern);
pattern = EventShortener.findShortcuts(pattern);
pattern = pattern ++ [\type, \buboEvent];
this[0] = Pbind(*pattern);
this.quant = 4; this.fadeTime = 0.01;
this.quant = quant;
this.fadeTime = fade;
this.play;
^this
}
/* FIX: Completely broken. What is the event type
* BuboEvent should fall back to after tweaking
* the pattern to my liking?
*/
/* Audio Looper (sample playback) */
== {
arg pattern;
var quant = this.getQuantFromPattern(pattern);
var fade = this.getFadeFromPattern(pattern);
pattern = EventShortener.findShortcuts(pattern);
pattern = pattern ++ [\type, \buboLoopEvent];
pattern = pattern ++ [\legato, 1];
pattern = pattern ++ [
\time, Pkey(\dur) / Pfunc { currentEnvironment.clock.tempo }
];
this[0] = Pbind(*pattern);
this.quant = quant;
this.fadeTime = fade;
this.play;
^this
}
/* FIX: Rewrite this part, slightly broken */
-> {
arg pattern;
var quant = this.getQuantFromPattern(pattern);
var fade = this.getFadeFromPattern(pattern);
pattern = EventShortener.findShortcuts(pattern);
// pattern = pattern ++ [\type, \buboMonoEvent];
this[0] = Pmono(*pattern);
this.quant = 4;
this.fadeTime = 0.01;
this.quant = quant;
this.fadeTime = fade;
this.play;
}
f {
@ -96,4 +121,24 @@
^this
}
getQuantFromPattern {
arg pattern; var quant;
var quantIndex = pattern.indexOf('quant');
if (quantIndex.notNil) {
^pattern[quantIndex + 1]
} {
^0
}
}
getFadeFromPattern {
arg pattern; var fade;
var fadeIndex = pattern.indexOf('fade');
if (fadeIndex.notNil) {
^pattern[fadeIndex + 1]
} {
^0.01
}
}
}

View File

@ -7,3 +7,6 @@ c = currentEnvironment.clock;
// Space for loading custom SynthDefs
"Loading SynthDefs...".postln;
"Synthdefs.scd".loadRelative;
// Debug during development
// OSCFunc.trace(true);

View File

@ -53,6 +53,55 @@ d.list = { arg obj; obj.keys.do({arg i; i.postln}); };
d.splayer = z;
);
(
/* Crafted with some help from Bruno Gola */
z = SynthDef(\looperMono,
{
arg out;
var sig, env, index;
index = Select.kr(\direction.kr(1) > 0, [\index.kr(0) + 1, \index.kr]);
sig = PlayBuf.ar(
1,
\buf.kr(0),
(BufRateScale.kr(\buf.kr) * (BufSamples.kr(\buf.kr)
/ \slices.kr(1) / BufSampleRate.kr(\buf.kr)) / \time.kr * \direction.kr) / 2,
1, BufSamples.kr(\buf.kr) * (index / \slices.kr), doneAction: 0
);
env = EnvGen.ar(
Env.asr(0.01, 1, 0.01), \gate.kr(1), doneAction: 2
);
sig = sig * env;
sig = sig * \amp.kr(-6.dbamp);
OffsetOut.ar(out,Pan2.ar(sig,\pan.kr(0)));
}).add;
d.looperMono = z;
);
(
/* Crafted with some help from Bruno Gola */
z = SynthDef(\looperStereo,
{
arg out;
var sig, env, index;
index = Select.kr(\direction.kr(1) > 0, [\index.kr(0) + 1, \index.kr]);
sig = PlayBuf.ar(
2,
\buf.kr(0),
(BufRateScale.kr(\buf.kr) * (BufSamples.kr(\buf.kr)
/ \slices.kr(1) / BufSampleRate.kr(\buf.kr)) / \time.kr * \direction.kr) / 2,
1, BufSamples.kr(\buf.kr) * (index / \slices.kr), doneAction: 0
);
env = EnvGen.ar(
Env.asr(0.01, 1, 0.01), \gate.kr(1), doneAction: 2
);
sig = sig * env;
sig = sig * \amp.kr(-6.dbamp);
OffsetOut.ar(out,Pan2.ar(sig,\pan.kr(0)));
}).add;
d.looperStereo = z;
);
(
z = SynthDef(\sinfb, {
arg out;

33
test_breakbeat.scd Normal file
View File

@ -0,0 +1,33 @@
~a => [sp: ["kick", \].pseq(inf), nb: 0, db: 0];
~a.play;
~a.clear;
Scope()
(
var sampleStr = "kick:2(1) snare:4(1/4) . hihat:1(1/8) .";
a = { |sampleStr, defaultRestDuration = 1.0|
var pattern = "(\\w+):(\\d+)\\(([\\d/]+)\\)|\\.";
var matches = sampleStr.findAllRegexp(pattern);
matches.collect { |match|
if(match.size == 1) {
[ 'sp': 'rest', 'nb': 0, 'dur': defaultRestDuration ]
} {
var sampleName = match[0];
var sampleNumber = match[1].asInteger;
var duration = match[2];
var durationValue;
if(duration.contains("/")) {
var nums = duration.split("/");
durationValue = nums[0].asInteger / nums[1].asInteger;
} {
durationValue = duration.asFloat;
};
[ 'sp': sampleName, 'nb': sampleNumber, 'dur': durationValue ]
}
}
};
a.value(sampleStr);
)