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
@@ -1,55 +1,59 @@
1
- require_relative 'send-nice'
2
-
3
- module DynamicProxyModule
4
- def method_missing(method_name, *args, **key_args, &block)
5
- if @receiver.respond_to? method_name
6
- @receiver._send_nice method_name, args, key_args, &block
7
- else
8
- super
9
- end
10
- end
1
+ module Musa
2
+ module Extension
3
+ module DynamicProxy
4
+ module DynamicProxyModule
5
+ def method_missing(method_name, *args, **key_args, &block)
6
+ if @receiver.respond_to? method_name
7
+ @receiver.send method_name, *args, **key_args, &block
8
+ else
9
+ super
10
+ end
11
+ end
11
12
 
12
- def respond_to_missing?(method_name, include_private)
13
- @receiver.respond_to?(method_name, include_private) || super
14
- end
13
+ def respond_to_missing?(method_name, include_private)
14
+ @receiver.respond_to?(method_name, include_private) || super
15
+ end
15
16
 
16
- alias _is_a? is_a?
17
+ alias _is_a? is_a?
17
18
 
18
- def is_a?(klass)
19
- _is_a?(klass) || @receiver.is_a?(klass)
20
- end
19
+ def is_a?(klass)
20
+ _is_a?(klass) || @receiver.is_a?(klass)
21
+ end
21
22
 
22
- alias _kind_of? kind_of?
23
+ alias _kind_of? kind_of?
23
24
 
24
- def kind_of?(klass)
25
- _kind_of?(klass) || @receiver.is_a?(klass)
26
- end
25
+ def kind_of?(klass)
26
+ _kind_of?(klass) || @receiver.is_a?(klass)
27
+ end
27
28
 
28
- alias _instance_of? instance_of?
29
+ alias _instance_of? instance_of?
29
30
 
30
- def instance_of?(klass)
31
- _instance_of?(klass) || @receiver.instance_of?(klass)
32
- end
31
+ def instance_of?(klass)
32
+ _instance_of?(klass) || @receiver.instance_of?(klass)
33
+ end
33
34
 
34
- alias _equalequal ==
35
+ alias _equalequal ==
35
36
 
36
- def ==(object)
37
- _equalequal(object) || @receiver.==(object)
38
- end
37
+ def ==(object)
38
+ _equalequal(object) || @receiver.==(object)
39
+ end
39
40
 
40
- alias _eql? eql?
41
+ alias _eql? eql?
41
42
 
42
- def eql?(object)
43
- _eql?(object) || @receiver.eql?(object)
44
- end
45
- end
43
+ def eql?(object)
44
+ _eql?(object) || @receiver.eql?(object)
45
+ end
46
+ end
46
47
 
47
- class DynamicProxy
48
- include DynamicProxyModule
48
+ class DynamicProxy
49
+ include DynamicProxyModule
49
50
 
50
- def initialize(receiver = nil)
51
- @receiver = receiver
52
- end
51
+ def initialize(receiver = nil)
52
+ @receiver = receiver
53
+ end
53
54
 
54
- attr_accessor :receiver
55
+ attr_accessor :receiver
56
+ end
57
+ end
58
+ end
55
59
  end
@@ -1,28 +1,46 @@
1
- class Hash
2
- def inspect
3
- all = collect { |key, value| [', ', key.is_a?(Symbol) ? key.to_s + ': ' : key.to_s + ' => ', value.inspect] }.flatten
4
- all.shift
5
- '{ ' + all.join + ' }'
6
- end
7
- end
1
+ module Musa
2
+ module Extension
3
+ module InspectNice
4
+ refine Hash do
5
+ def inspect
6
+ all = collect { |key, value| [', ', key.is_a?(Symbol) ? key.to_s + ': ' : key.inspect + ' => ', value.inspect] }.flatten
7
+ all.shift
8
+ '{ ' + all.join + ' }'
9
+ end
8
10
 
