Class: HeadMusic::Time::TempoMap
- Inherits:
-
Object
- Object
- HeadMusic::Time::TempoMap
- Includes:
- EventMapSupport
- Defined in:
- lib/head_music/time/tempo_map.rb
Overview
Manages tempo changes along a musical timeline
A TempoMap maintains a sorted list of tempo changes at specific musical positions, allowing you to determine which tempo is active at any point and iterate through tempo segments for time calculations.
Instance Attribute Summary collapse
-
#events ⇒ Array<TempoEvent>
readonly
All tempo events in chronological order.
-
#meter ⇒ Object
writeonly
private
Instance Method Summary collapse
-
#add_change(position, beat_value_or_tempo, beats_per_minute = nil) ⇒ Object
-
#clear_changes ⇒ Object
-
#compare_positions(first_position, second_position) ⇒ Object
included
from EventMapSupport
private
-
#each_segment(from_position, to_position) {|current_pos, to_pos, current_tempo| ... } ⇒ Object
-
#initialize(starting_tempo: nil, starting_position: nil) ⇒ TempoMap
constructor
A new instance of TempoMap.
-
#normalize_position(position) ⇒ Object
private
-
#position_tuple(position) ⇒ Object
included
from EventMapSupport
private
-
#positions_equal?(first_position, second_position) ⇒ Boolean
included
from EventMapSupport
private
-
#remove_change(position) ⇒ Object
-
#sort_events! ⇒ Object
included
from EventMapSupport
private
-
#tempo_at(position) ⇒ Object
Constructor Details
#initialize(starting_tempo: nil, starting_position: nil) ⇒ TempoMap
Returns a new instance of TempoMap.
31 32 33 34 35 36 |
# File 'lib/head_music/time/tempo_map.rb', line 31 def initialize(starting_tempo: nil, starting_position: nil) starting_tempo ||= HeadMusic::Rudiment::Tempo.new("quarter", 120) starting_position ||= MusicalPosition.new @events = [TempoEvent.new(starting_position, starting_tempo.beat_value.to_s, starting_tempo.beats_per_minute)] @meter = nil end |
Instance Attribute Details
#events ⇒ Array<TempoEvent> (readonly)
Returns all tempo events in chronological order.
29 30 31 |
# File 'lib/head_music/time/tempo_map.rb', line 29 def events @events end |
#meter=(value) ⇒ Object (writeonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
94 95 96 |
# File 'lib/head_music/time/tempo_map.rb', line 94 def meter=(value) @meter = value end |
Instance Method Details
#add_change(position, beat_value_or_tempo, beats_per_minute = nil) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/head_music/time/tempo_map.rb', line 38 def add_change(position, beat_value_or_tempo, beats_per_minute = nil) remove_change(position) event = if beat_value_or_tempo.is_a?(HeadMusic::Rudiment::Tempo) TempoEvent.new(position, beat_value_or_tempo.beat_value.to_s, beat_value_or_tempo.beats_per_minute).tap do |tempo_event| tempo_event.tempo = beat_value_or_tempo end else TempoEvent.new(position, beat_value_or_tempo, beats_per_minute) end @events << event sort_events! event end |
#clear_changes ⇒ Object
58 59 60 |
# File 'lib/head_music/time/tempo_map.rb', line 58 def clear_changes @events = [@events.first] end |
#compare_positions(first_position, second_position) ⇒ Object (private) Originally defined in module EventMapSupport
#each_segment(from_position, to_position) {|current_pos, to_pos, current_tempo| ... } ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/head_music/time/tempo_map.rb', line 70 def each_segment(from_position, to_position) from_pos = normalize_position(from_position) to_pos = normalize_position(to_position) relevant_events = @events.select do |event| normalize_position(event.position) < to_pos end current_pos = from_pos current_tempo = tempo_at(from_pos) relevant_events.each do |event| normalized_event_pos = normalize_position(event.position) next if normalized_event_pos <= from_pos yield current_pos, normalized_event_pos, current_tempo current_pos = normalized_event_pos current_tempo = event.tempo end yield current_pos, to_pos, current_tempo end |
#normalize_position(position) ⇒ Object (private)
98 99 100 101 102 |
# File 'lib/head_music/time/tempo_map.rb', line 98 def normalize_position(position) return position unless @meter position.dup.tap { |pos| pos.normalize!(@meter) } end |
#position_tuple(position) ⇒ Object (private) Originally defined in module EventMapSupport
#positions_equal?(first_position, second_position) ⇒ Boolean (private) Originally defined in module EventMapSupport
#remove_change(position) ⇒ Object
52 53 54 55 56 |
# File 'lib/head_music/time/tempo_map.rb', line 52 def remove_change(position) @events.reject! do |event| event != @events.first && positions_equal?(event.position, position) end end |
#sort_events! ⇒ Object (private) Originally defined in module EventMapSupport
#tempo_at(position) ⇒ Object
62 63 64 65 66 67 68 |
# File 'lib/head_music/time/tempo_map.rb', line 62 def tempo_at(position) normalized_pos = normalize_position(position) active_event = @events.reverse.find do |event| normalize_position(event.position) <= normalized_pos end active_event&.tempo || @events.first.tempo end |