musa-dsl 0.30.2 → 0.40.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.version +6 -0
  4. data/.yardopts +7 -0
  5. data/README.md +227 -6
  6. data/docs/README.md +83 -0
  7. data/docs/api-reference.md +86 -0
  8. data/docs/getting-started/quick-start.md +93 -0
  9. data/docs/getting-started/tutorial.md +58 -0
  10. data/docs/subsystems/core-extensions.md +316 -0
  11. data/docs/subsystems/datasets.md +465 -0
  12. data/docs/subsystems/generative.md +290 -0
  13. data/docs/subsystems/matrix.md +63 -0
  14. data/docs/subsystems/midi.md +123 -0
  15. data/docs/subsystems/music.md +233 -0
  16. data/docs/subsystems/musicxml-builder.md +264 -0
  17. data/docs/subsystems/neumas.md +71 -0
  18. data/docs/subsystems/repl.md +135 -0
  19. data/docs/subsystems/sequencer.md +98 -0
  20. data/docs/subsystems/series.md +302 -0
  21. data/docs/subsystems/transcription.md +152 -0
  22. data/docs/subsystems/transport.md +177 -0
  23. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
  24. data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
  25. data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
  26. data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
  27. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
  28. data/lib/musa-dsl/core-ext/extension.rb +53 -0
  29. data/lib/musa-dsl/core-ext/hashify.rb +162 -1
  30. data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
  31. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
  32. data/lib/musa-dsl/core-ext/with.rb +114 -0
  33. data/lib/musa-dsl/datasets/dataset.rb +109 -0
  34. data/lib/musa-dsl/datasets/delta-d.rb +78 -0
  35. data/lib/musa-dsl/datasets/e.rb +186 -2
  36. data/lib/musa-dsl/datasets/gdv.rb +279 -2
  37. data/lib/musa-dsl/datasets/gdvd.rb +201 -0
  38. data/lib/musa-dsl/datasets/helper.rb +75 -0
  39. data/lib/musa-dsl/datasets/p.rb +177 -2
  40. data/lib/musa-dsl/datasets/packed-v.rb +91 -0
  41. data/lib/musa-dsl/datasets/pdv.rb +136 -1
  42. data/lib/musa-dsl/datasets/ps.rb +134 -4
  43. data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
  44. data/lib/musa-dsl/datasets/score/render.rb +105 -1
  45. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
  46. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
  47. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
  48. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
  49. data/lib/musa-dsl/datasets/score.rb +279 -0
  50. data/lib/musa-dsl/datasets/v.rb +88 -0
  51. data/lib/musa-dsl/generative/darwin.rb +180 -1
  52. data/lib/musa-dsl/generative/generative-grammar.rb +359 -0
  53. data/lib/musa-dsl/generative/markov.rb +133 -3
  54. data/lib/musa-dsl/generative/rules.rb +258 -4
  55. data/lib/musa-dsl/generative/variatio.rb +217 -2
  56. data/lib/musa-dsl/logger/logger.rb +267 -2
  57. data/lib/musa-dsl/matrix/matrix.rb +256 -10
  58. data/lib/musa-dsl/midi/midi-recorder.rb +108 -1
  59. data/lib/musa-dsl/midi/midi-voices.rb +265 -4
  60. data/lib/musa-dsl/music/chord-definition.rb +233 -1
  61. data/lib/musa-dsl/music/chord-definitions.rb +33 -6
  62. data/lib/musa-dsl/music/chords.rb +308 -2
  63. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +315 -0
  64. data/lib/musa-dsl/music/scales.rb +957 -40
  65. data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
  66. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
  67. data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
  68. data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
  69. data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
  70. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
  71. data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
  72. data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
  73. data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
  74. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
  75. data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
  76. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
  77. data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
  78. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
  79. data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
  80. data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
  81. data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
  82. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
  83. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
  84. data/lib/musa-dsl/neumas/neumas.rb +67 -0
  85. data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
  86. data/lib/musa-dsl/repl/repl.rb +550 -0
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
  89. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
  90. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
  91. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
  92. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
  93. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
  94. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
  95. data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
  96. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
  97. data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
  98. data/lib/musa-dsl/series/array-to-serie.rb +37 -1
  99. data/lib/musa-dsl/series/base-series.rb +843 -5
  100. data/lib/musa-dsl/series/buffer-serie.rb +48 -0
  101. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +41 -0
  102. data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
  103. data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
  104. data/lib/musa-dsl/series/proxy-serie.rb +67 -0
  105. data/lib/musa-dsl/series/quantizer-serie.rb +45 -7
  106. data/lib/musa-dsl/series/queue-serie.rb +65 -0
  107. data/lib/musa-dsl/series/series-composer.rb +701 -0
  108. data/lib/musa-dsl/series/timed-serie.rb +473 -28
  109. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
  110. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
  111. data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
  112. data/lib/musa-dsl/transcription/transcription.rb +265 -0
  113. data/lib/musa-dsl/transport/clock.rb +125 -0
  114. data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
  115. data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
  116. data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
  117. data/lib/musa-dsl/transport/timer-clock.rb +183 -1
  118. data/lib/musa-dsl/transport/timer.rb +83 -0
  119. data/lib/musa-dsl/transport/transport.rb +318 -0
  120. data/lib/musa-dsl/version.rb +1 -1
  121. data/lib/musa-dsl.rb +132 -25
  122. data/musa-dsl.gemspec +12 -10
  123. metadata +87 -8
