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.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.version +6 -0
- data/.yardopts +7 -0
- data/README.md +227 -6
- data/docs/README.md +83 -0
- data/docs/api-reference.md +86 -0
- data/docs/getting-started/quick-start.md +93 -0
- data/docs/getting-started/tutorial.md +58 -0
- data/docs/subsystems/core-extensions.md +316 -0
- data/docs/subsystems/datasets.md +465 -0
- data/docs/subsystems/generative.md +290 -0
- data/docs/subsystems/matrix.md +63 -0
- data/docs/subsystems/midi.md +123 -0
- data/docs/subsystems/music.md +233 -0
- data/docs/subsystems/musicxml-builder.md +264 -0
- data/docs/subsystems/neumas.md +71 -0
- data/docs/subsystems/repl.md +135 -0
- data/docs/subsystems/sequencer.md +98 -0
- data/docs/subsystems/series.md +302 -0
- data/docs/subsystems/transcription.md +152 -0
- data/docs/subsystems/transport.md +177 -0
- data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
- data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
- data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
- data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
- data/lib/musa-dsl/core-ext/extension.rb +53 -0
- data/lib/musa-dsl/core-ext/hashify.rb +162 -1
- data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
- data/lib/musa-dsl/core-ext/with.rb +114 -0
- data/lib/musa-dsl/datasets/dataset.rb +109 -0
- data/lib/musa-dsl/datasets/delta-d.rb +78 -0
- data/lib/musa-dsl/datasets/e.rb +186 -2
- data/lib/musa-dsl/datasets/gdv.rb +279 -2
- data/lib/musa-dsl/datasets/gdvd.rb +201 -0
- data/lib/musa-dsl/datasets/helper.rb +75 -0
- data/lib/musa-dsl/datasets/p.rb +177 -2
- data/lib/musa-dsl/datasets/packed-v.rb +91 -0
- data/lib/musa-dsl/datasets/pdv.rb +136 -1
- data/lib/musa-dsl/datasets/ps.rb +134 -4
- data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
- data/lib/musa-dsl/datasets/score/render.rb +105 -1
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
- data/lib/musa-dsl/datasets/score.rb +279 -0
- data/lib/musa-dsl/datasets/v.rb +88 -0
- data/lib/musa-dsl/generative/darwin.rb +180 -1
- data/lib/musa-dsl/generative/generative-grammar.rb +359 -0
- data/lib/musa-dsl/generative/markov.rb +133 -3
- data/lib/musa-dsl/generative/rules.rb +258 -4
- data/lib/musa-dsl/generative/variatio.rb +217 -2
- data/lib/musa-dsl/logger/logger.rb +267 -2
- data/lib/musa-dsl/matrix/matrix.rb +256 -10
- data/lib/musa-dsl/midi/midi-recorder.rb +108 -1
- data/lib/musa-dsl/midi/midi-voices.rb +265 -4
- data/lib/musa-dsl/music/chord-definition.rb +233 -1
- data/lib/musa-dsl/music/chord-definitions.rb +33 -6
- data/lib/musa-dsl/music/chords.rb +308 -2
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +315 -0
- data/lib/musa-dsl/music/scales.rb +957 -40
- data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
- data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
- data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
- data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
- data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
- data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
- data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
- data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
- data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
- data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
- data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
- data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
- data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
- data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
- data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
- data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
- data/lib/musa-dsl/neumas/neumas.rb +67 -0
- data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
- data/lib/musa-dsl/repl/repl.rb +550 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
- data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
- data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
- data/lib/musa-dsl/series/array-to-serie.rb +37 -1
- data/lib/musa-dsl/series/base-series.rb +843 -5
- data/lib/musa-dsl/series/buffer-serie.rb +48 -0
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +41 -0
- data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
- data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
- data/lib/musa-dsl/series/proxy-serie.rb +67 -0
- data/lib/musa-dsl/series/quantizer-serie.rb +45 -7
- data/lib/musa-dsl/series/queue-serie.rb +65 -0
- data/lib/musa-dsl/series/series-composer.rb +701 -0
- data/lib/musa-dsl/series/timed-serie.rb +473 -28
- data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
- data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
- data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
- data/lib/musa-dsl/transcription/transcription.rb +265 -0
- data/lib/musa-dsl/transport/clock.rb +125 -0
- data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
- data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
- data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
- data/lib/musa-dsl/transport/timer-clock.rb +183 -1
- data/lib/musa-dsl/transport/timer.rb +83 -0
- data/lib/musa-dsl/transport/transport.rb +318 -0
- data/lib/musa-dsl/version.rb +1 -1
- data/lib/musa-dsl.rb +132 -25
- data/musa-dsl.gemspec +12 -10
- 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
|
-
|
|
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
|