jmtk 0.0.3.3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +10 -0
- data/DEVELOPMENT_NOTES.md +115 -0
- data/INTRO.md +129 -0
- data/LICENSE.txt +27 -0
- data/README.md +50 -0
- data/Rakefile +102 -0
- data/bin/jmtk +250 -0
- data/bin/mtk +250 -0
- data/examples/crescendo.rb +20 -0
- data/examples/drum_pattern.rb +23 -0
- data/examples/dynamic_pattern.rb +36 -0
- data/examples/gets_and_play.rb +27 -0
- data/examples/notation.rb +22 -0
- data/examples/play_midi.rb +17 -0
- data/examples/print_midi.rb +13 -0
- data/examples/random_tone_row.rb +18 -0
- data/examples/syntax_to_midi.rb +28 -0
- data/examples/test_output.rb +7 -0
- data/examples/tone_row_melody.rb +23 -0
- data/lib/mtk.rb +76 -0
- data/lib/mtk/core/duration.rb +213 -0
- data/lib/mtk/core/intensity.rb +158 -0
- data/lib/mtk/core/interval.rb +157 -0
- data/lib/mtk/core/pitch.rb +154 -0
- data/lib/mtk/core/pitch_class.rb +194 -0
- data/lib/mtk/events/event.rb +119 -0
- data/lib/mtk/events/note.rb +112 -0
- data/lib/mtk/events/parameter.rb +54 -0
- data/lib/mtk/events/timeline.rb +232 -0
- data/lib/mtk/groups/chord.rb +56 -0
- data/lib/mtk/groups/collection.rb +196 -0
- data/lib/mtk/groups/melody.rb +96 -0
- data/lib/mtk/groups/pitch_class_set.rb +163 -0
- data/lib/mtk/groups/pitch_collection.rb +23 -0
- data/lib/mtk/io/dls_synth_device.rb +146 -0
- data/lib/mtk/io/dls_synth_output.rb +62 -0
- data/lib/mtk/io/jsound_input.rb +87 -0
- data/lib/mtk/io/jsound_output.rb +82 -0
- data/lib/mtk/io/midi_file.rb +209 -0
- data/lib/mtk/io/midi_input.rb +97 -0
- data/lib/mtk/io/midi_output.rb +195 -0
- data/lib/mtk/io/notation.rb +162 -0
- data/lib/mtk/io/unimidi_input.rb +117 -0
- data/lib/mtk/io/unimidi_output.rb +140 -0
- data/lib/mtk/lang/durations.rb +57 -0
- data/lib/mtk/lang/intensities.rb +61 -0
- data/lib/mtk/lang/intervals.rb +73 -0
- data/lib/mtk/lang/mtk_grammar.citrus +237 -0
- data/lib/mtk/lang/parser.rb +29 -0
- data/lib/mtk/lang/pitch_classes.rb +29 -0
- data/lib/mtk/lang/pitches.rb +52 -0
- data/lib/mtk/lang/pseudo_constants.rb +26 -0
- data/lib/mtk/lang/variable.rb +32 -0
- data/lib/mtk/numeric_extensions.rb +66 -0
- data/lib/mtk/patterns/chain.rb +49 -0
- data/lib/mtk/patterns/choice.rb +43 -0
- data/lib/mtk/patterns/cycle.rb +18 -0
- data/lib/mtk/patterns/for_each.rb +71 -0
- data/lib/mtk/patterns/function.rb +39 -0
- data/lib/mtk/patterns/lines.rb +54 -0
- data/lib/mtk/patterns/palindrome.rb +45 -0
- data/lib/mtk/patterns/pattern.rb +171 -0
- data/lib/mtk/patterns/sequence.rb +20 -0
- data/lib/mtk/sequencers/event_builder.rb +132 -0
- data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
- data/lib/mtk/sequencers/sequencer.rb +111 -0
- data/lib/mtk/sequencers/step_sequencer.rb +26 -0
- data/spec/mtk/core/duration_spec.rb +372 -0
- data/spec/mtk/core/intensity_spec.rb +289 -0
- data/spec/mtk/core/interval_spec.rb +265 -0
- data/spec/mtk/core/pitch_class_spec.rb +343 -0
- data/spec/mtk/core/pitch_spec.rb +297 -0
- data/spec/mtk/events/event_spec.rb +234 -0
- data/spec/mtk/events/note_spec.rb +174 -0
- data/spec/mtk/events/parameter_spec.rb +220 -0
- data/spec/mtk/events/timeline_spec.rb +430 -0
- data/spec/mtk/groups/chord_spec.rb +85 -0
- data/spec/mtk/groups/collection_spec.rb +374 -0
- data/spec/mtk/groups/melody_spec.rb +225 -0
- data/spec/mtk/groups/pitch_class_set_spec.rb +340 -0
- data/spec/mtk/io/midi_file_spec.rb +243 -0
- data/spec/mtk/io/midi_output_spec.rb +102 -0
- data/spec/mtk/lang/durations_spec.rb +89 -0
- data/spec/mtk/lang/intensities_spec.rb +101 -0
- data/spec/mtk/lang/intervals_spec.rb +143 -0
- data/spec/mtk/lang/parser_spec.rb +603 -0
- data/spec/mtk/lang/pitch_classes_spec.rb +62 -0
- data/spec/mtk/lang/pitches_spec.rb +56 -0
- data/spec/mtk/lang/pseudo_constants_spec.rb +20 -0
- data/spec/mtk/lang/variable_spec.rb +52 -0
- data/spec/mtk/numeric_extensions_spec.rb +83 -0
- data/spec/mtk/patterns/chain_spec.rb +110 -0
- data/spec/mtk/patterns/choice_spec.rb +97 -0
- data/spec/mtk/patterns/cycle_spec.rb +123 -0
- data/spec/mtk/patterns/for_each_spec.rb +136 -0
- data/spec/mtk/patterns/function_spec.rb +120 -0
- data/spec/mtk/patterns/lines_spec.rb +77 -0
- data/spec/mtk/patterns/palindrome_spec.rb +108 -0
- data/spec/mtk/patterns/pattern_spec.rb +132 -0
- data/spec/mtk/patterns/sequence_spec.rb +203 -0
- data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
- data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
- data/spec/mtk/sequencers/step_sequencer_spec.rb +93 -0
- data/spec/spec_coverage.rb +2 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test.mid +0 -0
- metadata +226 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'unimidi'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module MTK
|
5
|
+
module IO
|
6
|
+
|
7
|
+
# Provides realtime MIDI input for MRI/YARV Ruby via the unimidi gem.
|
8
|
+
# @note This class is optional and only available if you require 'mtk/midi/unimidi_input'.
|
9
|
+
# It depends on the 'unimidi' gem.
|
10
|
+
class UniMIDIInput < MIDIInput
|
11
|
+
|
12
|
+
public_class_method :new
|
13
|
+
|
14
|
+
def self.devices
|
15
|
+
@devices ||= ::UniMIDI::Input.all.reject{|d| d.name.strip.empty? }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.devices_by_name
|
19
|
+
@devices_by_name ||= devices.each_with_object( Hash.new ){|device,hash| hash[device.name] = device }
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
attr_reader :device, :recording, :thread
|
24
|
+
|
25
|
+
def initialize(input_device, options={})
|
26
|
+
super
|
27
|
+
@open_time = Time.now.to_f
|
28
|
+
end
|
29
|
+
|
30
|
+
def record(options={})
|
31
|
+
@recording = [] unless options[:append] and @recording
|
32
|
+
monitor = options[:monitor]
|
33
|
+
|
34
|
+
stop
|
35
|
+
@thread = Thread.new do
|
36
|
+
@start_time = Time.now.to_f
|
37
|
+
loop do
|
38
|
+
@device.gets.each do |data|
|
39
|
+
puts data if monitor
|
40
|
+
record_raw_data data
|
41
|
+
end
|
42
|
+
sleep 0.001
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
time_limit = options[:time_limit]
|
47
|
+
if time_limit
|
48
|
+
puts "Blocking current thread for #{time_limit} seconds to record MIDI input."
|
49
|
+
@thread.join(time_limit)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def stop
|
54
|
+
Thread.kill @thread if @thread
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_timeline(options={})
|
58
|
+
return nil if not @recording
|
59
|
+
|
60
|
+
bpm = options.fetch :bmp, 120
|
61
|
+
beats_per_second = bpm.to_f/60
|
62
|
+
timeline = Timeline.new
|
63
|
+
note_ons = {}
|
64
|
+
start = nil
|
65
|
+
|
66
|
+
@recording.each do |message, time|
|
67
|
+
start ||= time
|
68
|
+
time -= start
|
69
|
+
time /= beats_per_second
|
70
|
+
|
71
|
+
if message.is_a? MTK::Events::Event
|
72
|
+
timeline.add time,message
|
73
|
+
else
|
74
|
+
case message.type
|
75
|
+
when :note_on
|
76
|
+
pitch = message.pitch
|
77
|
+
note_ons[pitch] = [message,time]
|
78
|
+
|
79
|
+
when :note_off
|
80
|
+
pitch = message.pitch
|
81
|
+
if note_ons.has_key? pitch
|
82
|
+
note_on, start_time = note_ons.delete(pitch)
|
83
|
+
duration = time - start_time
|
84
|
+
note = MTK::Events::Note.from_midi pitch, note_on.velocity, duration
|
85
|
+
timeline.add time,note
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
timeline.quantize! options[:quantize] if options.key? :quantize
|
92
|
+
timeline.shift_to! options[:shift_to] if options.key? :shift_to
|
93
|
+
|
94
|
+
timeline
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
#######################
|
99
|
+
private
|
100
|
+
|
101
|
+
def record_raw_data raw
|
102
|
+
status, data1, data2 = *raw[:data] # the 3 bytes of raw message data
|
103
|
+
message = (
|
104
|
+
case status & 0xF0
|
105
|
+
when 0x80 then OpenStruct.new({:type => :note_off, :pitch => data1, :velocity => data2})
|
106
|
+
when 0x90 then OpenStruct.new({:type => :note_on, :pitch => data1, :velocity => data2})
|
107
|
+
else MTK::Events::Parameter.from_midi(status,data1,data2)
|
108
|
+
end
|
109
|
+
)
|
110
|
+
time = raw[:timestamp]/1000 - (@start_time - @open_time)
|
111
|
+
@recording << [message, time]
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'unimidi'
|
2
|
+
|
3
|
+
module MTK
|
4
|
+
module IO
|
5
|
+
|
6
|
+
# Provides realtime MIDI output for "standard" Ruby (MRI) via the unimidi and gamelan gems.
|
7
|
+
# @note This class is optional and only available if you require 'mtk/midi/unimidi_output'.
|
8
|
+
# It depends on the 'unimidi' and 'gamelan' gems.
|
9
|
+
class UniMIDIOutput < MIDIOutput
|
10
|
+
|
11
|
+
public_class_method :new
|
12
|
+
|
13
|
+
def self.devices
|
14
|
+
@devices ||= ::UniMIDI::Output.all.reject{|d| d.name.strip.empty? }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.devices_by_name
|
18
|
+
@devices_by_name ||= devices.each_with_object( Hash.new ){|device,hash| hash[device.name] = device }
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
######################
|
23
|
+
protected
|
24
|
+
|
25
|
+
# (see MIDIOutput#note_on)
|
26
|
+
def note_on(pitch, velocity, channel)
|
27
|
+
@device.puts(0x90|channel, pitch, velocity)
|
28
|
+
end
|
29
|
+
|
30
|
+
# (see MIDIOutput#note_off)
|
31
|
+
def note_off(pitch, velocity, channel)
|
32
|
+
@device.puts(0x80|channel, pitch, velocity)
|
33
|
+
end
|
34
|
+
|
35
|
+
# (see MIDIOutput#control)
|
36
|
+
def control(number, midi_value, channel)
|
37
|
+
@device.puts(0xB0|channel, number, midi_value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# (see MIDIOutput#channel_pressure)
|
41
|
+
def channel_pressure(midi_value, channel)
|
42
|
+
@device.puts(0xD0|channel, midi_value, 0)
|
43
|
+
end
|
44
|
+
|
45
|
+
# (see MIDIOutput#poly_pressure)
|
46
|
+
def poly_pressure(pitch, midi_value, channel)
|
47
|
+
@device.puts(0xA0|channel, pitch, midi_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# (see MIDIOutput#bend)
|
51
|
+
def bend(midi_value, channel)
|
52
|
+
@device.puts(0xE0|channel, midi_value & 127, (midi_value >> 7) & 127)
|
53
|
+
end
|
54
|
+
|
55
|
+
# (see MIDIOutput#program)
|
56
|
+
def program(number, channel)
|
57
|
+
@device.puts(0xC0|channel, number, 0)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
#####################################################################
|
66
|
+
# MONKEY PATCHING for https://github.com/arirusso/ffi-coremidi/pull/2
|
67
|
+
# This can be removed once that pull request is released.
|
68
|
+
|
69
|
+
if RbConfig::CONFIG['host_os'] =~ /darwin/
|
70
|
+
# We're running on OS X
|
71
|
+
|
72
|
+
begin
|
73
|
+
ffi_coremidi_exists = !CoreMIDI::Map::CF.nil?
|
74
|
+
rescue NameError
|
75
|
+
ffi_coremidi_exists = false
|
76
|
+
end
|
77
|
+
|
78
|
+
if ffi_coremidi_exists
|
79
|
+
|
80
|
+
# @private
|
81
|
+
module CoreMIDI
|
82
|
+
|
83
|
+
# @private
|
84
|
+
class Device
|
85
|
+
def initialize(id, device_pointer, options = {})
|
86
|
+
include_if_offline = options[:include_offline] || false
|
87
|
+
@id = id
|
88
|
+
@resource = device_pointer
|
89
|
+
@entities = []
|
90
|
+
|
91
|
+
prop = Map::CF.CFStringCreateWithCString( nil, "name", 0 )
|
92
|
+
begin
|
93
|
+
name_ptr = FFI::MemoryPointer.new(:pointer)
|
94
|
+
Map::MIDIObjectGetStringProperty(@resource, prop, name_ptr)
|
95
|
+
name = name_ptr.read_pointer
|
96
|
+
len = Map::CF.CFStringGetMaximumSizeForEncoding(Map::CF.CFStringGetLength(name), :kCFStringEncodingUTF8)
|
97
|
+
bytes = FFI::MemoryPointer.new(len + 1)
|
98
|
+
raise RuntimeError.new("CFStringGetCString") unless Map::CF.CFStringGetCString(name, bytes, len, :kCFStringEncodingUTF8)
|
99
|
+
@name = bytes.read_string
|
100
|
+
ensure
|
101
|
+
Map::CF.CFRelease(name) unless name.nil? || name.null?
|
102
|
+
Map::CF.CFRelease(prop) unless prop.null?
|
103
|
+
end
|
104
|
+
populate_entities(:include_offline => include_if_offline)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
# @private
|
110
|
+
module Map
|
111
|
+
|
112
|
+
# @private
|
113
|
+
module CF
|
114
|
+
|
115
|
+
extend FFI::Library
|
116
|
+
ffi_lib '/System/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation'
|
117
|
+
|
118
|
+
typedef :pointer, :CFStringRef
|
119
|
+
typedef :long, :CFIndex
|
120
|
+
enum :CFStringEncoding, [ :kCFStringEncodingUTF8, 0x08000100 ]
|
121
|
+
|
122
|
+
# CFString* CFStringCreateWithCString( ?, CString, encoding)
|
123
|
+
attach_function :CFStringCreateWithCString, [:pointer, :string, :int], :pointer
|
124
|
+
# CString* CFStringGetCStringPtr(CFString*, encoding)
|
125
|
+
attach_function :CFStringGetCStringPtr, [:pointer, :int], :pointer
|
126
|
+
|
127
|
+
attach_function :CFStringGetLength, [ :CFStringRef ], :CFIndex
|
128
|
+
|
129
|
+
attach_function :CFStringGetMaximumSizeForEncoding, [ :CFIndex, :CFStringEncoding ], :long
|
130
|
+
|
131
|
+
attach_function :CFStringGetCString, [ :CFStringRef, :pointer, :CFIndex, :CFStringEncoding ], :bool
|
132
|
+
|
133
|
+
attach_function :CFRelease, [ :pointer ], :void
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rational'
|
2
|
+
|
3
|
+
module MTK
|
4
|
+
module Lang
|
5
|
+
|
6
|
+
# Defines duration constants using abbreviations for standard rhythm values ('w' for whole note, 'h' for half note, etc).
|
7
|
+
#
|
8
|
+
# In order to avoid conflict with pitch class 'e', the constant for eighth note is 'i'
|
9
|
+
#
|
10
|
+
# These can be thought of like constants, but they
|
11
|
+
# use lower-case names and therefore define them as "pseudo constant" methods.
|
12
|
+
# The methods are available either through the module (MTK::Core::Durations::e) or via mixin (include MTK::Core::Durations; q)
|
13
|
+
#
|
14
|
+
# These values assume the quarter note is one beat (1.0), so they work best with 4/4 and other */4 time signatures.
|
15
|
+
#
|
16
|
+
# @note Including this module defines a bunch of single-character variables, which may shadow existing variable names.
|
17
|
+
# Just be mindful of what is defined in this module when including it.
|
18
|
+
#
|
19
|
+
# @see Note
|
20
|
+
module Durations
|
21
|
+
extend MTK::Lang::PseudoConstants
|
22
|
+
|
23
|
+
# NOTE: the yard doc macros here only fill in [$2] with the actual value when generating docs under Ruby 1.9+
|
24
|
+
|
25
|
+
# whole note
|
26
|
+
# @macro [attach] durations.define_constant
|
27
|
+
# @attribute [r]
|
28
|
+
# @return [$2] number of beats for $1
|
29
|
+
define_constant 'w', MTK::Core::Duration[4]
|
30
|
+
|
31
|
+
# half note
|
32
|
+
define_constant 'h', MTK::Core::Duration[2]
|
33
|
+
|
34
|
+
# quarter note
|
35
|
+
define_constant 'q', MTK::Core::Duration[1]
|
36
|
+
|
37
|
+
# eight note
|
38
|
+
define_constant 'i', MTK::Core::Duration[Rational(1,2)]
|
39
|
+
|
40
|
+
# sixteenth note
|
41
|
+
define_constant 's', MTK::Core::Duration[Rational(1,4)]
|
42
|
+
|
43
|
+
# thirty-second note
|
44
|
+
define_constant 'r', MTK::Core::Duration[Rational(1,8)]
|
45
|
+
|
46
|
+
# sixty-fourth note
|
47
|
+
define_constant 'x', MTK::Core::Duration[Rational(1,16)]
|
48
|
+
|
49
|
+
# The values of all "psuedo constants" defined in this module
|
50
|
+
DURATIONS = [w, h, q, i, s, r, x].freeze
|
51
|
+
|
52
|
+
# The names of all "psuedo constants" defined in this module
|
53
|
+
DURATION_NAMES = MTK::Core::Duration::NAMES
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module MTK
|
2
|
+
module Lang
|
3
|
+
|
4
|
+
# Defines intensity constants using standard dynamic symbols.
|
5
|
+
#
|
6
|
+
# These can be thought of like constants, but in order to distinguish 'f' (forte) from the {PitchClass} 'F'
|
7
|
+
# it was necessary to use lower-case names and therefore define them as "pseudo constant" methods.
|
8
|
+
# The methods are available either through the module (MTK::Intensities::f) or via mixin (include MTK::Intensities; f)
|
9
|
+
#
|
10
|
+
# These values are intensities in the range 0.125 - 1.0 (in increments of 1/8), so they can be easily scaled (unlike MIDI velocities).
|
11
|
+
#
|
12
|
+
# It is also possible to retrieve values in increments of 1/24 by using the '+' and '-' suffix when looking
|
13
|
+
# up values via the {.[]} method.
|
14
|
+
#
|
15
|
+
# @note Including this module shadows Ruby's built-in p() method.
|
16
|
+
# If you include this module, you can access the built-in p() method via Kernel.p()
|
17
|
+
#
|
18
|
+
# @see Note
|
19
|
+
module Intensities
|
20
|
+
extend MTK::Lang::PseudoConstants
|
21
|
+
|
22
|
+
# NOTE: the yard doc macros here only fill in [$2] with the actual value when generating docs under Ruby 1.9+
|
23
|
+
|
24
|
+
# pianississimo
|
25
|
+
# @macro [attach] intensities.define_constant
|
26
|
+
# @attribute [r]
|
27
|
+
# @return [$2] intensity value for $1
|
28
|
+
define_constant 'ppp', MTK::Core::Intensity[0.125]
|
29
|
+
|
30
|
+
# pianissimo
|
31
|
+
define_constant 'pp', MTK::Core::Intensity[0.25]
|
32
|
+
|
33
|
+
# piano
|
34
|
+
# @note Including this module shadows Ruby's built-in p() method.
|
35
|
+
# If you include this module, you can access the built-in p() method via Kernel.p()
|
36
|
+
define_constant 'p', MTK::Core::Intensity[0.375]
|
37
|
+
|
38
|
+
# mezzo-piano
|
39
|
+
define_constant 'mp', MTK::Core::Intensity[0.5]
|
40
|
+
|
41
|
+
# mezzo-forte
|
42
|
+
define_constant 'mf', MTK::Core::Intensity[0.625]
|
43
|
+
|
44
|
+
# forte
|
45
|
+
define_constant 'o', MTK::Core::Intensity[0.75]
|
46
|
+
|
47
|
+
# fortissimo
|
48
|
+
define_constant 'ff', MTK::Core::Intensity[0.875]
|
49
|
+
|
50
|
+
# fortississimo
|
51
|
+
define_constant 'fff', MTK::Core::Intensity[1.0]
|
52
|
+
|
53
|
+
# The values of all "psuedo constants" defined in this module
|
54
|
+
INTENSITIES = [ppp, pp, p, mp, mf, o, ff, fff].freeze
|
55
|
+
|
56
|
+
# The names of all "psuedo constants" defined in this module
|
57
|
+
INTENSITY_NAMES = MTK::Core::Intensity::NAMES
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module MTK
|
2
|
+
module Lang
|
3
|
+
|
4
|
+
# Defines a constant for intervals up to an octave using diatonic naming conventions (see http://en.wikipedia.org/wiki/Interval_(music)#Main_intervals)
|
5
|
+
#
|
6
|
+
# Naming conventions
|
7
|
+
# P#: perfect interval
|
8
|
+
# M#: major interval
|
9
|
+
# m#: minor interval
|
10
|
+
# TT: tritone (AKA augmented 4th or diminished 5th)
|
11
|
+
#
|
12
|
+
# These can be thought of like constants, but in order to succinctly distinguish 'm2' (minor) from 'M2' (major),
|
13
|
+
# it was necessary to use lower-case names for some of the values and therefore define them as "pseudo constant" methods.
|
14
|
+
# The methods are available either through the module (MTK::Core::Intervals::m2) or via mixin (include MTK::Core::Intervals; m2)
|
15
|
+
module Intervals
|
16
|
+
extend MTK::Lang::PseudoConstants
|
17
|
+
|
18
|
+
# NOTE: the yard doc macros here only fill in [$2] with the actual value when generating docs under Ruby 1.9+
|
19
|
+
|
20
|
+
# perfect unison
|
21
|
+
# @macro [attach] interval.define_constant
|
22
|
+
# @attribute [r]
|
23
|
+
# @return [$2] number of semitones in the interval $1
|
24
|
+
define_constant 'P1', MTK::Core::Interval[0]
|
25
|
+
|
26
|
+
# minor second
|
27
|
+
# @macro [attach] interval.define_constant
|
28
|
+
# @attribute [r]
|
29
|
+
# @return [$2] number of semitones in the interval $1
|
30
|
+
define_constant 'm2', MTK::Core::Interval[1]
|
31
|
+
|
32
|
+
# major second
|
33
|
+
define_constant 'M2', MTK::Core::Interval[2]
|
34
|
+
|
35
|
+
# minor third
|
36
|
+
define_constant 'm3', MTK::Core::Interval[3]
|
37
|
+
|
38
|
+
# major third
|
39
|
+
define_constant 'M3', MTK::Core::Interval[4]
|
40
|
+
|
41
|
+
# pefect fourth
|
42
|
+
define_constant 'P4', MTK::Core::Interval[5]
|
43
|
+
|
44
|
+
# tritone (AKA augmented fourth or diminished fifth)
|
45
|
+
define_constant 'TT', MTK::Core::Interval[6]
|
46
|
+
|
47
|
+
# perfect fifth
|
48
|
+
define_constant 'P5', MTK::Core::Interval[7]
|
49
|
+
|
50
|
+
# minor sixth
|
51
|
+
define_constant 'm6', MTK::Core::Interval[8]
|
52
|
+
|
53
|
+
# major sixth
|
54
|
+
define_constant 'M6', MTK::Core::Interval[9]
|
55
|
+
|
56
|
+
# minor seventh
|
57
|
+
define_constant 'm7', MTK::Core::Interval[10]
|
58
|
+
|
59
|
+
# major seventh
|
60
|
+
define_constant 'M7', MTK::Core::Interval[11]
|
61
|
+
|
62
|
+
# pefect octave
|
63
|
+
define_constant 'P8', MTK::Core::Interval[12]
|
64
|
+
|
65
|
+
# The values of all "psuedo constants" defined in this module
|
66
|
+
INTERVALS = [P1, m2, M2, m3, M3, P4, TT, P5, m6, M6, m7, M7, P8].freeze
|
67
|
+
|
68
|
+
# The names of all "psuedo constants" defined in this module
|
69
|
+
INTERVAL_NAMES = MTK::Core::Interval::NAMES
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|