musicality 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +5 -5
  2. data/.coveralls.yml +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +4 -0
  5. data/ChangeLog.md +11 -0
  6. data/README.md +3 -0
  7. data/Rakefile +11 -3
  8. data/lib/musicality/composition/model/rhythm.rb +33 -0
  9. data/lib/musicality/composition/model/rhythm_class.rb +30 -0
  10. data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
  11. data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
  12. data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
  13. data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
  14. data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
  15. data/lib/musicality/composition/sequencing/note_array.rb +33 -0
  16. data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
  17. data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
  18. data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
  19. data/lib/musicality/errors.rb +2 -2
  20. data/lib/musicality/notation/model/dynamics.rb +2 -2
  21. data/lib/musicality/notation/model/key.rb +42 -91
  22. data/lib/musicality/notation/model/keys.rb +35 -34
  23. data/lib/musicality/notation/model/note.rb +31 -9
  24. data/lib/musicality/notation/model/pitch.rb +2 -2
  25. data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
  26. data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
  27. data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
  28. data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
  29. data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
  30. data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
  31. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
  32. data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
  33. data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
  34. data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
  35. data/lib/musicality/notation/parsing/parseable.rb +13 -17
  36. data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
  37. data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
  38. data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
  39. data/lib/musicality/performance/model/note_sequence.rb +22 -3
  40. data/lib/musicality/performance/supercollider/performer.rb +2 -2
  41. data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
  42. data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
  43. data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
  44. data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
  45. data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
  46. data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
  47. data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
  48. data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
  49. data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
  50. data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
  51. data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
  52. data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
  53. data/lib/musicality/pitch_class.rb +1 -1
  54. data/lib/musicality/pitch_classes.rb +3 -5
  55. data/lib/musicality/version.rb +1 -1
  56. data/lib/musicality.rb +25 -1
  57. data/musicality.gemspec +3 -2
  58. data/spec/composition/convenience_methods_spec.rb +8 -8
  59. data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
  60. data/spec/composition/model/pitch_class_spec.rb +22 -16
  61. data/spec/composition/model/pitch_classes_spec.rb +5 -5
  62. data/spec/composition/model/rhythm_class_spec.rb +42 -0
  63. data/spec/composition/model/rhythm_spec.rb +43 -0
  64. data/spec/composition/model/scale_class_spec.rb +26 -26
  65. data/spec/composition/model/scale_spec.rb +38 -38
  66. data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
  67. data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
  68. data/spec/composition/sequencing/note_array_spec.rb +94 -0
  69. data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
  70. data/spec/composition/sequencing/sequencer_spec.rb +76 -0
  71. data/spec/composition/util/adding_sequence_spec.rb +33 -33
  72. data/spec/composition/util/compound_sequence_spec.rb +6 -6
  73. data/spec/composition/util/note_generation_spec.rb +34 -34
  74. data/spec/composition/util/probabilities_spec.rb +7 -7
  75. data/spec/composition/util/random_sampler_spec.rb +3 -3
  76. data/spec/composition/util/repeating_sequence_spec.rb +28 -28
  77. data/spec/musicality_spec.rb +1 -1
  78. data/spec/notation/conversion/change_conversion_spec.rb +87 -87
  79. data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
  80. data/spec/notation/conversion/score_conversion_spec.rb +1 -1
  81. data/spec/notation/conversion/score_converter_spec.rb +31 -31
  82. data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
  83. data/spec/notation/model/change_spec.rb +80 -80
  84. data/spec/notation/model/key_spec.rb +135 -69
  85. data/spec/notation/model/link_spec.rb +27 -27
  86. data/spec/notation/model/meter_spec.rb +28 -28
  87. data/spec/notation/model/note_spec.rb +68 -47
  88. data/spec/notation/model/part_spec.rb +19 -19
  89. data/spec/notation/model/pitch_spec.rb +69 -68
  90. data/spec/notation/model/score_spec.rb +50 -47
  91. data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
  92. data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
  93. data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
  94. data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
  95. data/spec/notation/parsing/key_parsing_spec.rb +19 -0
  96. data/spec/notation/parsing/link_nodes_spec.rb +7 -7
  97. data/spec/notation/parsing/link_parsing_spec.rb +4 -4
  98. data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
  99. data/spec/notation/parsing/note_node_spec.rb +19 -19
  100. data/spec/notation/parsing/note_parsing_spec.rb +4 -4
  101. data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
  102. data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
  103. data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
  104. data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
  105. data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
  106. data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
  107. data/spec/notation/parsing/pitch_node_spec.rb +7 -7
  108. data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
  109. data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
  110. data/spec/notation/util/function_spec.rb +15 -15
  111. data/spec/notation/util/transition_spec.rb +12 -12
  112. data/spec/notation/util/value_computer_spec.rb +35 -36
  113. data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
  114. data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
  115. data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
  116. data/spec/performance/midi/midi_util_spec.rb +41 -41
  117. data/spec/performance/midi/part_sequencer_spec.rb +10 -10
  118. data/spec/performance/midi/score_sequencer_spec.rb +15 -15
  119. data/spec/performance/midi/score_sequencing_spec.rb +2 -2
  120. data/spec/performance/util/optimization_spec.rb +9 -9
  121. data/spec/printing/note_engraving_spec.rb +16 -16
  122. data/spec/printing/score_engraver_spec.rb +5 -5
  123. data/spec/spec_helper.rb +5 -0
  124. metadata +85 -30
