Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative implementations of a twelve tone matrix and possible design benefits #33

Open
jgarte opened this issue Apr 23, 2023 · 2 comments

Comments

@jgarte
Copy link
Contributor

jgarte commented Apr 23, 2023

Hi,

What do you think if we were to re-implement a twelve tone matrix without needing to use numpy.zeros?

For example we could generate the 12X12 matrix like this:

>>> from pprint import PrettyPrinter
>>> matrix = [[0] * 12] * 12
>>> pp = PrettyPrinter(indent=4)
>>> pp.pprint(matrix)

   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

We can then proceed to implement the compose function in terms of mutating the above matrix list variable to produce a matrix with the canonical row forms: P, R, I, and RI.

One possible algorithm:

We can loosely implement the steps as described in this instructable:

https://www.instructables.com/Create-a-Twelve-Tone-melody-with-a-Twelve-Tone-Mat/

  1. Compute the interval adjacencies of the initial row and store that in a variable.
  2. Compute the inversion of the initial row using step 1 and store that in a variable.
  3. Use the List[int] variables created in steps 1 and 2 to mutate/compute the rest of the 12 X 12 List[List[int]].

Another alternative could be to outsource the matrix generation logic to the music21 library:

https://web.mit.edu/music21/doc/moduleReference/moduleSerial.html?highlight=row#music21.serial.ToneRow.row

Using music21 would be an implementation detail of twelve-tone.

The cool thing that might arise from using music21 is that we could piggyback on its features to add/invent CLI flags for twelve-tone such as --historical that let's the user ask for a historical tone row, which is kind of cute:

> bergLyric = serial.getHistoricalRowByName('BergLyricSuite')
> bergLyric.pitchClasses()
[5, 4, 0, 9, 7, 2, 8, 1, 3, 6, 10, 11]

twelve-tone using music21's getHistoricalRowByName method

$ twelve-tone --historical

F E C A G D G♯ C♯ D♯ F♯ A♯ B

or with --verbose

$ twelve-tone --historical --verbose

🚀 The tone row from Berg's Lyric Suite!
F E C A G D G♯ C♯ D♯ F♯ A♯ B
@jgarte jgarte changed the title Implementing a twelve tone matrix not in terms of a numpy array Alternative implementations of a twelve tone matrix and possible benefits Apr 23, 2023
@jgarte
Copy link
Contributor Author

jgarte commented Apr 25, 2023

A third implementation is to use the abjad library to render the twelve-tone row.

I think this is our best option to easily support features I have mentioned here and in other issues #31 #29 #30 #32 .

Using abjad will make it very easy to generate a twelve-tone row:

>>> import abjad

>>> numbers = [1, 11, 9, 3, 6, 7, 5, 4, 10, 2, 8, 0]
>>> row = abjad.TwelveToneRow(numbers)
>>> row.as_midi(row, "row.midi")

>>> print(row)
PC<1, 11, 9, 3, 6, 7, 5, 4, 10, 2, 8, 0>

>>> # row is an object with methods
>>> row.
row.count(               row.index(               row.items                row.retrograde(          row.to_pitches(          row.voice_vertically(    
row.from_selection(      row.invert(              row.multiply(            row.rotate(              row.transpose(           
row.has_duplicates(      row.item_class           row.permute(             row.to_pitch_classes(    row.voice_horizontally(

>>> row.to_pitch_classes()
TwelveToneRow([1, 11, 9, 3, 6, 7, 5, 4, 10, 2, 8, 0])

>>> abjad.persist.as_midi(row, "row.midi")
('row.midi', 0.007839679718017578, 9.847418308258057, True)

>>> abjad.persist.as_png(row, "row.png")
(('row.png',), 0.008437156677246094, 2.8052899837493896, True)

>>> abjad.persist.as_ly(row, "row.ly")
('row.ly', 0.008110284805297852)

abjad uses lilypond to produce the midi file. We would be able to drop numpy and miditime as dependencies of python-twelve-tone if we use abjad.

abjad is also smaller as a library than numpy but we'll be getting a lot more use out of it than using numpy and as shown in these examples..

Outputs from REPL session above

row.ly

%! abjad.LilyPondFile._get_format_pieces()
\version "2.24.1"
%! abjad.LilyPondFile._get_format_pieces()
\language "english"

\layout {
    \accidentalStyle forget
    indent = 0
    \context {
        \Score
        \override BarLine.transparent = ##t
        \override BarNumber.stencil = ##f
        \override Beam.stencil = ##f
        \override Flag.stencil = ##f
        \override Stem.stencil = ##f
        \override TimeSignature.stencil = ##f
        proportionalNotationDuration = #(ly:make-moment 1 12)
    }
}

\paper {
    markup-system-spacing.padding = 8
    system-system-spacing.padding = 10
    top-markup-spacing.padding = 4
}
\new Score
<<
    \new Staff
    {
        \new Voice
        {
            cs'8
            b'8
            a'8
            ef'8
            fs'8
            g'8
            f'8
            e'8
            bf'8
            d'8
            af'8
            c'8
            %! SCORE_1
            \bar "|."
            \override Score.BarLine.transparent = ##f
        }
    }
>>

With the below png output we could add a feature to render the musical score fragment of the twelve-tone row in the terminal with terminal-img, for example.

from image import DrawImage

# feeding it the png output from abjad
image = DrawImage("row.png")

row.png

row

The score fragment output can be easily styled to not produce the footer.

@jgarte
Copy link
Contributor Author

jgarte commented Apr 25, 2023

@accraze Would you like me to draft a PR using abjad/lilypond to update the MIDI functionality mentioned in #31?

I can close #29 and #32 as well in this PR.

I would not be implementing the row score image terminal rendering mentioned above in this PR but I would be happy to do that in a near future PR.

@jgarte jgarte mentioned this issue Apr 25, 2023
@jgarte jgarte changed the title Alternative implementations of a twelve tone matrix and possible benefits Alternative implementations of a twelve tone matrix and possible design benefits Apr 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant