abcsound: an abc Front End for CSound |
|
|
abcsound Technical OverviewPyDoc for abcsound.py is here.Architectureabcsound.py parses an abc score into a list of "elements". Each element represents an "atomic" part of the score -- a measure division, repeat mark, key signature, time signature, note, rest, line-break, etc. Elements are also used to aggregate musical elements into larger entities such as "parts" (all the notes rendered by a particular voice). Finally, Elements are used to represent meta-data about the score. Each kind of element is represented by a class derived from Element. Processing of the score takes place in several passes. The first pass does an initial parse to extract all the atomic elements from the score. Subsequent passes compute note durations; compute relations between notes (such as slurs and ties); and partition parallel lines of abc notation into parts as directed by the controlling "voices" instructions.Each Element instance is responsible for computing Csound score-related information about itself, in its analyze() method. There are two particularly important subclasses of Element:
The high-level driver code contains some global functions that do very early processing. The CsoundScoreAnalyzer class performs most of the score analysis and emits the Csound score.
Pass 0: preprocessingThe input to the parser is a list of raw text lines supplied by xreadlines(). The preprocessLines() function looks at each line and does some preliminary massaging to get the abc notation in a normalized form. Mainly this means making sure repeat marks are always in the format |[n rather than just |n , which is allowed by the abc spec.
Pass 1: initial parseEach Element class has a static read() method, which looks at the text at the current position in the score and tries to read an instance of itself. The parser repeatedly invokes each Element class's read() method until one succeeds. Such a successful parse of an Element increments the score's read position to the next character after the element's text, and the parser tries to parse a new Element at the new position. The order in which Element class' read() methods are called is the primary way of handling ambiguity in the abc grammar. The global list allElementClasses[] determines the order in which read() calls occur. The core parser function is getElementsInString().When pass 1 is complete, we have a list of all Elements in the score, in textual order. (Actual we have a list of lists, each sublist corresponding to a line of input, and containing the Elements found on that line.) The textual order does not necessarily correspond to the temporal order, since abcsound.py allows parallel staves corresponding to multiple voices. If a flute voice and an oboe voice are both active at a given point in the score, for example, then each pair of score lines represents the same time period, each line corresponding to one of the voices.
Pass 2: building the timelineWhen all the score's Elements are available, the CsoundScoreAnalyzer.buildTimeline() function computes the note durations, start times, and voicings. The algorithm is basically this:
Pass 3: building the Csound scoreOnce the timeline is built and note values computed, generating the Csound score is straightforward. The CsoundScoreAnalyzer.writeCsdScore() reads the input CSD template file, copies all contents to standard output until the <CsScore> section is seen, emits the score information, and then emits the rest of the CSD template file.For each VoiceData element, the contents are traversed in order. Each note element is emitted as an "i" statement, taking its pfield values from the note element or the surrounding VoiceData element, as appropriate. Other elements, such as decorations, change the values of the pfields in either the VoiceElement or a range of notes. Such changes take effect immediately, and are reflected in the emitted score at the appropriate times. |
Last changed: 09-07-09 01:21:46 |
|
This page was rendered by LittleSite. LittleSite is Copyright (c) 2005 by J.Knapka. Questions and comments to JK |