@@ -4,31 +4,196 @@ module Musa
4
4
  module MusicXML
5
5
  module Builder
6
6
  module Internal
7
+ # Timeline rewind for polyphonic music.
8
+ #
9
+ # Backup moves the musical timeline backwards by a specified duration,
10
+ # allowing overlapping musical content to be written sequentially.
11
+ # This is essential for polyphonic music where multiple voices or staves
12
+ # play simultaneously.
13
+ #
14
+ # ## Use Cases
15
+ #
16
+ # **Multiple Voices**: Write voice 1, backup, then write voice 2 starting
17
+ # at the same timepoint.
18
+ #
19
+ # **Multi-Staff Instruments**: Write treble staff notes, backup, then write
20
+ # bass staff notes for the same measure.
21
+ #
22
+ # **Polyphonic Textures**: Layer independent melodic lines that share
23
+ # temporal alignment.
24
+ #
25
+ # ## Duration Units
26
+ #
27
+ # Duration is specified in the measure's division units (not note values).
28
+ # If divisions=4, then duration=8 means 8 divisions = 2 quarter notes = 1 half note.
29
+ #
30
+ # Common pattern: backup by the full measure duration to restart from the
31
+ # beginning of the measure.
32
+ #
33
+ # ## Workflow Example
34
+ #
35
+ # 1. Write notes for voice 1
36
+ # 2. Backup to measure start
37
+ # 3. Write notes for voice 2 (with voice: 2 parameter)
38
+ # 4. Optionally backup again for additional voices
39
+ #
40
+ # @example Piano with simultaneous treble and bass
41
+ # measure.pitch 'D', octave: 4, duration: 4, type: 'half'
42
+ # measure.pitch 'E', octave: 4, duration: 4, type: 'half'
43
+ #
44
+ # measure.backup 8 # Rewind full measure (8 divisions)
45
+ #
46
+ # measure.pitch 'C', octave: 3, duration: 8, type: 'whole', staff: 2
47
+ #
48
+ # @example Two voices on the same staff
49
+ # measure.pitch 'C', octave: 5, duration: 2, type: 'quarter', voice: 1
50
+ # measure.pitch 'D', octave: 5, duration: 2, type: 'quarter', voice: 1
51
+ # measure.pitch 'E', octave: 5, duration: 2, type: 'quarter', voice: 1
52
+ # measure.pitch 'F', octave: 5, duration: 2, type: 'quarter', voice: 1
53
+ #
54
+ # measure.backup 8 # Back to measure start
55
+ #
56
+ # measure.pitch 'E', octave: 4, duration: 4, type: 'half', voice: 2
57
+ # measure.pitch 'F', octave: 4, duration: 4, type: 'half', voice: 2
58
+ #
59
+ # @example Three-voice polyphony
60
+ # # Voice 1
61
+ # measure.pitch 'G', octave: 5, duration: 8, type: 'whole', voice: 1
62
+ #
63
+ # measure.backup 8
64
+ #
65
+ # # Voice 2
66
+ # measure.pitch 'C', octave: 5, duration: 8, type: 'whole', voice: 2
67
+ #
68
+ # measure.backup 8
69
+ #
70
+ # # Voice 3
71
+ # measure.pitch 'E', octave: 4, duration: 8, type: 'whole', voice: 3
72
+ #
73
+ # @see Forward Forward navigation for skipping time
7
74
  class Backup