@@ -51,6 +51,7 @@ module NonnegativeInteger
51
51
  else
52
52
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
53
53
  r0.extend(NonnegativeInteger0)
54
+ r0.extend(NonnegativeInteger0)
54
55
  end
55
56
 
56
57
  node_cache[:nonnegative_integer][start_index] = r0
@@ -52,7 +52,7 @@ module NonnegativeRational
52
52
  r2 = true
53
53
  @index += match_len
54
54
  else
55
- terminal_parse_failure("/")
55
+ terminal_parse_failure('"/"')
56
56
  r2 = nil
57
57
  end
58
58
  s0 << r2
@@ -36,18 +36,21 @@ module PositiveFloat
36
36
  r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
37
37
  r0 = r1
38
38
  r0.extend(PositiveFloat0)
39
+ r0.extend(PositiveFloat0)
39
40
  else
40
41
  r2 = _nt_float2
41
42
  if r2
42
43
  r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
43
44
  r0 = r2
44
45
  r0.extend(PositiveFloat0)
46
+ r0.extend(PositiveFloat0)
45
47
  else
46
48
  r3 = _nt_float3
47
49
  if r3
48
50
  r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
49
51
  r0 = r3
50
52
  r0.extend(PositiveFloat0)
53
+ r0.extend(PositiveFloat0)
51
54
  else
52
55
  @index = i0
53
56
  r0 = nil
@@ -436,7 +439,7 @@ module PositiveFloat
436
439
  r1 = true
437
440
  @index += match_len
438
441
  else
439
- terminal_parse_failure("e")
442
+ terminal_parse_failure('"e"')
440
443
  r1 = nil
441
444
  end
442
445
  s0 << r1
@@ -50,7 +50,7 @@ module PositiveRational
50
50
  r2 = true
51
51
  @index += match_len
52
52
  else
53
- terminal_parse_failure("/")
53
+ terminal_parse_failure('"/"')
54
54
  r2 = nil
55
55
  end
56
56
  s0 << r2
@@ -3,28 +3,24 @@ module Musicality
3
3
  # to use, include Parseable and define PARSER constant that has #parse method.
4
4
  module Parseable
5
5
  DEFAULT_SPLIT_PATTERN = " "
6
-
6
+
7
7
  def self.included(base)
8
8
  base.extend(ClassMethods)
9
9
  end
10
-
10
+
11
11
  module ClassMethods
12
- def parser
13
- self.const_get(:PARSER)
14
- end
15
-
16
- def convert node
17
- node.send(self.const_get(:CONVERSION_METHOD))
18
- end
19
-
20
12
  def parse str
21
- convert(parser.parse(str))
13
+ parser = self.const_get(:PARSER)
14
+ node = parser.parse(str)
15
+ raise ParseError, "Failed to parse #{str}" if node.nil?
16
+
17
+ node.send(self.const_get(:CONVERSION_METHOD))
22
18
  end
23
-
19
+
24
20
  def split_parse str, pattern=" "
25
- str.split(pattern).map {|x| convert(parser.parse(x)) }
26
- end
27
- end
28
- end
21
+ str.split(pattern).map {|x| parse(x) }
22
+ end
23
+ end
24
+ end
29
25
 
30
- end
26
+ end
@@ -252,6 +252,7 @@ module Pitch
252
252
  if has_terminal?(@regexps[gr = '\A[Aa]'] ||= Regexp.new(gr), :regexp, index)
253
253
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
254
254
  r0.extend(LetterA0)
255
+ r0.extend(LetterA0)
255
256
  @index += 1
