coltrane 2.2.1 → 3.0.0.pre

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -1
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile.lock +25 -2
  5. data/README.md +3 -0
  6. data/bin/console +6 -2
  7. data/coltrane.gemspec +2 -1
  8. data/exe/coltrane +14 -224
  9. data/lib/coltrane.rb +3 -50
  10. data/lib/coltrane/commands.rb +14 -0
  11. data/lib/coltrane/commands/chords.rb +77 -0
  12. data/lib/coltrane/commands/command.rb +45 -0
  13. data/lib/coltrane/commands/common_chords.rb +33 -0
  14. data/lib/coltrane/commands/errors.rb +44 -0
  15. data/lib/coltrane/commands/find_progression.rb +28 -0
  16. data/lib/coltrane/commands/find_scale.rb +39 -0
  17. data/lib/coltrane/commands/notes.rb +44 -0
  18. data/lib/coltrane/commands/progression.rb +27 -0
  19. data/lib/{cli → coltrane/commands}/representation.rb +0 -0
  20. data/lib/coltrane/commands/scale.rb +46 -0
  21. data/lib/coltrane/renderers.rb +6 -0
  22. data/lib/coltrane/renderers/renderer.rb +42 -0
  23. data/lib/coltrane/renderers/text_renderer.rb +23 -0
  24. data/lib/coltrane/renderers/text_renderer/array_drawer.rb +45 -0
  25. data/lib/coltrane/renderers/text_renderer/base_drawer.rb +20 -0
  26. data/lib/coltrane/renderers/text_renderer/hash_drawer.rb +16 -0
  27. data/lib/coltrane/renderers/text_renderer/representation_guitar_chord_drawer.rb +95 -0
  28. data/lib/coltrane/renderers/text_renderer/representation_guitar_note_set_drawer.rb +76 -0
  29. data/lib/coltrane/renderers/text_renderer/representation_piano_note_set_drawer.rb +49 -0
  30. data/lib/coltrane/renderers/text_renderer/theory_chord_drawer.rb +14 -0
  31. data/lib/coltrane/renderers/text_renderer/theory_note_set_drawer.rb +17 -0
  32. data/lib/coltrane/renderers/text_renderer/theory_progression_drawer.rb +13 -0
  33. data/lib/coltrane/renderers/text_renderer/theory_progression_set_drawer.rb +22 -0
  34. data/lib/coltrane/renderers/text_renderer/theory_scale_drawer.rb +13 -0
  35. data/lib/coltrane/renderers/text_renderer/theory_scale_set_drawer.rb +27 -0
  36. data/lib/coltrane/representation.rb +12 -0
  37. data/lib/coltrane/representation/guitar.rb +34 -0
  38. data/lib/coltrane/representation/guitar/chord.rb +180 -0
  39. data/lib/coltrane/representation/guitar/note.rb +26 -0
  40. data/lib/coltrane/representation/guitar/note_set.rb +35 -0
  41. data/lib/coltrane/representation/guitar/string.rb +31 -0
  42. data/lib/coltrane/representation/guitar_like_instruments.rb +21 -0
  43. data/lib/coltrane/representation/piano.rb +36 -0
  44. data/lib/coltrane/representation/piano/note_set.rb +22 -0
  45. data/lib/{coltrane_synth.rb → coltrane/synth.rb.rb} +0 -0
  46. data/lib/{coltrane_synth → coltrane/synth}/base.rb +0 -0
  47. data/lib/{coltrane_synth → coltrane/synth}/synth.rb +0 -0
  48. data/lib/coltrane/theory.rb +54 -0
  49. data/lib/coltrane/theory/cadence.rb +9 -0
  50. data/lib/coltrane/{changes.rb → theory/changes.rb} +0 -0
  51. data/lib/coltrane/theory/chord.rb +101 -0
  52. data/lib/coltrane/theory/chord_quality.rb +113 -0
  53. data/lib/coltrane/theory/chord_substitutions.rb +11 -0
  54. data/lib/coltrane/theory/circle_of_fifths.rb +33 -0
  55. data/lib/coltrane/theory/classic_scales.rb +113 -0
  56. data/lib/coltrane/theory/diatonic_scale.rb +38 -0
  57. data/lib/coltrane/theory/errors.rb +97 -0
  58. data/lib/coltrane/theory/frequency.rb +52 -0
  59. data/lib/coltrane/theory/frequency_interval.rb +83 -0
  60. data/lib/coltrane/theory/interval.rb +209 -0
  61. data/lib/coltrane/theory/interval_class.rb +212 -0
  62. data/lib/coltrane/theory/interval_sequence.rb +157 -0
  63. data/lib/coltrane/theory/key.rb +18 -0
  64. data/lib/coltrane/{mode.rb → theory/mode.rb} +0 -0
  65. data/lib/coltrane/theory/notable_progressions.rb +30 -0
  66. data/lib/coltrane/theory/note.rb +104 -0
  67. data/lib/coltrane/theory/note_set.rb +101 -0
  68. data/lib/coltrane/theory/pitch.rb +94 -0
  69. data/lib/coltrane/theory/pitch_class.rb +154 -0
  70. data/lib/coltrane/theory/progression.rb +81 -0
  71. data/lib/coltrane/theory/progression_set.rb +18 -0
  72. data/lib/coltrane/{qualities.rb → theory/qualities.rb} +0 -0
  73. data/lib/coltrane/theory/roman_chord.rb +114 -0
  74. data/lib/coltrane/theory/scale.rb +161 -0
  75. data/lib/coltrane/theory/scale_search_result.rb +6 -0
  76. data/lib/coltrane/theory/scale_set.rb +40 -0
  77. data/lib/coltrane/theory/voicing.rb +41 -0
  78. data/lib/coltrane/version.rb +1 -1
  79. metadata +88 -63
  80. data/bin/rails +0 -17
  81. data/data/qualities.yml +0 -83
  82. data/db/cache.sqlite3 +0 -0
  83. data/db/cache_test.sqlite3 +0 -0
  84. data/db/config.yml +0 -11
  85. data/lib/cli.rb +0 -24
  86. data/lib/cli/bass_guitar.rb +0 -12
  87. data/lib/cli/chord.rb +0 -39
  88. data/lib/cli/config.rb +0 -39
  89. data/lib/cli/errors.rb +0 -46
  90. data/lib/cli/guitar.rb +0 -67
  91. data/lib/cli/guitar_chords.rb +0 -122
  92. data/lib/cli/notes.rb +0 -20
  93. data/lib/cli/piano.rb +0 -57
  94. data/lib/cli/scale.rb +0 -53
  95. data/lib/cli/text.rb +0 -16
  96. data/lib/cli/ukulele.rb +0 -14
  97. data/lib/coltrane/cache.rb +0 -43
  98. data/lib/coltrane/cadence.rb +0 -7
  99. data/lib/coltrane/chord.rb +0 -89
  100. data/lib/coltrane/chord_quality.rb +0 -111
  101. data/lib/coltrane/chord_substitutions.rb +0 -9
  102. data/lib/coltrane/circle_of_fifths.rb +0 -31
  103. data/lib/coltrane/classic_scales.rb +0 -94
  104. data/lib/coltrane/diatonic_scale.rb +0 -36
  105. data/lib/coltrane/errors.rb +0 -95
  106. data/lib/coltrane/frequency.rb +0 -50
  107. data/lib/coltrane/frequency_interval.rb +0 -81
  108. data/lib/coltrane/interval.rb +0 -208
  109. data/lib/coltrane/interval_class.rb +0 -210
  110. data/lib/coltrane/interval_sequence.rb +0 -155
  111. data/lib/coltrane/key.rb +0 -16
  112. data/lib/coltrane/notable_progressions.rb +0 -28
  113. data/lib/coltrane/note.rb +0 -98
  114. data/lib/coltrane/note_set.rb +0 -89
  115. data/lib/coltrane/pitch.rb +0 -92
  116. data/lib/coltrane/pitch_class.rb +0 -148
  117. data/lib/coltrane/progression.rb +0 -74
  118. data/lib/coltrane/roman_chord.rb +0 -112
  119. data/lib/coltrane/scale.rb +0 -154
  120. data/lib/coltrane/unordered_interval_class.rb +0 -7
  121. data/lib/coltrane/voicing.rb +0 -39
  122. data/lib/coltrane_game/question.rb +0 -7
  123. data/lib/coltrane_instruments.rb +0 -7
  124. data/lib/coltrane_instruments/guitar.rb +0 -10
  125. data/lib/coltrane_instruments/guitar/base.rb +0 -29
  126. data/lib/coltrane_instruments/guitar/chord.rb +0 -170
  127. data/lib/coltrane_instruments/guitar/note.rb +0 -24
  128. data/lib/coltrane_instruments/guitar/string.rb +0 -29
  129. data/lib/os.rb +0 -21
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Theory
5
+ #
6
+ # Pitch classes, and by classes here we don't mean in the sense of a ruby class
7
+ # are all the classes of pitches (frequencies) that are in a whole number of
8
+ # octaves apart.
9
+ #
10
+ # For example, C1, C2, C3 are all pitches from the C pitch class. Take a look into
11
+ # Notes description if you somehow feel this is confuse and that it could just be
12
+ # called as notes instead.
13
+ #
14
+ class PitchClass
15
+ attr_reader :integer
16
+ include Comparable
17
+
18
+ NOTATION = %w[C C# D D# E F F# G G# A A# B].freeze
19
+
20
+ def self.all_letters
21
+ %w[C D E F G A B]
22
+ end
23
+
24
+ def self.all
25
+ NOTATION.map { |n| new(n) }
26
+ end
27
+
28
+ def initialize(arg = nil, frequency: nil)
29
+ @integer = case arg
30
+ when String then NOTATION.index(arg)
31
+ when Frequency then frequency_to_integer(Frequency.new(arg))
32
+ when Numeric then (arg % 12)
33
+ when nil then frequency_to_integer(Frequency.new(frequency))
34
+ when PitchClass then arg.integer
35
+ else raise(WrongArgumentsError)
36
+ end
37
+ end
38
+
39
+ def self.[](arg, frequency: nil)
40
+ new(arg, frequency: nil)
41
+ end
42
+
43
+ def ==(other)
44
+ integer == other.integer
45
+ end
46
+
47
+ alias eql? ==
48
+ alias hash integer
49
+
50
+ def true_notation
51
+ NOTATION[integer]
52
+ end
53
+
54
+ def letter
55
+ name[0]
56
+ end
57
+
58
+ def ascending_interval_to(other)
59
+ Interval.new(self, (other.is_a?(PitchClass) ? other : Note.new(other)))
60
+ end
61
+
62
+ alias interval_to ascending_interval_to
63
+
64
+ def descending_interval_to(other)
65
+ Interval.new(
66
+ self,
67
+ (other.is_a?(PitchClass) ? other : Note.new(other)),
68
+ ascending: false
69
+ )
70
+ end
71
+
72
+ alias name true_notation
73
+
74
+ def pretty_name
75
+ name.tr('b', "\u266D").tr('#', "\u266F")
76
+ end
77
+
78
+ def accidental?
79
+ notation.match? /#|b/
80
+ end
81
+
82
+ def sharp?
83
+ notation.match? /#/
84
+ end
85
+
86
+ def flat?
87
+ notation.match? /b/
88
+ end
89
+
90
+ alias notation true_notation
91
+ alias to_s true_notation
92
+
93
+ def +(other)
94
+ case other
95
+ when Interval then self.class[integer + other.semitones]
96
+ when Integer then self.class[integer + other]
97
+ when PitchClass then self.class[integer + other.integer]
98
+ when Frequency then self.class.new(frequency: frequency + other)
99
+ end
100
+ end
101
+
102
+ def -(other)
103
+ case other
104
+ when Interval then self.class[integer - other.semitones]
105
+ when Integer then self.class[integer - other]
106
+ when PitchClass then Interval.new(self, other)
107
+ when Frequency then self.class.new(frequency: frequency - other)
108
+ end
109
+ end
110
+
111
+ def pitch_class
112
+ self
113
+ end
114
+
115
+ def <=>(other)
116
+ integer <=> other.integer
117
+ end
118
+
119
+ def fundamental_frequency
120
+ @fundamental_frequency ||=
121
+ Frequency[
122
+ Theory.base_tuning *
123
+ (2**((integer - Theory::BASE_PITCH_INTEGER.to_f) / 12))
124
+ ]
125
+ end
126
+
127
+ alias frequency fundamental_frequency
128
+
129
+ def self.size
130
+ NOTATION.size
131
+ end
132
+
133
+ def size
134
+ self.class.size
135
+ end
136
+
137
+ def enharmonic?(other)
138
+ case other
139
+ when String then integer == Note[other].integer
140
+ when Note then integer == other.integer
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def frequency_to_integer(f)
147
+ begin
148
+ (::BASE_PITCH_INTEGER +
149
+ size * Math.log(f.to_f / Theory.base_tuning.to_f, 2)) % size
150
+ end.round
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Theory
5
+ # Allows the creation of chord progressions using standard notations.
6
+ # Ex: Progression.new('I-IV-V', key: 'Am')
7
+ class Progression
8
+ extend NotableProgressions
9
+ include Changes
10
+ attr_reader :scale, :chords, :notation
11
+
12
+ def self.find(*chords)
13
+ chords
14
+ .yield_self { |chords|
15
+ next chords if chords[0].is_a?(Chord)
16
+ chords.map {|c| Chord.new(name: c) }
17
+ }
18
+ .yield_self { |chords|
19
+ NoteSet[*chords.map(&:root_note)]
20
+ .yield_self { |root_notes|
21
+ Scale.having_notes(*root_notes).strict_scales
22
+ }
23
+ .reduce([]) { |memo, scale|
24
+ memo + [Progression.new(chords: chords, scale: scale)]
25
+ }
26
+ }
27
+ .yield_self { |progressions| ProgressionSet.new(*progressions) }
28
+ end
29
+
30
+ def initialize(notation = nil, chords: nil, roman_chords: nil, key: nil, scale: nil)
31
+ if notation.nil? && chords.nil? && roman_chords.nil? || key.nil? && scale.nil?
32
+ raise WrongKeywordsError,
33
+ '[chords:, [scale: || key:]] '\
34
+ '[roman_chords:, [scale: || key:]] '\
35
+ '[notation:, [scale: || key:]] '\
36
+ end
37
+
38
+ @scale = scale || Key[key]
39
+ @chords =
40
+ if !chords.nil?
41
+ chords
42
+ elsif !roman_chords.nil?
43
+ roman_chords.map(&:chord)
44
+ elsif !notation.nil?
45
+ @notation = notation
46
+ notation.split('-').map { |c| RomanChord.new(c, scale: @scale).chord }
47
+ end
48
+ end
49
+
50
+ def interval_sequence
51
+ @interval_sequence ||= IntervalSequence(notes: @root_notes)
52
+ end
53
+
54
+ def root_notes
55
+ @root_notes ||= @chords.map(&:root_note)
56
+ end
57
+
58
+ def roman_chords
59
+ @roman_chords ||= chords.map do |c|
60
+ RomanChord.new(chord: c, scale: scale)
61
+ end
62
+ end
63
+
64
+ def notation
65
+ roman_chords.map(&:notation).join('-')
66
+ end
67
+
68
+ def notes
69
+ NoteSet[*chords.map(&:notes).map(&:notes).flatten]
70
+ end
71
+
72
+ def notes_out
73
+ notes - scale.notes
74
+ end
75
+
76
+ def notes_out_size
77
+ notes_out.size
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Theory
5
+ class ProgressionSet
6
+ extend Forwardable
7
+ include Enumerable
8
+
9
+ def_delegators :progressions, :each
10
+
11
+ attr_accessor :progressions
12
+
13
+ def initialize(*progressions)
14
+ @progressions = progressions.sort_by(&:notes_out_size)
15
+ end
16
+ end
17
+ end
18
+ end
File without changes
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Theory
5
+ # This class deals with chords in roman notation. Ex: IVº.
6
+ class RomanChord
7
+ DIGITS = %w[I II III IV V VI VII].freeze
8
+ NOTATION_REGEX = /(b?[ivIV]*)(.*)/
9
+
10
+ NOTATION_SUBSTITUTIONS = [
11
+ %w[º dim],
12
+ %w[o dim],
13
+ %w[ø m7b5]
14
+ ].freeze
15
+
16
+ def initialize(notation = nil, chord: nil, key: nil, scale: nil)
17
+ if notation.nil? && chord.nil? || key.nil? && scale.nil?
18
+ raise WrongKeywordsError,
19
+ '[notation, [scale: || key:]] '\
20
+ '[chord:, [scale: || key:]] '\
21
+ end
22
+ @scale = scale || Key[key]
23
+ if notation
24
+ @notation = notation
25
+ elsif chord
26
+ @chord = chord.is_a?(String) ? Chord.new(name: chord) : chord
27
+ end
28
+ end
29
+
30
+ def degree
31
+ return @scale.degree_of_note(root_note) unless @chord.nil?
32
+ d = regexed_notation[:degree]
33
+ @flats = d.count('b')
34
+ d = d.delete('b')
35
+ @degree ||= DIGITS.index(d.upcase) + 1
36
+ end
37
+
38
+ def roman_numeral
39
+ r = DIGITS[degree]
40
+ minor? ? r.downcase : r
41
+ end
42
+
43
+ def upcase?
44
+ !!(regexed_notation[:degree][0].match /[[:upper:]]/)
45
+ end
46
+
47
+ def chord
48
+ @chord ||= Chord.new root_note: root_note,
49
+ quality: quality
50
+ end
51
+
52
+ def minor?
53
+ quality.has_minor_third?
54
+ end
55
+
56
+ def major?
57
+ quality.has_major_third?
58
+ end
59
+
60
+ def quality_name
61
+ return @chord.quality.name unless @chord.nil?
62
+ q = normalize_quality_name(regexed_notation[:quality])
63
+ minor = 'm' if (!q.match? /dim|m7b5/) && !upcase?
64
+ q = [minor, q].join
65
+ q.empty? ? 'M' : q
66
+ end
67
+
68
+ def quality
69
+ return @chord.quality unless @chord.nil?
70
+ ChordQuality.new(name: quality_name) if quality_name
71
+ end
72
+
73
+ def root_note
74
+ return @chord.root_note unless @chord.nil?
75
+ @scale[degree] - @flats
76
+ end
77
+
78
+ def notation
79
+ q = case quality_name
80
+ when 'm', 'M' then ''
81
+ when 'm7', 'M' then '7'
82
+ else quality_name
83
+ end
84
+
85
+ @notation ||= [
86
+ roman_numeral,
87
+ q
88
+ ].join
89
+ end
90
+
91
+ def function
92
+ return if @scale.name != 'Major'
93
+ %w[Tonic Supertonic Mediant Subdominant
94
+ Dominant Submediant Leading][degree - 1]
95
+ end
96
+
97
+ private
98
+
99
+ def regexed_notation
100
+ @regexed_notation ||= begin
101
+ matchdata = @notation.match(NOTATION_REGEX)
102
+ { degree: matchdata[1], quality: matchdata[2] }
103
+ end
104
+ end
105
+
106
+ def normalize_quality_name(quality_name)
107
+ NOTATION_SUBSTITUTIONS.reduce(quality_name) do |memo, subs|
108
+ break memo if memo.empty?
109
+ memo.gsub(*subs)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Theory
5
+ # Musical scale creation and manipulation
6
+ class Scale
7
+ extend ClassicScales
8
+ extend Forwardable
9
+
10
+ def_delegators :notes, :accidentals, :sharps, :flats
11
+
12
+ attr_reader :interval_sequence, :tone
13
+
14
+ def initialize(*relative_intervals, tone: 'C',
15
+ mode: 1,
16
+ name: nil,
17
+ notes: nil)
18
+ @name = name
19
+ if relative_intervals.any? && tone
20
+ @tone = Note[tone]
21
+ relative_intervals = relative_intervals.rotate(mode - 1)
22
+ @interval_sequence = IntervalSequence.new(
23
+ relative_intervals: relative_intervals
24
+ )
25
+ elsif notes
26
+ @notes = NoteSet[*notes]
27
+ @tone = @notes.first
28
+ ds = @notes.interval_sequence.relative_intervals
29
+ @interval_sequence = IntervalSequence.new(relative_intervals: ds)
30
+ else
31
+ raise WrongKeywordsError,
32
+ '[*relative_intervals, tone: "C", mode: 1] || [notes:]'
33
+ end
34
+ end
35
+
36
+ def id
37
+ [(name || @interval_sequence), tone.number]
38
+ end
39
+
40
+ def ==(other)
41
+ id == other.id
42
+ end
43
+
44
+ def name
45
+ @name ||= begin
46
+ is = interval_sequence.relative_intervals
47
+ (0...is.size).each do |i|
48
+ if (scale_name = ::ClassicScales::SCALES.key(is.rotate(i)))
49
+ return scale_name
50
+ end
51
+ end
52
+ nil
53
+ end
54
+ end
55
+
56
+ def full_name
57
+ "#{tone} #{name}"
58
+ end
59
+
60
+ alias to_s full_name
61
+
62
+ def pretty_name
63
+ "#{tone.pretty_name} #{name}"
64
+ end
65
+
66
+ alias full_name pretty_name
67
+
68
+ def degree(d)
69
+ raise WrongDegreeError, d if d < 1 || d > size
70
+ tone + interval_sequence[d - 1].semitones
71
+ end
72
+
73
+ alias [] degree
74
+
75
+ def degrees
76
+ (1..size)
77
+ end
78
+
79
+ def degree_of_chord(chord)
80
+ return if chords(chord.size).map(&:name).include?(chord.name)
81
+ degree_of_note(chord.root_note)
82
+ end
83
+
84
+ def degree_of_note(note)
85
+ notes.index(note)
86
+ end
87
+
88
+ def &(other)
89
+ raise HasNoNotesError unless other.respond_to?(:notes)
90
+ notes & other
91
+ end
92
+
93
+ def include_notes?(arg)
94
+ noteset = arg.is_a?(Note) ? NoteSet[arg] : arg
95
+ (self & noteset).size == noteset.size
96
+ end
97
+
98
+ alias include? include_notes?
99
+
100
+ def notes
101
+ @notes ||= NoteSet[*degrees.map { |d| degree(d) }]
102
+ end
103
+
104
+ def interval(i)
105
+ interval_sequence[(i - 1) % size]
106
+ end
107
+
108
+ def size
109
+ interval_sequence.size
110
+ end
111
+
112
+ def tertians(n = 3)
113
+ degrees.size.times.reduce([]) do |memo, d|
114
+ ns = NoteSet[ *Array.new(n) { |i| notes[(d + (i * 2)) % size] } ]
115
+ begin
116
+ chord = Chord.new(notes: ns)
117
+ rescue ChordNotFoundError
118
+ memo
119
+ else
120
+ memo + [chord]
121
+ end
122
+ end
123
+ end
124
+
125
+ def triads
126
+ tertians(3)
127
+ end
128
+
129
+ def sevenths
130
+ tertians(4)
131
+ end
132
+
133
+ def pentads
134
+ tertians(5)
135
+ end
136
+
137
+ def progression(*degrees)
138
+ Progression.new(self, degrees)
139
+ end
140
+
141
+ def chords(size = 3..12)
142
+ size = (size..size) if size.is_a?(Integer)
143
+ scale_rotations = interval_sequence.inversions
144
+ ChordQuality.intervals_per_name.reduce([]) do |memo1, (qname, qintervals)|
145
+ next memo1 unless size.include?(qintervals.size)
146
+ memo1 + scale_rotations.each_with_index
147
+ .reduce([]) do |memo2, (rot, index)|
148
+ if (rot & qintervals).size == qintervals.size
149
+ memo2 + [Chord.new(root_note: degree(index + 1),
150
+ quality: ChordQuality.new(name: qname))]
151
+ else
152
+ memo2
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ alias all_chords chords
159
+ end
160
+ end
161
+ end