Mini-Project 4 : Musical Copyright

Copyright is a legal “intellectual property” that gives owner exclusive rights to “copy, distribute, display, or perform” their own creative works. Copyright was developed in the 15th and 16th centuries in response to the printing press. Before the printing press, it was prohibitively time-consuming and expensive to copy a book—you had to do it by-hand! With the rise of the printing press, there were concerns that the work of an author would be copied and distributed without their consent, thus robbing them of the benefits—monetary and social—of developing that work. Copyright law was, therefore, developed to protect creators and incentive them to go through the effort of developing new work.

While copyright law was originally intended to protect book authors from the perils of the printing press, it has extended to virtually all creative industries, including music. For example, if you download a song from the Internet, e.g., from a torrent, you are likely violating the copyright of the artist and/or publishing company for that song. However, copyright law has had other chilling effects on the music industry. In, perhaps, the most infamous court case of its kind, Bright Tunes Music v. Harrisongs Music, the judge found that Beatles member George Harrison had “unconsciously copied” The Chiffons song He’s So Fine in his song My Sweet Lord. Similar cases of questionable quality have come up over the years, most recently between pop artist Katy Perry and Christian rap artist Flame. In that case, the judge ordered Perry and her associates to pay Flame 2.78 million dollars in damages although the ruling was eventually overturned.

In response to these copyright cases, lawyer Damien Rihel and technologist Noah Rubin took an extreme measure: they created a computer program to enumerate all possible melodies under a set of constraints (eight note songs drawn from a diatonic scale) and write them to disk. By writing them to disk, they, in theory, have infringed on the copyright of every existing song and copyrighted any song that has yet to be written!

For this mini-project, we will follow in Rihel and Rubin’s footsteps and write a small recursive program capable of enumerating all the songs of a given length drawn from a set of notes. We will briefly then reflect on the nature of computers, copyright, and creativity.

For this mini-project, write your code and reflection in a file called all-songs.scm.

Recursive Decompositions, Documentation, and Testing

For all the functions you write in this mini-project, make sure you:

  1. Provide a recursive decomposition of the function in a comment above the function’s definition if the function is recursive.
  2. Provide an appropriate docstring.
  3. Write a test suite adequately exercising the behavior of that function. Each function has examples of its execution; definitely use these examples as a starting point for your tests. Add more to ensure that you are covering all possible paths of execution in your function.

Finally, do not worry about providing test suites for functions that produce musical compositions as we do not have a meaningful way to test compositions for equality!

Part 1: Cartesian Product

As a warm-up to writing a function that produces all combinations of musical notes of a certain size, we’ll focus on the case where our compositions only have 2 notes. From there we’ll apply the technique developed in this part and generalize it to the case where the number of notes in the composition is arbitrary.

First, write a recursive function, (all-list2 v lst) that takes a value v and a list of values and creates a list of all possible lists of size 2 where the first element is v and the second element is a value from lst. For example:

(all-list2 "q" (range 5))
> (list (list "q" 0) (list "q" 1) (list "q" 2) (list "q" 3) (list "q" 4))

(all-list2 "q" null)
> null

Begin by using these examples to derive the recursive decomposition:

To generate all the lists of size two where the first element is v and the second element is drawn from a list lst:

  • When lst is empty, …
  • When lst is non-empty, …

Remember that in your recursive decomposition, you assume you can recursively “do the operation” on the tail of the list you are recursively decomposing. Use this assumption to write out what to do in the non-empty case. After you are done, create an appropriate docstring for all-list2 and implementation from this decomposition.

Next, use all-list2 to write a recursive function, (cartesian-product l1 l2) that takes two lists and produces the Cartesian Product of the elements drawn from lists l1 and l2. The Cartesian Product of two lists is a list that contains all the possible lists of size 2 (list x y) where x is drawn from l1 and y is drawn from l2.

(cartesian-product (range 3) (list "a" "b"))
> (list (list 0 "a") (list 0 "b")
        (list 1 "a") (list 1 "b")
        (list 2 "a") (list 2 "b"))

(cartesian-product null null)
> null

Again, begin with the recursive decomposition for this function. Like append, we have a choice of two lists to perform recursion over; let’s choose the first:

To form all pairs of values whose first component is drawn from l1 and second component is drawn from l2:

  • When l1 is empty, …
  • When l2 is non-empty, …

When design your recursive decomposition, ask yourself: “what is the “recursive assumption” that I can utilize in writing the recursive case?” After you have completed your recursive design, make sure to write a docstring and implementation for cartesian-product. When you go to implementation, you should use all-list2 to perform the work necessary in the non-empty case and combine this work with the work done in the recursive call with append.

Finally, use cartesian-product and a (small) list pipeline to write a function (all-two-note-songs notes) that takes a list of notes (as MIDI note values) as input and produces all the possible two note songs drawn from the list of provided notes. The duration of the notes should be quarter notes qn. For this function, think about what you should pass to cartesian-product to get the “effect” of all combinations of two notes drawn from notes and then how to transform that collection into a list of compositions using map.

Demonstrate that all-two-note-songs works by defining a list called two-note-example containing all 2 note songs drawn from the notes C (MIDI note 60) and A (MIDI note 69). You should have $2 \times 2 = 4$ compositions in your resulting list.

Part 2: All Combinations

In part 1, you wrote a function that generates all two-note melodies drawn from a collection of notes. Now, we will generalize these functions to write a function to generate all n-note melodies for any natural number n. While we will follow the same pattern of implementation from part 1, we will not reuse implementation, i.e., these functions will not call on all-list2 or cartesian-product.