9
- class Rational
10
- def inspect
11
- d = self - to_i
12
- if d != 0
13
- "#{to_i}(#{d.numerator}/#{d.denominator})"
14
- else
15
- to_i.to_s
16
- end
17
- end
11
+ alias _to_s to_s
12
+ alias to_s inspect
13
+ end
14
+
15
+ refine Rational do
16
+ def inspect(simple: nil)
17
+ value = self.abs
18
+ sign = negative? ? '-' : ''
19
+
20
+ if simple
21
+ if value.denominator == 1
22
+ "#{sign}#{value.numerator}"
23
+ else
24
+ "#{sign}#{value.numerator}/#{value.denominator}"
25
+ end
26
+ else
27
+ sign2 = negative? ? '-' : '+'
28
+
29
+ d = value - value.to_i
18
30
 
19
- alias _to_s to_s
31
+ if d == 0
32
+ "#{sign}#{value.to_i.to_s}r"
33
+ else
34
+ i = "#{value.to_i}#{sign2}" if value.to_i != 0
35
+ "#{sign}#{i}#{d.numerator}/#{d.denominator}r"
36
+ end
37
+ end
38
+ end
20
39
 
21
- def to_s
22
- if to_i == self
23
- to_i.to_s
24
- else
25
- _to_s
40
+ def to_s
41
+ inspect simple: true
42
+ end
43
+ end
26
44
  end
27
45
  end
28
46
  end
@@ -0,0 +1,108 @@
1
+ module Musa
2
+ module Extension
3
+ module SmartProcBinder
4
+ class SmartProcBinder
5
+ def initialize(procedure, on_rescue: nil)
6
+ @procedure = procedure
7
+ @on_rescue = on_rescue
8
+
9
+ @key_parameters = {}
10
+ @has_key_rest = false
11
+
12
+ @value_parameters_count = 0
13
+ @has_value_rest = false
14
+
15
+ procedure.parameters.each do |parameter|
16
+ @key_parameters[parameter[1]] = nil if parameter[0] == :key || parameter[0] == :keyreq
17
+ @has_key_rest = true if parameter[0] == :keyrest
18
+
19
+ @value_parameters_count += 1 if parameter[0] == :req || parameter[0] == :opt
20
+ @has_value_rest = true if parameter[0] == :rest
21
+ end
22
+ end
23
+
24
+ def parameters
25
+ @procedure.parameters
26
+ end
27
+
28
+ def call(*value_parameters, **key_parameters)
29
+ _call value_parameters, key_parameters
30
+ end
31
+
32
+ def _call(value_parameters, key_parameters)
33
+ if @on_rescue
34
+ begin
35
+ __call value_parameters, key_parameters
36
+ rescue StandardError, ScriptError => e
37
+ @on_rescue.call e
38
+ end
39
+ else
40
+ __call value_parameters, key_parameters
41
+ end
42
+ end
43
+
44
+ def __call(value_parameters, key_parameters)
45
+ effective_value_parameters, effective_key_parameters = apply(*value_parameters, **key_parameters)
46
+
47
+ if effective_key_parameters.empty?
48
+ if effective_value_parameters.empty?
49
+ @procedure.call
50
+ else
51
+ @procedure.call *effective_value_parameters
52
+ end
53
+ else
54
+ if effective_value_parameters.empty?
55
+ @procedure.call **effective_key_parameters
56
+ else
57
+ @procedure.call *effective_value_parameters, **effective_key_parameters
58
+ end
59
+ end
60
+ end
61
+
62
+ private :__call
63
+
64
+ def key?(key)
65
+ @has_key_rest || @key_parameters.include?(key)
66
+ end
67
+
68
+ alias_method :has_key?, :key?
69
+
70
+ def apply(*value_parameters, **key_parameters)
71
+ _apply(value_parameters, key_parameters)
72
+ end
73
+
74
+ def _apply(value_parameters, key_parameters)
75
+ value_parameters ||= []
76
+ key_parameters ||= {}
77
+
78
+ if @has_value_rest
79
+ values_result = value_parameters.clone
80
+ else
81
+ values_result = value_parameters.first(@value_parameters_count)
82
+ values_result += Array.new(@value_parameters_count - values_result.size)
83
+ end
84
+
85
+ hash_result = @key_parameters.clone
86
+
87
+ @key_parameters.each_key do |parameter_name|
88
+ hash_result[parameter_name] = key_parameters[parameter_name]
89
+ end
90
+
91
+ if @has_key_rest
92
+ key_parameters.each do |key, value|
93
+ hash_result[key] = value unless hash_result.key?(key)
94
+ end
95
+ end
96
+
97
+ return values_result, hash_result
98
+ end
99
+
100
+ def inspect
101
+ "KeyParametersProcedureBinder: parameters = #{@key_parameters} has_rest = #{@has_key_rest}"
102
+ end
103
+
104
+ alias to_s inspect
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'smart-proc-binder'
2
+
3
+ module Musa
4
+ module Extension
5
+ module With
6
+ def with(*value_parameters, **key_parameters, &block)
7
+ binder = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
8
+
9
+ keep_block_context = binder.parameters[0][1] == :_ unless binder.parameters.empty?
10
+ keep_block_context ||= false
11
+
12
+ effective_value_parameters, effective_key_parameters = binder._apply(value_parameters, key_parameters)
13
+
14
+ if keep_block_context
15
+ binder.call(self, *effective_value_parameters, **effective_key_parameters)
16
+ else
17
+ if effective_value_parameters.empty? && effective_key_parameters.empty?
18
+ instance_eval &block
19
+ else
20
+ instance_exec *effective_value_parameters, **effective_key_parameters, &block
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,10 @@
1
- require 'musa-dsl/datasets/gdv'
2
- require 'musa-dsl/datasets/gdv-decorators'
1
+ require_relative 'datasets/gdv'
2
+ require_relative 'datasets/gdvd'
3
+ require_relative 'datasets/pdv'
3
4
 
