How to do calculations in lists with *args in Python 3.5.1
<p>I'm not even sure how to ask this question; I've been doing programming for about a month and the progress I've made on this program is still a little bit above my head, so I'm sorry if the question is a little incomprehensible. I'm taking a programming class, but as far as I know, this program is just for my own functionality and enjoyment for music.</p>

<p>I'm trying to write a function that takes musical notes, represented by integers, and spits out a specific arrangement and transformation of those numbers. Specifically I'm trying to convert them into something from musical set theory called "prime form".</p>

<p>I wrote a function that successfully does this for a set of three pitches, but I wanted to expand it so that I could have any number of arguments for the function.</p>

<p>Hereâs the code for the first function</p>

<pre><code>def prime_form (pitch1, pitch2, pitch3, tones_in_octave = 12):
    """
    (int, int, int, int) -&gt; (str)

    finds the prime form of any 3 note pitch set in any equal temperament,
    one octave span of frequency classes (default is 12 tones).

    &gt;&gt;&gt; prime_form (9, 1, 5)
    (0 4 8)
    this is the prime form!
    &gt;&gt;&gt; prime_form (11, 1, 0)
    (0 1 2)
    this is the prime form!
    &gt;&gt;&gt; prime_form (1, 3, 4)
    (0 1 3)
    this is the prime form!
    """
    pitches = [pitch1 %tones_in_octave, pitch2 %tones_in_octave, pitch3 %tones_in_octave]
    spitches = sorted(pitches)
    intervals = [(spitches[1] - spitches[0]) %tones_in_octave, (spitches[2] - spitches[1]) %tones_in_octave, (spitches [0] - spitches[2]) %tones_in_octave]
    sintervals = sorted(intervals) 
    prime_form = [0, sintervals[0], sintervals[0]+sintervals[1]]
    print('({} {} {})\nthis is the prime form!'.format(prime_form[0], prime_form[1], prime_form[2]))        
</code></pre>

<p>I learned a bit about *args, and this is what I ended up with after some help from programmers much smarter than me. </p>

<pre><code>def prime_form (*pitches, tones_in_octave = 12):
    tones_in_octave=int(tones_in_octave)
    spitches = list(set(sorted([pitch %tones_in_octave for pitch in list(pitches)])))
    print(spitches)
</code></pre>

