In :%load_ext abjadext.ipython import abjad
Abjad extends the Python programming language with an object-oriented model of common practice music notation. To work with this model, we'll need to understand two key concepts: 1) object orientation and 2) the leaf, container, spanner, indicator (LCSI) model of a score.
What does it mean that we have an object model of music notation? To answer this question, we'll first make a single note by calling the Note class's initializer method.
In :grape = abjad.Note("d''2.") abjad.show(grape)
We now have a new note called
grape. If we forget what we've made because of our whimsical name, we can type the name of our note into the interpreter to see what it is.
Sure enough, it's a note, with a LilyPond string of D5 and a duration of a dotted half note. (If we hadn't provided a LilyPond string, we'd have gotten a middle C quarter note.)
So what happened when we made our note? In our object model, we have a class called
Note that models a musical note. A class is a template for a certain kind of thing. The
Note class models the characteristics of a note (attributes). To make a new note (a new instance of the
Note class), we called our class's initializer method,
Note(), and assigned the returned instance to a variable, named whatever we like (on the left side of the equals sign). You will see this pattern of instantiating objects through right-to-left assignment over and over, throughout the system.
Once we have our note instance, we can access characteristics about our note that we'd expect it to have using dot chaining syntax, where we start with our variable name and continue, after a dot, with the attribute we'd like to get:
In addition to getting these attributes, we can also write them using the same syntax -- here we change the pitch of our note to be inaudibly high:
In :grape.written_pitch = "fs'''''''''''''''"
And now, when we ask the interpreter what grape is, its written pitch has been changed.
We can do the same with our note's duration, and see the change in the note's LilyPond string.
In :grape.written_duration = (1,2)
For example, to find the
Note class, we look in the scoretools package in the API reference.
scoretools contains the most commonly used score elements. Under "leaves" we find the Note class. When we click
Note, we're taken to the reference page for
Note. The attributes summary shows us which characteristics of a note have been modelled. The read/write properties portion, often with examples, shows us which attributes we can read/write.
We notice in the API reference that there are other classes listed under scoretools-Leaves. We can create Rests, Chords, Skips in the same way we made our note.
In :rest = abjad.Rest() rest
We get a default value of a quarter-note, but we can also pass in an argument -- either a duration or a LilyPond string -- to choose something other than the default.
In :rest = abjad.Rest("r8..") rest
In :rest = abjad.Rest((7,32)) rest
Likewise, we can make notes other than a middle C quarter note by passing in arguments. We can make a new note using a LilyPond string,
In :note = abjad.Note("ds'32") note
Or by giving two comma-separated pitch and duration arguments:
In :note = abjad.Note(3, (1,32))
Note that Abjad represents pitch numerically by equating 0 to middle C. A pitch of 3 corresponds to three half-steps above middle C.
Hm - we got a flat, but we wanted a sharp. Good thing we can change Abjad's default accidental spellings inside a container:
In :container = abjad.Container([note]) abjad.Accidental.respell_with_sharps(container) note = abjad.Note(3, (1,32)) container
Chords work similarly:
In :chord = abjad.Chord("<c' e' g'>8.") chord
Out:Chord("<c' e' g'>8.")
In :chord = abjad.Chord([0,4,7], (3,16)) chord abjad.show(chord)
As do skips (blank spaces that occupy a specified duration -- like rests without the drawn symbol.)
In :skip = abjad.Skip("s8.") skip
In :skip = abjad.Skip((3,16)) skip
And remember, we can get back to the attributes of our leaves using dot chaining syntax.
You can also instantiate a new leaf instance from an existing leaf:
In :rest = abjad.Rest(note) rest
Be sure you understand the explanation of Abjad's score tree model, as illustated here: http://abjad.mbrsi.org/core_concepts/lcsi.html
In summary --
Leaves: instances of
Skip, as above. These can be arranged together sequentially or simultaneously in
Score. Containers can contain leaves directly (a staff containing notes) or can contain other containers hierarchically (a
Score containing a
StaffGroup containing two
Staffs which both contain leaves):
In :staff1 = abjad.Staff("c' d' e' f'") staff2 = abjad.Staff("f' e' d' c'") group = abjad.StaffGroup([staff1, staff2]) score = abjad.Score([group]) abjad.show(score)
Spanners: anything that spans from one component to another, i.e. a phrasing slur that starts at one note and ends at another note, spanning everything in between. Here, we slur all the notes in our staff1 container by attaching an instance of the
PhrasingSlur class to all the notes contained in staff1:
In :start_slur = abjad.StartPhrasingSlur() stop_slur = abjad.StopPhrasingSlur() abjad.attach(start_slur, staff1) abjad.attach(stop_slur, staff1) abjad.show(score)
Indicators: anything that attaches to a single component. Some indicators become effective at that point and remain so until a change (dynamic markings, time signatures, tempo markings) and some impact only the note to which they attach (articulations). Here we use indexing to attach an articulation to the second component in our staff2 container (remember that indexes count from 0, so index 1 is the second component in the container).
In :staccato = abjad.Articulation('staccato') abjad.attach(staccato, staff2) abjad.show(score)
It might be the case that we want to apply the same indicator to a consecutive series of leaves. Note that we can use iteration to do the same thing to multiple components sequentially -- here we use slice notation to apply a staccato marking to every leaf in staff1 after the first note:
In :for leaf in staff1 [1:]: staccato = abjad.Articulation('staccato') abjad.attach(staccato, leaf) abjad.show(score)
We can use anything in Python -- from built-in libraries to any of its thousands of external libraries -- to create leaves. Python's list comprehension syntax allows us to describe lists more easily:
In :notes = [abjad.Note(x,(1,8)) for x in range(24+1)]
The above list comprehension means, "a list of eighth notes with pitch values from 0 through 24."
In :staff = abjad.Staff(notes) abjad.show(staff)
We can use external libraries, too -- here we generate a hundred random numbers and use them as pitch values:
In :import random numbers = [random.randrange(0,25) for x in range(100)] numbers
Out:[23, 10, 20, 3, 23, 14, 1, 1, 21, 20, 24, 22, 14, 14, 4, 20, 21, 24, 7, 17, 5, 13, 18, 21, 17, 15, 3, 0, 0, 16, 20, 3, 18, 1, 1, 12, 2, 13, 11, 24, 9, 14, 14, 22, 11, 6, 3, 6, 1, 4, 23, 10, 0, 6, 24, 13, 20, 20, 9, 24, 17, 22, 18, 14, 19, 9, 20, 19, 12, 13, 21, 21, 18, 1, 18, 9, 5, 14, 8, 23, 18, 7, 9, 12, 4, 22, 16, 9, 19, 11, 10, 22, 22, 16, 11, 7, 1, 22, 23, 8]
Whoa - that's a lot of numbers. Let's just use a few of them - we can use list slicing syntax to take the portion of our list from the beginning through the tenth element:
In :numbers = numbers[:10] numbers
Out:[23, 10, 20, 3, 23, 14, 1, 1, 21, 20]
And now we can turn them into notes with a list comprehension:
In :notes = [abjad.Note(x,(1,8)) for x in numbers] staff = abjad.Staff(notes) abjad.show(staff)
N.B. we've just been using integers as chromatic pitch numbers, but we could use them as anything else we like (rhythmic durations, for example). Quarter-tone accidentals are also possible, using .5 resolution:
In :halfNumbers = [x / 2.0 for x in numbers] halfNumbers
Out:[11.5, 5.0, 10.0, 1.5, 11.5, 7.0, 0.5, 0.5, 10.5, 10.0]
And now we can use these numbers as pitch numbers to create notes.
In :quarterToneNotes = [abjad.Note(x,(1,8)) for x in halfNumbers] staff = abjad.Staff(quarterToneNotes) abjad.show(staff)
This tutorial outlines the basics of bottom-up work with Abjad. First, you create leaves by some mechanism, and then you put these leaves in containers, add spanners and indicators to them, etc., rather manually.