musa-dsl 0.21.4 → 0.22.3
Sign up to get free protection for your applications and to get access to all the features.
- 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/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 +2 -2
- 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 -597
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
- data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +59 -5
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
- data/lib/musa-dsl/sequencer/sequencer.rb +1 -1
- 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 +143 -0
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +32 -92
- 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 +8 -2
- data/lib/musa-dsl/series/union-timed-series.rb +109 -0
- data/musa-dsl.gemspec +2 -2
- metadata +12 -5
- 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: 193117ba393c58eaf2387d7b0a5ba54bc7fbad0c6ac2e5a7171997b1629d5f69
|
4
|
+
data.tar.gz: 5ac3515f62f3c5d8ea34cd91552fb6d0f8d53e40f60d1383fa34a28c0b11289d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ec912683ee5e0f0f0865ff9197e641671c430ed5a59d438b15acb5423f6d18f3f57624d5dd4c348daa69c93ac1d47428809cea84953893a4cb7f9b224613f9
|
7
|
+
data.tar.gz: b64ee9f844989e4db527787f763089c6bcd5aa050254da270c2c5c3461145aefef9b701da6944cda20b53286bfee2e42650c2a21de864ee8ea53f5d48aff0791
|
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
|