GGC
ES
GTCMT

1. Chapter One: Getting Started

1.1. Programming basics

Computers are programmable machines that process information by manipulating data. As the data can represent any real world information, and programs can be readily changed, computers are capable of solving many kinds of problems.

Programs are created in a programming language by writing a series of instructions into a text file. The basic unit of a program is called a statement. As the name indicates, a statement is simply a command for the computer. It instructs the computer to do something. For example, the line

1
setTempo(120)

instructs the computer to set the tempo of a song to 120 beats per minute, about the tempo of an average pop song. A collection of statements is called a block. A block can be stored and reused as a function.

The files containing the program (source) code are translated into executable applications or software. Most programs are intended to serve as interactive tools for customers referred to as users. Users interact with programs in many ways including:

  • Text user interfaces using the keyboard and a console.

  • Graphical user interfaces (GUI) using a keyboard, mouse, monitor, touch screen, …​

  • Audio user interfaces using speakers and/or a microphone.

  • Combinations of all of the above along with emerging technologies like brain wave interfaces, 3D printers, virtual reality headsets, bio implants, …​

1.2. Programming Languages and Environments

There are many different programming languages for programmers to choose from. Each language has its own advantages and disadvantages, and new languages gain popularity while older ones slowly lose ground. In this book, we use the Python 2.7 programming language. It is popular in both academia and industry and was designed with education in mind.

There are many different environments where a programmer may write and test Python. We will utilize a few different environments throughout the semester, but we will start with 2 web-based environments: PythonTutor and EarSketch.

1.3. PythonTutor

PythonTutor is an environment for creating very short and simple Python programs and visualizing their execution. This enables beginners to visually see the data as it gets manipulated by the instructions.

PythonTutor Example 1.1

Simple Program

Use the Forward button to step through the program below and watch the data get created and modified. Notice how the arrows move to indicate what instruction the program execution is on.

1.4. Introduction to EarSketch

EarSketch is a DAW (Digital Audio Workstation) that allows users to create music using Python. It has built-in sound clips made by professionals in the music industry for users to mix and combine into novel musical compositions. Instead of providing a GUI interface for users (such as Garageband from Apple), Earsketch provides an IDE (integrated development environment) where users can write Python code to create music. EarSketch runs in a web browser without installing any additional software. Earsketch currently supports Firefox, Chrome, and Safari. (Internet Explorer is not supported.)

Running a script

A typical EarSketch script follows the template below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Author: A User
# A simple EarSketch script

from earsketch import *

init()
setTempo(120)

# Your code goes here
insertMedia(ELECTRO_DRUM_MAIN_BEAT_008,1,1)

finish()

Click the link below to open this script in EarSketch.

In EarSketch, press the green "Run" button above the code editor. Then press the green play button to listen to the music produced by the code.

Rhythm and Tempo

“Rhythm describes how the music moves through time as a series of notes of different lengths. These rhythms reference a song’s beat, which is a steady pulse that serves as the basic unit of time in music. If you have ever clapped along to a song, you were probably clapping to the beat. Beats can be divided into sub-beats and they can be grouped into measures.”

So how long does a beat last? The length depends on the overall speed of the song, called the tempo. Tempo is measured in beats per minute (bpm). If we are clapping at 60 bpm, then each beat lasts one second. At 120 bpm, each beat takes half a second. The higher the bpm, the faster the song, the shorter the duration of each beat.

Beats are grouped into measures, with the same number of beats in each measure. In EarSketch, measures always have four beats. You may have noticed above that you can clap along to a song in quite a few ways that seem to fit. For example, if you clap once every 4 beats, you are clapping once every measure.

rhythm
Figure 1. This diagram shows the relationship between measures, beats, and subdivisions.

The EarSketch Workspace

Here are the different sections of the EarSketch workspace:

Accounts (top right): Log in, create an account, or reset your password.

Sound Browser: Browse or search 4000 sound clips to use in your music, made by musicians/producers Young Guru and Richard Devine. You can also record your own sounds or upload sound files from your computer.

Scripts Browser: When you write code in EarSketch, your scripts are automatically saved to the EarSketch server. Go here to find your saved scripts, open them, export them as WAV or MP3 sound files, and share them with others.

Share Browser: When you open an EarSketch script shared with you by someone else, this will show you information about the script and additional options.

API Browser: Information on every EarSketch function.

Digital Audio Workstation (DAW): A timeline view of your current song, showing which sound clips you have added to the song and when they come in. It lets you hear your song, and also visualize its structure.

Code Editor: A text editor with numbered lines. Type your code here, press "Run", and it will turn into music in the DAW.

Console: The console displays important information about your code as it runs, including the location of errors in your code. It is a common and important feature in programming tools.

The DAW in Detail

Take a look at the DAW. The DAW consists of several items:

Playhead: The red line, which represents your playback location in the timeline. The play button will start playback at the playhead’s location.

Transport Controls: The buttons at the top right of the DAW. You’ve probably seen most of these in a media player like iTunes. From left to right, the buttons are:

  • Play/Pause: Press this to hear the music you’ve added. Playback begins at the playhead.

  • Reset: Press to jump the playhead back to the beginning.

  • Loop: When the playhead reaches the end of the timeline, automatically start playing from the beginning again.

Toggle Metronome: Play a click track over your music.

Measure Numbers: At the top of the DAW timeline, there is a horizontal series of numbers. If this were a normal timeline, the numbers would represent minutes and seconds; however, here they represent measure numbers. A measure is a unit of musical time that depends on the speed (a.k.a.tempo) of a song. The tempo has to be specified in every script. For now, think of a measure as a block of time. This is how we tell EarSketch where to place our sound clips. Click on a measure number to move the playhead to it.

Sound Clips: If you have added music to the DAW, the DAW should display some boxes with squiggly lines inside. These are sound clips. They provide a visual representation of the sounds they contain.

Tracks: Every sound clip is placed on a specific track. Tracks are the rows that run across the DAW; they are numbered on the left. Tracks help you organize your sounds by instrument-type: for example, in a recording studio you would record each instrument (vocals, lead guitar, rhythm guitar, bass, drums, etc.) on a separate track. You can only have one sound clip at a given time on each track, so having multiple tracks also means you can overlap them.

Effects Toggle: Show or hide the effects added on each track, if you have any. Note that the effects will still play back; the toggle is just for visuals.

Solo/Mute: Next to each track number, the "S" and "M" stand for solo and mute. Mute turns off playback for that track, and Solo turns off playback for all other tracks.

1.5. EarSketch Chapter Projects

Each Chapter (except this one) will end with an EarSketch project which will allow you to create your own musical composition from scratch. The program will need to use the relevant concepts from the chapter. Peers will provide feedback both on how the music sounds and how the code looks.

2. Chapter Two: Data Types, Variables, and Expressions

2.1. Comments

