musa-dsl 0.14.32 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/README.md +5 -1
  4. data/lib/musa-dsl.rb +54 -11
  5. data/lib/musa-dsl/core-ext.rb +7 -13
  6. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  7. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  8. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  9. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  10. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  11. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  12. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  13. data/lib/musa-dsl/core-ext/with.rb +26 -0
  14. data/lib/musa-dsl/datasets.rb +8 -3
  15. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  16. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  17. data/lib/musa-dsl/datasets/e.rb +61 -0
  18. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  19. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  20. data/lib/musa-dsl/datasets/helper.rb +41 -0
  21. data/lib/musa-dsl/datasets/p.rb +68 -0
  22. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  23. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  24. data/lib/musa-dsl/datasets/ps.rb +113 -0
  25. data/lib/musa-dsl/datasets/score.rb +210 -0
  26. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  27. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  28. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  32. data/lib/musa-dsl/datasets/v.rb +23 -0
  33. data/lib/musa-dsl/generative.rb +5 -5
  34. data/lib/musa-dsl/generative/backboner.rb +274 -0
  35. data/lib/musa-dsl/generative/darwin.rb +102 -96
  36. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  37. data/lib/musa-dsl/generative/markov.rb +56 -53
  38. data/lib/musa-dsl/generative/variatio.rb +234 -222
  39. data/lib/musa-dsl/logger.rb +1 -0
  40. data/lib/musa-dsl/logger/logger.rb +31 -0
  41. data/lib/musa-dsl/matrix.rb +1 -0
  42. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  43. data/lib/musa-dsl/midi.rb +2 -2
  44. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  45. data/lib/musa-dsl/midi/midi-voices.rb +183 -182
  46. data/lib/musa-dsl/music.rb +5 -5
  47. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  48. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  49. data/lib/musa-dsl/music/chords.rb +236 -238
  50. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  51. data/lib/musa-dsl/music/scales.rb +331 -332
  52. data/lib/musa-dsl/musicxml.rb +1 -0
  53. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  54. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  55. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  56. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  57. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  58. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  59. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  60. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  61. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  62. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  63. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  64. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  65. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  66. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  67. data/lib/musa-dsl/neumalang.rb +1 -1
  68. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  69. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  70. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  71. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  72. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  73. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  74. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  75. data/lib/musa-dsl/neumas.rb +5 -0
  76. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  77. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  78. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  79. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  80. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  81. data/lib/musa-dsl/neumas/string-to-neumas.rb +33 -0
  82. data/lib/musa-dsl/repl.rb +1 -1
  83. data/lib/musa-dsl/repl/repl.rb +103 -110
  84. data/lib/musa-dsl/sequencer.rb +1 -1
  85. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +548 -321
  88. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
  89. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
  90. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  91. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  92. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  93. data/lib/musa-dsl/series.rb +1 -1
  94. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  95. data/lib/musa-dsl/series/base-series.rb +171 -168
  96. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  97. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  98. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  99. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  100. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  101. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  102. data/lib/musa-dsl/series/series.rb +2 -0
  103. data/lib/musa-dsl/transcription.rb +4 -0
  104. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  106. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  107. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  108. data/lib/musa-dsl/transport.rb +6 -6
  109. data/lib/musa-dsl/transport/clock.rb +26 -26
  110. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  111. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  112. data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
  113. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  114. data/lib/musa-dsl/transport/timer.rb +28 -26
  115. data/lib/musa-dsl/transport/transport.rb +100 -95
  116. data/musa-dsl.gemspec +3 -3
  117. metadata +73 -24
  118. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  119. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  120. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  121. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  122. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  123. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  124. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  125. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  126. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  127. data/lib/musa-dsl/generative/rules.rb +0 -282
  128. data/lib/musa-dsl/neuma.rb +0 -1
  129. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -0,0 +1,179 @@
