musa-dsl 0.21.5 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) 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 +28 -37
  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 +0 -57
  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 +210 -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-public.rb +58 -5
  21. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
  22. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
  23. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +8 -0
  24. data/lib/musa-dsl/series/base-series.rb +43 -78
  25. data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
  26. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +95 -0
  27. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  28. data/lib/musa-dsl/series/main-serie-constructors.rb +29 -83
  29. data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
  30. data/lib/musa-dsl/series/proxy-serie.rb +1 -1
  31. data/lib/musa-dsl/series/quantizer-serie.rb +546 -0
  32. data/lib/musa-dsl/series/queue-serie.rb +1 -1
  33. data/lib/musa-dsl/series/series.rb +7 -2
  34. data/musa-dsl.gemspec +2 -2
  35. metadata +10 -4
  36. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
  37. 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: 45dc15743b61b3ee68c878d59509dc86c7703198fbad479c60f299003ffdbb49
4
+ data.tar.gz: f598a8fccc84f4941652cf9f6bc186419e466c0d75cd772ff128d462b5af400a
5
5
  SHA512:
6
- metadata.gz: 113e51f155961205cf92897802108124b1f953e7d2d690fcf11582d014c828af3ab13880ac6f69eefbd6fbdfca8d2eb9c96dfd507cd0bf42be87cdb654781753
7
- data.tar.gz: b8a67793161526eff6a8be4dcd412da2d093228ff95b88c039973a5857da431b93e714b3e6d0d895462e6488a9368564c39b01ebaa6098c36ce7046269b20549
6
+ metadata.gz: 65296b4e141478755d23425f346b80ddfe9f72ffc6bf89fd69f032a86b5f600171e5da53bc07edada254a3f790dfc5375ec1872e710eca106ab124f8f0779855
7
+ data.tar.gz: 86c4ad977fc506e3a21c427a5bd2ea381c5d49d7d28447cdc4154ee576a07d43baf5dbb4d14666cb4d1bd9f63a0ab311f67b7508143e651821105c9eae3bdd45
@@ -1,5 +1,5 @@
1
1
  module Musa
2
- VERSION = '0.21.1'
2
+ VERSION = '0.22.0'
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,37 @@ 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, 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
- 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
+ # 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
- 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
+ Musa::Series::E(clone, base_duration, context: { time: time_start }) do |p, base_duration, context: |
32
+ value = p.shift
40
33
 
41
- run_sequencer = sequencer.nil?
34
+ if value
35
+ r = { time: context[:time], value: value } if !value.nil?
42
36
 
43
- score ||= Musa::Datasets::Score.new
37
+ delta_time = p.shift
38
+ context[:time] += delta_time * base_duration if delta_time
44
39
 
45
- sequencer ||= Sequencer.new(beats_per_bar, ticks_per_beat, do_log: do_log)
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
- if run_sequencer
61
- sequencer.run
62
- score
63
- else
64
- nil
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
@@ -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
@@ -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