jmtk 0.0.3.3-java → 0.4-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.
Files changed (56) hide show
  1. checksums.yaml +15 -0
  2. data/DEVELOPMENT_NOTES.md +20 -0
  3. data/INTRO.md +63 -31
  4. data/README.md +9 -3
  5. data/Rakefile +42 -42
  6. data/bin/jmtk +75 -32
  7. data/bin/mtk +75 -32
  8. data/examples/drum_pattern.rb +2 -2
  9. data/examples/dynamic_pattern.rb +1 -1
  10. data/examples/helpers/output_selector.rb +71 -0
  11. data/examples/notation.rb +5 -1
  12. data/examples/tone_row_melody.rb +1 -1
  13. data/lib/mtk.rb +1 -0
  14. data/lib/mtk/core/duration.rb +18 -3
  15. data/lib/mtk/core/intensity.rb +5 -3
  16. data/lib/mtk/core/interval.rb +21 -14
  17. data/lib/mtk/core/pitch.rb +2 -0
  18. data/lib/mtk/core/pitch_class.rb +6 -3
  19. data/lib/mtk/events/event.rb +2 -1
  20. data/lib/mtk/events/note.rb +1 -1
  21. data/lib/mtk/events/parameter.rb +1 -0
  22. data/lib/mtk/events/rest.rb +85 -0
  23. data/lib/mtk/events/timeline.rb +6 -2
  24. data/lib/mtk/io/jsound_input.rb +9 -3
  25. data/lib/mtk/io/midi_file.rb +38 -2
  26. data/lib/mtk/io/midi_input.rb +1 -1
  27. data/lib/mtk/io/midi_output.rb +95 -4
  28. data/lib/mtk/io/unimidi_input.rb +7 -3
  29. data/lib/mtk/lang/durations.rb +31 -26
  30. data/lib/mtk/lang/intensities.rb +29 -30
  31. data/lib/mtk/lang/intervals.rb +108 -41
  32. data/lib/mtk/lang/mtk_grammar.citrus +14 -4
  33. data/lib/mtk/lang/parser.rb +10 -5
  34. data/lib/mtk/lang/pitch_classes.rb +45 -17
  35. data/lib/mtk/lang/pitches.rb +169 -32
  36. data/lib/mtk/lang/tutorial.rb +279 -0
  37. data/lib/mtk/lang/tutorial_lesson.rb +87 -0
  38. data/lib/mtk/sequencers/event_builder.rb +29 -8
  39. data/spec/mtk/core/duration_spec.rb +14 -1
  40. data/spec/mtk/core/intensity_spec.rb +1 -1
  41. data/spec/mtk/events/event_spec.rb +10 -16
  42. data/spec/mtk/events/note_spec.rb +3 -3
  43. data/spec/mtk/events/rest_spec.rb +184 -0
  44. data/spec/mtk/events/timeline_spec.rb +5 -1
  45. data/spec/mtk/io/midi_file_spec.rb +13 -2
  46. data/spec/mtk/io/midi_output_spec.rb +42 -9
  47. data/spec/mtk/lang/durations_spec.rb +5 -5
  48. data/spec/mtk/lang/intensities_spec.rb +5 -5
  49. data/spec/mtk/lang/intervals_spec.rb +139 -13
  50. data/spec/mtk/lang/parser_spec.rb +65 -25
  51. data/spec/mtk/lang/pitch_classes_spec.rb +0 -11
  52. data/spec/mtk/lang/pitches_spec.rb +0 -15
  53. data/spec/mtk/patterns/chain_spec.rb +7 -7
  54. data/spec/mtk/patterns/for_each_spec.rb +2 -2
  55. data/spec/mtk/sequencers/event_builder_spec.rb +49 -17
  56. metadata +12 -22
data/bin/mtk CHANGED
@@ -10,38 +10,38 @@ options = {}
10
10
 
11
11
  option_parser = OptionParser.new do |opts|
12
12
 
13
- opts.banner = "Usage: #{$0} [options]"
13
+ opts.banner = "\nMTK: Music Tool Kit for Ruby\n\nUsage: #{$0} [options]"
14
14
  opts.separator ''
15
15
  opts.separator 'Options:'
16
16
 
