Instructions for measureMunger

(produced at 03:33 a.m. UTC on 2024-10-31)

This task is part of project08 which is due at 23:00 EST on 2024-11-05.

You have the option to work with a partner on this task if you wish. Working with a partner requires more work to coordinate schedules, but if you work together and make sure that you are both understanding the code you write, you will make progress faster and learn more.

You can download the starter code for this task using this link.

You can submit this task using this link.

Put all of your work for this task into the file measureMunger.py
(which is provided among the starter files)

This project is very similar the shapeSorter task which uses turtle to draw pictures instead of wavesynth to generate audio. You only have to do one of the two.

In this task you will define a number of short functions divided into several groups, to help you practice using list comprehensions and sorting:

  • List-builder functions:
    • makeRunsList
    • makeTriplesList
    • makeListWithDirections
    • makeMeasuresList
  • List-filtering functions:
    • oddNotesMeasures
    • measuresInDirection
    • measuresThatReach
  • Sorting helper functions:
    • getDirectionAndNotes
    • getPitchSpanIntervalAndNotes
  • Sorting functions:
    • sortByInterval
    • sortByDirection
    • sortBySpan
  • Final audio function:
    • addMeasureSequence

Almost all of these functions can be written in just one or two lines of code. We have provided a few helper functions that you will need for several of your functions:

  • pitchReachedFromC4 which can compute the pitch of the last note in a sequence of notes if the sequence starts at C4 and uses the specified interval between notes, number of notes, and direction (True for up or False for down). fit a polygon inside it.
  • pitchSpanFromC4 which can compute the ratio between the highest and lowest notes of a note sequence using a specific interval, number of notes, and direction (again assuming it starts at C4).
  • customMeasure which can add notes for a custom measure to the current track.
  • tuneTest which will use many of your functions together to create a complex track (we have also provided a test_measureMunger.py file for local testing).

As usual, each function you write must be documented.

Specifications

A key concept in this project is a specification: a tuple of values that specify the arguments for a function. The function in this case is customMeasure, which has three parameters: the interval between notes, the number of notes, and whether the notes increase (True) or decrease (False) in pitch. Each specification that we use will be a tuple with 3 elements holding the interval, notes, and direction. For example, the tuple:

(1, 3, False)

specifies that a sequence of 3 notes should be created, each one scale rung below the last (they'd be going up if the last value had been True instead). If we have a specification stored in a variable, we can use indexing or unpacking to access the individual parts, like so:

spec = (1, 3, True)
# Indexing to get parts of tuple:
interval = spec[0]
noteCount = spec[1]
goingUp = spec[2]
# Unpacking to get parts of tuple:
interval, noteCount, goingUp = spec

When the time comes to actually call customMeasure using a specification, we will need to unpack it so that we can provide each argument to customMeasure one at a time. If we have individual variables and want to create a specification, we can just use parentheses and commas, like so:

myDirection = True
myInterval = 2
myNotes = 4
mySpec = (myInterval, myNotes, myDirection)  # order is important here

Most functions in this assignment will deal with specifications one way or another.

Part A: List-building functions

For each list-building function, you will define a function that takes a few parameters and builds and returns a list of specification tuples (see above) using a list comprehension:

As usual, refer to the examples section for concrete examples of how these functions should work.

Part B: List-filtering functions

For each list-filtering function, you will define a function that takes a few parameters and returns a new list of specification tuples (see above) based on filtering out some of the provided specifications using a list comprehension :

Sorting Reminders

As you know, in order to do any custom sorting we need to define a key function that will take in one element being sorted and return a "key" object that determines how that element will get sorted (the rest of the sorting process is automatic).

For example, if our key function was the following:

def characterKey(character):
    if character == 'C':
        return 1
    elif character == 'S':
        return 2
    elif character == '1':
        return 100

then if we called .sort using that function like this:

letters = ['1', 'C', '1', 'S', '1']
letters.sort(key=characterKey)
print(letters)

We'd see the following output:

['C', 'S', '1', '1', '1']

That's because Python orders the key values from lowest to highest, and then arranges the original items based on where their key values end up. Since our characterKey function returns the number 1 as the key for the letter 'C', and that's smaller than the keys for the other letters we use, that letter ends up first in the result, etc.

As an additional reminder, to break ties when sorting, if the key value is a tuple or some other kind of sequence (including a string), Python tries to sort using just the first element of the sequence, then breaks ties based on the ordering of the second elements of each key, then breaks double-ties based on the third elements, and so on. So you can use tuples as the return value from a key function to specify both primary sort order (using first element of the tuple) and secondary sort orders in case of ties (using subsequent elements).

Part C: Sorting helper functions

For the next part, you'll define the key functions that we'll use to sort with:

Part D: Sorting functions

Now that you have helper functions ready, you'll define some sorting functions which can be used to re-order specification lists. These functions will NOT return anything because they will directly re-arrange the specifications list they are given . Each of these functions must call the .sort list method , and they may not use any loops (which aren't necessary).

