musa-dsl 0.21.5 → 0.22.4

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/musa-dsl.rb +1 -1
  3. data/lib/musa-dsl/core-ext.rb +1 -0
  4. data/lib/musa-dsl/core-ext/arrayfy.rb +9 -9
  5. data/lib/musa-dsl/core-ext/hashify.rb +42 -0
  6. data/lib/musa-dsl/core-ext/inspect-nice.rb +6 -1
  7. data/lib/musa-dsl/datasets/e.rb +22 -5
  8. data/lib/musa-dsl/datasets/gdv.rb +0 -1
  9. data/lib/musa-dsl/datasets/p.rb +29 -36
  10. data/lib/musa-dsl/datasets/pdv.rb +0 -1
  11. data/lib/musa-dsl/datasets/ps.rb +10 -78
  12. data/lib/musa-dsl/logger/logger.rb +2 -2
  13. data/lib/musa-dsl/matrix/matrix.rb +9 -64
  14. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
  15. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
  16. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +2 -2
  17. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +219 -0
  18. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
  19. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -597
  20. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
  21. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
  22. data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +63 -5
  23. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
  24. data/lib/musa-dsl/sequencer/sequencer.rb +1 -1
  25. data/lib/musa-dsl/series/base-series.rb +43 -78
  26. data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
  27. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +143 -0
  28. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  29. data/lib/musa-dsl/series/main-serie-constructors.rb +32 -92
  30. data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
  31. data/lib/musa-dsl/series/proxy-serie.rb +1 -1
  32. data/lib/musa-dsl/series/quantizer-serie.rb +558 -0
  33. data/lib/musa-dsl/series/queue-serie.rb +1 -1
  34. data/lib/musa-dsl/series/series.rb +8 -2
  35. data/lib/musa-dsl/series/union-timed-series.rb +109 -0
  36. data/musa-dsl.gemspec +2 -2
  37. metadata +12 -5
  38. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
  39. 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: 46172601ed5c7fc82111b9ef5d669006f581e9ea4ebb0c36ef6c7108c9e0107e
4
- data.tar.gz: aff0114b7c5a87e5e158eb5ff88882e0adfe4e39a8b7531f8aff323425e133f4
3
+ metadata.gz: fe8d0a64e4ba5518c7ed0fe4b75fffbf059217ef65e83025889a21d1c830a6e7
4
+ data.tar.gz: a78c43004243d81a9411c42e34338ecfe4ca7ef17322417dc2e8eb9a953b9abd
5
5
  SHA512:
6
- metadata.gz: 113e51f155961205cf92897802108124b1f953e7d2d690fcf11582d014c828af3ab13880ac6f69eefbd6fbdfca8d2eb9c96dfd507cd0bf42be87cdb654781753
7
- data.tar.gz: b8a67793161526eff6a8be4dcd412da2d093228ff95b88c039973a5857da431b93e714b3e6d0d895462e6488a9368564c39b01ebaa6098c36ce7046269b20549
6
+ metadata.gz: 6bf51f55471c9a753ec648cb1c223ef0564307d2807ec0c569a144856ef330ca7567e8ed4f8f0f651e1808ea42712c02c686ac123424d0feaa90955e2f6d77fe
7
+ data.tar.gz: 2bd503000a0d7cd2bd0e74f9790cbf5533335bc7d74cc6846cb60ea3bad4f1fd3fb24e74ed0bd1c6955b476d45274f51047202c89e12582e5fd642753d34144e
@@ -1,5 +1,5 @@
1
1
  module Musa
2
- VERSION = '0.21.1'
2
+ VERSION = '0.22.4'
3
3
  end
4
4
 
5
5
  require_relative 'musa-dsl/core-ext'
@@ -1,5 +1,6 @@
1
1
  require_relative 'core-ext/array-explode-ranges'
2
2
  require_relative 'core-ext/arrayfy'
3
+ require_relative 'core-ext/hashify'
3
4
  require_relative 'core-ext/deep-copy'
4
5
  require_relative 'core-ext/smart-proc-binder'
5
6
  require_relative 'core-ext/inspect-nice'
@@ -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 { self }
10
- else
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
@@ -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 = [:duration, # duration of the process (note reproduction, dynamics evolution, etc)
31
- :note_duration, # duration of the note (a staccato note is effectvely shorter than elapsed duration until next note)
32
- :forward_duration # duration to wait until next event (if 0 means the next event should be executed at the same time than this one)
33
- ].freeze
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]
@@ -9,7 +9,6 @@ using Musa::Extension::InspectNice
9
9
  module Musa::Datasets
10
10
  module GDV
11
11
  include AbsD
12
- include AbsI
13
12
 
14
13
  include Helper
15
14
 
@@ -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 = nil)
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 = clone
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,39 @@ module Musa::Datasets
21
22
  end
22
23
  end
23
24
 
24
- def to_score(score: nil,
25
- mapper: nil,
26
- position: nil,
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, time_start_component: nil, base_duration: nil)
26
+ time_start ||= 0r
27
+ time_start += self.first[time_start_component] if time_start_component
32
28
 