256
257
  else
257
258
  terminal_parse_failure('[Aa]')
@@ -281,6 +282,7 @@ module Pitch
281
282
  if has_terminal?(@regexps[gr = '\A[Bb]'] ||= Regexp.new(gr), :regexp, index)
282
283
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
283
284
  r0.extend(LetterB0)
285
+ r0.extend(LetterB0)
284
286
  @index += 1
285
287
  else
286
288
  terminal_parse_failure('[Bb]')
@@ -310,6 +312,7 @@ module Pitch
310
312
  if has_terminal?(@regexps[gr = '\A[Cc]'] ||= Regexp.new(gr), :regexp, index)
311
313
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
312
314
  r0.extend(LetterC0)
315
+ r0.extend(LetterC0)
313
316
  @index += 1
314
317
  else
315
318
  terminal_parse_failure('[Cc]')
@@ -339,6 +342,7 @@ module Pitch
339
342
  if has_terminal?(@regexps[gr = '\A[Dd]'] ||= Regexp.new(gr), :regexp, index)
340
343
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
341
344
  r0.extend(LetterD0)
345
+ r0.extend(LetterD0)
342
346
  @index += 1
343
347
  else
344
348
  terminal_parse_failure('[Dd]')
@@ -368,6 +372,7 @@ module Pitch
368
372
  if has_terminal?(@regexps[gr = '\A[Ee]'] ||= Regexp.new(gr), :regexp, index)
369
373
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
370
374
  r0.extend(LetterE0)
375
+ r0.extend(LetterE0)
371
376
  @index += 1
372
377
  else
373
378
  terminal_parse_failure('[Ee]')
@@ -397,6 +402,7 @@ module Pitch
397
402
  if has_terminal?(@regexps[gr = '\A[Ff]'] ||= Regexp.new(gr), :regexp, index)
398
403
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
399
404
  r0.extend(LetterF0)
405
+ r0.extend(LetterF0)
400
406
  @index += 1
401
407
  else
402
408
  terminal_parse_failure('[Ff]')
@@ -426,6 +432,7 @@ module Pitch
426
432
  if has_terminal?(@regexps[gr = '\A[Gg]'] ||= Regexp.new(gr), :regexp, index)
427
433
  r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
428
434
  r0.extend(LetterG0)
435
+ r0.extend(LetterG0)
429
436
  @index += 1
430
437
  else
431
438
  terminal_parse_failure('[Gg]')
@@ -70,6 +70,9 @@ module Segment
70
70
  @index = i2
71
71
  r2 = nil
72
72
  else
73
+ if s2.size < 3
74
+ @terminal_failures.pop
75
+ end
73
76
  r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
74
77
  end
75
78
  s0 << r2
@@ -7,97 +7,56 @@ class NoteSequenceExtractor
7
7
  mark_slurring
8
8
  remove_bad_links
9
9
  calculate_offsets
10
- establish_maps
10
+
11
11
  # now, ready to extract sequences!
12
12
  end
13
-
13
+
14
14
  def extract_sequences cents_per_step = 10
15
- return [] if @notes.empty?
16
-
17
- next_seqs = seqs_from_note(@notes.size-1, cents_per_step)
18
- return next_seqs if @notes.one?
19
-
20
- complete_seqs = []
21
- (@notes.size-2).downto(0) do |i|
22
- cur_seqs = seqs_from_note(i, cents_per_step)
23
- map = @maps[i]
24
-
25
- next_seqs.each do |next_seq|
26
- p1 = nil
27
- p2 = next_seq.elements.first.pitch
28
- if p1 = map[:ties].key(p2)
29
- cur_seq = cur_seqs.find {|x| x.elements.first.pitch == p1 }
30
- NoteSequenceExtractor.tie_seqs(cur_seq, next_seq)
31
- elsif p1 = map[:slurs].key(p2)
32
- cur_seq = cur_seqs.find {|x| x.elements.first.pitch == p1 }
33
- NoteSequenceExtractor.slur_seqs(cur_seq, next_seq)
34
- elsif p1 = map[:full_glissandos].key(p2)
35
- cur_seq = cur_seqs.find {|x| x.elements.first.pitch == p1 }
36
- NoteSequenceExtractor.glissando_seqs(cur_seq, next_seq)
37
- elsif p1 = map[:full_portamentos].key(p2)
38
- cur_seq = cur_seqs.find {|x| x.elements.first.pitch == p1 }
39
- NoteSequenceExtractor.portamento_seqs(cur_seq, next_seq, cents_per_step)
15
+ completed_seqs = []
16
+ continuing_sequences = {}
17
+
18
+ @notes.each_with_index do |note, idx|
19
+ offset = @offsets[idx]
20
+ duration = note.duration
21
+ attack = NoteSequenceExtractor.note_attack(note.articulation)
22
+ separation = NoteSequenceExtractor.note_separation(note.articulation, @slurring_flags[idx])
23
+
24
+ next_note = (idx == (@notes.size-1)) ? Note.quarter : @notes[idx+1]
25
+ continuation_map = NoteSequenceExtractor.continuation_map(note, next_note, separation)
26
+
27
+ new_continuing_sequences = {}
28
+
29
+ note.pitches.each do |p|
30
+ seq = if continuing_sequences.has_key?(p)
31
+ continuing_sequences[p].elements += note_pitch_elements(note, p, Attack::NONE, cents_per_step)
32
+ continuing_sequences.delete(p)
40
33
  else
