class MelodyToMidi

Converts a programmatically-defined melody to Midi.

Public Instance Methods

make_midi(melody_file, output_file) click to toggle source

Creates a Midi file from a ruby program defining a melody. It writes its output to the path specified by output_file.

melody_file is expected to contain the following functions:

melody() - contains a melody (see process_melody for details)
mybpm() - optional, sets the BPM (or default to 60 if not specified)
# File lib/melody_to_mid.rb, line 82
def make_midi(melody_file, output_file)
  seq = Sequence.new()

  require_relative 'shared_functions'
  load melody_file

  track = Track.new(seq)
  seq.tracks << track
  bpm = 60
  if defined? mybpm
    bpm = mybpm()
  end
  track.events << Tempo.new(Tempo.bpm_to_mpq(bpm))
  track.events << MetaEvent.new(META_SEQ_NAME, 'Sequence Name')

  track = Track.new(seq)
  seq.tracks << track

  track.name = 'Melody Track'
  track.instrument = GM_PATCH_NAMES[0]

  track.events << Controller.new(0, CC_VOLUME, 127)
  track.events << ProgramChange.new(0, 1, 0)

  process_melody(track, melody())

  File.open(output_file, 'wb') { |file| seq.write(file) }
end

Private Instance Methods

add_note(track, note, time_offset, duration, volume) click to toggle source

Adds a single note of a specified pitch, volume and duration to track at position time_offset. Make sure to call track.recalc_delta_from_times() after all notes have been added.

# File lib/melody_to_mid.rb, line 28
        def add_note(track, note, time_offset, duration, volume)
  event = NoteOn.new(0, note, volume, 0)
  event.time_from_start = time_offset
  track.events << event
  event = NoteOff.new(0, note, volume, 0)
  event.time_from_start = time_offset + duration
  track.events << event
end
add_to_track(track, melody) click to toggle source

Adds a melody to track. The melody is specified as an an array containg up to three sub-arrays:

  • List of pitches (as MIDI notes. eg: 60 is C4)

  • List of durations (as fractions of a measure. eg: 0.25 is a quarter)

  • (Optional) list of volumes (0..5 range)

# File lib/melody_to_mid.rb, line 43
        def add_to_track(track, melody)
  time_offset = 0
  (0..melody[0].length-1).each do |i|
    note = melody[0][i].to_i
    duration = (480 * melody[1][i]).to_i
    volume = 127
    if melody.length >= 3
      volume = ((127 * melody[2][i]) / 5).to_i
    end
    if note != 0
      add_note(track, note, time_offset, duration, volume)
    end
    time_offset += duration
  end
end
process_melody(track, melody) click to toggle source

Adds a melody to the track. The melody object can optionally contain sub-melodies if specified as a dictionary. For example, it can be of the form {m1: …, m2: …, m3: …} Alternatively, the melody object can be a single melody (see add_to_track for details).

# File lib/melody_to_mid.rb, line 64
        def process_melody(track, melody)
  if melody.respond_to?(:key)
    melody.values().each do |m|
      add_to_track(track, m)
    end
  elsif melody.respond_to?(:length)
    add_to_track(track, melody)
  end
  track.recalc_delta_from_times()
end