Part E: Building with specifications

For the final part of this project, you have to implement a addMeasureSequence function which takes a specifications list, a starting pitch, and a start time and adds notes for each specified measure one after the other starting from the given start pitch & starting at the given start time.

The whole process starts at the given pitch and starting time within the track, but you won't modify pitches or times between calls to customMeasure: just let the pitch changes from one measure dictate the starting pitch of the next so that they flow together.

addMeasureSequence must do the following:

Notes

  • As in other assignments, there is an extra goal to not waste the results of fruitful functions, but for this project the "don't waste boxes" goal is not used, since we might want to unpack a multi-part variable but then ignore some parts of it.

Examples

makeRunsList examples

These examples show what makeRunsList should return.

In []:
makeRunsList([4, 2, 3])
Out[]:
[(1, 4, True), (1, 2, True), (1, 3, True)]
In []:
makeRunsList([1, 1, 2, 3])
Out[]:
[(1, 1, True), (1, 1, True), (1, 2, True), (1, 3, True)]
In []:
makeRunsList([8, 9, 10])
Out[]:
[(1, 8, True), (1, 9, True), (1, 10, True)]

makeTriplesList examples

These examples show what makeTriplesList should return.

In []:
makeTriplesList(True, [2, 1, 3])
Out[]:
[(2, 3, True), (1, 3, True), (3, 3, True)]
In []:
makeTriplesList(False, [4])
Out[]:
[(4, 3, False)]
In []:
makeTriplesList(True, [2, 2, 4, 2])
Out[]:
[(2, 3, True), (2, 3, True), (4, 3, True), (2, 3, True)]

makeListWithDirections examples

These examples show what makeListWithDirections should return.

In []:
makeListWithDirections([(8, 1), (6, 2), (4, 3)], True)
Out[]:
[(8, 1, True), (6, 2, True), (4, 3, True)]
In []:
makeListWithDirections([(3, 5), (3, 4), (4, 4)], False)
Out[]:
[(3, 5, False), (3, 4, False), (4, 4, False)]
In []:
makeListWithDirections([(5, 2), (1, 3), (7, 2), (5, 3)], True)
Out[]:
[(5, 2, True), (1, 3, True), (7, 2, True), (5, 3, True)]

makeMeasuresList examples

These examples show what makeMeasuresList should return.

In []:
makeMeasuresList([1, 2, 4], [8, 6, 3], [False, False, True])
Out[]:
[(1, 8, False), (2, 6, False), (4, 3, True)]
In []:
makeMeasuresList( [3, 1, 2, 3, 2, 3, 4], [4, 6, 8, 6, 4, 5, 5], [False, False, True, True, False, True, False] )
Out[]:
[ (3, 4, False), (1, 6, False), (2, 8, True), (3, 6, True), (2, 4, False), (3, 5, True), (4, 5, False), ]
In []:
makeMeasuresList([4], [1], [False])
Out[]:
[(4, 1, False)]

oddNotesMeasures examples

These examples show what oddNotesMeasures should return.

In []:
oddNotesMeasures( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] )
Out[]:
[(1, 3, True), (1, 5, False)]
In []:
oddNotesMeasures( [ (1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True), ] )
Out[]:
[ (1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True), ]
In []:
oddNotesMeasures( [ (3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True), ] )
Out[]:
[(3, 3, True), (5, 3, False), (2, 5, False), (5, 1, True)]

measuresInDirection examples

These examples show what measuresInDirection should return.

In []:
measuresInDirection( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], True )
Out[]:
[(1, 3, True), (1, 4, True), (1, 6, True)]
In []:
measuresInDirection( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], False )
Out[]:
[(1, 5, False), (1, 2, False)]
In []:
measuresInDirection( [ (1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True), ], True )
Out[]:
[(1, 3, True), (3, 3, True), (5, 3, True), (6, 3, True)]

