OM Score Transformer — User Guide
Native-Praat symbolic score transformation: read MusicXML, apply a fixed chain of pitch/chord/order/time operations, then render the transformed notes with additive synthesis.
What this does
OM Score Transformer works on symbolic notes rather than on an existing audio waveform. It parses an uncompressed MusicXML score into note records containing onset, end time, MIDI pitch and amplitude; applies a fixed series of transformations; and synthesizes the result directly in Praat with a harmonic additive bank.
The order is fixed. Earlier stages change the material seen by later stages: for example, the chord stage operates on pitches after transposition and inversion.
Score input & MusicXML
Two score sources
| Source | Behavior |
|---|---|
| File on disk | Reads an uncompressed .musicxml or .xml file. If the field is blank, the script opens a file chooser. Leading/trailing whitespace and surrounding double quotes are removed from a typed path. |
| Selected Strings object | Uses exactly one Praat Strings object selected before the script starts. The object is written to a temporary MusicXML file and sent through the same parser as the file-input path. This supports direct handoff from a Strings-based transcription workflow. |
.mxl is not supported. An .mxl file is a ZIP archive; this script does not unzip it. Export uncompressed MusicXML instead.Praat 7.0 and later may request permission to write temporary files. Temporary parser files are removed by the script when processing completes normally.
Parser behavior
The parser handles score parts, divisions, chords, rests, grace-note omission, voices using backup/forward, pitch alteration, and ties. Tied note segments with matching part, voice and MIDI pitch are joined into a longer note. Grace notes are ignored.
When a dynamics attribute is present on a note tag, its value is divided by 100 and limited to a maximum of 1.0. Otherwise the note amplitude defaults to 0.7. These amplitudes are retained through the symbolic transformations and drive the additive render.
Tempo
Tempo_bpm = 0 means “read tempo from the score.” Version 0.4 resolves a single global tempo in this priority order:
Metronome values respect beat-unit and any beat-unit-dot elements; for example, an eighth-note or dotted-quarter metronome mark is converted to quarter-note BPM before note times are converted to seconds.
Fixed transformation chain
The transformations are not independent plug-ins: they run in the following exact sequence.
| Stage | Operation | Important behavior |
|---|---|---|
| 1 | Filter | Rejects notes shorter than Min_note_duration_s or outside the inclusive MIDI range Lowest_midi … Highest_midi. |
| 2 | Pitch | Applies transposition first, then optional inversion. Out-of-range results are octave-folded back into MIDI 0–127. |
| 3 | Chord | Builds simultaneity groups using a 12 ms onset tolerance, then optionally arpeggiates, thins or re-octaves chord members. |
| 4 | Order | Optionally performs a time-domain retrograde or rotates onset groups with their inter-onset intervals. |
| 5 | Time | Scales all onsets and durations, then separately scales note lengths while keeping transformed onsets fixed. |
| 6 | Synthesis | Renders the final note table into a mono Sound using a harmonic bank and an amplitude envelope. |
Parameters
| Parameter | Default | Meaning |
|---|---|---|
| Score source | File on disk | Choose a disk file or the Strings object selected before running. |
| Score file | blank | Path to uncompressed MusicXML/XML. Blank opens a chooser in interactive use. |
| Tempo bpm | 0 | 0 = resolve tempo from MusicXML; positive value overrides score tempo globally. |
| Min note duration s | 0 | Remove notes whose parsed duration is shorter than this value. |
| Lowest MIDI | 0 | Lowest accepted source pitch in the filter stage. |
| Highest MIDI | 127 | Highest accepted source pitch in the filter stage. Lowest must not exceed Highest. |
| Transpose semitones | 0 | Added to every surviving MIDI pitch before inversion. |
| Invert mode | none | None, inversion about a fixed MIDI axis, or inversion about the mean pitch after transposition. |
| Invert axis MIDI | 60 | Axis for fixed-axis inversion. Ignored by mean-pitch inversion. |
| Chord mode | none | None, three arpeggiation orders, three thinning modes, or voice-leading. |
| Arpeggio stride ms | 70 | Time offset between successive ranks in an arpeggiated simultaneity group. |
| Keep per chord | 3 | Maximum number retained by the three thinning modes. |
| Order mode | none | None, retrograde, or rotate onset groups. |
| Rotate steps | 1 | Number of group positions used by rotation. Negative values wrap; multiples of the group count are identity. |
| Time scale | 1.0 | Multiplies transformed note onsets and ends together. |
| Note length scale | 1.0 | Multiplies durations only, leaving onsets fixed; resulting duration is never shorter than 10 ms. |
| Edit synthesis settings | no | Opens the secondary synthesis dialog. |
| Draw visualization | yes | Draws score, audio and summary panels in the Picture window. |
| Play result | yes | Plays the rendered Sound after completion. |
Pitch transformation
Transposition occurs before inversion.
After the complete pitch operation, values below 0 or above 127 are moved by whole octaves until they lie in the legal MIDI range. This preserves pitch class but changes octave. The report states how many notes required this octave folding.
Chord operations
Chord operations first sort notes by onset and descending pitch. Notes whose onsets fall within 12 ms of the first onset of a group are treated as one simultaneity group.
Arpeggiate up / down / up-down
Each chord member receives a multiple of Arpeggio_stride_ms. Because groups are internally sorted high-to-low, the rank is reversed for “up” so lower pitches enter first. “Down” uses the sorted order directly. “Up-down” alternates from the low and high ends.
An arpeggiated onset is limited to at most 20 ms before the chord's original latest end. If necessary, note duration is adjusted to maintain at least 20 ms, but the operation does not push a note beyond that group end. Thus arpeggiation does not lengthen the score merely by spreading a chord.
Thin
- keep highest: retain the highest
Keep_per_chordpitches; - keep lowest: retain the lowest
Keep_per_chordpitches; - keep outer: divide the retained count between the top and bottom of the chord. For an odd count, the lower side receives the extra member.
Groups already at or below the requested retained count are unchanged.
Voice-lead
The first group establishes a reference centre. In each later group, every member is tested at octave displacements from −3 to +3 octaves and moved to the legal MIDI octave nearest the previous group's centre. Pitch class is preserved. The centre of the re-octaved group becomes the reference for the next group.
Order & time operations
Retrograde
Retrograde mirrors every note interval around the transformed score end:
Each note keeps its duration, and the symbolic score length is preserved. This is a temporal mirror of the score, not merely a reversal of the internal note list.
Rotate groups
Rotation rebuilds the onset-group sequence starting at another group while carrying each group's inter-onset interval with it. The resulting IOI sequence is therefore a rotation of the original IOI sequence. Negative steps wrap modulo the number of groups.
Time scale vs. note length scale
Time scale multiplies both starts and ends, so it performs whole-score augmentation/diminution. Note length scale is applied afterwards and changes duration only. Values above 1 can therefore create new overlaps; values below 1 produce shorter articulations, with a 10 ms minimum duration.
After these transformations, the earliest resulting onset is shifted to time 0. The audio duration then includes the transformed score extent plus the synthesis release time and an additional 50 ms margin.
Additive synthesis
The result is a mono Sound. Each transformed MIDI note is converted to frequency with:
Each note is synthesized as a harmonic series. Harmonic k has amplitude:
The bank uses deterministic Schroeder phases:
This reduces coincident partial peaks without randomizing the spectrum or requiring a seed.
Synthesis settings
| Setting | Default | Behavior |
|---|---|---|
| Harmonics | 6 | Requested harmonic count; validated to 1–24. |
| Spectral tilt | 1.0 | Exponent in 1/k^tilt. It is not clamped. |
| Attack | 15 ms | Linear attack factor inside the note envelope. |
| Release | 150 ms | Each note's render window extends by this amount. |
| Decay per second | 0.8 | Exponential factor exp(−decay × elapsedTime). |
| Sampling rate | 44100 Hz | Output sample rate; values below 8000 Hz are raised to 8000. |
| Peak ceiling | 0.95 | Valid range is (0,1]; invalid values revert to 0.95. The ceiling only attenuates. |
Envelope
The note signal is multiplied by the parsed note amplitude and by a trapezoidal attack/release envelope combined with exponential decay. Release is part of the rendered note window, so overlapping release tails sum naturally with other notes.
Nyquist handling
The harmonic count is reduced independently for each note until every synthesized partial lies below Nyquist. If the fundamental itself is at or above Nyquist, that note is skipped rather than aliased. The Info report states the number of skipped notes.
Peak ceiling
After all notes are summed, the script measures the absolute peak. If it exceeds Peak ceiling, the whole Sound is multiplied by ceiling / peak. Quiet renders are not amplified. The report shows raw peak, final peak, applied gain and RMS.
Visualization
When enabled, the Picture window contains five main regions:
- Original score — piano-roll-style rectangles for parsed source notes.
- Transformed score — the final symbolic note table after filter, pitch, chord, order and time stages. Rectangle color varies with the stored note amplitude.
- Rendered waveform — the mono additive result, using the measured final peak as the vertical range.
- Rendered spectrogram — displayed from 0 Hz to the smaller of Nyquist and 6000 Hz.
- Summary strip — source/result note counts, filtering/chord-op counts, tempo source, transformation chain, synthesis settings, duration, peak, gain, RMS and parser warning when applicable.
The original and transformed score panels use a shared pitch range and a shared time extent large enough to contain both the source score and the rendered result. Octave reference lines and note-name marks are drawn on the pitch axis.
Output & limitations
Output object
The script creates and leaves selected a mono Sound named:
For file input, scoreName is the filename without path and extension. For Strings input, it is the Strings object name. The output sample rate is the synthesis setting, normally 44.1 kHz.
Important limits
- Uncompressed MusicXML only: compressed
.mxlarchives are rejected. - One global tempo: later tempo changes are detected and reported but are not mapped through the score.
- Grace notes are omitted.
- No external instrument model: the output is a synthetic harmonic-bank render, not orchestral playback or sample-based realization.
- Voice-leading is octave re-placement: it minimizes distance to the previous chord centre while preserving pitch class; it is not a general voice-separation optimizer.
- High notes can be inaudible at low sample rates: notes whose fundamental reaches Nyquist are intentionally skipped.
- Peak protection is attenuation-only: the tool does not normalize quiet output upward.
Quick start
- Run
OM_Score_Transformer_v0.4.praat. - Choose File on disk, or select one appropriate Strings object before running and choose Selected Strings object.
- Leave Tempo bpm at 0 to use the score's resolved tempo.
- Choose any filter, pitch, chord, order and time operations. Unused stages can remain at their neutral defaults.
- Leave Edit synthesis settings off for the default 6-harmonic, 44.1 kHz render, or enable it to open the advanced synthesis dialog.
- Run. The result is
<scoreName>_OM; the Info window reports the exact chain and any parser/Nyquist warnings.