Class: HeadMusic::Time::Conductor
- Inherits:
-
Object
- Object
- HeadMusic::Time::Conductor
- Defined in:
- lib/head_music/time/conductor.rb
Overview
Representation of a conductor track for musical material
The Conductor class synchronizes three different time representations: - Clock time: elapsed nanoseconds (source of truth) - Musical position: bars:beats:ticks:subticks notation - SMPTE timecode: hours:minutes:seconds:frames
Each moment in a track corresponds to all three positions simultaneously. The conductor handles conversions between these representations based on the current tempo, meter, and framerate.
Instance Attribute Summary collapse
-
#framerate ⇒ Integer
Frames per second for SMPTE conversions.
-
#meter_map ⇒ MeterMap
readonly
The meter map for this conductor.
-
#starting_musical_position ⇒ MusicalPosition
The musical position at clock time 0.
-
#starting_smpte_timecode ⇒ SmpteTimecode
The SMPTE timecode at clock time 0.
-
#tempo_map ⇒ TempoMap
readonly
The tempo map for this conductor.
Instance Method Summary collapse
-
#clock_to_musical(clock_position) ⇒ MusicalPosition
Convert clock position to musical position.
-
#clock_to_smpte(clock_position) ⇒ SmpteTimecode
Convert clock position to SMPTE timecode.
-
#initialize(starting_musical_position: nil, starting_smpte_timecode: nil, framerate: SmpteTimecode::DEFAULT_FRAMERATE, starting_tempo: nil, starting_meter: nil, tempo_map: nil, meter_map: nil) ⇒ Conductor
constructor
Create a new conductor.
-
#musical_time_converter ⇒ Object
private
A fresh musical-time converter over the current maps and starting position (starting_musical_position is a mutable accessor), rebuilt per call rather than memoized so reassignment takes effect.
-
#musical_to_clock(musical_position) ⇒ ClockPosition
Convert musical position to clock position.
-
#smpte_converter ⇒ Object
private
A fresh SMPTE converter reflecting the current framerate and starting timecode.
-
#smpte_to_clock(smpte_timecode) ⇒ ClockPosition
Convert SMPTE timecode to clock position.
-
#starting_meter ⇒ HeadMusic::Rudiment::Meter
The initial meter (delegates to meter_map).
-
#starting_tempo ⇒ HeadMusic::Rudiment::Tempo
The initial tempo (delegates to tempo_map).
Constructor Details
#initialize(starting_musical_position: nil, starting_smpte_timecode: nil, framerate: SmpteTimecode::DEFAULT_FRAMERATE, starting_tempo: nil, starting_meter: nil, tempo_map: nil, meter_map: nil) ⇒ Conductor
Create a new conductor
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/head_music/time/conductor.rb', line 68 def initialize( starting_musical_position: nil, starting_smpte_timecode: nil, framerate: SmpteTimecode::DEFAULT_FRAMERATE, starting_tempo: nil, starting_meter: nil, tempo_map: nil, meter_map: nil ) @starting_musical_position = starting_musical_position || MusicalPosition.new @starting_smpte_timecode = starting_smpte_timecode || SmpteTimecode.new(0, 0, 0, 0, framerate: framerate) @framerate = framerate # Create or use provided maps @tempo_map = tempo_map || TempoMap.new( starting_tempo: starting_tempo || HeadMusic::Rudiment::Tempo.new("quarter", 120), starting_position: @starting_musical_position ) @meter_map = meter_map || MeterMap.new( starting_meter: starting_meter || "4/4", starting_position: @starting_musical_position ) # Link maps together for position normalization @tempo_map.meter = @meter_map.meter_at(@starting_musical_position) end |
Instance Attribute Details
#framerate ⇒ Integer
Returns frames per second for SMPTE conversions.
41 42 43 |
# File 'lib/head_music/time/conductor.rb', line 41 def framerate @framerate end |
#meter_map ⇒ MeterMap (readonly)
Returns the meter map for this conductor.
47 48 49 |
# File 'lib/head_music/time/conductor.rb', line 47 def meter_map @meter_map end |
#starting_musical_position ⇒ MusicalPosition
Returns the musical position at clock time 0.
35 36 37 |
# File 'lib/head_music/time/conductor.rb', line 35 def starting_musical_position @starting_musical_position end |
#starting_smpte_timecode ⇒ SmpteTimecode
Returns the SMPTE timecode at clock time 0.
38 39 40 |
# File 'lib/head_music/time/conductor.rb', line 38 def starting_smpte_timecode @starting_smpte_timecode end |
#tempo_map ⇒ TempoMap (readonly)
Returns the tempo map for this conductor.
44 45 46 |
# File 'lib/head_music/time/conductor.rb', line 44 def tempo_map @tempo_map end |
Instance Method Details
#clock_to_musical(clock_position) ⇒ MusicalPosition
Convert clock position to musical position
Uses the tempo map to determine how many beats have elapsed, accounting for tempo changes along the timeline.
102 103 104 |
# File 'lib/head_music/time/conductor.rb', line 102 def clock_to_musical(clock_position) musical_time_converter.clock_to_musical(clock_position) end |
#clock_to_smpte(clock_position) ⇒ SmpteTimecode
Convert clock position to SMPTE timecode
Uses the framerate to determine the timecode.
123 124 125 |
# File 'lib/head_music/time/conductor.rb', line 123 def clock_to_smpte(clock_position) smpte_converter.clock_to_smpte(clock_position) end |
#musical_time_converter ⇒ Object (private)
A fresh musical-time converter over the current maps and starting position (starting_musical_position is a mutable accessor), rebuilt per call rather than memoized so reassignment takes effect.
142 143 144 145 146 147 148 |
# File 'lib/head_music/time/conductor.rb', line 142 def musical_time_converter MusicalTimeConverter.new( tempo_map: tempo_map, meter_map: meter_map, starting_musical_position: starting_musical_position ) end |
#musical_to_clock(musical_position) ⇒ ClockPosition
Convert musical position to clock position
Uses the tempo map to determine how much clock time has elapsed based on the musical position, accounting for tempo changes.
113 114 115 |
# File 'lib/head_music/time/conductor.rb', line 113 def musical_to_clock(musical_position) musical_time_converter.musical_to_clock(musical_position) end |
#smpte_converter ⇒ Object (private)
A fresh SMPTE converter reflecting the current framerate and starting timecode. Both are mutable accessors, so it is rebuilt per call rather than memoized, ensuring a reassigned framerate takes effect.
153 154 155 |
# File 'lib/head_music/time/conductor.rb', line 153 def smpte_converter SmpteConverter.new(framerate: framerate, starting_smpte_timecode: starting_smpte_timecode) end |
#smpte_to_clock(smpte_timecode) ⇒ ClockPosition
Convert SMPTE timecode to clock position
Uses the framerate to determine the clock time.
133 134 135 |
# File 'lib/head_music/time/conductor.rb', line 133 def smpte_to_clock(smpte_timecode) smpte_converter.smpte_to_clock(smpte_timecode) end |
#starting_meter ⇒ HeadMusic::Rudiment::Meter
Returns the initial meter (delegates to meter_map).
55 56 57 |
# File 'lib/head_music/time/conductor.rb', line 55 def starting_meter meter_map.events.first.meter end |
#starting_tempo ⇒ HeadMusic::Rudiment::Tempo
Returns the initial tempo (delegates to tempo_map).
50 51 52 |
# File 'lib/head_music/time/conductor.rb', line 50 def starting_tempo tempo_map.events.first.tempo end |