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:
@ -51,22 +51,22 @@ Boot {
|
|||||||
|
|
||||||
// Post actions: installing behavior after server boot
|
// Post actions: installing behavior after server boot
|
||||||
Server.default.waitForBoot({
|
Server.default.waitForBoot({
|
||||||
d = ();
|
// d = ();
|
||||||
// Exceptional Dual Sardine Boot
|
// // Exceptional Dual Sardine Boot
|
||||||
d.dirt = SuperDirt(2, s);
|
// d.dirt = SuperDirt(2, s);
|
||||||
d.dirt.fileExtensions = ["wav","aif","aiff","aifc","mp3"];
|
// d.dirt.fileExtensions = ["wav","aif","aiff","aifc","mp3"];
|
||||||
d.dirt.loadSoundFiles("/Users/bubo/Library/Application\ Support/Sardine/SON/*");
|
// d.dirt.loadSoundFiles("/Users/bubo/Library/Application\ Support/Sardine/SON/*");
|
||||||
d.dirt.loadSoundFiles("/Users/bubo/.config/livecoding/samples/*");
|
// d.dirt.loadSoundFiles("/Users/bubo/.config/livecoding/samples/*");
|
||||||
d.dirt.doNotReadYet = true;
|
// d.dirt.doNotReadYet = true;
|
||||||
d.dirt.start(57120, [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
|
// 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.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.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.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.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(\midi, MIDIOut.newByName("MIDI", "Bus 1"));
|
||||||
d.dirt.soundLibrary.addMIDI(\midi2, MIDIOut.newByName("MIDI", "Bus 2"));
|
// d.dirt.soundLibrary.addMIDI(\midi2, MIDIOut.newByName("MIDI", "Bus 2"));
|
||||||
s.latency = 0.3;
|
s.latency = 0.3;
|
||||||
|
|
||||||
// Resume normal boot sequence
|
// Resume normal boot sequence
|
||||||
@ -92,8 +92,26 @@ Boot {
|
|||||||
Server.default.avgCPU.round(2),
|
Server.default.avgCPU.round(2),
|
||||||
Server.default.peakCPU.round(2)), 40)
|
Server.default.peakCPU.round(2)), 40)
|
||||||
}, Server.default);
|
}, 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, {
|
Event.addEventType(\buboEvent, {
|
||||||
// This is a custom event that makes it easier to play samples
|
|
||||||
arg server;
|
arg server;
|
||||||
if (~sp.notNil && ~nb.notNil, {
|
if (~sp.notNil && ~nb.notNil, {
|
||||||
~sp = ~sp ?? 'default';
|
~sp = ~sp ?? 'default';
|
||||||
|
|||||||
@ -40,34 +40,59 @@
|
|||||||
/* Syntax for sending MIDI messages */
|
/* Syntax for sending MIDI messages */
|
||||||
>> {
|
>> {
|
||||||
arg pattern;
|
arg pattern;
|
||||||
|
var quant = this.getQuantFromPattern(pattern);
|
||||||
|
var fade = this.getFadeFromPattern(pattern);
|
||||||
pattern = EventShortener.findShortcuts(pattern);
|
pattern = EventShortener.findShortcuts(pattern);
|
||||||
pattern = pattern ++ [type: 'midi'];
|
pattern = pattern ++ [type: 'midi'];
|
||||||
this[0] = Pbind(*pattern);
|
this[0] = Pbind(*pattern);
|
||||||
this.quant = 4; this.fadeTime = 0.01;
|
this.quant = quant;
|
||||||
|
this.fadeTime = fade;
|
||||||
|
this.play;
|
||||||
^this
|
^this
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Player-like syntax sugar */
|
/* Player syntax sugar */
|
||||||
=> {
|
=> {
|
||||||
arg pattern;
|
arg pattern;
|
||||||
|
var quant = this.getQuantFromPattern(pattern);
|
||||||
|
var fade = this.getFadeFromPattern(pattern);
|
||||||
pattern = EventShortener.findShortcuts(pattern);
|
pattern = EventShortener.findShortcuts(pattern);
|
||||||
pattern = pattern ++ [\type, \buboEvent];
|
pattern = pattern ++ [\type, \buboEvent];
|
||||||
this[0] = Pbind(*pattern);
|
this[0] = Pbind(*pattern);
|
||||||
this.quant = 4; this.fadeTime = 0.01;
|
this.quant = quant;
|
||||||
|
this.fadeTime = fade;
|
||||||
|
this.play;
|
||||||
^this
|
^this
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIX: Completely broken. What is the event type
|
/* Audio Looper (sample playback) */
|
||||||
* BuboEvent should fall back to after tweaking
|
== {
|
||||||
* the pattern to my liking?
|
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;
|
arg pattern;
|
||||||
|
var quant = this.getQuantFromPattern(pattern);
|
||||||
|
var fade = this.getFadeFromPattern(pattern);
|
||||||
pattern = EventShortener.findShortcuts(pattern);
|
pattern = EventShortener.findShortcuts(pattern);
|
||||||
// pattern = pattern ++ [\type, \buboMonoEvent];
|
|
||||||
this[0] = Pmono(*pattern);
|
this[0] = Pmono(*pattern);
|
||||||
this.quant = 4;
|
this.quant = quant;
|
||||||
this.fadeTime = 0.01;
|
this.fadeTime = fade;
|
||||||
|
this.play;
|
||||||
}
|
}
|
||||||
|
|
||||||
f {
|
f {
|
||||||
@ -96,4 +121,24 @@
|
|||||||
^this
|
^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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,3 +7,6 @@ c = currentEnvironment.clock;
|
|||||||
// Space for loading custom SynthDefs
|
// Space for loading custom SynthDefs
|
||||||
"Loading SynthDefs...".postln;
|
"Loading SynthDefs...".postln;
|
||||||
"Synthdefs.scd".loadRelative;
|
"Synthdefs.scd".loadRelative;
|
||||||
|
|
||||||
|
// Debug during development
|
||||||
|
// OSCFunc.trace(true);
|
||||||
|
|||||||
@ -53,6 +53,55 @@ d.list = { arg obj; obj.keys.do({arg i; i.postln}); };
|
|||||||
d.splayer = z;
|
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, {
|
z = SynthDef(\sinfb, {
|
||||||
arg out;
|
arg out;
|
||||||
|
|||||||
33
test_breakbeat.scd
Normal file
33
test_breakbeat.scd
Normal 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);
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user