33
- raise ArgumentError,
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
+ base_duration ||= 1/4r # TODO review incoherence between neumalang 1/4r base duration for quarter notes and general 1r size of bar
36
30
 
37
- raise ArgumentError,
38
- "'sequencer' parameter should not be used when 'beats_per_bar' and 'ticks_per_beat' parameters are used" \
39
- if sequencer && beats_per_bar
31
+ # 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
40
32
 
41
- run_sequencer = sequencer.nil?
33
+ Musa::Series::E(clone, base_duration, context: { time: time_start }) do |p, base_duration, context: |
34
+ value = p.shift
42
35
 
43
- score ||= Musa::Datasets::Score.new
36
+ if value
37
+ r = { time: context[:time], value: value } if !value.nil?
44
38
 
45
- sequencer ||= Sequencer.new(beats_per_bar, ticks_per_beat, do_log: do_log)
39
+ delta_time = p.shift
40
+ context[:time] += delta_time * base_duration if delta_time
46
41
 
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)
42
+ r&.extend(AbsTimed)
57
43
  end
58
44
  end
45
+ end
59
46
 
60
- if run_sequencer
61
- sequencer.run
62
- score
63
- else
64
- nil
47
+ def map(&block)
48
+ i = 0
49
+ clone.map! do |element|
50
+ # Process with block only the values (values are the alternating elements because P
51
+ # structure is <value> <duration> <value> <duration> <value>)
52
+ #
53
+ if (i += 1) % 2 == 1
54
+ block.call(element)
55
+ else
56
+ element
57
+ end
65
58
  end
66
59
  end
67
60
  end
@@ -6,7 +6,6 @@ require_relative 'helper'
6
6
  module Musa::Datasets
7
7
  module PDV
8
8
  include AbsD
9
- include AbsI
10
9
 
11
10
  include Helper
12
11
 
@@ -29,85 +29,17 @@ module Musa::Datasets
29
29
  # TODO ?????
30
30
  end
31
31
 
32
- def to_score(score: nil,
33
- mapper: nil,
34
- position: nil,
35
- sequencer: nil,
36
- beats_per_bar: nil, ticks_per_beat: nil,
37
- right_open: nil,
38
- do_log: nil,
39
- &block)
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
- duration.rationalize
110
- end
41
+ false
42
+ end && self[:duration].is_a?(Numeric) && self[:duration] > 0
111
43
  end
112
44
  end
113
45
  end
@@ -20,9 +20,9 @@ module Musa; module Logger
20
20
  "%#{integer_digits + decimal_digits + 1}s: " % ("%.#{decimal_digits}f" % sequencer.position.to_f)
21
21
  end
22
22
 
23
- progname = "[#{progname}] " if progname
23
+ progname = "[#{progname}]" if progname
24
24
 
25
- "#{position}#{level}#{progname}#{msg}\n"
25
+ "#{position}#{level}#{progname} #{msg}\n"
26
26
  else
27
27
  "\n"
28
28
  end
@@ -22,8 +22,8 @@ module Musa
22
22
  indexes
23
23
  end
24
24
 
25
- def to_p(time_dimension, keep_time: nil)
26
- condensed_matrices.collect { |m| m.to_p(time_dimension, keep_time: keep_time) }
25
+ def to_p(time_dimension:, keep_time: nil)
26
+ condensed_matrices.collect { |m| m.to_p(time_dimension: time_dimension, keep_time: keep_time) }
27
27
  end
28
28
 
29
29
  def condensed_matrices
@@ -69,15 +69,14 @@ module Musa
69
69
  refine ::Matrix do
70
70
  include Musa::Datasets
71
71
 
72
- def to_p(time_dimension, keep_time: nil)
73
-
72
+ def to_p(time_dimension:, keep_time: nil)
74
73
  decompose(self.to_a, time_dimension).collect do |points|
75
74
  line = []
76
75
 
77
76
  start_point = points[0]
78
77
  start_time = start_point[time_dimension]
79
78
 
80
- line << start_point.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
79
+ line << start_point.clone.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
81
80
 
82
81
  (1..points.size-1).each do |i|
83
82
  end_point = points[i]
@@ -85,7 +84,7 @@ module Musa
85
84
  end_time = end_point[time_dimension]
86
85
 
87
86
  line << end_time - start_time
88
- line << end_point.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
87
+ line << end_point.clone.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
89
88
 
90
89
  start_time = end_time
91
90
  end
@@ -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
@@ -164,8 +107,9 @@ module Musa
164
107
 
165
108
  x_dim_values_indexes.keys.sort.each do |value|
166
109
  x_dim_values_indexes[value].each do |index|
110
+ #
167
111
  # hacia un lado
168
-
112
+ #
169
113
  unless used_indexes.include?(index)
170
114
  i = index
171
115
  xx = array[i][time_dimension]
@@ -182,8 +126,9 @@ module Musa
182
126
 
183
127
  directional_segments << a if a.size > 1
184
128
 
129
+ #
185
130
  # y hacia el otro
186
-
131
+ #
187
132
  i = index
188
133
  xx = array[i][time_dimension]
189
134