musa-dsl 0.14.32 → 0.21.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Gemfile +0 -1
  4. data/README.md +5 -1
  5. data/lib/musa-dsl.rb +54 -11
  6. data/lib/musa-dsl/core-ext.rb +7 -13
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  8. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  9. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  10. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  11. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  12. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  13. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  14. data/lib/musa-dsl/core-ext/with.rb +26 -0
  15. data/lib/musa-dsl/datasets.rb +8 -3
  16. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  17. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  18. data/lib/musa-dsl/datasets/e.rb +61 -0
  19. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  20. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  21. data/lib/musa-dsl/datasets/helper.rb +41 -0
  22. data/lib/musa-dsl/datasets/p.rb +68 -0
  23. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  24. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  25. data/lib/musa-dsl/datasets/ps.rb +113 -0
  26. data/lib/musa-dsl/datasets/score.rb +210 -0
  27. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  28. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  32. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  33. data/lib/musa-dsl/datasets/v.rb +23 -0
  34. data/lib/musa-dsl/generative.rb +5 -5
  35. data/lib/musa-dsl/generative/backboner.rb +274 -0
  36. data/lib/musa-dsl/generative/darwin.rb +102 -96
  37. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  38. data/lib/musa-dsl/generative/markov.rb +56 -53
  39. data/lib/musa-dsl/generative/variatio.rb +234 -222
  40. data/lib/musa-dsl/logger.rb +1 -0
  41. data/lib/musa-dsl/logger/logger.rb +32 -0
  42. data/lib/musa-dsl/matrix.rb +1 -0
  43. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  44. data/lib/musa-dsl/midi.rb +2 -2
  45. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  46. data/lib/musa-dsl/midi/midi-voices.rb +187 -182
  47. data/lib/musa-dsl/music.rb +5 -5
  48. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  49. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  50. data/lib/musa-dsl/music/chords.rb +236 -238
  51. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  52. data/lib/musa-dsl/music/scales.rb +331 -332
  53. data/lib/musa-dsl/musicxml.rb +1 -0
  54. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  55. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  56. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  57. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  58. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  59. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  60. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  61. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  62. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  63. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  64. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  65. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  66. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  67. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  68. data/lib/musa-dsl/neumalang.rb +1 -1
  69. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  70. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  71. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  72. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  73. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  74. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  75. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  76. data/lib/musa-dsl/neumas.rb +5 -0
  77. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  78. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  79. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  80. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  81. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  82. data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
  83. data/lib/musa-dsl/repl.rb +1 -1
  84. data/lib/musa-dsl/repl/repl.rb +122 -110
  85. data/lib/musa-dsl/sequencer.rb +1 -1
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +550 -321
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +75 -0
  91. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  92. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  93. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  94. data/lib/musa-dsl/series.rb +1 -1
  95. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  96. data/lib/musa-dsl/series/base-series.rb +171 -168
  97. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  98. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  99. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  100. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  101. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  102. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  103. data/lib/musa-dsl/series/series.rb +2 -0
  104. data/lib/musa-dsl/transcription.rb +4 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  106. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  107. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  108. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  109. data/lib/musa-dsl/transport.rb +6 -6
  110. data/lib/musa-dsl/transport/clock.rb +26 -26
  111. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  112. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  113. data/lib/musa-dsl/transport/input-midi-clock.rb +89 -80
  114. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  115. data/lib/musa-dsl/transport/timer.rb +28 -26
  116. data/lib/musa-dsl/transport/transport.rb +111 -93
  117. data/musa-dsl.gemspec +3 -3
  118. metadata +73 -24
  119. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  120. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  121. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  122. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  123. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  124. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  125. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  126. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  127. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  128. data/lib/musa-dsl/generative/rules.rb +0 -282
  129. data/lib/musa-dsl/neuma.rb +0 -1
  130. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,18 +0,0 @@
