music_set_theory 0.0.2
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.
- checksums.yaml +7 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +104 -0
- data/Rakefile +14 -0
- data/examples/mst_chords.rb +25 -0
- data/examples/mst_temperament.rb +46 -0
- data/lib/music_set_theory/chord_generator.rb +331 -0
- data/lib/music_set_theory/chords.rb +406 -0
- data/lib/music_set_theory/musutility.rb +284 -0
- data/lib/music_set_theory/scales.rb +456 -0
- data/lib/music_set_theory/temperament.rb +783 -0
- data/lib/music_set_theory/version.rb +11 -0
- data/lib/music_set_theory.rb +24 -0
- data/sig/music_theory.rbs +4 -0
- metadata +73 -0
@@ -0,0 +1,456 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# filename: music_set_theory/scale.rb
|
4
|
+
#
|
5
|
+
|
6
|
+
|
7
|
+
#-*- coding: UTF-8 -*-
|
8
|
+
# scales.py: Defines the classes for note sequences and scales.
|
9
|
+
#
|
10
|
+
# Copyright (c) 2008-2020 Peter Murphy <peterkmurphy@gmail.com>
|
11
|
+
# All rights reserved.
|
12
|
+
#
|
13
|
+
# Redistribution and use in source and binary forms, with or without
|
14
|
+
# modification, are permitted provided that the following conditions are met:
|
15
|
+
# * Redistributions of source code must retain the above copyright
|
16
|
+
# notice, this list of conditions and the following disclaimer.
|
17
|
+
# * Redistributions in binary form must reproduce the above copyright
|
18
|
+
# notice, this list of conditions and the following disclaimer in the
|
19
|
+
# documentation and/or other materials provided with the distribution.
|
20
|
+
# * The names of its contributors may not be used to endorse or promote
|
21
|
+
# products derived from this software without specific prior written
|
22
|
+
# permission.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ''AS IS'' AND ANY
|
25
|
+
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
26
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
27
|
+
# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
28
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
29
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
30
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
31
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
32
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
33
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
# import unittest;
|
36
|
+
#
|
37
|
+
# from .musutility import rotate, rotate_and_zero, multislice;
|
38
|
+
# from .temperament import temperament, WestTemp, seq_dict, NSEQ_SCALE, \
|
39
|
+
# NSEQ_CHORD, M_SHARP, M_FLAT, CHROM_NAT_NOTE_POS;
|
40
|
+
#
|
41
|
+
require_relative "./musutility"
|
42
|
+
require_relative "./temperament"
|
43
|
+
|
44
|
+
|
45
|
+
#
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# This represents a pattern of notes - a scale or a chord - each with a
|
49
|
+
# specified position from a base key or note. For example, a major scale
|
50
|
+
# is specified as the pattern [0, 2, 4, 5, 7, 9, 11], while a major chord
|
51
|
+
# is specified as [0, 4, 7].[*] In each case, we don't specify the key.
|
52
|
+
# However, this class provides functions that allow users to generate
|
53
|
+
# notes with a specified key as a function argument.
|
54
|
+
#
|
55
|
+
# [* If this doesn't make sense, consider the first note of a major scale
|
56
|
+
# is 0 semitones from the first note of a major scale, the second note is
|
57
|
+
# 2 semitones (a tone) from the first note, the third note is 4 semitones
|
58
|
+
# from the first note... and so on to the final note of the scale, which
|
59
|
+
# is 11 tones from the first note. Exercise for the reader: try this
|
60
|
+
# concept with a _major_ chord. ]
|
61
|
+
#
|
62
|
+
module MusicSetTheory
|
63
|
+
|
64
|
+
class NoteSeq
|
65
|
+
include Temperament
|
66
|
+
include MusUtility
|
67
|
+
end
|
68
|
+
class NoteSeqScale < NoteSeq
|
69
|
+
#include MusUtility
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
#
|
76
|
+
#
|
77
|
+
#
|
78
|
+
module MusicSetTheory
|
79
|
+
class NoteSeq
|
80
|
+
|
81
|
+
#
|
82
|
+
# Initialiser. It contains the following arguments.
|
83
|
+
# ==== Args
|
84
|
+
# nseq_name:: the full name of the note sequence.
|
85
|
+
# nseq_type:: the type of note sequence (e.g., NSEQ_SCALE or NSEQ_CHORD).
|
86
|
+
# nseq_temp:: the musical temperament from which the sequence of notes is
|
87
|
+
# taken. This should be an instance of the class temperament.
|
88
|
+
# nseq_posn:: a sequence of integers representing positions of the notes
|
89
|
+
# in the sequence relative to its first note. (For best results,
|
90
|
+
# the first item should be 0 to represent the first note.)
|
91
|
+
# nseq_nat_posns:: a sequence of integers (which should be the same size
|
92
|
+
# as nseq_posn). For each item in nseq_posn, the corresponding item
|
93
|
+
# in nseq_nat_posns represent the difference in its calculated
|
94
|
+
# natural note from the base key's natural note. For example, this
|
95
|
+
# parameter is [0, 2, 4] for a major chord; the second note is always
|
96
|
+
# two letters higher than the first note, and the third note is two
|
97
|
+
# letters higher again.
|
98
|
+
# (! this is in degrees.)
|
99
|
+
# nseq_abbrv:: the primary abbreviation for the note sequence (if any).
|
100
|
+
# nseq_synonyms:: a list of possible synonyms, or extra names, for the
|
101
|
+
# note sequence. For example, the "Ionian" mode is another name for
|
102
|
+
# the major scale as far as this class is concerned.
|
103
|
+
# nseq_other_abbrevs:: a list of possible alternate abbreviations for the
|
104
|
+
# note sequence. For example, both "min7" and "m7" are abbreviations
|
105
|
+
# for the minor seventh chord.
|
106
|
+
#
|
107
|
+
# ==== Examples of defining scales:
|
108
|
+
# Major scale:: NoteSeq.new("Major", NSEQ_SCALE, WestTemp, [0, 2, 4, 5, 7,
|
109
|
+
# 9, 11], range(7), nseq_synonyms: ["Ionian"])
|
110
|
+
# Harmonic Minor scale:: NoteSeq.new("Harmonic Minor", NSEQ_SCALE, WestTemp,
|
111
|
+
# [0, 2, 3, 5, 7, 8, 11], 0...7);
|
112
|
+
#
|
113
|
+
# Examples of defining chords:
|
114
|
+
# Major chord: noteseq("Major", NSEQ_CHORD, WestTemp, [0, 4, 7],
|
115
|
+
# [0, 2, 4], "maj");
|
116
|
+
# Minor chord: noteseq("Minor", NSEQ_CHORD, WestTemp,
|
117
|
+
# [0, 3, 7], [0, 2, 4], "min", nseq_other_abbrevs = ["m"]);
|
118
|
+
# Min 7 chord: noteseq("Minor Seventh", NSEQ_CHORD, WestTemp,
|
119
|
+
# [0, 3, 7, 11], [0, 2, 4, 6], "min7", nseq_other_abbrevs = ["m7"]);
|
120
|
+
#
|
121
|
+
# Note: it is easier to define scales using the noteseq_scale class (this
|
122
|
+
# file) and chord using the noteseq_chord class (in chords.py)
|
123
|
+
#
|
124
|
+
attr_accessor :nseq_name, :nseq_type, :nseq_temp, :nseq_posn
|
125
|
+
attr_accessor :nseq_nat_posns, :nseq_abbrev, :nseq_synonyms,
|
126
|
+
:nseq_other_abbrevs
|
127
|
+
def initialize( nseq_name, nseq_type, nseq_temp, nseq_posn,
|
128
|
+
nseq_nat_posns,
|
129
|
+
# nseq_abbrev = "", nseq_synonyms = [],
|
130
|
+
# nseq_other_abbrevs = [] )
|
131
|
+
nseq_abbrev: "", nseq_synonyms: [],
|
132
|
+
nseq_other_abbrevs: [] )
|
133
|
+
self.nseq_name = nseq_name
|
134
|
+
self.nseq_type = nseq_type
|
135
|
+
self.nseq_temp = nseq_temp
|
136
|
+
self.nseq_posn = nseq_posn
|
137
|
+
|
138
|
+
self.nseq_nat_posns = nseq_nat_posns
|
139
|
+
self.nseq_abbrev = nseq_abbrev
|
140
|
+
self.nseq_synonyms = nseq_synonyms
|
141
|
+
self.nseq_other_abbrevs = nseq_other_abbrevs
|
142
|
+
|
143
|
+
self.register_with_temp()
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# alias name nseq_name
|
148
|
+
# alias type nseq_type
|
149
|
+
# alias temperament nseq_temp
|
150
|
+
# alias tment nseq_temp # *
|
151
|
+
# :
|
152
|
+
# etc.
|
153
|
+
{
|
154
|
+
nseq_name: [:name],
|
155
|
+
nseq_type: [:type],
|
156
|
+
nseq_temp: [:temp, :temperament, :tment],
|
157
|
+
nseq_posn: [:posn, :note_pos, :notes],
|
158
|
+
nseq_nat_posns: [:nat_posns, :note_nat, :notes_degree,
|
159
|
+
:notes_deg],
|
160
|
+
nseq_abbrev: [:abbrev, :abbr],
|
161
|
+
nseq_synonyms: [:synonyms, :syns],
|
162
|
+
nseq_other_abbrevs: [:other_abbrevs, :abbr_others],
|
163
|
+
}.each do |k, vary|
|
164
|
+
|
165
|
+
vary.each do |new_name|
|
166
|
+
getter_name = k
|
167
|
+
setter_name = k.to_s + "="
|
168
|
+
if method_defined? getter_name
|
169
|
+
new_getter_name = new_name
|
170
|
+
alias_method new_getter_name, getter_name
|
171
|
+
end
|
172
|
+
if method_defined? setter_name
|
173
|
+
new_setter_name = new_name.to_s + "="
|
174
|
+
alias_method new_setter_name, setter_name
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
#
|
185
|
+
#
|
186
|
+
#
|
187
|
+
module MusicSetTheory
|
188
|
+
class NoteSeq
|
189
|
+
|
190
|
+
# Registers this note sequence with the underlying temperament, so
|
191
|
+
# that it can be looked up by name, by abbreviation or by sequence.
|
192
|
+
#
|
193
|
+
def register_with_temp
|
194
|
+
if self.nseq_synonyms
|
195
|
+
#if self.nseq_name not in self.nseq_synonyms
|
196
|
+
if !(self.nseq_synonyms.include? self.nseq_name)
|
197
|
+
our_names = [self.nseq_name] + self.nseq_synonyms;
|
198
|
+
else
|
199
|
+
our_names = self.nseq_synonyms;
|
200
|
+
end
|
201
|
+
else
|
202
|
+
our_names = [self.nseq_name];
|
203
|
+
end
|
204
|
+
|
205
|
+
if self.nseq_other_abbrevs
|
206
|
+
#if self.nseq_abbrev not in self.nseq_other_abbrevs
|
207
|
+
if !(self.nseq_other_abbrevs.include? self.nseq_abbrev)
|
208
|
+
our_abbrevs = [self.nseq_abbrev] + self.nseq_other_abbrevs
|
209
|
+
else
|
210
|
+
our_abbrevs = self.nseq_other_abbrevs
|
211
|
+
end
|
212
|
+
else
|
213
|
+
our_abbrevs = [self.nseq_abbrev]
|
214
|
+
end
|
215
|
+
self.nseq_temp.seq_maps.add_elem(
|
216
|
+
self, self.nseq_type, our_names, our_abbrevs, self.nseq_posn)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Get the notes for the note_seq starting from a given key. Then
|
220
|
+
# rotates the sequence (by rotate_by). Then slices it (using the
|
221
|
+
# argument in the slice parameter).
|
222
|
+
#
|
223
|
+
def get_notes_for_key( key, rotate_by=0, slice=nil )
|
224
|
+
ret = nil
|
225
|
+
default_seq = self.nseq_temp.get_note_sequence(
|
226
|
+
key, self.nseq_posn, self.nseq_nat_posns); #C
|
227
|
+
modulus = self.nseq_temp.no_nat_keys
|
228
|
+
if slice
|
229
|
+
ret = multislice(
|
230
|
+
default_seq, slice, offset: rotate_by, mod: modulus);
|
231
|
+
else
|
232
|
+
ret = rotate(default_seq, rotate_by);
|
233
|
+
end
|
234
|
+
ret
|
235
|
+
end
|
236
|
+
|
237
|
+
# For this noteseq, output its positions relative to its first
|
238
|
+
# note, then rotates the sequence (by rotate_by), then slices
|
239
|
+
# it (using slice, if not none). If and only if raz is True, the
|
240
|
+
# result is rotated-and-zeroed.
|
241
|
+
#
|
242
|
+
def get_posn_for_offset( rotate_by=0, slice=nil, raz: false )
|
243
|
+
if slice
|
244
|
+
modulus = self.nseq_temp.no_nat_keys
|
245
|
+
multisliced = multislice(
|
246
|
+
self.nseq_posn, slice,
|
247
|
+
offset: rotate_by, mod: modulus)
|
248
|
+
if raz
|
249
|
+
return rotate_and_zero(multisliced, 0, self.nseq_temp.no_keys);
|
250
|
+
else
|
251
|
+
return multisliced;
|
252
|
+
end
|
253
|
+
else
|
254
|
+
if raz
|
255
|
+
return rotate_and_zero(
|
256
|
+
self.nseq_posn, rotate_by, self.nseq_temp.no_keys)
|
257
|
+
else
|
258
|
+
return rotate(self.nseq_posn, rotate_by)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
# FIXME. separate the file.
|
269
|
+
#
|
270
|
+
#
|
271
|
+
# A specialisation of noteseq used exclusively for defining scales -
|
272
|
+
# especially heptatonic/diotonic scales.
|
273
|
+
#
|
274
|
+
module MusicSetTheory
|
275
|
+
class NoteSeqScale
|
276
|
+
|
277
|
+
#
|
278
|
+
# ==== Args
|
279
|
+
# nseq_name:: name of scale.
|
280
|
+
# nseq_temp:: temperament for scale.
|
281
|
+
# nseq_posn:: position of notes in scale.
|
282
|
+
# nseq_nat_posns:: natural note positions for notes in scales.
|
283
|
+
# nseq_modes:: a sequence of modes for the scale, listed in order of
|
284
|
+
# position.
|
285
|
+
#
|
286
|
+
def initialize( nseq_name, nseq_temp, nseq_posn, nseq_nat_posns,
|
287
|
+
nseq_modes = [], debug_f: false )
|
288
|
+
#
|
289
|
+
return super(
|
290
|
+
nseq_name, NSEQ_SCALE, nseq_temp, nseq_posn, nseq_nat_posns
|
291
|
+
) if nseq_modes.empty?
|
292
|
+
|
293
|
+
###
|
294
|
+
super(nseq_name, NSEQ_SCALE, nseq_temp, nseq_posn, nseq_nat_posns,
|
295
|
+
nseq_abbrev: "", nseq_synonyms: [nseq_modes[0]])
|
296
|
+
|
297
|
+
new_nseq_pos = nseq_posn
|
298
|
+
new_nseq_nat_pos = nseq_nat_posns
|
299
|
+
|
300
|
+
# This creates more instances of noteseq_scales - all for the different
|
301
|
+
# modes.
|
302
|
+
# By creating them, they will be automatically connected to the
|
303
|
+
# appropriate temperament's dictionary.
|
304
|
+
for i in 1...nseq_posn.size
|
305
|
+
$stderr.puts "{#{__method__}} new_nseq_pos: #{new_nseq_pos.inspect}," +
|
306
|
+
" new_nseq_nat_pos: #{new_nseq_nat_pos.inspect}" if debug_f
|
307
|
+
|
308
|
+
new_nseq_pos = rotate_and_zero(new_nseq_pos, 1, nseq_temp.no_keys)
|
309
|
+
new_nseq_nat_pos = rotate_and_zero(new_nseq_nat_pos, 1,
|
310
|
+
nseq_temp.no_nat_keys)
|
311
|
+
|
312
|
+
# create an other scale.
|
313
|
+
NoteSeqScale.new(
|
314
|
+
nseq_modes[i], nseq_temp, new_nseq_pos, new_nseq_nat_pos)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def to_s
|
319
|
+
self.nseq_name.to_s
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
|
326
|
+
module MusicSetTheory
|
327
|
+
|
328
|
+
#
|
329
|
+
include Temperament
|
330
|
+
|
331
|
+
# The following scales and names are derived from:
|
332
|
+
# http://docs.solfege.org/3.9/C/scales/modes.html
|
333
|
+
|
334
|
+
# The only exception is the "Discordant Minor", which I invented for
|
335
|
+
# shit and giggles.
|
336
|
+
|
337
|
+
# Note: MelMinScale represents a melodic minor scale _ascending_. See the
|
338
|
+
# Aeolian mode of the Major scale for melodic minor scale _descending_.
|
339
|
+
|
340
|
+
HEPT_NAT_POSNS = (0...7).to_a
|
341
|
+
MEL_MIN_NOTE_POS = [0, 2, 3, 5, 7, 9, 11]
|
342
|
+
HARM_MIN_NOTE_POS = [0, 2, 3, 5, 7, 8, 11]
|
343
|
+
HARM_MAJ_NOTE_POS = [0, 2, 4, 5, 7, 8, 11]
|
344
|
+
DISC_MIN_NOTE_POS = [0, 2, 3, 5, 6, 9, 11]
|
345
|
+
HUNGARIAN_NOTE_POS = [0, 3, 4, 6, 7, 9, 10]
|
346
|
+
|
347
|
+
# For ease of comprehension, we have the list of modes as arrays which
|
348
|
+
# can be browsed from outside.
|
349
|
+
MAJORMODES = [ "Ionian",
|
350
|
+
"Dorian",
|
351
|
+
"Phrygian",
|
352
|
+
"Lydian",
|
353
|
+
"Mixolydian",
|
354
|
+
"Aeolian",
|
355
|
+
"Locrian", ]
|
356
|
+
|
357
|
+
MELMINORMODES = [ "Jazz Minor",
|
358
|
+
"Dorian " + M_FLAT + "9",
|
359
|
+
"Lydian Augmented",
|
360
|
+
"Lydian Dominant",
|
361
|
+
"Mixolydian " + M_FLAT + "13",
|
362
|
+
"Semilocrian",
|
363
|
+
"Superlocrian", ]
|
364
|
+
|
365
|
+
HARMINORMODES = [ "Harmonic Minor",
|
366
|
+
"Locrian " + M_SHARP + "6",
|
367
|
+
"Ionian Augmented",
|
368
|
+
"Romanian",
|
369
|
+
"Phrygian Dominant",
|
370
|
+
"Lydian " + M_SHARP + "2",
|
371
|
+
"Ultralocrian", ]
|
372
|
+
|
373
|
+
HARMMAJORMODES = [ "Harmonic Major",
|
374
|
+
"Dorian " + M_FLAT + "6",
|
375
|
+
"Phrygian " + M_FLAT + "4",
|
376
|
+
"Lydian " + M_FLAT + "3",
|
377
|
+
"Mixolydian " + M_FLAT + "9",
|
378
|
+
"Lydian " + M_SHARP + "2 " + M_SHARP + "5",
|
379
|
+
"Locrian " + M_FLAT + M_FLAT + "7", ]
|
380
|
+
|
381
|
+
DISCORDMINMODES = [ "Melodic Minor " + M_FLAT + "5",
|
382
|
+
"Dorian " + M_FLAT + "9 " + M_FLAT + "4",
|
383
|
+
"Minor Lydian Augmented",
|
384
|
+
"Lydian Dominant " + M_FLAT + "9",
|
385
|
+
"Lydian Augmented " + M_SHARP + "2 " + M_SHARP + "3",
|
386
|
+
"Semilocrian " + M_FLAT + M_FLAT + "7",
|
387
|
+
"Superlocrian " + M_FLAT + M_FLAT + "6", ]
|
388
|
+
|
389
|
+
HUNGARIANMODES = [ "Hungarian",
|
390
|
+
"Superlocrian " + M_FLAT + M_FLAT + "6 " + M_FLAT + M_FLAT + "7",
|
391
|
+
"Harmonic Minor " + M_FLAT + "5",
|
392
|
+
"Superlocrian " + M_SHARP + "6",
|
393
|
+
"Melodic Minor " + M_SHARP + "5",
|
394
|
+
"Dorian " + M_FLAT + "9 " + M_SHARP + "11",
|
395
|
+
"Lydian Augmented " + M_SHARP + "3", ]
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
# Scales.
|
401
|
+
#
|
402
|
+
#
|
403
|
+
module MusicSetTheory
|
404
|
+
MajorScale = NoteSeqScale.new("Major", WestTemp,
|
405
|
+
CHROM_NAT_NOTE_POS, HEPT_NAT_POSNS, MAJORMODES)
|
406
|
+
|
407
|
+
MelMinorScale = NoteSeqScale.new("Melodic Minor", WestTemp,
|
408
|
+
MEL_MIN_NOTE_POS, HEPT_NAT_POSNS, MELMINORMODES)
|
409
|
+
|
410
|
+
HarmMinorScale = NoteSeqScale.new("Harmonic Minor", WestTemp,
|
411
|
+
HARM_MIN_NOTE_POS, HEPT_NAT_POSNS, HARMINORMODES)
|
412
|
+
|
413
|
+
HarmMajorScale = NoteSeqScale.new("Harmonic Major", WestTemp,
|
414
|
+
HARM_MAJ_NOTE_POS, HEPT_NAT_POSNS, HARMMAJORMODES)
|
415
|
+
|
416
|
+
DiscMinorScale = NoteSeqScale.new("Discordant Minor", WestTemp,
|
417
|
+
DISC_MIN_NOTE_POS, HEPT_NAT_POSNS, DISCORDMINMODES)
|
418
|
+
|
419
|
+
HungarianScale = NoteSeqScale.new("Hungarian", WestTemp,
|
420
|
+
HUNGARIAN_NOTE_POS, HEPT_NAT_POSNS, HUNGARIANMODES)
|
421
|
+
end
|
422
|
+
|
423
|
+
|
424
|
+
module MusicSetTheory
|
425
|
+
# This is for decomposing a scale into chords. We use this as a test
|
426
|
+
# routine so we know what is required.
|
427
|
+
#
|
428
|
+
def scale_analysis( scale_name, perm_chord_type )
|
429
|
+
# 1. Lookup scale name.
|
430
|
+
noteseq_founditem = noteseq.find_by_name(scale_name)
|
431
|
+
|
432
|
+
# 2. Find scale pattern.
|
433
|
+
ournoteseq = noteseq_founditem.noteseq
|
434
|
+
|
435
|
+
#
|
436
|
+
noteseq_founditem.noteseq.getpattern(noteseq_founditem.indices)
|
437
|
+
|
438
|
+
#for i in range(ournoteseq.nseq_posn.len()):
|
439
|
+
for i in 0...ournoteseq.nseq_posn.size
|
440
|
+
ournoteslice = noteseq_for_slice(i, perm_chord_type)
|
441
|
+
notechord_founditem = noteseq.find_by_chord(ournoteslice)
|
442
|
+
|
443
|
+
if notechord_founditem == None
|
444
|
+
print("None")
|
445
|
+
else
|
446
|
+
print(notechord_founditem.getName())
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
return
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|
454
|
+
|
455
|
+
|
456
|
+
#### endof filename: music_set_theory/scales.rb
|