Class: Musa::Transcriptors::FromGDV::ToMIDI::Trill
- Inherits:
-
Musa::Transcription::FeatureTranscriptor
- Object
- Musa::Transcription::FeatureTranscriptor
- Musa::Transcriptors::FromGDV::ToMIDI::Trill
- Defined in:
- lib/musa-dsl/transcription/from-gdv-to-midi.rb
Overview
Trill transcriptor for MIDI playback.
Expands trill ornaments into a rapid alternation between the main note and its upper neighbor. The trill fills the entire note duration with alternating notes, with sophisticated duration management including acceleration.
Trill Options
.tror.tr(true)- Standard trill starting with upper neighbor.tr(:low)- Start with lower neighbor first (2 notes).tr(:low2)- Start with upper but include lower neighbor (4 notes).tr(:same)- Start with main note.tr(factor)- Custom duration factor (e.g.,.tr(1/8r))
Duration Algorithm
The trill uses a sophisticated multi-phase duration algorithm:
- Initial pattern: Based on trill options (:low, :low2, :same)
- Regular pattern: Two cycles at full
note_duration - Accelerando: Cycles at 2/3
note_duration(faster) - Final notes: Distribute remaining duration
Processing
Given .tr on a note:
{ grade: 0, duration: 1r, tr: true }
Expands to alternating sequence:
[
{ grade: 1, duration: 1/16r }, # Upper (initial)
{ grade: 0, duration: 1/16r }, # Main
{ grade: 1, duration: 1/16r }, # Upper (regular)
{ grade: 0, duration: 1/16r }, # Main
{ grade: 1, duration: ~1/24r }, # Upper (accelerando)
{ grade: 0, duration: ~1/24r }, # Main
...
]
Process: .tr
Instance Method Summary collapse
-
#initialize(duration_factor: nil) ⇒ Trill
constructor
Creates trill transcriptor.
-
#transcript(gdv, base_duration:, tick_duration:) ⇒ Array<Hash>, Hash
Transcribes trill to alternating note sequence.
Constructor Details
#initialize(duration_factor: nil) ⇒ Trill
Creates trill transcriptor.
447 448 449 |
# File 'lib/musa-dsl/transcription/from-gdv-to-midi.rb', line 447 def initialize(duration_factor: nil) @duration_factor = duration_factor || 1/4r end |
Instance Method Details
#transcript(gdv, base_duration:, tick_duration:) ⇒ Array<Hash>, Hash
Transcribes trill to alternating note sequence.
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/musa-dsl/transcription/from-gdv-to-midi.rb', line 460 def transcript(gdv, base_duration:, tick_duration:) tr = gdv.delete :tr if tr note_duration = base_duration * @duration_factor check(tr) do |tr| case tr when Numeric # duration factor note_duration *= base_duration * tr.to_r end end used_duration = 0r last = nil gdvs = [] check(tr) do |tr| case tr when :low # start with lower note gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = -1); gdv[:duration] = note_duration } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration } used_duration += 2 * note_duration when :low2 # start with upper note but go to lower note once gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = -1); gdv[:duration] = note_duration } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration } used_duration += 4 * note_duration when :same # start with the same note gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration } used_duration += note_duration end end 2.times do if used_duration + 2 * note_duration <= gdv[:duration] gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration } used_duration += 2 * note_duration end end while used_duration + 2 * note_duration * 2/3r <= gdv[:duration] gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration * 2/3r } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration * 2/3r } used_duration += 2 * note_duration * 2/3r end duration_diff = gdv[:duration] - used_duration if duration_diff >= note_duration gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = duration_diff / 2 } gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = duration_diff / 2 } elsif duration_diff > 0 gdvs[-1][:duration] += duration_diff / 2 gdvs[-2][:duration] += duration_diff / 2 end super gdvs, base_duration: base_duration, tick_duration: tick_duration else super end end |