music_set_theory 0.0.3 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3d6c653105c33d0aad4903ab2f5fc4e3df1092174fea8f44277f422f0dbb6c6
4
- data.tar.gz: 572212c3e54b19770e15483658cb4e1a5c4193f26ba9716048e80959e2969ea5
3
+ metadata.gz: 2b66a2a0c031f2d15f603607c3ce78762a0f3e738f63d968c917fd7872618721
4
+ data.tar.gz: 505349cc9f85f8ecaaa890090522153a35e34c452707fb54f3d4112de5317a06
5
5
  SHA512:
6
- metadata.gz: f618cb4c86604a1432d7a4cb1b330cad6551a3b2da38d036b46b31215000d97cd33e0ac245fbe3328eec32b7708154ed1393126c95797cc1f99fb5d3b36629c0
7
- data.tar.gz: b04ee383b072f6ecca89f5cbc05cc2e6e44f0c4b886777f76a7ee824c3faeae83062cd7bd2f015d0ebb190771ab7eb631ced7b1a3634ec788e0c379deb4568e2
6
+ metadata.gz: 456d90f4f7e2b1c263381554d4587a2052285822d357af26417362dc8b0fc7d4386a18dc15f60b0ed03f883209f0ca20cfbd65adf079007b83a9439b2539cedb
7
+ data.tar.gz: 192520afd4ac5954fc1b933b4560061f7958d8a809036b08443fb44ed73a2f4eabf5a655377af2bb9d24c0e25fc33b56255c854e78e15b5af4976cd7fb4a5b9d
@@ -24,19 +24,19 @@ nseqtype_dict.each {|k, v|
24
24
  dict = v
25
25
  puts pad2+"name_dict (#{dict.name_dict.keys.size}):"
26
26
  dict.name_dict.each_with_index {|(k, v), i|
27
- puts pad2+pad+"(#{i+1}) #{k}: #{v}"
27
+ puts pad2+pad+"(#{i+1}) #{k}:#{v}"
28
28
  }
29
29
  puts
30
30
 
31
31
  puts pad2+"abbr_dict (#{dict.abbr_dict.keys.size}):"
32
32
  dict.abbr_dict.each_with_index {|(k, v), i|
33
- puts pad2+pad+"(#{i+1}) #{k}: #{v}"
33
+ puts pad2+pad+"(#{i+1}) #{k}:#{v}"
34
34
  }
35
35
  puts
36
36
 
37
37
  puts pad2+"seqpos_dict (#{dict.seqpos_dict.keys.size}):"
38
38
  dict.seqpos_dict.each_with_index {|(k, v), i|
39
- puts pad2+pad+"(#{i+1}) #{k}: #{v}"
39
+ puts pad2+pad+"(#{i+1}) #{k}:#{v}"
40
40
  }
41
41
 
42
42
  puts '-'*40
@@ -47,7 +47,7 @@ require_relative "./temperament"
47
47
  require_relative "./scales"
48
48
  require_relative "./chords"
49
49
 
50
- require 'romannumerals'
50
+ require 'romanumerals'
51
51
 
52
52
 
53
53
  # import copy, codecs
@@ -57,6 +57,10 @@ require 'romannumerals'
57
57
  # from .scales import MajorScale, MelMinorScale, HarmMinorScale,\
58
58
  # HarmMajorScale;
59
59
  # from .chords import CHORDTYPE_DICT;
60
+ require_relative "musutility"
61
+ require_relative "temperament"
62
+ require_relative "scales"
63
+ require_relative "chords"
60
64
 
61
65
 
62
66
  #
@@ -142,8 +146,9 @@ module MusicSetTheory
142
146
  # >>> print int_to_roman(1999)
143
147
  # MCMXCIX
144
148
  # """
145
- def int_to_roman(input)
146
- raise "#{input} must be greater than zero." if input <= 0
149
+ def int_to_roman( input )
150
+ raise ArgumentError, "#{input} must be greater than zero." if input <= 0
151
+ raise TypeError, "Input must be an integer." unless input.is_a? Integer
147
152
 
148
153
  input.to_roman
149
154
  end
@@ -166,12 +171,28 @@ module MusicSetTheory
166
171
 
167
172
  attr_accessor :full_name, :key, :full_notes, :table_title, :rows
168
173
  def initialize( full_name, key, full_notes, table_title )
169
- self.full_name = full_name;
170
- self.key = key;
171
- self.full_notes = full_notes;
172
- self.table_title = table_title;
173
- self.rows = [];
174
+ self.full_name = full_name
175
+ self.key = key
176
+ self.full_notes = full_notes
177
+ self.table_title = table_title
178
+ self.rows = []
174
179
  end
180
+
181
+ def to_a
182
+ tmp = []
183
+ tmp << [ self.full_name, self.key, self.full_notes, self.table_title, ]
184
+
185
+ #
186
+ self.rows.map{|r|
187
+ # tmp << r.to_a
188
+ # tmp += r.to_a
189
+ tmp << r.to_a
190
+ }
191
+
192
+ ret = tmp
193
+ ret
194
+ end
195
+
175
196
  end
176
197
 
177
198
  # Represents different rows (triads, 7ths, 9ths) in tabular
@@ -180,8 +201,18 @@ module MusicSetTheory
180
201
  class ScaleChordRow
181
202
  attr_accessor :chord_type, :notes
182
203
  def initialize( chord_type )
183
- self.chord_type = chord_type;
184
- self.notes = [];
204
+ self.chord_type = chord_type
205
+ self.notes = []
206
+ end
207
+
208
+ def to_a
209
+ # ret = "#{self.chord_type}:#{self.notes}"
210
+ tmp = []
211
+ self.notes.each do |nt|
212
+ tmp << [self.chord_type,] + nt.to_a
213
+ end
214
+ ret = tmp
215
+ ret
185
216
  end
186
217
  end
187
218
 
@@ -189,9 +220,13 @@ module MusicSetTheory
189
220
  class ScaleChordCell
190
221
  attr_accessor :chordname_1, :chordname_2, :notes
191
222
  def initialize( chordname_1, chordname_2, notes )
192
- self.chordname_1 = chordname_1;
193
- self.chordname_2 = chordname_2;
194
- self.notes = notes;
223
+ self.chordname_1 = chordname_1
224
+ self.chordname_2 = chordname_2
225
+ self.notes = notes
226
+ end
227
+
228
+ def to_a
229
+ [self.chordname_1, self.chordname_2, self.notes]
195
230
  end
196
231
  end
197
232
 
@@ -201,6 +236,8 @@ end
201
236
  module MusicSetTheory
202
237
 
203
238
  # Used for converting "C" -> 1, "Db"-> 2b, etc.
239
+ #
240
+ #
204
241
  def makebaserep( notex, base = 0 )
205
242
  notexparsed = WestTemp.note_parse(notex)
206
243
  #pos_rep = str(WestTemp.nat_key_lookup_order[notexparsed[0]] + base)
@@ -211,7 +248,7 @@ module MusicSetTheory
211
248
  elsif notexparsed[1] < 0
212
249
  ret = pos_rep + (M_FLAT * (-1 * notexparsed[1]))
213
250
  else
214
- ret = pos_rep;
251
+ ret = pos_rep
215
252
  end
216
253
 
217
254
  ret
@@ -219,25 +256,33 @@ module MusicSetTheory
219
256
 
220
257
 
221
258
  # Returns an instance of scale_chords using the following inputs:
222
- #
223
- # scale_name: a name of a scale like "Dorian".
224
- # key: generally a standard music key like "C".
225
- # possiblechords: a sequence of chord types like "Seventh" and "Ninth".
259
+ # ==== Args
260
+ # scale_name:: a name of a scale like "Dorian".
261
+ # key:: generally a standard music key like "C".
262
+ # possiblechords:: a sequence of chord types like "Seventh" and "Ninth".
263
+ # west_temp:: Temperament object.
226
264
  #
227
- def populate_scale_chords( scale_name, key, possiblechords )
228
- our_scale = WestTemp.get_nseqby_name(scale_name, NSEQ_SCALE);
229
- num_elem = len(our_scale.nseq_posn);
265
+ # ==== Returns
266
+ # ScaleChords object.
267
+ #
268
+ #def populate_scale_chords( scale_name, key, possiblechords )
269
+ def populate_scale_chords( scale_name, key, possiblechords,
270
+ west_temp = WestTemp )
271
+ our_scale = west_temp.get_nseqby_name(scale_name, NSEQ_SCALE)
272
+ # num_elem = len(our_scale.nseq_posn)
273
+ num_elem = our_scale.nseq_posn.size
274
+
230
275
  begin
231
276
  int_of_key = key.to_i
232
- is_key_an_int = true;
277
+ is_key_an_int = true
233
278
  rescue ValueError
234
- is_key_an_int = false;
235
- int_of_key = nil;
279
+ is_key_an_int = false
280
+ int_of_key = nil
236
281
  end
237
282
 
238
283
  if is_key_an_int
239
284
  #our_scale_notes = [makebaserep(x, int_of_key) for x in
240
- #our_scale.get_notes_for_key("C")];
285
+ #our_scale.get_notes_for_key("C")]
241
286
  our_scale_notes = our_scale.get_notes_for_key("C").map{|x|
242
287
  makebaserep(x, int_of_key) }
243
288
  else
@@ -251,19 +296,22 @@ module MusicSetTheory
251
296
  ourchordrow = ScaleChordRow.new(i)
252
297
  our_chord_data.rows.append(ourchordrow)
253
298
 
254
- for j in range(num_elem):
255
- our_slice = CHORDTYPE_DICT[i];
299
+ # for j in range(num_elem):
300
+ for j in 0...num_elem
301
+ our_slice = CHORDTYPE_DICT[i]
302
+
256
303
  if is_key_an_int
257
304
  #our_chord_notes = [makebaserep(x, int_of_key) for x in
258
- # our_scale.get_notes_for_key("C", j, our_slice)];
305
+ # our_scale.get_notes_for_key("C", j, our_slice)]
259
306
  our_chord_notes = our_scale.get_notes_for_key("C", j, our_slice).
260
307
  map{|x| makebaserep(x, int_of_key) }
261
308
  else
262
309
  our_chord_notes = our_scale.get_notes_for_key(key, j, our_slice)
263
310
  end
264
311
 
265
- our_posn = our_scale.get_posn_for_offset(j, our_slice, true)
266
- our_chord = WestTemp.get_nseqby_seqpos(our_posn, NSEQ_CHORD)
312
+ #our_posn = our_scale.get_posn_for_offset(j, our_slice, true)
313
+ our_posn = our_scale.get_posn_for_offset(j, our_slice, raz: true)
314
+ our_chord = west_temp.get_nseqby_seqpos(our_posn, NSEQ_CHORD)
267
315
  if our_chord
268
316
  ourchordrow.notes.append(ScaleChordCell.new(our_chord.nseq_name,
269
317
  our_chord.nseq_abbrev, our_chord_notes))
@@ -295,16 +343,17 @@ module MusicSetTheory
295
343
  thestring += "<caption>%s</caption>\n" %
296
344
  (scale.key + " " + scale.full_name +
297
345
  ": " + seqtostr(scale.full_notes))
298
- thestring += "<thead>\n" + startrow + "<th>Chord Types</th>\n";
299
- for q in range(7):
300
- # thestring += "<th>%s</th>\n" % str(int_to_roman(q+1));
346
+ thestring += "<thead>\n" + startrow + "<th>Chord Types</th>\n"
347
+ # for q in range(7)
348
+ for q in 0...7
349
+ thestring += "<th>%s</th>\n" % str(int_to_roman(q+1))
301
350
  end
302
- thestring += endrow + "</thead>\n<tbody>\n";
351
+ thestring += endrow + "</thead>\n<tbody>\n"
303
352
 
304
- for i in scale.rows:
305
- thestring += startrow;
306
- thestring += "<td>%s</td>\n" % i.chord_type;
307
- for j in i.notes:
353
+ for i in scale.rows
354
+ thestring += startrow
355
+ thestring += "<td>%s</td>\n" % i.chord_type
356
+ for j in i.notes
308
357
  if not j.chordname_1
309
358
  thestring += ("<td><p>%s<br />" % (str(j.chordname_1)))
310
359
  thestring += ("<i>%s</i><br />" % (str(j.chordname_2)))
@@ -264,17 +264,35 @@ end
264
264
 
265
265
  require 'active_support'
266
266
  require 'active_support/core_ext/object/deep_dup'
267
+ require 'ice_nine'
267
268
  module MusicSetTheory
268
269
  module MusUtility
269
270
 
270
271
  def deep_freeze( obj )
272
+ IceNine.deep_freeze(obj)
273
+ end
274
+
275
+ def deep_melt( obj )
271
276
  case obj
272
277
  when Hash
273
- obj.each { |k, v| deep_freeze(k); deep_freeze(v) }
278
+ obj.each_with_object({}) do |(key, value), new_hash|
279
+ new_hash[deep_melt(key)] = deep_melt(value)
280
+ end
274
281
  when Array
275
- obj.each { |e| deep_freeze(e) }
282
+ obj.map { |element| deep_melt(element) }
283
+ when Object
284
+ # インスタンス変数の解除
285
+ obj.instance_variables.each do |var|
286
+ deep_melt(var)
287
+ value = obj.instance_variable_get(var)
288
+ obj.remove_instance_variable(var)
289
+ obj.instance_variable_set(var, deep_melt(value))
290
+ end
291
+ obj.dup rescue obj # 凍結状態を解除
292
+ else
293
+ obj.dup rescue obj
276
294
  end
277
- obj.freeze
295
+ obj.dup rescue obj
278
296
  end
279
297
 
280
298
  end
@@ -121,6 +121,9 @@ module MusicSetTheory
121
121
  # Note: it is easier to define scales using the noteseq_scale class (this
122
122
  # file) and chord using the noteseq_chord class (in chords.py)
123
123
  #
124
+ # ==== Warning
125
+ # - ! This method updates `nseq_temp`.
126
+ #
124
127
  attr_accessor :nseq_name, :nseq_type, :nseq_temp, :nseq_posn
125
128
  attr_accessor :nseq_nat_posns, :nseq_abbrev, :nseq_synonyms,
126
129
  :nseq_other_abbrevs
@@ -132,7 +135,10 @@ module MusicSetTheory
132
135
  nseq_other_abbrevs: [] )
