-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bar and beat #9
Comments
Thank you, that's good to hear. I do plan to add more stuff to this later in the tutorial, but I'm curious as to what you mean by bar and beat. Something I do plan to add is a bit on how you can write parameters that are dependent upon the beat, or bar. But I'm guessing that you're looking for something a little bit different. If you want to clarify what you're looking for (and the scsynth.org forum might be a better place), that would help me a lot. Thanks :) |
To show what I mean, here are two examples:
I think the method of example 2 is not so good as example 1. Example 1 must be rewritten with patterns. You need the following sample: I am not sure if it is good to post these examples in the scsynth.org because they are too long. If you think I should post all two examples or one of them in the scsynth.org, I will post it or them there. I think the example 1 should also be rewritten with the piece "twinkle, twinkle, little star".
(
fork{
var baseFolder, snd, gtrSmpl, aLetter_kjKim, player, reverb;
s.freeAll;
baseFolder = thisProcess.nowExecutingPath.dirname;
snd = "Alesis-Fusion-Nylon-String-Guitar-C4.wav";
gtrSmpl = Buffer.read(s, baseFolder+/+snd);
s.sync;
SynthDef(\gtr5, {
|ptch=60, mul=0.25, ads=0.5, ade=0.25, rls=0.05, gate=1, vfs=4, vfe=5, vds=0.25, vde=0.25, len=1|
var smplPtch, bRate, vShp, vDpth, rate, sig, env, envGen, vAmp;
smplPtch = 60;
bRate = 2 ** (ptch - smplPtch / 12);
vShp = {|phs| SinOsc.kr(XLine.kr(vfs + 1, vfe + 1, len) - 1, phs)};
vAmp = vShp.(pi/2).range(XLine.kr(ads + 1, ade + 1, len) - 1, 1);
vDpth = vShp.(3pi/2).range(1, 2 ** (XLine.kr(vds + 1, vde + 1, len) - 1 / 12));
rate = bRate * vDpth;
env = Env.asr(0.01, 1, rls);
envGen = EnvGen.kr(env, gate, doneAction:2);
sig = PlayBuf.ar(gtrSmpl.numChannels, gtrSmpl, rate);
sig = sig * envGen * mul * vAmp * [-1, 1].choose;
OffsetOut.ar(0, sig)
}
).add;
SynthDef(\melody, {
|ptch=60, mul=0.25, ads=0.5, ade=0.25, rls=0.05, gate=1, vfs=4, vfe=5, vds=0.25, vde=0.25, len=1|
var vShp, vDpth, sig, env, envGen, vAmp;
vShp = {|phs| SinOsc.kr(XLine.kr(vfs + 1, vfe + 1, len) - 1, phs)};
vAmp = vShp.(pi/2).range(XLine.kr(ads + 1, ade + 1, len) - 1, 1);
vDpth = vShp.(3pi/2).range(1, 2**(XLine.kr(vds + 1, vde + 1, len) - 1 / 12));
env = Env.adsr(0.12, 0.3, 0.6, rls + 0.05, 1, 4);
envGen = EnvGen.kr(env, gate, doneAction:2);
sig = LFTri.ar([1, 1.013]*ptch.midicps * vDpth);
sig = sig * envGen * mul * vAmp * [-1, 1].choose;
OffsetOut.ar(0, sig)
}
).add;
SynthDef(\reverb2Ch, {
|oCh, mix = 0.25, room = 0.15, damp = 0.5, amp = 1.0|
var signal;
signal = In.ar(oCh, 2);
ReplaceOut.ar(oCh,
FreeVerb2.ar( // FreeVerb2 - true stereo UGen
signal[0], // Left channel
signal[1], // Right Channel
mix, room, damp, amp
)
); // same params as FreeVerb 1 chn version
}).add;
s.sync;
aLetter_kjKim = [
[ // 1st bar
[ // voice 1
[[69,60],65,8], // entry: [aChord, velocity, length.reciprocal]
[[70,62],60,8],
[[70,62],65,8],
[[69,60],60,8],
[[69,60],57,2]
],
[ // voice 2
[53,55,1] // entry: [aNote, velocity, length.reciprocal]
]
],
[ // 2nd bar
[ // voice 1
[67,62,8],
[69,60,8],
[69,65,8],
[67,61,8],
[67,58,2]
],
[ // voice 2
[62,40,4],
[59,35,4],
[61,40,2]
],
[ // voice 3
[52,50,2],
[45,45,2]
]
],
[ // 3rd bar
([
[65,50,8],
[67,47,8],
[67,48,8],
[65,52,8]
]!2).flatten,
[
[57,48,4],
[62,43,4],
[63,0,8],
[63,53,8],
[61,48,4]
],
[
[50,47,2],
[49,45,2]
]
],
[ // 4th bar
[
[[65,60,58],50,2],
[[64,60,55],45,2]
],
[
[48,50,1]
]
]
];
player = {
|music, synth, tempo=60, nthBar=0, vol=1|
var tF, entries, voiceItems, maxItemVoice, lastVoice;
tF = 60 / tempo * 4;
entries = music[nthBar];
voiceItems = entries.size.collect{
|nth|
entries[nth].size.collect{
|ith|
entries[nth][ith][2].reciprocal
}
};
maxItemVoice = voiceItems.size.collect{
|nth|
var items, range;
items = voiceItems[nth];
range = (0..items.size - 2);
(items.size == 1).if{ 0 }{ items[range].sum }
};
maxItemVoice.postln;
lastVoice = maxItemVoice.maxIndex;
("Bar"+nthBar++"\nThe voice which will be played lastly:" + lastVoice).postln;
{
|vce|
fork{
("\t\t\t\t\t\t\tVoice"+vce+"numItems:" + entries[vce].size
).postln;
("\t\t\t\t\t\t\t"++entries[vce]).postln;
entries[vce].do{
|entry,idxEntry|
var aChord, entryPlayer, len, untilNext, rAmp, rRls;
aChord = entry[0].asArray;
entryPlayer = Array.newClear(10);
len = entry[2];
untilNext = len.reciprocal;
rAmp = -0.1.rand;
rRls = rrand(0.01, 0.03);
aChord.size.do{
|i|
var aNote, amp;
aNote = aChord[i];
amp = entry[1]/127 * (2**(-3 - (i - 1.0.rand) + rAmp));
s.makeBundle(
0.2,
{
entryPlayer[i] = Synth(
synth,
[
\ptch, aNote,
\mul, amp * vol,
\ads, 0.9,
\ade, 0.85,
\rls, rRls,
\gate, 1,
\vfs, 3,
\vfe, 4,
\vds, 2 ** -4,
\vde, 2 ** -5,
\len, 1
],
1,
0) });
(
[
"voice:" + vce,
"MIDI note:" + aNote,
"rhythm:" + untilNext.asString.padRight(8, "0"),
"dbFS:" + amp.ampdb.round(0.01).asString.padRight(6, "0")+"dB"
]
).postln;
rrand(256, 384).reciprocal.wait;
};
( tF * untilNext + (128.reciprocal.rand2) - rRls).wait;
aChord.size.do{
|i|
entryPlayer[i].release
};
rRls.wait;
if (
(nthBar != (music.size - 1))
&&
vce == lastVoice
&&
(idxEntry == (entries[vce].size - 1))
)
{
nthBar = nthBar+1;
player.(music, synth, tempo, nthBar, vol);
}
}
};
}!entries.size;
};
// start the reverb
reverb = Synth(\reverb2Ch,
[
\oCh, 0,
\mix, 0.7,
\room, 0.5,
\damp, 0.6,
\amp, 1
],
addAction:\addToTail
);
// play music
player.(aLetter_kjKim ++ aLetter_kjKim, \gtr5, 75, 0, 1);
player.(
(aLetter_kjKim * [[[[[1],0,1]]]] ++ aLetter_kjKim).collect{
|item|
[
item[0].collect{
|itm|
[if(itm[0].isArray){ itm[0][0] }{ itm[0] }, itm[1], itm[2]]
}
]
+ [[[[-12],0,0]]]
},
\melody,
75,
0,
0.4);
}
)
(
// score[nth bar][nth voice][nth note information][pitch, velocity, length to next note]
~twinkle_a=
[
[ // bar 1, 17
[ // voice 1
[72,64,4], [72,64,4] // [pitch, velocity, length to next note]
],
[ // voice 2
[48,52,4],[60,52,4]
]
],
[ // bar 2, 18
[
[79,64,4], [79,64,4]
],
[
[64,52,4],[60,52,4]
]
],
[ // bar 3, 19
[81,64,4].dup(2),
[
[65,52,4],[60,52,4]
]
],
[ // bar 4, 20
[
[79,58,2]
],
[
[64,46,4],[60,38,4]
]
],
[ // bar 5, 21
[77,64,4]!2,
[
[62,52,4],[59,52,4]
]
],
[ // bar 6, 22
[76,64,4]!2,
[
[60,52,4],[52,52,4]
]
],
[ // bar 7, 23
[74,64,4]!2,
[
[53,52,4],[55,52,4]
]
],
[ // bar 8, 24
[
[72,64,2]
],
[
[48,52,2]
]
]
];
~twinkle_b=
[
[ // bar 9, 13
[79,48,4]!2,
[ // voice 2
[64,48,4],[55,48,4]
]
],
[ // bar 10, 14
[77,48,4]!2,
[
[62,48,4],[55,48,4]
]
],
[ // bar 11, 15
[76,64,4].dup(2),
[
[60,48,4],[55,48,4]
]
],
[ // bar 12, 16
[
[74,48,2]
],
[
[59,48,4],[55,48,4]
]
]
];
~twinkle=~twinkle_a++(~twinkle_b!2).flatten(1)++~twinkle_a;
)
/* bus */
(
SynthDef(\reverb, {
arg oCh, iCh, rs=100, rt=2.5, mul=0.5;
var sig= GVerb.ar(In.ar(iCh), rs, rt, mul:mul);
Out.ar(oCh, sig)
}
).add
)
~gtrC4m= Buffer.readChannel(s, "Alesis-Fusion-Nylon-String-Guitar-C4.wav".resolveRelative, channels:0);
(
SynthDef(\gtrM, {
arg len=1, oCh=0, pit=60, vSpd=3.5, vDepth=0.3, mul=1;
var env, atk=0.01, rls=0.05, rate, fm, am, sig;
env=Env([0,1,1,0],[atk,len-atk-rls,rls]).kr(doneAction:2);
fm= SinOsc.kr(vSpd,1.5pi).range(1, 2**(vDepth/12));
rate= 2**(pit-60/12) * BufRateScale.kr(~gtrC4m.bufnum) * fm;
am= SinOsc.kr(vSpd, 0.5pi).range(0.5.sqrt, 1);
sig= PlayBuf.ar(~gtrC4m.numChannels, ~gtrC4m.bufnum, rate);
sig= sig * am * env * mul;
Out.ar(oCh, sig)
}
).add
)
(
~gtrM={
arg score, voice=0, temp=2, offset=0, leg=1;
fork{
score.do{
arg barItms, barIdx;
barItms[voice].do{
arg item, idx;
var wait, len, notes, mul, phr;
if (idx==0 && voice==0) {barIdx.postln};
phr= if ((barIdx/2).asInteger.even==3) {idx} {barItms.size-idx} - barItms.size;
wait= 2**(phr/20) * temp * item[2].reciprocal;
len= wait * leg;
notes= item[0].asArray;
mul= exprand(2**2.5.neg, 2**1.neg) * (item[1]/127).sqrt;
[voice, idx, item].postln;
notes.size.do{
arg i;
var deTune, phrMul;
deTune= rrand( -0.02, 0.02);
phrMul= 2**(phr/3);
Synth.before(
~reverb,
\gtrM,
[
oCh:~bus_reverb,
pit:notes[i]+deTune+offset,
len:len,
mul:mul*(2**(1/(i+1)).neg).sqrt * phrMul,
vSpd:2,
vDepth:0.2
]
);
(rrand(1/256, 1/128)).wait
};
( wait + rrand(-1/256, 1/256) ).wait
}
}
}
}
)
~bus_reverb= Bus.audio(s, 1);
~reverb= Synth(\reverb, [iCh:~bus_reverb, oCh:0]);
(
~gtrM.(score:~twinkle, voice:0, leg:1);
~gtrM.(score:~twinkle, voice:1, leg:0.4)
)
~reverb.set(\rs, 10, \rt,1.15, \mul,2) |
I probably won't do this, no, though I may augment the melodic stuff a little (for example showing how you can specify the notes and duration together using nested arrays). I will also show a way to use environments so that you can use note names, rather than numbers (e.g. \cs4 for C sharp 4) - though that will probably go into the cookbook. I'm also going to talk about importing midi files, and using those with patterns. If you want to discuss this further though, the SCcode forum is the place to do it. Other people may have views, and I would like to discuss this more generally. I think it's a shame that there isn't an easy way to do melodies in SuperCollider, though this looks pretty promising: You don't get the bar lines, but there may be other ways to achieve that (e.g. using the current time in a pbind). |
Thank you for your precious opinion! In February, 2018, I posted it in the mailing list, but nobody gave me any feedback: I am a bit confused with the term SCcode forum. Do you mean scsynth.org, sccode.org or the mailing list? I probably make code simpler with Pbind, then should post it. What do you think about it? I do not use bar lines as an element of arrays. However, I can easily accentuate the first note or chord of each bar with altering velocity or altering duration in Example 1 because the playback firstly detects the size of the array of a bar then plays each element then go to next bar if the all notes in the current bar are played. In Example 1, I also make a rubato, accelerando, ritardando, crescendo and decrescendo within a bar. By using a global variable, I can do such things for some bars in Example 1. I am not sure if pitch name is good because pitch names are diverse according to lands: In Germany, they use the Helmholtz-system; in the US, they use American Standard Pitch Notation (ASPN); In France, the octave number is lower than ASPN. Yamaha follows the French system, and Rolland follows the American system. Most software programmes provide an option to choose middle C as C3 or C4. Thus, I think that fixing middle C as C4 would be not good. Anyway, Panola is cool! Is it your Quarks? |
Sorry I meant scsynth.org There is a way to detect which beat of a bar you're in from within a pattern, and I plan to show how you can use that to create more realistic playback (it's a trick I use quite a bit). You can also do rubato/crescendo etc using patterns relatively easily - perhaps I should also show how to do that so it relates to bars/beats as well. As far as notation goes - this is for an example, so the user can change it if they want. However, it is far easier to support ASPN in SuperCollider, than any of the others: \C0; \\ No problems
\C-1; \\ Not going to work. Panola isn't mine - but I plan to use it. |
I expect to read your method in the tutorial! Twinkle ... is too simple, and the Korean song is good enough to discuss on notation method, but it is not well-known. Thank you a lot! |
Is the first part of the following piece interesting enough for a transcription example? |
Ha, I remember learning that piece for piano. Yes, that's pretty good. Multiple voices, a tied note, rests, repeats. Post it on the forum and see what people make of it. |
Hello, thank you for writing the tutorial series.
I think the following melody section is excellent.
https://github.com/supercollider/learn/blob/master/src/beginner/src/ch02-01-melody.md
However, the array of melody does not contain bar and beat. I know introducing these might be more complex.
I would like to know if the concepts of bar and beat will be introduced later or not?
The text was updated successfully, but these errors were encountered: