Skip to content

Instantly share code, notes, and snippets.

@Xpktro
Created October 11, 2014 05:30
Show Gist options
  • Save Xpktro/4eba5069d97eec7b1dc0 to your computer and use it in GitHub Desktop.
Save Xpktro/4eba5069d97eec7b1dc0 to your computer and use it in GitHub Desktop.
One of my ChucK experiments
// Our sound chain is quite simple buy nice-sounding.
// The Rhodey instrument (even when not shown in lectures, is
// a STK instrument and meets the evaluation criteria) is a nice
// Rhodes-keyboard-like sound, I love it and now I can use it.
// (you should REALLY hear the ChucK website demo)
Rhodey rho[3];
Pan2 rhoPan[3];
Gain rhoGain => NRev rhoRev => dac;
// I'm using really low gain parameters to avoid distorsion
.14 => rhoRev.gain;
.2 => rhoRev.mix;
.2 => rhoGain.gain;
// Then assign each Rhodey to it's own pan (in a random position)
// and with a random gain to finally chuck them to their master gain.
for(0 => int i; i < rho.cap()-1; i++) {
rho[i] => rhoPan[i] => rhoGain;
Math.random2f(-1., 1.) => rhoPan[i].pan;
Math.random2f(8., 1.) => rho[i].gain;
}
// Our lead voice is... a voice! for the first time, and sound great also.
VoicForm voice => NRev voiceRev => dac;
.5 => voiceRev.gain;
.1 => voiceRev.mix;
0.05 => voice.vibratoGain;
// It must remain silent until we order it to sing.
0 => voice.noteOn;
// Our scale
[49, 50, 52, 54, 56, 57, 59, 61] @=> int notes[];
// And an apparently meaningless variable (see below).
1 => int grade;
// Our timing system, not all variables are used but it's shown if it's
// useful for anyone.
.75::second => dur quarter;
quarter / 2 => dur eighth;
quarter * 2 => dur half;
half * 2 => dur whole;
// possiblyInverse would return a number of a note if it happens to shift
// octaves up (+12) or down (-12) using a random number as a decider.
fun int possiblyInverse(int note) {
Math.random2f(0., 1.) => float chance;
if(chance <= .1) {
note + 12 => note;
} else if(chance <= .2) {
note - 12 => note;
}
return note;
}
// This function would return a possibly inverted chord of
// the give grade for the given scale. Note that the scale
// must have 8 or 8*X notes to get this to work properly.
// (see below for information on what a grade is)
fun int[] getChord(int grade, int scale[]) {
// Grade: 1-7
int base, third, fifth;
scale[grade - 1] => base;
if(grade + 2 >= notes.cap()) {
scale[(grade + 2 - notes.cap())] + 12 => third;
} else {
scale[(grade + 2) - 1] => third;
}
if(grade + 4 >= notes.cap()) {
scale[(grade + 4 - notes.cap())] + 12 => fifth;
} else {
scale[(grade + 4) - 1] => fifth;
}
// Inversions:
possiblyInverse(base) => base;
possiblyInverse(third) => third;
possiblyInverse(fifth) => fifth;
return [base, third, fifth];
}
// This is the heart of the song. Let's talk a little about harmony.
// Chords are made of 3 notes basically: the base (say C), the third,
// which is the *third* note from the base (say E) and the fifht, which
// is the *fifth* note from the base (say G), moving positions would give us
// a series of chords which are numbered from 1 to 7 and are called 'grades'.
// In any *common* song, the notes, grouped by chords, follows some
// kinds of 'recipes', these chord recipes are called progressions.
// The one I'm using is got from http://www.musictheory.net/lessons/57
fun int nextGrade(int prevGrade) {
if(prevGrade == 1) {
return Math.random2(1, 7);
}
if(prevGrade == 5 || prevGrade == 7) {
return 1;
}
if(prevGrade == 4) {
if(Math.random2(0, 1) == 0) {
return 7;
} else {
if(Math.random2(0, 1) == 0) {
return 5;
} else {
return 7;
}
}
}
if(prevGrade == 2) {
if(Math.random2(0, 1) == 0) {
return 5;
} else {
return 7;
}
}
if(prevGrade == 6) {
if(Math.random2(0, 1) == 0) {
return 2;
} else {
return 4;
}
}
if(prevGrade == 3) {
return 6;
}
if(prevGrade == 7) {
return 3;
}
}
// If you saw the forementioned link, you have found that the former function
// was to be used with minor scales, so this is the *major* version of the recipe:
/*fun int nextGrade(int prevGrade) {
// http://www.musictheory.net/lessons/57
if(prevGrade == 1) {
return Math.random2(1, 7);
}
if(prevGrade == 5) {
return 1;
}
if(prevGrade == 7) {
if(Math.random2(0, 1) == 0) {
return 3;
} else {
return 1;
}
}
if(prevGrade == 2 || prevGrade == 4) {
if(Math.random2(0, 1) == 0) {
return 5;
} else {
return 7;
}
}
if(prevGrade == 6) {
if(Math.random2(0, 1) == 0) {
return 2;
} else {
return 4;
}
}
if(prevGrade == 3) {
return 6;
}
}*/
// This function would make the voice sing each 2 eighths
// (a quarter).
fun void voiceSing(int beat, int chord[]) {
if(beat % 2 == 0) {
// We set the voice to sing an octave upper the give frequency.
Std.mtof(chord[Math.random2(0, 2)]) * 2 => voice.freq;
1 => voice.noteOn;
}
}
// We define our beat counter.
0 => int beat;
// Define the ending point of our song.
now + 27::second => time end;
// And repeat while we're not done yet:
while(now < end) {
// Get a new chord based on our current grade.
getChord(grade, notes) @=> int chord[];
// See if the voice will sing.
voiceSing(beat, chord);
// And play our chords with the Rhodey
if(beat % 4 == 0) {
for(0 => int i; i<rho.cap()-1; i++) {
Std.mtof(chord[i]) => rho[i].freq;
1 => rho[i].noteOn;
}
// At the end, we get the next grade in our sequence
// and store it for the next beat.
nextGrade(grade) => grade;
}
// We increment our beat counter.
beat++;
// And let an eighth pass...
eighth => now;
}
// The sad (and very quick) ending of our song consists of
// the Rhodey and the voice playing the main chord.
getChord(1, notes) @=> int chord[];
for(0 => int i; i<rho.cap()-1; i++) {
Std.mtof(chord[i]) => rho[i].freq;
1 => rho[i].noteOn;
}
voiceSing(0, chord);
3::second => now;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment