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.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +4 -0
- data/ChangeLog.md +11 -0
- data/README.md +3 -0
- data/Rakefile +11 -3
- data/lib/musicality/composition/model/rhythm.rb +33 -0
- data/lib/musicality/composition/model/rhythm_class.rb +30 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
- data/lib/musicality/composition/sequencing/note_array.rb +33 -0
- data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
- data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
- data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
- data/lib/musicality/errors.rb +2 -2
- data/lib/musicality/notation/model/dynamics.rb +2 -2
- data/lib/musicality/notation/model/key.rb +42 -91
- data/lib/musicality/notation/model/keys.rb +35 -34
- data/lib/musicality/notation/model/note.rb +31 -9
- data/lib/musicality/notation/model/pitch.rb +2 -2
- data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
- data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
- data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
- data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/parseable.rb +13 -17
- data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
- data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
- data/lib/musicality/performance/model/note_sequence.rb +22 -3
- data/lib/musicality/performance/supercollider/performer.rb +2 -2
- data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
- data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
- data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
- data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
- data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
- data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
- data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
- data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
- data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
- data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
- data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
- data/lib/musicality/pitch_class.rb +1 -1
- data/lib/musicality/pitch_classes.rb +3 -5
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +25 -1
- data/musicality.gemspec +3 -2
- data/spec/composition/convenience_methods_spec.rb +8 -8
- data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
- data/spec/composition/model/pitch_class_spec.rb +22 -16
- data/spec/composition/model/pitch_classes_spec.rb +5 -5
- data/spec/composition/model/rhythm_class_spec.rb +42 -0
- data/spec/composition/model/rhythm_spec.rb +43 -0
- data/spec/composition/model/scale_class_spec.rb +26 -26
- data/spec/composition/model/scale_spec.rb +38 -38
- data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
- data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
- data/spec/composition/sequencing/note_array_spec.rb +94 -0
- data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
- data/spec/composition/sequencing/sequencer_spec.rb +76 -0
- data/spec/composition/util/adding_sequence_spec.rb +33 -33
- data/spec/composition/util/compound_sequence_spec.rb +6 -6
- data/spec/composition/util/note_generation_spec.rb +34 -34
- data/spec/composition/util/probabilities_spec.rb +7 -7
- data/spec/composition/util/random_sampler_spec.rb +3 -3
- data/spec/composition/util/repeating_sequence_spec.rb +28 -28
- data/spec/musicality_spec.rb +1 -1
- data/spec/notation/conversion/change_conversion_spec.rb +87 -87
- data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
- data/spec/notation/conversion/score_conversion_spec.rb +1 -1
- data/spec/notation/conversion/score_converter_spec.rb +31 -31
- data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
- data/spec/notation/model/change_spec.rb +80 -80
- data/spec/notation/model/key_spec.rb +135 -69
- data/spec/notation/model/link_spec.rb +27 -27
- data/spec/notation/model/meter_spec.rb +28 -28
- data/spec/notation/model/note_spec.rb +68 -47
- data/spec/notation/model/part_spec.rb +19 -19
- data/spec/notation/model/pitch_spec.rb +69 -68
- data/spec/notation/model/score_spec.rb +50 -47
- data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
- data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
- data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
- data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
- data/spec/notation/parsing/key_parsing_spec.rb +19 -0
- data/spec/notation/parsing/link_nodes_spec.rb +7 -7
- data/spec/notation/parsing/link_parsing_spec.rb +4 -4
- data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
- data/spec/notation/parsing/note_node_spec.rb +19 -19
- data/spec/notation/parsing/note_parsing_spec.rb +4 -4
- data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
- data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
- data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
- data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
- data/spec/notation/parsing/pitch_node_spec.rb +7 -7
- data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
- data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
- data/spec/notation/util/function_spec.rb +15 -15
- data/spec/notation/util/transition_spec.rb +12 -12
- data/spec/notation/util/value_computer_spec.rb +35 -36
- data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
- data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
- data/spec/performance/midi/midi_util_spec.rb +41 -41
- data/spec/performance/midi/part_sequencer_spec.rb +10 -10
- data/spec/performance/midi/score_sequencer_spec.rb +15 -15
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/util/optimization_spec.rb +9 -9
- data/spec/printing/note_engraving_spec.rb +16 -16
- data/spec/printing/score_engraver_spec.rb +5 -5
- data/spec/spec_helper.rb +5 -0
- metadata +85 -30
@@ -0,0 +1,46 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
module SynthDefs
|
4
|
+
|
5
|
+
CHEAP_PIANO = SynthDef.new(name: "cheappiano", params: { :out => 0, :freq => 440, :amp => 1, :dur => 1, :gate => 1, :pan => 0 },
|
6
|
+
body: <<-SCLANG,
|
7
|
+
var sig, in, n = 6, max = 0.04, min = 0.01, delay, pitch, detune, hammer;
|
8
|
+
freq = freq.cpsmidi;
|
9
|
+
hammer = Decay2.ar(Impulse.ar(0.001), 0.008, 0.04, LFNoise2.ar([2000,4000].asSpec.map(amp), 0.25));
|
10
|
+
sig = Mix.ar(Array.fill(3, { arg i;
|
11
|
+
detune = #[-0.04, 0, 0.03].at(i);
|
12
|
+
delay = (1/(freq + detune).midicps);
|
13
|
+
CombL.ar(hammer, delay, delay, 50 * amp)
|
14
|
+
}) );
|
15
|
+
|
16
|
+
sig = HPF.ar(sig,50) * EnvGen.ar(Env.perc(0.0001,dur, amp * 4, -1), gate: gate, doneAction:2);
|
17
|
+
Out.ar(out, Pan2.ar(sig, pan));
|
18
|
+
SCLANG
|
19
|
+
credit: "based on something posted 2008-06-17 by jeff, based on an old example by james mcc",
|
20
|
+
source: "https://github.com/supercollider-quarks/SynthDefPool",
|
21
|
+
)
|
22
|
+
|
23
|
+
EVERYTHING_RHODES = SynthDef.new(name: "everythingrhodes", params: { :out => 0, :freq => 440, :amp => 0.1, :gate => 1,
|
24
|
+
:lforate => 1.85, :lfowidth => 0.5, :cutoff => 2000, :rq => 0.2, :pan => 0.0 },
|
25
|
+
body: <<-SCLANG,
|
26
|
+
var pulse, filter, env;
|
27
|
+
|
28
|
+
pulse = Pulse.ar(freq*[1,33.5.midiratio],[0.2,0.1],[0.7,0.3]);
|
29
|
+
env = EnvGen.ar(Env.adsr(0.0,1.0,0.8,3.0),gate,doneAction:2);
|
30
|
+
//keyboard tracking filter cutoff
|
31
|
+
filter = BLowPass4.ar(pulse,(cutoff*(env.squared))+200+freq,rq);
|
32
|
+
|
33
|
+
Out.ar(out,Pan2.ar(Mix(filter)*env*amp,pan));
|
34
|
+
SCLANG
|
35
|
+
credit: <<-EOS,
|
36
|
+
Sound recipes from:
|
37
|
+
Mitchell Sigman (2011) Steal this Sound. Milwaukee, WI: Hal Leonard Books
|
38
|
+
adapted for SuperCollider and elaborated by Nick Collins (http://www.sussex.ac.uk/Users/nc81/index.html)
|
39
|
+
under GNU GPL 3 as per SuperCollider license
|
40
|
+
EOS
|
41
|
+
source: "https://github.com/acarabott/roundhouse-synth-design-course-2014",
|
42
|
+
)
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
module SynthDefs
|
4
|
+
|
5
|
+
SNARE1 = SynthDef.new(name: "snare1", params: { :out => 0, :amp => 0.8 },
|
6
|
+
body: <<-SCLANG,
|
7
|
+
var env0, env1, env2, env1m, oscs, noise, sig;
|
8
|
+
|
9
|
+
env0 = EnvGen.ar(Env([0.5, 1, 0.5, 0], [0.005, 0.03, 0.10], [-4, -2, -4]));
|
10
|
+
env1 = EnvGen.ar(Env([110, 60, 49], [0.005, 0.1], [-4, -5]));
|
11
|
+
env1m = env1.midicps;
|
12
|
+
env2 = EnvGen.ar(Env([1, 0.4, 0], [0.05, 0.13], [-2, -2]), doneAction:2);
|
13
|
+
|
14
|
+
oscs = LFPulse.ar(env1m, 0, 0.5, 1, -0.5) +
|
15
|
+
LFPulse.ar(env1m * 1.6, 0, 0.5, 0.5, -0.25);
|
16
|
+
oscs = LPF.ar(oscs, env1m * 1.2, env0);
|
17
|
+
oscs = oscs + SinOsc.ar(env1m, 0.8, env0);
|
18
|
+
|
19
|
+
noise = WhiteNoise.ar(0.2);
|
20
|
+
noise = HPF.ar(noise, 200, 2);
|
21
|
+
noise = BPF.ar(noise, 6900, 0.6, 3) + noise;
|
22
|
+
noise = noise * env2;
|
23
|
+
|
24
|
+
sig = oscs + noise;
|
25
|
+
sig = sig.clip2(1) * amp;
|
26
|
+
|
27
|
+
Out.ar(out, sig.dup);
|
28
|
+
SCLANG
|
29
|
+
source: "https://github.com/acarabott/roundhouse-synth-design-course-2014",
|
30
|
+
)
|
31
|
+
|
32
|
+
SNARE2 = SynthDef.new(name: "snare2", params: { :sfreq => 1500, :out => 0 },
|
33
|
+
body: <<-SCLANG,
|
34
|
+
var tri = Mix([LFTri.ar([111, 175, 224])]) * 0.5;
|
35
|
+
var sine = Mix([SinOsc.ar([330, 180])]) * 0.5;
|
36
|
+
var env = EnvGen.ar(Env.perc(0.01, 0.2), doneAction:2);
|
37
|
+
var snares = WhiteNoise.ar(1);
|
38
|
+
var snareEnv = EnvGen.ar(Env.perc(0.01, 0.2));
|
39
|
+
|
40
|
+
snares = HPF.ar(snares, sfreq);
|
41
|
+
snares = snares * snareEnv;
|
42
|
+
|
43
|
+
Out.ar(out, Mix([tri, sine, snares]) * env);
|
44
|
+
SCLANG
|
45
|
+
credit: "Based on Sound on Sound Synth Secrets 35, by Arthur Carabott",
|
46
|
+
source: "https://github.com/acarabott/roundhouse-synth-design-course-2014",
|
47
|
+
)
|
48
|
+
|
49
|
+
SOS_SNARE = SynthDef.new(name: "SOSsnare", params: { :out => 0, :decay => 0.12, :drum_mode_level => 0.25, :snare_level => 40, :snare_tightness => 3000, :freq => 405, :amp => 0.8 },
|
50
|
+
body: <<-SCLANG,
|
51
|
+
var drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc, drum_mode_mix,
|
52
|
+
drum_mode_env;
|
53
|
+
var snare_noise, snare_brf_1, snare_brf_2, snare_brf_3, snare_brf_4,
|
54
|
+
snare_reson;
|
55
|
+
var snare_env;
|
56
|
+
var snare_drum_mix;
|
57
|
+
|
58
|
+
drum_mode_env = EnvGen.ar(Env.perc(0.005, decay), 1.0, doneAction: 2);
|
59
|
+
drum_mode_sin_1 = SinOsc.ar(freq*0.53, 0, drum_mode_env * 0.5);
|
60
|
+
drum_mode_sin_2 = SinOsc.ar(freq, 0, drum_mode_env * 0.5);
|
61
|
+
drum_mode_pmosc = PMOsc.ar( Saw.ar(freq*0.85), 184, 0.5/1.3, mul: drum_mode_env*5, add: 0);
|
62
|
+
drum_mode_mix = Mix.new([drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc]) * drum_mode_level;
|
63
|
+
|
64
|
+
// choose either noise source below
|
65
|
+
// snare_noise = Crackle.ar(2.01, 1);
|
66
|
+
snare_noise = LFNoise0.ar(20000, 0.1);
|
67
|
+
snare_env = EnvGen.ar(Env.perc(0.005, decay, curve:-5), 1.0, doneAction: 2);
|
68
|
+
snare_brf_1 = BRF.ar(in: snare_noise, freq: 8000, mul: 0.5, rq: 0.1);
|
69
|
+
snare_brf_2 = BRF.ar(in: snare_brf_1, freq: 5000, mul: 0.5, rq: 0.1);
|
70
|
+
snare_brf_3 = BRF.ar(in: snare_brf_2, freq: 3600, mul: 0.5, rq: 0.1);
|
71
|
+
snare_brf_4 = BRF.ar(in: snare_brf_3, freq: 2000, mul: snare_env, rq: 0.0001);
|
72
|
+
snare_reson = Resonz.ar(snare_brf_4, snare_tightness, mul: snare_level) ;
|
73
|
+
snare_drum_mix = Mix.new([drum_mode_mix, snare_reson]) * 5 * amp;
|
74
|
+
Out.ar(out, [snare_drum_mix, snare_drum_mix])
|
75
|
+
SCLANG
|
76
|
+
credit: "recipe basically from Gordon Reid
|
77
|
+
http://www.soundonsound.com/sos/Mar02/articles/synthsecrets0302.asp
|
78
|
+
programmed by Renick Bell, renick_at_gmail.com",
|
79
|
+
source: "https://github.com/willieavendano/SC-SynthDefs/blob/master/DrumMachines",
|
80
|
+
)
|
81
|
+
|
82
|
+
SNARE_OTO_309 = SynthDef.new(name: "snare_oto309", params: { :out => 0, :amp => 0.1, :pan => 0 },
|
83
|
+
body: <<-SCLANG,
|
84
|
+
var env0, env1, env2, env1m, oscs, noise, son;
|
85
|
+
|
86
|
+
env0 = EnvGen.ar(Env.new([0.5, 1, 0.5, 0], [0.005, 0.03, 0.10], [-4, -2, -4]));
|
87
|
+
env1 = EnvGen.ar(Env.new([110, 60, 49], [0.005, 0.1], [-4, -5]));
|
88
|
+
env1m = env1.midicps;
|
89
|
+
env2 = EnvGen.ar(Env.new([1, 0.4, 0], [0.05, 0.13], [-2, -2]), doneAction:2);
|
90
|
+
|
91
|
+
oscs = LFPulse.ar(env1m, 0, 0.5, 1, -0.5) + LFPulse.ar(env1m * 1.6, 0, 0.5, 0.5, -0.25);
|
92
|
+
oscs = LPF.ar(oscs, env1m*1.2, env0);
|
93
|
+
oscs = oscs + SinOsc.ar(env1m, 0.8, env0);
|
94
|
+
|
95
|
+
noise = WhiteNoise.ar(0.2);
|
96
|
+
noise = HPF.ar(noise, 200, 2);
|
97
|
+
noise = BPF.ar(noise, 6900, 0.6, 3) + noise;
|
98
|
+
noise = noise * env2;
|
99
|
+
|
100
|
+
son = oscs + noise;
|
101
|
+
son = son.clip2(1) * amp;
|
102
|
+
|
103
|
+
Out.ar(out, Pan2.ar(son, pan));
|
104
|
+
SCLANG
|
105
|
+
credit: "from 08091500Acid309 by_otophilia",
|
106
|
+
source: "https://github.com/supercollider-quarks/SynthDefPool",
|
107
|
+
)
|
108
|
+
|
109
|
+
SNARE_STEIN = SynthDef.new(name: "snare_stein", params: { :out => 0, :amp => 0.1, :pan => 0 },
|
110
|
+
body: <<-SCLANG,
|
111
|
+
var snare, filtWhite;
|
112
|
+
|
113
|
+
filtWhite = LPF.ar(WhiteNoise.ar(1), 7040, 1);
|
114
|
+
|
115
|
+
snare = (SinOsc.ar(330,0,0.25) * EnvGen.ar(Env.perc(0.0005,0.055))) + (SinOsc.ar(185,0,0.25) * EnvGen.ar(Env.perc(0.0005,0.075))) + (filtWhite * EnvGen.ar(Env.perc(0.0005,0.2), doneAction: 2) * 0.2) + (HPF.ar(filtWhite, 523, 1) * EnvGen.ar(Env.perc(0.0005,0.183)) * 0.2);
|
116
|
+
Out.ar(out, Pan2.ar(snare * amp * 10, pan));
|
117
|
+
SCLANG
|
118
|
+
credit: "Snare written by Esben Stein, I believe",
|
119
|
+
source: "https://github.com/supercollider-quarks/SynthDefPool",
|
120
|
+
)
|
121
|
+
|
122
|
+
SNARE3 = SynthDef.new(name: "snare", params: { :amp => 1, :dur => 0.05, :out => 0 },
|
123
|
+
body: <<-SCLANG,
|
124
|
+
dur = dur * 16;
|
125
|
+
Out.ar(out, amp * XLine.ar(2,1/1000,dur) * BPF.ar(PinkNoise.ar(0.8), XLine.ar(20000,1000,dur, doneAction:2), 0.8).dup);
|
126
|
+
SCLANG
|
127
|
+
source: "https://github.com/bwestergard/supercollider-experiments",
|
128
|
+
)
|
129
|
+
|
130
|
+
SNARE_909 = SynthDef.new(name: "snare909", params: { :out => 0, :lpFreq => 1000, :vol => 1, :gate => 1 },
|
131
|
+
body: <<-SCLANG,
|
132
|
+
var sig1, sig2;
|
133
|
+
var triEnv;
|
134
|
+
var shifted1;
|
135
|
+
var shifted2;
|
136
|
+
var sinEnv;
|
137
|
+
var sin1, sin2;
|
138
|
+
var mixed;
|
139
|
+
var sig3;
|
140
|
+
var noiseEnv;
|
141
|
+
|
142
|
+
// tri -> final mixer
|
143
|
+
triEnv = Env.adsr(0, 0.4, 0, 0, curve: -4, peakLevel: 0.5);
|
144
|
+
sig1 = LFTri.ar(111, 0, 0.5) * EnvGen.kr(triEnv, gate: gate, doneAction: 2);
|
145
|
+
shifted1 = FreqShift.ar(sig1, 175);
|
146
|
+
shifted2 = FreqShift.ar(sig1, 224);
|
147
|
+
sig1 = Mix.new([shifted1, shifted2]);
|
148
|
+
|
149
|
+
// sines -> final mixer
|
150
|
+
sin1 = SinOsc.ar(330, mul: 0.2);
|
151
|
+
sin2 = SinOsc.ar(180, mul: 0.2);
|
152
|
+
sinEnv = Env.adsr(0, 0.2, 0, 0);
|
153
|
+
sig2 = Mix.new([sin1, sin2]) * EnvGen.kr(sinEnv, gate: gate, doneAction: 2);
|
154
|
+
|
155
|
+
// noise -> final mixer
|
156
|
+
noiseEnv = Env.adsr(0, 0.3, 0, 0);
|
157
|
+
sig3 = LPF.ar(WhiteNoise.ar() * EnvGen.kr(noiseEnv, gate: gate, doneAction: 2), 1000);
|
158
|
+
sig3 = HPF.ar(sig3, 600);
|
159
|
+
|
160
|
+
mixed = Mix.new([sig1, sig2, sig3]);
|
161
|
+
mixed = LPF.ar(mixed, lpFreq) * vol;
|
162
|
+
Out.ar(out, mixed ! 2);
|
163
|
+
SCLANG
|
164
|
+
source: "https://github.com/mattvears/supercollider-stuff",
|
165
|
+
)
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
module SynthDefs
|
4
|
+
|
5
|
+
TOM1 = SynthDef.new(name: "tom1", params: { :out => 0, :freq => 200, :amp => 1, :pan => 0.0 },
|
6
|
+
body: <<-SCLANG,
|
7
|
+
var env, tom;
|
8
|
+
env = EnvGen.kr(Env.perc(0.001, 0.1, 1, -5), 1, doneAction:2);
|
9
|
+
tom = SinOsc.ar(freq) * env;
|
10
|
+
Out.ar(out, Pan2.ar(tom, pan, amp));
|
11
|
+
SCLANG
|
12
|
+
source: "http://superdupercollider.blogspot.com/2009/02/simple-drum-machine.html"
|
13
|
+
)
|
14
|
+
|
15
|
+
FM_TOM = SynthDef.new(name: "fmtom", params: { :out => 0, :freq => 200, :gate => 1, :amp => 1 },
|
16
|
+
body: <<-SCLANG,
|
17
|
+
var tom = PMOsc.ar(freq, 280, Line.kr(0.0, 12, 1), mul: EnvGen.ar(Env.adsr(0.003,0.2,0,0), gate, levelScale: 0.3, doneAction: 2));
|
18
|
+
Out.ar(out, tom * amp ! 2);
|
19
|
+
SCLANG
|
20
|
+
source: "https://github.com/mattvears/supercollider-stuff",
|
21
|
+
)
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Musicality
|
2
|
+
module SuperCollider
|
3
|
+
module SynthDefs
|
4
|
+
|
5
|
+
VOLUME_CONTROL = SynthDef.new(name: "volume_control", params: { :in => nil, :out => nil, :control => nil },
|
6
|
+
body: <<-SCLANG,
|
7
|
+
var sig = In.ar([in,in+1]) * In.kr(control);
|
8
|
+
Out.ar(out,sig);
|
9
|
+
SCLANG
|
10
|
+
credit: "James Tunnell",
|
11
|
+
)
|
12
|
+
|
13
|
+
VOLUME_CHANGE = SynthDef.new(name: "volume_change", params: { :vol_bus => nil, :vol => nil, :dur => nil },
|
14
|
+
body: " Out.kr(vol_bus, Line.kr(In.kr(vol_bus), vol, dur));",
|
15
|
+
credit: "James Tunnell",
|
16
|
+
)
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
|
-
module PitchClasses
|
3
|
+
module PitchClasses
|
4
4
|
C = Bs = 0
|
5
5
|
Cs = Db = 1
|
6
6
|
D = 2
|
@@ -15,8 +15,6 @@ module PitchClasses
|
|
15
15
|
B = Cb = 11
|
16
16
|
end
|
17
17
|
|
18
|
-
PITCH_CLASSES = PitchClasses.constants.map
|
19
|
-
PitchClasses.const_get(sym)
|
20
|
-
end.sort
|
18
|
+
PITCH_CLASSES = PitchClasses.constants.map { |sym| PitchClasses.const_get(sym) }.sort
|
21
19
|
|
22
|
-
end
|
20
|
+
end
|
data/lib/musicality/version.rb
CHANGED
data/lib/musicality.rb
CHANGED
@@ -38,6 +38,7 @@ require 'musicality/notation/parsing/numbers/nonnegative_float_parsing'
|
|
38
38
|
require 'musicality/notation/parsing/numbers/nonnegative_rational_parsing'
|
39
39
|
require 'musicality/notation/parsing/pitch_parsing'
|
40
40
|
require 'musicality/notation/parsing/pitch_node'
|
41
|
+
require 'musicality/notation/parsing/key_parsing'
|
41
42
|
require 'musicality/notation/parsing/duration_parsing'
|
42
43
|
require 'musicality/notation/parsing/duration_nodes'
|
43
44
|
require 'musicality/notation/parsing/articulation_parsing'
|
@@ -78,6 +79,18 @@ require 'musicality/composition/util/note_generation'
|
|
78
79
|
require 'musicality/composition/model/scale'
|
79
80
|
require 'musicality/composition/model/scale_class'
|
80
81
|
require 'musicality/composition/model/scale_classes'
|
82
|
+
require 'musicality/composition/model/rhythm_class'
|
83
|
+
require 'musicality/composition/model/rhythm'
|
84
|
+
|
85
|
+
require 'musicality/composition/sequencing/sequenceable'
|
86
|
+
require 'musicality/composition/sequencing/note_fifo'
|
87
|
+
require 'musicality/composition/sequencing/sequencer'
|
88
|
+
require 'musicality/composition/sequencing/note_array'
|
89
|
+
require 'musicality/composition/sequencing/drum_machine/drum_parts'
|
90
|
+
require 'musicality/composition/sequencing/drum_machine/drum_pattern'
|
91
|
+
require 'musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns'
|
92
|
+
require 'musicality/composition/sequencing/drum_machine/drum_kit'
|
93
|
+
require 'musicality/composition/sequencing/drum_machine/drum_machine'
|
81
94
|
|
82
95
|
require 'musicality/composition/generation/counterpoint_generator'
|
83
96
|
require 'musicality/composition/generation/random_rhythm_generator'
|
@@ -121,10 +134,21 @@ require 'musicality/performance/supercollider/node'
|
|
121
134
|
require 'musicality/performance/supercollider/synth'
|
122
135
|
require 'musicality/performance/supercollider/group'
|
123
136
|
require 'musicality/performance/supercollider/synthdef'
|
124
|
-
require 'musicality/performance/supercollider/synthdefs'
|
137
|
+
require 'musicality/performance/supercollider/synthdefs/bass'
|
138
|
+
require 'musicality/performance/supercollider/synthdefs/claps'
|
139
|
+
require 'musicality/performance/supercollider/synthdefs/cymbals'
|
140
|
+
require 'musicality/performance/supercollider/synthdefs/hihats'
|
141
|
+
require 'musicality/performance/supercollider/synthdefs/kicks'
|
142
|
+
require 'musicality/performance/supercollider/synthdefs/mario'
|
143
|
+
require 'musicality/performance/supercollider/synthdefs/other'
|
144
|
+
require 'musicality/performance/supercollider/synthdefs/pianos'
|
145
|
+
require 'musicality/performance/supercollider/synthdefs/snares'
|
146
|
+
require 'musicality/performance/supercollider/synthdefs/toms'
|
147
|
+
require 'musicality/performance/supercollider/synthdefs/volume'
|
125
148
|
require 'musicality/performance/supercollider/performer'
|
126
149
|
require 'musicality/performance/supercollider/conductor'
|
127
150
|
require 'musicality/performance/supercollider/score_conducting'
|
151
|
+
require 'musicality/performance/supercollider/sc_drum_kits'
|
128
152
|
|
129
153
|
#
|
130
154
|
# Printing
|
data/musicality.gemspec
CHANGED
@@ -22,10 +22,11 @@ SuperCollider."
|
|
22
22
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler", "~>
|
25
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
-
spec.add_development_dependency "rspec", "~>
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
28
28
|
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "coveralls", '~> 0.8'
|
29
30
|
|
30
31
|
spec.add_dependency "treetop", "~> 1.5"
|
31
32
|
spec.add_dependency 'midilib', '~> 2.0'
|
@@ -5,12 +5,12 @@ describe 'transpose' do
|
|
5
5
|
notes = "/4A2,C2 /4D2,F2,Gb2 /8 /8E4".to_notes
|
6
6
|
semitones = 3
|
7
7
|
notes2 = transpose(notes,semitones)
|
8
|
-
|
9
|
-
notes2.size.
|
8
|
+
|
9
|
+
expect(notes2.size).to eq(notes.size)
|
10
10
|
notes2.each_index do |i|
|
11
11
|
notes2[i].pitches.each_with_index do |pitch2,j|
|
12
12
|
pitch = notes[i].pitches[j]
|
13
|
-
pitch2.diff(pitch).
|
13
|
+
expect(pitch2.diff(pitch)).to eq(semitones)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -30,19 +30,19 @@ end
|
|
30
30
|
describe method do
|
31
31
|
context 'given no args' do
|
32
32
|
it 'should produce an empty array' do
|
33
|
-
send(method).
|
33
|
+
expect(send(method)).to eq([])
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
context 'given one pitch' do
|
38
38
|
it 'should produce an array with one note, with proper duration' do
|
39
|
-
send(method,*[C2]).
|
39
|
+
expect(send(method,*[C2])).to eq([Note.new(dur,C2)])
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
context 'given one pitch group' do
|
44
44
|
it 'should produce an array with one note, given pitch group, and with proper duration' do
|
45
|
-
send(method,*[[C2,E2,G2]]).
|
45
|
+
expect(send(method,*[[C2,E2,G2]])).to eq([Note.new(dur,[C2,E2,G2])])
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -51,10 +51,10 @@ end
|
|
51
51
|
pg1 = A3
|
52
52
|
pg2 = [B3,G3]
|
53
53
|
pg3 = F4
|
54
|
-
send(method,*[pg1,pg2,pg3]).
|
54
|
+
expect(send(method,*[pg1,pg2,pg3])).to eq([
|
55
55
|
Note.new(dur,pg1), Note.new(dur,pg2), Note.new(dur,pg3)
|
56
56
|
])
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
-
end
|
60
|
+
end
|
@@ -13,27 +13,27 @@ describe RandomRhythmGenerator do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
before :all do
|
18
18
|
@rrgs = [
|
19
19
|
{ 1/8.to_r => 0.25, 1/4.to_r => 0.5, 1/2.to_r => 0.25 },
|
20
20
|
{ 1/6.to_r => 0.25, 1/4.to_r => 0.25, 1/3.to_r => 0.25, 1/12.to_r => 0.25 }
|
21
21
|
].map {|durs_w_probs| RandomRhythmGenerator.new(durs_w_probs) }
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
describe '#random_rhythm' do
|
25
25
|
it 'should return durations that add to given total dur' do
|
26
26
|
@rrgs.each do |rrg|
|
27
27
|
[3,1,1/2.to_r,5/8.to_r,15/16.to_r].each do |total_dur|
|
28
28
|
20.times do
|
29
29
|
rhythm = rrg.random_rhythm(total_dur)
|
30
|
-
rhythm.inject(0,:+).
|
30
|
+
expect(rhythm.inject(0,:+)).to eq(total_dur)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
describe '#random_dur' do
|
38
38
|
it 'should return a random duration, according to the probabilities given at initialization' do
|
39
39
|
@rrgs.each do |rrg|
|
@@ -42,7 +42,7 @@ describe RandomRhythmGenerator do
|
|
42
42
|
rrg.durations.each_with_index do |dur,i|
|
43
43
|
count = counts[dur]
|
44
44
|
tgt_prob = rrg.probabilities[i]
|
45
|
-
(count / 1000.to_f).
|
45
|
+
expect((count / 1000.to_f)).to be_within(0.05).of(tgt_prob)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -4,48 +4,54 @@ include PitchClasses
|
|
4
4
|
|
5
5
|
describe PitchClass do
|
6
6
|
it 'should define the MOD constant' do
|
7
|
-
PitchClass.constants.
|
7
|
+
expect(PitchClass.constants).to include(:MOD)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
describe '.from_i' do
|
11
11
|
it 'should return the given integer % PitchClass::MOD' do
|
12
|
-
PitchClass.from_i(-1).
|
13
|
-
PitchClass.from_i(12).
|
14
|
-
PitchClass.from_i(2).
|
15
|
-
PitchClass.from_i(16).
|
12
|
+
expect(PitchClass.from_i(-1)).to eq(11)
|
13
|
+
expect(PitchClass.from_i(12)).to eq(0)
|
14
|
+
expect(PitchClass.from_i(2)).to eq(2)
|
15
|
+
expect(PitchClass.from_i(16)).to eq(4)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
it 'should add the #to_pc method to the
|
20
|
-
5.methods.
|
19
|
+
it 'should add the #to_pc method to the Integer class' do
|
20
|
+
expect(5.methods).to include(:to_pc)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should add the #to_pc method to the Pitch class' do
|
24
|
-
Pitch.new.methods.
|
24
|
+
expect(Pitch.new.methods).to include(:to_pc)
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'should add the #to_pcs method to Enumerable classes, like Array' do
|
28
|
-
[1,2,3].methods.
|
28
|
+
expect([1,2,3].methods).to include(:to_pcs)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
describe 'Pitch#to_pc' do
|
32
32
|
it 'should send semitone through PitchClass.from_i' do
|
33
33
|
[ C4, D3, E5, G5,
|
34
34
|
Pitch.new(semitone: 4),
|
35
35
|
Pitch.new(semitone: 13),
|
36
36
|
].each do |pitch|
|
37
|
-
pitch.to_pc.
|
37
|
+
expect(pitch.to_pc).to eq(PitchClass.from_i(pitch.semitone))
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
describe '
|
42
|
+
describe 'Integer#to_pc' do
|
43
43
|
it 'should pass self to PitchClass.from_i' do
|
44
44
|
[-1,12,2,16].each do |i|
|
45
|
-
i.to_pc.
|
45
|
+
expect(i.to_pc).to eq(PitchClass.from_i(i))
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
describe 'Integer#to_pcs' do
|
51
|
+
it 'should pass self to PitchClass.from_i' do
|
52
|
+
expect([-1,12,2,16].to_pcs).to eq([-1.to_pc,12.to_pc,2.to_pc,16.to_pc])
|
53
|
+
end
|
54
|
+
end
|
49
55
|
|
50
56
|
describe '.invert' do
|
51
57
|
before :all do
|
@@ -62,13 +68,13 @@ describe PitchClass do
|
|
62
68
|
|
63
69
|
it 'should produce a pitch class' do
|
64
70
|
@cases.each do |input_pc, output_pc|
|
65
|
-
PitchClass.invert(input_pc).
|
71
|
+
expect(PitchClass.invert(input_pc)).to eq(output_pc)
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
69
75
|
it 'should produce a pitch class that when inverted again produces the original pitch class' do
|
70
76
|
@cases.each do |input_pc, output_pc|
|
71
|
-
PitchClass.invert(output_pc).
|
77
|
+
expect(PitchClass.invert(output_pc)).to eq(input_pc)
|
72
78
|
end
|
73
79
|
end
|
74
80
|
end
|
@@ -5,7 +5,7 @@ pc_syms = [:C, :Db, :D, :Eb, :E, :F, :Gb, :G, :Ab, :A, :Bb, :B]
|
|
5
5
|
describe PitchClasses do
|
6
6
|
it 'should include pitch-class constants for C, Db, D, ...' do
|
7
7
|
pc_syms.each do |sym|
|
8
|
-
PitchClasses.constants.
|
8
|
+
expect(PitchClasses.constants).to include(sym)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
@@ -13,12 +13,12 @@ end
|
|
13
13
|
|
14
14
|
describe 'PITCH_CLASSES' do
|
15
15
|
it 'should be in the Musicality module namespace' do
|
16
|
-
Musicality.constants.
|
16
|
+
expect(Musicality.constants).to include(:PITCH_CLASSES)
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
it 'should have each constant value in PitchClasses' do
|
20
20
|
PitchClasses.constants.each do |sym|
|
21
|
-
PITCH_CLASSES.
|
21
|
+
expect(PITCH_CLASSES).to include(PitchClasses.const_get(sym))
|
22
22
|
end
|
23
23
|
end
|
24
|
-
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe RhythmClass do
|
4
|
+
describe '.new' do
|
5
|
+
it 'should raise ArgumentError if given portions contains any zero(s)' do
|
6
|
+
expect { RhythmClass.new([1,0,2]) }.to raise_error(ArgumentError)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#portions' do
|
11
|
+
it 'should return the same portions given initially' do
|
12
|
+
portions = [4,2,-2,-1]
|
13
|
+
rc = RhythmClass.new(portions)
|
14
|
+
expect(rc.portions).to eq(portions)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#portions_sum' do
|
19
|
+
it 'should return the sum of portions using their absolute value' do
|
20
|
+
rc = RhythmClass.new([4,2,-2,-1])
|
21
|
+
expect(rc.portions_sum).to eq(9)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#to_rhythm' do
|
26
|
+
it 'should produce the expected Rhythm object' do
|
27
|
+
portions = [5,1,-7,3,-1,2]
|
28
|
+
rhythm_class = RhythmClass.new(portions)
|
29
|
+
portions_sum = rhythm_class.portions_sum
|
30
|
+
rhythm_duration = 2
|
31
|
+
rhythm = rhythm_class.to_rhythm(rhythm_duration)
|
32
|
+
|
33
|
+
expect(rhythm).to be_a(Rhythm)
|
34
|
+
expect(rhythm.durations.size).to eq(portions.size)
|
35
|
+
portions.each_with_index do |portion, idx|
|
36
|
+
dur = rhythm.durations[idx]
|
37
|
+
expect(dur).to eq(rhythm_duration * Rational(portion, portions_sum))
|
38
|
+
end
|
39
|
+
expect(rhythm.durations_sum).to eq(rhythm_duration)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Rhythm do
|
4
|
+
describe '.new' do
|
5
|
+
it 'should raise ArgumentError if given durations contains any zero(s)' do
|
6
|
+
expect { Rhythm.new([1,0,2]) }.to raise_error(ArgumentError)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#durations' do
|
11
|
+
it 'should return the same portions given initially' do
|
12
|
+
durations = [4,2,-2,-1]
|
13
|
+
rc = Rhythm.new(durations)
|
14
|
+
expect(rc.durations).to eq(durations)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#durations_sum' do
|
19
|
+
it 'should return the sum of durations using their absolute value' do
|
20
|
+
rc = Rhythm.new([4,2,-2,-1])
|
21
|
+
expect(rc.durations_sum).to eq(9)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#to_notes' do
|
26
|
+
it 'should produce the expected Note objects' do
|
27
|
+
durations = [Rational(1,2), Rational(2,1), Rational(2,3)]
|
28
|
+
rhythm = Rhythm.new(durations)
|
29
|
+
durations_sum = rhythm.durations_sum
|
30
|
+
pitch = Pitches::C4
|
31
|
+
notes = rhythm.to_notes(pitch)
|
32
|
+
|
33
|
+
expect(notes.size).to eq(durations.size)
|
34
|
+
notes.each do |note|
|
35
|
+
expect(note).to be_a(Note)
|
36
|
+
end
|
37
|
+
durations.each_with_index do |dur, idx|
|
38
|
+
dur2 = notes[idx].duration
|
39
|
+
expect(dur).to eq(dur2)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|