First, implement a recursive function (cons-all x lsts) that takes a single value x and a list of lists, lsts, and returns lsts but with x added to the front of every list.

(cons-all 0 (list (list 1 2)
                  (list 3 4 5)
                  (list 6 7)))
> (list (list 0 1 2)
        (list 0 3 4 5)
        (list 0 6 7))
(cons-all 0 null)
> null

Now, use cons-all to implement (combinations lsts) that returns a list of lists. For each list returned in the result, the ith element of the list is drawn from ith list of lsts. The result, therefore, contains all the ways we can combine the elements of the lists found in lsts.

(combinations (list (list 1 2)
                    (list 3 4 5)
                    (list 6 7)))
> (list
    (list 1 3 6) (list 1 3 7)
    (list 1 4 6) (list 1 4 7)
    (list 1 5 6) (list 1 5 7)
    (list 2 3 6) (list 2 3 7)
    (list 2 4 6) (list 2 4 7)
    (list 2 5 6) (list 2 5 7))

(combinations null)
> (list null)

Note that when given the empty list, combinations produces a list containing null, not null itself! This is a little bit strange, but intuitively, there is one way to form a valid list when we are given nothing—just null itself! Also note that if the list passed to combinations only contains two lists, then the function returns the same output as cartesian-product!


(combinations (list (range 3)
                    (list "a" "b")))
> (list (list 0 "a") (list 0 "b")
        (list 1 "a") (list 1 "b")
        (list 2 "a") (list 2 "b"))

(combinations (list null null))
> null

To implement combinations, you need to be very careful about types! You are manipulating three levels of objects here:

  • Individual values.
  • Lists of values.
  • Lists of lists of values.

In your recursive decomposition, be clear about which of three types you are manipulating at every step in your reasoning.

You will likely find it useful to also try the recursive decomposition out on concrete examples to get a sense of how to proceed. Choose a number of small examples, say 3–5 of them, stick to what our recursive decomposition gets you, i.e., a case analysis in terms of empty/non-emptiness, and once you have written then out, see if you can generalize the pattern of behavior you see in them

Finally, use combinations to write a function (all-songs n notes) that takes a non-negative number n and a list of notes (as MIDI note values) as input and produces all the possible songs of n notes drawn from the list of provided notes. The duration of the notes should be quarter notes qn. You may implement this function with either recursion or a list transformation pipeline.

Demonstrate that all-songs works by defining a list called five-note-example containing all 5 note songs drawn from the notes C (MIDI note 60), B♭ (MIDI note 58), and F (MIDI note 65).

Part 3: Reflection

Once you have finished your all-songs implementation, let’s reflect on what we have done. You hopefully noticed that your recursive implementation of all-songs is simple and elegant (although, perhaps, difficult to have derived in the first place). But yet, it is capable of generating, literally, all the songs, according to the opinion of Rihel and Rubin. The fact that such a simple thing is capable of so much calls into question why we value music in the first place. Computers can play music—we wrote all that in the first two mini-projects—and now we can compose music (“all the music”!) as well. Of course, this does not apply only to music; other creative endeavours such as writing, art, and dance are, to varying degrees, already being challenged by computation.

In a few paragraphs (at most one page of text), respond to the following prompt:

Do you think music should still be valued in light of modern-day computation’s ability to “do it all?” If so, what do you personally value about music in spite of this assignment? If not, why do you feel that music has lost its value?

You should leave your response as a comment at the bottom of all-songs.scm. In formatting your text, feel free to use line breaks within a paragraph to avoid making lines that are too long, e.g., favor this style of formatting:

; Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sit amet
; porta massa. Proin fermentum mi eu magna tristique, nec gravida sapien luctus.
; Vivamus ut tincidunt dolor, a ultrices velit. Curabitur volutpat augue mollis
; dictum maximus. Maecenas magna enim, euismod a mauris sed, convallis blandit
; dui. Suspendisse ut nisl vitae tellus malesuada vehicula. Cras tincidunt
; commodo libero, ut lacinia sem. Donec sit amet convallis ante. Vivamus cursus
; nec massa eget finibus. Integer mattis ac mi ac blandit. Cras ligula felis,
; rhoncus sit amet facilisis non, gravida quis justo.

versus this style of formatting:

; Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sit amet porta massa. Proin fermentum mi eu magna tristique, nec gravida sapien luctus. Vivamus ut tincidunt dolor, a ultrices velit. Curabitur volutpat augue mollis dictum maximus. Maecenas magna enim, euismod a mauris sed, convallis blandit dui. Suspendisse ut nisl vitae tellus malesuada vehicula. Cras tincidunt commodo libero, ut lacinia sem. Donec sit amet convallis ante. Vivamus cursus nec massa eget finibus. Integer mattis ac mi ac blandit. Cras ligula felis, rhoncus sit amet facilisis non, gravida quis justo.

Where all the text of a paragraph appears on a single line.

This is, of course, not a writing course, so we are not scrutinizing your response to the degree we would if this were Tutorial. But we will be checking that (a) you actually answer the prompt at hand and (b) your response demonstrates that you have put some genuine thought about the nature of computation in relation to music.

Summary of Deliverables

all-songs.scm

  • Part 1:
    • (all-list2 v l)
    • (cartesian-product l1 l2)
    • (all-two-note-songs notes)
    • two-note-example
  • Part 2:
    • (cons-all v lsts)
    • (combinations lsts)
    • (all-songs n notes)
    • five-note-example
  • Part 3:
    • Response to writing prompt given in a comment.