measuresThatReach examples

These examples show what measuresThatReach should return.

In []:
measuresThatReach( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], 293.672 )
Out[]:
[(1, 3, True), (1, 4, True), (1, 6, True)]
In []:
measuresThatReach( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], 392.0051 )
Out[]:
[(1, 4, True), (1, 6, True)]
In []:
measuresThatReach( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], 1046.528 )
Out[]:
[]

getDirectionAndNotes examples

These examples show what getDirectionAndNotes should return.

In []:
getDirectionAndNotes((1, 3, True))
Out[]:
(True, 3)
In []:
getDirectionAndNotes((1, 4, True))
Out[]:
(True, 4)
In []:
getDirectionAndNotes((3, 3, True))
Out[]:
(True, 3)

getPitchSpanIntervalAndNotes examples

These examples show what getPitchSpanIntervalAndNotes should return.

In []:
getPitchSpanIntervalAndNotes((1, 3, True))
Out[]:
(1.498307076876685, 1, 3)
In []:
getPitchSpanIntervalAndNotes((5, 3, True))
Out[]:
(8.000000000000028, 5, 3)
In []:
getPitchSpanIntervalAndNotes((5, 3, False))
Out[]:
(7.9999999999999964, 5, 3)

addMeasureSequence examples

These examples show what notes should added when addMeasureSequence is f called.

In []:
addMeasureSequence( [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)], 261.632, 0 )
Audio In []:
addMeasureSequence( [ (1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True), ], 329.6357, 0 )
Audio In []:
addMeasureSequence( [ (3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True), ], 880.0216, 0.5 )
Audio

sortByInterval examples

These examples show how the order of the target list should be modified when calling sortByInterval. Remember that sortByInterval is NOT supposed to use return but should instead modify the order of the list it's given using the .sort method. The prints here are part of our testing setup; your sortByInterval function does NOT need to print anything.

In []:
specifications = [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] print("Before sorting we have:") print(specifications) returned = sortByInterval(specifications, True) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] After sorting we get: [(1, 2, False), (1, 3, True), (1, 4, True), (1, 5, False), (1, 6, True)]
In []:
specifications = [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] print("Before sorting we have:") print(specifications) returned = sortByInterval(specifications, False) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] After sorting we get: [(1, 6, True), (1, 5, False), (1, 4, True), (1, 3, True), (1, 2, False)]
In []:
specifications = [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] print("Before sorting we have:") print(specifications) returned = sortByInterval(specifications, True) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] After sorting we get: [(1, 3, True), (2, 3, False), (3, 3, True), (4, 3, False), (5, 3, True), (6, 3, True)]
In []:
specifications = [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] print("Before sorting we have:") print(specifications) returned = sortByInterval(specifications, False) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] After sorting we get: [(6, 3, True), (5, 3, True), (4, 3, False), (3, 3, True), (2, 3, False), (1, 3, True)]

sortByDirection examples

These examples show how the order of the target list should be modified when calling sortByDirection. Remember that sortByDirection is NOT supposed to use return but should instead modify the order of the list it's given using the .sort method. The prints here are part of our testing setup; your sortByDirection function does NOT need to print anything.

In []:
specifications = [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] print("Before sorting we have:") print(specifications) returned = sortByDirection(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] After sorting we get: [(1, 2, False), (1, 5, False), (1, 3, True), (1, 4, True), (1, 6, True)]
In []:
specifications = [(3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True)] print("Before sorting we have:") print(specifications) returned = sortByDirection(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True)] After sorting we get: [(5, 3, False), (1, 4, False), (2, 5, False), (5, 1, True), (3, 3, True), (3, 4, True), (1, 6, True)]
In []:
specifications = [(5, 1, True), (3, 4, True), (2, 5, False), (1, 6, True), (5, 3, False), (1, 4, False), (3, 3, True)] print("Before sorting we have:") print(specifications) returned = sortByDirection(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(5, 1, True), (3, 4, True), (2, 5, False), (1, 6, True), (5, 3, False), (1, 4, False), (3, 3, True)] After sorting we get: [(5, 3, False), (1, 4, False), (2, 5, False), (5, 1, True), (3, 3, True), (3, 4, True), (1, 6, True)]

sortBySpan examples

These examples show how the order of the target list should be modified when calling sortBySpan. Remember that sortBySpan is NOT supposed to use return but should instead modify the order of the list it's given using the .sort method. The prints here are part of our testing setup; your sortBySpan function does NOT need to print anything.