133
136
  self.nseq_name = nseq_name
134
137
  self.nseq_type = nseq_type
138
+
135
139
  self.nseq_temp = nseq_temp
140
+ # self.nseq_temp = deep_melt(nseq_temp.deep_dup)
141
+
136
142
  self.nseq_posn = nseq_posn
137
143
 
138
144
  self.nseq_nat_posns = nseq_nat_posns
@@ -140,7 +146,8 @@ module MusicSetTheory
140
146
  self.nseq_synonyms = nseq_synonyms
141
147
  self.nseq_other_abbrevs = nseq_other_abbrevs
142
148
 
143
- self.register_with_temp()
149
+ #
150
+ self.register_with_temp(self.nseq_temp)
144
151
  end
145
152
 
146
153
  #
@@ -189,8 +196,10 @@ module MusicSetTheory
189
196
 
190
197
  # Registers this note sequence with the underlying temperament, so
191
198
  # that it can be looked up by name, by abbreviation or by sequence.
199
+ # ==== Warning
200
+ # - This methods updates `self.nseq_temp`
192
201
  #
193
- def register_with_temp
202
+ def register_with_temp( nseq_temp = self.nseq_temp )
194
203
  if self.nseq_synonyms
195
204
  #if self.nseq_name not in self.nseq_synonyms
