musa-dsl 0.30.2 → 0.41.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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -1
  3. data/.version +6 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +0 -1
  6. data/README.md +227 -6
  7. data/docs/README.md +83 -0
  8. data/docs/api-reference.md +86 -0
  9. data/docs/getting-started/quick-start.md +93 -0
  10. data/docs/getting-started/tutorial.md +58 -0
  11. data/docs/subsystems/core-extensions.md +316 -0
  12. data/docs/subsystems/datasets.md +465 -0
  13. data/docs/subsystems/generative.md +290 -0
  14. data/docs/subsystems/matrix.md +63 -0
  15. data/docs/subsystems/midi.md +123 -0
  16. data/docs/subsystems/music.md +544 -0
  17. data/docs/subsystems/musicxml-builder.md +264 -0
  18. data/docs/subsystems/neumas.md +71 -0
  19. data/docs/subsystems/repl.md +135 -0
  20. data/docs/subsystems/sequencer.md +98 -0
  21. data/docs/subsystems/series.md +302 -0
  22. data/docs/subsystems/transcription.md +152 -0
  23. data/docs/subsystems/transport.md +177 -0
  24. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
  25. data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
  26. data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
  27. data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
  28. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
  29. data/lib/musa-dsl/core-ext/extension.rb +53 -0
  30. data/lib/musa-dsl/core-ext/hashify.rb +162 -1
  31. data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
  32. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
  33. data/lib/musa-dsl/core-ext/with.rb +114 -0
  34. data/lib/musa-dsl/datasets/dataset.rb +109 -0
  35. data/lib/musa-dsl/datasets/delta-d.rb +78 -0
  36. data/lib/musa-dsl/datasets/e.rb +186 -2
  37. data/lib/musa-dsl/datasets/gdv.rb +279 -2
  38. data/lib/musa-dsl/datasets/gdvd.rb +201 -0
  39. data/lib/musa-dsl/datasets/helper.rb +75 -0
  40. data/lib/musa-dsl/datasets/p.rb +177 -2
  41. data/lib/musa-dsl/datasets/packed-v.rb +91 -0
  42. data/lib/musa-dsl/datasets/pdv.rb +136 -1
  43. data/lib/musa-dsl/datasets/ps.rb +134 -4
  44. data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
  45. data/lib/musa-dsl/datasets/score/render.rb +105 -1
  46. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
  47. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
  48. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
  49. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
  50. data/lib/musa-dsl/datasets/score.rb +279 -0
  51. data/lib/musa-dsl/datasets/v.rb +88 -0
  52. data/lib/musa-dsl/generative/darwin.rb +215 -1
  53. data/lib/musa-dsl/generative/generative-grammar.rb +387 -0
  54. data/lib/musa-dsl/generative/markov.rb +135 -3
  55. data/lib/musa-dsl/generative/rules.rb +312 -4
  56. data/lib/musa-dsl/generative/variatio.rb +286 -2
  57. data/lib/musa-dsl/logger/logger.rb +267 -2
  58. data/lib/musa-dsl/matrix/matrix.rb +256 -10
  59. data/lib/musa-dsl/midi/midi-recorder.rb +113 -2
  60. data/lib/musa-dsl/midi/midi-voices.rb +275 -4
  61. data/lib/musa-dsl/music/chord-definition.rb +233 -1
  62. data/lib/musa-dsl/music/chord-definitions.rb +33 -6
  63. data/lib/musa-dsl/music/chords.rb +353 -2
  64. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +70 -206
  65. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_dominant_scale_kind.rb +110 -0
  66. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_major_scale_kind.rb +110 -0
  67. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_minor_scale_kind.rb +110 -0
  68. data/lib/musa-dsl/music/scale_kinds/blues/blues_major_scale_kind.rb +100 -0
  69. data/lib/musa-dsl/music/scale_kinds/blues/blues_scale_kind.rb +99 -0
  70. data/lib/musa-dsl/music/scale_kinds/chromatic_scale_kind.rb +79 -0
  71. data/lib/musa-dsl/music/scale_kinds/ethnic/double_harmonic_scale_kind.rb +102 -0
  72. data/lib/musa-dsl/music/scale_kinds/ethnic/hungarian_minor_scale_kind.rb +102 -0
  73. data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_major_scale_kind.rb +102 -0
  74. data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_minor_scale_kind.rb +101 -0
  75. data/lib/musa-dsl/music/scale_kinds/ethnic/phrygian_dominant_scale_kind.rb +103 -0
  76. data/lib/musa-dsl/music/scale_kinds/harmonic_major/harmonic_major_scale_kind.rb +104 -0
  77. data/lib/musa-dsl/music/scale_kinds/major_scale_kind.rb +110 -0
  78. data/lib/musa-dsl/music/scale_kinds/melodic_minor/altered_scale_kind.rb +106 -0
  79. data/lib/musa-dsl/music/scale_kinds/melodic_minor/dorian_b2_scale_kind.rb +104 -0
  80. data/lib/musa-dsl/music/scale_kinds/melodic_minor/locrian_sharp2_scale_kind.rb +103 -0
  81. data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_augmented_scale_kind.rb +103 -0
  82. data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_dominant_scale_kind.rb +106 -0
  83. data/lib/musa-dsl/music/scale_kinds/melodic_minor/melodic_minor_scale_kind.rb +104 -0
  84. data/lib/musa-dsl/music/scale_kinds/melodic_minor/mixolydian_b6_scale_kind.rb +103 -0
  85. data/lib/musa-dsl/music/scale_kinds/minor_harmonic_scale_kind.rb +125 -0
  86. data/lib/musa-dsl/music/scale_kinds/minor_natural_scale_kind.rb +123 -0
  87. data/lib/musa-dsl/music/scale_kinds/modes/dorian_scale_kind.rb +111 -0
  88. data/lib/musa-dsl/music/scale_kinds/modes/locrian_scale_kind.rb +114 -0
  89. data/lib/musa-dsl/music/scale_kinds/modes/lydian_scale_kind.rb +111 -0
  90. data/lib/musa-dsl/music/scale_kinds/modes/mixolydian_scale_kind.rb +111 -0
  91. data/lib/musa-dsl/music/scale_kinds/modes/phrygian_scale_kind.rb +111 -0
  92. data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_major_scale_kind.rb +93 -0
  93. data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_minor_scale_kind.rb +99 -0
  94. data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_hw_scale_kind.rb +110 -0
  95. data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_wh_scale_kind.rb +110 -0
  96. data/lib/musa-dsl/music/scale_kinds/symmetric/whole_tone_scale_kind.rb +99 -0
  97. data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +80 -0
  98. data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +60 -0
  99. data/lib/musa-dsl/music/scales.rb +1384 -40
  100. data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
  101. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
  102. data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
  103. data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
  104. data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
  105. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
  106. data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
  107. data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
  108. data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
  109. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
  110. data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
  111. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
  112. data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
  113. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
  114. data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
  115. data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
  116. data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
  117. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
  118. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
  119. data/lib/musa-dsl/neumas/neumas.rb +67 -0
  120. data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
  121. data/lib/musa-dsl/repl/repl.rb +550 -0
  122. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
  123. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
  124. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
  125. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
  126. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
  127. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
  128. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
  129. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
  130. data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
  131. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
  132. data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
  133. data/lib/musa-dsl/series/array-to-serie.rb +37 -1
  134. data/lib/musa-dsl/series/base-series.rb +843 -5
  135. data/lib/musa-dsl/series/buffer-serie.rb +54 -0
  136. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +64 -0
  137. data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
  138. data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
  139. data/lib/musa-dsl/series/proxy-serie.rb +67 -0
  140. data/lib/musa-dsl/series/quantizer-serie.rb +57 -7
  141. data/lib/musa-dsl/series/queue-serie.rb +78 -0
  142. data/lib/musa-dsl/series/series-composer.rb +701 -0
  143. data/lib/musa-dsl/series/timed-serie.rb +473 -28
  144. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
  145. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
  146. data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
  147. data/lib/musa-dsl/transcription/transcription.rb +265 -0
  148. data/lib/musa-dsl/transport/clock.rb +125 -0
  149. data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
  150. data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
  151. data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
  152. data/lib/musa-dsl/transport/timer-clock.rb +183 -1
  153. data/lib/musa-dsl/transport/timer.rb +83 -0
  154. data/lib/musa-dsl/transport/transport.rb +318 -0
  155. data/lib/musa-dsl/version.rb +2 -1
  156. data/lib/musa-dsl.rb +132 -25
  157. data/musa-dsl.gemspec +25 -18
  158. metadata +158 -16
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Musa
4
+ module Scales
5
+ # Diminished half-whole scale kind.
6
+ #
7
+ # DiminishedHWScaleKind defines the half-whole diminished scale (also called
8
+ # octatonic scale), an eight-note symmetric scale alternating half steps and
9
+ # whole steps. It's commonly used over diminished 7th chords.
10
+ #
11
+ # ## Pitch Structure
12
+ #
13
+ # 8 degrees plus extended:
14
+ #
15
+ # **Scale Degrees** (pattern: H-W-H-W-H-W-H-W):
16
+ #
17
+ # - **i** (_1): Root (0 semitones)
18
+ # - **ii** (_2): Minor second (1 semitone)
19
+ # - **iii** (_3): Minor third (3 semitones)
20
+ # - **iv** (_4): Major third (4 semitones)
21
+ # - **v** (_5): Diminished fifth (6 semitones)
22
+ # - **vi** (_6): Perfect fifth (7 semitones)
23
+ # - **vii** (_7): Major sixth (9 semitones)
24
+ # - **viii** (_8): Minor seventh (10 semitones)
25
+ #
26
+ # ## Symmetric Properties
27
+ #
28
+ # - Only 3 distinct diminished scales exist
29
+ # - Repeats every minor third (3 semitones)
30
+ # - Contains 4 minor thirds, 4 major thirds, 2 tritones
31
+ # - Every diminished 7th chord is contained within
32
+ #
33
+ # ## Musical Character
34
+ #
35
+ # The half-whole diminished scale:
36
+ #
37
+ # - Tense, dark, unstable quality
38
+ # - Used over diminished 7th chords
39
+ # - Common in jazz, film scores, classical
40
+ # - Creates strong chromatic tension
41
+ #
42
+ # ## Usage
43
+ #
44
+ # c_dim = Scales[:et12][440.0][:diminished_hw][60]
45
+ # c_dim[0].pitch # C (60)
46
+ # c_dim[1].pitch # Db (61)
47
+ #
48
+ # @see ScaleKind Abstract base class
49
+ # @see DiminishedWHScaleKind Whole-half diminished (dominant diminished)
50
+ # @see WholeToneScaleKind Whole tone scale
51
+ class DiminishedHWScaleKind < ScaleKind
52
+ @base_metadata = {
53
+ family: :symmetric,
54
+ brightness: nil,
55
+ character: [:diminished, :tense, :jazz],
56
+ parent: nil
57
+ }.freeze
58
+
59
+ class << self
60
+ @@pitches =
61
+ [{ functions: %i[i _1 tonic first],
62
+ pitch: 0 },
63
+ { functions: %i[ii _2 second],
64
+ pitch: 1 },
65
+ { functions: %i[iii _3 third],
66
+ pitch: 3 },
67
+ { functions: %i[iv _4 fourth],
68
+ pitch: 4 },
69
+ { functions: %i[v _5 fifth],
70
+ pitch: 6 },
71
+ { functions: %i[vi _6 sixth],
72
+ pitch: 7 },
73
+ { functions: %i[vii _7 seventh],
74
+ pitch: 9 },
75
+ { functions: %i[viii _8 eighth],
76
+ pitch: 10 },
77
+ { functions: %i[ix _9 ninth],
78
+ pitch: 12 },
79
+ { functions: %i[x _10 tenth],
80
+ pitch: 12 + 1 },
81
+ { functions: %i[xi _11 eleventh],
82
+ pitch: 12 + 3 },
83
+ { functions: %i[xii _12 twelfth],
84
+ pitch: 12 + 4 },
85
+ { functions: %i[xiii _13 thirteenth],
86
+ pitch: 12 + 6 },
87
+ { functions: %i[xiv _14 fourteenth],
88
+ pitch: 12 + 7 },
89
+ { functions: %i[xv _15 fifteenth],
90
+ pitch: 12 + 9 },
91
+ { functions: %i[xvi _16 sixteenth],
92
+ pitch: 12 + 10 }].freeze
93
+
94
+ def pitches
95
+ @@pitches
96
+ end
97
+
98
+ def grades
99
+ 8
100
+ end
101
+
102
+ def id
103
+ :diminished_hw
104
+ end
105
+ end
106
+
107
+ EquallyTempered12ToneScaleSystem.register DiminishedHWScaleKind
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Musa
4
+ module Scales
5
+ # Diminished whole-half scale kind.
6
+ #
7
+ # DiminishedWHScaleKind defines the whole-half diminished scale (also called
8
+ # dominant diminished), an eight-note symmetric scale alternating whole steps
9
+ # and half steps. It's commonly used over dominant 7th chords with altered tensions.
10
+ #
11
+ # ## Pitch Structure
12
+ #
13
+ # 8 degrees plus extended:
14
+ #
15
+ # **Scale Degrees** (pattern: W-H-W-H-W-H-W-H):
16
+ #
17
+ # - **I** (_1): Root (0 semitones)
18
+ # - **II** (_2): Major second (2 semitones)
19
+ # - **III** (_3): Minor third (3 semitones)
20
+ # - **IV** (_4): Perfect fourth (5 semitones)
21
+ # - **V** (_5): Diminished fifth (6 semitones)
22
+ # - **VI** (_6): Augmented fifth (8 semitones)
23
+ # - **VII** (_7): Major sixth (9 semitones)
24
+ # - **VIII** (_8): Major seventh (11 semitones)
25
+ #
26
+ # ## Symmetric Properties
27
+ #
28
+ # - Only 3 distinct diminished scales exist
29
+ # - Repeats every minor third (3 semitones)
30
+ # - Same notes as half-whole, but different starting point
31
+ # - Contains natural 9, #9, #11, 13 over dominant chord
32
+ #
33
+ # ## Musical Character
34
+ #
35
+ # The whole-half diminished scale:
36
+ #
37
+ # - Used over dominant 7th chords (hence "dominant diminished")
38
+ # - Provides b9, #9, #11, and natural 13 tensions
39
+ # - Common in bebop and modern jazz
40
+ # - Creates sophisticated altered dominant sound
41
+ #
42
+ # ## Usage
43
+ #
44
+ # g_dom_dim = Scales[:et12][440.0][:diminished_wh][67]
45
+ # g_dom_dim[0].pitch # G (67)
46
+ # g_dom_dim[1].pitch # A (69)
47
+ #
48
+ # @see ScaleKind Abstract base class
49
+ # @see DiminishedHWScaleKind Half-whole diminished
50
+ # @see AlteredScaleKind Altered scale (another dominant scale)
51
+ class DiminishedWHScaleKind < ScaleKind
52
+ @base_metadata = {
53
+ family: :symmetric,
54
+ brightness: nil,
55
+ character: [:diminished, :dominant, :jazz],
56
+ parent: nil
57
+ }.freeze
58
+
59
+ class << self
60
+ @@pitches =
61
+ [{ functions: %i[I _1 tonic first],
62
+ pitch: 0 },
63
+ { functions: %i[II _2 second],
64
+ pitch: 2 },
65
+ { functions: %i[III _3 third],
66
+ pitch: 3 },
67
+ { functions: %i[IV _4 fourth],
68
+ pitch: 5 },
69
+ { functions: %i[V _5 fifth],
70
+ pitch: 6 },
71
+ { functions: %i[VI _6 sixth],
72
+ pitch: 8 },
73
+ { functions: %i[VII _7 seventh],
74
+ pitch: 9 },
75
+ { functions: %i[VIII _8 eighth],
76
+ pitch: 11 },
77
+ { functions: %i[IX _9 ninth],
78
+ pitch: 12 },
79
+ { functions: %i[X _10 tenth],
80
+ pitch: 12 + 2 },
81
+ { functions: %i[XI _11 eleventh],
82
+ pitch: 12 + 3 },
83
+ { functions: %i[XII _12 twelfth],
84
+ pitch: 12 + 5 },
85
+ { functions: %i[XIII _13 thirteenth],
86
+ pitch: 12 + 6 },
87
+ { functions: %i[XIV _14 fourteenth],
88
+ pitch: 12 + 8 },
89
+ { functions: %i[XV _15 fifteenth],
90
+ pitch: 12 + 9 },
91
+ { functions: %i[XVI _16 sixteenth],
92
+ pitch: 12 + 11 }].freeze
93
+
94
+ def pitches
95
+ @@pitches
96
+ end
97
+
98
+ def grades
99
+ 8
100
+ end
101
+
102
+ def id
103
+ :diminished_wh
104
+ end
105
+ end
106
+
107
+ EquallyTempered12ToneScaleSystem.register DiminishedWHScaleKind
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Musa
4
+ module Scales
5
+ # Whole tone scale kind.
6
+ #
7
+ # WholeToneScaleKind defines the whole tone scale, a six-note symmetric
8
+ # scale where every interval is a whole step (major second). It has a
9
+ # dreamy, ambiguous quality with no clear tonal center.
10
+ #
11
+ # ## Pitch Structure
12
+ #
13
+ # 6 degrees plus extended:
14
+ #
15
+ # **Scale Degrees**:
16
+ #
17
+ # - **I** (_1): Root (0 semitones)
18
+ # - **II** (_2): Major second (2 semitones)
19
+ # - **III** (_3): Major third (4 semitones)
20
+ # - **IV#** (_4): Augmented fourth (6 semitones)
21
+ # - **V#** (_5): Augmented fifth (8 semitones)
22
+ # - **VII** (_6): Minor seventh (10 semitones)
23
+ #
24
+ # ## Symmetric Properties
25
+ #
26
+ # - Only 2 distinct whole tone scales exist (C and C#)
27
+ # - Every note can function as the root
28
+ # - Divides the octave into 6 equal parts
29
+ # - No perfect fifths = no strong harmonic function
30
+ #
31
+ # ## Musical Character
32
+ #
33
+ # The whole tone scale:
34
+ #
35
+ # - Dreamy, floating, ambiguous quality
36
+ # - No leading tones or tendency tones
37
+ # - Associated with impressionism (Debussy)
38
+ # - Used over augmented and dominant 7#5 chords
39
+ #
40
+ # ## Usage
41
+ #
42
+ # c_whole = Scales[:et12][440.0][:whole_tone][60]
43
+ # c_whole[0].pitch # C (60)
44
+ # c_whole[3].pitch # F# (66)
45
+ #
46
+ # @see ScaleKind Abstract base class
47
+ # @see DiminishedHWScaleKind Diminished scale (another symmetric scale)
48
+ class WholeToneScaleKind < ScaleKind
49
+ @base_metadata = {
50
+ family: :symmetric,
51
+ brightness: nil,
52
+ character: [:floating, :impressionist, :ambiguous],
53
+ parent: nil
54
+ }.freeze
55
+
56
+ class << self
57
+ @@pitches =
58
+ [{ functions: %i[I _1 tonic first],
59
+ pitch: 0 },
60
+ { functions: %i[II _2 second],
61
+ pitch: 2 },
62
+ { functions: %i[III _3 third],
63
+ pitch: 4 },
64
+ { functions: %i[IV _4 fourth],
65
+ pitch: 6 },
66
+ { functions: %i[V _5 fifth],
67
+ pitch: 8 },
68
+ { functions: %i[VI _6 sixth],
69
+ pitch: 10 },
70
+ { functions: %i[VII _7 seventh],
71
+ pitch: 12 },
72
+ { functions: %i[VIII _8 eighth],
73
+ pitch: 12 + 2 },
74
+ { functions: %i[IX _9 ninth],
75
+ pitch: 12 + 4 },
76
+ { functions: %i[X _10 tenth],
77
+ pitch: 12 + 6 },
78
+ { functions: %i[XI _11 eleventh],
79
+ pitch: 12 + 8 },
80
+ { functions: %i[XII _12 twelfth],
81
+ pitch: 12 + 10 }].freeze
82
+
83
+ def pitches
84
+ @@pitches
85
+ end
86
+
87
+ def grades
88
+ 6
89
+ end
90
+
91
+ def id
92
+ :whole_tone
93
+ end
94
+ end
95
+
96
+ EquallyTempered12ToneScaleSystem.register WholeToneScaleKind
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'twelve_semitones_scale_system'
4
+
5
+ module Musa
6
+ module Scales
7
+ # Equal temperament 12-tone scale system.
8
+ #
9
+ # EquallyTempered12ToneScaleSystem implements the standard equal temperament
10
+ # tuning where each semitone has exactly the same frequency ratio: 2^(1/12).
11
+ # This is the most common tuning system in modern Western music.
12
+ #
13
+ # ## Frequency Calculation
14
+ #
15
+ # Uses the equal temperament formula based on A440 concert pitch:
16
+ #
17
+ # frequency = a_frequency × 2^((pitch - 69) / 12)
18
+ #
19
+ # Where:
20
+ #
21
+ # - **a_frequency**: Reference A frequency (typically 440 Hz)
22
+ # - **pitch**: MIDI pitch number (69 = A4)
23
+ #
24
+ # ## Historical Pitch Standards
25
+ #
26
+ # Different A frequencies represent different historical standards:
27
+ #
28
+ # - **440 Hz**: Modern concert pitch (ISO 16)
29
+ # - **442 Hz**: Used by some orchestras (brighter sound)
30
+ # - **415 Hz**: Baroque pitch (approximately A=415)
31
+ # - **432 Hz**: Alternative tuning (some claim harmonic benefits)
32
+ #
33
+ # ## Registration
34
+ #
35
+ # This system is registered as the default scale system, accessible via:
36
+ #
37
+ # Scales[:et12] # By ID
38
+ # Scales.default_system # As default
39
+ #
40
+ # ## Usage
41
+ #
42
+ # # Get system with standard A440 tuning
43
+ # system = Scales[:et12][440.0]
44
+ #
45
+ # # Get system with baroque tuning
46
+ # baroque = Scales[:et12][415.0]
47
+ #
48
+ # # Access scale kinds
49
+ # c_major = system[:major][60]
50
+ # a_minor = system[:minor][69]
51
+ #
52
+ # @see TwelveSemitonesScaleSystem Abstract base class
53
+ # @see ScaleSystem#frequency_of_pitch Abstract method implemented here
54
+ class EquallyTempered12ToneScaleSystem < TwelveSemitonesScaleSystem
55
+ class << self
56
+ # Calculates frequency for a pitch using equal temperament.
57
+ #
58
+ # Implements the equal temperament tuning formula where each semitone
59
+ # has a frequency ratio of 2^(1/12) ≈ 1.059463.
60
+ #
61
+ # @param pitch [Integer] MIDI pitch number
62
+ # @param _root_pitch [Integer] unused (required by interface)
63
+ # @param a_frequency [Numeric] reference A4 frequency in Hz
64
+ # @return [Float] frequency in Hz
65
+ #
66
+ # @example Standard A440 tuning
67
+ # frequency_of_pitch(69, nil, 440.0) # => 440.0 (A4)
68
+ # frequency_of_pitch(60, nil, 440.0) # => 261.63 (C4, middle C)
69
+ #
70
+ # @example Baroque tuning
71
+ # frequency_of_pitch(69, nil, 415.0) # => 415.0 (A4)
72
+ def frequency_of_pitch(pitch, _root_pitch, a_frequency)
73
+ (a_frequency * Rational(2)**Rational(pitch - 69, 12)).to_f
74
+ end
75
+ end
76
+
77
+ Scales.register EquallyTempered12ToneScaleSystem, default: true
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Musa
4
+ module Scales
5
+ # Base class for 12-semitone scale systems.
6
+ #
7
+ # TwelveSemitonesScaleSystem provides the foundation for any scale system
8
+ # using 12 semitones per octave. It defines intervals and structure but
9
+ # doesn't specify tuning (frequency calculation).
10
+ #
11
+ # Concrete subclasses must implement frequency calculation:
12
+ #
13
+ # - {EquallyTempered12ToneScaleSystem}: Equal temperament (12-TET)
14
+ # - Other temperaments could be added (e.g., meantone, just intonation)
15
+ #
16
+ # ## Intervals
17
+ #
18
+ # Defines standard interval names using semitone distances:
19
+ #
20
+ # { P0: 0, m2: 1, M2: 2, m3: 3, M3: 4, P4: 5, TT: 6,
21
+ # P5: 7, m6: 8, M6: 9, m7: 10, M7: 11, P8: 12 }
22
+ #
23
+ # @abstract Subclasses must implement {frequency_of_pitch}
24
+ # @see EquallyTempered12ToneScaleSystem Concrete equal temperament implementation
25
+ class TwelveSemitonesScaleSystem < ScaleSystem
26
+ class << self
27
+ @@intervals = { P0: 0, m2: 1, M2: 2, m3: 3, M3: 4, P4: 5, TT: 6, P5: 7, m6: 8, M6: 9, m7: 10, M7: 11, P8: 12 }
28
+
29
+ # System identifier.
30
+ # @return [Symbol] :et12
31
+ def id
32
+ :et12
33
+ end
34
+
35
+ # Number of distinct notes per octave.
36
+ # @return [Integer] 12
37
+ def notes_in_octave
38
+ 12
39
+ end
40
+
41
+ # Size of smallest pitch division.
42
+ # @return [Integer] 1 (semitone)
43
+ def part_of_tone_size
44
+ 1
45
+ end
46
+
47
+ # Interval definitions.
48
+ #
49
+ # @return [Hash{Symbol => Integer}] interval name to semitones mapping
50
+ #
51
+ # @example
52
+ # intervals[:P5] # => 7 (perfect fifth)
53
+ # intervals[:M3] # => 4 (major third)
54
+ def intervals
55
+ @@intervals
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end