17
- opts.on('-c FILE', '--convert FILE', 'Convert a file containing MTK syntax to MIDI',
18
- 'if a --file is given, write the MIDI to a file',
19
- 'if an --output is given, play the MIDI',
17
+ opts.on('-c FILE', '--convert FILE', 'Convert file containing MTK syntax to MIDI',
18
+ 'if --file is given, write the MIDI to file',
19
+ 'if --output is given, play the MIDI',
20
20
  'otherwise print the MIDI') {|file| options[:convert] = file }
21
21
 
22
22
  opts.separator ''
23
23
 
24
- opts.on('-e [syntax]', '--eval [syntax]', 'Convert the given MTK syntax String to MIDI',
25
- 'or start an interactive interpreter when [syntax] is omitted',
26
- 'Behaves like --convert when a --file or --output is given') {|syntax| options[:eval] = syntax }
24
+ opts.on('-e [syntax]', '--eval [syntax]', 'Convert the given MTK syntax to MIDI or',
25
+ 'interactive interpreter when no [syntax]',
26
+ 'Behaves like --convert for --file/--output') {|syntax| options[:eval] = syntax }
27
27
 
28
28
  opts.separator ''
29
29
 
30
- opts.on('-f FILE', '--file FILE', 'Write the output of --convert, --eval, --input, or --watch to a file'
31
- ) {|file| options[:file] = file }
30
+ opts.on('-f FILE', '--file FILE', 'Write output of --convert, --eval, --input',
31
+ 'or --watch to a file') {|file| options[:file] = file }
32
32
 
33
33
  opts.separator ''
34
34
 
35
- opts.on('-h', '--help', 'Show this message') { puts opts; exit }
35
+ opts.on('-h', '--help', 'Show these usage instructions') { puts opts; exit }
36
36
 
37
37
  opts.separator ''
38
38
 
39
39
  opts.on('-i INPUT', '--input INPUT', 'Set MIDI input for recording',
40
- 'if no --file is specified, prints the recorded MIDI') {|input| options[:input] = input }
40
+ 'if no --file given, prints recorded MIDI') {|input| options[:input] = input }
41
41
 
42
42
  opts.separator ''
43
43
 
44
- opts.on('-l', '--list', 'List available MIDI devices for --input and --output') { options[:list] = true }
44
+ opts.on('-l', '--list', 'List MIDI devices for --input and --output') { options[:list] = true }
45
45
 
46
46
  opts.separator ''
47
47
 
@@ -53,17 +53,19 @@ option_parser = OptionParser.new do |opts|
53
53
 
54
54
  opts.separator ''
55
55
 
56
- opts.on('-p FILE', '--play FILE', 'Play or print the contents of a MIDI file',
57
- 'if no --output is specified, print the MIDI file') {|file| options[:play] = file }
56
+ opts.on('-p FILE', '--play FILE', 'Play or print a MIDI file',
57
+ 'if no --output given, print the MIDI') {|file| options[:play] = file }
58
58
 
59
59
  opts.separator ''
60
60
 
61
- #opts.on('-t', '--tutorial', 'Start an interactive tutorial for the MTK syntax') { options[:tutorial] = true }
62
- #
63
- #opts.separator ''
61
+ opts.on('-t [color]', '--tutorial [color]', 'Interactive tutorial for MTK syntax',
62
+ 'Text color can be set on/off') {|color| options[:tutorial] = true; options[:color] = color }
64
63
 
65
- opts.on('-w FILE', '--watch FILE', 'Watch an MTK syntax file for changes and automatically convert to MIDI',
66
- 'Behaves like --convert when a --file or --output is given') {|file| options[:watch] = file }
64
+ opts.separator ''
65
+
66
+ opts.on('-w FILE', '--watch FILE', 'Watch an MTK syntax file for changes and',
67
+ 'automatically convert to MIDI',
68
+ 'Behaves like --convert for --file/--output') {|file| options[:watch] = file }
67
69
 
68
70
  end
69
71
 
@@ -71,18 +73,16 @@ end
71
73
  #######################################################################
72
74
 
73
75
  puts option_parser and exit if ARGV.length == 0
74
- #p ARGV
75
- #p options
76
76
 
77
77
  ERROR_INVALID_COMMAND = 1
78
78
  ERROR_FILE_NOT_FOUND = 2
79
79
  ERROR_OUTPUT_NOT_FOUND = 3
80
80
  ERROR_INPUT_NOT_FOUND = 4
81
81
 
82
- # Immediately trying to play output while Ruby is still "warming up" can cause timing issues with
83
- # the first couple notes. So we play this "empty" Timeline containing a rest to address that issue.
82
+ # Empty timeline used to prime the realtime output
84
83
  WARMUP = MTK::Events::Timeline.from_h( {0 => MTK.Note(60,-1)} )