41
- complete_seqs.push next_seq
34
+ NoteSequence.new(offset, separation, note_pitch_elements(note, p, attack, cents_per_step))
42
35
  end
43
- end
44
- next_seqs = cur_seqs
45
- end
46
- complete_seqs += next_seqs
47
- return complete_seqs
48
- end
49
-
50
- private
51
-
52
- def self.tie_seqs(cur_seq, next_seq)
53
- cur_seq.elements.last.duration += next_seq.elements.first.duration
54
- cur_seq.elements += next_seq.elements[1..-1]
55
- end
56
-
57
- def self.slur_seqs(cur_seq, next_seq)
58
- if next_seq.elements.first.attack == Attack::NORMAL
59
- next_seq.elements.first.attack = Attack::NONE
60
- end
61
- cur_seq.separation = next_seq.separation
62
- cur_seq.elements += next_seq.elements
63
- end
64
36
 
65
- def self.glissando_seqs(cur_seq, next_seq)
66
- cur_seq.elements = GlissandoConverter.glissando_elements(cur_seq.last_pitch,
67
- next_seq.first_pitch, cur_seq.full_duration, cur_seq.last_attack)
68
- cur_seq.separation = next_seq.separation
69
- cur_seq.elements += next_seq.elements
70
- end
37
+ if continuation_map.include?(p)
38
+ new_continuing_sequences[continuation_map[p]] = seq
39
+ else
40
+ completed_seqs.push seq
41
+ end
42
+ end
71
43
 
72
- def self.portamento_seqs(cur_seq, next_seq, cents_per_step)
73
- cur_seq.elements = PortamentoConverter.portamento_elements(cur_seq.last_pitch,
74
- next_seq.first_pitch, cents_per_step, cur_seq.full_duration, cur_seq.last_attack)
75
- cur_seq.separation = Separation::NONE
76
- cur_seq.elements += next_seq.elements
77
- end
78
-
79
- def seqs_from_note(idx, cents_per_step)
80
- map = @maps[idx]
81
- note = @notes[idx]
82
- attack = NoteSequenceExtractor.note_attack(note.articulation)
83
- separation = NoteSequenceExtractor.note_separation(note.articulation, @slurring_flags[idx])
84
- offset = @offsets[idx]
85
- note.pitches.map do |p|
86
- if map[:half_glissandos].has_key?(p)
87
- NoteSequence.new(offset, separation,
88
- GlissandoConverter.glissando_elements(
89
- p, map[:half_glissandos][p], note.duration, attack))
90
- elsif map[:half_portamentos].has_key?(p)
91
- NoteSequence.new(offset, Separation::NONE,
92
- PortamentoConverter.portamento_elements(
93
- p, map[:half_portamentos][p], cents_per_step, note.duration, attack))
94
- else
95
- NoteSequence.new(offset, separation,
96
- [NoteSequence::Element.new(note.duration, p, attack)])
44
+ if continuing_sequences.any?
45
+ require 'pry'
46
+ binding.pry
47
+ # raise "Should be no previous continuing sequences remaining"
97
48
  end
49
+ continuing_sequences = new_continuing_sequences
98
50
  end
51
+
52
+ raise "Should be no previous continuing sequences remaining" if continuing_sequences.any?
53
+
54
+ completed_seqs.each {|seq| seq.simplify! }
55
+ return completed_seqs
99
56
  end
100
57
 
58
+ private
59
+
101
60
  def self.note_attack articulation
102
61
  case articulation