4
- require 'musa-dsl/datasets/pdv'
5
+ require_relative 'datasets/packed-v'
6
+ require_relative 'datasets/v'
7
+ require_relative 'datasets/p'
8
+ require_relative 'datasets/ps'
5
9
 
10
+ require_relative 'datasets/score'
@@ -0,0 +1,3 @@
1
+ module Musa::Datasets
2
+ module Dataset; end
3
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'e'
2
+
3
+ module Musa::Datasets
4
+ module DeltaD
5
+ include Delta
6
+
7
+ NaturalKeys = [:abs_duration, # absolute duration
8
+ :delta_duration, # incremental duration
9
+ :factor_duration # multiplicative factor duration
10
+ ].freeze
11
+ end
12
+ end
@@ -0,0 +1,61 @@
1
+ require_relative 'dataset'
2
+
3
+ module Musa::Datasets
4
+ module E
5
+ include Dataset
6
+
7
+ NaturalKeys = [].freeze
8
+ end
9
+
10
+ module Abs
11
+ include E
12
+ def duration; 0; end
13
+ end
14
+
15
+ module Delta
16
+ include E
17
+ end
18
+
19
+ module AbsI
20
+ include Abs
21
+ end
22
+
23
+ module DeltaI
24
+ include Delta
25
+ end
26
+
27
+ module AbsD
28
+ include Abs
29
+
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
34
+
35
+ def forward_duration
36
+ self[:forward_duration] || self[:duration]
37
+ end
38
+
39
+ def note_duration
40
+ self[:note_duration] || self[:duration]
41
+ end
42
+
43
+ def duration
44
+ self[:duration]
45
+ end
46
+
47
+ def self.is_compatible?(thing)
48
+ thing.is_a?(AbsD) || thing.is_a?(Hash) && thing.has_key?(:duration)
49
+ end
50
+
51
+ def self.to_AbsD(thing)
52
+ if thing.is_a?(AbsD)
53
+ thing
54
+ elsif thing.is_a?(Hash) && thing.has_key?(:duration)
55
+ thing.clone.extend(AbsD)
56
+ else
57
+ raise ArgumentError, "Cannot convert #{thing} to AbsD dataset"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,344 +1,28 @@
1
- require 'musa-dsl/neuma'
1
+ require_relative 'e'
2
+ require_relative 'gdvd'
3
+ require_relative 'pdv'
2
4
 
