musicality 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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