Program files can contain source code and comments. Comments are not instructions for the computer to follow, but instead notes for programmers to read. Comments in Python start with a pound sign (#). Anything following the pound sign, on the same line, will not be executed. Often, at the very beginning of a program, comments are used to indicate the author and other information. Comments are also used to explain tricky sections of code or disable code from executing.

1
2
3
4
5
6
# This line is not Python code, it is a comment.

setTempo(120) # sets beats per minute.

# The next line of code is disabled because is starts with a #.
# setTempo(480)

2.2. Importing a module

At the beginning of many Python programs, there will be statements which use the import keyword. These statements enable the program to use specific functions contained in a module. For example, all EarSketch programs begin with the line of code below.

1
from earsketch import *

Once this line is executed, the entire application programming interface (API) of EarSketch is enabled. This allows the program to use functions like init(), setTempo(), and insertMedia(). Function calls are covered in more detail in Chapter 3.

2.3. Data Types

Programming is all about information processing. Information is categorized by data types. Three basic data types are int (integer), float, and string. Integers are whole numbers (without a decimal point). Floats are numbers that include decimal places. Strings are text (sequences of characters) including punctuation, symbols, and whitespace. Every value in Python has a corresponding data type. The table below shows examples of ints, floats, and strings.

Table 1. Basic Data Types
Data Type Example Values

int

2, -2, 0, 834529

float

2.0, -2.235, 0.0, 8329.123782

string

"Hello World!", 'Coconut', "0", '4 + 6'

Strings and Quotes

Strings are always surrounded by quotes. Python allows either single (') or double(") quotes. Some strings may look like numbers, but as long as they are surrounded by quotes, they are treated like text.

Examples of Data Types in EarSketch

In music, numeric data types can be used to define the tempo of a song (e.g. 120 beats per minute), a length of a section of music (e.g. 4 measures), or parameters such as volume or effects levels (e.g. 6 decibels). Some numbers such as effects levels are best represented as floats (e.g. 0.5 mix of an effect). Strings can be be used to refer to the name of a sound clip (e.g. "OS_CLAP04") or an effect (e.g. "VOLUME").

2.4. Variables

Variables are (virtual) boxes that store values for reuse later. A variable has a name and a current value. Each variable can only hold one value at a time. Variables are assigned a value using the single equal sign (=). As Python executes one line at a time, variables come into existence on the line where they are first assigned.

PythonTutor Asg. 2.1

Basic Variables and Data Types

Use the Forward button to step through the program below and watch the variables get created.

Variable Names

Variables can have complex names like player1_score. In general, never start a variable name with numbers, and never use spaces.

EarSketch Example 2.1

Basic Variables and Data Types

In this EarSketch script, the variables tempo, start, track, and clip store int and string values which control the speed and timing of a sound clip.

Experiment with changing the values of the variables and see what happens. Each time you change a variable’s value, press run again, and then play again, to hear how the music changes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from earsketch import *

init()

tempo = 120
track = 1
start = 1
clip = "YG_HOUSE_PERC_1"

setTempo(tempo)

insertMedia(clip,track,start)

finish()
GGCVariables
DAW for EarSketch Example 2.1

EarSketch Asg. 2.1

Basic Variables and Data Types

Replace the question marks in the code below with the values necessary to match the screenshot below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from earsketch import *

init()
tempo = 120
setTempo(tempo)

clip1 = "ELECTRO_DRUM_MAIN_BEAT_001"
clip1_track = ????
clip1_start = ????

clip2 = "ELECTRO_ANALOGUE_BASS_001"
clip2_track = ????
clip2_start = ????

insertMedia(clip1, clip1_track, clip1_start)
insertMedia(clip2, clip2_track, clip2_start)

finish()
GGC2 1
DAW for EarSketch Asg. 2.1

2.5. Operators and Expressions

Python supports many operators including the standard numeric operators (+ - * /), the remainder operator (%) for integer division, and others. Different operators do different things depending on the data types used. For example, + does addition for ints, but concatenation for strings. Operators, values, and existing variables combine to form expressions. Play with the program below and learn how to predict the return value of expressions. Can you explain how Python divides floats versus integers?

PythonTutor Asg. 2.2

Operators and Expressions

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

Expression Evaluation

When Python encounters a line with an expression, it always evaluates the expression first.

x = (3 + 4) * 2

Python first calculates the return value of the expression by using the standard order of operations and starting inside the parentheses. Then, Python creates the variable and stores the return value (14). The variable only stores the returned value, not the entire expression.

EarSketch Example 2.2

Operators and Expressions

In this EarSketch code, expressions are used to calculate new variables from existing variables.

Imagine you know you want to start a sound clip 17 beats into a song. In order to do this, you need to convert beats into measures, since insertMedia() requires a starting measure. We know that there are 4 beats in a measure, so we divide the number of beats by 4 to get the correct starting measure number. The code below shows how to do this in Python. Notice that we are using the float value 4.0 because the answer is not an integer.

1
2
3
startingBeat = 17

startingMeasure = startingBeat / 4.0

2.6. Modifying Variables

As you might expect, variables can have their values changed. As a variable can only hold 1 value at a time, the previous value of the variable gets erased when a new value is stored. The single equal sign (=) stores a new value in a variable. The += increments a variable by doing a + operation on the previously stored value.

PythonTutor Asg. 2.3

Modifying Variables

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Example 2.3

Modifying Variables

In this EarSketch code, the start variable is modified using the += operator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from earsketch import *

init()

tempo = 120

setTempo(tempo)

track = 1
start = 1
insertMedia("Y02_GUITAR_1",track,start)

start += 4
insertMedia("Y01_GUITAR_1",track,start)

finish()
GGCModifyVars
DAW for EarSketch Example 2.3

EarSketch Asg. 2.2

Modifying Variables

Replace the question marks in the code below with increment (+=) statements to modify the track and start variables. Use the screenshot below to determine the correct values.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from earsketch import *

init()

tempo = 120

setTempo(tempo)

track = 1
start = 1
insertMedia("RD_POP_ARPBASS_2",track,start)

????
????
insertMedia("RD_POP_BRIGHTLEAD_5",track,start)

????
????
insertMedia("RD_POP_MAINBEAT_13",track,start)

????
????
insertMedia("RD_POP_KEYPLUCK_2",track,start)

????
????
insertMedia("RD_POP_ARPBASS_4",track,start)

????
????
insertMedia("RD_POP_MAINBEAT_8",track,start)

finish()
GGC 2 2
DAW for EarSketch Asg. 2.2

2.7. Constants

Some Python modules come with pre-defined variables that can be used at anytime. These are referred to as constants and should never be modified.

PythonTutor Example 2.1

Constants

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Example 2.4

Constants

Every sound clip and effect name has already been saved as a constant in the EarSketch library. Instead of using strings in the insertMedia() function, you can use the equivalent constant, which is simply the string without the quotes. A list of every sound clip constant in EarSketch can be found in the Sound Library (see the next section for details).

In the example below, one insertMedia() call uses the string (with quotes) while the other uses the constant (without quotes). In general, we recommend you use the constants instead of the strings to keep the code looking cleaner.

1
2
3
4
5
6
7
8
9
from earsketch import *

init()
setTempo(120)

insertMedia("Y01_GUITAR_1",1,1)
insertMedia(Y01_DRUMS_1,2,1)

finish()
GGCConst
DAW for EarSketch Example 2.4

2.8. Using The EarSketch Sound Library

To find sound clips that work well together in your music, choose them from the same folder. For example, pick all your sounds from DUBSTEP_140_BPM or all of them from Y30_68_BPM_B_MINOR.

To hear a sound clip, click the play button next to its name. To use a sound clip in EarSketch, click the paste button to paste the sound’s constant into your script at the current cursor position. To help you find sound clips, you can search by keyword and you can filter by artist, genre, and instrument.

As you get more comfortable creating music with EarSketch, you may want to experiment some more by combining sound clips from several different folders in the same song and by trying out different tempos. When experimenting, use your musical ear to help you decide what sounds good and what doesn’t, and try a bunch of different possibilities to figure out what you like best.

2.9. Chapter 2 Project

Based on the examples above or any other source, make any song you want with EarSketch. Make sure it is called Chap2Proj and has at least 15 seconds. Your peers will listen to the song and examine your code. Your grade will be partially based on their feedback.

3. Chapter Three: Using Functions

3.1. Function Calls

In the last chapter, we introduced the basic mathematical operators (+ - * /). There are many other operations we might want to perform on data but there are not enough symbols for all of them. Instead, programmers use functions, which have a name and perform some complex operation given the appropriate inputs. Like the addition operation, they take input values, called parameters, and can result in a return value. The following program has two example function calls to the len() function. The len() function calculates the length of a string. On the first line, the input parameter value is the string "Mississippi" and the return value is the integer 11. On the second line, the input is "Hi there!" and the return value is 9.

PythonTutor Example 3.1

Function Calls

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

Function Calls and Parentheses
To call a function, use its name followed by parentheses (). Place all the input parameter values inside the parentheses separated by commas. Ex: randint(10, 20)

3.2. Function Calls in EarSketch

EarSketch includes a special set of functions for making music in Python. To use the EarSketch functions, always import the EarSketch application programming interface (API) at the top of your Python script:

from earsketch import *

We have already used several EarSketch functions, including init(), setTempo(), insertMedia(), and finish().

Inserting Clips

The insertMedia() function is what allows you to place sound clips into the EarSketch DAW. The function takes in 3 parameters:

  1. clipName: A string specifying the name of the sound clip to add. Although this is a string, we typically use a string constant from the EarSketch sound library for this parameter.

  2. track: An int specifying the track to add the clip to. Track 1 is the first track in the DAW.

  3. startMeasure: A float specifying the measure location to place the clip on the track. Measure 1 is the beginning of the song.

Setting Effects

Another useful function is setEffect(). It allows you to apply audio effects to your tracks to enhance the sound. This function takes in 4 parameters:

  1. track: An int specifying the track to add the effect to.

  2. effectName: A string (constant) specifying name of the effect (e.g. VOLUME)

  3. effectParam: A string (constant) specifying the parameter of the effect to set (e.g. GAIN)

  4. paramValue: A float specifying the value of the effect parameter.

There are many effects available in EarSketch such as VOLUME (how loud a track is), PAN (best heard with headphones, this is where the sound lies in stereo from left to right), DELAY (adds echos to the sound), and DISTORTION (makes a sound lofi and noisier). Most effects have multiple parameters which can be adjusted. Below are some of the most common effect parameters and examples of their sound in popular music.

VOLUME

  • GAIN: The amount to change the volume. Ranges from -60.0 decibels to 12.0 decibels with 0.0 being the original volume.

The song “More Than a Feeling” by Boston begins with a volume fade in. A fade in is accomplished by slowly increasing the volume gain.

PAN

  • LEFT_RIGHT: Adjusts where the sound falls between the left and right stereo speakers or headphones. Ranges from -100.0 (all the way left) to 100.0 (all the way right) with 0.0 being in the center.

In Queen’s song “Now I’m Here”, the left-right pan of vocal parts is manipulated.

DELAY

  • DELAY_TIME: Adjusts time between echoes in milliseconds (ms). Ranges from 0.0 (no delay) to 4000 (4 second delay).

  • MIX: Adjusts the volume of the delayed sound verses the original sound without delay. 0.0 is no delayed sound and the full original sound, while 1.0 is full delayed sound and no original sound. 0.5 is equal volumes of both the original and delayed sounds.

The Pink Floyd song “Us and Them” features delay on the vocal part starting around 1:38.

DISTORTION

  • DISTO_GAIN: The amount of distortion applied to the signal. Ranges from 0.0 (no distortion) to 50.0 (maximum distortion).

The song “Revolution” by The Beatles is iconic for its use of heavily distorted guitar.

If you are interested in what other effects and parameters can be used in EarSketch, look in the curriculum panel on the right side of EarSketch under "Every Effect Explained in Detail".

Other EarSketch Functions

There are many more functions included with Earsketch which are all documented in the API browser. To access the browser within EarSketch, click on the API icon on the left side of the EarSketch workspace.

EarSketch Example 3.1

Function Calls

The example below shows how insertMedia() and setEffect() can be used on a drum loop. Open the example in EarSketch, run it, and experiment with adjusting function parameters.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from earsketch import *

init()
setTempo(120)

# Place the drum loops one after another on their own tracks
insertMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001, 1, 1)
insertMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001, 2, 3)
insertMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001, 3, 5)
insertMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001, 4, 7)
insertMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001, 5, 9)

