musicality 0.8.0 → 0.9.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.
- 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
|