class InevitableCacophony::Parser::RhythmLine

Constants

BAR_LINE
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.

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.

Public Class Methods

parse(rhythm_string) click to toggle source
# File lib/inevitable_cacophony/parser/rhythm_line.rb, line 74
def self.parse(rhythm_string)
        new.parse(rhythm_string)
end

Public Instance Methods

parse(rhythm_string) click to toggle source

@param rhythm_string [String] In the notation Dwarf Fortress produces, like | X x ! x | @return [Rhythm]

# 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