# Set a different effect on each track, leaving the first one normal
setEffect(2, VOLUME, GAIN, -12)
setEffect(3, DELAY, MIX, .3)
setEffect(4, PAN, LEFT_RIGHT, -100)
setEffect(5, DISTORTION, DISTO_GAIN, 25)

finish()
GGCFunctions

EarSketch Asg. 3.1

Function Calls

Edit the given code to match the screenshot below. Note the volume of track 1 has been set to a gain of 6.

1
2
3
4
5
6
7
8
from earsketch import *

init()
setTempo(135)

# Your code goes here

finish()
GGC 3 1

3.3. Data Type Conversion Functions

In the last chapter, we introduced the basic data types int, float, _and _string. As you know, different operations (such as +) work different ways on different data types. Therefore, it is very useful to convert data from one type to another. Learn the functions below:

  • str() - convert any value into a string.

  • int() - convert a string containing digits into an int.

  • float() - convert a string containing digits with a decimal point into a float.

In the following code example, pay special attention to the types of data stored in each variable. Remember, all strings are surrounded in quotes "".

PythonTutor Asg. 3.1

Data Type Conversion Functions

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

PythonTutor Example 3.2

Errors in Data Type Conversion

What is wrong with the conversion functions in the the code example below? Try to identify the issue and correct the problems for each statement. Use the Edit Code button to modify and correct the code.

EarSketch Example 3.2

Data Type Conversion Functions

In the example below, the str() function is used to convert the clipNum int into a string so it can be concatenated (+) to the clipName string. OS_CLAP has 4 different versions, try changing the variable clipNum to be 1, 2, 3, or 4 to get the different versions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from earsketch import *
init()

tempo = 120
start = 1
track = 1

clipName = "OS_CLAP0"
clipNum = 1
clipNumStr = str(clipNum)

clip = clipName + clipNumStr

setTempo(tempo)
insertMedia(clip,track,start)
finish()
GGCDataTypeConv

3.4. Combining Expressions

In the last chapter, we introduced expressions. Generally, an expression is any code that returns a value. Furthermore, anywhere it is legal syntax to use a value, it is legal syntax to use an expression instead. This gives rise to function chaining and complex expressions.

PythonTutor Asg. 3.2

Combining Expressions

Try to predict the variable names, values, and data types in the code example below. Use the Forward button to check your answers.

Remember, Python always starts evaluating expressions with the inner most parentheses first.

3.5. Random Numbers

The random() function takes no input parameters and returns a random float greater or equal to 0 and less than 1.

The randint() function takes 2 integer input parameters and returns a random int somewhere betweeen them (inclusive).

Importing Random Functions

In Chapter 1, we explained how importing modules enables specific functions for a script. The code below uses from random import random, randint statement to enable the random() and randint() functions.

PythonTutor Example 3.3

Random Numbers

Note: As the variable values are created randomly at runtime, you can not predict them. You should, however, be able to predict the variable names and data types. Use the Forward button to check your answers.

EarSketch Example 3.3

Random Numbers

Random numbers can be used for any numerical value in EarSketch as long as the range is set appropriately. In the example below, randint() is used to set the tempo between 80 and 150 BPM. Try running the code a few times and listen the results. The audio clip below had a random value of 113.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from earsketch import *
from random import randint

init()

tempo = randint(80,150)

setTempo(tempo)

insertMedia(Y04_DRUMS_SAMPLE_1,1,1)

finish()
GGCRand

EarSketch Asg. 3.2

Random Numbers

Edit the given code to randomly place the track 1 sound clip on either measure 1, 2, or 3. Run the code multiple times to make sure the start measure is being randomly selected.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from earsketch import *
from random import randint

init()

setTempo(100)

insertMedia(RD_UK_HOUSE_MAINBEAT_17,1,1)

insertMedia(RD_UK_HOUSE_ACOUSTICGUITAR_1 ,2,1)

finish()
Example when randint() returned 2.

GGC 3 2

3.6. Console User Interaction

A console, also known as a shell or terminal, is a user interface which allows programs to interact with humans through text. Unlike graphical user interfaces, a console does not allow for images, sound, video, or even mouse input.

The print() function displays a value to the console user. It does not return a value, so it can not be part of an expression.

The input() function returns a string typed by a user in the console. It takes 1 input string parameter to display as a question prompt for the user. As input() always returns a string, we frequently use the data type conversion functions to change the value to an integer or a float.

PythonTutor Asg. 3.3

User Input

Note: As the variable values are created by the user at runtime, you can not predict them. You should, however, be able to predict the variable names and data types. Use the Forward button to check your answers.

EarSketch Example 3.4

User Input

In this example, input() is used to set the tempo based on user input. Notice how the int() function is used to convert the user’s input from a string to an integer for setTempo().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from earsketch import *

init()

tempo = int(input("What tempo would you like?"))

setTempo(tempo)

insertMedia(HIPHOP_DUSTYGROOVE_005,1,1)

finish()
Table 2. Example where a user inputs "125".

GGCUserPopup

GGCUserInput

EarSketch Asg. 3.3

User Input

Edit the code below to ask the user to type in a starting measure for the track 1 clip.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from earsketch import *

init()

setTempo(100)

insertMedia(RD_UK_HOUSE_MAINBEAT_17,1,1)

insertMedia(RD_UK_HOUSE_ACOUSTICGUITAR_1 ,2,1)

finish()
Table 3. Example where a user inputs "2".

GGC 3 3 Popup

GGC 3 3

Unpredicatable Values
Some functions like input() and randint() return values that the programmer can not predict in advance. In most textbook examples, it is clear what value a variable will hold, but in most real world examples, programmers only know the data type of a variable, not its value.

3.7. Chapter 3 Project

Create an original song in EarSketch using the functions you’ve learned so far. Use the following functions and concepts:

  • Called Chap3Proj

  • At least 15 seconds long

  • init()

  • setTempo()

  • insertMedia()

  • setEffect()

  • finish()

In addition use at least one of the following functions:

  • input()

  • randint()

Listen to the audio of the example project

4. Chapter Four: Conditions

4.1. Making Decisions

Computers make decisions that give the illusion of "thinking". For example, a digital thermostat turns on or off the heater depending on the current temperature in the room. IBM’s Big Blue computer decides what chess piece to move next when beating world chess champions. Google’s self-driving car decides when to apply the brakes depending on what is in front of it. All computer decisions are based on conditions built out of a simple logic called Boolean logic.

4.2. Booleans

The boolean data type has just 2 possible values; True and False. This contrasts with the other data types (int, float, string) that have near-infinite possible values. The True and False values always start with a capital letter. The following example assigns the boolean value of False to the variable a.

1
a = False
Never put quotes ("False") around a boolean value. Quotes will make Python think it is a string.

Comparison Operators

The comparison operators are often used to generate boolean values. They can compare 2 ints (or other data types) and return either True or False.

Table 4. Comparison Operators

>

Greater Than

>=

Greater Than or Equal

<

Less Than

<=

Less Than or Equal

==

Equals

!=

Not Equals

Equality vs. Storage
Checking if two values are identical (==) is unrelated to storing a value in a variable (=).

PythonTutor Asg. 4.1

Booleans and Comparators

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

4.3. Boolean Operators

Just like ints have numeric operators (+ - * /), booleans have their own operators. The 3 boolean operators are and, or, and not.

Boolean Operator: and
True and False

The and operator takes 2 boolean inputs and returns True only when both inputs are True, False otherwise.

Boolean Operator: or
False or True

The or operator takes 2 boolean inputs and returns True when at least 1 input is True, False otherwise.

Boolean Operator: not
not True

The not operator takes 1 boolean input and returns the opposite (negated) boolean.

PythonTutor Asg. 4.2

Boolean Operators

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

4.4. If Statements

Boolean logic allows a program to make a decision based on a condition. The if statement executes specific lines of code only when the condition is True. If the condition is False, the lines are skipped. The lines of code to be executed are grouped with indentation (tabs or spaces) into a block. Code blocks are always preceded by a colon (:).

PythonTutor Asg. 4.3

If Statements

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Example 4.1

If Statements and Probability

The randint() function can be combined with if statements to create probability based code. The example below has a 33% chance of playing the drum clip. Hit Run inside EarSketch a few times and observe track 2.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from random import randint
from earsketch import *

init()
setTempo(115)

lead = EIGHT_BIT_ATARI_LEAD_007
drum = EIGHT_BIT_ANALOG_DRUM_LOOP_001

insertMedia(lead, 1, 1)

r = randint(1, 3)

if r == 1:
  insertMedia(drum, 2, 1)

finish()

EarSketch Asg. 4.1

If Statements and Probability

Change the code below by adding another if statement block on line 18 so that drumB is placed on track 2 if drumA fails to be added. When Run, there should be a 33% chance for drumA, and a 66% chance for drumB.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from random import randint
from earsketch import *

init()
setTempo(115)

lead = EIGHT_BIT_ATARI_LEAD_007
drumA = EIGHT_BIT_ANALOG_DRUM_LOOP_001
drumB = EIGHT_BIT_ANALOG_DRUM_LOOP_008

insertMedia(lead, 1, 1)

r = randint(1, 3)

if r == 1:
  insertMedia(drumA, 2, 1)

# add if statement block here


finish()
Audio of the answer with drumA
Audio of the answer with drumB
GGC 4 1a
Figure 2. DAW view of the answer with drumA
GGC 4 1b
Figure 3. DAW view of the answer with drumB

4.5. If, Elif, Else

As we learned above, if statements will either execute or skip 1 block of code depending on the condition. In some situations, we want to choose between 2 blocks of code depending on the condition. This can be done with the if …​else…​ statement.

PythonTutor Asg. 4.4

If and Else Statements

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Asg. 4.2

If and Else Statements

Change the code below by adding an else statement block on line 18 so that drumB is placed on track 2 if drumA fails to be added. When Run, there should be a 33% chance for drumA, and a 66% chance for drumB. Notice that this is identical to the previous EarSketch exercise but uses an else statement instead of a second if statement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from random import randint
from earsketch import *

init()
setTempo(115)

lead = EIGHT_BIT_ATARI_LEAD_007
drumA = EIGHT_BIT_ANALOG_DRUM_LOOP_001
drumB = EIGHT_BIT_ANALOG_DRUM_LOOP_008

insertMedia(lead, 1, 1)

r = randint(1, 3)

if r == 1:
  insertMedia(drumA, 2, 1)

# add else statement block here


finish()
Audio of the answer with drumA
Audio of the answer with drumB
GGC 4 1a
Figure 4. DAW view of the answer with drumA
GGC 4 1b
Figure 5. DAW view of the answer with drumB

In some situations, we want to choose to execute 1 block out of 3 or more options. This requires multiple conditions combined with the if…​elif…​else…​ statements.

PythonTutor Asg. 4.5

If, Elif, and Else Statements

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Example 4.2

If, Elif, and Else Statements

By using if, elif, and else statements in EarSketch, we can create interesting variations in the music by making changes based on the status of variables. In the example below, there are 3 different variations based on the user input. Note that we use data type conversion on the input to convert it from a string to an integer. The first if statement checks that the input is in range, printing a statement to the console if it is not. This is followed by three elif statements which contain the different variations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from earsketch import *

init()
setTempo(120)

num_members = int(input("Enter a number of band members 1-3"))

if num_members == 1:
	insertMedia(Y02_GUITAR_1, 1, 1)

elif num_members == 2:
	insertMedia(Y02_DRUM_SAMPLES_1, 1, 1)
	insertMedia(Y02_GUITAR_1, 2, 1)

elif num_members == 3:
	insertMedia(Y02_DRUM_SAMPLES_1, 1, 1)
	insertMedia(Y01_BASS_1, 2, 1)
	insertMedia(Y02_GUITAR_1, 3, 1)

else:
	print("Number of members must be 1-3")

finish()
Audio view with 3 band members
GGCElif
Figure 6. DAW view with 3 band members

EarSketch Asg. 4.3

If, Elif, and Else Statements

Alter the code below by adding conditional statements. If the user input is "Calm", it should add only the calm sound clip. If the user input is "Intense", it should add only the two intense sound clips. If the user input is anything else, it should add only the other sound clip. The answer should contain exactly one if, one elif, and one else.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from earsketch import *

init()
setTempo(135)

mood = input("Input Mood (Calm or Intense)")

# Calm Sound
insertMedia(RD_CINEMATIC_SCORE_HARP_3,1,1)

# Intense Sounds
insertMedia(RD_CINEMATIC_SCORE_STRINGS_1,2,1)
insertMedia(RD_CINEMATIC_SCORE_MAINDRUM_7,3,1)

# Other Sound
insertMedia(HOUSE_SFX_WHOOSH_001,4,1)

finish()

4.6. While Loops

As we learned above, the if statement allows us to execute a code block one time if a condition is True. The while statement, on the other hand, allows us to execute a code block repeatedly while a condition is True. This allows our code to loop potentially infinite times. To prevent infinite looping, the code block typically modifies the variable used in the condition. For example, the value of x is increased with every loop in the code snippet below.

x = 1
while x < 5:
	x += 1

PythonTutor Asg. 4.6

While Statements

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Example 4.3

While Statements

Repetition is one of the basic building blocks of music composition. Modern pop music relays heavily on repetition such as the song “We Found Love” by Rihanna. Listen to how the same background music is repeated for the first 50 seconds of the song.

In EarSketch, using loops is a great way to easily repeat clips. The two examples below both play the clip 8 times in a row; however, the code for the first version is nearly twice as long as the second. The while loop itself only takes up four lines of code and can be modified to repeat any number of times by simply changing the int in the condition. Notice how we use the dur() function to get the length of the clip and redefine the start position with each repetition.

Without a while loop
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from earsketch import *
init()
setTempo(120)

start = 1
clip = HOUSE_BREAKBEAT_001
length = dur(clip)

insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length
insertMedia(clip,1,start)
start += length

finish()
With a while loop
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from earsketch import *
init()
setTempo(120)


start = 1
clip = HOUSE_BREAKBEAT_001
length = dur(clip)

x = 1
while x < 9:
	insertMedia(clip,1,start)
	start += length
	x += 1

finish()
GGCWhile

EarSketch Asg. 4.4

While Statements

Alter the code below to use a while loop rather than repeated code to play the clips 5 times in a row.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from earsketch import *

init()
setTempo(88)

start = 1
clip = YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1
length = dur(clip)

# Change this section
insertMedia(YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1,1,start)
insertMedia(YG_WEST_COAST_HIP_HOP_CLAP_SNARE_1,2,start)
insertMedia(YG_WEST_COAST_HIP_HOP_KICK_1,3,start)
insertMedia(YG_WEST_COAST_HIP_HOP_HIHAT_3,4,start)
start += length
insertMedia(YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1,1,start)
insertMedia(YG_WEST_COAST_HIP_HOP_CLAP_SNARE_1,2,start)
insertMedia(YG_WEST_COAST_HIP_HOP_KICK_1,3,start)
insertMedia(YG_WEST_COAST_HIP_HOP_HIHAT_3,4,start)
start += length
insertMedia(YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1,1,start)
insertMedia(YG_WEST_COAST_HIP_HOP_CLAP_SNARE_1,2,start)
insertMedia(YG_WEST_COAST_HIP_HOP_KICK_1,3,start)
insertMedia(YG_WEST_COAST_HIP_HOP_HIHAT_3,4,start)
start += length
insertMedia(YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1,1,start)
insertMedia(YG_WEST_COAST_HIP_HOP_CLAP_SNARE_1,2,start)
insertMedia(YG_WEST_COAST_HIP_HOP_KICK_1,3,start)
insertMedia(YG_WEST_COAST_HIP_HOP_HIHAT_3,4,start)
start += length
insertMedia(YG_WEST_COAST_HIP_HOP_PIANO_HIGH_1,1,start)
insertMedia(YG_WEST_COAST_HIP_HOP_CLAP_SNARE_1,2,start)
insertMedia(YG_WEST_COAST_HIP_HOP_KICK_1,3,start)
insertMedia(YG_WEST_COAST_HIP_HOP_HIHAT_3,4,start)
start += length

finish()
GGC 4 4

4.7. Input Validation

While loops are often used to validate user input. Users will often enter incorrect data repeatedly (invalid birth month for example). We can use a while loop, along with a condition for invalid data, to repeatedly ask the user for valid input. Notice what happens in the example below when the user inputs numbers like 14, and 112, before entering a valid month.

PythonTutor Asg. 4.7

Input Validation

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

4.8. Chapter 4 Project

Create an original song in EarSketch using the functions you’ve learned so far. Use the following functions and concepts:

  • Called Chap4Proj

  • At least 15 seconds long

  • init(), setTempo(), insertMedia(), setEffect(), finish()

  • At least one if statement

  • At least one while loop

Listen to the audio of the example project

5. Chapter Five: String Indexes and Loops

5.1. More Functions in EarSketch

In this chapter, we will use two new EarSketch functions which will be very useful for the rest of the course, fitMedia() and makeBeat().

At the end of the last chapter, we used while loops with insertMedia() to repeat clips many times in a row. This is such a useful feature for making music that EarSketch provides a built in function to do this without a loop, the fitMedia() function.

fitMedia() takes four arguments:

  1. clipName: A string (or constant) specifying the name of the sound clip to add.

  2. track: An int specifying the track to add the clip to.

  3. startMeasure: A float specifying the measure location to place the clip on the track.

  4. endMeasure: A float specifying the measure location to stop the clip.

The ability to specify the end location gives the freedom to play only a short segment of a clip or to automatically repeat it as much as needed such as in the example below.

EarSketch Example 5.1

FitMedia Function

Notice how the clips repeat as many times as necessary to reach the endMeasure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from earsketch import *

init()

setTempo(100)

fitMedia(Y02_DRUM_SAMPLES_1, 1, 1, 9)
fitMedia(Y01_BASS_2, 2, 3, 7)
fitMedia(Y02_GUITAR_1, 3, 5, 6)

finish()
GGCFitMedia

So far, we’ve been making music using pre-made clips and loops on the measure level, but we can also create custom music on the beat level using an EarSketch function called makeBeat().

makeBeat() takes four arguments:

  1. clipName: A string (or constant) specifying the name of the sound clip to add.

  2. track: An int specifying the track to add the clip to.

  3. startMeasure: A float specifying the measure location to place the clip on the track.

  4. beatString: A string which defines the rhythm of the beat.

The beat string is usually 16 characters long (which equals 1 measure) and looks something like this:

myBeat = “0-00-00-0++0+0”

Every character stands for one sixteenth-note sub-beat of a measure.

  • 0 starts playing the clip.

  • - is a rest, meaning that there’s nothing being played.

  • `` extends the sound clip into the next sixteenth-note sub-beat, so it should always follow either a ``0`` or a ``.

EarSketch Example 5.2

makeBeat() Function

Run the example below to make some custom beats. Experiment with changing the beat strings and using different clips.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from earsketch import *

init()
setTempo(120)

beatString1 = "0000000000000000"
beatString2 = "0+++++++++++++++"
beatString3 = "0-------0-------"
beatString4 = "0+0---000--0+-0-"

makeBeat(OS_CLAP01, 1, 1, beatString1)
makeBeat(OS_CLAP01, 2, 2, beatString2)
makeBeat(OS_CLAP01, 3, 3, beatString3)
makeBeat(OS_CLAP01, 4, 4, beatString4)

finish()
GGCMakeBeat

EarSketch Asg. 5.1

fitMedia() and makeBeat() Functions

Complete the code by adding one fitMedia() and one makeBeat() function call to match the DAW screenshot below. Note that makeBeat() should use clip2 and beatString.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from earsketch import *

init()
setTempo(100)

clip1 = RD_RNB_PROPHETPOLYARP_1
clip2 = OS_KICK06

beatString = "0++0++0+-0000+0+"

# Add your code here

finish()
GGC 5 1

5.2. Indexes

Strings in Python can vary in length from 0 characters to millions of characters (limited by the computer’s memory). As such, we often need to break down strings into shorter fragments or individual characters in order to process them. String processing starts with the concept that each character in a string has a unique index which represents its position in the string. Indexes start with the first chracter at position 0, and end with the last character at position length - 1. The indexes for the string "Hi There" are below. Note that the string is of length 8, and thus has indexes from 0 to 7.

Table 5. Indexes

String Characters:

H

i

T

h

e

r

e

Indexes:

0

1

2

3

4

5

6

7

Individual characters can also be identified with reverse indexes starting with the last character at position -1, and ending with the first character at position -length. The reverse indexes for the string "Mr. Bob" are below. Note that the string is of length 7, and thus has reverse indexes from -1 to -7 right to left.

Table 6. Reverse Indexes

String: Characters

M

r

.

B

o

b

Indexes:

0

1

2

3

4

5

6

Reverse Indexes:

-7

-6

-5

-4

-3

-2

-1

5.3. Accessing Characters

We can access individual characters of a string by using the square bracket ([]) notation along with an index. The code snippet below shows how square bracket notation relates to the characters in a string.

‘a’ == ‘apple’[0]
‘l’ == ‘apple’[3]
‘e’ == ‘apple’[-1]

PythonTutor Asg. 5.1

String Indexing

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

5.4. Slicing

We can access slices or substrings of a larger string by using the bracket notation and two indexes separated by a colon (:). The first index specifies the starting point of the slice, while the second index specifies the stopping point of the slice + 1. This is known as incluse:exclusive notation.

PythonTutor Asg. 5.2

String Slicing

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

The Last Index

To get the last letter of a string into a slice, we need the last index + 1. This is identical to the length of the string. If we leave the second index of a slice blank, Python assumes you want the last letter. Thus, in the example below, b and c are equivalent.

1
2
3
a = "great"
b = a[2:5]
c = a[2:]

EarSketch Example 5.3

String Slicing

You can use string slicing with beat strings to remix a groove. The code below remixes a beat string in four ways and places them one after the other to create a complex rhythm.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from earsketch import *

init()
setTempo(120)

beatString = "0000-0-00++0-00-"

a = beatString[0:4]
b = beatString[4:8]
c = beatString[8:12]
d = beatString[12:16]

newBeat1 = d + c + b + a
newBeat2 = a + d + c + c
newBeat3 = b + b + b + b
newBeat4 = a + c + d + c

makeBeat(OS_CLAP01, 1, 1, beatString)
makeBeat(OS_CLAP01, 1, 2, newBeat1)
makeBeat(OS_CLAP01, 1, 3, newBeat2)
makeBeat(OS_CLAP01, 1, 4, newBeat3)
makeBeat(OS_CLAP01, 1, 5, newBeat4)

finish()
GGCStringSlicing

EarSketch Asg. 5.2

String Slicing

Use string slicing to rearrange the beat string in the code below. Divide the original beat into three slices. sliceA contains the first 6 characters, sliceB contains the next 6, and sliceC contains the rest of the string to the end. Make newBeat by combining the slices B, C, then A.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from earsketch import *

init()
setTempo(120)

# Original beat string
beatString = "0+-00-00+0--000+"

# Write your string slicing code here
sliceA = ????
sliceB = ????
sliceC = ????

# Make your new beat
newBeat = ????

makeBeat(OS_COWBELL01, 1, 1, newBeat)

finish()
GGC 5 2

5.5. For Loops

In many situations, we want to access every character of a string one at a time. Although this could be accomplished by using each index from 0..length - 1, it is much more convenient to use the for loop. The for loop creates a new variable, stores the first character of the string in it, and repeatedly executes the attached block. Each time the block is executed, the next character is stored in the new variable.

PythonTutor Asg. 5.3

String For Loop

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Asg. 5.3

String For Loops

A for loop can iterate over a string in order to use one character at a time. Alter the code below to use a for loop and the string "2143" to recreate the same song. The new version should only contain one call to fitMedia() and one += operator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from earsketch import *

init()
setTempo(70)

s = "Y13_PERCUSSION_"

start = 1

num = "2"
fitMedia(s + num, start, start, 5)
start += 1

num = "1"
fitMedia(s + num, start, start, 5)
start += 1

num = "4"
fitMedia(s + num, start, start, 5)
start += 1

num = "3"
fitMedia(s + num, start, start, 5)
start += 1

finish()
GGC 5 3

EarSketch Example 5.4

Strings and Musical Structure

Most popular songs make use of repeated sections of music. Sometimes these sections are referred to by letters such as an "A section and B section" or by terms such as "verse and chorus".

Strings can be used to describe the structure of a piece of music in terms of section letters. Some typical structures might be "AABA" or "ABABCA". The first minute of the song “Happy” by Pharrell Williams features an "A" and a "B" section, each of which loops four times. Listen to the song and follow along with the structure "AAAABBBB".

String For Loops

In the example below, there are two sections of music, "A" and "B", each of which use different sound clips. By using the string songPattern to represent the structure of a song, you can easily change the structure. Notice how the code iterates over the songPattern with a for loop and constructs the music with fitMedia() calls.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from earsketch import *

init()
setTempo(140)

start = 1
sectionLen = 4

clipA1 = TECHNO_SYNTHPLUCK_001
clipA2 = RD_TRAP_MAIN808_BEAT_2
clipB1 = TECHNO_POLYLEAD_004
clipB2 = Y05_HI_HATS_1

songPattern = "AABA"

for letter in songPattern:
	if letter == "A":
		fitMedia(clipA1, 1, start, start + sectionLen)
		fitMedia(clipA2, 2, start, start + sectionLen)
	elif letter == "B":
		fitMedia(clipB1, 1, start, start + sectionLen)
		fitMedia(clipB2, 2, start, start + sectionLen)

	start += sectionLen

finish()
GGCFor

PythonTutor Asg. 5.4

Counting With Loops

Loops in conjunction with if statements and the increment operator (+=) can be used to count occurrences of characters and do other valuable processing. Follow the code below closely.

5.6. Chapter 5 Project: Beat Challenge

Compose a song that is centered around beats that you create with the makebeat()function. Use the following functions and concepts:

  • Called Chap5Proj

  • At least 15 seconds long.

  • Use a for loop, a song pattern, and the makebeat() function to repeat different beats multiple times (see EarSketch Example 5.4).

  • You will need to create at least 2 of your own beat strings and choose a clip for each one.

Listen to the audio of the example project

6. Chapter Six: Lists

6.1. Creating Lists

Lists are collections of values combined into a single entity. They enable a single variable to store multiple values, like a cubbyhole holding different items in each space. Lists can be created manually with brackets ([]), or by using functions like range() or string.split().

The range(a, b) function returns a list of integers from a up to, but not including b. Thus range(2, 5) returns [2, 3, 4].

PythonTutor Asg. 6.1

Creating Lists

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

String Splitting With Numbers
Note that the string.split() function always returns a list of strings, even if they look like numbers. Thus, remember to use the int() or float() functions when working with numbers from string.split().

6.2. Indexes

The indexes of each value in a list are identical to the indexes for each character in a string. They start with the first value at position 0 and end with the last value at position length - 1. The indexes for the list ["Apple", "Plum", "Kiwi"] are below. Note that the list is of length 3 and thus has indexes from 0 to 2. Reverse indexes are also supported.

List Values:

"Apple"

"Plum"

"Kiwi"

Indexes:

0

1

2

Reverse Indexes:

-3

-2

-1

6.3. Accessing and Modifying List Values

We can access individual values of a list by using the square bracket ([]) notation along with an index. Furthermore, we can modify any value in a list with the same bracket notation and the storage (=) operator.

PythonTutor Asg. 6.2

List Indexing

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

Swapping Items in a List
Note that since we can access and modify elements in a list, we can also swap them. Can you figure out how to swap the first and last elements of any list?

EarSketch Example 6.1

Lists

Lists in EarSketch are great for organizing multiple sound clips. In the example below, all of the clips for the song are put into a list. Rather than saving clips in individual variables, the values are accessed with their indexes in the list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from earsketch import *

init()

setTempo(130)

myClips = [RD_ROCK_POPRHYTHM_MAINDRUMS_1, RD_ROCK_POPELECTRICBASS_3, RD_ROCK_POPELECTRICLEAD_12]

fitMedia(myClips[0], 1, 1, 11)
fitMedia(myClips[1], 2, 3, 11)
fitMedia(myClips[2], 3, 7, 11)

finish()
GGCLists

EarSketch Asg. 6.1

Lists

In the code below, replace the question marks in the fitMedia() calls with the correct index into the myClips list. The answer should match the screenshot below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from earsketch import *

init()

setTempo(108)

myClips = [RD_WORLD_PERCUSSION_BASSWOODENTONE_2, RD_WORLD_PERCUSSION_DRIPPYSYNTHFX_1, RD_WORLD_PERCUSSION_DRUMPART_10,RD_WORLD_PERCUSSION_DRUMPART_12]

fitMedia( ???? , 1, 1, 9)
fitMedia( ???? , 2, 3, 9)
fitMedia( ???? , 3, 5, 9)
fitMedia( ???? , 4, 7, 9)

finish()
GGC 6 1

EarSketch Example 6.2

Lists with makeBeat()

In the last chapter, we used the makeBeat() function with one clip at a time. By using lists, we can use one makeBeat() call to trigger many different sounds and make more interesting beats.

You can create a list that contains all of your drum sound clips and use that list as the first argument to your makeBeat() call. Previously in beat strings, we used a "0" character to trigger a clip. Now you can use the characters "0" through "9" which correspond to the indexes of your list of sound clips.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from earsketch import *

init()

setTempo(100)

drums = [OS_KICK05, OS_SNARE06, Y24_HI_HATS_1]

drumPattern = '0+0+1221+10+1+22'

makeBeat(drums, 1, 1, drumPattern)

finish()
GGCMakeBeatLists

Programming beats in this way is similar to making music with a drum machine. Drum machines are popular in hip hop and electronic music and have been used to create iconic beats.

EarSketch Asg. 6.2

Lists with makeBeat()

In the code below, replace the question marks with beat string required to match the DAW screenshot. The correct answer will use a 16 character combination of "0"s, "1"s, and "2"s for selecting the correct clip and "+"s for continuing a clip.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from earsketch import *

init()

setTempo(100)

drums = [OS_LOWTOM02, OS_COWBELL01, OS_CLAP04]

drumPattern = ????

makeBeat(drums, 1, 1, drumPattern)

finish()
GGC 6 2

6.4. List Appending and Slicing

We can append to lists with the concatenation operator (+). We can also slice a list using the bracket notation and two indexes separated by a colon (:). The first index specifies the starting point of the slice while the second index specifies the stopping point of the slice + 1.

PythonTutor Asg. 6.3

List Appending and Slicing

Try to predict the variable names, values, and data types in the code example below. Use the Forward button to check your answers.

6.5. For Loops with Lists

Much like when using strings, we often want to access every element of a list one by one. We can use a for loop to repeatedly execute the attached block; once for each value of the list.

PythonTutor Asg. 6.4

For Loops with Lists

Try to predict the variable names, values, and data types in the code example below. Use the Forward button to check your answers.

EarSketch Example 6.3

Lists and For Loops

Using for loops opens up even more possibilities for lists in EarSketch. By iterating over a list of clips, many tracks can be added to a song with only a few lines of code.

In the example below, each clip in the list is added to the song and the track number is increased by one so that every clip is placed on a different track.

On each iteration, the start of the clip is also increased by two measures so that each clip starts two measures after the previous one. This musical technique, in which clips are added one by one to the music, is called additive form, and it is a very common way to start a song. A good example of this is from Kanye West’s song “Power”. In the introduction, listen as the different tracks are added. Also, the sound becomes more complex and intense. This technique is also popular in electronic music such as in the song “The Veldt” by deadmau5.

This example could be expanded to include different clip lists for different song sections to build complex songs much more quickly than without lists and loops.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from earsketch import *

init()

setTempo(120)

clips = [YG_NEW_FUNK_DRUMS_1, YG_NEW_FUNK_SYNTH_1,
		 YG_NEW_FUNK_SYNTH_3, YG_ALT_POP_CRASH_2 ]

track = 1
start = 1
end = 9
for c in clips:
	fitMedia(c, track, start, end)
	track += 1
	start += 2

finish()
GGCForLists

EarSketch Asg. 6.3

Lists and For Loops

The list below contains 8 sound clips of kalimba piano.

clips = [RD_WORLD_PERCUSSION_KALIMBA_PIANO_1, RD_WORLD_PERCUSSION_KALIMBA_PIANO_2, RD_WORLD_PERCUSSION_KALIMBA_PIANO_3, RD_WORLD_PERCUSSION_KALIMBA_PIANO_4, RD_WORLD_PERCUSSION_KALIMBA_PIANO_5, RD_WORLD_PERCUSSION_KALIMBA_PIANO_6, RD_WORLD_PERCUSSION_KALIMBA_PIANO_7, RD_WORLD_PERCUSSION_KALIMBA_PIANO_8]

Write a script in EarSketch with a tempo of 115. The script should use a for loop to add each clip to the DAW. Match the screenshot below. Notice:

  • Each clip has its own track

  • Each clip starts one measure later.

  • Each clip lasts for 5 measures.

Ass6 3

6.6. For Loops with Indexes

Loops over a list of indexes created by the range() function allow us to do more complex processing like running through two lists at the same time, modifying lists, searching for the index of certain elements, using multiple indexes in the same list, and more. Follow the code below closely.

PythonTutor Asg. 6.5

Advanced Loops

Try to predict the variable names, values, and data types in the code example below. Use the Forward button to check your answers.

EarSketch Example 6.4

For Loops with Indexes

The example below uses three related lists. The first contains sound clips, the second contains panning values, and the third contains volume gain values. The code inside the for loop uses one index to access all three lists, applying both the pan and volume effects to each clip.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from earsketch import *

init()
setTempo(98)

clips = [YG_NEW_HIP_HOP_CLAP_1, YG_NEW_HIP_HOP_HIHAT_2, YG_NEW_HIP_HOP_KICK_8,YG_NEW_HIP_HOP_SNARE_5, YG_NEW_HIP_HOP_ORCH_HITS_1, YG_NEW_HIP_HOP_PIANO_1, YG_NEW_HIP_HOP_STRINGS_3]

pan = [0, -100, 0, 60, -10, 80, -80]
vol = [6, -3, 9, -2, -3, 8, 0]

numClips = len(clips)

for i in range(0, numClips):
  fitMedia(clips[i], i+1, 1, 9)
  setEffect(i + 1, PAN, LEFT_RIGHT, pan[i])
  setEffect(i + 1, VOLUME, GAIN, vol[i])

finish()

GGCForIndexes

6.7. Chapter 6 Project: Complete Drummer

Compose a song that is centered around a multi-instrument beat that you create with the makebeat() function. Use the following functions and concepts:

  • Called Chap6Proj

  • At least 15 seconds long.

  • Use the makebeat() function with a list of at least 4 different clips and an appropriate beat string. For example, you might consider using a drum combination consisting of cymbal, kick, tom, and snare drums (see EarSketch Example 6.2).

  • Use a for loop with a list of measures (Ex. [1, 2, 5, 7]) to place your beat multiple times.

Note the list of measures is separate from the list of clips (drum instruments).

Listen to the audio of the example project

7. Chapter Seven: Defining Your Own Functions

7.1. Review: Calling Functions

In Chapter 3, we introduced functions like len(), print(), input(), str(), int(), randint(), range(), and more. Calling these functions has been fundamental to most of the examples in the book. A function call typically takes 1 or more input parameters. For example, to call the print() function, we specify 1 string input parameter. This function then displays the string to the console user.

7.2. More Functions in EarSketch

In this chapter, we will use a new version of the setEffect() EarSketch function which will be very useful for the rest of the course.

EarSketch Example 7.1

Advanced SetEffect Function

The code below introduces a new version of the setEffect() function. This version allows different parameter settings at different points in time. It takes in 5 parameters:

  1. track: An int specifying the track to add the effect to.

  2. effectName: A string (constant) specifying name of the effect (e.g. VOLUME)

  3. effectParam: A string (constant) specifying the parameter of the effect to set (e.g. GAIN)

  4. paramValue: A float specifying the value of the effect parameter.

  5. paramLocation: A float specifying the measure where this parameter should be set.

This version of setEffect() can be called many times on the same track to set different effect parameter values for different measures.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from earsketch import *

init()
setTempo(120)

fitMedia(EIGHT_BIT_ANALOG_DRUM_LOOP_001,1,1,9)

setEffect(1, VOLUME, GAIN, -20, 1)
setEffect(1, VOLUME, GAIN, 12, 4.5)
setEffect(1, VOLUME, GAIN, -20, 7)

finish()
GGCSetEffectAdv

7.3. Defining custom functions

Before a function can be called, it must be defined. Every function we have used this semester has been pre-defined for you by other programmers. Here, we introduce how to define your own custom functions. Once defined, you and other programmers will be able to use them like any other function. Thus, by defining your own functions, you are adding new functionality to Python. The fundamental approach to solving large programming problems is breaking them down into small function definitions, and then calling those functions to solve the original complex problem.

As an example, if we are writing a game that needs to print out player names surrounded by star (*) characters, we might want to define our own function called star_print. The function will need an input parameter for the players’s name, and will then print out the name surrounded by * characters. Once defined, the function can be called as many times as needed.

PythonTutor Asg. 7.1

Simple Function

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

Function Definitions

To define a function, we use the def statment followed by the function name, and 1 variable name per input value required. These input parameter variables are surrounded by parentheses. The attached code block is what is executed when the function is called.

Once called, a function comes alive in its own space (called scope). It has its own variables that are separate from variables outside the function. Furthermore, its parameter variables are automatically initialized to the values passed in by the function call.

EarSketch Example 7.2

Custom Functions (Section Form)

Repetitive code is lengthy and difficult to modify. If we define functions, we can simplify the code and make it easier to work with. Musically, this allows us to reduce our code into sections that can be repeat throughout a song with variation.

Note: This code uses the advanced SetEffect() function allowing the user to use the last parameter to set the start measure of the effect.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from earsketch import *

init()
setTempo(117)

