Class: InevitableCacophony::Parser::RhythmLine
- Inherits:
-
Object
- Object
- InevitableCacophony::Parser::RhythmLine
- Defined in:
- lib/inevitable_cacophony/parser/rhythm_line.rb
Constant Summary collapse
- BEAT_VALUES =
Amplitude symbols used by Dwarf Fortress These are in no particular scale; the maximum volume will be whatever’s loudest in any particular string.
{ # Silence '-' => 0, # Regular beat 'x' => 4, # Accented beat 'X' => 6, # Primary accent '!' => 9 }
- TIMING_VALUES =
Values for each kind of timing symbol. By default a beat is in the middle of its time-slice (0.0); a value of 1.0 means to play it as late as possible, and -1.0 means play as early as possible.
Technically position of these matters, but we handle that in the parser regexp.
{ # Normal beat (no special timing) '' => 0.0, # Early beat '`' => -1.0, # Late beat '\'' => 1.0 }
- BAR_LINE =
'|'
Class Method Summary collapse
Instance Method Summary collapse
Class Method Details
.parse(rhythm_string) ⇒ Object
74 75 76 |
# File 'lib/inevitable_cacophony/parser/rhythm_line.rb', line 74 def self.parse(rhythm_string) new.parse(rhythm_string) end |
Instance Method Details
#parse(rhythm_string) ⇒ Rhythm
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/inevitable_cacophony/parser/rhythm_line.rb', line 49 def parse(rhythm_string) # TODO: should I be ignoring bar lines? Is there anything I can do with them? raw_beats = rhythm_string.split(/ |(?=`)|(?<=')/).reject { |beat| beat == BAR_LINE }.map do |beat| timing_symbol = beat.chars.reject { |char| BEAT_VALUES.keys.include?(char) }.join timing = TIMING_VALUES[timing_symbol] || raise("Unknown timing symbol #{timing_symbol}") accent_symbol = beat.delete(timing_symbol) amplitude = BEAT_VALUES[accent_symbol] || raise("Unknown beat symbol #{accent_symbol}") Rhythm::Beat.new(amplitude, 1, timing) end # Ensure all our amplitudes are between 0.0 and 1.0 # TODO: find a way to do this without creating twice as many beats as we need. highest_volume = raw_beats.map(&:amplitude).max scaled_beats = raw_beats.map do |beat| scaled = beat.amplitude.to_f / highest_volume Rhythm::Beat.new(scaled, 1, beat.timing) end Rhythm.new(scaled_beats) end |