One for All: Difference between revisions
No edit summary |
trying to add pdf score |
||
Line 1: | Line 1: | ||
[[File:SS01 One for All.pdf|thumb]] | |||
Score in sagittal. | |||
Rough multitrack recording by Jacob Barton, http://oneforall.ytmnd.com | Rough multitrack recording by Jacob Barton, http://oneforall.ytmnd.com | ||
Code tutorial (with assignment for xenharmonic campers) in ChucK (save as a .ck file to use in ChucK): | Code tutorial (with assignment for xenharmonic campers) in ChucK (save as a .ck file to use in ChucK): | ||
<nowiki>/* Sagittal Songbook 01 | <nowiki>/* Sagittal Songbook 01 | ||
One for All | |||
by Ryan Stickney | |||
A four-part round in just intonation, in 11/4 time | A four-part round in just intonation, in 11/4 time | ||
Coded by xenjacob Jan. 2020 | Coded by xenjacob Jan. 2020 | ||
The implementation is basic, and shared in this way both to introduce | The implementation is basic, and shared in this way both to introduce | ||
some basics of ChucK and to illustrate the | some basics of ChucK and to illustrate the | ||
degree of 'grunt work' which may (not must) accompany any work of art. | degree of 'grunt work' which may (not must) accompany any work of art. | ||
ASSIGNMENT FOR XENCAMPERS: | ASSIGNMENT FOR XENCAMPERS: | ||
1. Get this code to work on your setup! Save this text as a .ck file. | 1. Get this code to work on your setup! Save this text as a .ck file. | ||
If you are running miniAudicle, all you have to do then is | If you are running miniAudicle, all you have to do then is | ||
'Start Virtual Machine' and then 'Add Shred'. | 'Start Virtual Machine' and then 'Add Shred'. | ||
2. Try modifying 1/1 pitch and/or tempo (read thru the comments below for how) | 2. Try modifying 1/1 pitch and/or tempo (read thru the comments below for how) | ||
3. Learn the song! | 3. Learn the song! | ||
4. Make a rough recording of yourself singing along to patch. (Change anything, have phun with it) | 4. Make a rough recording of yourself singing along to patch. (Change anything, have phun with it) | ||
5. (Optional) Think up a single alteration that would make this patch | 5. (Optional) Think up a single alteration that would make this patch | ||
'more musical', and send it to xenjacob. No need to know how to code it yourself. | 'more musical', and send it to xenjacob. No need to know how to code it yourself. | ||
The melody line is first encoded as a 2D array corresponding | The melody line is first encoded as a 2D array corresponding | ||
to pitch and rhythm values | to pitch and rhythm values | ||
[[ pitch, rhythm ], ...] | [[ pitch, rhythm ], ...] | ||
This kind of score entry is labor-intensive, but a rather good match to the | This kind of score entry is labor-intensive, but a rather good match to the | ||
Sagittal Songbook project due to the brevity of most of the songs. | Sagittal Songbook project due to the brevity of most of the songs. | ||
Pitches are in JI intervals in relation to the defined 1/1 (notated C) | Pitches are in JI intervals in relation to the defined 1/1 (notated C) | ||
A decimal point in the fraction forces ChucK to do non-integer | A decimal point in the fraction forces ChucK to do non-integer | ||
arithmetic to create a floating-point value (otherwise it will e.g. compute | arithmetic to create a floating-point value (otherwise it will e.g. compute | ||
4/3 as 1 remainder 1 and discard the remainder) | 4/3 as 1 remainder 1 and discard the remainder) | ||
Rhythms are declared in relation to the value of a quarter note, | Rhythms are declared in relation to the value of a quarter note, | ||
assigned here to the value 1 (half note = 2, dotted half = 3, etc.) | assigned here to the value 1 (half note = 2, dotted half = 3, etc.) | ||
*/ | */ | ||
[ | [ | ||
[ 1/1., 2 ], // All | [ 1/1., 2 ], // All | ||
[ 3/2., 2 ], // things | [ 3/2., 2 ], // things | ||
[ 2/1., 1 ], // wing- | [ 2/1., 1 ], // wing- | ||
[ 7/4., 1], // -ed | [ 7/4., 1], // -ed | ||
[ 3/2., 1 ], // are | [ 3/2., 1 ], // are | ||
[ 4/3., 2 ], // made | [ 4/3., 2 ], // made | ||
[ 5/4., 2 ], // for | [ 5/4., 2 ], // for | ||
[ 3/2., 2 ], // jump- | [ 3/2., 2 ], // jump- | ||
[ 2/1., 2 ], // -ing | [ 2/1., 2 ], // -ing | ||
[ 5/2., 1 ], // in- | [ 5/2., 1 ], // in- | ||
[ 9/4., 1 ], // -to | [ 9/4., 1 ], // -to | ||
[ 2/1., 1 ], // the | [ 2/1., 1 ], // the | ||
[ 7/4., 1 ], // sky__ | [ 7/4., 1 ], // sky__ | ||
[ 7/4., 2 ], // (bend) | [ 7/4., 2 ], // (bend) | ||
[ 2/1., 5/3. ], // ____. | [ 2/1., 5/3. ], // ____. | ||
// implementing a rhythmic breath or 'hiccup' at the end of each phrase | // implementing a rhythmic breath or 'hiccup' at the end of each phrase | ||
// equal to two-thirds of a beat. | // equal to two-thirds of a beat. | ||
[ 5/4., 2 ], // Fall- | [ 5/4., 2 ], // Fall- | ||
[ 5/4., 2 ], // -ing | [ 5/4., 2 ], // -ing | ||
[ 4/3., 1 ], // brings | [ 4/3., 1 ], // brings | ||
[ 9/8., 1 ], // no | [ 9/8., 1 ], // no | ||
[ 5/4., 1 ], // di- | [ 5/4., 1 ], // di- | ||
[ 2/1., 2 ], // -sas- | [ 2/1., 2 ], // -sas- | ||
[ 7/4., 2 ], // -ter | [ 7/4., 2 ], // -ter | ||
[ 15/8., 2 ], // when | [ 15/8., 2 ], // when | ||
[ 5/4., 2 ], // you | [ 5/4., 2 ], // you | ||
[ 3/2., 3 ], // can | [ 3/2., 3 ], // can | ||
[ 4/3., 1 ], // fly_ | [ 4/3., 1 ], // fly_ | ||
[ 4/3., 2 ], // (bend) | [ 4/3., 2 ], // (bend) | ||
[ 5/4., 5/3. ], // __. | [ 5/4., 5/3. ], // __. | ||
[ 3/2., 2 ], // Calls | [ 3/2., 2 ], // Calls | ||
[ 2/1., 2 ], // sing | [ 2/1., 2 ], // sing | ||
[ 3/2., 3 ], // birds | [ 3/2., 3 ], // birds | ||
[ 9/8., 2 ], // to | [ 9/8., 2 ], // to | ||
[ 1/1., 2 ], // each | [ 1/1., 2 ], // each | ||
[ 9/8., 1 ], // o- | [ 9/8., 1 ], // o- | ||
[ 5/4., 1 ], // -ther | [ 5/4., 1 ], // -ther | ||
[ 11/8., 1 ], // but | [ 11/8., 1 ], // but | ||
[ 3/2., 1], // who | [ 3/2., 1], // who | ||
[ 2/1., 3 ], // knows | [ 2/1., 3 ], // knows | ||
[ 9/4., 1 ], // why?__ | [ 9/4., 1 ], // why?__ | ||
[ 9/4., 2 ], // __(bend) | [ 9/4., 2 ], // __(bend) | ||
[ 2/1., 5/3.], // ___ | [ 2/1., 5/3.], // ___ | ||
[ 2/1., 4], // Fly- | [ 2/1., 4], // Fly- | ||
[ 7/4., 3 ], // -ing | [ 7/4., 3 ], // -ing | ||
[ 4/3., 2 ], // looks | [ 4/3., 2 ], // looks | ||
[ 3/2., 2 ], // fun; | [ 3/2., 2 ], // fun; | ||
[ 3/2., 4 ], // I'm | [ 3/2., 4 ], // I'm | ||
[ 1/1., 1 ], // will- | [ 1/1., 1 ], // will- | ||
[ 9/8., 1 ], // -ing | [ 9/8., 1 ], // -ing | ||
[ 5/4., 1 ], // to | [ 5/4., 1 ], // to | ||
[ 1/1., 4.+2/3. ] // try. | [ 1/1., 4.+2/3. ] // try. | ||
] @=> float score[][]; // "@=>" is the assignment operator for arrays. | ] @=> float score[][]; // "@=>" is the assignment operator for arrays. | ||
// Since there are only a few glissandi in the score, | // Since there are only a few glissandi in the score, | ||
// let's collect the index #'s of the notes which gliss | // let's collect the index #'s of the notes which gliss | ||
// into an array "bends": | // into an array "bends": | ||
[ 13, 26, 39 ] @=> int bends[]; | [ 13, 26, 39 ] @=> int bends[]; | ||
// one_one will define the 1/1 frequency in Hz | // one_one will define the 1/1 frequency in Hz | ||
// **CHANGE THIS** to try in different keys! | // **CHANGE THIS** to try in different keys! | ||
221 => float one_one; | 221 => float one_one; | ||
// 261.6 is approximately concert C pitch | // 261.6 is approximately concert C pitch | ||
// 240 tunes to electrical hum (in the Americas and Asia anyway) | // 240 tunes to electrical hum (in the Americas and Asia anyway) | ||
// B flat (233) has also been traditionally used in this round. | // B flat (233) has also been traditionally used in this round. | ||
// 'pulse' wil define the time duration of a quarter note | // 'pulse' wil define the time duration of a quarter note | ||
// **CHANGE THIS** to try different tempi! | // **CHANGE THIS** to try different tempi! | ||
556::ms => dur pulse; | 556::ms => dur pulse; | ||
// the :: must separate the numerical value and the duration unit | // the :: must separate the numerical value and the duration unit | ||
// (which can be samp, ms, second, minute, hour, day, or week) | // (which can be samp, ms, second, minute, hour, day, or week) | ||
// PlayScore is a function which will read the score (any score specified | // PlayScore is a function which will read the score (any score specified | ||
// in the same manner, actually), note by note, into | // in the same manner, actually), note by note, into | ||
// a dedicated triangle wave oscillator. | // a dedicated triangle wave oscillator. | ||
// But Wait! | // But Wait! | ||
// Musicality Mod 1 (suggested by Thomas): the ability to play in other registers. | // Musicality Mod 1 (suggested by Thomas): the ability to play in other registers. | ||
// PlayScore will take an additional argument, specifying the number of | // PlayScore will take an additional argument, specifying the number of | ||
// octaves offset (-1 for octave down, 0 for at pitch, 1 for octave up, etc. | // octaves offset (-1 for octave down, 0 for at pitch, 1 for octave up, etc. | ||
fun void PlayScore( float play[][], int octave_shift ) | fun void PlayScore( float play[][], int octave_shift ) | ||
{ | { | ||
TriOsc t => dac; // direct link to the digital audio converter (soundcard) | |||
0.25 => t.gain; // range [0,1] - let's leave room for 4 voices here | |||
// (digital distortion otherwise...which actually makes some really neat effects, try it! | |||
// loop iterates thru the play array, one note entry at a time | |||
for( 0 => int i; i < play.cap(); i++) | |||
{ | |||
// read the array, change the frequency | |||
play[i][0] * one_one * Math.pow(2, octave_shift) => t.freq; | |||
// glissando code | |||
// hard-coded to 3 total glisses, because ChucK doesn't | |||
// seem to have any built-in array searching | |||
if( bends[0] == i || bends[1] == i || bends[2] == i ) | |||
{ | |||
// divides the length of the rhythm of that note | |||
// into 366 parts, because, hey, leap year! | |||
366 => float rhdiv; | |||
for( 0 => int j; j <= rhdiv; j++) | |||
{ | |||
// one_one * play[i][0] * | |||
// Math.pow( (play[i+1][0]/play[i][0]) , j/rhdiv ) => t.freq; | |||
// Above code divides the glissando down by equal (logarithmic) steps, | |||
// Doesn't sound 'natural' to me, | |||
// Let's try equal-frequency steps: | |||
((play[i+1][0] - play[i][0])*one_one/rhdiv*j + play[i][0]*one_one) * Math.pow(2, octave_shift) => t.freq; | |||
pulse*play[i][1]/rhdiv => now; | |||
// I still wasn't happy with it, | |||
// but hey, "Publish or die." -- Rob Scott | |||
} | |||
} | |||
// this code is executed in non-glissando case | |||
else { | |||
// chucking a duration to now advances time | |||
// by that amount within the shred | |||
pulse*play[i][1] => now; | |||
} | |||
} | |||
} | } | ||
PlayScore( score, 0); // Calling the function once will play thru the melody once. | PlayScore( score, 0); // Calling the function once will play thru the melody once. | ||
// See if you can add multiple shreds of this at just the right time to play in round! | // See if you can add multiple shreds of this at just the right time to play in round! | ||
// Try alternating lower and higher octaves! | // Try alternating lower and higher octaves! | ||
/* | /* | ||
// remove lines 169 and 205, AND comment/remove line 165, to unlock... | // remove lines 169 and 205, AND comment/remove line 165, to unlock... | ||
// CHAPTER TWO - Programmed Polyphony | // CHAPTER TWO - Programmed Polyphony | ||
// a function to hang out between successive entries | // a function to hang out between successive entries | ||
fun void waitLine() { | fun void waitLine() { | ||
(22.+2/3.)*pulse => now; | |||
} | } | ||
// to execute functions 'in series', simply call them, as | // to execute functions 'in series', simply call them, as | ||
// to execute 'in parallel', use 'spork~' to create breakoff shreds. | // to execute 'in parallel', use 'spork~' to create breakoff shreds. | ||
// 'spork a shred' > 'fork a thread', good one Ge Wang... | // 'spork a shred' > 'fork a thread', good one Ge Wang... | ||
// the below code initiates five separate shreds | // the below code initiates five separate shreds | ||
// to simulate five round entries | // to simulate five round entries | ||
spork~ PlayScore ( score, 0 ); // first entry | spork~ PlayScore ( score, 0 ); // first entry | ||
waitLine(); | waitLine(); | ||
spork~ PlayScore ( score, 1 ); | spork~ PlayScore ( score, 1 ); | ||
waitLine(); | waitLine(); | ||
spork~ PlayScore ( score, 0 ); | spork~ PlayScore ( score, 0 ); | ||
waitLine(); | waitLine(); | ||
spork~ PlayScore ( score, 1 ); | spork~ PlayScore ( score, 1 ); | ||
waitLine(); | waitLine(); | ||
// now check this out | // now check this out | ||
// for the last entry, we gonna do a 'Meno Mosso' (slower tempo) | // for the last entry, we gonna do a 'Meno Mosso' (slower tempo) | ||
// we change ONE VARIABLE, and all four lines follow! | // we change ONE VARIABLE, and all four lines follow! | ||
// if we had passed the pulse as an argument to each function instead of | // if we had passed the pulse as an argument to each function instead of | ||
// using this sort of global variable, this wouldn't work. | // using this sort of global variable, this wouldn't work. | ||
1.1 *=> pulse; // multiply value of pulse by 1.1 and re-assign | 1.1 *=> pulse; // multiply value of pulse by 1.1 and re-assign | ||
spork~ PlayScore ( score, 0 ); // final entry | spork~ PlayScore ( score, 0 ); // final entry | ||
// now, let the round play out; | // now, let the round play out; | ||
// if the main shred of this script terminated early, | // if the main shred of this script terminated early, | ||
// it would automatically terminate any child shreds still running | // it would automatically terminate any child shreds still running | ||
waitLine(); | waitLine(); | ||
waitLine(); | waitLine(); | ||
waitLine(); | waitLine(); | ||
waitLine(); | waitLine(); | ||
/*</nowiki> | /*</nowiki> |