3
- module Musa::Datasets
4
- module GDVd
5
- include Musa::Neumalang::Dataset
6
-
7
- NaturalKeys = [:abs_grade, :abs_sharps, :abs_octave,
8
- :delta_grade, :delta_sharps, :delta_interval_sign, :delta_interval, :delta_octave,
9
- :abs_duration, :delta_duration, :factor_duration,
10
- :abs_velocity, :delta_velocity].freeze
11
-
12
- attr_accessor :base_duration
13
-
14
- def to_gdv(scale, previous:)
15
- r = previous.clone.delete_if {|k,_| !GDV::NaturalKeys.include?(k)}.extend GDV
16
-
17
- r.base_duration = @base_duration
18
-
19
- if include? :abs_grade
20
- if self[:abs_grade] == :silence
21
- r[:silence] = true
22
- else
23
- r.delete :silence
24
- r.delete :sharps
25
-
26
- r[:grade] = scale[self[:abs_grade]].wide_grade
27
- r[:sharps] = self[:abs_sharps] if include?(:abs_sharps)
28
- end
29
-
30
- elsif include?(:delta_grade)
31
- r.delete :silence
32
-
33
- r[:grade], r[:sharps] =
34
- normalize_to_scale(scale,
35
- scale[r[:grade]].wide_grade + self[:delta_grade],
36
- (r[:sharps] || 0) + (self[:delta_sharps] || 0))
37
-
38
- r.delete :sharps if r[:sharps].zero?
39
-
40
- elsif include?(:delta_interval)
41
- r.delete :silence
42
-
43
- sign = self[:delta_interval_sign] || 1
44
-
45
- r[:grade], r[:sharps] =
46
- normalize_to_scale scale,
47
- scale[r[:grade]].wide_grade,
48
- sign * scale.kind.tuning.scale_system.intervals[self[:delta_interval]]
49
-
50
- r.delete :sharps if r[:sharps].zero?
51
-
52
- elsif include?(:delta_sharps)
53
- r.delete :silence
54
-
55
- r[:grade], r[:sharps] =
56
- normalize_to_scale scale,
57
- scale[r[:grade]].wide_grade,
58
- (r[:sharps] || 0) + self[:delta_sharps]
59
-
60
- r.delete :sharps if r[:sharps].zero?
61
- end
62
-
63
- if include?(:abs_octave)
64
- r[:octave] = self[:abs_octave]
65
- elsif include?(:delta_octave)
66
- r[:octave] += self[:delta_octave]
67
- end
68
-
69
- if include?(:abs_duration)
70
- r[:duration] = self[:abs_duration]
71
- elsif include?(:delta_duration)
72
- r[:duration] += self[:delta_duration]
73
- elsif include?(:factor_duration)
74
- r[:duration] *= self[:factor_duration]
75
- end
76
-
77
- if include?(:abs_velocity)
78
- r[:velocity] = self[:abs_velocity]
79
- elsif include?(:delta_velocity)
80
- r[:velocity] += self[:delta_velocity]
81
- end
82
-
83
- (keys - NaturalKeys).each { |k| r[k] = self[k] }
84
-
85
- r
86
- end
87
-
88
- def normalize_to_scale(scale, grade, sharps)
89
- note = scale[grade].sharp(sharps)
90
- background = note.background_note
91
-
92
- if background
93
- return background.wide_grade, note.background_sharps
94
- else
95
- return note.wide_grade, 0
96
- end
97
- end
98
-
99
- def to_neuma(mode = nil)
100
- mode ||= :dots # :parenthesis
101
-
102
- @base_duration ||= Rational(1,4)
103
-
104
- attributes = []
105
-
106
- c = 0
107
-
108
- if include?(:abs_grade)
109
- attributes[c] = self[:abs_grade].to_s
110
-
111
- elsif include?(:delta_grade)
112
- attributes[c] = positive_sign_of(self[:delta_grade]) + self[:delta_grade].to_s unless self[:delta_grade].zero?
113
-
114
- elsif include?(:delta_interval)
115
-
116
- attributes[c] = self[:delta_interval_sign] if include?(:delta_interval_sign)
117
- attributes[c] ||= ''
118
- attributes[c] += self[:delta_interval].to_s
119
- end
120
-
121
- if include?(:delta_sharps) && !self[:delta_sharps].zero?
122
- char = self[:delta_sharps] > 0 ? '#' : '_'
123
- sign = attributes[c].nil? ? positive_sign_of(self[:delta_sharps]) : ''
124
-
125
- attributes[c] ||= ''
126
- attributes[c] += sign + char * self[:delta_sharps].abs
127
- end
128
-
129
- if include?(:abs_octave)
130
- attributes[c += 1] = 'o' + positive_sign_of(self[:abs_octave]) + self[:abs_octave].to_s
131
- elsif include?(:delta_octave)
132
- attributes[c += 1] = sign_of(self[:delta_octave]) + 'o' + self[:delta_octave].abs.to_s if self[:delta_octave] != 0
133
- end
134
-
135
- if include?(:abs_duration)
136
- attributes[c += 1] = (self[:abs_duration] / @base_duration).to_s
137
- elsif include?(:delta_duration)
138
- attributes[c += 1] = positive_sign_of(self[:delta_duration]) + (self[:delta_duration] / @base_duration).to_s
139
- elsif include?(:factor_duration)
140
- attributes[c += 1] = '*' + self[:factor_duration].to_s
141
- end
142
-
143
- if include?(:abs_velocity)
144
- attributes[c += 1] = velocity_of(self[:abs_velocity])
145
- elsif include?(:delta_velocity)
146
- attributes[c += 1] = sign_of(self[:delta_velocity]) + 'f' * self[:delta_velocity].abs
147
- end
148
-
149
- (keys - NaturalKeys).each do |k|
150
- attributes[c += 1] = modificator_string(k, self[k])
151
- end
152
-
153
- if mode == :dots
154
- if !attributes.empty?
155
- attributes.join '.'
156
- else
157
- '.'
158
- end
159
-
160
- elsif mode == :parenthesis
161
- '<' + attributes.join(', ') + '>'
162
- else
163
- attributes
164
- end
165
- end
166
-
167
- module Parser
168
- class << self
169
- def parse(expression, base_duration: nil)
170
- base_duration ||= Rational(1,4)
171
-
172
- neuma = expression.clone
173
-
174
- command = {}.extend GDVd
175
- command.base_duration = base_duration
176
-
177
- grade = neuma.shift
178
-
179
- if grade && !grade.empty?
180
- if '+-#_'.include?(grade[0])
181
- sign, interval, number, sharps = parse_grade(grade)
182
-
183
- sign ||= 1
184
-
185
- command[:delta_grade] = number * sign if number
186
- command[:delta_sharps] = sharps * sign unless sharps.zero?
187
-
188
- command[:delta_interval] = interval if interval
189
- command[:delta_interval_sign] = sign if interval && sign && interval
190
- else
191
- _, name, number, sharps = parse_grade(grade)
5
+ require_relative 'helper'
192
6
 
