Skip to content

Instantly share code, notes, and snippets.

@zeffii
Forked from anonymous/ModCarp.ck
Created December 18, 2013 11:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zeffii/8021115 to your computer and use it in GitHub Desktop.
Save zeffii/8021115 to your computer and use it in GitHub Desktop.
tb = [54, 0,55,54,61,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66, 0,64,66,61, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0,
54, 0,55,54,61, 0,66, 0,64]
expander = lambda i: [i, 300] if i > 0 else [0,0]
tkm = [expander(i) for i in tb]
print(tkm)
Machine.add(me.dir() + "/WaveformMixerMono.ck");
Machine.add(me.dir() + "/PolyWaveForm.ck");
Machine.add(me.dir() + "/PolySynth.ck");
Machine.add(me.dir() + "/ModCarp.ck");
Machine.add(me.dir() + "/score.ck");
12::second => now;
// gist -m
public class ModCarp {
Mix2 out;
Chorus manCh_left => out.left;
Chorus manCh_right => out.right;
manCh_left.modDepth(0.04);
manCh_left.modFreq(.42);
manCh_right.modDepth(0.08);
manCh_right.modFreq(0.64);
int note, attack, decay;
float vol;
fun void play(int note, float vol, int attack, int decay){
note => this.note;
vol => this.vol;
decay => this.decay;
attack => this.attack;
spork ~ splay();
}
fun void splay(){
// new object for each note? are we wasteful or what? :)
StifKarp arper => LPF knight =>
ADSR madsr => manCh_left;
madsr => manCh_right;
Step s => ADSR filterEnv => blackhole;
arper.noteOn(vol);
filterEnv.keyOn();
filterEnv.set( attack::ms, (decay*1.2)::ms, 0.0, 0::ms ); //a, d, s, r
madsr.keyOn();
madsr.set( attack::ms, (decay*1.02)::ms, 0.00, 0::ms ); //a, d, s, r
note -12 => Std.mtof => float note_freq => arper.freq;
knight.Q(.827);
now => time start;
while(now < start + (attack+decay)::ms){
filterEnv.last() * 2699 + 799 => knight.freq;
20::ms => now;
}
}
}
public class PolySynth{
// use this to hook up to externally.
Mix2 out;
float max_filter, max_q;
float continual;
int notes[];
// some default values for these envelope params.
2 => int volume_attack;
300 => int volume_decay;
2 => int filter_attack;
300 => int filter_decay;
// for big changes
fun void set_envelopes(int va, int vd, int fa, int fd){
va => this.volume_attack;
vd => this.volume_decay;
fa => this.filter_attack;
fd => this.filter_decay;
}
fun void play_synth(int notes[], float max_filter, float max_q, float continual){
notes @=> this.notes;
max_filter => this.max_filter;
max_q => this.max_q;
continual => this.continual;
spork ~ splay_synth();
}
fun void splay_synth(){
PolyWaveForm synth;
synth.set_gain(0.21);
LPF lpf1[2];
synth.sum_waveforms.left => lpf1[0];
synth.sum_waveforms.right => lpf1[1];
ADSR vEnv[2];
lpf1[0] => vEnv[0] => out.left;
lpf1[1] => vEnv[1] => out.right;
for(0 => int i; i<2; i++){
// yeah, there's no consideration for sustain in this machine
vEnv[i].set( volume_attack::ms, volume_decay::ms, 0.0, 0::ms ); //a, d, s, r
vEnv[i].keyOn();
}
now => time start;
volume_attack::ms + volume_decay::ms => dur attack_decay;
(start + attack_decay) => time end;
// frequency filter envelope
Step s => ADSR fEnv => blackhole;
fEnv.set( filter_attack::ms, filter_decay::ms, 0.0, 0::ms );
fEnv.keyOn();
synth.play_chord(notes, continual);
// filter envelope, this loop passes time and adjusts the
// filter frequency every iteration using the value of fEnv.last()
// at that time.
float real_filter;
while (now <= end){
for(0 => int i; i<2; i++){
fEnv.last() * max_filter => real_filter;
real_filter => lpf1[i].freq;
max_q => lpf1[i].Q;
}
2::ms => now;
}
fEnv.keyOff();
for(0 => int i; i<2; i++){
vEnv[i].keyOff();
}
}
}
public class PolyWaveForm{
// this will act as the master out gain control
.4 => float max_gain;
Mix2 sum_waveforms;
sum_waveforms.gain(max_gain);
// defaults to a mono synth.
1 => int polyphony;
max_gain / polyphony => float voice_volume;
WaveformMixerMono bloop[polyphony];
Pan2 pan_array[polyphony];
fun void set_gain(float mgain){
mgain => this.max_gain;
sum_waveforms.gain(mgain);
}
// sets all the waveforms at once,
// it might be nice to offer the option to set them indivually
fun void waveform_mix(float continual){
for(0 => int i; i<this.polyphony; i++){
this.bloop[i].mixer2(continual);
}
}
fun void play_chord(int notes[], float continual){
// check if number of notes has change, an rewire if it has
if (!(notes.cap() == polyphony)){
set_polyphony(notes);
}
waveform_mix(continual);
set_voice_volume(notes.cap());
for(0 => int n; n<notes.cap(); n++){
notes[n] => Std.mtof => this.bloop[n].freq;
}
}
fun void set_voice_volume(int polyphony){
this.max_gain / this.polyphony => this.voice_volume;
}
fun void set_polyphony(int notes[]){
if (notes.cap() <= 1) 1 => this.polyphony;
else notes.cap() => this.polyphony;
// this could be optimized by only adding elements if polyphony increases
// and .clear() on the array and build a new one if polyphony decreases
WaveformMixerMono bloop[this.polyphony] @=> this.bloop;
Pan2 pan_array[this.polyphony] @=> this.pan_array;
for(0 => int n; n<notes.cap(); n++){
this.bloop[n].mixer2(2.3);
this.bloop[n].final => this.pan_array[n] => this.sum_waveforms;
this.bloop[n].final.gain(this.voice_volume);
((((n%2)*2)-1)*0.9) => this.pan_array[n].pan;
}
}
}
// gist -m
PolySynth polysynBass;
PolySynth polysynArp;
PolySynth polysynLead;
ModCarp carper;
carper.out => dac;
NRev reverb_bass[2];
reverb_bass[0].mix(0.013);
reverb_bass[1].mix(0.013);
polysynBass.out.gain(1.5);
polysynBass.out.left => DelayA bassD => reverb_bass[0] => dac.left;
polysynBass.out.right => reverb_bass[1] => dac.right;
123::samp => bassD.delay => bassD.max;
NRev reverb_arp[2];
reverb_arp[0].mix(0.07);
reverb_arp[1].mix(0.07);
polysynArp.out.gain(.31);
polysynArp.out.left => reverb_arp[0] => dac.left;
polysynArp.out.right => DelayA arpD => reverb_arp[1] => dac.right;
223::samp => arpD.delay => arpD.max;
NRev reverb_lead[2];
reverb_lead[0].mix(0.21);
reverb_lead[1].mix(0.21);
polysynLead.out.gain(.41);
reverb_lead[0].gain(0.11);
reverb_lead[1].gain(0.11);
polysynLead.out => Mix2 leadgain => dac;
leadgain.gain(0.6);
Chorus pads[2];
polysynLead.out.left => pads[0] => reverb_lead[0] => dac.left;
polysynLead.out.right => pads[1] => DelayA leadD => reverb_lead[1] => dac.right;
143::samp => leadD.delay => leadD.max;
for(0 => int i; i<pads.cap(); i++){
pads[i].gain(21.2);
pads[i].modFreq(0.25 + i*0.032);
pads[i].modDepth(.052 + i*0.014);
}
[1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0] @=> int pseq[];
[0, 52, 54, 55] @=> int arp_1_notes[];
[0, 50, 52, 53] @=> int arp_2_notes[];
[2,0,3,2,2,3,2,2,3,2,2,2,1,2,2,3,2,0,3,2,2,3,2,2,3,2,2,2,1,2,2] @=> int arp_1_triggers[];
[42, 40, 43] @=> int bass_notes[];
// this is mighty ugly, but it allows each note to have a unique decay length.
[[54, 500], [0, 0], [55, 300], [54, 300], [61, 2300],
[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
[66, 600], [0, 0], [64, 500], [66, 200], [61, 3100],
[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
[54, 350], [0, 0], [55, 300], [54, 360], [61, 370], [0, 0], [66, 300], [0, 0], [64, 5300]
] @=> int lead_notes_1[][];
[[54, 500], [0, 0], [55, 300], [54, 300], [61, 2300],
[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
[66, 600], [0, 0], [64, 500], [66, 200], [61, 3100],
[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
[54, 350], [0, 0], [55, 300], [54, 360], [61, 370], [0, 0], [66, 300], [0, 0], [67, 5300]
] @=> int lead_notes_2[][];
// INTRO
repeat(1){
polysynArp.set_envelopes(2, 217, 2, 1410);
spork ~ play_lead(lead_notes_1);
spork ~ play_arp(arp_1_notes, arp_1_triggers);
spork ~ play_bassline(bass_notes[0], pseq, 0, 32);
advance_time(32);
spork ~ play_arp(arp_2_notes, arp_1_triggers);
spork ~ play_bassline(bass_notes[1], pseq, 0, 32);
advance_time(32);
spork ~ play_lead(lead_notes_2);
spork ~ play_arp(arp_1_notes, arp_1_triggers);
spork ~ play_bassline(bass_notes[0], pseq, 0, 32);
advance_time(32);
spork ~ play_arp(arp_1_notes, arp_1_triggers);
spork ~ play_bassline(bass_notes[2], pseq, 0, 32);
advance_time(32);
}
fun int to_int(float input){
input $ int => int output;
return output;
}
// lead
fun void play_lead(int sequence[][]){
int tnote;
for(0 => int i; i<sequence.cap(); i++){
sequence[i][0] => int tval;
if (tval > 0) {
tval + 12 => tnote;
sequence[i][1] => int decay;
polysynLead.set_envelopes(42, decay, 22, to_int(decay*1.3));
polysynLead.play_synth([tnote, tnote], 7500.0, 2.9, 2.1);
}
advance_time();
}
advance_time(25);
}
fun void play_bassline(int note, int triggers[], int start, int end){
// extra insurance
if (end > triggers.cap()) triggers.cap() => end;
for(start => int i; i<end; i++){
if ( triggers[i] == 1){
polysynBass.play_synth([note, note], 1500.0, 2.9, 1.2);
}
advance_time();
}
}
fun void play_arp(int notes[], int triggers[]){
for(0 => int i; i<triggers.cap(); i++){
triggers[i] => int trigval;
if (trigval > 0) {
notes[trigval] + 12 => int note_val;
(notes[trigval] * 90) => float filter_from_freq;
polysynArp.play_synth([note_val,note_val], filter_from_freq+1100.0, 5.2, 2.4);
carper.play(note_val, 0.5, 2, 140);
}
advance_time();
}
}
// overloading, careful.
fun void advance_time(int num_units){
(0.13::second * num_units) => now;
}
fun void advance_time(){
0.13::second => now;
}
public class WaveformMixerMono{
SinOsc vsin => Gain final;
SawOsc vsaw => final;
TriOsc vtri => final;
PulseOsc vpls => final;
Noise vnse => final;
440 => float frequency;
fun void pwidth(float pw){
pw => this.vpls.width;
}
fun void freq(float frequency){
frequency => this.frequency;
vsin.freq(frequency);
vsaw.freq(frequency);
vtri.freq(frequency);
vpls.freq(frequency);
}
fun void mixer(float components[], float mgain){
mixer(components);
mgain => this.final.gain;
}
fun void mixer2(float continual){
// continual range is 0.0 to 8.0
// goes from (sin, saw, tri, pulse to noise)
float mix_comp[];
if (continual >= 7.9996) [0.0, 0.0, 0.0, 0.0, 1.0] @=> mix_comp;
else if (continual <= 0.0001) [1.0, 0.0, 0.0, 0.0, 0.0] @=> mix_comp;
else {
continual => float j;
Math.floor(j/2.0) $ int => int k;
k*2 => int k2;
((j - k2) / 2.0) => float n;
mix_arrays(k, n) @=> mix_comp;
}
mixer(mix_comp);
}
fun void mixer(float components[]){
// set defautls, just in case -- make it a SinOsc
if (!(components.cap() == 5)) {
[1.0, 0.0, 0.0, 0.0, 0.0] @=> components;
}
float summer;
for(0 => int i; i<components.cap(); i++){
components[i] +=> summer;
}
if (summer <= 0.0) {
<<< "no sound!" >>>;
0.0 => this.vsin.gain;
0.0 => this.vsaw.gain;
0.0 => this.vtri.gain;
0.0 => this.vpls.gain;
0.0 => this.vnse.gain;
}
else{
components[0] / summer => this.vsin.gain;
components[1] / summer => this.vsaw.gain;
components[2] / summer => this.vtri.gain;
components[3] / summer => this.vpls.gain;
components[4] / summer => this.vnse.gain;
}
}
fun float fixmin(float fin){
if (fin < 0.0001) return 0.0;
else return fin;
}
fun float[] mix_arrays(int idx, float amount){
[0.0, 0.0, 0.0, 0.0, 0.0] @=> float final_mix[];
(1-amount) => fixmin => final_mix[idx];
(amount) => fixmin => final_mix[idx+1];
return final_mix;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment