Lab Exercise 4: Building a piece
This week we're going to build upon the prior week's project, focusing on using it to create a piece. We'll do this by building up players and patterns one by one, testing each as we go.
For today's lab, download this zip file and put it in a working directory. The Desktop is fine.
Open up the maxpat file. Let's go through its structure from top to bottom.
- The checkbox controls whether the metronome is on or off.
- The slider controls the metronome speed.
- The slider also feeds the prepend object, which creates a message that is the string 'play' followed by a number.
- The prepend object feeds the right input of a message box. The metronome feeds the left input of the same message box. The slider and prepend object control the contents of the message. The metronome specifies when to send the message.
- The message play XX, where XX is a number, goes to the python engine.
- The python engine sends one output to the unpack object, which splits up a list into its component parts. The arguments to the unpack object specify that the list should have four parts. Each of these feeds a different output.
- The first three of the outputs are pitch, velocity and duration. These three feed the makenote object. The fourth output is the MIDI channel, which feeds the noteout object. Note that the choice of the meaning and order of the values is completely arbitrary. They are all just numbers. How we use them is what gives them meaning. We have to make sure that the python code is using the same ordering and meaning as the Max patcher.
- The four number fields show the output of the python script engine.
Play the patcher and see if you can work out what is occurring.
Open the file tune.py in TextWrangler. First, focus on the
definitions of pattern and player. Read the comments in the file.
- The variable patterns is a list of lists of lists. Another way to phrase it is that the variable patterns is a list of specific rhythmic/tonal patterns. Each individual pattern is a list of notes. Each note contains a pitch, a duration, and a velocity (volume).
- The variable players is a list of lists. Another way to phrase it, is that players is a list of individual players. Each individual player is a list of six numbers that characterize the player. We are using them with the meaning specified in the comments.
- whichPattern is a single list of integers. Each number specifies which pattern a certain player is currently using. The first number corresponds to the first player's pattern, and so on.
Look at the play function. It has two parts to it. The first part is
the three global statements that tell the function to use the
variables whichPattern, player, and pattern defined outside the
The second part of the function is a loop. The for loop executes once for each player in the player list. Inside the for loop, it calls the function playtune, which requires three arguments. The arguments are the current player information, the current patter, and the time unit of a tick. Once the function has called playtune for each player, it terminates.
The play function has some other parts to it that are commented out. One part enables players to randomly choose their next pattern to play. The second part shows how you could randomly shuffle the ordering or a pattern.
Scroll up to the function playtune. This function has four parts.
- The first part is the function definition. The name of the function is playtune, and it takes three arguments. The first is a player list. The second is a pattern list. The third is the time (in ms) of a tick (an integer).
- The second part specifies what happens if the tick count is zero. The tick count will be zero only when the function is supposed to play a note. Note that the following code is indented so that it is inside the if condition. The first set of assignments get useful values out of the player list. The second set of assignments calculate the pitch, duration, and velocity of the current note. The maxObject.outlet function then sets the output channel to a list with 4 items. The ordering of these items has to match how they are used in Max.
- The third part increments the tick counter (player).
- The last part tests if the tick counter has reached the end of the current note. If so, then the tick counter goes back to zero and the note counter moves ahead to the next note in the sequence. The modulo computation means that it will loop back to the first note in the sequence after reaching the end.
- Delete all the patterns but the first one. Then change whichPattern to be a list of all zeros. Uncomment all the players and see what happens.
- Create some new patterns. Try out different things.
- Change around one or more of your players. Comment all but one out while you are testing a single player. Experiment with different base pitches, volumes, and MIDI channels. The others should really just be zeros.
- Take a look at the sttune.py. Play it and see what happens. Work through the main function and see if you can figure out what it is doing. It works almost identically to the tune.py file.
Put a comment character, #, in front of all but one of the player lists. Reload the script and turn on the metronome. Try each of the other players by themselves. Can you predict their sound?
Once you are comfortable with the above material, go on to the next project.