1
+ require_relative 'delta-d'
2
+ require_relative 'gdv'
3
+
4
+ require_relative 'helper'
5
+
6
+ using Musa::Extension::InspectNice
7
+
8
+ module Musa::Datasets
9
+ module GDVd
10
+ include DeltaD
11
+ include DeltaI
12
+
13
+ include Helper
14
+
15
+ NaturalKeys = (NaturalKeys +
16
+ [:abs_grade, :abs_sharps, :abs_octave,
17
+ :delta_grade, :delta_sharps, :delta_interval_sign, :delta_interval, :delta_octave,
18
+ :abs_velocity, :delta_velocity,
19
+ :modifiers]).freeze
20
+
21
+ attr_reader :base_duration
22
+
23
+ def base_duration=(value)
24
+ factor = value / (@base_duration || 1)
25
+ @base_duration = value
26
+
27
+ self[:abs_duration] *= factor if has_key?(:abs_duration)
28
+ self[:delta_duration] *= factor if has_key?(:delta_duration)
29
+ end
30
+
31
+ def to_gdv(scale, previous:)
32
+ r = previous.clone.delete_if {|k,_| !GDV::NaturalKeys.include?(k)}.extend GDV
33
+
34
+ r.base_duration = @base_duration
35
+
36
+ if include?(:abs_grade)
37
+ if self[:abs_grade] == :silence
38
+ r[:silence] = true
39
+ else
40
+ r.delete :silence
41
+ r.delete :sharps
42
+
43
+ r[:grade] = scale[self[:abs_grade]].wide_grade
44
+ r[:sharps] = self[:abs_sharps] if include?(:abs_sharps)
45
+ end
46
+
47
+ elsif include?(:delta_grade)
48
+ r.delete :silence
49
+
50
+ r[:grade], r[:sharps] =
51
+ normalize_to_scale(scale,
52
+ scale[r[:grade]].wide_grade + self[:delta_grade],
53
+ (r[:sharps] || 0) + (self[:delta_sharps] || 0))
54
+
55
+ r.delete :sharps if r[:sharps].zero?
56
+
57
+ elsif include?(:delta_interval)
58
+ r.delete :silence
59
+
60
+ sign = self[:delta_interval_sign] || 1
61
+
62
+ r[:grade], r[:sharps] =
63
+ normalize_to_scale scale,
64
+ scale[r[:grade]].wide_grade,
65
+ sign * scale.kind.tuning.scale_system.intervals[self[:delta_interval]]
66
+
67
+ r.delete :sharps if r[:sharps].zero?
68
+
69
+ elsif include?(:delta_sharps)
70
+ r.delete :silence
71
+
72
+ r[:grade], r[:sharps] =
73
+ normalize_to_scale scale,
74
+ scale[r[:grade]].wide_grade,
75
+ (r[:sharps] || 0) + self[:delta_sharps]
76
+
77
+ r.delete :sharps if r[:sharps].zero?
78
+ end
79
+
80
+ if include?(:abs_octave)
81
+ r[:octave] = self[:abs_octave]
82
+ elsif include?(:delta_octave)
83
+ r[:octave] += self[:delta_octave]
84
+ end
85
+
86
+ if include?(:abs_duration)
87
+ r[:duration] = self[:abs_duration]
88
+ elsif include?(:delta_duration)
89
+ r[:duration] += self[:delta_duration]
90
+ elsif include?(:factor_duration)
91
+ r[:duration] *= self[:factor_duration]
92
+ end
93
+
94
+ if include?(:abs_velocity)
95
+ r[:velocity] = self[:abs_velocity]
96
+ elsif include?(:delta_velocity)
97
+ r[:velocity] += self[:delta_velocity]
98
+ end
99
+
100
+ if include?(:modifiers)
101
+ self[:modifiers].each_pair do |k, v|
102
+ r[k] = v
103
+ end
104
+ end
105
+
106
+ (keys - NaturalKeys).each { |k| r[k] = self[k] }
107
+
108
+ r
109
+ end
110
+
111
+ def normalize_to_scale(scale, grade, sharps)
112
+ note = scale[grade].sharp(sharps)
113
+ background = note.background_note
114
+
115
+ if background
116
+ return background.wide_grade, note.background_sharps
117
+ else
118
+ return note.wide_grade, 0
119
+ end
120
+ end
121
+
122
+ def to_neuma
123
+ @base_duration ||= Rational(1,4)
124
+
125
+ attributes = []
126
+
127
+ c = 0
128
+
129
+ if include?(:abs_grade)
130
+ attributes[c] = self[:abs_grade].to_s
131
+
132
+ elsif include?(:delta_grade)
133
+ attributes[c] = positive_sign_of(self[:delta_grade]) + self[:delta_grade].to_s unless self[:delta_grade].zero?
134
+
135
+ elsif include?(:delta_interval)
136
+
137
+ attributes[c] = self[:delta_interval_sign] if include?(:delta_interval_sign)
138
+ attributes[c] ||= ''
139
+ attributes[c] += self[:delta_interval].to_s
140
+ end
141
+
142
+ if include?(:delta_sharps) && !self[:delta_sharps].zero?
143
+ char = self[:delta_sharps] > 0 ? '#' : '_'
144
+ sign = attributes[c].nil? ? positive_sign_of(self[:delta_sharps]) : ''
145
+
146
+ attributes[c] ||= ''
147
+ attributes[c] += sign + char * self[:delta_sharps].abs
148
+ end
149
+
150
+ attributes[c] = '.' if attributes[c].nil? || attributes[c].empty?
151
+
152
+ if include?(:abs_octave)
153
+ attributes[c += 1] = 'o' + self[:abs_octave].to_s
154
+ elsif include?(:delta_octave)
155
+ attributes[c += 1] = sign_of(self[:delta_octave]) + 'o' + self[:delta_octave].abs.to_s if self[:delta_octave] != 0
156
+ end
157
+
158
+ if include?(:abs_duration)
159
+ attributes[c += 1] = (self[:abs_duration] / @base_duration).to_s
160
+ elsif include?(:delta_duration)
161
+ attributes[c += 1] = positive_sign_of(self[:delta_duration]) + (self[:delta_duration] / @base_duration).to_s
162
+ elsif include?(:factor_duration)
163
+ attributes[c += 1] = '*' + self[:factor_duration].to_s
164
+ end
165
+
166
+ if include?(:abs_velocity)
167
+ attributes[c += 1] = velocity_of(self[:abs_velocity])
168
+ elsif include?(:delta_velocity)
169
+ attributes[c += 1] = sign_of(self[:delta_velocity]) + 'f' * self[:delta_velocity].abs
170
+ end
171
+
172
+ (keys - NaturalKeys).each do |k|
173
+ attributes[c += 1] = modificator_string(k, self[k])
174
+ end
175
+
176
+ '(' + attributes.join(' ') + ')'
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,41 @@
1
+ module Musa::Datasets
2
+ module Helper
3
+ protected
4
+
5
+ def positive_sign_of(x)
6
+ x >= 0 ? '+' : ''
7
+ end
8
+
9
+ def sign_of(x)
10
+ '++-'[x <=> 0]
11
+ end
12
+
13
+ def velocity_of(x)
14
+ %w[ppp pp p mp mf f ff fff][x + 3]
15
+ end
16
+
17
+ def modificator_string(modificator, parameter_or_parameters)
18
+ case parameter_or_parameters
19
+ when true
20
+ modificator.to_s
21
+ when Array
22
+ "#{modificator.to_s}(#{parameter_or_parameters.collect { |p| parameter_to_string(p) }.join(', ')})"
23
+ else
24
+ "#{modificator.to_s}(#{parameter_to_string(parameter_or_parameters)})"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def parameter_to_string(parameter)
31
+ case parameter
32
+ when String
33
+ "\"#{parameter}\""
34
+ when Numeric
35
+ "#{parameter}"
36
+ when Symbol
37
+ "#{parameter}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,68 @@
1
+ require_relative 'dataset'
2
+ require_relative 'ps'
3
+
4
+ require_relative '../sequencer'
5
+
6
+ module Musa::Datasets
7
+ module P
8
+ include Dataset
9
+
10
+ def to_ps_serie(base_duration = nil)
11
+ base_duration ||= 1/4r
12
+
13
+ p = clone
14
+
15
+ Musa::Series::E() do
16
+ (p.size >= 3) ?
17
+ { from: p.shift,
18
+ duration: p.shift * base_duration,
19
+ to: p.first,
20
+ right_open: (p.length > 1) }.extend(PS).tap { |_| _.base_duration = base_duration } : nil
21
+ end
22
+ end
23
+
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)
32
+
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?
36
+
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
40
+
41
+ run_sequencer = sequencer.nil?
42
+
43
+ score ||= Musa::Datasets::Score.new
44
+
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)
57
+ end
58
+ end
59
+
60
+ if run_sequencer
61
+ sequencer.run
62
+ score
63
+ else
64
+ nil
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'e'
2
+ require_relative 'v'
3
+
4
+ module Musa::Datasets
5
+ module PackedV
6
+ include AbsI
7
+
8
+ def to_V(mapper)
9
+ case mapper
10
+ when Hash
11
+ mapper.collect { |key, default| self[key] || default }.extend(V)
12
+ when Array
13
+ mapper.collect { |key| self[key] }.extend(V)
14
+ else
15
+ raise ArgumentError, "Expected Hash or Array as mapper but got a #{mapper.class.name}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,44 +1,51 @@
1
- require 'musa-dsl/neuma'
1
+ require_relative 'e'
2
+ require_relative 'gdv'
3
+
4
+ require_relative 'helper'
2
5
 
