module Sidtool
Constants
- CLOCK_FREQUENCY
- EndOfTrack
- FRAMES_PER_SECOND
PAL properties
- KeySignature
- NoteOff
- NoteOn
- ProgramChange
- STATE
- TimeSignature
- TrackName
- VERSION
Public Class Methods
new(synths_for_voices)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 93 def initialize(synths_for_voices) @synths_for_voices = synths_for_voices end
Public Instance Methods
build_track(synths)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 106 def build_track(synths) waveforms = [:tri, :saw, :pulse, :noise] track = [] current_frame = 0 synths.each do |synth| channel = waveforms.index(synth.waveform) || raise("Unknown waveform #{synth.waveform}") track << DeltaTime[synth.start_frame - current_frame] track << NoteOn[channel, synth.tone] current_frame = synth.start_frame current_tone = synth.tone synth.controls.each do |start_frame, tone| track << DeltaTime[start_frame - current_frame] track << NoteOff[channel, current_tone] track << DeltaTime[0] track << NoteOn[channel, tone] current_tone = tone current_frame = start_frame end end_frame = [current_frame, synth.start_frame + (FRAMES_PER_SECOND * (synth.attack + synth.decay + synth.sustain_length)).to_i].max track << DeltaTime[end_frame - current_frame] track << NoteOff[channel, current_tone] current_frame = end_frame end track end
write_to(path)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 97 def write_to(path) tracks = @synths_for_voices.map { |synths| build_track(synths) } File.open(path, 'wb') do |file| write_header(file) tracks.each_with_index { |track, index| write_track(file, track, "Voice #{index + 1}") } end end
Private Instance Methods
write_byte(file, value)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 193 def write_byte(file, value) bytes = [value & 255] file << bytes.pack('c') end
write_header(file)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 138 def write_header(file) # Type file << 'MThd' # Length write_uint32(file, 6) # Format write_uint16(file, 1) # Number of tracks write_uint16(file, 3) # Division # Default tempo is 120 BPM - 120 quarter-notes per minute. Which is 2 quarter-notes per second. If we then define # 25 ticks per quarter-note, we end up with a timing of 50 ticks per second. write_uint16(file, 25) end
write_track(file, track, name)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 157 def write_track(file, track, name) track_with_metadata = [ DeltaTime[0], TrackName[name], DeltaTime[0], TimeSignature[4, 2, 24, 8], DeltaTime[0], KeySignature[0, 0], DeltaTime[0], ProgramChange[0, 1], # Triangular - maps to piano DeltaTime[0], ProgramChange[1, 25], # Saw - maps to guitar DeltaTime[0], ProgramChange[2, 33], # Pulse - maps to bass DeltaTime[0], ProgramChange[3, 41] # Noise - maps to strings ] + track + [ DeltaTime[0], EndOfTrack[] ] track_bytes = track_with_metadata.flat_map(&:bytes) # Type file << 'MTrk' # Length write_uint32(file, track_bytes.length) file << track_bytes.pack('c' * track_bytes.length) end
write_uint16(file, value)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 188 def write_uint16(file, value) bytes = [(value >> 8) & 255, value & 255] file << bytes.pack('cc') end
write_uint32(file, value)
click to toggle source
# File lib/sidtool/midi_file_writer.rb, line 183 def write_uint32(file, value) bytes = [(value >> 24) & 255, (value >> 16) & 255, (value >> 8) & 255, value & 255] file << bytes.pack('cccc') end