8
75
  include Helper::ToXML
9
76
 
77
+ # Creates a backup (timeline rewind).
78
+ #
79
+ # @param duration [Integer] rewind amount in division units
80
+ #
81
+ # @example Rewind full measure (divisions=4, 4/4 time)
82
+ # Backup.new(8) # 8 divisions = 2 quarter notes
83
+ #
84
+ # @example Rewind half measure
85
+ # Backup.new(4) # 4 divisions = 1 quarter note
10
86
  def initialize(duration)
11
87
  @duration = duration
12
88
  end
13
89
 
90
+ # Duration to rewind in division units.
91
+ # @return [Integer]
14
92
  attr_accessor :duration
15
93
 
94
+ # Generates the backup XML element.
95
+ #
96
+ # @param io [IO] output stream
97
+ # @param indent [Integer] indentation level
98
+ # @param tabs [String] tab string
99
+ # @return [void]
100
+ #
101
+ # @api private
16
102
  def _to_xml(io, indent:, tabs:)
17
103
  io.puts "#{tabs}<backup><duration>#{@duration.to_i}</duration></backup>"
18
104
  end
19
105
  end
20
106
 
107
+ # Timeline advance without producing sound.
108
+ #
109
+ # Forward moves the musical timeline forward by a specified duration
110
+ # without generating notes or rests. It's used for positioning within
111
+ # multi-voice contexts and creating invisible space.
112
+ #
113
+ # ## Use Cases
114
+ #
115
+ # **Voice Positioning**: Advance to a specific point in time before
116
+ # adding notes in a particular voice.
117
+ #
118
+ # **Invisible Rests**: Skip time without displaying rest symbols
119
+ # (useful in multi-voice scenarios where another voice fills the space).
120
+ #
121
+ # **Rhythmic Offset**: Start a voice partway through a measure without
122
+ # explicit rest notation.
123
+ #
124
+ # ## Duration Units
125
+ #
126
+ # Duration is specified in the measure's division units (not note values).
127
+ # If divisions=4, then duration=2 means 2 divisions = 1 eighth note.
128
+ #
129
+ # ## Voice and Staff
130
+ #
131
+ # Optional voice and staff parameters indicate which voice/staff the
132
+ # forward applies to. This helps notation software correctly position
133
+ # subsequent notes.
134
+ #
135
+ # @example Skip a quarter note in voice 2
136
+ # measure.forward 2, voice: 2 # Skip 2 divisions in voice 2
137
+ # measure.pitch 'C', octave: 5, duration: 2, type: 'quarter', voice: 2
138
+ #
139
+ # @example Offset entry on bass staff
140
+ # measure.forward 4, staff: 2 # Skip half measure on bass staff
141
+ # measure.pitch 'C', octave: 3, duration: 4, type: 'half', staff: 2
142
+ #
143
+ # @example Multi-voice with staggered entries
144
+ # # Voice 1 starts immediately
145
+ # measure.pitch 'G', octave: 5, duration: 4, type: 'half', voice: 1
146
+ #
147
+ # measure.backup 4 # Return to measure start
148
+ #
149
+ # # Voice 2 starts after quarter note delay
150
+ # measure.forward 2, voice: 2 # Skip quarter note
151
+ # measure.pitch 'E', octave: 5, duration: 2, type: 'quarter', voice: 2
152
+ #
153
+ # @see Backup Backup for timeline rewind
21
154
  class Forward
22
155
  include Helper::ToXML
23
156
 