3
6
  module Musa::Datasets
4
7
  module PDV
5
- include Musa::Neumalang::Dataset
8
+ include AbsD
9
+ include AbsI
10
+
11
+ include Helper
6
12
 
7
- NaturalKeys = [:pitch, :duration, :velocity].freeze
13
+ NaturalKeys = (NaturalKeys + [:pitch, :velocity]).freeze
8
14
 
9
15
  attr_accessor :base_duration
10
16
 
11
17
  def to_gdv(scale)
12
- r = {}.extend Musa::Datasets::GDV
13
- r.base_duration = @base_duration
18
+ gdv = {}.extend GDV
19
+ gdv.base_duration = @base_duration
14
20
 
15
21
  if self[:pitch]
16
22
  if self[:pitch] == :silence
17
- r[:grade] = :silence
23
+ gdv[:grade] = :silence
18
24
  else
19
25
  note = scale.note_of_pitch(self[:pitch], allow_chromatic: true)
20
26
 
21
27
  if background_note = note.background_note
22
- r[:grade] = background_note.grade
23
- r[:octave] = background_note.octave
24
- r[:sharps] = note.background_sharps
28
+ gdv[:grade] = background_note.grade
29
+ gdv[:octave] = background_note.octave
30
+ gdv[:sharps] = note.background_sharps
25
31
  else