fitMedia(RD_TRAP_ARPBLEEPLEAD_1, 1, 1, 5)
setEffect(1, VOLUME, GAIN, -20, 1)
fitMedia(RD_TRAP_BASSDROPS_1, 2, 1, 5)
fitMedia(RD_TRAP_DRUM_PART_1, 3, 1, 5)

fitMedia(RD_TRAP_BELLLEAD_1, 1, 5, 9)

fitMedia(RD_TRAP_ARPBLEEPLEAD_1, 1, 9, 13)
setEffect(1, VOLUME, GAIN, 0, 9)
fitMedia(RD_TRAP_BASSDROPS_1, 2, 9, 13)
fitMedia(RD_TRAP_DRUM_PART_1, 3, 9, 13)

fitMedia(RD_TRAP_ANALOGSINELEAD_1, 1, 13, 17)

fitMedia(RD_TRAP_ARPBLEEPLEAD_1, 1, 17, 21)
setEffect(1, VOLUME, GAIN, 5, 17)
fitMedia(RD_TRAP_BASSDROPS_1, 2, 17, 21)
fitMedia(RD_TRAP_DRUM_PART_1, 3, 17, 21)

finish()
GGCUserDefFunc

Look for blocks of code that repeat. In the example above, each section contains three fitMedia() calls and one setEffect() call.

Next, look to see what differences exist between the repetitive code blocks. These differences will suggest what input parameters your function will need to take in. In the code above, the start and end times change for each section, as well as the volume gain.

Now that we know what is changing and what is staying the same, we can write the corresponding function. The code below produces the same musical result as before but uses a custom function called sectionA() to replace the repetitive blocks of code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from earsketch import *

init()
setTempo(117)

def sectionA(start, end, x):
	fitMedia(RD_TRAP_ARPBLEEPLEAD_1, 1, start, end)
	setEffect(1, VOLUME, GAIN, x, start)
	fitMedia(RD_TRAP_BASSDROPS_1, 2, start, end)
	fitMedia(RD_TRAP_DRUM_PART_1, 3, start, end)

sectionA(1, 5, -20)
fitMedia(RD_TRAP_BELLLEAD_1, 1, 5, 9)
sectionA(9, 13, 0)
fitMedia(RD_TRAP_ANALOGSINELEAD_1, 1, 13, 17)
sectionA(17, 21, 5)

finish()

Functions like this are useful for creating interesting song structures. Each function call represents a section of the song that can be added in different measures and with different clips.

More sophisticated music could have multiple sections (A, B, C, …​) called in intertwining patterns such as ABBACABBACC.

EarSketch Asg. 7.1

Using Custom Functions to create Sections

Alter the repetitive code below using a custom function. Create a custom function called sectionA and call it where appropriate to reproduce the same song with cleaner and more organized code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from earsketch import *

init()

setTempo(100)

fitMedia(HIPHOP_DUSTYGUITAR_001, 1, 1, 3)
setEffect(1, DISTORTION, DISTO_GAIN, 15, 1)
fitMedia(HIPHOP_HIHAT_ROLL_002, 2, 1, 3)
fitMedia(HIPHOP_STOMP_BEAT_001, 3, 1, 3)

fitMedia(HIPHOP_DUSTYGUITAR_002, 1, 3, 5)

fitMedia(HIPHOP_DUSTYGUITAR_001, 1, 5, 7)
setEffect(1, DISTORTION, DISTO_GAIN, 45, 5)
fitMedia(HIPHOP_HIHAT_ROLL_002, 2, 5, 7)
fitMedia(HIPHOP_STOMP_BEAT_001, 3, 5, 7)

fitMedia(HIPHOP_DUSTYMOOG_002, 1, 7, 9)

fitMedia(HIPHOP_DUSTYGUITAR_001, 1, 9, 11)
setEffect(1, DISTORTION, DISTO_GAIN, 0, 9)
fitMedia(HIPHOP_HIHAT_ROLL_002, 2, 9, 11)
fitMedia(HIPHOP_STOMP_BEAT_001, 3, 9, 11)

finish()
GGC 7 1

Note, once complete your script should like this…​

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from earsketch import *

init()

setTempo(100)

# Define sectionA function here

sectionA(1, 3, 15);
fitMedia(HIPHOP_DUSTYGUITAR_002, 1, 3, 5)
sectionA(5, 7, 45);
fitMedia(HIPHOP_DUSTYMOOG_002, 1, 7, 9)
sectionA(9, 11, 0);

finish()

7.4. Return Statements

Many functions return a value. The return value can then be stored in a variable, or used as part of a complex expression. To make a function return a value, use the return statement.

As an example, we might want to define a function, called repeat_string, that returns a new string by repeating a simple string multiple times. The function will need two input parameters; one for the string to repeat, and another for the number of times to repeat it. The function will then return the newly created string.

PythonTutor Asg. 7.2

Functions with Return

Use the Forward button to step through the program below and watch the variables get created.

Return Statement Evaluation

When python executes a return statement, it immediately exits the function and replaces the function call with the return value. Thus, code like:

a = repeat_string("*", 4)

gets converted to

a = "****"

during execution.

EarSketch Asg. 7.2

Functions with Return

In the incomplete code below, a function is defined to generate a beat string which plays a simple drum groove. The repeatBeat() function repeats a short pattern to get a complete beat string (16 beats). The returned string can then be used in the makebeat() function. Replace the question marks below each comment to match the DAW screenshot below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from earsketch import *

init()
setTempo(130)

def repeatBeat(pattern):
	n = 16 / len(pattern)
	newBeat = ""
	for i in range(0, n):
		newBeat += pattern
	# return the new beat string to the caller
	????

# call the repeatBeat function with the "0+++++++" pattern.
makeBeat(OS_KICK05, 1, 1, ????)
# call the repeatBeat function with the "0+++" pattern.
makeBeat(OS_KICK05, 1, 2, ????)
# call the repeatBeat function with the "0+" pattern.
makeBeat(OS_KICK05, 1, 3, ????)
# call the repeatBeat function with the "0" pattern.
makeBeat(OS_KICK05, 1, 4, ????)

finish()
GGC 7 2

7.5. Combining Functions

Once defined, a function can be called from anywhere, including other function definitions. This allows us to take a complex problem and break it down into smaller problems.

For example, if we want our original star_print() function to print out more stars for longer names, we can call our repeat_string() function from inside the star_print() definition.

PythonTutor Asg. 7.3

Combining Functions

Use the Forward button to step through the program below and watch the variables get created.

7.6. Chapter 7 Project: Structured Song

Popular music consists of various sections, which include intro, verse, chorus, and bridge. The main goal of this project is to take advantage of custom functions in order to create a musical piece that has structural form (A-B-B-A for example). Use the following functions and concepts:

  • Called Chap7Proj

  • At least 15 seconds long.

  • Use fitMedia() and the advanced setEffect() (see EarSketch Example 7.1.)

  • Two custom functions for creating two different musical sections (see EarSketch Example 7.2). Make sure to call each section at least twice in some pattern (A-B-B-A for example).

Listen to the audio of the example project

8. Chapter Eight: File IO

8.1. Getting Data into Programs

In this book, we have covered 3 basic ways of getting data into programs:

  • Hard Coding: Writing data values directly into the code (age = 27) is generally referred to as hard coding. It is rarely appropriate for real programs because it does not allow the value to change without editing the source code.

  • User Input: Asking the user to input information (ex. input()) is the standard way of building interactive user software. It is ideal for programs that do not need lots of data.

  • Random Generator: Generating random values (ex. randint()) is fundamental to building programs designed for simulations, real world modeling, artificial intelligence (AI), and of course music.

In this chapter, we introduce a fourth way of getting data into programs: text file input. This is a common technique for programs which analyze data intensive systems like stock markets, social media websites, science experiments, etc.

8.2. Review: String.split()

In chapter 6, we introduced the string.split() function, which takes one big string and breaks it up into a list of smaller strings. The function uses a character (specified by the input parameter) to determine how to split the big string. Data text files are typically composed of lines of text separated by the new line character, that like the space character, is invisible white space but important. In Python the newline character is written "\n". Follow the example below to get a refresher on split() and the "\n" character.

PythonTutor Example 8.1

Split Function Review

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

8.3. Reading and Splitting Text Files

Python can open and read the entire contents of a text file with two simple functions: open() and read(). The open() function finds the file on the file system (hard drive). The read() function loads all of the contents of the file into one string value.

Once a file has been read, we can use the split() function with the newline ("\n") character to create a list of lines. We can then split any individual line to get a specific item on that line.

Assume you have a text file called mary.txt with the 4 lines below. Notice how there are newline characters between each sentence and space characters between each word.

mary-example.csv file
Mary had a little lamb
His fleece was white as snow
And everywhere that Mary went
The lamb was sure to go.

The following code would read the entire file, grab specific words out of the file, and print them out.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
f = open("mary.txt")
big_str = f.read()
line_list = big_str.split("\n")

first_line = line_list[0]
last_line = line_list[3]
first_line_word_list = first_line.split(" ")
last_line_word_list = last_line.split(" ")
print(first_line_word_list[3])
print(last_line_word_list[-1])
Testing File I/O
Web Browser Applications like Python Visualizer and EarSketch are not allowed to open files on the local computer. To test the code above, create the text file and the program on your desktop and then run the code inside the shell.

One alternative to opening a local file is to simply copy/paste the content with newline characters into the program (used in PythonTutor). Another alternative is to load a file from the web (used in EarSketch).

PythonTutor Asg. 8.1

Splitting a File

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Asg. 8.1

Text File Input and Splitting

This exercise loads the clipAndMeasures.txt file below using the importFile() function.

clipAndMeasures.txt file
HIPHOP_DUSTYGROOVE_018;1;7
HIPHOP_DUSTYMOOG_001;2;7
HIPHOP_DUSTYGUITAR_001;4;7

