EarSketch - Day 3

Print Return to index

Table of Contents

Musicality Data Structures Questions and Exercises Answers

Musicality

Fills

In popular music, a fill is a short musical passage, riff, or rhythmic sound which helps to sustain the listener's attention during a break between the phrases of a melody. Fills represent the end of a phrase and offer a chance to build in something a little special into a measure. Literally, fills “fill in” space that would otherwise be monotonous (or empty) in a song.

A fill may be played by rock or pop instruments such as the electric lead guitar or bass, or drums, or by other instruments such as strings or horns. In blues or swing-style scat singing, a fill may even be sung. In a hip-hop group, a fill may consist of rhythmic turntable scratching performed by a DJ.

In many musical cases, fills happen on the fourth measure, meaning that three measures are of a standard type and the fourth is the fill. This pattern is called “AAAB.” Using the beat pattern techniques and for loops from yesterday, we can create beats that contain these kinds of fills. Here’s an example of a three measure phrase with a fill at the fourth measure:

from earsketch import *

init()
setTempo(120)

beatPattern = "0-0-0-000+++0-0-"
fillPattern = "0++00++00+0+0000"

drum = DRUM_N_BASS_DRUMS1_4M

for counter in range(1, 13, 4):
	#three measures of a standard pattern
    makeBeat(drum, 1, counter, beatPattern)
    makeBeat(drum, 1, counter + 1, beatPattern)
    makeBeat(drum, 1, counter + 2, beatPattern)
    #one measure of a fill pattern
    makeBeat(drum, 1, counter + 3, fillPattern)

finish()
See this example on the social network

The addition of a fill can add more variety and interest to your music. All other tracks can drop out and the fill can emerge as a stand-alone group of beats. For a different approach, try only changing the track with the fill and leaving all other tracks intact.

Questions and Exercises

  1. Write a script that generates 16 measures of music on at least two tracks and has two different kinds of fills.

Data Structures

By now, you’ve seen that there can be a lot going on in a script. In order to make programming easier, computer scientists have developed data structures. Data structures are used to hold information of various kinds and make manipulating that data easier. Without data structures, storing and manipulating data can quickly become complicated and chaotic. For example, imagine trying to organize books without a bookshelf. Every time you needed to find a book, you would have to rummage through impossible piles of them. In this case, a bookshelf acts as a data structure that holds all of the books in an organized fashion--making them easy to store and to retrieve. With a bookshelf, finding and storing books becomes a very simple and efficient task. The same principle holds true to data when held within a data structure.

Lists

One very useful data structure that we’ll frequently use is called a list. Lists are a way to store many different values under a single variable. Every item in this list is numbered with what’s called the index. By calling the list and passing it a particular index value, a programmer can pull out any item placed into it. Unlike counting things that exist in the real world, index variables always begin with the number 0.

To illustrate how this works, let’s return to the book metaphor from earlier. Imagine that our list is a bookshelf complete with numbered placeholders in which to put books. The numbered placeholders represent index values in the list. An empty list might look something like this:

an empty bookshelf called 'beats'

A list is named just like a variable is, but needs brackets around the items that are being placed in it. These items are separated by a comma as follows:

beats = [HIP_HOP_GUITAR1_2M, HIP_HOP_GUITAR2_4M, HIP_HOP_GUITAR3_4M, HIP_HOP_GUITAR4_4M]

Once the above code is run, our bookshelf list would look something like this:

beats[0] is the first slot in the shelf

Notice that HIP_HOP_GUITAR1_2M is at the 0 index of the list, since it is in the very first slot in the bookshelf.

To refer to a particular item in the list, the list name is followed by the index of the item you want in brackets. Finding the item at an index would be as simple as looking for whatever item is in the corresponding numerical placeholder within our bookshelf:

beats[0]

Running that line by itself will return the current value of that item in the list, in this case HIP_HOP_GUITAR1_2M.

This syntax also works to set any list item’s value directly. For instance, if we want to change the first elements of the list to add some other kind of music into the mix, we might say:

beats[0] = HOUSE_VOICE_4M

After that line is executed, the list would now look like this:

beats = [HOUSE_VOICE_4M,  HIP_HOP_GUITAR2_4M, HIP_HOP_GUITAR3_4M, HIP_HOP_GUITAR4_4M]