103
62
  when Articulations::NORMAL then Attack::NORMAL
@@ -137,7 +96,7 @@ class NoteSequenceExtractor
137
96
  def mark_slurring
138
97
  @slurring_flags = []
139
98
  under_slur = false
140
-
99
+
141
100
  @slurring_flags = Array.new(@notes.size) do |i|
142
101
  note = @notes[i]
143
102
 
@@ -162,7 +121,7 @@ class NoteSequenceExtractor
162
121
  end
163
122
  end
164
123
  end
165
-
124
+
166
125
  def calculate_offsets
167
126
  offset = 0.to_r
168
127
  @offsets = Array.new(@notes.size) do |i|
@@ -171,61 +130,50 @@ class NoteSequenceExtractor
171
130
  cur_offset
172
131
  end
173
132
  end
174
-
175
- def self.no_separation?(articulation, under_slur)
176
- under_slur && (
177
- articulation == Articulations::NORMAL ||
178
- articulation == Articulations::TENUTO ||
179
- articulation == Articulations::ACCENT
180
- )
181
- end
182
-
183
- def establish_maps
184
- @maps = []
185
-
186
- @notes.each_index do |i|
187
- map = { :ties => {}, :slurs => {}, :full_glissandos => {},
188
- :full_portamentos => {}, :half_glissandos => {},
189
- :half_portamentos => {}}
190
- note = @notes[i]
191
-
192
- # Create a dummy note (with no pitches) for the last note to "link" to.
193
- # This will allow half glissandos and half portamentos from the last note
194
- next_note = (i == (@notes.size-1)) ? Note.quarter : @notes[i+1]
195
-
196
- no_separation = NoteSequenceExtractor.no_separation?(note.articulation, @slurring_flags[i])
197
-
198
- linked = note.pitches & note.links.keys
199
- linked.each do |p|
200
- l = note.links[p]
201
- if l.is_a?(Link::Tie)
202
- map[:ties][p] = p
203
- elsif l.is_a?(Link::Glissando)
204
- if next_note.pitches.include?(l.target_pitch)
205
- map[:full_glissandos][p] = l.target_pitch
206
- else
207
- map[:half_glissandos][p] = l.target_pitch
208
- end
209
- elsif l.is_a?(Link::Portamento)
210
- if next_note.pitches.include?(l.target_pitch)
211
- map[:full_portamentos][p] = l.target_pitch
212
- else
213
- map[:half_portamentos][p] = l.target_pitch
214
- end
215
- end
133
+
134
+ def self.continuation_map note, next_note, separation
135
+ map = {}
136
+
137
+ linked = note.pitches & note.links.keys
138
+ targeted = []
139
+ linked.each do |p|
140
+ l = note.links[p]
141
+ if l.is_a?(Link::Tie)
142
+ map[p] = p
143
+ elsif l.is_a?(Link::TargetedLink) && next_note.pitches.include?(l.target_pitch)
144
+ map[p] = l.target_pitch
216
145
  end
217
-
218
- if(no_separation)
219
- unlinked = note.pitches - linked
220
- target_pitches = note.links.map {|p,l| l.is_a?(Link::Tie) ? p : l.target_pitch }
221
- untargeted = next_note.pitches - target_pitches
222
- Optimization.linking(unlinked, untargeted).each do |pitch,tgt_pitch|
223
- map[:slurs][pitch] = tgt_pitch
224
- end
146
+ end
147
+
148
+ if(separation == Separation::NONE)
149
+ unlinked = note.pitches - linked
150
+ untargeted = next_note.pitches - map.values
151
+ Optimization.linking(unlinked, untargeted).each do |pitch,tgt_pitch|
152
+ map[pitch] = tgt_pitch
153
+ end
154
+ end
155
+
156
+ return map
157
+ end
158
+
159
+ def note_pitch_elements note, pitch, attack, cents_per_step
160
+ duration = note.duration
161
+ link = note.links[pitch]
162
+ elements = if link && link.is_a?(Link::TargetedLink)
163
+ tgt_pitch = link.target_pitch
164
+ case link
165
+ when Link::Glissando
166
+ GlissandoConverter.glissando_elements(pitch, tgt_pitch, duration, attack)
167
+ when Link::Portamento
168
+ PortamentoConverter.portamento_elements(pitch, tgt_pitch, cents_per_step, duration, attack)
169
+ else
170
+ raise "Unexpected targeted link type"
225
171
  end
226
-
227
- @maps.push map
172
+ else
173
+ [ NoteSequence::Element.new(note.duration, pitch, attack) ]
228
174
  end