1
- # TODO hacer que *_nice permitar recibir atributos para indicar cómo se quieren procesar los parámetros (haciendo *, **, o sin hacer nada)
2
-
3
- class Array
4
- def apply method_name, source
5
-
6
- source = [source] unless source.is_a? Array
7
-
8
- self.each_with_index do |o, i|
9
- o.send method_name, source[i % source.length]
10
- end
11
- end
12
-
13
- def get method_name
14
- self.collect { |o| o.send method_name }
15
- end
16
- end
17
-
18
-
@@ -1,28 +0,0 @@
1
- require 'musa-dsl/series'
2
- require 'musa-dsl/neumalang'
3
-
4
- class Array
5
- def to_neumas
6
- if length > 1
7
- MERGE(*collect { |e| convert_to_neumas(e) })
8
- else
9
- convert_to_neumas(first)
10
- end
11
- end
12
-
13
- alias_method :neumas, :to_neumas
14
- alias_method :n, :to_neumas
15
-
16
- private
17
-
18
- def convert_to_neumas(e)
19
- case e
20
- when Musa::Neumalang::Neumas then e
21
- when Musa::Neumalang::Neuma::Parallel then _SE([e], extends: Musa::Neumalang::Neumas)
22
- when String then e.to_neumas
23
- else
24
- raise ArgumentError, "Don't know how to convert to neumas #{e}"
25
- end
26
- end
27
- end
28
-
@@ -1,44 +0,0 @@
1
- # TODO: hacer que *_nice permitar recibir atributos para indicar cómo se quieren procesar los parámetros (haciendo *, **, o sin hacer nada)
2
-
3
- class Object
4
- def as_context_run(procedure, *list_or_key_args, **key_args)
5
- _as_context_run procedure, list_or_key_args, key_args
6
- end
7
-
8
- def _as_context_run(procedure, list_or_key_args = nil, key_args = nil)
9
- if !list_or_key_args.nil? && list_or_key_args.is_a?(Hash)
10
- key_args = list_or_key_args
11
- list_or_key_args = nil
12
- end
13
-
14
- if procedure.lambda?
15
- if !list_or_key_args.nil? && !list_or_key_args.empty?
16
- if !key_args.nil? && !key_args.empty?
17
- procedure.call *list_or_key_args, **key_args
18
- else
19
- procedure.call *list_or_key_args
20
- end
21
- else
22
- if !key_args.nil? && !key_args.empty?
23
- procedure.call **key_args
24
- else
25
- procedure.call
26
- end
27
- end
28
- else
29
- if !list_or_key_args.nil? && !list_or_key_args.empty?
30
- if !key_args.nil? && !key_args.empty?
31
- instance_exec *list_or_key_args, **key_args, &procedure
32
- else
33
- instance_exec *list_or_key_args, &procedure
34
- end
35
- else
36
- if !key_args.nil? && !key_args.empty?
37
- instance_exec **key_args, &procedure
38
- else
39
- instance_eval &procedure
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,134 +0,0 @@
1
- # Based on https://github.com/adamluzsi/duplicate.rb/blob/master/lib/duplicate.rb
2
- # Modifications by JSY
3
-
4
- module Duplicate
5
- extend self
6
-
7
- def duplicate(object)
8
- register = {}
9
-
10
- _dup(register, object)
11
- end
12
-
13
- protected
14
-
15
- def registered(object, register)
16
- register[object.__id__]
17
- end
18
-
19
- def register_duplication(register, object, duplicate)
20
- register[object.__id__] = duplicate
21
- duplicate
22
- end
23
-
24
- def _dup(register, object)
25
- return registered(object, register) if registered(object, register)
26
- return register_duplication(register, object, object) unless identifiable?(object)
27
-
28
- case object
29
-
30
- when Array
31
- dup_array(register, object)
32
-
33
- when Hash
34
- dup_hash(register, object)
35
-
36
- when Range
37
- dup_range(register, object)
38
-
39
- when Struct
40
- dup_struct(register, object)
41
-
42
- when NilClass, Symbol, Numeric, TrueClass, FalseClass, Method
43
- register_duplication(register, object, object)
44
-
45
- else
46
- dup_object(register, object)
47
-
48
- end
49
- end
50
-
51
- def identifiable?(object)
52
- object.class && object.respond_to?(:is_a?)
53
- rescue NoMethodError
54
- false
55
- end
56
-
57
- def dup_array(register, object)
58
- duplication = dup_object(register, object)
59
- duplication.map! { |e| _dup(register, e) }
60
- end
61
-
62
- def dup_hash(register, object)
63
- duplication = dup_object(register, object)
64
- object.reduce(duplication) { |hash, (k, v)| hash.merge!(_dup(register, k) => _dup(register, v)) }
65
- end
66
-
67
- def dup_range(register, range)
68
- register_duplication(register, range, range.class.new(_dup(register, range.first), _dup(register, range.last)))
69
- rescue StandardError
70
- register_duplication(register, range, range.dup)
71
- end
72
-
73
- def dup_struct(register, struct)
74
- duplication = register_duplication(register, struct, struct.dup)
75
-
76
- struct.each_pair do |attr, value|
77
- duplication.__send__("#{attr}=", _dup(register, value))
78
- end
79
-
80
- duplication
81
- end
82
-
83
- def dup_object(register, object)
84
- dup_instance_variables(register, object, register_duplication(register, object, try_dup(object)))
85
- end
86
-
87
- def dup_instance_variables(register, object, duplication)
88
- return duplication unless respond_to_instance_variables?(object)
89
-
90
- object.instance_variables.each do |instance_variable|
91
- value = get_instance_variable(object, instance_variable)
92
-
93
- set_instance_variable(duplication, instance_variable, _dup(register, value))
94
- end
95
-
96
- duplication
97
- end
98
-
99
- def get_instance_variable(object, instance_variable_name)
100
- object.instance_variable_get(instance_variable_name)
101
- rescue NoMethodError
102
- object.instance_eval(instance_variable_name.to_s)
103
- end
104
-
105
- def set_instance_variable(duplicate, instance_variable_name, value_to_set)
106
- duplicate.instance_variable_set(instance_variable_name, value_to_set)
107
- rescue NoMethodError
108
- duplicate.instance_eval("#{instance_variable_name} = Marshal.load(#{Marshal.dump(value_to_set).inspect})")
109
- end
110
-
111
- def try_dup(object)
112
- o = object.dup
113
-
114
- o.tap do
115
- object.singleton_class.included_modules.each do |m|
116
- o.extend m unless o.is_a? m
117
- end
118
- end
119
- rescue NoMethodError, TypeError
120
- object
121
- end
122
-
123
- def respond_to_instance_variables?(object)
124
- object.respond_to?(:instance_variables) && object.instance_variables.is_a?(Array)
125
- rescue NoMethodError
126
- false
127
- end
128
- end
129
-
130
- class Object
131
- def duplicate
132
- Duplicate.duplicate(self)
133
- end
134
- end
@@ -1,85 +0,0 @@
1
- class KeyParametersProcedureBinder
2
- attr_reader :procedure
3
-
4
- def initialize(procedure, on_rescue: nil)
5
- @procedure = procedure
6
- @on_rescue = on_rescue
7
-
8
- @parameters = {}
9
- @has_rest = false
10
- @value_parameters_count = 0
11
-
12
- procedure.parameters.each do |parameter|
13
- @parameters[parameter[1]] = nil if parameter[0] == :key || parameter[0] == :keyreq
14
- @has_rest = true if parameter[0] == :keyrest
15
-
16
- @value_parameters_count += 1 if parameter[0] == :req || parameter[0] == :opt
17
- end
18
- end
19
-
20
- def call(*value_parameters, **key_parameters)
21
- _call value_parameters, key_parameters
22
- end
23
-
24
- def _call(value_parameters, key_parameters)
25
- if @on_rescue
26
- begin
27
- __call value_parameters, key_parameters
28
- rescue StandardError, ScriptError => e
29
- @on_rescue.call e
30
- end
31
- else
32
- __call value_parameters, key_parameters
33
- end
34
- end
35
-
36
- def __call(value_parameters, key_parameters)
37
- effective_key_parameters = apply(key_parameters)
38
-
39
- if effective_key_parameters.empty?
40
- if value_parameters.nil? || value_parameters.empty? || @value_parameters_count == 0
41
- @procedure.call
42
- else
43
- @procedure.call *value_parameters.first(@value_parameters_count)
44
- end
45
- else
46
- if value_parameters.nil? || value_parameters.empty?
47
- @procedure.call **effective_key_parameters
48
- else
49
- @procedure.call *value_parameters, **effective_key_parameters
50
- end
51
- end
52
- end
53
-
54
- private :__call
55
-
56
- def key?(key)
57
- @has_rest || @parameters.include?(key)
58
- end
59
-
60
- alias_method :has_key?, :key?
61
-
62
- def apply(hsh)
63
- hsh ||= {}
64
-
65
- result = @parameters.clone
66
-
67
- @parameters.each_key do |parameter_name|
68
- result[parameter_name] = hsh[parameter_name]
69
- end
70
-
71
- if @has_rest
72
- hsh.each do |key, value|
73
- result[key] = value unless result.key?(key)
74
- end
75
- end
76
-
77
- result
78
- end
79
-
80
- def inspect
81
- "KeyParametersProcedureBinder: parameters = #{@parameters} has_rest = #{@has_rest}"
82
- end
83
-
84
- alias to_s inspect
85
- end
@@ -1,13 +0,0 @@
1
- class Proc
2
- def _call(value_args, key_value_args)
3
- if value_args && key_value_args
4
- call(*value_args, **key_value_args)
5
- elsif value_args
6
- call(*value_args)
7
- elsif key_value_args
8
- call(**key_value_args)
9
- else
10
- call
11
- end
12
- end
13
- end
@@ -1,21 +0,0 @@
1
- class Object
2
- def send_nice(method_name, *args, **key_args, &block)
3
- _send_nice method_name, args, key_args, &block
4
- end
5
-
6
- def _send_nice(method_name, args, key_args, &block)
7
- if args && !args.empty?
8
- if key_args && !key_args.empty?
9
- send method_name, *args, **key_args, &block
10
- else
11
- send method_name, *args, &block
12
- end
13
- else
14
- if key_args && !key_args.empty?
15
- send method_name, **key_args, &block
16
- else
17
- send method_name, &block
18
- end
19
- end
20
- end
21
- end
@@ -1,27 +0,0 @@
1
- require 'musa-dsl/neumalang'
2
- require 'musa-dsl/generative/generative-grammar'
3
-
4
- class String
5
- def to_neumas(language: nil, decode_with: nil, debug: nil)
6
- Musa::Neumalang.parse(self, language: language, decode_with: decode_with, debug: debug)
7
- end
8
-
9
- def to_neumas_to_node(language: nil, decode_with: nil, debug: nil)
10
- to_neumas(language: language, decode_with: decode_with, debug: debug).to_node
11
- end
12
-
13
- def |(other)
14
- case other
15
- when String
16
- { kind: :parallel,
17
- parallel: [{ kind: :serie, serie: self.to_neumas },
18
- { kind: :serie, serie: other.to_neumas }] }.extend(Musa::Neumalang::Neuma::Parallel)
19
- else
20
- raise ArgumentError, "Don't know how to parallelize #{other}"
21
- end
22
- end
23
-
24
- alias_method :neumas, :to_neumas
25
- alias_method :n, :to_neumas
26
- alias_method :nn, :to_neumas_to_node
27
- end
@@ -1,221 +0,0 @@
1
- module Musa::Datasets::GDV
2
-
3
- # Process: appogiatura (neuma)neuma
4
- class AppogiaturaDecorator < TwoNeumasDecorator
5
- def process(gdv, base_duration:, tick_duration:)
6
- if gdv_appogiatura = gdv[:appogiatura]
7
- gdv.delete :appogiatura
8
-
9
- # TODO process with Decorators the gdv_appogiatura
10
- # TODO implement also posterior appogiatura neuma(neuma)
11
- # TODO implement also multiple appogiatura with several notes (neuma neuma)neuma or neuma(neuma neuma)
12
-
13
- gdv[:duration] = gdv[:duration] - gdv_appogiatura[:duration]
14
-
15
- [ gdv_appogiatura, gdv ]
16
- else
17
- gdv
18
- end
19
- end
20
- end
21
-
22
- # Process: .mor
23
- class MordentDecorator < Decorator
24
- def initialize(duration_factor: nil)
25
- @duration_factor = duration_factor || 1/4r
26
- end
27
-
28
- def process(gdv, base_duration:, tick_duration:)
29
- mor = gdv.delete :mor
30
-
31
- if mor
32
- direction = :up
33
-
34
- check(mor) do |mor|
35
- case mor
36
- when true, :up
37
- direction = :up
38
- when :down, :low
39
- direction = :down
40
- end
41
- end
42
-
43
- short_duration = [base_duration * @duration_factor, tick_duration].max
44
-
45
- gdvs = []
46
-
47
- gdvs << gdv.clone.tap { |gdv| gdv[:duration] = short_duration }
48
-
49
- case direction
50
- when :up
51
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 1; gdv[:duration] = short_duration }
52
- when :down
53
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] -= 1; gdv[:duration] = short_duration }
54
- end
55
-
56
- gdvs << gdv.clone.tap { |gdv| gdv[:duration] -= 2 * short_duration }
57
-
58
- gdvs
59
- else
60
- gdv
61
- end
62
- end
63
- end
64
-
65
- # Process: .turn
66
- class TurnDecorator < Decorator
67
- def process(gdv, base_duration:, tick_duration:)
68
- turn = gdv.delete :turn
69
-
70
- if turn
71
- start = :up
72
-
73
- check(turn) do |turn|
74
- case turn
75
- when :true, :up
76
- start = :up
77
- when :down, :low
78
- start = :down
79
- end
80
- end
81
-
82
- duration = gdv[:duration] / 4r
83
-
84
- gdvs = []
85
-
86
- case start
87
- when :up
88
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 1; gdv[:duration] = duration }
89
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 0; gdv[:duration] = duration }
90
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += -1; gdv[:duration] = duration }
91
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 0; gdv[:duration] = duration }
92
- when :down
93
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += -1; gdv[:duration] = duration }
94
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 0; gdv[:duration] = duration }
95
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 1; gdv[:duration] = duration }
96
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += 0; gdv[:duration] = duration }
97
- end
98
-
99
- gdvs
100
- else
101
- gdv
102
- end
103
- end
104
- end
105
-
106
- # Process: .tr
107
- class TrillDecorator < Decorator
108
- def initialize(duration_factor: nil)
109
- @duration_factor = duration_factor || 1/4r
110
- end
111
-
112
- def process(gdv, base_duration:, tick_duration:)
113
- if gdv[:tr]
114
- tr = gdv.delete :tr
115
-
116
- note_duration = base_duration * @duration_factor
117
-
118
- check(tr) do |tr|
119
- case tr
120
- when Numeric # duration factor
121
- note_duration *= base_duration * tr.to_r
122
- end
123
- end
124
-
125
- used_duration = 0r
126
- last = nil
127
-
128
- gdvs = []
129
-
130
- check(tr) do |tr|
131
- case tr
132
- when :low # start with lower note
133
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = -1); gdv[:duration] = note_duration }
134
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration }
135
- used_duration += 2 * note_duration
136
-
137
- when :low2 # start with upper note but go to lower note once
138
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration }
139
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration }
140
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = -1); gdv[:duration] = note_duration }
141
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration }
142
- used_duration += 4 * note_duration
143
-
144
- when :same # start with the same note
145
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration }
146
- used_duration += note_duration
147
- end
148
- end
149
-
150
- 2.times do
151
- if used_duration + 2 * note_duration <= gdv[:duration]
152
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration }
153
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration }
154
-
155
- used_duration += 2 * note_duration
156
- end
157
- end
158
-
159
- while used_duration + 2 * note_duration * 2/3r <= gdv[:duration]
160
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = note_duration * 2/3r }
161
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = note_duration * 2/3r }
162
-
163
- used_duration += 2 * note_duration * 2/3r
164
- end
165
-
166
- duration_diff = gdv[:duration] - used_duration
167
- if duration_diff >= note_duration
168
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 1); gdv[:duration] = duration_diff / 2 }
169
- gdvs << gdv.clone.tap { |gdv| gdv[:grade] += (last = 0); gdv[:duration] = duration_diff / 2 }
170
-
171
- elsif duration_diff > 0
172
- gdvs[-1][:duration] += duration_diff / 2
173
- gdvs[-2][:duration] += duration_diff / 2
174
- end
175
-
176
- gdvs
177
- else
178
- gdv
179
- end
180
- end
181
- end
182
-
183
- # Process: .st .st(1) .st(2) .st(3): staccato level 1 2 3
184
- class StaccatoDecorator < Decorator
185
- def initialize(min_duration_factor: nil)
186
- @min_duration_factor = min_duration_factor || 1/8r
187
- end
188
-
189
- def process(gdv, base_duration:, tick_duration:)
190
- st = gdv.delete :st
191
-
192
- if st
193
- calculated = 0
194
-
195
- check(st) do |st|
196
- case st
197
- when true
198
- calculated = gdv[:duration] / 2r
199
- when Numeric
200
- calculated = gdv[:duration] / 2**st if st >= 1
201
- end
202
- end
203
-
204
- gdv[:effective_duration] = [calculated, base_duration * @min_duration_factor].max
205
- end
206
-
207
- gdv
208
- end
209
- end
210
-
211
- # Process: .base .b
212
- class BaseDecorator < Decorator
213
- def process(gdv, base_duration:, tick_duration:)
214
- base = gdv.delete :base
215
- base ||= gdv.delete :b
216
-
217
- base ? { duration: 0 }.extend(Musa::Datasets::GDV) : gdv
218
- end
219
- end
220
-
221
- end