And so our bookshelf (and the list itself) reflects the change in the following way:

beats[0] is now different

Finally, list items can be referred to individually using variables. This line of code stores the sound clip at the index 1—the sound HIP_HOP_GUITAR2_4M as the new variable drum2:

drum2 = beats[1]

Lists are very useful within the EarSketch environment. For instance, you can create a list of sound clips or sound folders from which your program chooses for use. With one variable, you can refer to many different files that can be used in your EarSketch composition.

drums = [DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M,
         DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M,
         DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M,
         DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M]

To illustrate, The above code stores a list of EarSketch sound files in the list drums. The list makes it easier to sort files by type, and allows you to choose any of these files simply by referring to its index in the list.

Lists and Randomness

Another way to use lists is with randomness. Python's randint() function can be used to select from a list at a random index. Here’s the 12 measure fill example from before with random drums:

from earsketch import *
from random import randint

init()
setTempo(120)

beatPattern = "0-0-0-000+++0-0-"
fillPattern = "0+--0+--0+0+0000"

for counter in range(1, 13, 4):
    drums = [DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M]
    fills = [ELEKTRO_HOUSE_DRUMS6_2M,
             HIP_HOP_DRUMS1_2M,
             HIP_HOP_JAZZDRUMS1_4M,
             HIP_HOP_JAZZDRUMS2_4M]

    index = randint(0, 3) #remember, lists start at zero!
    drum = drums[index]
    fill = fills[index]
    
    makeBeat(drum, 1, counter, beatPattern)
    makeBeat(drum, 1, counter + 1, beatPattern)
    makeBeat(drum, 1, counter + 2, beatPattern)
    makeBeat(fill, 1, counter + 3, fillPattern)

finish()
See this example on the social network

These techniques can also be used in functions, allowing you to create and call multiple sections very easily. This example refactors the previous one into a function and adds another layer that generates a horn line on top:

from earsketch import *
from random import randint

init()
setTempo(120)

def randomBeat(counter):
    #set up the beat patterns
    beatPattern = "0-0-0-000+++0-0-"
    fillPattern = "0+--0+--0+0+0000"
    
    #get some samples in lists
    drums = [DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M,
             DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M]
    fills = [ELEKTRO_HOUSE_DRUMS6_2M,
             HIP_HOP_DRUMS1_2M,
             HIP_HOP_JAZZDRUMS1_4M,
             HIP_HOP_JAZZDRUMS2_4M]

    #get a random sample every iteration
    index = randint(0, 3) #remember, lists start at zero!
    drum = drums[index]
    fill = fills[index]
    
    #make the beat with random samples
    makeBeat(drum, 1, counter, beatPattern)
    makeBeat(drum, 1, counter + 1, beatPattern)
    makeBeat(drum, 1, counter + 2, beatPattern)
    makeBeat(fill, 1, counter + 3, fillPattern)
    
def hornSection(counter):
    #a stabbing horn pattern as a fill
    horn = "0+++++++-0+0+---"
    
    #a brass section over the drum (with fill)
    fitMedia(DRUM_N_BASS_BRASS_4M, 2, counter, counter+3)
    makeBeat(LATIN_BRASS_2M, 2, counter + 3, horn)
    
# a loop for 12 measures of four measure phrases
for counter in range(1, 13, 4):
    randomBeat(counter)
    hornSection(counter)
    
finish()
See this example on the social network

Questions and Exercises #2

  1. Make a list called myMusic that contains at least 4 samples that you think will work well together. Use for loops and functions (as needed) use the list to create a 12 measure composition with fills.

Lists and Loops

A common implementation of lists is to iterate through each element of the list one by one, start to finish, and to perform some task with each element. This can be achieved by combining lists with loops. A for loop can be given a range corresponding to the length of some list and, by using the for loop index variable to refer to the index of the list, each element within the list can be reached.

The following code goes through a list of four-character beat patterns and combines them in order to form one 16 measure string that can be passed into the makeBeat() function. In addition, it uses a similar set of denser patterns to make a single measure fill string in the same way:

from earsketch import *
from random import randint
 
init()
setTempo(120)
 
