I was rereading Lydia Goehr's The Imaginary Museum of Musical Works the other evening after a long day spent translating several of music21's score-representation code from Python to JavaScript (for music21j). What struck me when I was reading the introduction, which lays out several pre-existing theories about the work-concept, and the relationship(s) among the musical idea, the building blocks of scores (pitches, etc.), the score-copy, and performances, was my own need to take a stand on the proper relationships of such conceptions when choosing a computational language in which to express musical languages.
Those who haven't programmed may not know that no modern computer program (or very very few) is built from a single code file, or flowchart leading from input to output. Instead each program is built from components (a file browser, a set of functions for manipulating canvases for drawing, a module for representing tempo) that can be called upon by other components in a systematized but reusable and testable manner. These are get bundled or packed or linked together to make a complete or extensible application or library. Different philosophies exist about which structures (or ontologies, to use a word with related but quite different meanings between the humanities and computer science) can be well-formed or desirable.
These philosophies about file linking--importing and exporting--lie close to the marrow of the designs of various computer languages and in many cases evolved in response to the environments within which the languages were originally created. Python, a language run on individual computers that came of age in the era of fast hard drives and, from the user's perspective, near instantaneous loading of small files, aims to put as few limitations on the possible relationships between modules as possible. JavaScript, on the other hand, which appeared first on the web in the time of dialup internet and unreliable connections, has, even in its most recent incarnations, placed sharper restrictions on connecting resources in the name of efficiency.
Translating music analysis software from the first language to the other has raised complex problems for the representation of music in code. Python allowed me to interweave different levels of musical thought, such that notes could will into existence a measure (say by asking for the creation of an object to encompass them) while a measure could in another context give birth to notes (for instance by asking for a suitable number to fill it, given some metrical, harmonic, and accentual constraints). A score could of course be a container to many measures, but a measure could also be linked or contain many scores (for instance as a key or heading to a catalogue of quotations or standard topoi). As I created the original music21 in Python, I reveled in the multiplicity of possible relationships, in the way some musical philosophers might argue that a score gives rise to a performance which, if transcribed or imagined, gives rise to a new score, which gives rise to a new performance, and so on to infinity.
Rewriting the "same code" posed, and continues to pose, a challenge to my ecumenical notion of musical relationships. (With "same code" in quotation marks since the work-concept-concept for computer works has not been the subject of nearly so much rumination.) In JavaScript, in order to make sure that everything has been loaded before the user closes her browser in frustration, in general if one module (A) uses another module (B) in its code, then the second module (B) cannot use, or import, the first (A) into its code. What some, perhaps those trained as humanists, might exult as a beautiful web of inter-compu-textuality, is called a cyclic or circular dependency and it is easy to find categorial pronouncements that such things are bad or the result of lazy or sloppy thinking. They resist creating a hierarchy of elements, and prevent creating beautiful tree structures that are, or at least were during the time when computers were problem-solving devices and not enablers of exploration, the key to moving in an efficient manner for point A to point Z without getting into an endless loop somewhere around J to M. (A programmer--who had apparently gotten too deep into the trenches of coding to remember that the terms which undergird so many computational structures are metaphors--once criticized a part of my code that had many pointers running up and down a hierarchy by saying, "This is absurd! A child cannot have more than one parent.")
In Python, I could say that a Note in the presence of another Note created an Interval. (Like in German, in most computer languages, nouns, or Objects, are capitalized.) And, I could simultaneously say that an Interval, given a starting Note for reference, could define a second Note that fulfilled it. Both of these generating relationships seemed not just plausible, but natural and essential to a full representation of the complexity of music. The ambiguity of which came first, the interval or the note can never be resolved. In JavaScript, however, the programming musicologist is left with a decision to be made: either Notes can create Intervals or Intervals can create Notes, but not both. The work creates the score (or performance), or the performance or the score creates the work, but not both. The one who is able to create both Notes and Intervals is an entity that stands outside the system--the calling program--which is perhaps better named "the observer" in the best literary criticism traditions, since the network of Notes and Intervals cannot operate with knowledge that it exists.
(To be fair, there are some complex and fragile ways to work with circular dependencies in JavaScript, and in Python, true circular dependencies are also impossible: either the Note can only become aware of its ability to create Intervals at the moment of action [an import nested in a method] or vice-versa.)
I have found that programming musical logic has sharpened my awareness of the ambiguities, hierarchies, and underdefined elements of music. By underdefined elements, I suggest: is the interval from E# to Fb an ascending doubly-diminished second or a descending doubly-diminished second? If spelling matters more than sound, such that C-G is consonant but Dbb-G is dissonant, is the bass of a chord beginning on E##-Fbb-Bb the E## or the Fbb? (If it's the Fbb, then is a B###-Dbbb-F# chord in root position or first inversion? If the E##, does that mean that we cannot determine the bass of a chord by ear?) These may be absurdities to practicing musicians but deciding a "right answer" to them makes all the difference in how standard musical relationships should be represented and encoded.
It is extremely difficult to tell a computer to hold off on making a decision or to leave a paradox in place to solve later. The human ability (flaw?) in being able to reason around ambiguity, or to hold conflicting ideas without breaking down, is a capacity that those who design practical computing systems have either not been able to replicate or have deliberately chosen not to. Within the limited choices, I have generally been drawn to computing frameworks that let me come as close as possible to representing multiple perspectives. (Ironically, I've found the closest match so far in Python, despite its community adopting a motto that says there should be only one way to do it.) There is a danger that when good but still inadequate tools are used to model human behavior and creativity, eventually human behavior will bend to suit the tools, rather than the other way around. It is a force that those who design and use these tools must be aware of and continually fight against.
(updated 2022.02.03 -- corrected "revealed" to "reveled")
No comments:
Post a Comment