85
84
 
85
+
86
86
  #######################################################################
87
87
 
88
88
  begin
@@ -115,6 +115,9 @@ end
115
115
  def output(timelines, print_header='Timeline')
116
116
  timelines = [timelines] unless timelines.is_a? Array
117
117
  if @output
118
+ # Immediately trying to play output while Ruby is still "warming up" can cause timing issues with
119
+ # the first couple notes. So we play this "empty" Timeline containing a rest to address that issue.
120
+ # TODO? move this into the output class and do it automatically when playing for the first time? (warmup code is also in output_selector))
118
121
  @output.play WARMUP
119
122
  @output.play timelines.first # TODO: support multiple timelines
120
123
  elsif @file
@@ -151,6 +154,33 @@ def watch_file_updated?
151
154
  end
152
155
 
153
156
 
157
+ def set_tutorial_color(color_option)
158
+ if color_option
159
+ case color_option.strip.downcase
160
+ when /^(on|yes|true|y|t|color)$/ then $tutorial_color = true
161
+ when /^(off|no|false|n|f)$/ then $tutorial_color = false
162
+ else
163
+ STDERR.puts "Invalid tutorial color setting '#{color}'. Try 'on' or 'off'."
164
+ exit ERROR_INVALID_COMMAND
165
+ end
166
+ else
167
+ require 'rbconfig'
168
+ os = RbConfig::CONFIG['host_os'].downcase
169
+ if os =~ /win/ and os !~ /darwin/
170
+ puts
171
+ puts "Windows command line text color is off by default."
172
+ puts "If you want color, use ANSI terminal software like Cygwin or Ansicon and "
173
+ puts "run #{$0} with the color option \"--tutorial on\""
174
+ $tutorial_color = false
175
+ else
176
+ $tutorial_color = true
177
+ end
178
+ end
179
+ puts "Tutorial color is #{if $tutorial_color then 'enabled' else 'disabled' end}."
180
+ puts
181
+ end
182
+
183
+
154
184
  #######################################################################
155
185
 
156
186
  if options[:list]
@@ -162,18 +192,21 @@ if options[:list]
162
192
  puts
163
193
  puts (['OUTPUTS:']+output_names).join("\n * ")
164
194
  puts
165
- puts 'When specifying --input INPUT or --output OUTPUT, the first substring match will be used.'
166
- puts "For example: --output IAC will use 'Apple Inc. IAC Driver' if it's the first OUTPUT containing 'IAC'"
195
+ puts 'When specifying --input INPUT or --output OUTPUT, the first substring match'
196
+ puts '(case-insensitive) will be used. For example: "--output iac" will use'
197
+ puts '"Apple Inc. IAC Driver" if it\'s the first OUTPUT containing "IAC".'
167
198
  puts
168
199
  exit
169
200
  end
170
201
 
202
+
171
203
  @monitor = true if options[:monitor]
172
204
 
205
+
173
206
  if options[:input]
174
207
  setup_io
175
208
  input_name = options[:input]
176
- @input = MTK::IO::MIDIInput.find_by_name /#{input_name}/
209
+ @input = MTK::IO::MIDIInput.find_by_name /#{input_name}/i
177
210
  if @input
178
211
  puts "Using input '#{@input.name}'"
179
212
  else
@@ -182,10 +215,11 @@ if options[:input]
182
215
  end
183
216
  end
184
217
 
218
+
185
219
  if options[:output]
186
220
  setup_io
187
221
  output_name = options[:output]
188
- @output = MTK::IO::MIDIOutput.find_by_name /#{output_name}/
222
+ @output = MTK::IO::MIDIOutput.find_by_name /#{output_name}/i
189
223
  if @output
190
224
  puts "Using output '#{@output.name}'"
191
225
  else
@@ -194,8 +228,9 @@ if options[:output]
194
228
  end
195
229
  end
196
230
 
197
- file = options[:file]
198
- @file = file if file
231
+
232
+ @file = options[:file]
233
+
199
234
 
200
235
  if options[:play]
201
236
  filename = options[:play]
@@ -204,6 +239,7 @@ if options[:play]
204
239
  output(timelines, "Timeline for #{filename}")
205
240
  end
206
241
 
242
+
207
243
  if options.has_key? :eval
208
244
  mtk_syntax = options[:eval]
209
245
  if mtk_syntax.nil?
@@ -221,12 +257,14 @@ if options.has_key? :eval
221
257
  end
222
258
  end
223
259
 
