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
|
@@ -1,11 +1,78 @@
|
|
|
1
|
+
#
|
|
2
|
+
# @api public
|
|
1
3
|
require_relative 'base-series'
|
|
2
4
|
|
|
3
5
|
module Musa
|
|
4
6
|
module Series::Constructors
|
|
7
|
+
# Creates a proxy serie with optional initial source.
|
|
8
|
+
#
|
|
9
|
+
# Proxy series enable late binding - creating a serie placeholder that will
|
|
10
|
+
# be resolved later. Useful for:
|
|
11
|
+
#
|
|
12
|
+
# ## Use Cases
|
|
13
|
+
#
|
|
14
|
+
# - **Forward references**: Reference series before definition
|
|
15
|
+
# - **Circular structures**: Self-referential or mutually referential series
|
|
16
|
+
# - **Dependency injection**: Define structure, inject source later
|
|
17
|
+
# - **Dynamic routing**: Change source serie at runtime
|
|
18
|
+
#
|
|
19
|
+
# ## Method Delegation
|
|
20
|
+
#
|
|
21
|
+
# Proxy delegates all methods to underlying source via method_missing,
|
|
22
|
+
# making it transparent proxy for most operations.
|
|
23
|
+
#
|
|
24
|
+
# ## State Resolution
|
|
25
|
+
#
|
|
26
|
+
# Proxy starts in :undefined state, becomes :prototype/:instance when
|
|
27
|
+
# source is set and resolved.
|
|
28
|
+
#
|
|
29
|
+
# @param serie [Serie, nil] initial source serie (default: nil)
|
|
30
|
+
#
|
|
31
|
+
# @return [ProxySerie] proxy serie
|
|
32
|
+
#
|
|
33
|
+
# @example Forward reference
|
|
34
|
+
# proxy = PROXY()
|
|
35
|
+
# proxy.undefined? # => true
|
|
36
|
+
#
|
|
37
|
+
# # Define later
|
|
38
|
+
# proxy.proxy_source = S(1, 2, 3)
|
|
39
|
+
# proxy.prototype? # => true
|
|
40
|
+
#
|
|
41
|
+
# @example Circular structure
|
|
42
|
+
# loop_serie = PROXY()
|
|
43
|
+
# sequence = S(1, 2, 3).after(loop_serie)
|
|
44
|
+
# loop_serie.proxy_source = sequence
|
|
45
|
+
# # Creates infinite loop: 1, 2, 3, 1, 2, 3, ...
|
|
46
|
+
#
|
|
47
|
+
# @example With initial source
|
|
48
|
+
# proxy = PROXY(S(1, 2, 3))
|
|
49
|
+
#
|
|
50
|
+
# @api public
|
|
5
51
|
def PROXY(serie = nil)
|
|
6
52
|
ProxySerie.new(serie)
|
|
7
53
|
end
|
|
8
54
|
|
|
55
|
+
# Proxy/wrapper serie that delegates to another serie.
|
|
56
|
+
#
|
|
57
|
+
# Acts as transparent proxy forwarding all method calls to the wrapped
|
|
58
|
+
# serie. Useful for lazy evaluation, conditional serie switching, or
|
|
59
|
+
# adding indirection layer.
|
|
60
|
+
#
|
|
61
|
+
# The proxy can be reassigned to a different serie dynamically by
|
|
62
|
+
# changing the `proxy_source` attribute.
|
|
63
|
+
#
|
|
64
|
+
# @example Basic proxy
|
|
65
|
+
# original = FromArray.new([1, 2, 3])
|
|
66
|
+
# proxy = ProxySerie.new(original)
|
|
67
|
+
# proxy.next_value # => 1 (delegates to original)
|
|
68
|
+
#
|
|
69
|
+
# @example Dynamic serie switching
|
|
70
|
+
# proxy = ProxySerie.new(serie_a)
|
|
71
|
+
# proxy.next_value # Uses serie_a
|
|
72
|
+
# proxy.proxy_source = serie_b
|
|
73
|
+
# proxy.next_value # Now uses serie_b
|
|
74
|
+
#
|
|
75
|
+
# @api private
|
|
9
76
|
class ProxySerie
|
|
10
77
|
include Series::Serie.with(source: true, source_as: :proxy_source)
|
|
11
78
|
|
|
@@ -3,16 +3,54 @@ require_relative '../core-ext/inspect-nice'
|
|
|
3
3
|
|
|
4
4
|
require_relative 'base-series'
|
|
5
5
|
|
|
6
|
-
# TODO remove debugging puts, intermediate hash comments on :info and InspectNice
|
|
7
6
|
module Musa
|
|
8
7
|
module Series::Operations
|
|
8
|
+
# Quantizes time-value serie to discrete steps.
|
|
9
|
+
#
|
|
10
|
+
# ## Quantization Modes
|
|
11
|
+
#
|
|
12
|
+
# - **Raw**: Rounds values to nearest step, interpolates between points
|
|
13
|
+
# - **Predictive**: Predicts crossings of quantization boundaries
|
|
14
|
+
#
|
|
15
|
+
# ## Applications
|
|
16
|
+
#
|
|
17
|
+
# - Quantize MIDI controller data to discrete values
|
|
18
|
+
# - Convert continuous pitch bends to semitones
|
|
19
|
+
# - Snap timing to grid
|
|
20
|
+
# - Generate stepped automation curves
|
|
21
|
+
# - Convert analog input to digital steps
|
|
22
|
+
#
|
|
23
|
+
# @param reference [Numeric, nil] quantization reference (default: 0)
|
|
24
|
+
# @param step [Numeric, nil] step size (default: 1)
|
|
25
|
+
# @param value_attribute [Symbol, nil] attribute to quantize (default: :value)
|
|
26
|
+
# @param stops [Boolean, nil] include stop points (default: false)
|
|
27
|
+
# @param predictive [Boolean, nil] use predictive mode (default: false)
|
|
28
|
+
# @param left_open [Boolean, nil] left boundary open (raw mode)
|
|
29
|
+
# @param right_open [Boolean, nil] right boundary open (raw mode)
|
|
30
|
+
#
|
|
31
|
+
# @return [RawQuantizer, PredictiveQuantizer] quantized serie
|
|
32
|
+
#
|
|
33
|
+
# @example Basic quantization
|
|
34
|
+
# # Quantize to semitones (12 steps per octave)
|
|
35
|
+
# pitch_bend = S({time: 0r, value: 60.3}, {time: 1r, value: 61.8})
|
|
36
|
+
# quantized = pitch_bend.quantize(step: 1)
|
|
37
|
+
# quantized.i.to_a # => [{time: 0, value: 60, duration: 1}, ...]
|
|
38
|
+
#
|
|
39
|
+
# @example Predictive quantization
|
|
40
|
+
# continuous = S({time: 0r, value: 0}, {time: 4r, value: 10})
|
|
41
|
+
# pred = continuous.quantize(step: 2, predictive: true)
|
|
42
|
+
# # Generates crossing points at values 0, 2, 4, 6, 8, 10
|
|
43
|
+
#
|
|
44
|
+
# @api public
|
|
9
45
|
def quantize(reference: nil, step: nil,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
46
|
+
value_attribute: nil,
|
|
47
|
+
stops: nil,
|
|
48
|
+
predictive: nil,
|
|
49
|
+
left_open: nil,
|
|
50
|
+
right_open: nil)
|
|
51
|
+
|
|
52
|
+
# TODO remove debugging puts, intermediate hash comments on :info and InspectNice
|
|
53
|
+
|
|
16
54
|
Series::Constructors.QUANTIZE(self,
|
|
17
55
|
reference: reference,
|
|
18
56
|
step: step,
|
|
@@ -1,11 +1,76 @@
|
|
|
1
|
+
# Queue serie for dynamic series concatenation.
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
# @api public
|
|
1
5
|
require_relative 'base-series'
|
|
2
6
|
|
|
3
7
|
module Musa
|
|
4
8
|
module Series::Constructors
|
|
9
|
+
# Creates queue serie from initial series.
|
|
10
|
+
#
|
|
11
|
+
# Queue allows adding series dynamically during playback, creating flexible
|
|
12
|
+
# sequential playback with runtime modification.
|
|
13
|
+
#
|
|
14
|
+
# ## Features
|
|
15
|
+
#
|
|
16
|
+
# - **Dynamic addition**: Add series with `<<` during playback
|
|
17
|
+
# - **Sequential playback**: Plays series in queue order
|
|
18
|
+
# - **Method delegation**: Delegates methods to current serie
|
|
19
|
+
# - **Clear**: Can clear queue and reset
|
|
20
|
+
#
|
|
21
|
+
# ## Use Cases
|
|
22
|
+
#
|
|
23
|
+
# - Interactive sequencing with user input
|
|
24
|
+
# - Dynamic phrase assembly
|
|
25
|
+
# - Playlist-style serie management
|
|
26
|
+
# - Reactive composition systems
|
|
27
|
+
# - Live coding pattern queuing
|
|
28
|
+
#
|
|
29
|
+
# @param series [Array<Serie>] initial series in queue
|
|
30
|
+
#
|
|
31
|
+
# @return [QueueSerie] queue serie
|
|
32
|
+
#
|
|
33
|
+
# @example Basic queue
|
|
34
|
+
# queue = QUEUE(S(1, 2, 3)).i
|
|
35
|
+
# queue.next_value # => 1
|
|
36
|
+
# queue << S(4, 5, 6).i # Add dynamically
|
|
37
|
+
# queue.to_a # => [2, 3, 4, 5, 6]
|
|
38
|
+
#
|
|
39
|
+
# @example Dynamic playlist
|
|
40
|
+
# queue = QUEUE().i
|
|
41
|
+
# queue << melody1.i
|
|
42
|
+
# queue << melody2.i
|
|
43
|
+
# # Plays melody1 then melody2
|
|
44
|
+
#
|
|
45
|
+
# @api public
|
|
5
46
|
def QUEUE(*series)
|
|
6
47
|
QueueSerie.new(series)
|
|
7
48
|
end
|
|
8
49
|
|
|
50
|
+
# Serie that processes multiple source series in queue/sequence fashion.
|
|
51
|
+
#
|
|
52
|
+
# Combines multiple series by playing them sequentially - when one
|
|
53
|
+
# series exhausts, moves to the next. New series can be added dynamically
|
|
54
|
+
# with `<<` operator.
|
|
55
|
+
#
|
|
56
|
+
# All queued series must be instances (not prototypes). The queue can
|
|
57
|
+
# be cleared with `clear` method.
|
|
58
|
+
#
|
|
59
|
+
# @example Sequential series playback
|
|
60
|
+
# serie_a = FromArray.new([1, 2, 3]).instance
|
|
61
|
+
# serie_b = FromArray.new([4, 5, 6]).instance
|
|
62
|
+
# queue = QueueSerie.new([serie_a, serie_b])
|
|
63
|
+
# queue.next_value # => 1
|
|
64
|
+
# queue.next_value # => 2
|
|
65
|
+
# queue.next_value # => 3
|
|
66
|
+
# queue.next_value # => 4 (switches to serie_b)
|
|
67
|
+
#
|
|
68
|
+
# @example Dynamic queueing
|
|
69
|
+
# queue = QueueSerie.new([serie_a]).instance
|
|
70
|
+
# queue << serie_b # Add series on the fly
|
|
71
|
+
# queue.clear # Empty the queue
|
|
72
|
+
#
|
|
73
|
+
# @api private
|
|
9
74
|
class QueueSerie
|
|
10
75
|
include Series::Serie.with(sources: true)
|
|
11
76
|
|