function setup() {
createCanvas(640, 360);
var synth = new MonoSynth();
synth.playNotes(makeSongOrganized());
}
This example builds on sketch_quickmusic
generating
a song with a more complex, organized structure.
setup() is called by p5 kick off the program.
function setup() {
createCanvas(640, 360);
var synth = new MonoSynth();
synth.playNotes(makeSongOrganized());
}
makeSongOrganized() generates a structured something like
this: A B B'B / A B B' C
Each letter represents a four beat measure. The first and fifth measures are the same, as are the second and sixth and third and seventh.
The measure B'
is a variation on measure B
. Using repetion and
variation makes the song feel more cohesive.
function makeSongOrganized() {
Create an empty song.
var song = [];
makePhrase()
creates a random, 1 measure musical phrase.
We will use it to create the parts of our song.
Generate A
.
var introPhrase = makePhrase();
Generate B
.
var middlePhrase = makePhrase();
Modify B
to create B'
.
var alternatePhrase = quickMusic.shiftPhrase(middlePhrase, -2);
Generate C
.
var concludingPhrase = quickMusic.clonePhrase(middlePhrase);
Modify C
to make sure that the last note is the tonic.
Ending on the tonic usually sounds good.
concludingPhrase[concludingPhrase.length - 1][0] = 0;
concat
appends one array to another.
Here we use concat
to add each phrase to the array.
Notice that we can add multiple phrases, and add a phrase
more than once.
song = song.concat(
introPhrase,
middlePhrase,
alternatePhrase,
middlePhrase,
introPhrase,
middlePhrase,
alternatePhrase,
concludingPhrase
);
console.log("hello");
This will “impose” the phrase into C-minor and return the finished song.
return quickMusic.imposePhrase(song, quickMusic.nameToMIDI("C", 3), quickMusic.scales.minor);
}
makePhrase() generates a single measure of music It picks notes by walking up and down the scale. It picks note lengths at random, being careful that the total length works out to 1.0
function makePhrase() {
Start with an empty phrase.
var phrase = [];
Choose a random position in the scale to start the phrase.
var position = floor(random(7));
lengthLeft
will keep track of how much time is left in the measure.
It starts at 1.
var lengthLeft = 1;
Keep adding notes until we have 1 measure.
while (lengthLeft > 0) {
Choose how far to walk up/down the scale at random from a set.
position += sample([-2, -1, -1, -1, 0, 1, 1, 1, 2]);
Choose note length at random from the set.
var length = sample([1 / 2, 1 / 4, 1 / 4, 1 / 4, 1 / 8, 1 / 8]);
Make sure that our notes length won’t make our measure too long.
length = constrain(length, 0, lengthLeft);
Add the note (or a rest).
if (random() < 0.2) {
phrase.push(["rest", length]);
} else {
phrase.push([position, length]);
}
Remove the length of the note we just added from lengthLeft
so we know
how much more time to fill.
lengthLeft -= length;
}
Return the phrase to the caller.
return phrase;
}
sample() recieves and array, selects an item in the array randomly, and returns it
function sample(a) {
return a[floor(random(a.length))];
}