26
- r[:grade] = note.grade
27
- r[:octave] = note.octave
32
+ gdv[:grade] = note.grade
33
+ gdv[:octave] = note.octave
28
34
  end
29
35
  end
30
36
  end
31
37
 
32
- r[:duration] = self[:duration] if self[:duration]
38
+ gdv[:duration] = self[:duration] if self[:duration]
33
39
 
34
40
  if self[:velocity]
35
41
  # ppp = 16 ... fff = 127
36
- r[:velocity] = [0..16, 17..32, 33..48, 49..64, 65..80, 81..96, 97..112, 113..127].index { |r| r.cover? self[:velocity] } - 3
42
+ # TODO create a customizable MIDI velocity to score dynamics bidirectional conversor
43
+ gdv[:velocity] = [1..1, 2..8, 9..16, 17..33, 34..49, 49..64, 65..80, 81..96, 97..112, 113..127].index { |r| r.cover? self[:velocity] } - 5
37
44
  end
38
45
 
39
- (keys - NaturalKeys).each { |k| r[k] = self[k] }
46
+ (keys - NaturalKeys).each { |k| gdv[k] = self[k] }
40
47
 
41
- r
48
+ gdv
42
49
  end
43
50
  end
44
51
  end
@@ -0,0 +1,113 @@
1
+ require_relative 'e'
2
+ require_relative 'score'
3
+
4
+ require_relative '../sequencer'
5
+
6
+ module Musa::Datasets
7
+ module PS
8
+ include AbsD
9
+
10
+ include Helper
11
+
12
+ NaturalKeys = (NaturalKeys + [:from, :to, :right_open]).freeze
13
+
14
+ attr_accessor :base_duration
15
+
16
+ def to_neuma
17
+ # TODO ???????
18
+ end
19
+
20
+ def to_pdv
21
+ # TODO ??????
22
+ end
23
+
24
+ def to_gdv
25
+ # TODO ?????
26
+ end
27
+
28
+ def to_absI
29
+ # TODO ?????
30
+ end
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
108
+ else
109
+ duration.rationalize
110
+ end
111
+ end
112
+ end
113
+ end