musicality 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +27 -1
- data/README.md +153 -10
- data/bin/collidify +102 -0
- data/bin/lilify +57 -29
- data/bin/midify +64 -24
- data/bin/musicality +39 -0
- data/examples/composition/auto_counterpoint.rb +4 -5
- data/examples/composition/part_generator.rb +8 -2
- data/examples/composition/scale_exercise.rb +1 -1
- data/examples/notation/notes.rb +27 -0
- data/examples/notation/parts.rb +51 -0
- data/examples/notation/scores.rb +38 -0
- data/examples/notation/twinkle.rb +34 -0
- data/examples/notation/twinkle.score +33 -0
- data/lib/musicality.rb +46 -11
- data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
- data/lib/musicality/composition/dsl/score_methods.rb +10 -7
- data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
- data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
- data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
- data/lib/musicality/notation/conversion/score_converter.rb +50 -67
- data/lib/musicality/notation/model/articulations.rb +3 -2
- data/lib/musicality/notation/model/change.rb +15 -6
- data/lib/musicality/notation/model/dynamics.rb +11 -8
- data/lib/musicality/notation/model/instrument.rb +61 -0
- data/lib/musicality/notation/model/instruments.rb +111 -0
- data/lib/musicality/notation/model/key.rb +137 -0
- data/lib/musicality/notation/model/keys.rb +37 -0
- data/lib/musicality/notation/model/link.rb +6 -19
- data/lib/musicality/notation/model/mark.rb +43 -0
- data/lib/musicality/notation/model/marks.rb +11 -0
- data/lib/musicality/notation/model/meter.rb +4 -0
- data/lib/musicality/notation/model/note.rb +42 -28
- data/lib/musicality/notation/model/part.rb +18 -5
- data/lib/musicality/notation/model/pitch.rb +13 -4
- data/lib/musicality/notation/model/score.rb +104 -66
- data/lib/musicality/notation/model/symbols.rb +16 -11
- data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
- data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
- data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
- data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
- data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
- data/lib/musicality/notation/parsing/note_node.rb +19 -12
- data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
- data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/util/function.rb +41 -18
- data/lib/musicality/packable.rb +156 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
- data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
- data/lib/musicality/performance/conversion/score_collator.rb +70 -64
- data/lib/musicality/performance/midi/midi_events.rb +3 -3
- data/lib/musicality/performance/midi/midi_settings.rb +127 -0
- data/lib/musicality/performance/midi/midi_util.rb +8 -2
- data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
- data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
- data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
- data/lib/musicality/performance/model/attack.rb +8 -0
- data/lib/musicality/performance/model/duration_functions.rb +23 -0
- data/lib/musicality/performance/model/note_sequence.rb +52 -95
- data/lib/musicality/performance/model/separation.rb +10 -0
- data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
- data/lib/musicality/performance/supercollider/bundle.rb +18 -0
- data/lib/musicality/performance/supercollider/conductor.rb +125 -0
- data/lib/musicality/performance/supercollider/group.rb +71 -0
- data/lib/musicality/performance/supercollider/message.rb +26 -0
- data/lib/musicality/performance/supercollider/node.rb +122 -0
- data/lib/musicality/performance/supercollider/performer.rb +123 -0
- data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
- data/lib/musicality/performance/supercollider/server.rb +8 -0
- data/lib/musicality/performance/supercollider/synth.rb +43 -0
- data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
- data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
- data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
- data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
- data/lib/musicality/printing/lilypond/clef.rb +12 -0
- data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
- data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
- data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
- data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
- data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
- data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
- data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
- data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
- data/lib/musicality/project/create_tasks.rb +31 -0
- data/lib/musicality/project/file_cleaner.rb +19 -0
- data/lib/musicality/project/file_raker.rb +107 -0
- data/lib/musicality/project/load_config.rb +43 -0
- data/lib/musicality/project/project.rb +64 -0
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +3 -0
- data/spec/composition/util/random_sampler_spec.rb +1 -1
- data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
- data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
- data/spec/notation/conversion/score_conversion_spec.rb +6 -41
- data/spec/notation/conversion/score_converter_spec.rb +19 -137
- data/spec/notation/model/change_spec.rb +55 -0
- data/spec/notation/model/key_spec.rb +171 -0
- data/spec/notation/model/link_spec.rb +34 -5
- data/spec/notation/model/meter_spec.rb +15 -0
- data/spec/notation/model/note_spec.rb +33 -27
- data/spec/notation/model/part_spec.rb +53 -4
- data/spec/notation/model/pitch_spec.rb +15 -0
- data/spec/notation/model/score_spec.rb +64 -72
- data/spec/notation/parsing/link_nodes_spec.rb +3 -3
- data/spec/notation/parsing/link_parsing_spec.rb +6 -6
- data/spec/notation/parsing/note_node_spec.rb +34 -9
- data/spec/notation/parsing/note_parsing_spec.rb +11 -9
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
- data/spec/notation/parsing/pitch_node_spec.rb +0 -1
- data/spec/notation/util/value_computer_spec.rb +2 -2
- data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
- data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
- data/spec/performance/conversion/score_collator_spec.rb +59 -63
- data/spec/performance/midi/midi_util_spec.rb +22 -8
- data/spec/performance/midi/part_sequencer_spec.rb +2 -2
- data/spec/performance/midi/score_sequencer_spec.rb +12 -10
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/model/note_sequence_spec.rb +41 -134
- data/spec/printing/note_engraving_spec.rb +204 -0
- data/spec/printing/score_engraver_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +69 -23
- data/examples/notation/hip.rb +0 -32
- data/examples/notation/missed_connection.rb +0 -26
- data/examples/notation/song1.rb +0 -33
- data/examples/notation/song2.rb +0 -32
- data/lib/musicality/notation/model/links.rb +0 -11
- data/lib/musicality/notation/packing/change_packing.rb +0 -56
- data/lib/musicality/notation/packing/part_packing.rb +0 -31
- data/lib/musicality/notation/packing/score_packing.rb +0 -123
- data/lib/musicality/performance/model/note_attacks.rb +0 -19
- data/lib/musicality/performance/util/note_linker.rb +0 -28
- data/spec/notation/packing/change_packing_spec.rb +0 -304
- data/spec/notation/packing/part_packing_spec.rb +0 -66
- data/spec/notation/packing/score_packing_spec.rb +0 -255
- data/spec/performance/util/note_linker_spec.rb +0 -68
@@ -2,14 +2,14 @@ module Musicality
|
|
2
2
|
|
3
3
|
class Score
|
4
4
|
class Timed < Score
|
5
|
-
def to_midi_seq
|
6
|
-
ScoreSequencer.new(self).make_midi_seq(
|
5
|
+
def to_midi_seq **kwargs
|
6
|
+
ScoreSequencer.new(self).make_midi_seq(**kwargs)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
class
|
11
|
-
def to_midi_seq tempo_sample_rate,
|
12
|
-
to_timed(tempo_sample_rate).to_midi_seq(
|
10
|
+
class Tempo < Score
|
11
|
+
def to_midi_seq tempo_sample_rate, **kwargs
|
12
|
+
to_timed(tempo_sample_rate).to_midi_seq(**kwargs)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
module DurationFunctions
|
4
|
+
TENUTO_DURATION = Function::Linear.new([0,0],[1,1])
|
5
|
+
|
6
|
+
NORMAL_DURATION = Function.new(0...Float::INFINITY) do |x|
|
7
|
+
x - Rational(1,8) * (1 - Math.exp(-1.75*x))
|
8
|
+
end
|
9
|
+
|
10
|
+
PORTATO_DURATION = Function.new(0...Float::INFINITY) do |x|
|
11
|
+
x - Rational(2,8) * (1 - Math.exp(-1.75*x))
|
12
|
+
end
|
13
|
+
|
14
|
+
STACCATO_DURATION = Function.new(0...Float::INFINITY) do |x|
|
15
|
+
x - Rational(3,8) * (1 - Math.exp(-1.75*x))
|
16
|
+
end
|
17
|
+
|
18
|
+
STACCATISSIMO_DURATION = Function.new(0...Float::INFINITY) do |x|
|
19
|
+
x - Rational(4,8) * (1 - Math.exp(-1.75*x))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -1,111 +1,68 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
|
-
SlurredElement = Struct.new(:duration, :pitch, :accented) do
|
4
|
-
def slurred?; true; end
|
5
|
-
def articulation; Articulations::NORMAL; end
|
6
|
-
def accented?; accented; end
|
7
|
-
end
|
8
|
-
|
9
|
-
LegatoElement = Struct.new(:duration, :pitch, :accented) do
|
10
|
-
def slurred?; false; end
|
11
|
-
def articulation; Articulations::NORMAL; end
|
12
|
-
def accented?; accented; end
|
13
|
-
end
|
14
|
-
|
15
|
-
FinalElement = Struct.new(:duration, :pitch, :accented, :articulation) do
|
16
|
-
def slurred?; false; end
|
17
|
-
def accented?; accented; end
|
18
|
-
end
|
19
|
-
|
20
3
|
class NoteSequence
|
21
|
-
|
22
|
-
x = duration
|
23
|
-
y = Math.log2(x)
|
4
|
+
Element = Struct.new(:duration, :pitch, :attack)
|
24
5
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
6
|
+
def self.adjust_duration duration, separation
|
7
|
+
function = case separation
|
8
|
+
when Separation::TENUTO
|
9
|
+
DurationFunctions::TENUTO_DURATION
|
10
|
+
when Separation::PORTATO
|
11
|
+
DurationFunctions::PORTATO_DURATION
|
12
|
+
when Separation::STACCATO
|
13
|
+
DurationFunctions::STACCATO_DURATION
|
14
|
+
when Separation::STACCATISSIMO
|
15
|
+
DurationFunctions::STACCATISSIMO_DURATION
|
34
16
|
else
|
35
|
-
|
17
|
+
DurationFunctions::NORMAL_DURATION
|
36
18
|
end
|
19
|
+
|
20
|
+
function.at(duration)
|
37
21
|
end
|
38
22
|
|
39
|
-
|
40
|
-
def initialize
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
if pitches.empty?
|
46
|
-
raise ArgumentError, "no pitches given (at least one pitch is required at start offset)"
|
47
|
-
end
|
48
|
-
|
49
|
-
unless pitches.has_key?(start)
|
50
|
-
raise ArgumentError, "no start pitch given"
|
51
|
-
end
|
52
|
-
|
53
|
-
pitches.keys.each do |offset|
|
54
|
-
unless offset.between?(start,stop)
|
55
|
-
raise ArgumentError, "pitch offset #{offset} is not between start #{start} and stop #{stop}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
if attacks.empty?
|
60
|
-
raise ArgumentError, "no attacks given (at least one is required at start offset)"
|
61
|
-
end
|
62
|
-
|
63
|
-
unless attacks.has_key?(start)
|
64
|
-
raise ArgumentError, "no start attack given"
|
65
|
-
end
|
66
|
-
|
67
|
-
attacks.keys.each do |offset|
|
68
|
-
unless offset.between?(start,stop)
|
69
|
-
raise ArgumentError, "attack offset #{offset} is not between start #{start} and stop #{stop}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
@start, @stop = start, stop
|
74
|
-
@pitches, @attacks = pitches, attacks
|
23
|
+
attr_accessor :offset, :separation, :elements
|
24
|
+
def initialize offset, separation, elements = []
|
25
|
+
@offset = offset
|
26
|
+
@separation = separation
|
27
|
+
@elements = elements
|
75
28
|
end
|
29
|
+
|
30
|
+
alias start offset
|
31
|
+
|
32
|
+
def offsets
|
33
|
+
raise "contains no elements" if elements.empty?
|
76
34
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
if elements.empty?
|
83
|
-
raise ArgumentError, "no elements given"
|
84
|
-
end
|
85
|
-
|
86
|
-
last = elements.last
|
87
|
-
skip_attack = false
|
88
|
-
elements.each do |el|
|
89
|
-
if skip_attack
|
90
|
-
unless pitches.max[1] == el.pitch
|
91
|
-
pitches[offset] = el.pitch
|
92
|
-
end
|
93
|
-
else
|
94
|
-
pitches[offset] = el.pitch
|
95
|
-
attacks[offset] = el.accented ? ACCENTED : UNACCENTED
|
96
|
-
end
|
97
|
-
skip_attack = el.slurred?
|
98
|
-
|
99
|
-
unless el.equal?(last)
|
100
|
-
offset += el.duration
|
101
|
-
end
|
35
|
+
off = @offset
|
36
|
+
elements.map do |e|
|
37
|
+
x = off
|
38
|
+
off += e.duration
|
39
|
+
x
|
102
40
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop
|
44
|
+
offsets.last + NoteSequence.adjust_duration(elements.last.duration, separation)
|
106
45
|
end
|
107
46
|
|
108
|
-
def duration
|
47
|
+
def duration
|
48
|
+
stop - offset
|
49
|
+
end
|
50
|
+
|
51
|
+
def full_duration
|
52
|
+
offsets.last + elements.last.duration
|
53
|
+
end
|
54
|
+
|
55
|
+
def first_pitch
|
56
|
+
elements.first.pitch
|
57
|
+
end
|
58
|
+
|
59
|
+
def last_pitch
|
60
|
+
elements.last.pitch
|
61
|
+
end
|
62
|
+
|
63
|
+
def last_attack
|
64
|
+
elements.last.attack
|
65
|
+
end
|
109
66
|
end
|
110
67
|
|
111
68
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
|
4
|
+
class Bundle
|
5
|
+
attr_reader :time, :messages
|
6
|
+
def initialize time, *messages
|
7
|
+
@time = time
|
8
|
+
@messages = messages
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_sclang
|
12
|
+
raise "Bundle contains no messages" if @messages.empty?
|
13
|
+
"[ #{@time.to_f}, #{@messages.map {|m| m.to_sclang }.join(", ")} ]"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
|
4
|
+
class Conductor
|
5
|
+
def initialize score
|
6
|
+
unless score.is_a?(Score::Timed)
|
7
|
+
raise ArgumentError, "The given score is not a Score::Timed. \
|
8
|
+
Convert it first using ScoreConverter."
|
9
|
+
end
|
10
|
+
|
11
|
+
parts = score.collated? ? score.parts : ScoreCollator.new(score).collate_parts
|
12
|
+
@performers = Hash[ parts.map do |name, part|
|
13
|
+
[name, Performer.new(part)]
|
14
|
+
end]
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform base_fpath, selected_parts: @performers.keys, verbose: false, lead_time: 0.1
|
18
|
+
bundles = bundles(selected_parts, lead_time)
|
19
|
+
fpath = write_sc_code bundles, base_fpath
|
20
|
+
exec_sc_code fpath, bundles.last.time, verbose
|
21
|
+
end
|
22
|
+
|
23
|
+
def bundles selected_parts = @performers.keys, lead_time
|
24
|
+
Node.reset_id_counter
|
25
|
+
|
26
|
+
default_group = Group.default(nil)
|
27
|
+
aux_audio_bus = 16
|
28
|
+
volume_control_bus = 0
|
29
|
+
bundle_kwargs = {
|
30
|
+
:parent_group => default_group,
|
31
|
+
:aux_audio_bus => aux_audio_bus,
|
32
|
+
:volume_control_bus => volume_control_bus,
|
33
|
+
:lead_time => lead_time
|
34
|
+
}
|
35
|
+
|
36
|
+
all_bundles = [ default_group.bundle_queue(0.0) ]
|
37
|
+
selected_parts.each do |name|
|
38
|
+
bundles = @performers[name].bundles(**bundle_kwargs)
|
39
|
+
bundle_kwargs[:aux_audio_bus] += 2
|
40
|
+
bundle_kwargs[:volume_control_bus] += 1
|
41
|
+
all_bundles.concat bundles
|
42
|
+
end
|
43
|
+
all_bundles = all_bundles.sort_by {|b| b.time }
|
44
|
+
default_group.free_all
|
45
|
+
all_bundles.push(default_group.bundle_queue(lead_time+all_bundles.last.time))
|
46
|
+
|
47
|
+
coalesced_bundles = []
|
48
|
+
all_bundles.each do |bundle|
|
49
|
+
if coalesced_bundles.any? && coalesced_bundles.last.time == bundle.time
|
50
|
+
coalesced_bundles.last.messages.concat bundle.messages
|
51
|
+
else
|
52
|
+
coalesced_bundles.push bundle
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
return coalesced_bundles
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
BASE_FPATH_PLACEHOLDER = "BASE_FPATH"
|
62
|
+
SYNTHDEFS_PLACEHOLDER = "SYNTHDEFS"
|
63
|
+
COMPLETION_MSG = "Work complete."
|
64
|
+
POST_PID_MSG = "sclang pid:"
|
65
|
+
|
66
|
+
SC_HEADER = <<SCLANG
|
67
|
+
// auto-generated by Musicality
|
68
|
+
|
69
|
+
(\"#{POST_PID_MSG}\" + thisProcess.pid).postln;
|
70
|
+
|
71
|
+
#{SYNTHDEFS_PLACEHOLDER}
|
72
|
+
|
73
|
+
(
|
74
|
+
x = [
|
75
|
+
SCLANG
|
76
|
+
|
77
|
+
SC_FOOTER = <<SCLANG
|
78
|
+
];
|
79
|
+
|
80
|
+
f = File(\"#{BASE_FPATH_PLACEHOLDER}.osc\","w");
|
81
|
+
x.do({ arg item, i;
|
82
|
+
var bytes = item.asRawOSC;
|
83
|
+
f.write(bytes.size);
|
84
|
+
f.write(bytes);
|
85
|
+
});
|
86
|
+
f.close;
|
87
|
+
|
88
|
+
\"#{COMPLETION_MSG}\".postln;
|
89
|
+
);
|
90
|
+
SCLANG
|
91
|
+
|
92
|
+
def write_sc_code bundles, base_fpath
|
93
|
+
fpath = "#{base_fpath}.scd"
|
94
|
+
File.open(fpath, "w") do |f|
|
95
|
+
synthdefs = [ SynthDefs::VOLUME_CONTROL, SynthDefs::VOLUME_CHANGE ] + @performers.values.map {|p| p.settings.synthdef }
|
96
|
+
|
97
|
+
f.write SC_HEADER.gsub(SYNTHDEFS_PLACEHOLDER, synthdefs.map {|s| s.to_sclang }.join("\n\n"))
|
98
|
+
f.write bundles.map {|b| " " + b.to_sclang }.join(",\n") + "\n"
|
99
|
+
f.write SC_FOOTER.gsub(BASE_FPATH_PLACEHOLDER, base_fpath)
|
100
|
+
end
|
101
|
+
fpath
|
102
|
+
end
|
103
|
+
|
104
|
+
def exec_sc_code fpath, last_time, verbose
|
105
|
+
post_sclang_pid = Regexp.new(POST_PID_MSG + " ([0-9]+)")
|
106
|
+
|
107
|
+
sclang_pid = nil
|
108
|
+
IO.popen("sclang \"#{fpath}\"") do |io|
|
109
|
+
pid = io.pid
|
110
|
+
while response = io.gets
|
111
|
+
puts response if verbose
|
112
|
+
|
113
|
+
case response.chomp
|
114
|
+
when post_sclang_pid
|
115
|
+
sclang_pid = $1.to_i
|
116
|
+
when COMPLETION_MSG
|
117
|
+
Process.kill 'INT', sclang_pid
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
|
4
|
+
class Group < Node
|
5
|
+
def initialize server, group, add_action, target_id, parallel
|
6
|
+
raise ArgumentError unless ADD_ACTIONS.include?(add_action)
|
7
|
+
super server, group
|
8
|
+
|
9
|
+
send_msg(Message.new(parallel ? '/p_new' : '/g_new',
|
10
|
+
id, add_action, target_id))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.default server, parallel = false
|
14
|
+
new(server, nil, ADD_TAIL, 0, parallel)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.after target, parallel = false
|
18
|
+
raise ArgumentError unless target.is_a?(Node)
|
19
|
+
new target.server, target.group, ADD_AFTER, target.id, parallel
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.before target, parallel = false
|
23
|
+
raise ArgumentError unless target.is_a?(Node)
|
24
|
+
new target.server, target.group, ADD_BEFORE, target.id, parallel
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.head target, parallel = false
|
28
|
+
raise ArgumentError unless target.is_a?(Group)
|
29
|
+
new target.server, target, ADD_HEAD, target.id, parallel
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.tail target, parallel = false
|
33
|
+
raise ArgumentError unless target.is_a?(Group)
|
34
|
+
new target.server, target, ADD_TAIL, target.id, parallel
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.replace target, parallel = false
|
38
|
+
raise ArgumentError unless target.is_a?(Node)
|
39
|
+
new target.server, target.group, ADD_REPLACE, target.id, parallel
|
40
|
+
end
|
41
|
+
|
42
|
+
def head node
|
43
|
+
raise ArgumentError unless node.is_a?(Node)
|
44
|
+
send_msg(Message.new('/g_head', id, node.id))
|
45
|
+
end
|
46
|
+
|
47
|
+
def tail node
|
48
|
+
raise ArgumentError unless node.is_a?(Node)
|
49
|
+
send_msg(Message.new('/g_tail', id, node.id))
|
50
|
+
end
|
51
|
+
|
52
|
+
def free_all
|
53
|
+
send_msg(Message.new('/g_freeAll', id))
|
54
|
+
end
|
55
|
+
|
56
|
+
def deep_free
|
57
|
+
send_msg(Message.new('/g_deepFree', id))
|
58
|
+
end
|
59
|
+
|
60
|
+
def dump_tree flag
|
61
|
+
send_msg(Message.new('/g_dumpTree', id, flag ? 1 : 0))
|
62
|
+
end
|
63
|
+
|
64
|
+
def query_tree
|
65
|
+
raise NotImplementedError
|
66
|
+
# TODO
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|