In []:
specifications = [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] print("Before sorting we have:") print(specifications) returned = sortBySpan(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (1, 4, True), (1, 5, False), (1, 2, False), (1, 6, True)] After sorting we get: [(1, 2, False), (1, 3, True), (1, 4, True), (1, 5, False), (1, 6, True)]
In []:
specifications = [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] print("Before sorting we have:") print(specifications) returned = sortBySpan(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(1, 3, True), (3, 3, True), (2, 3, False), (5, 3, True), (4, 3, False), (6, 3, True)] After sorting we get: [(1, 3, True), (2, 3, False), (3, 3, True), (4, 3, False), (5, 3, True), (6, 3, True)]
In []:
specifications = [(3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True)] print("Before sorting we have:") print(specifications) returned = sortBySpan(specifications) if returned != None: print('Oops, the sorting function had a return value!') print("After sorting we get:") print(specifications)
Prints
Before sorting we have: [(3, 3, True), (1, 4, False), (5, 3, False), (1, 6, True), (2, 5, False), (3, 4, True), (5, 1, True)] After sorting we get: [(1, 4, False), (5, 1, True), (1, 6, True), (3, 3, True), (2, 5, False), (3, 4, True), (5, 3, False)]

tuneTest example

Although the code for tuneTest was provided with the starter code, it won't work until all of your other functions are working. This shows what the result should sound like when tuneTest is run after your project is complete. You can hear the results of the various sorting functions used by tuneTest.

In []:
tuneTest()
Audio

Rubric

Group goals:
 
unknown All functions are documented
Each function you define must include a non-empty documentation string as the very first thing in the function.
 
unknown Do not ignore the results of any fruitful function calls
According to the "Don't waste fruit" principle, every place you call a fruitful function (built-in or custom) you must store the result in a variable, or that function call must be part of a larger expression that uses its return value.
 
unknown makeRunsList must return the correct result
The result returned when your makeRunsList function is run must match the solution result.
 
unknown makeTriplesList must return the correct result
The result returned when your makeTriplesList function is run must match the solution result.
 
unknown makeListWithDirections must return the correct result
The result returned when your makeListWithDirections function is run must match the solution result.
 
unknown makeMeasuresList must return the correct result
The result returned when your makeMeasuresList function is run must match the solution result.
 
unknown oddNotesMeasures must return the correct result
The result returned when your oddNotesMeasures function is run must match the solution result.
 
unknown measuresInDirection must return the correct result
The result returned when your measuresInDirection function is run must match the solution result.
 
unknown measuresThatReach must return the correct result
The result returned when your measuresThatReach function is run must match the solution result.
 
unknown getDirectionAndNotes must return the correct result
The result returned when your getDirectionAndNotes function is run must match the solution result.
 
unknown getPitchSpanIntervalAndNotes must return the correct result
The result returned when your getPitchSpanIntervalAndNotes function is run must match the solution result.
 
unknown sortByInterval must modify its first argument correctly
We will call sortByInterval with a test argument, and check to make sure that it modifies its first argument correctly. We will also make sure that the function returns None.
 
unknown sortByDirection must modify its first argument correctly
We will call sortByDirection with a test argument, and check to make sure that it modifies its first argument correctly. We will also make sure that the function returns None.
 
unknown sortBySpan must modify its first argument correctly
We will call sortBySpan with a test argument, and check to make sure that it modifies its first argument correctly. We will also make sure that the function returns None.
 
unknown addMeasureSequence must produce the correct note sequence
The notes added to the current track when addMeasureSequence is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown tuneTest must produce the correct note sequence
The notes added to the current track when tuneTest is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown Define makeRunsList with 1 parameter
Use def to define makeRunsList with 1 parameter
 
unknown Use a comprehension
Within the definition of makeRunsList with 1 parameter, use a comprehension in at least one place.
 
unknown Define makeTriplesList with 2 parameters
Use def to define makeTriplesList with 2 parameters
 
unknown Use a comprehension
Within the definition of makeTriplesList with 2 parameters, use a comprehension in at least one place.
 
unknown Define makeListWithDirections with 2 parameters
Use def to define makeListWithDirections with 2 parameters
 
unknown Use a comprehension
Within the definition of makeListWithDirections with 2 parameters, use a comprehension in at least one place.
 