157
+ # Creates a forward (timeline advance).
158
+ #
159
+ # @param duration [Integer] advance amount in division units
160
+ # @param voice [Integer, nil] voice number this forward applies to
161
+ # @param staff [Integer, nil] staff number this forward applies to
162
+ #
163
+ # @example Skip quarter note
164
+ # Forward.new(2) # 2 divisions
165
+ #
166
+ # @example Skip with voice specification
167
+ # Forward.new(4, voice: 2)
168
+ #
169
+ # @example Skip on specific staff
170
+ # Forward.new(4, staff: 2)
24
171
  def initialize(duration, voice: nil, staff: nil)
25
172
  @duration = duration
26
173
  @voice = voice
27
174
  @staff = staff
28
175
  end
29
176
 
30
- attr_accessor :duration, :voice, :staff
177
+ # Duration to advance in division units.
178
+ # @return [Integer]
179
+ attr_accessor :duration
180
+
181
+ # Voice number (for multi-voice contexts).
182
+ # @return [Integer, nil]
183
+ attr_accessor :voice
184
+
185
+ # Staff number (for multi-staff instruments).
186
+ # @return [Integer, nil]
187
+ attr_accessor :staff
31
188
 
189
+ # Generates the forward XML element.
190
+ #
191
+ # @param io [IO] output stream
192
+ # @param indent [Integer] indentation level
193
+ # @param tabs [String] tab string
194
+ # @return [void]
195
+ #
196
+ # @api private
32
197
  def _to_xml(io, indent:, tabs:)
33
198
  io.puts "#{tabs}<forward>"
34
199
 
@@ -7,6 +7,69 @@ module Musa
7
7
  module Internal
8
8
  using Musa::Extension::Arrayfy
9
9
 
10
+ # Musical direction container.
11
+ #
12
+ # Direction represents performance instructions and expressive markings that
13
+ # affect interpretation but aren't part of the note structure. Directions
14
+ # include tempo, dynamics, pedaling, text instructions, and other musical
15
+ # indications.
16
+ #
17
+ # ## Direction Types
18
+ #
19
+ # Directions can contain multiple direction-type elements:
20
+ #
21
+ # ### Tempo and Metronome
22
+ # - **Metronome**: Tempo markings (♩ = 120, etc.)
23
+ # - **Words**: Textual tempo indications ("Allegro", "Adagio")
24
+ #
25
+ # ### Dynamics
26
+ # - **Dynamics**: Dynamic levels (pp, p, mp, mf, f, ff, etc.)
27
+ # - **Wedge**: Crescendo/diminuendo hairpins
28
+ #
29
+ # ### Pedaling
30
+ # - **Pedal**: Piano pedal markings (start, stop, change)
31
+ #
32
+ # ### Text and Symbols
33
+ # - **Words**: General text directions
34
+ # - **Bracket**: Analytical brackets
35
+ # - **Dashes**: Dashed extension lines
36
+ #
37
+ # ### Transposition
38
+ # - **OctaveShift**: 8va/8vb markings
39
+ #
40
+ # ## Placement
41
+ #
42
+ # Directions can be placed above or below the staff:
43
+ # - **above**: Above staff (typical for tempo, dynamics)
44
+ # - **below**: Below staff (typical for pedal markings)
45
+ #
46
+ # ## Voice and Staff
47
+ #
48
+ # For multi-voice or multi-staff contexts, directions can be associated with
49
+ # specific voices or staves.
50
+ #
51
+ # ## Offset
52
+ #
53
+ # Directions can have timing offsets for precise positioning relative to notes.
54
+ #
55
+ # @example Tempo marking
56
+ # Direction.new(placement: 'above') do
57
+ # metronome beat_unit: 'quarter', per_minute: '120'
58
+ # words 'Allegro'
59
+ # end
60
+ #
61
+ # @example Dynamic marking
62
+ # Direction.new(placement: 'below', dynamics: 'f')
63
+ #
64
+ # @example Crescendo hairpin
65
+ # Direction.new(placement: 'below') do
66
+ # wedge 'crescendo'
67
+ # end
68
+ #
69
+ # @example Pedal down
70
+ # Direction.new(placement: 'below', pedal: 'start')
71
+ #
72
+ # @see Measure Container for directions
10
73
  class Direction
