musa-dsl 0.40.0 → 0.42.0
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 +4 -4
- data/.gitignore +3 -0
- data/Gemfile +0 -1
- data/README.md +15 -1
- data/docs/README.md +1 -0
- data/docs/subsystems/datasets.md +75 -0
- data/docs/subsystems/generative.md +92 -6
- data/docs/subsystems/music.md +349 -19
- data/docs/subsystems/transport.md +26 -0
- data/lib/musa-dsl/datasets/dataset.rb +2 -0
- data/lib/musa-dsl/datasets/gdv.rb +3 -3
- data/lib/musa-dsl/datasets/p.rb +1 -1
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +4 -2
- data/lib/musa-dsl/datasets/score.rb +3 -1
- data/lib/musa-dsl/generative/darwin.rb +36 -1
- data/lib/musa-dsl/generative/generative-grammar.rb +31 -1
- data/lib/musa-dsl/generative/markov.rb +3 -1
- data/lib/musa-dsl/generative/rules.rb +54 -0
- data/lib/musa-dsl/generative/variatio.rb +69 -0
- data/lib/musa-dsl/midi/midi-recorder.rb +4 -0
- data/lib/musa-dsl/midi/midi-voices.rb +13 -1
- data/lib/musa-dsl/music/chord-definition.rb +7 -5
- data/lib/musa-dsl/music/chord-definitions.rb +37 -0
- data/lib/musa-dsl/music/chords.rb +88 -21
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +70 -521
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_dominant_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_major_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_minor_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/blues/blues_major_scale_kind.rb +100 -0
- data/lib/musa-dsl/music/scale_kinds/blues/blues_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_kinds/chromatic_scale_kind.rb +79 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/double_harmonic_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/hungarian_minor_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_major_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_minor_scale_kind.rb +101 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/phrygian_dominant_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/harmonic_major/harmonic_major_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/major_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/altered_scale_kind.rb +106 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/dorian_b2_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/locrian_sharp2_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_augmented_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_dominant_scale_kind.rb +106 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/melodic_minor_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/mixolydian_b6_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/minor_harmonic_scale_kind.rb +125 -0
- data/lib/musa-dsl/music/scale_kinds/minor_natural_scale_kind.rb +123 -0
- data/lib/musa-dsl/music/scale_kinds/modes/dorian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/locrian_scale_kind.rb +114 -0
- data/lib/musa-dsl/music/scale_kinds/modes/lydian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/mixolydian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/phrygian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_major_scale_kind.rb +93 -0
- data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_minor_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_hw_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_wh_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/whole_tone_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +80 -0
- data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +60 -0
- data/lib/musa-dsl/music/scales.rb +606 -67
- data/lib/musa-dsl/musicxml/builder/note.rb +31 -92
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +33 -94
- data/lib/musa-dsl/musicxml/builder/rest.rb +30 -91
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +31 -91
- data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +2 -2
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +367 -3
- data/lib/musa-dsl/series/base-series.rb +250 -240
- data/lib/musa-dsl/series/buffer-serie.rb +16 -5
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +29 -3
- data/lib/musa-dsl/series/main-serie-constructors.rb +19 -15
- data/lib/musa-dsl/series/main-serie-operations.rb +74 -29
- data/lib/musa-dsl/series/proxy-serie.rb +5 -1
- data/lib/musa-dsl/series/quantizer-serie.rb +16 -2
- data/lib/musa-dsl/series/queue-serie.rb +15 -1
- data/lib/musa-dsl/series/series-composer.rb +5 -2
- data/lib/musa-dsl/series/timed-serie.rb +8 -4
- data/lib/musa-dsl/transport/timer-clock.rb +4 -2
- data/lib/musa-dsl/transport/timer.rb +27 -4
- data/lib/musa-dsl/version.rb +1 -1
- data/musa-dsl.gemspec +18 -15
- metadata +85 -22
|
@@ -47,13 +47,15 @@ module Musa
|
|
|
47
47
|
#
|
|
48
48
|
# ### Move - Relocate specific chord tones to different octaves:
|
|
49
49
|
#
|
|
50
|
-
# chord.
|
|
50
|
+
# chord.with_move(root: -1, seventh: 1)
|
|
51
51
|
# # Root down one octave, seventh up one octave
|
|
52
|
+
# chord.move # => { root: -1, seventh: 1 } (current settings)
|
|
52
53
|
#
|
|
53
54
|
# ### Duplicate - Add copies of chord tones in other octaves:
|
|
54
55
|
#
|
|
55
|
-
# chord.
|
|
56
|
+
# chord.with_duplicate(root: -2, third: [-1, 1])
|
|
56
57
|
# # Add root 2 octaves down, third 1 octave down and 1 up
|
|
58
|
+
# chord.duplicate # => { root: -2, third: [-1, 1] } (current settings)
|
|
57
59
|
#
|
|
58
60
|
# ### Octave - Transpose entire chord:
|
|
59
61
|
#
|
|
@@ -90,8 +92,8 @@ module Musa
|
|
|
90
92
|
# @example Voicing with move and duplicate
|
|
91
93
|
# scale = Scales::Scales.default_system.default_tuning.major[60]
|
|
92
94
|
# chord = scale.dominant.chord(:seventh)
|
|
93
|
-
# .
|
|
94
|
-
# .
|
|
95
|
+
# .with_move(root: -1, third: -1)
|
|
96
|
+
# .with_duplicate(fifth: [0, 1])
|
|
95
97
|
#
|
|
96
98
|
# @example Feature navigation
|
|
97
99
|
# scale = Scales::Scales.default_system.default_tuning.major[60]
|
|
@@ -194,9 +196,9 @@ module Musa
|
|
|
194
196
|
# Maps each chord position (root, third, fifth, etc.) to its corresponding
|
|
195
197
|
# note in the scale or chromatic scale.
|
|
196
198
|
#
|
|
197
|
-
# @param root [NoteInScale] chord root note
|
|
199
|
+
# @param root [Scales::NoteInScale] chord root note
|
|
198
200
|
# @param chord_definition [ChordDefinition] chord structure
|
|
199
|
-
# @param scale [Scale] scale context
|
|
201
|
+
# @param scale [Scales::Scale] scale context
|
|
200
202
|
# @return [Hash{Symbol => Array<NoteInScale>}] position to notes mapping
|
|
201
203
|
#
|
|
202
204
|
# @api private
|
|
@@ -214,7 +216,7 @@ module Musa
|
|
|
214
216
|
#
|
|
215
217
|
# @param root_pitch [Integer] MIDI pitch of chord root
|
|
216
218
|
# @param features [Hash] desired chord features (quality:, size:, etc.)
|
|
217
|
-
# @param scale [Scale] scale context for diatonic filtering
|
|
219
|
+
# @param scale [Scales::Scale] scale context for diatonic filtering
|
|
218
220
|
# @param allow_chromatic [Boolean] allow non-diatonic chords
|
|
219
221
|
# @return [ChordDefinition, nil] matching definition or nil
|
|
220
222
|
#
|
|
@@ -242,7 +244,7 @@ module Musa
|
|
|
242
244
|
# @!attribute grade
|
|
243
245
|
# @return [Symbol] position name (:root, :third, :fifth, etc.)
|
|
244
246
|
# @!attribute note
|
|
245
|
-
# @return [NoteInScale] the note at this position
|
|
247
|
+
# @return [Scales::NoteInScale] the note at this position
|
|
246
248
|
#
|
|
247
249
|
# @api private
|
|
248
250
|
ChordGradeNote = Struct.new(:grade, :note, keyword_init: true)
|
|
@@ -253,8 +255,8 @@ module Musa
|
|
|
253
255
|
#
|
|
254
256
|
# Use {with_root} or create chords from scale notes instead.
|
|
255
257
|
#
|
|
256
|
-
# @param root [NoteInScale] chord root note
|
|
257
|
-
# @param scale [Scale, nil] scale context (nil if chromatic notes present)
|
|
258
|
+
# @param root [Scales::NoteInScale] chord root note
|
|
259
|
+
# @param scale [Scales::Scale, nil] scale context (nil if chromatic notes present)
|
|
258
260
|
# @param chord_definition [ChordDefinition] chord structure
|
|
259
261
|
# @param move [Hash, nil] octave moves for positions
|
|
260
262
|
# @param duplicate [Hash, nil] octave duplications for positions
|
|
@@ -423,10 +425,10 @@ module Musa
|
|
|
423
425
|
# chord.octave(2)
|
|
424
426
|
def octave(octave)
|
|
425
427
|
source_notes_map = @source_notes_map.transform_values do |notes|
|
|
426
|
-
notes.collect { |note| note.
|
|
428
|
+
notes.collect { |note| note.at_octave(octave) }.freeze
|
|
427
429
|
end.freeze
|
|
428
430
|
|
|
429
|
-
Chord.new(@root.
|
|
431
|
+
Chord.new(@root.at_octave(octave), @scale, chord_definition, @move, @duplicate, source_notes_map)
|
|
430
432
|
end
|
|
431
433
|
|
|
432
434
|
# Creates new chord with positions moved to different octaves.
|
|
@@ -439,11 +441,11 @@ module Musa
|
|
|
439
441
|
# @return [Chord] new chord with moved positions
|
|
440
442
|
#
|
|
441
443
|
# @example Move root down, seventh up
|
|
442
|
-
# chord.
|
|
444
|
+
# chord.with_move(root: -1, seventh: 1)
|
|
443
445
|
#
|
|
444
446
|
# @example Drop voicing (move third and seventh down)
|
|
445
|
-
# chord.
|
|
446
|
-
def
|
|
447
|
+
# chord.with_move(third: -1, seventh: -1)
|
|
448
|
+
def with_move(**octaves)
|
|
447
449
|
Chord.new(@root, @scale, @chord_definition, @move.merge(octaves), @duplicate, @source_notes_map)
|
|
448
450
|
end
|
|
449
451
|
|
|
@@ -457,17 +459,82 @@ module Musa
|
|
|
457
459
|
# @return [Chord] new chord with duplicated positions
|
|
458
460
|
#
|
|
459
461
|
# @example Duplicate root two octaves down
|
|
460
|
-
# chord.
|
|
462
|
+
# chord.with_duplicate(root: -2)
|
|
461
463
|
#
|
|
462
464
|
# @example Duplicate third in multiple octaves
|
|
463
|
-
# chord.
|
|
465
|
+
# chord.with_duplicate(third: [-1, 1])
|
|
464
466
|
#
|
|
465
467
|
# @example Duplicate multiple positions
|
|
466
|
-
# chord.
|
|
467
|
-
def
|
|
468
|
+
# chord.with_duplicate(root: -1, fifth: 1)
|
|
469
|
+
def with_duplicate(**octaves)
|
|
468
470
|
Chord.new(@root, @scale, @chord_definition, @move, @duplicate.merge(octaves), @source_notes_map)
|
|
469
471
|
end
|
|
470
472
|
|
|
473
|
+
# Finds this chord in other scales.
|
|
474
|
+
#
|
|
475
|
+
# Searches through scale kinds matching the given metadata criteria to find
|
|
476
|
+
# all scales that contain this chord. Returns new chord instances, each with
|
|
477
|
+
# its containing scale as context.
|
|
478
|
+
#
|
|
479
|
+
# @param roots [Range, Array, nil] pitch offsets to search (default: full octave)
|
|
480
|
+
# @param metadata [Hash] metadata filters for scale kinds (family:, brightness:, etc.)
|
|
481
|
+
# @return [Array<Chord>] this chord in different scale contexts
|
|
482
|
+
#
|
|
483
|
+
# @example Find G major triad in diatonic scales
|
|
484
|
+
# g_triad = c_major.dominant.chord
|
|
485
|
+
# g_triad.in_scales(family: :diatonic)
|
|
486
|
+
#
|
|
487
|
+
# @example Find chord in scales with specific brightness
|
|
488
|
+
# g7.in_scales(brightness: -1..1)
|
|
489
|
+
#
|
|
490
|
+
# @example Iterate over results
|
|
491
|
+
# g7.in_scales(family: :greek_modes).each do |chord|
|
|
492
|
+
# scale = chord.scale
|
|
493
|
+
# degree = scale.degree_of_chord(chord)
|
|
494
|
+
# puts "#{scale.kind.class.id} on #{scale.root_pitch}: degree #{degree}"
|
|
495
|
+
# end
|
|
496
|
+
#
|
|
497
|
+
# @see Musa::Scales::Scale#chord_on
|
|
498
|
+
# @see Musa::Scales::ScaleSystemTuning#search_chord_in_scales
|
|
499
|
+
def search_in_scales(roots: nil, **metadata)
|
|
500
|
+
tuning = @scale&.kind&.tuning || @root.scale.kind.tuning
|
|
501
|
+
tuning.search_chord_in_scales(self, roots: roots, **metadata)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Creates an equivalent chord with the given scale as its context.
|
|
505
|
+
#
|
|
506
|
+
# Returns a new Chord object representing the same chord but with
|
|
507
|
+
# the specified scale as its harmonic context. Returns nil if the
|
|
508
|
+
# chord is not contained in the scale.
|
|
509
|
+
#
|
|
510
|
+
# @param scale [Musa::Scales::Scale] the target scale
|
|
511
|
+
# @return [Chord, nil] new chord with target scale, or nil if not contained
|
|
512
|
+
#
|
|
513
|
+
# @example
|
|
514
|
+
# c_major = Scales.et12[440.0].major[60]
|
|
515
|
+
# g7 = c_major.dominant.chord :seventh
|
|
516
|
+
#
|
|
517
|
+
# g_mixolydian = Scales.et12[440.0].mixolydian[67]
|
|
518
|
+
# g7_in_mixolydian = g7.as_chord_in_scale(g_mixolydian)
|
|
519
|
+
# g7_in_mixolydian.scale # => G Mixolydian scale
|
|
520
|
+
#
|
|
521
|
+
# @see #search_in_scales
|
|
522
|
+
# @see Musa::Scales::Scale#contains_chord?
|
|
523
|
+
def as_chord_in_scale(scale)
|
|
524
|
+
return nil unless scale.contains_chord?(self)
|
|
525
|
+
|
|
526
|
+
root_note = scale.note_of_pitch(@root.pitch, allow_chromatic: false)
|
|
527
|
+
return nil unless root_note
|
|
528
|
+
|
|
529
|
+
Chord.with_root(
|
|
530
|
+
root_note,
|
|
531
|
+
scale: scale,
|
|
532
|
+
name: @chord_definition.name,
|
|
533
|
+
move: @move.empty? ? nil : @move,
|
|
534
|
+
duplicate: @duplicate.empty? ? nil : @duplicate
|
|
535
|
+
)
|
|
536
|
+
end
|
|
537
|
+
|
|
471
538
|
# Checks chord equality.
|
|
472
539
|
#
|
|
473
540
|
# Chords are equal if they have the same notes and chord definition.
|
|
@@ -504,12 +571,12 @@ module Musa
|
|
|
504
571
|
notes_map = notes_map.transform_values(&:dup)
|
|
505
572
|
|
|
506
573
|
moved&.each do |position, octave|
|
|
507
|
-
notes_map[position][0] = notes_map[position][0].
|
|
574
|
+
notes_map[position][0] = notes_map[position][0].at_octave(octave)
|
|
508
575
|
end
|
|
509
576
|
|
|
510
577
|
duplicated&.each do |position, octave|
|
|
511
578
|
octave.arrayfy.each do |octave|
|
|
512
|
-
notes_map[position] << notes_map[position][0].
|
|
579
|
+
notes_map[position] << notes_map[position][0].at_octave(octave)
|
|
513
580
|
end
|
|
514
581
|
end
|
|
515
582
|
|