unknown Define makeMeasuresList with 3 parameters
Use def to define makeMeasuresList with 3 parameters
 
unknown Use a comprehension
Within the definition of makeMeasuresList with 3 parameters, use a comprehension in at least one place.
 
unknown Call len
Within the definition of makeMeasuresList with 3 parameters, call len in at least one place.
 
unknown Call range
Within the definition of makeMeasuresList with 3 parameters, call range in at least one place.
 
unknown Define oddNotesMeasures with 1 parameter
Use def to define oddNotesMeasures with 1 parameter
 
unknown Use a comprehension
Within the definition of oddNotesMeasures with 1 parameter, use a comprehension in at least one place.
 
unknown Define measuresInDirection with 2 parameters
Use def to define measuresInDirection with 2 parameters
 
unknown Use a comprehension
Within the definition of measuresInDirection with 2 parameters, use a comprehension in at least one place.
 
unknown Define measuresThatReach with 2 parameters
Use def to define measuresThatReach with 2 parameters
 
unknown Use a comprehension
Within the definition of measuresThatReach with 2 parameters, use a comprehension in at least one place.
 
unknown Call pitchReachedFromC4
Within the comprehension within the definition of measuresThatReach with 2 parameters, call pitchReachedFromC4 in at least one place.
 
unknown Define measuresThatReach with 2 parameters
Use def to define measuresThatReach with 2 parameters
 
unknown Use a comprehension
Within the definition of measuresThatReach with 2 parameters, use a comprehension in at least one place.
 
unknown Call pitchReachedFromC4
Within the definition of measuresThatReach with 2 parameters, call pitchReachedFromC4 in at least one place.
 
unknown Define getDirectionAndNotes with 1 parameter
Use def to define getDirectionAndNotes with 1 parameter
 
unknown Do not use any kind of loop
Within the definition of getDirectionAndNotes with 1 parameter, do not use any kind of loop.
 
unknown Define getPitchSpanIntervalAndNotes with 1 parameter
Use def to define getPitchSpanIntervalAndNotes with 1 parameter
 
unknown Do not use any kind of loop
Within the definition of getPitchSpanIntervalAndNotes with 1 parameter, do not use any kind of loop.
 
unknown Call pitchSpanFromC4
Within the definition of getPitchSpanIntervalAndNotes with 1 parameter, call pitchSpanFromC4 in at least one place.
 
unknown Define sortByInterval with 2 parameters
Use def to define sortByInterval with 2 parameters
 
unknown Call sort
Within the definition of sortByInterval with 2 parameters, call sort in at least one place.
 
unknown Do not use any kind of loop
Within the definition of sortByInterval with 2 parameters, do not use any kind of loop.
 
unknown Do not use a return statement
Within the definition of sortByInterval with 2 parameters, do not use return _.
 
unknown Define sortByDirection with 1 parameter
Use def to define sortByDirection with 1 parameter
 
unknown Call sort
Within the definition of sortByDirection with 1 parameter, call sort in at least one place.
 
unknown Do not use any kind of loop
Within the definition of sortByDirection with 1 parameter, do not use any kind of loop.
 
unknown Do not use a return statement
Within the definition of sortByDirection with 1 parameter, do not use return _.
 
unknown Define sortBySpan with 1 parameter
Use def to define sortBySpan with 1 parameter
 
unknown Call sort
Within the definition of sortBySpan with 1 parameter, call sort in at least one place.
 
unknown Do not use any kind of loop
Within the definition of sortBySpan with 1 parameter, do not use any kind of loop.
 
unknown Do not use a return statement
Within the definition of sortBySpan with 1 parameter, do not use return _.
 
unknown Define addMeasureSequence with 3 parameters
Use def to define addMeasureSequence with 3 parameters
 
unknown Use any kind of loop
Within the definition of addMeasureSequence with 3 parameters, use any kind of loop in at least one place.
 
unknown Call setPitch
Within the definition of addMeasureSequence with 3 parameters, call setPitch in exactly one place.
 
unknown Call setTime
Within the definition of addMeasureSequence with 3 parameters, call setTime in exactly one place.
 
unknown Call customMeasure
Within the definition of addMeasureSequence with 3 parameters, call customMeasure in at least one place.
 
unknown Do not call sort
Within the definition of addMeasureSequence with 3 parameters, do not call sort.
 
unknown Do not use a return statement
Within the definition of addMeasureSequence with 3 parameters, do not use return _.