beatList = ["-0-0", "0---", "0-0-", "--00",
            "-0--", "0+++", "0--0", "--0+", 
            "-00-", "0+-0", "0-0+", "0+0+",
            "0+00", "000+", "-000", "0000"]
 
fillBeats = ["0000", "-00-", "0+0+", "-000"]
 
#Start with empty strings
beatString = ""
fillString = ""
 
#make four three measure beats from random beatList items
for beat in range(0,16):
      beatString = beatString + beatList[beat]
 
#make a random percussion fill
for beat in range(0, 4):
      fillString = fillString + fillBeats[beat]
       
for measure in range(1, 17, 4):
      #call the makeBeat function for random beats
      makeBeat(DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M, 1, measure, beatString)

      #add the random fill every fourth measure
      makeBeat(AFRO_LATIN_DRUMS12_2M, 2, measure+3, fillString)
       
      #add a little keyboard with fill
      fitMedia(AFRO_LATIN_KEYBOARD1_1M, 3, measure, measure+3)
      insertMedia(AFRO_LATIN_KEYBOARD2_1M, 3, measure+3)
 
finish()
See this example on the social network

This example builds on the previous one, showing how a random beat can be generated that uses the power of looping through lists coupled with the random function learned in Day 1:

from earsketch import *
from random import randint

init()
setTempo(120)

beatList = ["-0-0", "0---", "0-0-", "--00",
            "-0--", "0+++", "0--0", "--0+", 
            "-00-", "0+-0", "0-0+"]

fillBeats = ["0000", "-00-", "0+0+", "-000"]

#Start with empty strings
beatString = ""
fillString = ""

#make a sixty-four beat string from random items of beatList
for beat in range(1, 65):
      index = randint(0, 10)
      beatString = beatString + beatList[index]

#make a random percussion fill string from fillBeats
for measure in range(1, 5):
      index = randint(0, 3)
      fillString = fillString + fillBeats[index]
      
#call the makeBeat function on our new randomly generated beat string
makeBeat(DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M, 1, 1, beatString)
      
for measure in range(1, 17, 4):
      #add the random fill every fourth measure
      makeBeat(AFRO_LATIN_DRUMS12_2M, 2, measure+3, fillString)
      
      #add a little keyboard with fill
      fitMedia(AFRO_LATIN_KEYBOARD1_1M, 3, measure, measure+3)
      insertMedia(AFRO_LATIN_KEYBOARD2_1M, 3, measure+3)

finish()
See this example on the social network

Using lists of samples to make beats

Finally, the makeBeat function itself takes strings to make beats, but these strings are comprised of list indices. This means that its possible to refer to a list of samples and choose the samples that you want to play as a part of a beat string:

drumList = [DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M,
            DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M,
            DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M,
            DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M]

drumPattern = "0+0+11112+2+3+++"

makeBeat(drumList, 1, 1, drumPattern)

This is telling reaper to:

0+ play DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M for one eighth of a measure
0+ do it again
1 play DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M for a first sixteenth
1 play the first sixteenth again
1 and again
1 and again
2+ play DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M for an eighth
2+ do it again
3+++ Play the first quarter beat of DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M

Here' a script that brings all of these techniques together:

from earsketch import *
from random import randint

#create libraries of beat patterns and samples
drumBeats = ["0-0-0-000+++0-0-", "00000-000+++0-0-",
             "0-0-0-0-00000-0-", "0--0--00++00++00"]

drumFills = ["0+--0+--0+0+0000", "0+000000+0000000",
             "0+++0+++----0000", "0+--0+0+0+0+0000"]

bassPattern = "0++0++112+++2+++"
bassFill    = "--------3++-3+++"
hornFill    = "0+++++++-0+0+---"

drums =   [DOWNBEAT_AND_LEFTFIELD_DRUMS1_4M,
           DOWNBEAT_AND_LEFTFIELD_DRUMS2_4M,
           DOWNBEAT_AND_LEFTFIELD_DRUMS3_4M,
           DOWNBEAT_AND_LEFTFIELD_DRUMS4_2M]
    
cymbals = [ELEKTRO_HOUSE_DRUMS6_2M,
           HIP_HOP_DRUMS1_2M,
           HIP_HOP_JAZZDRUMS1_4M,
           HIP_HOP_JAZZDRUMS2_4M]