11
74
  extend Musa::Extension::AttributeBuilder
12
75
  include Musa::Extension::With
@@ -14,6 +77,28 @@ module Musa
14
77
  include Helper
15
78
  include ToXML
16
79
 
80
+ # Creates a direction.
81
+ #
82
+ # @param placement [String, nil] 'above' or 'below' staff
83
+ # @param voice [Integer, nil] voice number
84
+ # @param staff [Integer, nil] staff number
85
+ # @param offset [Numeric, nil] timing offset in divisions
86
+ # @param directions [Hash] direction types as keyword arguments
87
+ # @yield Optional DSL block for adding direction types
88
+ #
89
+ # @example Tempo with metronome
90
+ # Direction.new(placement: 'above') do
91
+ # metronome beat_unit: 'quarter', per_minute: '120'
92
+ # end
93
+ #
94
+ # @example Forte dynamic
95
+ # Direction.new(placement: 'below', dynamics: 'f')
96
+ #
97
+ # @example Multiple directions
98
+ # Direction.new(placement: 'above') do
99
+ # words 'Allegro con brio'
100
+ # metronome beat_unit: 'quarter', per_minute: '132'
101
+ # end
17
102
  def initialize(placement: nil, # above / below
18
103
  voice: nil, # number
19
104
  staff: nil, # number
@@ -35,20 +120,62 @@ module Musa
35
120
  with &block if block_given?
36
121
  end
37
122
 
123
+ # Voice builder/setter.
124
+ # @return [Integer, nil]
38
125
  attr_simple_builder :voice
126
+
127
+ # Staff builder/setter.
128
+ # @return [Integer, nil]
39
129
  attr_simple_builder :staff
130
+
131
+ # Offset builder/setter.
132
+ # @return [Numeric, nil]
40
133
  attr_simple_builder :offset
134
+
135
+ # Placement builder/setter ('above' or 'below').
136
+ # @return [String, nil]
41
137
  attr_simple_builder :placement
42
138
 
139
+ # Adds a metronome marking.
140
+ # @see Metronome
43
141
  attr_complex_adder_to_custom(:metronome) { |*p, **kp, &b| Metronome.new(*p, **kp, &b).tap { |t| @types << t } }
142
+
143
+ # Adds a wedge (crescendo/diminuendo hairpin).
144
+ # @see Wedge
44
145
  attr_complex_adder_to_custom(:wedge) { |*p, **kp, &b| Wedge.new(*p, **kp, &b).tap { |t| @types << t } }
146
+
147
+ # Adds dynamics marking.
148
+ # @see Dynamics
45
149
  attr_complex_adder_to_custom(:dynamics) { |*p, **kp, &b| Dynamics.new(*p, **kp, &b).tap { |t| @types << t } }
150
+
151
+ # Adds pedal marking.
152
+ # @see Pedal
46
153
  attr_complex_adder_to_custom(:pedal) { |*p, **kp, &b| Pedal.new(*p, **kp, &b).tap { |t| @types << t } }
154
+
155
+ # Adds bracket.
156
+ # @see Bracket
47
157
  attr_complex_adder_to_custom(:bracket) { |*p, **kp, &b| Bracket.new(*p, **kp, &b).tap { |t| @types << t } }
158
+
159
+ # Adds dashes.
160
+ # @see Dashes
48
161
  attr_complex_adder_to_custom(:dashes) { |*p, **kp, &b| Dashes.new(*p, **kp, &b).tap { |t| @types << t } }
162
+
163
+ # Adds text words.
164
+ # @see Words
49
165
  attr_complex_adder_to_custom(:words) { |*p, **kp, &b| Words.new(*p, **kp, &b).tap { |t| @types << t } }
166
+
167
+ # Adds octave shift (8va/8vb).
168
+ # @see OctaveShift
50
169
  attr_complex_adder_to_custom(:octave_shift) { |*p, **kp, &b| OctaveShift.new(*p, **kp, &b).tap { |t| @types << t } }
51
170
 
171
+ # Generates the direction XML element.
172
+ #
173
+ # @param io [IO] output stream
174
+ # @param indent [Integer] indentation level
175
+ # @param tabs [String] tab string
176
+ # @return [void]
177
+ #
178
+ # @api private
52
179
  def _to_xml(io, indent:, tabs:)
53
180
  io.puts "#{tabs}<direction#{ decode_bool_or_string_attribute(@placement, 'placement') }>"
54
181
 
@@ -87,6 +214,16 @@ module Musa
87
214
 
88
215
  private_constant :DirectionType
89
216
 
217
+ # Metronome tempo marking direction type.
218
+ #
219
+ # Represents tempo markings with beat unit and metronome value (e.g., ♩ = 120).
220
+ # Supports dotted beat units.
221
+ #
222
+ # @example Quarter note = 120 BPM
223
+ # metronome beat_unit: 'quarter', per_minute: '120'
224
+ #
225
+ # @example Dotted eighth = 90
226
+ # metronome beat_unit: 'eighth', beat_unit_dots: 1, per_minute: '90'
90
227
  class Metronome < DirectionType
91
228
  include Helper
92
229
 
@@ -121,6 +258,19 @@ module Musa
121
258
  end
122
259
  end
123
260
 
261
+ # Wedge hairpin direction type for crescendo/diminuendo.
262
+ #
263
+ # Represents dynamic hairpins (crescendo <, diminuendo >).
264
+ # Supports niente (to/from nothing) hairpins.
265
+ #
266
+ # @example Crescendo
267
+ # wedge 'crescendo'
268
+ #
269
+ # @example Diminuendo to nothing
270
+ # wedge 'diminuendo', niente: true
271
+ #
272
+ # @example Stop wedge
273
+ # wedge 'stop'
124
274
  class Wedge < DirectionType
125
275
  include Helper
126
276
 
@@ -141,6 +291,16 @@ module Musa
141
291
  end
142
292
  end
143
293
 
294
+ # Dynamic marking direction type.
295
+ #
296
+ # Represents dynamic levels (pp, p, mp, mf, f, ff, fff, etc.).
297
+ # Can specify multiple dynamics for compound markings.
298
+ #
299
+ # @example Single dynamic
300
+ # dynamics 'f'
301
+ #
302
+ # @example Multiple dynamics (sforzando-forte)
303
+ # dynamics ['sf', 'f']
144
304
  class Dynamics < DirectionType
145
305
  def initialize(value, # pp / ppp / ... or array of
146
306
  &block)
@@ -161,6 +321,19 @@ module Musa
161
321
  end
162
322
  end
163
323
 
324
+ # Piano sustain pedal marking direction type.
325
+ #
326
+ # Represents pedal down/up markings. Supports start, stop, change,
327
+ # and continue types with optional line display.
328
+ #
329
+ # @example Pedal down
330
+ # pedal 'start', line: true
331
+ #
332
+ # @example Pedal up
333
+ # pedal 'stop'
334
+ #
335
+ # @example Pedal change
336
+ # pedal 'change'
164
337
  class Pedal < DirectionType
165
338
  include Helper
166
339
 
@@ -182,6 +355,16 @@ module Musa
182
355
  end
183
356
  end
184
357
 
358
+ # Bracket direction type for analytical markings.
359
+ #
360
+ # Represents brackets used for grouping or analytical notation.
361
+ # Supports different line types and end styles.
362
+ #
363
+ # @example Start bracket
364
+ # bracket 'start', line_end: 'down', line_type: 'solid'
365
+ #
366
+ # @example Stop bracket
367
+ # bracket 'stop', line_end: 'up'
185
368
  class Bracket < DirectionType
186
369
  include Helper
187
370
 
@@ -206,6 +389,15 @@ module Musa
206
389
  end
207
390
  end
208
391
 
392
+ # Dashed line direction type.
393
+ #
394
+ # Represents dashed extension lines for text or other markings.
395
+ #
396
+ # @example Start dashed line
397
+ # dashes 'start'
398
+ #
399
+ # @example Stop dashed line
400
+ # dashes 'stop'
209
401
  class Dashes < DirectionType
210
402
  def initialize(type, # start / stop / continue
211
403
  &block)
@@ -222,6 +414,16 @@ module Musa
222
414
  end
223
415
  end
224
416
 
417
+ # Text words direction type.
418
+ #
419
+ # Represents textual performance instructions or expressions.
420
+ # Can contain multiple text strings.
421
+ #
422
+ # @example Single text
423
+ # words 'Allegro'
424
+ #
425
+ # @example Multiple texts
426
+ # words ['con', 'brio']
225
427
  class Words < DirectionType
226
428
  def initialize(value, # string | Array of string
227
429
  &block)
@@ -240,6 +442,19 @@ module Musa
240
442
  end
241
443
  end
242
444
 
445
+ # Octave shift direction type for 8va/8vb markings.
446
+ #
447
+ # Represents octave transposition markings (8va, 8vb, 15ma, 15mb).
448
+ # Type indicates up/down/stop/continue, size indicates octaves (8 or 15).
449
+ #
450
+ # @example Start 8va
451
+ # octave_shift 'up', size: 8
452
+ #
453
+ # @example Start 8vb
454
+ # octave_shift 'down', size: 8
455
+ #
456
+ # @example Stop octave shift
457
+ # octave_shift 'stop'
243
458
  class OctaveShift < DirectionType
244
459
  include Helper
245
460
 
@@ -261,58 +476,86 @@ module Musa
261
476
  end
262
477
  end
263
478
 
479
+ # Accordion registration direction type (not implemented).
480
+ # @api private
264
481
  class AccordionRegistration < DirectionType
265
482
  include Helper::NotImplemented
266
483
  end
267
484
 
485
+ # Coda symbol direction type (not implemented).
486
+ # @api private
268
487
  class Coda < DirectionType
269
488
  include Helper::NotImplemented
270
489
  end
271
490
 
491
+ # Damp (mute) marking direction type (not implemented).
492
+ # @api private
272
493
  class Damp < DirectionType
273
494
  include Helper::NotImplemented
274
495
  end
275
496
 
497
+ # Damp all strings marking direction type (not implemented).
498
+ # @api private
276
499
  class DampAll < DirectionType
277
500
  include Helper::NotImplemented
278
501
  end
279
502
 
503
+ # Eye glasses symbol direction type (not implemented).
504
+ # @api private
280
505
  class EyeGlasses < DirectionType
281
506
  include Helper::NotImplemented
282
507
  end
283
508
 
509
+ # Harp pedals diagram direction type (not implemented).
510
+ # @api private
284
511
  class HarpPedals < DirectionType
285
512
  include Helper::NotImplemented
286
513
  end
287
514
 
515
+ # Embedded image direction type (not implemented).
516
+ # @api private
288
517
  class Image < DirectionType
289
518
  include Helper::NotImplemented
290
519
  end
291
520
 
521
+ # Custom/other direction type (not implemented).
522
+ # @api private
292
523
  class OtherDirection < DirectionType
293
524
  include Helper::NotImplemented
294
525
  end
295
526
 
527
+ # Percussion notation direction type (not implemented).
528
+ # @api private
296
529
  class Percussion < DirectionType
297
530
  include Helper::NotImplemented
298
531
  end
299
532
 
533
+ # Principal voice marking direction type (not implemented).
534
+ # @api private
300
535
  class PrincipalVoice < DirectionType
301
536
  include Helper::NotImplemented
302
537
  end
303
538
 
539
+ # Rehearsal mark direction type (not implemented).
540
+ # @api private
304
541
  class Rehearsal < DirectionType
305
542
  include Helper::NotImplemented
306
543
  end
307
544
 
545
+ # Scordatura (altered tuning) direction type (not implemented).
546
+ # @api private
308
547
  class Scordatura < DirectionType
309
548
  include Helper::NotImplemented
310
549
  end
311
550
 
551
+ # Segno symbol direction type (not implemented).
552
+ # @api private
312
553
  class Segno < DirectionType
313
554
  include Helper::NotImplemented
314
555
  end
315
556
 
557
+ # String mute marking direction type (not implemented).
558
+ # @api private
316
559
  class StringMute < DirectionType
317
560
  include Helper::NotImplemented
318
561
  end