260
+
224
261
  if options[:convert]
225
262
  mtk_syntax_file = options[:convert]
226
263
  mtk_syntax = IO.read(mtk_syntax_file)
227
264
  convert(mtk_syntax)
228
265
  end
229
266
 
267
+
230
268
  if options[:watch]
231
269
  @watch_file = options[:watch]
232
270
  puts "Watching #{@watch_file}. Press Ctrl+C to exit."
@@ -243,8 +281,13 @@ if options[:watch]
243
281
  end
244
282
  end
245
283
 
246
- #if options.has_key? :tutorial
247
- # puts "TODO: tutorial"
248
- #end
284
+
285
+ if options.has_key? :tutorial
286
+ set_tutorial_color(options[:color])
287
+ require 'mtk/lang/tutorial'
288
+ tutorial = MTK::Lang::Tutorial.new
289
+ tutorial.run(@output)
290
+ end
291
+
249
292
 
250
293
  record if @input
@@ -9,8 +9,8 @@ file = ARGV[0] || "MTK-#{File.basename(__FILE__,'.rb')}.mid"
9
9
  _ = nil # defines _ as a rest
10
10
 
11
11
  pattern = {# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
12
- C2 => [fff, _, _, _, mf, _, _, _, o, _, _, _, mp, _, _, _], # kick
13
- Db2 => [ _, _, o, _, _, _, mp, _, _, _, o, _, _, _, mf, _], # rim shot
12
+ C2 => [fff, _, _, _, mf, _, _, _, f, _, _, _, mp, _, _, _], # kick
13
+ Db2 => [ _, _, f, _, _, _, mp, _, _, _, f, _, _, _, mf, _], # rim shot
14
14
  D2 => [ _, mp, _, mp, _, mp, _, mf, _, mp, _, mp, _, pp, _, mf] # snare
15
15
  }
16
16
 
@@ -29,7 +29,7 @@ end
29
29
  pitches = Patterns.Function( interval_generator, max_elements: 24 )
30
30
 
31
31
  # we'll also use a weighted choice to generate the intensities
32
- intensities = Patterns.Choice( mp,mf,o,ff,fff, weights: [1,2,3,2,1], max_cycles: 24 )
32
+ intensities = Patterns.Choice( mp,mf,f,ff,fff, weights: [1,2,3,2,1], max_cycles: 24 )
33
33
 
34
34
  sequencer = Sequencers.StepSequencer( pitches,intensities, step_size: 0.5, max_interval: 17 )
35
35
 