<p>Paralleling the last program, this does what I need it to do so far up to the part where I start defining âintervalsâ, but I donât know how to go about doing so. I guess I could write a lot of if statements, but theoretically if I wanted to make it functional for <code>tones_in_octave = 12</code>, then I would have to write a lot of <code>if</code> and <code>elif</code> statements, and even then if I wanted to go past that (there is even an established system of music which utilize <code>43</code> tones in an octave, though that specific system wouldn't benefit from this function), I would have to write a bunch of them manually, and even then my function would stop working at the point I decide to stop.</p>

<p>In this case, what I would want to write out literally in the code would be </p>

<pre><code>sintervals = sorted([(spitches[1] - spitches[0]) %tones_in_octave, (spitches[2] - spitches[1]) %tones_in_octave, â¦, (spitches[n-1] - spitches[n-2]) %tones_in_octave, (spitches[0] - spitches[-1]) %tones_in_octave])
</code></pre>

<p>Where n is the number of items in the list <code>spitches</code> (which is different from the items in *pitches, since the way <code>spitches</code> is defined removes redundant values)</p>

<p>Question 1. How do I define a variable as this list in python?</p>

<p>After that, adding intervals like this yields prime form</p>

<pre><code>prime_from = [0, sintervals[0], sintervals[0] + sintervals[1], sintervals[0] + sintervals[1] + sintervals [2], ..., sintervals[0] + sintervals[1] + ... + sintervals[n-2]]
</code></pre>

<p>Where n is the number of items in <code>sintervals</code> (and also the number of items in this list)</p>

<p>Question 2. How do I add numbers like this depending on how many items are in my list from Question 1?</p>

<p>Edit: </p>

<p>Here is an explanation of what is ultimately trying to be accomplished, sorry if it isn't the clearest (it might even be flat out wrong aahahaha lets hope not).</p>

<p>---BACKGROUND: Pitch and Octaves---</p>

<p>In the most popularly used system of music, specific frequencies of air vibrations are called a "pitches"; frequency of the pitch is calculated by</p>

<p>(reference)*2^(distance from reference in pitches / pitches in an octave)</p>

<p>An "octave" is a (2^x):1 frequency relationship where x is an integer and x = the "amount of octaves"; this relationship is important, because us humans perceive frequencies of air vibrations related by octaves/this ratio to be more or less the same. The frequency most commonly used for the reference pitch in this system of music is "A 440" meaning "A4" is the frequency 440Hz. The 4 in "A4" is a register number for which "octave register" the note is in. The octave registers are divided up on the pitch C, so A4 is the A "above" or "with a higher frequency than" C4 (which has a frequency of (440)^-9/12 = ~261.6Hz) Ex. A0 = 27.5Hz, A1 = 55Hz, A2 = 110Hz, etc. (You can tell that the alphabetical notation system we still use was conceived before the measurement of the frequency of air vibrations)</p>

<p>---Background: Music Theory---</p>

<p>In Music Theory, Set Theory is one of the well established tools used to approach Music Theory. Musical Set Theory abstractifies pitch as integers. It also usually disregards octave registers, treating A4 completely equal to A2, A3, A6 etc. In the aforementioned most popularly used system of music, there are 12 tones in an octave, so the way to reference pitches in Set Theory changes from (C, C#, D, D#, E, F, F#, G, G#, A, A#, B) to (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) respectively; to make sure that everyone is on the same page, there is a name for when octave registers are treated as irrelevant information for a pitch called "pitch class". With pitch classes, all math is done in mod 12, like a clock face, since there are 12 tones in an octave.</p>

<p>Also in Set Theory, there is a useful way to list a set of pitch classes ("pitch class set") called "prime form". Prime forms, also referred to as set classes are regarded as the most concise and abstract way to represent pitch class sets.</p>

<p>---What I'm Trying to Accomplish---</p>

<p>I want to write code that eats pitch class sets and spits out set classes/prime form. As a note, prime form must begin on 0, if it meets the other requirements (leftmost-compact considering the inversion of the set) and does not begin on 0, then will be transposed to start on 0 Ex. [1,2,4] is a leftmost-compact arrangement considering its inversion [1,3,4], but does not start on zero, so the set is transposed by (-1) to (0 1 3) which is its prime from. A human being trying to figure out prime form usually takes a few steps to arrive at the answer:</p>

<ol>
<li><p>Remove redundant pitches classes - if you get pitches like (1, 13, 0, 2, 0), remove 13 because it is redundant with 1 (13%12 = 1) and remove the second 0.</p></li>
<li><p>Arrange the pitch classes within a single octave span - (not necessarily octave register; octave register is understood to be always based on the pitch C, and octave span refers to a span of any two notes with a 2:1 frequency relationship, not just two Cs an octave apart.). As an example, we'd arrange (10, 9, 0, 11) as (0, 9, 10, 11) (starting on zero/within an octave register) or [9,10,11,0] (Normal form/leftmost-compact arrangement) or a few other ways that probably aren't as useful.</p></li>
<li><p>Find intervals - The interval in this case is the absolute value of the difference of adjacent pitch classes in a one octave: 9-10 or 10-9 = 1, 10-11 = 1, 0-11 = 1 (0 needs to be momentarily thought of as 12; this is a case where the numbers span across the loop point for the "clock face" of mod 12 and screw up the math), and 0-9 (0 is good as 0 here since it doesn't cross the loop point; if 0 is thought of as 12, you get the wrong interval) = 9. At this point, the difference of the first and last interval, in this case 9, is also considered in case there is a set like [3,4,7,9,0] or [1,2,4,5,7,8,10,11] where there is a tie between intervals. So you can't ignore the last interval.</p></li>
<li><p>Relist the intervals according to inversions and leftmost-compactness - This is why we found the intervals; the intervals abstractify the actual pitch so we don't have to transpose it to 0 (as the requirement of prime form is that the list starts on 0), and so we can list our intervals in the leftmost-compact fashion between the "normal" and "inverted" list of intervals (clockwise and counter-clockwise on a clockface) to calculate prime form. The way that a human would do this is to start at a point in the list of intervals and re-list it going left or right from that point, keeping the intervals in the same order as the pitches they correspond to and looping when necessary.</p>

<ol start="5">
<li>Choose the right interval list and calculate prime form -
(0,9,10,11)'s interval list is (9,1,1,1), what we do here is choose the leftmost compact version, which ignores the 9, since it is the least compact, and then use the intervals to build the prime form which is (0 1 2 3)</li>
</ol></li>
</ol>

<p>for (9,11,1,2,4,6,8), the interval list is (2,2,1,2,2,2,1). the most left compact is (1, 2, 2, 1, 2, 2, 2), so prime form is (0 1 3 5 6 8 10).</p>

<p>However, there is some disagreement on this final step, the disagreement is between the Rahn and Forte Algorithms. This is because the criteria I layed out results in two answers in five specific cases, because in those cases the question "what is leftmost-compact?" requires more definition. Honestly I have no clue if changing the tones_in_octave to something other than 12 will some how change these exceptions to the criteria I've presented out or not. I also don't know how to explain the differences between the two algorithms in terms of intervals, because the algorithms are defined based on certain pitch's intervals from 0 that cause disagreement between what is leftmost-compact, not the actual order of intervals. I guess I should work on that if I want to finish this program.</p>

<p>Python seems to be good at following these steps from what I have been shown by Stack Overflow and other sources (except maybe the interval list sorting), it's just a matter of figuring out how to generalize it enough so that the function works for a potentially infinite amount of arguments. Thanks to Moses Koledoye doing most of the heavy lifting by generalizing the function to work with *args, there seems to be only one problem that hasn't been solved, which is sorting the list of intervals in the fashion shown above in step 4. (the rest of the steps work pretty well; Koledoye's version of step 3 gave the wrong intervals, but applying mod 12 to the answer he came up with sometimes fixes that for cases where step 4 happens to work out correctly (AND SOME TIMES SCREWS IT UP).</p>

<p>Here is the code with a flawed step 4, print messages to notify what just got defined, and an extra step at the end that SOMETIMES fixes cases where step 3 doesn't work correctly due to, I presume, math across the "loop point"/"clockface", and other times messes it up when it was correct with Koledoye's code.</p>

<pre><code>def prime_form (*pitches, tones_in_octave = 12):
    tones_in_octave=int(tones_in_octave)
    spitches = list(set(sorted([pitch %tones_in_octave for pitch in list(pitches)])))
    print('{}\nthis is the sorted list of pitches \n'.format(spitches))

    lth = len(spitches)
    print('{}\nthis is the length of spitches \n'.format(lth))

    intervals = [(spitches[0 if (i+1) &gt;= lth else (i+1)]-x) % tones_in_octave for i, x in enumerate(spitches)]    
    print('{}\nthis is the interval list \n'.format(intervals))

    sintervals = sorted(intervals)
    print('{}\nthis is the sorted interval list \n'.format(sintervals))

    p_form = [sum(sintervals[:i]) for i in range(len(intervals))]
    print('{}\nthis may be the prime form, but maybe not \n'.format(p_form))

    true_p_form = list({i % tones_in_octave for i in p_form})
    print('({})\nthis is the prime form! (apparently it might not be)'.format(' '.join(map(str, true_p_form))
</code></pre>

<p>and here are some examples to try</p>

<pre><code>&gt;&gt;&gt; prime_form(9, 3, 0)
(0 3 6)
this is the prime form!

&gt;&gt;&gt; prime_form(1, 11, 9, 4, 2, 6, 8)
(0 1 3 5 6 8 10)
this is the prime form!

&gt;&gt;&gt; prime_form(10, 9, 0, 11)
(0 1 2 3)
this is the prime form!
</code></pre>

<p>And here is a calculator that already does most of this and more (except changing the number of tones in the octave)
<a href="http://composertools.com/Tools/PCSets/setfinder.html" rel="nofollow">http://composertools.com/Tools/PCSets/setfinder.html</a></p>

<p>It even has an explanation on the difference between the Rahn and Forte algorithms.</p>

<p>The following pretty much does what you want. </p>

<ul>
<li><p>The tricky part is the computation of the intervals which was done
using <a href="https://docs.python.org/2/library/functions.html#enumerate" rel="nofollow"><code>enumerate</code></a> to subtract the current item from the item at the next index, and subtracting the last item from the first.</p></li>
<li><p>The cumulatives are taken by <em>summing</em> the slices of the computed <code>sintervals</code>. The stop index of each slice is increased by 1 than that of the previous:</p></li>
<li><p>The last part is the formatting part which uses <code>.join</code> to <em>join</em> the list items, which are then formatted.</p></li>
</ul>

<hr>

<pre><code>def prime_form(*pitches, tones_in_octave=12):
    # pitches  = set(pitches)
    spitches = sorted([p % tones_in_octave for p in pitches])
    lth = len(spitches)

    # Question 1
    intervals = [(spitches[0 if (i+1) &gt;= lth else (i+1)]-x) % tones_in_octave for i, x in enumerate(spitches)]    
    sintervals = sorted(intervals) 

    # Question 2
    p_form = [sum(sintervals[:i]) for i in range(len(intervals))]

    print('({})\nthis is the prime form!'.format(' '.join(map(str, p_form))))
</code></pre>

<hr>

<p><strong>Tests</strong>:</p>

<pre><code>&gt;&gt;&gt; prime_form(9, 1, 5)
(0 4 8)
this is the prime form!

&gt;&gt;&gt; prime_form(11, 1, 0)
(0 1 2)
this is the prime form!

&gt;&gt;&gt; prime_form(1, 3, 4)
(0 1 3)
this is the prime form!
</code></pre>

python list python-3.x music args