Add generic granular sampler
This commit is contained in:
@ -119,5 +119,22 @@ Boot {
|
|||||||
~type = \note;
|
~type = \note;
|
||||||
currentEnvironment.play;
|
currentEnvironment.play;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Event.addEventType(\buboGranular, {
|
||||||
|
arg server;
|
||||||
|
if (~sp.notNil, {
|
||||||
|
if (BuboUtils.stringIsNumber(~sp), {}, {
|
||||||
|
~sp = BuboUtils.cleanSampleName(~sp);
|
||||||
|
~nb = BuboUtils.cleanSampleIndex(~nb);
|
||||||
|
if (~sp !== "", {
|
||||||
|
~buf = Bank(~sp)[~nb % Bank(~sp).paths.size];
|
||||||
|
~instrument = 'grainSampler';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
~type = \note;
|
||||||
|
currentEnvironment.play;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,6 +81,19 @@
|
|||||||
^this
|
^this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Granular Sampler */
|
||||||
|
+=> {
|
||||||
|
arg pattern;
|
||||||
|
var quant = BuboUtils.getQuantFromPattern(pattern);
|
||||||
|
var fade = BuboUtils.getFadeFromPattern(pattern);
|
||||||
|
"Hello granular".postln;
|
||||||
|
pattern = EventShortener.process(pattern, this.key, 'granular', 1);
|
||||||
|
pattern = EffectChain.process(pattern, this.key);
|
||||||
|
this[0] = Pbind(*pattern);
|
||||||
|
this.prepareToPlay(this, quant, fade);
|
||||||
|
^this
|
||||||
|
}
|
||||||
|
|
||||||
/* Pmono player */
|
/* Pmono player */
|
||||||
-> {
|
-> {
|
||||||
arg pattern;
|
arg pattern;
|
||||||
|
|||||||
@ -99,7 +99,4 @@ BuboUtils {
|
|||||||
arg pattern;
|
arg pattern;
|
||||||
^this.getValueFromPattern(pattern, 'fade', 0.01)
|
^this.getValueFromPattern(pattern, 'fade', 0.01)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,10 +25,35 @@ d.list = { arg obj; obj.keys.do({arg i; i.postln}); };
|
|||||||
d.player = z;
|
d.player = z;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Granular Sampler
|
||||||
|
*/
|
||||||
|
(
|
||||||
|
z = SynthDef('grainSampler', {
|
||||||
|
arg out, buf;
|
||||||
|
var sound = GrainBuf.ar(
|
||||||
|
numChannels: buf.numChannels,
|
||||||
|
trigger: Impulse.kr(\grain.kr(4)),
|
||||||
|
dur: 1, sndbuf: buf,
|
||||||
|
rate: \rate.kr(4),
|
||||||
|
pos: \pos.kr(0.0),
|
||||||
|
interp: 2,
|
||||||
|
pan: \pan.kr(0.0),
|
||||||
|
envbufnum: \env.kr(-1),
|
||||||
|
);
|
||||||
|
sound = sound * Env.perc(
|
||||||
|
\attack.kr(0.1), \release.kr(0.5)
|
||||||
|
).kr(2);
|
||||||
|
sound = sound * \amp.kr(-6).dbamp;
|
||||||
|
OffsetOut.ar(out, sound);
|
||||||
|
}).add;
|
||||||
|
d.grainSampler = z;
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stereo variant
|
* Stereo variant
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(
|
(
|
||||||
z = SynthDef.new(\splayer, {
|
z = SynthDef.new(\splayer, {
|
||||||
arg buf, out;
|
arg buf, out;
|
||||||
|
|||||||
@ -3,9 +3,6 @@ EventShortener {
|
|||||||
*process {
|
*process {
|
||||||
arg pattern, key, type, time;
|
arg pattern, key, type, time;
|
||||||
var new_pattern;
|
var new_pattern;
|
||||||
var additionalKeys = Dictionary.newFrom([
|
|
||||||
\looper, [type: \buboLoopEvent, legato: 1, time: time],
|
|
||||||
]);
|
|
||||||
new_pattern = this.findShortcuts(pattern);
|
new_pattern = this.findShortcuts(pattern);
|
||||||
new_pattern = this.functionsToNdef(new_pattern, key);
|
new_pattern = this.functionsToNdef(new_pattern, key);
|
||||||
new_pattern = switch(type,
|
new_pattern = switch(type,
|
||||||
@ -14,6 +11,7 @@ EventShortener {
|
|||||||
'midi', this.patternMidi(new_pattern),
|
'midi', this.patternMidi(new_pattern),
|
||||||
'midicc', this.patternMidiCC(new_pattern),
|
'midicc', this.patternMidiCC(new_pattern),
|
||||||
'looper', this.patternLooper(new_pattern),
|
'looper', this.patternLooper(new_pattern),
|
||||||
|
'granular', this.patternGranular(new_pattern),
|
||||||
);
|
);
|
||||||
^new_pattern
|
^new_pattern
|
||||||
}
|
}
|
||||||
@ -46,12 +44,11 @@ EventShortener {
|
|||||||
^new_pattern
|
^new_pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
*patternBuboEvent {
|
*patternGranular {
|
||||||
arg pattern;
|
arg pattern;
|
||||||
var new_pattern = List();
|
var new_pattern = List();
|
||||||
var sp_position = nil;
|
var sp_position = nil;
|
||||||
var nb_position = nil;
|
var nb_position = nil;
|
||||||
|
|
||||||
// Check if the sp key already exists in the pattern
|
// Check if the sp key already exists in the pattern
|
||||||
if (pattern.includes('sp'), {
|
if (pattern.includes('sp'), {
|
||||||
pattern.do({ arg e, i;
|
pattern.do({ arg e, i;
|
||||||
@ -60,7 +57,6 @@ EventShortener {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if the nb key already exists in the pattern
|
// Check if the nb key already exists in the pattern
|
||||||
if (pattern.includes('nb'), {
|
if (pattern.includes('nb'), {
|
||||||
pattern.do({ arg e, i;
|
pattern.do({ arg e, i;
|
||||||
@ -69,7 +65,64 @@ EventShortener {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
new_pattern = new_pattern ++ [\type, 'buboGranular'];
|
||||||
|
pattern.doAdjacentPairs({ | a, b, index |
|
||||||
|
if (index % 2 == 0, {
|
||||||
|
if (a === 'pat', {
|
||||||
|
var temp = Pmini(b);
|
||||||
|
new_pattern = new_pattern ++ [
|
||||||
|
[\trig, \delta, \dur, \str, \num], Pmini(b),
|
||||||
|
];
|
||||||
|
new_pattern = new_pattern ++ [
|
||||||
|
degree: Pfunc({ |e|
|
||||||
|
if (e.trig > 0, {
|
||||||
|
e.str.asInteger
|
||||||
|
}, {
|
||||||
|
\rest
|
||||||
|
});
|
||||||
|
});
|
||||||
|
];
|
||||||
|
if (sp_position.notNil, {
|
||||||
|
new_pattern = new_pattern ++ [
|
||||||
|
sp: pattern[sp_position + 1],
|
||||||
|
nb: pattern[nb_position + 1],
|
||||||
|
];
|
||||||
|
}, {
|
||||||
|
new_pattern = new_pattern ++ [
|
||||||
|
sp: Pfunc { |e| e.str ? "" },
|
||||||
|
nb: Pfunc { |e| e.num ? 0 }
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
new_pattern = new_pattern ++ [a, b];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
new_pattern.postln;
|
||||||
|
^new_pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
*patternBuboEvent {
|
||||||
|
arg pattern;
|
||||||
|
var new_pattern = List();
|
||||||
|
var sp_position = nil;
|
||||||
|
var nb_position = nil;
|
||||||
|
// Check if the sp key already exists in the pattern
|
||||||
|
if (pattern.includes('sp'), {
|
||||||
|
pattern.do({ arg e, i;
|
||||||
|
if (e == 'sp', {
|
||||||
|
sp_position = i;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Check if the nb key already exists in the pattern
|
||||||
|
if (pattern.includes('nb'), {
|
||||||
|
pattern.do({ arg e, i;
|
||||||
|
if (e == 'nb', {
|
||||||
|
nb_position = i;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
new_pattern = new_pattern ++ [\type, 'buboEvent'];
|
new_pattern = new_pattern ++ [\type, 'buboEvent'];
|
||||||
pattern.doAdjacentPairs({ | a, b, index |
|
pattern.doAdjacentPairs({ | a, b, index |
|
||||||
if (index % 2 == 0, {
|
if (index % 2 == 0, {
|
||||||
|
|||||||
20
README.md
20
README.md
@ -75,6 +75,7 @@ I personally dislike the `Pbind(\qdklsj)` or `Ndef(\qkljsdf)` syntax. The `\` sy
|
|||||||
|
|
||||||
- Operators for creating SuperCollider patterns on-the-fly:
|
- Operators for creating SuperCollider patterns on-the-fly:
|
||||||
- `=>` (Pbind): basic musical pattern
|
- `=>` (Pbind): basic musical pattern
|
||||||
|
- `+=>` (Pbind): granular sampler
|
||||||
- `->` (Pmono): monophonic expression pattern
|
- `->` (Pmono): monophonic expression pattern
|
||||||
- `==>` (Looper): looper/sampler (**WIP**, currently broken)
|
- `==>` (Looper): looper/sampler (**WIP**, currently broken)
|
||||||
- `>>` (Note): MIDI Note Pattern
|
- `>>` (Note): MIDI Note Pattern
|
||||||
@ -216,7 +217,24 @@ This is pitched sample playback. Note that you can also decompose patterns with
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
All the remaining keys in patterns are behaving just like regular SuperCollider patterns.
|
Here is some granular sampling:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
(
|
||||||
|
~test +=> [
|
||||||
|
sp: "casio", nb: [0, 2, 4].pseq(inf), amp: 1,
|
||||||
|
grain: {SinOsc.ar(1/4).range(1,20)},
|
||||||
|
pos: {LFNoise2.kr(1/8).range(0, 0.25)},
|
||||||
|
rate: Pwhite(1, 2, inf)
|
||||||
|
];
|
||||||
|
~test.play;
|
||||||
|
~test.fx(100, 0.5, {
|
||||||
|
arg in; MiVerb.ar(in, time: 0.5);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
All the remaining pattern keys you can think of are behaving just like regular SuperCollider patterns.
|
||||||
|
|
||||||
### Controlling synthesizers
|
### Controlling synthesizers
|
||||||
|
|
||||||
|
|||||||
44
test_granular.scd
Normal file
44
test_granular.scd
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
Boot(
|
||||||
|
samplePath: "/Users/bubo/.config/livecoding/samples"
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
~test +=> [
|
||||||
|
sp: "casio", nb: [0, 2, 4].pseq(inf), amp: 1,
|
||||||
|
grain: {SinOsc.ar(1/4).range(1,20)},
|
||||||
|
pos: {LFNoise2.kr(1/8).range(0, 0.25)},
|
||||||
|
rate: Pwhite(1, 2, inf)
|
||||||
|
];
|
||||||
|
~test.play;
|
||||||
|
~test.fx(100, 0.5, {
|
||||||
|
arg in; MiVerb.ar(in, time: 0.5);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
~test ++> [];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Granular Sampler
|
||||||
|
*/
|
||||||
|
(
|
||||||
|
z = SynthDef('grainSampler', {
|
||||||
|
arg out, buf;
|
||||||
|
var sound = GrainBuf.ar(
|
||||||
|
numChannels: buf.numChannels,
|
||||||
|
trigger: Impulse.kr(\grain.kr(4)),
|
||||||
|
dur: 1, sndbuf: buf,
|
||||||
|
rate: \rate.kr(4),
|
||||||
|
pos: \pos.kr(0.0),
|
||||||
|
interp: 2,
|
||||||
|
pan: \pan.kr(0.0),
|
||||||
|
envbufnum: \env.kr(-1),
|
||||||
|
);
|
||||||
|
sound = sound * Env.perc(
|
||||||
|
\attack.kr(0.1), \release.kr(0.5)
|
||||||
|
).kr(2);
|
||||||
|
sound = sound * \amp.kr(-6).dbamp;
|
||||||
|
OffsetOut.ar(out, sound);
|
||||||
|
}).add;
|
||||||
|
d.grainPlayer = z;
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user