class InevitableCacophony::ToneGenerator

Constants

SAMPLE_RATE
TAU

One full revolution of a circle (or one full cycle of a sine wave)

Public Class Methods

new(tonic) click to toggle source

@param tonic [Numeric] The tonic frequency, in Hertz

# File lib/inevitable_cacophony/tone_generator.rb, line 37
def initialize(tonic)
        @tonic = tonic
        @phrases = []
end

Public Instance Methods

add_phrase(phrase) click to toggle source
# File lib/inevitable_cacophony/tone_generator.rb, line 24
def add_phrase(phrase)
        @phrases << phrase_buffer(phrase)
end
phrase_buffer(phrase) click to toggle source

Create a buffer representing a given phrase as an audio sample

@param phrase [Phrase]

# File lib/inevitable_cacophony/tone_generator.rb, line 19
def phrase_buffer(phrase)
        samples = phrase.notes.map { |note| note_samples(note, phrase.tempo) }
        WaveFile::Buffer.new(samples.flatten, WaveFile::Format.new(:mono, :float, SAMPLE_RATE))
end
write(io) click to toggle source
# File lib/inevitable_cacophony/tone_generator.rb, line 28
def write(io)
        WaveFile::Writer.new(io, WaveFile::Format.new(:mono, :pcm_16, SAMPLE_RATE)) do |writer|
                @phrases.each do |phrase|
                        writer.write(phrase)
                end
        end
end

Private Instance Methods

note_samples(note, tempo) click to toggle source

Create a array of amplitudes representing a single note as a sample.

@param note [Note] @param tempo [Numeric] Tempo in BPM to play the note at

(exact duration will also depend on the beat).
# File lib/inevitable_cacophony/tone_generator.rb, line 49
def note_samples(note, tempo)
        samples_per_wave = SAMPLE_RATE / (note.ratio.to_f * @tonic)
        samples_per_beat = (60.0 / tempo) * SAMPLE_RATE
        samples = []
        
        start_delay = note.start_delay * samples_per_beat
        after_delay = note.after_delay * samples_per_beat
        note_length = (note.duration * samples_per_beat) - start_delay - after_delay
        
        samples << ([0.0] * start_delay)
        
        samples << note_length.to_i.times.map do |index|
                wave_fraction = index / samples_per_wave.to_f
                note.beat.amplitude * Math.sin(wave_fraction * TAU)
        end
        samples << ([0.0] * after_delay)
        samples.flatten
end