Modify the code below to add track 2 from the second line of the text file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from earsketch import *

init()
setTempo(100)

fileData = importFile("https://ggc-itec2120.github.io/EarSketchBook/data/clipAndMeasures.txt")

lines = fileData.split("\n")

track = 1
line = lines[0]
values = line.split(";")
clip = values[0]
start = int(values[1])
end = int(values[2])
fitMedia(clip, track, start, end)

# add track 2 from second line of the text file.

finish()
GGCReadSimpleFile Sol

8.4. Looping Through Files

The most common data file format is called the CSV file. It is composed of lines of comma separated values. Look at the example file for daily high temperatures in US cities. Notice how each line is composed of a city name, a date, and a temperature all separated by commas.

big_str
Atlanta,1/1/2012,67
Chicago,1/1/2012,47
Miami,1/1/2012,77
Atlanta,1/2/2012,59
Chicago,1/2/2012,48
Miami,1/2/2012,72
...

The following example assumes the file has 2 lines and has been read into the variable big_str. It loops through all contents of the file grabbing each value in a separate variable and converting data types when necessary.

PythonTutor Asg. 8.2

Looping Through a File

Try to predict the variable names, values, and data types in the the code example below. Use the Forward button to check your answers.

EarSketch Asg. 8.2

Looping Through a File

This exercise loads the clipAndMeasures.txt file below using the importFile() function.

clipAndMeasures.txt file
HIPHOP_DUSTYGROOVE_018;1;7
HIPHOP_DUSTYMOOG_001;2;7
HIPHOP_DUSTYGUITAR_001;4;7

Modify the code below to use a for loop to add all the lines from the file on separate tracks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from earsketch import *

init()
setTempo(100)

fileData = importFile("https://ggc-itec2120.github.io/EarSketchBook/data/clipAndMeasures.txt")

lines = fileData.split("\n")

# replace the code below with a for loop that adds all the lines on separate tracks
track = 1
line = lines[0]
values = line.split(";")
clip = values[0]
start = int(values[1])
end = int(values[2])
fitMedia(clip, track, start, end)

finish()
GGC 8 2

8.5. Perceptualizing Data

When working with large data sets, users usually want traditional visualizations such as charts and graphs. There are situations, however, where data can be turned into a more artistic perceptions such as digital paintings or sounds. This section explores how we can use sonification in EarSketch to create auditory perceptions of data.

EarSketch Example 8.1

Sonification

Sonification is a way to use non-speech audio to convey information, or in other words, turning data into sound. Sonification can be used to help scientists discover patterns in data, help musicians make interesting new kinds of music, or help the visually-impaired to understand data they can’t visualize.

There are many examples of music which has been created based on sonification such as a piano composition based on the number pi and a heavy metal song based on data from the Higgs Boson particle.

In this example, we will use stock information to alter the pitch of music. Below is one year’s worth of Google’s stock data obtained from Yahoo Finance Historical Data. The goog-data.csv file has seven values per line:

1. Date
2. Open Price
3. High
4. Low
5. Close Price
6. Volume
7. Adjusted Close Price
goog-data.csv file
7/27/2015,621,635.219971,620.5,625.609985,1831600,625.609985
8/3/2015,625.340027,647.859985,625.340027,635.299988,1621200,635.299988
8/10/2015,639.47998,674.900024,631.249023,657.119995,2531500,657.119995
8/17/2015,656.799988,667,612.330017,612.47998,2351900,612.47998
8/24/2015,573,643.590027,565.049988,630.380005,3802800,630.380005
8/31/2015,627.539978,635.799988,594.099976,600.700012,2460600,600.700012
9/8/2015,612.48999,626.52002,604.119995,625.77002,1815100,625.77002
9/14/2015,625.700012,650.900024,619.429993,629.25,2496200,629.25
9/21/2015,634.400024,636.48999,611,611.969971,2047200,611.969971
9/28/2015,610.340027,627.340027,589.380005,626.909973,2480600,626.909973
10/5/2015,632,650.609009,625.559998,643.609985,1978600,643.609985
10/12/2015,642.090027,664.969971,639.01001,662.200012,1599000,662.200012
10/19/2015,661.179993,730,641.72998,702,3296600,702
10/26/2015,701.549988,719.150024,701.26001,710.809998,2101200,710.809998
11/2/2015,711.059998,739.47998,705.849976,733.76001,1706300,733.76001
11/9/2015,730.200012,741,716.72998,717,1791300,717
11/16/2015,715.599976,757.919983,711.330017,756.599976,1728100,756.599976
11/23/2015,757.450012,762.708008,737.630005,750.26001,1427000,750.26001
11/30/2015,748.809998,775.955017,741.27002,766.809998,2362100,766.809998
12/7/2015,767.77002,768.72998,736.75,738.869995,2110200,738.869995
12/14/2015,741.789978,762.679993,724.169983,739.309998,2354800,739.309998
12/21/2015,746.130005,754.849976,740,748.400024,1246000,748.400024
12/28/2015,752.919983,779.97998,749.52002,758.880005,1515800,758.880005
1/4/2016,743,752,713,714.469971,2517000,714.469971
1/11/2016,716.609985,734.73999,685.369995,694.450012,2487000,694.450012
1/19/2016,703.299988,728.130005,673.26001,725.25,2534200,725.25
1/25/2016,723.580017,744.98999,694.390015,742.950012,2277600,742.950012
2/1/2016,750.460022,789.869995,680.150024,683.570007,5586500,683.570007
2/8/2016,667.849976,701.309998,663.059998,682.400024,3131900,682.400024
2/16/2016,692.97998,712.349976,685.049988,700.909973,2121200,700.909973
2/22/2016,707.450012,713.429993,680.780029,705.070007,1961600,705.070007
2/29/2016,700.320007,720,697.679993,710.890015,2038300,710.890015
3/7/2016,706.900024,726.919983,685.340027,726.820007,2257400,726.820007
3/14/2016,726.809998,743.070007,724.51001,737.599976,1981000,737.599976
3/21/2016,736.5,745.719971,731,735.299988,1533300,735.299988
3/28/2016,736.789978,757.880005,728.76001,749.909973,1656600,749.909973
4/4/2016,750.059998,752.799988,735.369995,739.150024,1212800,739.150024
4/11/2016,743.02002,761,731.01001,759,1444900,759
4/18/2016,760.460022,769.900024,713.609985,718.77002,2826100,718.77002
4/25/2016,716.099976,725.765991,689,693.01001,2631400,693.01001
5/2/2016,697.630005,711.859985,689.01001,711.119995,1678100,711.119995
5/9/2016,712,724.47998,709,710.830017,1489400,710.830017
5/16/2016,709.130005,721.52002,696.799988,709.73999,1716700,709.73999
5/23/2016,706.530029,733.935974,704.179993,732.659973,1688100,732.659973
5/31/2016,731.73999,739.72998,720.559998,722.340027,1487800,722.340027
6/6/2016,724.909973,729.539978,714.609985,719.409973,1338100,719.409973
6/13/2016,716.51001,725.440002,688.452026,691.719971,1832800,691.719971
6/20/2016,698.77002,702.77002,673.450012,675.219971,2270500,675.219971
6/27/2016,671,700.650024,663.283997,699.210022,1935500,699.210022
7/5/2016,696.059998,705.710022,688.215027,705.630005,1438400,705.630005
7/11/2016,708.049988,725.73999,707.23999,719.849976,1122800,719.849976
7/18/2016,722.710022,743.23999,721.190002,742.73999,1207600,742.73999

Below is an example of using setEffect() with data from the text file. Read the comments carefully to understand the code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from earsketch import *

# a custom function to help convert units
def unit_convert(in_val, in_min, in_max, out_min, out_max):
    norm_val = float(in_val - in_min) / float(in_max - in_min)
    return (norm_val * (out_max - out_min)) + out_min

init()
setTempo(120)

fitMedia(Y31_SYNTH_HARP_1,1,1,15)
fitMedia(HIPHOP_DUSTYGROOVE_007,2,1,15)

fileData = importFile("https://ggc-itec2120.github.io/EarSketchBook/data/goog-data.csv")
lines = fileData.split("\n")
start = 1
for line in lines:
  values = line.split(',')
  price = float(values[-1]) # get adjusted closing price
  # price can range from 600 to 767, but pitch should range from -12 to 12
  pitch = unit_convert(price, 600, 767, -12, 12)
  setEffect(1, PITCHSHIFT, PITCHSHIFT_SHIFT, pitch, start)
  start += 0.25 # increase by 1 beat per line of data

finish()
GGCStockData

EarSketch Asg. 8.3

Sonification

Convert the example above so that:

  1. The tempo is 100

  2. Instead of PITCHSHIFT on track 1, setEffect() changes the VOLUME for both tracks 1 and 2.

    • the GAIN should be mapped between -20 and 0

  3. Track 2 uses makeBeat() instead of fitMedia(). A clip should play for each line of data using:

    • the OS_SNARE04 clip when the stock price is above 700

    • the OS_OPENHAT06 clip otherwise.

Note: To make a single beat, use the makeBeat() function as follows:

makeBeat(OS_OPENHAT06, 2, start, "0+++")
GGC 8 3

8.6. Chapter 8 Project: Final Composition

Create an original song in EarSketch using what you’ve learned in this course.

  • Called Chap8Proj

  • Roughly 1 minute long.

  • Use setEffect() and fitMedia().

  • Pick 4 of the following requirements:

    • If

    • While

    • For loop

    • Custom functions

    • List

    • String slicing

    • One or more imported files with a loop. This can be one of the files provided (listed below) or any text file from the Internet.

Listen to the audio of the example project