@@ -0,0 +1,71 @@
1
+ require 'mtk/io/midi_output'
2
+
3
+ # Assists with selecting an output.
4
+ class OutputSelector
5
+
6
+ # Empty timeline used to prime the realtime output
7
+ WARMUP = MTK::Events::Timeline.from_h( {0 => MTK.Note(60,-1)} )
8
+
9
+ class << self
10
+
11
+ def output
12
+ MTK::IO::MIDIOutput
13
+ end
14
+
15
+ # Look for an output by name using case insensitive matching,
16
+ # treating underscore like either an underscore or whitespace
17
+ def search output_name_pattern
18
+ output.find_by_name(/#{output_name_pattern.to_s.sub '_','(_|\\s+)'}/i)
19
+ end
20
+
21
+ # Command line interface to list output choices and select an output.
22
+ def prompt_for_output
23
+ devices_by_name = output.devices_by_name
24
+ names_by_number = {}
25
+
26
+ puts "Available MIDI outputs:"
27
+ devices_by_name.keys.each_with_index do |name,index|
28
+ number = index+1
29
+ names_by_number[number] = name
30
+ puts " #{number} => #{name}"
31
+ end
32
+
33
+ print "Enter the number of the output to test: "
34
+ device = nil
35
+ loop do
36
+ begin
37
+ # NOTE: invalid input will turn into 0, but that's ok because we index from 1 so it will be caught as invalid
38
+ number = STDIN.gets.to_i
39
+ name = names_by_number[number]
40
+ device = devices_by_name[name]
41
+ return output.open(device) if device
42
+ rescue
43
+ if $DEBUG
44
+ puts $!
45
+ puts $!.backtrace
46
+ end
47
+ # keep looping
48
+ end
49
+ print "Invalid input. Enter a number listed above: "
50
+ end
51
+ end
52
+
53
+
54
+ def ensure_output name=nil
55
+ output = nil
56
+ if name
57
+ output = search name
58
+ puts "Output '#{name}' not found." unless output
59
+ end
60
+ output ||= prompt_for_output
61
+
62
+ # Immediately trying to play output while Ruby is still "warming up" can cause timing issues with
63
+ # the first couple notes. So we play this "empty" Timeline containing a rest to address that issue.
64
+ output.play WARMUP
65
+
66
+ output
67
+ end
68
+
69
+ end
70
+ end
71
+
@@ -1,3 +1,7 @@
1
+ # NOTE: experimental example!
2
+ # This requires Lilypond to be installed, see http://lilypond.org/
3
+ # The lilypond command must be on your PATH or specificed via the LILYPOND_PATH environment variable.
4
+
1
5
  require 'mtk'
2
6
  require 'mtk/io/notation'
3
7
  include MTK
@@ -13,7 +17,7 @@ arg_error "MTK syntax string not provided" unless syntax
13
17
 
14
18
 
15
19
  file = ARGV[1]
16
- arg_error "The output_file must end in '.png', '.pdf', or '.ps'" unless file
20
+ arg_error "The output_file must end in '.png', '.pdf', or '.ps'" unless file =~ /\.(png|pdf|ps)$/
17
21
 
18
22
 
19
23
  sequencer = MTK::Lang::Parser.parse(syntax)
@@ -12,7 +12,7 @@ file = ARGV[0] || 'MTK-tone_row_melody.mid'
12
12
 
13
13
  row = PitchClassSet Db, G, Ab, F, Eb, E, D, C, B, Gb, A, Bb
14
14
  pitch_pattern = Patterns.Cycle *row
15
- rhythm_pattern = Patterns.Choice s, i, i+s, q # choose between sixteenth, eighth, dotted eighth, and quarter
15
+ rhythm_pattern = Patterns.Choice s, e, e+s, q # choose between sixteenth, eighth, dotted eighth, and quarter
16
16
 
17
17
  chain = Patterns.Chain pitch_pattern, rhythm_pattern, min_elements: 36, max_elements: 36
18
18
 
data/lib/mtk.rb CHANGED
@@ -56,6 +56,7 @@ require 'mtk/groups/chord'
56
56
 
57
57
  require 'mtk/events/event'
58
58
  require 'mtk/events/note'
59
+ require 'mtk/events/rest'
59
60
  require 'mtk/events/parameter'
60
61
  require 'mtk/events/timeline'
61
62
 
@@ -3,18 +3,20 @@ module MTK
3
3
 
4
4
  # A measure of time in musical beats.
5
5
  # May be negative to indicate a rest, which uses the absolute value for the effective duration.
6
+ #
7
+ # @see Lang::Durations
6
8
  class Duration
7
9
 
8
10
  include Comparable
9
11
 
10
12
  # The names of the base durations. See {MTK::Lang::Durations} for more info.
11
- NAMES = %w[w h q i s r x].freeze
13
+ NAMES = %w[w h q e s r x].freeze
12
14
 
13
15
  VALUES_BY_NAME = {
14
16
  'w' => 4,
15
17
  'h' => 2,
16
18
  'q' => 1,
17
- 'i' => Rational(1,2),
19
+ 'e' => Rational(1,2),
18
20
  's' => Rational(1,4),
19
21
  'r' => Rational(1,8),
20
22
  'x' => Rational(1,16)
@@ -55,7 +57,7 @@ module MTK
55
57
  # @example lookup the value of 3/4w, which three-quarters of a whole note (3 beats):
56
58
  # MTK::Core::Duration.from_s('3/4w')
57
59
  def self.from_s(s)
58
- if s =~ /^(-)?(\d+([\.\/]\d+)?)?([whqisrx])((\.|t)*)$/i
60
+ if s =~ /^(-)?(\d+([\.\/]\d+)?)?([whqesrx])((\.|t)*)$/i
59
61
  name = $4.downcase
60
62
  modifier = $5.downcase
61
63
  modifier << $1 if $1 # negation
@@ -95,6 +97,7 @@ module MTK
95
97
  # The magnitude (absolute value) of the duration.
96
98
  # This is the actual duration for rests.
97
99
  # @see #rest?
100
+ # @see #abs
98
101
  def length
99
102
  @value < 0 ? -@value : @value
100
103
  end
@@ -106,6 +109,18 @@ module MTK
106
109
  @value < 0
107
110
  end
108
111
 
112
+ # Force resets to be non-rests, otherwise don't change the duration.
113
+ # @see #-@
114
+ # @see #length
115
+ # @see #rest?
116
+ def abs
117
+ if @value < 0
118
+ -self
119
+ else
120
+ self
121
+ end
122
+ end
123
+
109
124
  # The number of beats as a floating point number
110
125
  def to_f
111
126
  @value.to_f
@@ -2,12 +2,14 @@ module MTK
2
2
  module Core
3
3
 
4
4
  # A measure of intensity, using an underlying value in the range 0.0-1.0
5
+ #
6
+ # @see Lang::Intensities
5
7
  class Intensity
6
8
 
7
9
  include Comparable
8
10
 
9
- # The names of the base intensities. See {}MTK::Lang::Intensities} for more info.
10
- NAMES = %w[ppp pp p mp mf o ff fff].freeze
11
+ # The names of the base intensities. See {MTK::Lang::Intensities} for more info.
12
+ NAMES = %w[ppp pp p mp mf f ff fff].freeze
11
13
 
12
14
  VALUES_BY_NAME = {
13
15
  'ppp' => 0.125,
@@ -15,7 +17,7 @@ module MTK
15
17
  'p' => 0.375,
16
18
  'mp' => 0.5,
17
19
  'mf' => 0.625,
18
- 'o' => 0.75,
20
+ 'f' => 0.75,
19
21
  'ff' => 0.875,
20
22
  'fff' => 1.0
21
23
  }
@@ -2,29 +2,35 @@ module MTK
2
2
  module Core
3
3
 
4
4
  # A measure of intensity, using an underlying value in the range 0.0-1.0
5
+ #
6
+ # @see Lang::Intervals
5
7
  class Interval
6
8
 
7
9
  include Comparable
8
10
 
9
11
  # The preferred names of all pre-defined intervals
12
+ # @see ALL_NAMES
10
13
  NAMES = %w[P1 m2 M2 m3 M3 P4 TT P5 m6 M6 m7 M7 P8].freeze
11
14
 
12
15
  # All valid names of pre-defined intervals, indexed by their value.
16
+ # @see ALL_NAMES
17
+ # @see NAMES
18
+ # @see http://en.wikipedia.org/wiki/Interval_(music)#Main_intervals
13
19
  NAMES_BY_VALUE =
14
- [ # names # value # description
15
- %w( P1 p1 ), # 0 # unison
16
- %w( m2 min2 ), # 1 # minor second
17
- %w( M2 maj2 ), # 2 # major second
18
- %w( m3 min3 ), # 3 # minor third
19
- %w( M3 maj3 ), # 4 # major third
20
- %w( P4 p4 ), # 5 # perfect fourth
21
- %w( TT tt ), # 6 # tritone (AKA augmented fourth, diminished fifth)
22
- %w( P5 p5 ), # 7 # perfect fifth
23
- %w( m6 min6 ), # 8 # minor sixth
24
- %w( M6 maj6 ), # 9 # major sixth
25
- %w( m7 min7 ), # 10 # minor seventh
26
- %w( M7 maj7 ), # 11 # major seventh
27
- %w( P8 p8 ) # 12 # octave
20
+ [ # names # value # description # enharmonic equivalents
21
+ %w( P1 d2 ), # 0 # unison # diminished second
22
+ %w( m2 a1 ), # 1 # minor second # augmented unison
23
+ %w( M2 d3 ), # 2 # major second # diminished third
24
+ %w( m3 a2 ), # 3 # minor third # augmented second
25
+ %w( M3 d4 ), # 4 # major third # diminished fourth
26
+ %w( P4 a3 ), # 5 # perfect fourth # augmented third
27
+ %w( TT a4 d5 ),# 6 # tritone # augmented fourth, diminished fifth
28
+ %w( P5 d6 ), # 7 # perfect fifth # diminished sixth
29
+ %w( m6 a5 ), # 8 # minor sixth # augmented fifth
30
+ %w( M6 d7 ), # 9 # major sixth # diminished seventh
31
+ %w( m7 a6 ), # 10 # minor seventh # augmented sixth
32
+ %w( M7 d8 ), # 11 # major seventh # diminished octave
33
+ %w( P8 a7 ) # 12 # octave # augmented seventh
28
34
  ].freeze
29
35
 
30
36
  # A mapping from intervals names to their value
@@ -35,6 +41,7 @@ module MTK
35
41
  ].freeze
36
42
 
37
43
  # All valid interval names
44
+ # @see NAMES_BY_VALUE
38
45
  ALL_NAMES = NAMES_BY_VALUE.flatten.freeze
39
46
 
40
47