196
205
  if !(self.nseq_synonyms.include? self.nseq_name)
@@ -212,7 +221,9 @@ module MusicSetTheory
212
221
  else
213
222
  our_abbrevs = [self.nseq_abbrev]
214
223
  end
215
- self.nseq_temp.seq_maps.add_elem(
224
+
225
+ #
226
+ nseq_temp.seq_maps.add_elem(
216
227
  self, self.nseq_type, our_names, our_abbrevs, self.nseq_posn)
217
228
  end
218
229
 
@@ -239,6 +250,9 @@ module MusicSetTheory
239
250
  # it (using slice, if not none). If and only if raz is True, the
240
251
  # result is rotated-and-zeroed.
241
252
  #
253
+ # ==== See Also
254
+ # - chord_generator.rb:`populate_scale_chords()`
255
+ #
242
256
  def get_posn_for_offset( rotate_by=0, slice=nil, raz: false )
243
257
  if slice
244
258
  modulus = self.nseq_temp.no_nat_keys
@@ -344,55 +358,114 @@ module MusicSetTheory
344
358
  DISC_MIN_NOTE_POS = [0, 2, 3, 5, 6, 9, 11]
345
359
  HUNGARIAN_NOTE_POS = [0, 3, 4, 6, 7, 9, 10]
346
360
 
361
+
347
362
  # For ease of comprehension, we have the list of modes as arrays which
348
363
  # can be browsed from outside.
349
- MAJORMODES = [ "Ionian",
364
+ MAJOR_MODES = [ "Ionian",
350
365
  "Dorian",
351
366
  "Phrygian",
352
367
  "Lydian",
353
368
  "Mixolydian",
354
369
  "Aeolian",
355
370
  "Locrian", ]
371
+ MAJORMODES = MAJOR_MODES
356
372
 
357
- MELMINORMODES = [ "Jazz Minor",
373
+ MEL_MINOR_MODES = [ "Jazz Minor",
358
374
  "Dorian " + M_FLAT + "9",
359
375
  "Lydian Augmented",
360
376
  "Lydian Dominant",
361
377
  "Mixolydian " + M_FLAT + "13",
362
378
  "Semilocrian",
363
379
  "Superlocrian", ]
380
+ MELMINORMODES = MEL_MINOR_MODES
364
381
 
365
- HARMINORMODES = [ "Harmonic Minor",
382
+ HARM_MINOR_MODES = [ "Harmonic Minor",
366
383
  "Locrian " + M_SHARP + "6",
367
384
  "Ionian Augmented",
368
385
  "Romanian",
369
386
  "Phrygian Dominant",
370
387
  "Lydian " + M_SHARP + "2",
371
388
  "Ultralocrian", ]
389
+ HARMINORMODES = HARM_MINOR_MODES # for compatibility... typo?
372
390
 
373
- HARMMAJORMODES = [ "Harmonic Major",
391
+ HARM_MAJOR_MODES = [ "Harmonic Major",
374
392
  "Dorian " + M_FLAT + "6",
375
393
  "Phrygian " + M_FLAT + "4",
376
394
  "Lydian " + M_FLAT + "3",
377
395
  "Mixolydian " + M_FLAT + "9",
378
396
  "Lydian " + M_SHARP + "2 " + M_SHARP + "5",
379
397
  "Locrian " + M_FLAT + M_FLAT + "7", ]
398
+ HARMMAJORMODES = HARM_MAJOR_MODES
380
399
 
381
- DISCORDMINMODES = [ "Melodic Minor " + M_FLAT + "5",
400
+ DISCORD_MIN_MODES = [ "Melodic Minor " + M_FLAT + "5",
382
401
  "Dorian " + M_FLAT + "9 " + M_FLAT + "4",
383
402
  "Minor Lydian Augmented",
384
403
  "Lydian Dominant " + M_FLAT + "9",
385
404
  "Lydian Augmented " + M_SHARP + "2 " + M_SHARP + "3",
386
405
  "Semilocrian " + M_FLAT + M_FLAT + "7",
387
406
  "Superlocrian " + M_FLAT + M_FLAT + "6", ]
407
+ DISCORDMINMODES = DISCORD_MIN_MODES
388
408
 
389
- HUNGARIANMODES = [ "Hungarian",
409
+ HUNGARIAN_MODES = [ "Hungarian",
390
410
  "Superlocrian " + M_FLAT + M_FLAT + "6 " + M_FLAT + M_FLAT + "7",
391
411
  "Harmonic Minor " + M_FLAT + "5",
392
412
  "Superlocrian " + M_SHARP + "6",
393
413
  "Melodic Minor " + M_SHARP + "5",
394
414
  "Dorian " + M_FLAT + "9 " + M_SHARP + "11",
395
415
  "Lydian Augmented " + M_SHARP + "3", ]
416
+ HUNGARIANMODES = HUNGARIAN_MODES
417
+
418
+ MODE_ARRAY = [
419
+ MAJOR_MODES,
420
+ MEL_MINOR_MODES,
421
+ HARM_MINOR_MODES,
422
+ HARM_MAJOR_MODES,
423
+ DISCORD_MIN_MODES,
424
+ HUNGARIAN_MODES,
425
+ ]
426
+ end
427
+
428
+ module MusicSetTheory
429
+
430
+ #
431
+ #
432
+ #
433
+ Pentatonic_NAT_POSNS = (0...5).to_a # 5音音階
434
+ Hexatonic_NAT_POSNS = (0...6).to_a # 6音音階
435
+ Heptatonic_NAT_POSNS = HEPT_NAT_POSNS # 7音音階
436
+ Octatonic_NAT_POSNS = (0...8).to_a # 8音音階
437
+
438
+ # Pentatonic.
439
+ #
440
+ #
441
+ MAJOR_PENTA_NOTE_POS = [ 0, 2, 4, 7, 9, ]
442
+ MINOR_PENTA_NOTE_POS = [ 0, 3, 5, 7, 10, ]
443
+ RYUKYU_PENTA_NOTE_POS = [ 0, 4, 5, 7, 11, ]
444
+
445
+ BLUES_HEXA_NOTE_POS = [ 0, 3, 5, 6, 7, 10, ]
446
+
447
+ def self.def_scale( const_name, name: , tment: ,
448
+ note_pos: , modes: [],
449
+ scale_array: :ScaleArray )
450
+ posns = (0...(note_pos.size)).to_a
451
+
452
+ tmp = NoteSeqScale.new(name, tment, note_pos, posns, modes)
453
+ self.const_set(const_name, tmp)
454
+ ret = self.const_get(const_name)
455
+
456
+ self.const_get(scale_array).const_set(const_name,ret)
457
+
458
+ ret
459
+ end
460
+
461
+ def self.undef_scale( const_name, scale_array: :ScaleArray )
462
+ self.const_get(scale_array).send(:remove_const, const_name)
463
+ self.send(:remove_const, const_name)
464
+ end
465
+
466
+ def self.scales( scale_array: :ScaleArray )
467
+ self.const_get(scale_array).constants
468
+ end
396
469
 
397
470
  end
398
471
 
@@ -401,23 +474,51 @@ end
401
474
  #
402
475
  #
403
476
  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)
477
+ #ScaleArray = []
478
+ module ScaleArray; end
479
+
480
+ #MajorScale = NoteSeqScale.new("Major", WestTemp,
481
+ # CHROM_NAT_NOTE_POS, HEPT_NAT_POSNS, MAJORMODES)
482
+ #MelMinorScale = NoteSeqScale.new("Melodic Minor", WestTemp,
483
+ # MEL_MIN_NOTE_POS, HEPT_NAT_POSNS, MELMINORMODES)
484
+ #HarmMinorScale = NoteSeqScale.new("Harmonic Minor", WestTemp,
485
+ # HARM_MIN_NOTE_POS, HEPT_NAT_POSNS, HARMINORMODES)
486
+ #HarmMajorScale = NoteSeqScale.new("Harmonic Major", WestTemp,
487
+ # HARM_MAJ_NOTE_POS, HEPT_NAT_POSNS, HARMMAJORMODES)
488
+ #DiscMinorScale = NoteSeqScale.new("Discordant Minor", WestTemp,
489
+ # DISC_MIN_NOTE_POS, HEPT_NAT_POSNS, DISCORDMINMODES)
490
+ #HungarianScale = NoteSeqScale.new("Hungarian", WestTemp,
491
+ # HUNGARIAN_NOTE_POS, HEPT_NAT_POSNS, HUNGARIANMODES)
492
+ def_scale :MajorScale, name: "Major", tment: WestTemp,
493
+ note_pos: CHROM_NAT_NOTE_POS, modes: MAJOR_MODES
494
+
495
+ def_scale :MelMinorScale, name: "Melodic Minor", tment: WestTemp,
496
+ note_pos: MEL_MIN_NOTE_POS, modes: MEL_MINOR_MODES
497
+
498
+ def_scale :HarmMinorScale, name: "Harmonic Minor", tment: WestTemp,
499
+ note_pos: HARM_MIN_NOTE_POS, modes: HARM_MINOR_MODES
500
+
501
+ def_scale :HarmMajorScale, name: "Harmonic Major", tment: WestTemp,
502
+ note_pos: HARM_MAJ_NOTE_POS, modes: HARM_MAJOR_MODES
503
+
504
+ def_scale :DiscMinorScale, name: "Discordant Minor", tment: WestTemp,
505
+ note_pos: DISC_MIN_NOTE_POS, modes: DISCORD_MIN_MODES
506
+
507
+ def_scale :HungarianScale, name: "Hungarian", tment: WestTemp,
508
+ note_pos: HUNGARIAN_NOTE_POS, modes: HUNGARIAN_MODES
509
+
510
+ # Pentatonic scales.
511
+ def_scale :MajorPentaScale, name: "Major Pentatonic", tment: WestTemp,
512
+ note_pos: MAJOR_PENTA_NOTE_POS
513
+ def_scale :MinorPentaScale, name: "Minor Pentatonic", tment: WestTemp,
514
+ note_pos: MINOR_PENTA_NOTE_POS
515
+ def_scale :RyukyuPentaScale, name: "Ryukyu Pentatonic", tment: WestTemp,
516
+ note_pos: RYUKYU_PENTA_NOTE_POS
517
+
518
+ # Hexatonic scales.
519
+ def_scale :BluesHexaScale, name: "Blues", tment: WestTemp,
520
+ note_pos: BLUES_HEXA_NOTE_POS
418
521
 
419
- HungarianScale = NoteSeqScale.new("Hungarian", WestTemp,
420
- HUNGARIAN_NOTE_POS, HEPT_NAT_POSNS, HUNGARIANMODES)
421
522
  end
422
523
 
423
524
 
@@ -396,13 +396,23 @@ module MusicSetTheory
396
396
  # Initialiser.
397
397
  # ==== Args
398
398
  # no_keys:: the number of keys in the temperament.
399
+ # !number of semitones in one octave. ex. 12.
399
400
  # nat_keys:: an array consisting of the names of the natural
400
401
  # (unsharped or unflattened) keys in the temperament.
402
+ # ex.
403
+ # ["C", "D", "E", "F", "G", "A", "B"]
404
+ #
401
405
  # nat_key_posn:: the position of the natural keys in the temperament.
402
406
  # These should correspond to the elements in nat_keys.
403
407
  # Positions are calculated base zero.
408
+ # ex.
409
+ # [ 0, 2, 4, 5, 7, 9, 11]
404
410
  #
405
- def initialize( no_keys, nat_keys, nat_key_posn )
411
+ # def initialize( no_keys, nat_keys, nat_key_posn )
412
+ def initialize( no_keys = CHROM_SIZE,
413
+ nat_keys = CHROM_NAT_NOTES,
414
+ nat_key_posn = CHROM_NAT_NOTE_POS )
415
+ #
406
416
  self.no_keys = no_keys
407
417
  self.nat_keys = nat_keys
408
418
  self.nat_key_posn = nat_key_posn
@@ -436,13 +446,29 @@ module MusicSetTheory
436
446
 
437
447
  # Useful for dictionary lookup later.
438
448
  #self.seq_maps = seq_dict([NSEQ_SCALE, NSEQ_CHORD], self);
439
- #self.seq_maps = SeqDict.new(NSEQ_SCALE, NSEQ_CHORD);
440
449
  self.seq_maps = SeqDict.new([NSEQ_SCALE, NSEQ_CHORD], self)
441
450
 
442
451
  end
443
452
 
453
+ # Alias methods of getters+setters.
454
+ # {
455
+ # original_base_name: [ name of aliases ],
456
+ # original_base_name: [ name of aliases ],
457
+ # :
458
+ # :
459
+ # }
460
+ #
444
461
  {
445
- seq_maps: [:seq_dict],
462
+ no_keys: [ :num_semitones, :num_keys, ],
463
+ nat_keys: [ :natural_key_names, ],
464
+ nat_key_posn: [ :natural_key_positions, ],
465
+ no_nat_keys: [ :num_natural_keys, ],
466
+ nat_key_pos_lookup: [
467
+ :natural_key_position_lookup, :natural_key_position_dict, ],
468
+ pos_lookup_nat_key: [
469
+ :position_natural_key_lookup, :position_natural_key_dict, ],
470
+
471
+ seq_maps: [:seq_dict],
446
472
  }.each do |k, vary|
447
473
 
448
474
  vary.each do |new_name|
@@ -525,6 +551,9 @@ module MusicSetTheory
525
551
  # position of the key in the unit of halftone. ex. key: "C" =>0,
526
552
  # key: "D#" =>3, key: "Cb" =>-1
527
553
  #
554
+ # ==== See Also
555
+ # - `#get_key_of_pos()`
556
+ #
528
557
  def get_pos_of_key( key, debug_f: false )
529
558
  key_parsed = self.note_parse(key)
530
559
  $stderr.puts "key_parsed: #{key_parsed}" if debug_f
@@ -534,6 +563,9 @@ module MusicSetTheory
534
563
  ret = self.nat_key_pos_lookup[key_parsed[0]] + key_parsed[1]
535
564
  ret
536
565
  end
566
+ alias pos_of_key get_pos_of_key
567
+ alias position_of get_pos_of_key
568
+ alias pos_of get_pos_of_key
537
569
 
538
570
  # Given a position in the temperament, this function attempts to
539
571
  # return the "best" key name corresponding to it. This is not a
@@ -546,9 +578,9 @@ module MusicSetTheory
546
578
  # pos:: the position inside the temperament.
547
579
  # desired_nat_note:: the preferred natural key to start the key name.
548
580
  # For example "C" makes the function return "C#" instead of "Db".
549
- # If None, then the preference depends on...
550
- # sharp_not_flat:: if True, returns the sharpened accidental form
551
- # (e.g., "C#"); if False, returns the flattened accidental form
581
+ # If nil, then the preference depends on...
582
+ # sharp_not_flat:: if true, returns the sharpened accidental form
583
+ # (e.g., "C#"); if false, returns the flattened accidental form
552
584
  # (i.e., "Db").
553
585
  # ==== Returns
554
586
  #
@@ -602,6 +634,8 @@ module MusicSetTheory
602
634
 
603
635
  return nil
604
636
  end
637
+ alias key_of_pos get_key_of_pos
638
+ alias key_of get_key_of_pos
605
639
 
606
640
 
607
641
  # This function takes a key and a sequence of positions relative to
@@ -669,6 +703,8 @@ module MusicSetTheory
669
703
  # ["D", "C#", "E"] =>["D", [0, 11, 2]]
670
704
  #
671
705
  # this is returned by the function.
706
+ # ==== See Also
707
+ # - `#get_note_sequence()`
672
708
  #
673
709
  def get_keyseq_notes( note_seq )
674
710
  base_key = note_seq[0]
@@ -679,52 +715,70 @@ module MusicSetTheory
679
715
  [base_key, pos_seq]
680
716
  end
681
717
 
718
+ end
719
+
720
+ end
721
+ end
722
+
723
+
724
+ #
725
+ #
726
+ #
727
+ module MusicSetTheory
728
+ module Temperament
729
+
730
+ class Temperament
731
+
682
732
 
683
733
  ### The next few functions are rip-offs of SeqDict functions.
734
+ #
735
+ #! actually these are the utility methods for SeqDict instance.
736
+ #
737
+
684
738
 
685
- # This adds an element to the dictionary inside the temperament. The
686
- # arguments:
687
- # elem: the element to add to the dictionary .
688
- # nseq_type: the type of the elemenet (such as scale or chord).
689
- # name_s: a string, or a sequence of strings. This provides names
739
+ # This adds an element to the dictionary inside the temperament.
740
+ # ==== Args
741
+ # elem:: the element to add to the dictionary .
742
+ # nseq_type:: the type of the elemenet (such as scale or chord).
743
+ # name_s:: a string, or a sequence of strings. This provides names
690
744
  # as keys that map onto elem.
691
- # abbrv_s: a string, or a sequence of strings. This provides
745
+ # abbrv_s:: a string, or a sequence of strings. This provides
692
746
  # abbreviations as keys that map onto elem.
693
- # seqpos: a sequence. A tuple form will be used as a key that
747
+ # seqpos:: a sequence. A tuple form will be used as a key that
694
748
  # maps onto elem.
695
749
  #
696
750
  # If nseq_type is not associated with any of the sub-dictionaries in
697
751
  # the dictionary in the temperament, then this function exits.
698
752
  #
699
753
  def add_elem( elem, nseq_type, name_s, abbrv_s, seqpos )
700
- self.seq_maps.add_elem(elem, nseq_type, name_s, abbrv_s, seqpos)
754
+ self.seq_dict.add_elem(elem, nseq_type, name_s, abbrv_s, seqpos)
701
755
  end
702
756
 
703
757
 
704
758
  # Checks if there is a subdictionary associated with nseq_type.
705
759
  def check_nseqby_subdict( nseq_type )
706
- self.seq_maps.check_nseqby_subdict(nseq_type)
760
+ self.seq_dict.check_nseqby_subdict(nseq_type)
707
761
  end
708
762
 
709
763
  # Checks if there is a noteseq with a given name.
710
764
  def check_nseqby_name( nseq_type, name )
711
- self.seq_maps.check_nseqby_name(nseq_type, name)
765
+ self.seq_dict.check_nseqby_name(nseq_type, name)
712
766
  end
713
767
 
714
768
  # Checks if there is a noteseq with a given abbreviation.
715
769
  def check_nseqby_abbrv( nseq_type, abbrv )
716
- self.seq_maps.check_nseqby_abbrv(nseq_type, abbrv)
770
+ self.seq_dict.check_nseqby_abbrv(nseq_type, abbrv)
717
771
  end
718
772
 
719
773
  # Checks if there is a noteseq with a given sequence position.
720
774
  def check_nseqby_seqpos( nseq_type, seqpos )
721
- self.seq_maps.check_nseqby_seqpos(nseq_type, seqpos)
775
+ self.seq_dict.check_nseqby_seqpos(nseq_type, seqpos)
722
776
  end
723
-
777
+
724
778
  # Looks up a noteseq (or anything else) by name.
725
779
  def get_nseqby_name( name, nseq_type )
726
- if self.seq_maps.check_nseqby_name(nseq_type, name)
727
- self.seq_maps.get_nseqby_name(name, nseq_type)
780
+ if self.seq_dict.check_nseqby_name(nseq_type, name)
781
+ self.seq_dict.get_nseqby_name(name, nseq_type)
728
782
  else
729
783
  nil
730
784
  end
@@ -748,8 +802,8 @@ module MusicSetTheory
748
802
  end
749
803
  end
750
804
 
751
-
752
805
  end
806
+
753
807
  end
754
808
  end
755
809
 
@@ -760,9 +814,15 @@ end
760
814
  module MusicSetTheory
761
815
  module Temperament
762
816
 
763
- CHROM_NAT_NOTES = ["C", "D", "E", "F", "G", "A", "B"]
764
- CHROM_NAT_NOTE_POS = [0, 2, 4, 5, 7, 9, 11]
817
+ #
818
+ # CHROM_SIZE:: number of semitones.
819
+ # CHROM_NAT_NOTE_POS:: position in number of semitones.
820
+ # ex. D = 2 (i.e., C + #*2), E = 4 (C + #*4), etc.
821
+ # CHROM_NAT_NOTES:: natural notes.
822
+ #
765
823
  CHROM_SIZE = 12
824
+ CHROM_NAT_NOTES = ["C", "D", "E", "F", "G", "A", "B"]
825
+ CHROM_NAT_NOTE_POS = [ 0, 2, 4, 5, 7, 9, 11]
766
826
  def self.WestTempNew
767
827
  Temperament.new(CHROM_SIZE, CHROM_NAT_NOTES, CHROM_NAT_NOTE_POS)
768
828
  end
@@ -772,9 +832,13 @@ module MusicSetTheory
772
832
 
773
833
  #WestTemp = deep_freeze(WestTempNew()) # the last failed in chords_test(1).
774
834
  #WestTemp = WestTempNew() # the last failed in chords_test(1).
775
- WestTemp = MusicSetTheory.deep_freeze(WestTempNew())
776
835
  #ng. WestTemp.deep_freeze
777
836
 
837
+ ### freeze for debug.
838
+ # WestTemp = MusicSetTheory.deep_freeze(WestTempNew())
839
+ WestTemp = WestTempNew() # ok. (dependancied removed in test cases).
840
+ WestTment = WestTemp # alias.
841
+
778
842
  end
779
843
  end
780
844
 
@@ -4,7 +4,7 @@
4
4
  #
5
5
 
6
6
  module MusicSetTheory
7
- VERSION = "0.0.3"
7
+ VERSION = "0.0.5"
8
8
  end
9
9
 
10
10
 
@@ -20,5 +20,8 @@ require_relative "music_set_theory/temperament"
20
20
  require_relative "music_set_theory/scales"
21
21
  require_relative "music_set_theory/chords"
22
22
 
23
+ #
24
+ require_relative "music_set_theory/chord_generator"
25
+
23
26
 
24
27
  #### endof filename: music_set_theory.rb.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: music_set_theory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - YAMAMOTO, Masayuki
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ice_nine
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.11'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.11'
26
40
  description: A music theory library based on Python's `musictheory` package.
27
41
  email:
28
42
  - mephistobooks@users.noreply.github.com
@@ -45,12 +59,12 @@ files:
45
59
  - lib/music_set_theory/temperament.rb
46
60
  - lib/music_set_theory/version.rb
47
61
  - sig/music_theory.rbs
48
- homepage: https://voidptrjp.blogspot.com/2025/07/musictheorygem.html
62
+ homepage: https://voidptrjp.blogspot.com/2025/07/musicsettheorygem.html
49
63
  licenses:
50
64
  - MIT
51
65
  metadata:
52
66
  allowed_push_host: https://rubygems.org
53
- homepage_uri: https://voidptrjp.blogspot.com/2025/07/musictheorygem.html
67
+ homepage_uri: https://voidptrjp.blogspot.com/2025/07/musicsettheorygem.html
54
68
  source_code_uri: https://github.com/mephistobooks/music_set_theory
55
69
  changelog_uri: https://github.com/mephistobooks/music_set_theory/CHANGELOG.md
56
70
  rdoc_options: []