musa-dsl 0.21.3 → 0.22.2
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/lib/musa-dsl.rb +1 -1
- data/lib/musa-dsl/core-ext.rb +1 -0
- data/lib/musa-dsl/core-ext/arrayfy.rb +9 -9
- data/lib/musa-dsl/core-ext/hashify.rb +42 -0
- data/lib/musa-dsl/core-ext/inspect-nice.rb +6 -1
- data/lib/musa-dsl/datasets/e.rb +22 -5
- data/lib/musa-dsl/datasets/gdv.rb +0 -1
- data/lib/musa-dsl/datasets/p.rb +28 -37
- data/lib/musa-dsl/datasets/pdv.rb +0 -1
- data/lib/musa-dsl/datasets/ps.rb +10 -78
- data/lib/musa-dsl/logger/logger.rb +4 -3
- data/lib/musa-dsl/matrix/matrix.rb +0 -57
- data/lib/musa-dsl/repl/repl.rb +4 -8
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +3 -3
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +210 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -595
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +58 -5
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +5 -9
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
- data/lib/musa-dsl/series/base-series.rb +43 -78
- data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +95 -0
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +29 -83
- data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
- data/lib/musa-dsl/series/proxy-serie.rb +1 -1
- data/lib/musa-dsl/series/quantizer-serie.rb +558 -0
- data/lib/musa-dsl/series/queue-serie.rb +1 -1
- data/lib/musa-dsl/series/series.rb +7 -2
- data/lib/musa-dsl/transport/input-midi-clock.rb +19 -12
- data/lib/musa-dsl/transport/transport.rb +6 -6
- data/musa-dsl.gemspec +2 -2
- metadata +10 -4
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
- data/lib/musa-dsl/series/hash-serie-splitter.rb +0 -196
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 700593377e2427ac571b039197f3fdb0c3d904dbe0ed74725e54f1c4421f074c
|
4
|
+
data.tar.gz: a0bb8dbf80d824eaf5543db333964d5cb449819c22a60fb54670a007c9b327b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de57aaaf8a10d8a1b6ab68ae8ae9e6660488cbc3efce53fa7a1c9a4bd84872a8225ab6d854f9101deb5c7b872389789fbe653dc5b608c809cdd387f1351e53c5
|
7
|
+
data.tar.gz: 2719f0f97281138feb53542ea842759e965d0c1f756fdbd92797935963c9adaffe91e67212f5efd3ac2e3e2ef2d956da60cce73efbefce764aef224d8042f0bf
|
data/lib/musa-dsl.rb
CHANGED
data/lib/musa-dsl/core-ext.rb
CHANGED
@@ -4,28 +4,28 @@ module Musa
|
|
4
4
|
module Extension
|
5
5
|
module Arrayfy
|
6
6
|
refine Object do
|
7
|
-
def arrayfy(size: nil)
|
7
|
+
def arrayfy(size: nil, default: nil)
|
8
8
|
if size
|
9
|
-
size.times.collect
|
10
|
-
|
11
|
-
if nil?
|
12
|
-
[]
|
13
|
-
else
|
14
|
-
[self]
|
9
|
+
size.times.collect do
|
10
|
+
nil? ? default : self
|
15
11
|
end
|
12
|
+
else
|
13
|
+
nil? ? [] : [self]
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
18
|
+
# TODO add a refinement for Hash? Should receive a list parameter with the ordered keys
|
19
|
+
|
20
20
|
refine Array do
|
21
|
-
def arrayfy(size: nil)
|
21
|
+
def arrayfy(size: nil, default: nil)
|
22
22
|
if size
|
23
23
|
DeepCopy::DeepCopy.copy_singleton_class_modules(
|
24
24
|
self,
|
25
25
|
(self * (size / self.size + ((size % self.size).zero? ? 0 : 1) )).take(size))
|
26
26
|
else
|
27
27
|
self.clone
|
28
|
-
end
|
28
|
+
end.map! { |value| value.nil? ? default : value }
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'deep-copy'
|
2
|
+
|
3
|
+
module Musa
|
4
|
+
module Extension
|
5
|
+
module Hashify
|
6
|
+
refine Object do
|
7
|
+
def hashify(keys:, default: nil)
|
8
|
+
keys.collect do |key|
|
9
|
+
[ key,
|
10
|
+
if nil?
|
11
|
+
default
|
12
|
+
else
|
13
|
+
self
|
14
|
+
end ]
|
15
|
+
end.to_h
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
refine Array do
|
20
|
+
def hashify(keys:, default: nil)
|
21
|
+
values = clone
|
22
|
+
keys.collect do |key|
|
23
|
+
value = values.shift
|
24
|
+
[ key,
|
25
|
+
value.nil? ? default : value ]
|
26
|
+
end.to_hash
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
refine Hash do
|
31
|
+
def hashify(keys:, default: nil)
|
32
|
+
keys.collect do |key|
|
33
|
+
value = self[key]
|
34
|
+
[ key,
|
35
|
+
value.nil? ? default : value ]
|
36
|
+
end.to_h
|
37
|
+
.tap {|_| DeepCopy::DeepCopy.copy_singleton_class_modules(self, _) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -12,6 +12,11 @@ module Musa
|
|
12
12
|
alias to_s inspect
|
13
13
|
end
|
14
14
|
|
15
|
+
|
16
|
+
refine Rational.singleton_class do
|
17
|
+
attr_accessor :to_s_as_inspect
|
18
|
+
end
|
19
|
+
|
15
20
|
refine Rational do
|
16
21
|
def inspect(simple: nil)
|
17
22
|
value = self.abs
|
@@ -38,7 +43,7 @@ module Musa
|
|
38
43
|
end
|
39
44
|
|
40
45
|
def to_s
|
41
|
-
inspect simple: true
|
46
|
+
inspect simple: true # !Rational.to_s_as_inspect
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
data/lib/musa-dsl/datasets/e.rb
CHANGED
@@ -5,11 +5,21 @@ module Musa::Datasets
|
|
5
5
|
include Dataset
|
6
6
|
|
7
7
|
NaturalKeys = [].freeze
|
8
|
+
|
9
|
+
# TODO implement valid? in all 'subclasses'. This implies recollecting from other places where validations are done and refactoring
|
10
|
+
# TODO should valid? and validate! be on Dataset instead of E? P dataset inherits from Dataset but probably it could be validated
|
11
|
+
#
|
12
|
+
def valid?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate!
|
17
|
+
raise RuntimeError, "Invalid dataset #{self}" unless valid?
|
18
|
+
end
|
8
19
|
end
|
9
20
|
|
10
21
|
module Abs
|
11
22
|
include E
|
12
|
-
def duration; 0; end
|
13
23
|
end
|
14
24
|
|
15
25
|
module Delta
|
@@ -20,6 +30,12 @@ module Musa::Datasets
|
|
20
30
|
include Abs
|
21
31
|
end
|
22
32
|
|
33
|
+
module AbsTimed
|
34
|
+
include Abs
|
35
|
+
|
36
|
+
NaturalKeys = (NaturalKeys + [:time]).freeze
|
37
|
+
end
|
38
|
+
|
23
39
|
module DeltaI
|
24
40
|
include Delta
|
25
41
|
end
|
@@ -27,10 +43,11 @@ module Musa::Datasets
|
|
27
43
|
module AbsD
|
28
44
|
include Abs
|
29
45
|
|
30
|
-
NaturalKeys =
|
31
|
-
:
|
32
|
-
|
33
|
-
|
46
|
+
NaturalKeys = (NaturalKeys +
|
47
|
+
[:duration, # duration of the process (note reproduction, dynamics evolution, etc)
|
48
|
+
:note_duration, # duration of the note (a staccato note is effectvely shorter than elapsed duration until next note)
|
49
|
+
:forward_duration # duration to wait until next event (if 0 means the next event should be executed at the same time than this one)
|
50
|
+
]).freeze
|
34
51
|
|
35
52
|
def forward_duration
|
36
53
|
self[:forward_duration] || self[:duration]
|
data/lib/musa-dsl/datasets/p.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
require_relative 'dataset'
|
2
2
|
require_relative 'ps'
|
3
3
|
|
4
|
+
require_relative '../series'
|
4
5
|
require_relative '../sequencer'
|
5
6
|
|
6
7
|
module Musa::Datasets
|
7
8
|
module P
|
8
9
|
include Dataset
|
9
10
|
|
10
|
-
def to_ps_serie(base_duration
|
11
|
-
base_duration ||= 1/4r
|
11
|
+
def to_ps_serie(base_duration: nil)
|
12
|
+
base_duration ||= 1/4r # TODO review incoherence between neumalang 1/4r base duration for quarter notes and general 1r size of bar
|
12
13
|
|
13
|
-
p
|
14
|
+
# TODO if instead of using clone (needed because of p.shift) we use index counter the P elements would be evaluated on the last moment
|
14
15
|
|
15
|
-
Musa::Series::E() do
|
16
|
+
Musa::Series::E(clone, base_duration) do |p, base_duration|
|
16
17
|
(p.size >= 3) ?
|
17
18
|
{ from: p.shift,
|
18
19
|
duration: p.shift * base_duration,
|
@@ -21,47 +22,37 @@ module Musa::Datasets
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
sequencer: nil,
|
28
|
-
beats_per_bar: nil, ticks_per_beat: nil,
|
29
|
-
right_open: nil,
|
30
|
-
do_log: nil,
|
31
|
-
&block)
|
25
|
+
def to_timed_serie(time_start = nil, base_duration: nil)
|
26
|
+
time_start ||= 0r
|
27
|
+
base_duration ||= 1/4r # TODO review incoherence between neumalang 1/4r base duration for quarter notes and general 1r size of bar
|
32
28
|
|
33
|
-
|
34
|
-
"'beats_per_bar' and 'ticks_per_beat' parameters should be both nil or both have values" \
|
35
|
-
unless beats_per_bar && ticks_per_beat || beats_per_bar.nil? && ticks_per_beat.nil?
|
29
|
+
# TODO if instead of using clone (needed because of p.shift) we use index counter the P elements would be evaluated on the last moment
|
36
30
|
|
37
|
-
|
38
|
-
|
39
|
-
if sequencer && beats_per_bar
|
31
|
+
Musa::Series::E(clone, base_duration, context: { time: time_start }) do |p, base_duration, context: |
|
32
|
+
value = p.shift
|
40
33
|
|
41
|
-
|
34
|
+
if value
|
35
|
+
r = { time: context[:time], value: value } if !value.nil?
|
42
36
|
|
43
|
-
|
37
|
+
delta_time = p.shift
|
38
|
+
context[:time] += delta_time * base_duration if delta_time
|
44
39
|
|
45
|
-
|
46
|
-
|
47
|
-
sequencer.at(position || 1r) do |_|
|
48
|
-
|
49
|
-
_.play to_ps_serie do |_, line|
|
50
|
-
|
51
|
-
line.to_score(sequencer: _,
|
52
|
-
score: score,
|
53
|
-
mapper: mapper,
|
54
|
-
position: _.position,
|
55
|
-
right_open: right_open,
|
56
|
-
&block)
|
40
|
+
r&.extend(AbsTimed)
|
57
41
|
end
|
58
42
|
end
|
43
|
+
end
|
59
44
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
45
|
+
def map(&block)
|
46
|
+
i = 0
|
47
|
+
clone.map! do |element|
|
48
|
+
# Process with block only the values (values are the alternating elements because P
|
49
|
+
# structure is <value> <duration> <value> <duration> <value>)
|
50
|
+
#
|
51
|
+
if (i += 1) % 2 == 1
|
52
|
+
block.call(element)
|
53
|
+
else
|
54
|
+
element
|
55
|
+
end
|
65
56
|
end
|
66
57
|
end
|
67
58
|
end
|
data/lib/musa-dsl/datasets/ps.rb
CHANGED
@@ -29,85 +29,17 @@ module Musa::Datasets
|
|
29
29
|
# TODO ?????
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
raise ArgumentError,
|
42
|
-
"'beats_per_bar' and 'ticks_per_beat' parameters should be both nil or both have values" \
|
43
|
-
unless beats_per_bar && ticks_per_beat || beats_per_bar.nil? && ticks_per_beat.nil?
|
44
|
-
|
45
|
-
raise ArgumentError,
|
46
|
-
"'sequencer' parameter should not be used when 'beats_per_bar' and 'ticks_per_beat' parameters are used" \
|
47
|
-
if sequencer && beats_per_bar
|
48
|
-
|
49
|
-
run_sequencer = sequencer.nil?
|
50
|
-
|
51
|
-
binder = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
|
52
|
-
|
53
|
-
score ||= Musa::Datasets::Score.new
|
54
|
-
|
55
|
-
sequencer ||= Musa::Sequencer::Sequencer.new(beats_per_bar, ticks_per_beat, do_log: do_log)
|
56
|
-
|
57
|
-
ticks_per_bar = sequencer.ticks_per_bar
|
58
|
-
|
59
|
-
from = mapper && self[:from].is_a?(V) ? self[:from].to_packed_V(mapper) : self[:from]
|
60
|
-
to = mapper && self[:to].is_a?(V) ? self[:to].to_packed_V(mapper) : self[:to]
|
61
|
-
|
62
|
-
if right_open.is_a?(Array)
|
63
|
-
right_open = right_open.collect do |v|
|
64
|
-
v.is_a?(Symbol) ? v : mapper[v]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# TODO sequencer step should be 1????
|
69
|
-
#
|
70
|
-
sequencer.at(position || 1r) do |_|
|
71
|
-
_.move from: from,
|
72
|
-
to: to,
|
73
|
-
right_open: right_open,
|
74
|
-
duration: _quantize(self[:duration], ticks_per_bar),
|
75
|
-
step: 1 do
|
76
|
-
| _,
|
77
|
-
value, next_value,
|
78
|
-
duration:,
|
79
|
-
quantized_duration:,
|
80
|
-
position_jitter:, duration_jitter:,
|
81
|
-
started_ago:|
|
82
|
-
|
83
|
-
binder.call value, next_value,
|
84
|
-
position: _.position,
|
85
|
-
duration: duration,
|
86
|
-
quantized_duration: quantized_duration,
|
87
|
-
position_jitter: position_jitter,
|
88
|
-
duration_jitter: duration_jitter,
|
89
|
-
started_ago: started_ago,
|
90
|
-
score: score,
|
91
|
-
logger: _.logger
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
if run_sequencer
|
96
|
-
sequencer.run
|
97
|
-
score
|
98
|
-
else
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def _quantize(duration, ticks_per_bar)
|
106
|
-
if ticks_per_bar &.< Float::INFINITY
|
107
|
-
((duration.rationalize * ticks_per_bar).round / ticks_per_bar).to_r
|
32
|
+
def valid?
|
33
|
+
case self[:from]
|
34
|
+
when Array
|
35
|
+
self[:to].is_a?(Array) &&
|
36
|
+
self[:from].size == self[:to].size
|
37
|
+
when Hash
|
38
|
+
self[:to].is_a?(Hash) &&
|
39
|
+
self[:from].keys == self[:to].keys
|
108
40
|
else
|
109
|
-
|
110
|
-
end
|
41
|
+
false
|
42
|
+
end && self[:duration].is_a?(Numeric) && self[:duration] > 0
|
111
43
|
end
|
112
44
|
end
|
113
45
|
end
|
@@ -3,11 +3,12 @@ require 'logger'
|
|
3
3
|
module Musa; module Logger
|
4
4
|
class Logger < ::Logger
|
5
5
|
def initialize(sequencer: nil, position_format: nil)
|
6
|
-
super STDERR
|
6
|
+
super STDERR, level: WARN
|
7
7
|
|
8
8
|
@sequencer = sequencer
|
9
9
|
@position_format = position_format || 3.3
|
10
10
|
|
11
|
+
|
11
12
|
self.formatter = proc do |severity, time, progname, msg|
|
12
13
|
level = "[#{severity}] " unless severity == 'DEBUG'
|
13
14
|
|
@@ -19,9 +20,9 @@ module Musa; module Logger
|
|
19
20
|
"%#{integer_digits + decimal_digits + 1}s: " % ("%.#{decimal_digits}f" % sequencer.position.to_f)
|
20
21
|
end
|
21
22
|
|
22
|
-
progname = "[#{progname}]
|
23
|
+
progname = "[#{progname}]" if progname
|
23
24
|
|
24
|
-
"#{position}#{level}#{progname}#{msg}\n"
|
25
|
+
"#{position}#{level}#{progname} #{msg}\n"
|
25
26
|
else
|
26
27
|
"\n"
|
27
28
|
end
|
@@ -70,7 +70,6 @@ module Musa
|
|
70
70
|
include Musa::Datasets
|
71
71
|
|
72
72
|
def to_p(time_dimension, keep_time: nil)
|
73
|
-
|
74
73
|
decompose(self.to_a, time_dimension).collect do |points|
|
75
74
|
line = []
|
76
75
|
|
@@ -94,62 +93,6 @@ module Musa
|
|
94
93
|
end
|
95
94
|
end
|
96
95
|
|
97
|
-
def to_score(time_dimension,
|
98
|
-
mapper: nil,
|
99
|
-
score: nil,
|
100
|
-
position: nil,
|
101
|
-
sequencer: nil,
|
102
|
-
beats_per_bar: nil, ticks_per_beat: nil,
|
103
|
-
right_open: nil,
|
104
|
-
do_log: nil,
|
105
|
-
&block)
|
106
|
-
|
107
|
-
raise ArgumentError,
|
108
|
-
"'beats_per_bar' and 'ticks_per_beat' parameters should be both nil or both have values" \
|
109
|
-
unless beats_per_bar && ticks_per_beat ||
|
110
|
-
beats_per_bar.nil? && ticks_per_beat.nil?
|
111
|
-
|
112
|
-
raise ArgumentError,
|
113
|
-
"'sequencer' parameter should not be used when 'beats_per_bar' and 'ticks_per_beat' parameters are used" \
|
114
|
-
if sequencer && beats_per_bar
|
115
|
-
|
116
|
-
raise ArgumentError,
|
117
|
-
"'time_dimension' parameter should be an index number if no 'mapping' is provided" \
|
118
|
-
unless time_dimension.is_a?(Symbol) && mapper&.include?(time_dimension) ||
|
119
|
-
time_dimension.is_a?(Integer) && (0..self.column_size-1).include(time_dimension)
|
120
|
-
|
121
|
-
time_dimension = mapper&.find_index(time_dimension) if time_dimension.is_a?(Symbol)
|
122
|
-
|
123
|
-
mapper = mapper.clone.tap { |_| _.delete_at(time_dimension) } if mapper
|
124
|
-
|
125
|
-
run_sequencer = sequencer.nil?
|
126
|
-
|
127
|
-
score ||= Musa::Datasets::Score.new
|
128
|
-
|
129
|
-
sequencer ||= Sequencer::Sequencer.new(beats_per_bar, ticks_per_beat, do_log: do_log)
|
130
|
-
|
131
|
-
right_open = right_open.clone.tap { |_| _.delete_at(time_dimension) } if right_open&.is_a?(Array)
|
132
|
-
|
133
|
-
sequencer.at(position || 1r) do |_|
|
134
|
-
to_p(time_dimension).each do |p|
|
135
|
-
p.to_score(score: score,
|
136
|
-
mapper: mapper,
|
137
|
-
sequencer: _,
|
138
|
-
position: _.position,
|
139
|
-
right_open: right_open,
|
140
|
-
do_log: do_log,
|
141
|
-
&block)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
if run_sequencer
|
146
|
-
sequencer.run
|
147
|
-
score
|
148
|
-
else
|
149
|
-
nil
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
96
|
def _rows
|
154
97
|
@rows
|
155
98
|
end
|