193
- command[:abs_grade] = name || number
194
- command[:abs_sharps] = sharps unless sharps.zero?
195
- end
196
- end
197
-
198
- octave = neuma.reject {|a| a.is_a?(Hash)}.find { |a| /\A[+-]?o[+-]?[0-9]+\Z/x.match a }
199
-
200
- if octave
201
- if (octave[0] == '+' || octave[0] == '-') && octave[1] == 'o'
202
- command[:delta_octave] = (octave[0] + octave[2..-1]).to_i
203
- elsif octave[0] == 'o'
204
- command[:abs_octave] = octave[1..-1].to_i
205
- end
206
-
207
- neuma.delete octave
208
- end
209
-
210
- to_delete = velocity = neuma.select {|a| a.is_a?(Hash)}.find { |a| /\A(mp | mf | (\+|\-)?(p+|f+))\Z/x.match a[:modifier] }
211
- velocity = velocity[:modifier].to_s if velocity
212
-
213
- velocity ||= to_delete = neuma.reject {|a| a.is_a?(Hash)}.find { |a| /\A(mp | mf | (\+|\-)?(p+|f+))\Z/x.match a }
214
-
215
- if velocity
216
- if velocity[0] == '+' || velocity[0] == '-'
217
- command[:delta_velocity] = (velocity[1] == 'f' ? 1 : -1) * (velocity.length - 1) * (velocity[0] + '1').to_i
218
- elsif velocity[0] == 'm'
219
- command[:abs_velocity] = velocity[1] == 'f' ? 1 : 0
220
- else
221
- command[:abs_velocity] = velocity.length * (velocity[0] == 'f' ? 1 : -1) + (velocity[0] == 'f' ? 1 : 0)
222
- end
223
-
224
- neuma.delete to_delete
225
- end
226
-
227
- duration = neuma.reject {|a| a.is_a?(Hash)}.first
228
-
229
- if duration && !duration.empty?
230
- if duration[0] == '+' || duration[0] == '-'
231
- command[:delta_duration] = (duration[0] == '-' ? -1 : 1) * eval_duration(duration[1..-1]) * base_duration
232
-
233
- elsif /\A\/+·*\Z/x.match(duration)
234
- command[:abs_duration] = eval_duration(duration) * base_duration
235
-
236
- elsif duration[0] == '*'
237
- command[:factor_duration] = eval_duration(duration[1..-1])
238
-
239
- elsif duration[0] == '/'
240
- command[:factor_duration] = Rational(1, eval_duration(duration[1..-1]))
241
-
242
- else
243
- command[:abs_duration] = eval_duration(duration) * base_duration
244
- end
245
- end
246
-
247
- neuma.delete duration if duration
248
-
249
- neuma.select {|a| a.is_a?(Hash)}.each do |a|
250
- command[a[:modifier]] = a[:parameters] || true
251
- end
252
-
253
- raise EncodingError, "Neuma #{neuma} cannot be decoded" unless neuma.reject {|a| a.is_a?(Hash)}.size.zero?
254
-
255
- command
256
- end
257
-
258
- def parse_grade(neuma_grade)
259
- sign = name = wide_grade = nil
260
- accidentals = 0
261
-
262
- case neuma_grade
263
- when Symbol, String
264
- match = /\A(?<sign>[+|-]?)(?<name>[^[#|_]]*)(?<accidental_sharps>#*)(?<accidental_flats>_*)\Z/.match neuma_grade.to_s
265
-
266
- if match
267
- sign = (match[:sign] == '-' ? -1 : 1) unless match[:sign].empty?
268
-
269
- if match[:name] == match[:name].to_i.to_s
270
- wide_grade = match[:name].to_i
271
- else
272
- name = match[:name].to_sym unless match[:name].empty?
273
- end
274
- accidentals = match[:accidental_sharps].length - match[:accidental_flats].length
275
- else
276
- name = neuma_grade.to_sym unless (neuma_grade.nil? || neuma_grade.empty?)
277
- end
278
- when Numeric
279
- wide_grade = neuma_grade.to_i
280
-
281
- else
282
- raise ArgumentError, "Cannot eval #{neuma_grade} as name or grade position."
283
- end
284
-
285
- return sign, name, wide_grade, accidentals
286
- end
287
-
288
- def eval_duration(string)
289
- # format: ///···
290
- #
291
- if match = /\A(?<slashes>\/+)(?<dots>\·*)\Z/x.match(string)
292
- base = Rational(1, 2**match[:slashes].length.to_r)
293
- dots_extension = 0
294
- match[:dots].length.times do |i|
295
- dots_extension += Rational(base, 2**(i+1))
296
- end
297
-
298
- base + dots_extension
299
-
300
- # format: 1··
301
- #
302
- elsif match = /\A(?<number>\d*\/?\d+?)(?<dots>\·*)\Z/x.match(string)
303
- base = match[:number].to_r
304
- dots_extension = 0
305
- match[:dots].length.times do |i|
306
- dots_extension += Rational(base, 2**(i+1))
307
- end
308
-
309
- base + dots_extension
310
-
311
- else
312
- string.to_r
313
- end
314
- end
315
- end
316
- end
317
-
318
- class NeumaDifferentialDecoder < Musa::Neumalang::DifferentialDecoder # to get a GDVd
319
- def initialize(base_duration: nil)
320
- @base_duration = base_duration || Rational(1,4)
321
- end
322
-
323
- def parse(expression)
324
- Parser.parse(expression, base_duration: @base_duration)
325
- end
326
- end
327
- end
7
+ using Musa::Extension::InspectNice
328
8
 
9
+ module Musa::Datasets
329
10
  module GDV
330
- include Musa::Neumalang::Dataset
11
+ include AbsD
12
+ include AbsI
13
+
14
+ include Helper
331
15
 
332
- NaturalKeys = [:grade, :sharps, :octave, :duration, :velocity, :silence].freeze
16
+ NaturalKeys = (NaturalKeys + [:grade, :sharps, :octave, :velocity, :silence]).freeze
333
17
 
334
18
  attr_accessor :base_duration
335
19
 
336
20
  def to_pdv(scale)
337
- r = {}.extend Musa::Datasets::PDV
338
- r.base_duration = @base_duration
21
+ pdv = {}.extend PDV
22
+ pdv.base_duration = @base_duration
339
23
 
340
24
  if self[:grade]
341
- r[:pitch] = if self[:silence]
25
+ pdv[:pitch] = if self[:silence]
342
26
  :silence
343
27
  else
344
28
  scale[self[:grade]].sharp(self[:sharps] || 0).octave(self[:octave] || 0).pitch
@@ -346,22 +30,29 @@ module Musa::Datasets
346
30
  end
347
31
 
348
32
  if self[:duration]
349
- r[:duration] = self[:duration]
33
+ pdv[:duration] = self[:duration]
34
+ end
35
+
36
+ if self[:note_duration]
37
+ pdv[:note_duration] = self[:note_duration]
38
+ end
39
+
40
+ if self[:forward_duration]
41
+ pdv[:forward_duration] = self[:forward_duration]
350
42
  end
351
43
 
352
44
  if self[:velocity]
353
- # ppp = 16 ... fff = 127
354
- r[:velocity] = [16, 32, 48, 64, 80, 96, 112, 127][self[:velocity] + 3]
45
+ # ppp = 16 ... fff = 127 (-5 ... 4) the standard used by Musescore 3 and others starts at ppp = 16
46
+ # TODO create a customizable MIDI velocity to score dynamics bidirectional conversor
47
+ pdv[:velocity] = [1, 8, 16, 33, 49, 64, 80, 96, 112, 127][self[:velocity] + 5]
355
48
  end
356
49
 
357
- (keys - NaturalKeys).each { |k| r[k] = self[k] }
50
+ (keys - NaturalKeys).each { |k| pdv[k] = self[k] }
358
51
 
359
- r
52
+ pdv
360
53
  end
361
54
 
362
- def to_neuma(mode = nil)
363
- mode ||= :dotted # :parenthesis
364
-
55
+ def to_neuma
365
56
  @base_duration ||= Rational(1,4)
366
57
 
367
58
  attributes = []
@@ -381,7 +72,9 @@ module Musa::Datasets
381
72
  end
382
73
  end
383
74
 
384
- attributes[c += 1] = 'o' + positive_sign_of(self[:octave]) + self[:octave].to_s if self[:octave]
75
+ attributes[c] = '.' if attributes[c].nil? || attributes[c].empty?
76
+
77
+ attributes[c += 1] = 'o' + self[:octave].to_s if self[:octave]
385
78
  attributes[c += 1] = (self[:duration] / @base_duration).to_s if self[:duration]
386
79
  attributes[c += 1] = velocity_of(self[:velocity]) if self[:velocity]
387
80
 
@@ -389,14 +82,7 @@ module Musa::Datasets
389
82
  attributes[c += 1] = modificator_string(k, self[k])
390
83
  end
391
84
 
392
- if mode == :dotted
393
- attributes.join '.'
394
-
395
- elsif mode == :parenthesis
396
- '(' + attributes.join(', ') + ')'
397
- else
398
- attributes
399
- end
85
+ '(' + attributes.join(' ') + ')'
400
86
  end
401
87
 
402
88
  def velocity_of(x)
@@ -406,94 +92,48 @@ module Musa::Datasets
406
92
  private :velocity_of
407
93
 
408
94
  def to_gdvd(scale, previous: nil)
409
- r = {}.extend Musa::Datasets::GDVd
410
- r.base_duration = @base_duration
95
+ gdvd = {}.extend GDVd
96
+ gdvd.base_duration = @base_duration
411
97
 
412
98
  if previous
413
99
 
414
100
  if include?(:silence)
415
- r[:abs_grade] = :silence
101
+ gdvd[:abs_grade] = :silence
416
102
 
417
103
  elsif include?(:grade) && !previous.include?(:grade)
418
- r[:abs_grade] = self[:grade]
419
- r[:abs_sharps] = self[:sharps]
104
+ gdvd[:abs_grade] = self[:grade]
105
+ gdvd[:abs_sharps] = self[:sharps]
420
106
 
421
107
  elsif include?(:grade) && previous.include?(:grade)
422
108
  if self[:grade] != previous[:grade] ||
423
109
  (self[:sharps] || 0) != (previous[:sharps] || 0)
424
110
 
425
- r[:delta_grade] = scale[self[:grade]].octave(self[:octave]).wide_grade - scale[previous[:grade]].octave(previous[:octave]).wide_grade
426
- r[:delta_sharps] = (self[:sharps] || 0) - (previous[:sharps] || 0)
111
+ gdvd[:delta_grade] =
112
+ scale[self[:grade]].octave(self[:octave]).wide_grade -
113
+ scale[previous[:grade]].octave(previous[:octave]).wide_grade
114
+
115
+ gdvd[:delta_sharps] = (self[:sharps] || 0) - (previous[:sharps] || 0)
427
116
  end
428
117
  elsif include?(:sharps)
429
- r[:delta_sharps] = self[:sharps] - (previous[:sharps] || 0)
118
+ gdvd[:delta_sharps] = self[:sharps] - (previous[:sharps] || 0)
430
119
  end
431
120
 
432
121
  if self[:duration] && previous[:duration] && (self[:duration] != previous[:duration])
433
- r[:delta_duration] = (self[:duration] - previous[:duration])
122
+ gdvd[:delta_duration] = (self[:duration] - previous[:duration])
434
123
  end
435
124
 
436
125
  if self[:velocity] && previous[:velocity] && (self[:velocity] != previous[:velocity])
437
- r[:delta_velocity] = self[:velocity] - previous[:velocity]
126
+ gdvd[:delta_velocity] = self[:velocity] - previous[:velocity]
438
127
  end
439
128
  else
440
- r[:abs_grade] = self[:grade] if self[:grade]
441
- r[:abs_duration] = self[:duration] if self[:duration]
442
- r[:abs_velocity] = self[:velocity] if self[:velocity]
443
- end
444
-
445
- (keys - NaturalKeys).each { |k| r[k] = self[k] }
446
-
447
- r
448
- end
449
-
450
- class NeumaDecoder < Musa::Neumalang::Decoder # to get a GDV
451
- def initialize(scale, base_duration: nil, processor: nil, **base)
452
- @base_duration = base_duration || Rational(1,4)
453
-
454
- base = { grade: 0, octave: 0, duration: @base_duration, velocity: 1 } if base.empty?
455
-
456
- @scale = scale
457
-
458
- super base, processor: processor
459
- end
460
-
461
- attr_accessor :scale, :base_duration
462
-
463
- def parse(expression)
464
- expression = expression.clone
465
-
466
- appogiatura_neuma = expression.find { |_| _.is_a?(Hash) && _[:appogiatura] }
467
- expression.delete appogiatura_neuma if appogiatura_neuma
468
-
469
- parsed = GDVd::Parser.parse(expression, base_duration: @base_duration)
470
-
471
- if appogiatura_neuma
472
- appogiatura = GDVd::Parser.parse(appogiatura_neuma[:appogiatura], base_duration: @base_duration)
473
- parsed[:appogiatura] = appogiatura
474
- end
475
-
476
- parsed
129
+ gdvd[:abs_grade] = self[:grade] if self[:grade]
130
+ gdvd[:abs_duration] = self[:duration] if self[:duration]
131
+ gdvd[:abs_velocity] = self[:velocity] if self[:velocity]
477
132
  end
478
133
 
479
- def subcontext
480
- NeumaDecoder.new @scale, base_duration: @base_duration, processor: @processor, **@last
481
- end
482
-
483
- def apply(action, on:)
484
- gdv = action.to_gdv @scale, previous: on
485
-
486
- appogiatura_action = action[:appogiatura]
487
- gdv[:appogiatura] = appogiatura_action.to_gdv @scale, previous: on if appogiatura_action
488
-
489
- gdv
490
- end
491
-
492
- def inspect
493
- "GDV NeumaDecoder: @last = #{@last}"
494
- end
134
+ (keys - NaturalKeys).each { |k| gdvd[k] = self[k] }
495
135
 
496
- alias to_s inspect
136
+ gdvd
497
137
  end
498
138
  end
499
139
  end