One for All: Difference between revisions

Xenjacob (talk | contribs)
No edit summary
Xenjacob (talk | contribs)
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
  One for All
by Ryan Stickney
  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)
    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
    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!
    // (digital distortion otherwise...which actually makes some really neat effects, try it!
   
   
    // loop iterates thru the play array, one note entry at a time
    // loop iterates thru the play array, one note entry at a time
    for( 0 => int i; i < play.cap(); i++)
    for( 0 => int i; i < play.cap(); i++)
    {
    {
        // read the array, change the frequency
        // read the array, change the frequency
        play[i][0] * one_one * Math.pow(2, octave_shift) => t.freq;
        play[i][0] * one_one * Math.pow(2, octave_shift) => t.freq;
       
       
        // glissando code
        // glissando code
        // hard-coded to 3 total glisses, because ChucK doesn't
        // hard-coded to 3 total glisses, because ChucK doesn't
        // seem to have any built-in array searching
        // seem to have any built-in array searching
        if( bends[0] == i || bends[1] == i || bends[2] == i )
        if( bends[0] == i || bends[1] == i || bends[2] == i )
        {
        {
            // divides the length of the rhythm of that note
            // divides the length of the rhythm of that note
            // into 366 parts, because, hey, leap year!
            // into 366 parts, because, hey, leap year!
            366 => float rhdiv;
            366 => float rhdiv;
            for( 0 => int j; j <= rhdiv; j++)
            for( 0 => int j; j <= rhdiv; j++)
            {
            {
                // one_one * play[i][0] *
                // one_one * play[i][0] *
                //  Math.pow( (play[i+1][0]/play[i][0]) , j/rhdiv ) => t.freq;
                //  Math.pow( (play[i+1][0]/play[i][0]) , j/rhdiv ) => t.freq;
                // Above code divides the glissando down by equal (logarithmic) steps,
                // Above code divides the glissando down by equal (logarithmic) steps,
                // Doesn't sound 'natural' to me,
                // Doesn't sound 'natural' to me,
                // Let's try equal-frequency steps:
                // 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;
                ((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;
                pulse*play[i][1]/rhdiv => now;
                // I still wasn't happy with it,
                // I still wasn't happy with it,
                // but hey, "Publish or die." -- Rob Scott
                // but hey, "Publish or die." -- Rob Scott
            }
              }
        }
        }
        // this code is executed in non-glissando case
        // this code is executed in non-glissando case
        else {
        else {
            // chucking a duration to now advances time
            // chucking a duration to now advances time
            // by that amount within the shred
            // by that amount within the shred
            pulse*play[i][1] => now;
            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;
    (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>