175
+
176
+ return elements
229
177
  end
230
178
  end
231
179
 
@@ -27,11 +27,30 @@ class NoteSequence
27
27
  @elements = elements
28
28
  end
29
29
 
30
+ # any consecutive elements with the same pitch and no attack will be combined
31
+ def simplify!
32
+ return if @elements.none?
33
+
34
+ prev_element = @elements[0]
35
+ idx = 1
36
+
37
+ while idx < @elements.size
38
+ element = @elements[idx]
39
+ if (element.pitch == prev_element.pitch) && (element.attack == Attack::NONE)
40
+ prev_element.duration += element.duration
41
+ @elements.delete_at(idx)
42
+ else
43
+ prev_element = element
44
+ idx += 1
45
+ end
46
+ end
47
+ end
48
+
30
49
  alias start offset
31
-
50
+
32
51
  def offsets
33
52
  raise "contains no elements" if elements.empty?
34
-
53
+
35
54
  off = @offset
36
55
  elements.map do |e|
37
56
  x = off
@@ -39,7 +58,7 @@ class NoteSequence
39
58
  x
40
59
  end
41
60
  end
42
-
61
+
43
62
  def stop
44
63
  offsets.last + NoteSequence.adjust_duration(elements.last.duration, separation)
45
64
  end
@@ -22,7 +22,7 @@ class Performer
22
22
  group = create_part_group parent_group, bundles
23
23
  set_start_volume volume_control_bus, bundles
24
24
  add_volume_control group, aux_audio_bus, volume_control_bus, lead_time, bundles
25
- add_volume_changes volume_control_bus, lead_time, bundles
25
+ add_volume_changes group, volume_control_bus, lead_time, bundles
26
26
  add_part_notes group, aux_audio_bus, lead_time, bundles
27
27
 
28
28
  bundles
@@ -51,7 +51,7 @@ class Performer
51
51
  bundles.push vol_control.bundle_queue(lead_time / 2.0)
52
52
  end
53
53
 
54
- def add_volume_changes volume_control_bus, lead_time, bundles
54
+ def add_volume_changes group, volume_control_bus, lead_time, bundles
55
55
  # change part volume
56
56
  part.dynamic_changes.each do |offset,change|
57
57
  case change
@@ -0,0 +1,29 @@
1
+ module Musicality
2
+
3
+ module DrumKits
4
+
5
+ SC_DRUM_KIT_01 = DrumKit.new(
6
+ DrumParts::BASS_DRUM => SuperCollider::SynthDefs::KICK2.settings,
7
+ DrumParts::SNARE_DRUM => SuperCollider::SynthDefs::SNARE_STEIN.settings,
8
+ DrumParts::CRASH_CYMBAL => SuperCollider::SynthDefs::CYMBALIC_MCLD.settings,
9
+ DrumParts::CLOSED_HI_HAT => SuperCollider::SynthDefs::CLOSED_HAT.settings,
10
+ DrumParts::OPEN_HI_HAT => SuperCollider::SynthDefs::OPEN_HAT.settings,
11
+ DrumParts::HI_TOM => SuperCollider::SynthDefs::TOM1.settings,
12
+ DrumParts::MED_TOM => SuperCollider::SynthDefs::TOM1.settings,
13
+ DrumParts::LOW_TOM => SuperCollider::SynthDefs::TOM1.settings,
14
+ )
15
+
16
+ SC_DRUM_KIT_02 = DrumKit.new(
17
+ DrumParts::BASS_DRUM => SuperCollider::SynthDefs::KICK_CHIRP.settings,
18
+ DrumParts::SNARE_DRUM => SuperCollider::SynthDefs::SNARE1.settings,
19
+ DrumParts::CRASH_CYMBAL => SuperCollider::SynthDefs::CYMBALIC_MCLD.settings,
20
+ DrumParts::CLOSED_HI_HAT => SuperCollider::SynthDefs::HIHAT1.settings,
21
+ DrumParts::OPEN_HI_HAT => SuperCollider::SynthDefs::HIHAT1.settings(:release => 0.6),
22
+ DrumParts::HI_TOM => SuperCollider::SynthDefs::FM_TOM.settings,
23
+ DrumParts::MED_TOM => SuperCollider::SynthDefs::FM_TOM.settings,
24
+ DrumParts::LOW_TOM => SuperCollider::SynthDefs::FM_TOM.settings,
25
+ )
26
+
27
+ end
28
+
29
+ end