Transcription - MIDI & MusicXML Output
The Transcription system converts GDV events to MIDI (with ornament expansion) or MusicXML format (preserving ornaments as symbols).
When is this the answer
Transcription is the step between what the music is and how a particular medium says it. A trill is one note with an ornament; a MIDI instrument has no ornaments and needs the notes; a score has no notes to spare and needs the symbol. Both are the same music, and the transcriptor is what decides which telling.
| You are going to | You need | Because |
|---|---|---|
| play through MIDI | ToMIDI |
the ornament has to become the notes it stands for |
| write a score | ToMusicXML |
the ornament has to stay a symbol |
| both, from one source | two transcriptors over the same GDV | the source says the music, not the rendering |
Without a transcriptor, ornaments are silently ignored. A (0 1 mf tr)
played with no transcription set produces one plain note and no error. That
silence is the most common surprise in this subsystem.
When it is NOT the answer. If the material has no ornaments and no articulation -- plain notes with pitch, duration and velocity -- there is nothing to transcribe, and a decoder alone is enough.
MIDI with Ornament Expansion
require 'musa-dsl'
using Musa::Extension::Neumas
# Neuma notation with ornaments: trill (.tr) and mordent (.mor)
neumas = "(0 1 mf) (+2 1 tr) (+4 1 mor) (+5 1)"
# Create scale and decoder
scale = Musa::Scales::Scales.et12[440.0].major[60]
decoder = Musa::Neumas::Decoders::NeumaDecoder.new(scale, base_duration: 1/4r)
# Create MIDI transcriptor with ornament expansion
transcriptor = Musa::Transcription::Transcriptor.new(
Musa::Transcriptors::FromGDV::ToMIDI.transcription_set(duration_factor: 1/6r),
base_duration: 1/4r,
tick_duration: 1/96r
)
# Parse and expand ornaments to PDV
result = Musa::Neumalang::Neumalang.parse(neumas, decode_with: decoder)
.process_with { |gdv| transcriptor.transcript(gdv) }
.map { |gdv| gdv.to_pdv(scale) }
.to_a(recursive: true)
# View expanded notes (ornaments rendered as note sequences)
result.each do |pdv|
puts "Pitch: #{pdv[:pitch]}, Duration: #{pdv[:duration]}, Velocity: #{pdv[:velocity]}"
end
# => Pitch: 60, Duration: 1/4, Velocity: 80 # C4 (no ornament)
# Pitch: 65, Duration: 1/24, Velocity: 80 # Trill: F4 (upper neighbor)
# Pitch: 64, Duration: 1/24, Velocity: 80 # Trill: E4 (original)
# Pitch: 65, Duration: 1/24, Velocity: 80 # Trill: F4
# Pitch: 64, Duration: 1/24, Velocity: 80 # Trill: E4
# ... (trill alternation continues)
# Pitch: 71, Duration: 1/24, Velocity: 80 # Mordent: B4 (original)
# Pitch: 72, Duration: 1/24, Velocity: 80 # Mordent: C5 (neighbor)
# Pitch: 71, Duration: 1/6, Velocity: 80 # Mordent: B4 (return)
# Pitch: 79, Duration: 1/4, Velocity: 80 # G5 (no ornament)
Supported ornaments:
.tr- Trill (rapid alternation with upper note).mor- Mordent (quick alternation with adjacent note).turn- Turn (four-note figure).st- Staccato (shortened duration)
MusicXML with Ornament Symbols
require 'musa-dsl'
using Musa::Extension::Neumas
# Same phrase as MIDI example (ornaments preserved as symbols)
neumas = "(0 1 mf) (+2 1 tr) (+4 1 mor) (+5 1)"
# Create scale and decoder
scale = Musa::Scales::Scales.et12[440.0].major[60]
decoder = Musa::Neumas::Decoders::NeumaDecoder.new(scale, base_duration: 1/4r)
# Create MusicXML transcriptor (preserves ornaments as symbols)
transcriptor = Musa::Transcription::Transcriptor.new(
Musa::Transcriptors::FromGDV::ToMusicXML.transcription_set,
base_duration: 1/4r,
tick_duration: 1/96r
)
# Parse and convert to GDV with preserved ornament markers
serie = Musa::Neumalang::Neumalang.parse(neumas, decode_with: decoder)
.process_with { |gdv| transcriptor.transcript(gdv) }
# Create Score and use sequencer to fill it
score = Musa::Datasets::Score.new
sequencer = Musa::Sequencer::Sequencer.new(4, 24)
sequencer.at 1 do
play serie, decoder: decoder, mode: :neumalang do |gdv|
pdv = gdv.to_pdv(scale)
score.at(position, add: pdv) # position is automatically tracked by sequencer
end
end
sequencer.run
# Convert to MusicXML
mxml = score.to_mxml(
4, 24, # 4 beats per bar, 24 ticks per beat
bpm: 120,
title: 'Ornaments Example',
creators: { composer: 'MusaDSL' },
parts: { piano: { name: 'Piano', clefs: { g: 2 } } }
)
# Generated MusicXML (excerpt showing notes with ornaments):
puts mxml.to_xml.string
Generated MusicXML output (excerpt):
<note>
<pitch>
<step>C</step>
<octave>4</octave>
</pitch>
<duration>24</duration>
<type>quarter</type>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>24</duration>
<type>quarter</type>
<notations>
<ornaments>
<trill-mark /> <!-- Trill preserved as notation symbol -->
</ornaments>
</notations>
</note>
<note>
<pitch>
<step>B</step>
<octave>4</octave>
</pitch>
<duration>24</duration>
<type>quarter</type>
<notations>
<ornaments>
<inverted-mordent /> <!-- Mordent preserved as notation symbol -->
</ornaments>
</notations>
</note>
Note: Only 4 notes (vs 11 in MIDI) - ornaments preserved as notation symbols, not expanded
API Reference
Complete API documentation:
- Musa::Transcription - Musical event transformation and ornament expansion
Source code: lib/transcription/ and lib/musicxml/