bass =    [LATIN_BASS1_2M,
           LATIN_BASS3_1M,
           LATIN_BASS4_2M,
           LATIN_BASS5_2M,
           LATIN_BASS6_2M,
           LATIN_BASS7_2M,
           LATIN_BASS8_4M]

brass = DRUM_N_BASS_BRASS_4M
horn = LATIN_BRASS_2M

#funtions to put music sections together
def beatSection(counter, track, pattern, fillPattern):
    #get a random sample every iteration
    index  = randint(0, 3) #remember, lists start at zero!
    
    beat   = pattern[index]
    fill   = fillPattern[index]
    drum   = drums[index]
    cymbal = cymbals[index]
    
    #make the beat with random samples
    for increment in range(0, 3):
        makeBeat(drum, track, counter + increment, beat)
    makeBeat(cymbal, track, counter + 3, fill)
    
def bassSection(counter, track, array, pattern, fillPattern):
    shuffleList(bass)
    for increment in range(0, 3):
        makeBeat(array, track, counter + increment, pattern)
    makeBeat(array, track, counter + 3, fillPattern)
    
def hornSection(counter, track, main, fill, fillPattern):
    #a brass section over the drum (with fill)
    fitMedia(main, track, counter, counter+3)
    makeBeat(fill, track, counter + 3, fillPattern)

init()
setTempo(120)

# a loop for 12 measures of four measure phrases
for counter in range(1, 13, 4):
    beatSection(counter, 1, drumBeats, drumFills)
    bassSection(counter, 2, bass, bassPattern, bassFill)
    hornSection(counter, 3, brass, horn, hornFill)
    
finish()
See this example on the social network

Questions and Exercises #3

Write a script that will use a list of beat pattern components (either single characters or component patterns) to create beat strings randomly.

Answers to Questions and Exercises

Questions and Exercises #1

Possible answer:

from earsketch import *
from random import randint

init()
setTempo(100)

drum = DRUM_N_BASS_DRUMS3_1M
music = ELEKTRO_HOUSE_SYNTH6_2M

beat = "0+0-0+0-0+0-0+0-"
fill1 = "00++00++00++00++"
fill2 = "000--0-0++00--00"

for measure in range(1, 17, 8):
	makeBeat(drum, 1, measure, beat)
	makeBeat(drum, 1, measure+1, beat)
	makeBeat(drum, 1, measure+2, beat)
	makeBeat(drum, 1, measure+3, fill1)
	makeBeat(drum, 1, measure+4, beat)
	makeBeat(drum, 1, measure+5, beat)
	makeBeat(drum, 1, measure+6, beat)
	makeBeat(drum, 1, measure+7, fill2)
	
fitMedia(music, 2, 1, 17)

finish()

Questions and Exercises #2

Possible answer:

from earsketch import *
from random import randint

init()
setTempo(100)

drum = HIP_HOP_DRUMS3_2M
fill = HIP_HOP_DRUMS2_2M

drumBeat = "0+++0+0+0+++0+0+"
fillBeat = "0+0+0-0-0++-0000"

myMusic = [HOUSE_SYNTH2_2M, HIP_HOP_GUITARMELODY2_4M, ELEKTRO_HOUSE_SYNTH6_2M, SOUL_SYNTH1_2M]

for measure in range(1,13,4):
	makeBeat(drum, 1, measure, drumBeat)
	makeBeat(drum, 1, measure + 1, drumBeat)
	makeBeat(drum, 1, measure + 2, drumBeat)
	makeBeat(fill, 1, measure + 3, fillBeat)

for measure in range(1, 13, 4):
    randMusic = randint(0,3)
    fitMedia(myMusic[randMusic], 2, measure, measure+3)

    
finish()

Questions and Exercises #3

Possible answer:

from earsketch import *
from random import randint

init()
setTempo(100)

beatStrings = ["0++0", "0000", "0+0+", "-0-0", "0+00", "--00"]

for measure in range(8):
    one = randint(0,5)
    two = randint(0,5)
    three = randint(0,5)
    four = randint(0,5)
    beatString = beatStrings[one] + beatStrings[two] + beatStrings[three] + beatStrings[four]
    makeBeat(SOUL_DRUMS4_2M, 1, measure, beatString)

fitMedia(SOUL_FLUTE_2M, 2, 1, 8)
    
finish()