Class: Cyclotone::Backends::MIDIFileBackend

Inherits:
Object
  • Object
show all
Includes:
MIDIMessageSupport
Defined in:
lib/cyclotone/backends/midi_file_backend.rb

Constant Summary collapse

DEFAULT_BPM =
120
DEFAULT_PPQN =
480
DEFAULT_TRACK_NAME =
"Cyclotone"
TEMPO_EVENT_PRIORITY =
-30
TIME_SIGNATURE_EVENT_PRIORITY =
-20
TRACK_NAME_EVENT_PRIORITY =
-10
END_OF_TRACK_PRIORITY =
99

Constants included from MIDIMessageSupport

Cyclotone::Backends::MIDIMessageSupport::FRACTIONAL_NOTE_POLICIES, Cyclotone::Backends::MIDIMessageSupport::SUPPORTED_CC_CONTROLS, Cyclotone::Backends::MIDIMessageSupport::SUPPORTED_NOTE_CONTROLS, Cyclotone::Backends::MIDIMessageSupport::UNSUPPORTED_CONTROL_POLICIES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MIDIMessageSupport

#messages_for

Constructor Details

#initialize(path:, bpm: DEFAULT_BPM, ppqn: DEFAULT_PPQN, channel: 0, track_name: DEFAULT_TRACK_NAME, time_signature: [4, 4], track_mode: :single, unsupported_controls: :ignore, fractional_notes: :floor) ⇒ MIDIFileBackend

Returns a new instance of MIDIFileBackend.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 24

def initialize(
  path:,
  bpm: DEFAULT_BPM,
  ppqn: DEFAULT_PPQN,
  channel: 0,
  track_name: DEFAULT_TRACK_NAME,
  time_signature: [4, 4],
  track_mode: :single,
  unsupported_controls: :ignore,
  fractional_notes: :floor
)
  @path = path
  @bpm = normalize_bpm(bpm)
  @ppqn = normalize_positive_integer(ppqn, "ppqn")
  @channel = channel.to_i
  @track_name = track_name.to_s
  @time_signature = normalize_time_signature(time_signature)
  @track_mode = track_mode.to_sym
  @unsupported_controls = normalize_unsupported_control_policy(unsupported_controls)
  @fractional_notes = normalize_fractional_note_policy(fractional_notes)
  @messages = []
  @tempo_changes = []
  @time_signature_changes = []
  @origin_time = nil
end

Instance Attribute Details

#bpmObject (readonly)

Returns the value of attribute bpm.



18
19
20
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 18

def bpm
  @bpm
end

#channelObject (readonly)

Returns the value of attribute channel.



18
19
20
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 18

def channel
  @channel
end

#pathObject (readonly)

Returns the value of attribute path.



18
19
20
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 18

def path
  @path
end

#ppqnObject (readonly)

Returns the value of attribute ppqn.



18
19
20
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 18

def ppqn
  @ppqn
end

#track_modeObject (readonly)

Returns the value of attribute track_mode.



18
19
20
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 18

def track_mode
  @track_mode
end

Class Method Details

.bpm_from_cps(cps, beats_per_cycle: 4) ⇒ Object



20
21
22
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 20

def self.bpm_from_cps(cps, beats_per_cycle: 4)
  cps.to_f * 60.0 * beats_per_cycle.to_f
end

Instance Method Details

#begin_capture(at:) ⇒ Object



50
51
52
53
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 50

def begin_capture(at:)
  @origin_time = at.to_f
  self
end

#clearObject



59
60
61
62
63
64
65
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 59

def clear
  @messages.clear
  @tempo_changes.clear
  @time_signature_changes.clear
  @origin_time = nil
  self
end

#closeObject



103
104
105
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 103

def close
  self
end

#end_captureObject



55
56
57
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 55

def end_capture
  self
end

#flushObject



99
100
101
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 99

def flush
  clear
end

#midi_file_dataObject



111
112
113
114
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 111

def midi_file_data
  tracks = track_payloads
  header_chunk(tracks.length) + tracks.map { |data| track_chunk(data) }.join
end

#panicObject



107
108
109
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 107

def panic
  self
end

#send_event(event, at: Time.now.to_f, cps: nil, slot_id: nil, **_options) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 78

def send_event(event, at: Time.now.to_f, cps: nil, slot_id: nil, **_options)
  capture_time = at.to_f
  @origin_time ||= capture_time

  messages_for(event, cps: cps).each do |message|
    @messages << normalize_message(message, capture_time, slot_id)
  end

  self
rescue StandardError => error
  raise ConnectionError, error.message
end

#tempo_change(at:, bpm:) ⇒ Object



67
68
69
70
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 67

def tempo_change(at:, bpm:)
  @tempo_changes << { at: at.to_f, bpm: normalize_bpm(bpm) }
  self
end

#time_signature_change(at:, numerator:, denominator:) ⇒ Object



72
73
74
75
76
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 72

def time_signature_change(at:, numerator:, denominator:)
  signature = normalize_time_signature([numerator, denominator])
  @time_signature_changes << { at: at.to_f, signature: signature }
  self
end

#write!Object



91
92
93
94
95
96
97
# File 'lib/cyclotone/backends/midi_file_backend.rb', line 91

def write!
  FileUtils.mkdir_p(File.dirname(path))
  File.binwrite(path, midi_file_data)
  path
rescue StandardError => error
  raise ConnectionError, error.message
end