musa-dsl 0.41.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 +1 -0
- 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 +33 -14
- 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/generative-grammar.rb +3 -1
- data/lib/musa-dsl/generative/markov.rb +1 -1
- data/lib/musa-dsl/midi/midi-voices.rb +3 -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 +69 -47
- data/lib/musa-dsl/music/scale_kinds/major_scale_kind.rb +1 -1
- data/lib/musa-dsl/music/scale_kinds/minor_natural_scale_kind.rb +1 -1
- data/lib/musa-dsl/music/scales.rb +219 -107
- 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 +10 -5
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +6 -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 +4 -2
- data/lib/musa-dsl/series/queue-serie.rb +2 -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 -2
- data/musa-dsl.gemspec +0 -2
- metadata +1 -1
|
@@ -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,62 +425,48 @@ 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
|
-
# Creates new chord with positions moved to different octaves
|
|
434
|
+
# Creates new chord with positions moved to different octaves.
|
|
433
435
|
#
|
|
434
|
-
#
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
# When called without arguments, returns the current move settings hash.
|
|
436
|
+
# Relocates specific chord positions to different octaves while keeping
|
|
437
|
+
# other positions unchanged. Multiple positions can be moved at once.
|
|
438
|
+
# Merges with existing moves.
|
|
439
439
|
#
|
|
440
440
|
# @param octaves [Hash{Symbol => Integer}] position to octave offset mapping
|
|
441
|
-
# @return [Chord
|
|
441
|
+
# @return [Chord] new chord with moved positions
|
|
442
442
|
#
|
|
443
443
|
# @example Move root down, seventh up
|
|
444
|
-
# chord.
|
|
444
|
+
# chord.with_move(root: -1, seventh: 1)
|
|
445
445
|
#
|
|
446
446
|
# @example Drop voicing (move third and seventh down)
|
|
447
|
-
# chord.
|
|
448
|
-
|
|
449
|
-
# @example Get current move settings
|
|
450
|
-
# chord.move # => { root: -1 }
|
|
451
|
-
def move(**octaves)
|
|
452
|
-
return @move if octaves.empty?
|
|
453
|
-
|
|
447
|
+
# chord.with_move(third: -1, seventh: -1)
|
|
448
|
+
def with_move(**octaves)
|
|
454
449
|
Chord.new(@root, @scale, @chord_definition, @move.merge(octaves), @duplicate, @source_notes_map)
|
|
455
450
|
end
|
|
456
451
|
|
|
457
|
-
# Creates new chord with positions duplicated in other octaves
|
|
452
|
+
# Creates new chord with positions duplicated in other octaves.
|
|
458
453
|
#
|
|
459
|
-
#
|
|
460
|
-
#
|
|
454
|
+
# Adds copies of specific chord positions in different octaves.
|
|
455
|
+
# Original positions remain at their current octave.
|
|
461
456
|
# Merges with existing duplications.
|
|
462
457
|
#
|
|
463
|
-
# When called without arguments, returns the current duplicate settings hash.
|
|
464
|
-
#
|
|
465
458
|
# @param octaves [Hash{Symbol => Integer, Array<Integer>}] position to octave(s)
|
|
466
|
-
# @return [Chord
|
|
459
|
+
# @return [Chord] new chord with duplicated positions
|
|
467
460
|
#
|
|
468
461
|
# @example Duplicate root two octaves down
|
|
469
|
-
# chord.
|
|
462
|
+
# chord.with_duplicate(root: -2)
|
|
470
463
|
#
|
|
471
464
|
# @example Duplicate third in multiple octaves
|
|
472
|
-
# chord.
|
|
465
|
+
# chord.with_duplicate(third: [-1, 1])
|
|
473
466
|
#
|
|
474
467
|
# @example Duplicate multiple positions
|
|
475
|
-
# chord.
|
|
476
|
-
|
|
477
|
-
# @example Get current duplicate settings
|
|
478
|
-
# chord.duplicate # => { root: -1 }
|
|
479
|
-
def duplicate(**octaves)
|
|
480
|
-
return @duplicate if octaves.empty?
|
|
481
|
-
|
|
468
|
+
# chord.with_duplicate(root: -1, fifth: 1)
|
|
469
|
+
def with_duplicate(**octaves)
|
|
482
470
|
Chord.new(@root, @scale, @chord_definition, @move, @duplicate.merge(octaves), @source_notes_map)
|
|
483
471
|
end
|
|
484
472
|
|
|
@@ -507,10 +495,44 @@ module Musa
|
|
|
507
495
|
# end
|
|
508
496
|
#
|
|
509
497
|
# @see Musa::Scales::Scale#chord_on
|
|
510
|
-
# @see Musa::Scales::ScaleSystemTuning#
|
|
511
|
-
def
|
|
498
|
+
# @see Musa::Scales::ScaleSystemTuning#search_chord_in_scales
|
|
499
|
+
def search_in_scales(roots: nil, **metadata)
|
|
512
500
|
tuning = @scale&.kind&.tuning || @root.scale.kind.tuning
|
|
513
|
-
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
|
+
)
|
|
514
536
|
end
|
|
515
537
|
|
|
516
538
|
# Checks chord equality.
|
|
@@ -549,12 +571,12 @@ module Musa
|
|
|
549
571
|
notes_map = notes_map.transform_values(&:dup)
|
|
550
572
|
|
|
551
573
|
moved&.each do |position, octave|
|
|
552
|
-
notes_map[position][0] = notes_map[position][0].
|
|
574
|
+
notes_map[position][0] = notes_map[position][0].at_octave(octave)
|
|
553
575
|
end
|
|
554
576
|
|
|
555
577
|
duplicated&.each do |position, octave|
|
|
556
578
|
octave.arrayfy.each do |octave|
|
|
557
|
-
notes_map[position] << notes_map[position][0].
|
|
579
|
+
notes_map[position] << notes_map[position][0].at_octave(octave)
|
|
558
580
|
end
|
|
559
581
|
end
|
|
560
582
|
|
|
@@ -43,7 +43,7 @@ module Musa
|
|
|
43
43
|
# c_major.tonic # C (60)
|
|
44
44
|
# c_major.dominant # G (67)
|
|
45
45
|
# c_major.VI # A (69) - relative minor root
|
|
46
|
-
# c_major.relative_minor.
|
|
46
|
+
# c_major.relative_minor.as_root_of(:minor) # A minor scale
|
|
47
47
|
#
|
|
48
48
|
# @see ScaleKind Abstract base class
|
|
49
49
|
# @see MinorNaturalScaleKind Natural minor scale
|
|
@@ -56,7 +56,7 @@ module Musa
|
|
|
56
56
|
# a_minor.tonic # A (69)
|
|
57
57
|
# a_minor.dominant # E (76)
|
|
58
58
|
# a_minor.iii # C (72) - relative major root
|
|
59
|
-
# a_minor.relative_major.
|
|
59
|
+
# a_minor.relative_major.as_root_of(:major) # C major scale
|
|
60
60
|
#
|
|
61
61
|
# @see ScaleKind Abstract base class
|
|
62
62
|
# @see MajorScaleKind Major scale
|