我已经阅读了一些教程,但是在我看来,他们似乎都不知道什么是合理的架构:
Instrument
个实例,Score
定义了一组Note
个对象,Player
类(可能是函数),用于将Note
个实例从乐谱路由到乐器,以便产生音乐。我在这种模式中看到的,但在我到目前为止所读到的例子中没有看到,是(a)得分和乐器之间的完全分离和(b)明确的定义(以a的形式) Note
对象的类和/或API)告诉乐器该做什么。
他们的内置实用程序是否支持这种类型的操作模式?
这是一种思考问题的非常简单方法吗?
答案 0 :(得分:2)
鉴于你已经看过这些例子,我不确定你想要什么。奇数位是“完全分离”要求;通常得分需要对哪些参数与哪些工具相关做出一些假设 - 尽管SynthDef中有足够的内省方法可以使程序进行有根据的猜测。
但基本原理图非常标准:SynthDef定义了工具,Collection及其子类存储数据,Routine和其他类可以在预定的时间内解释数据结构以制作音乐。
在底部,我使用SynthDef,Routine和Array粘贴了一些样板代码,用于对这种结构进行非常简单的类c方法。在音符生成时任意选择使用哪种乐器,“乐谱”与乐器无关。
然而,SC中的惯用方法是使用模式和事件,特别是Pbind类。我个人认为这些有点限制和冗长,但他们肯定会按照你的要求行事。查看“Streams-Patterns-Events”系列帮助文件。
各种各样的人都编写了第三方扩展程序,如Instr和Voicer,以适应他们自己的乐谱模型。查看Quarks列表或考虑自己推出?
s = Server.local.boot;
s.waitForBoot{ Routine {
/// in a "real" patch, i'd make these local variables,
/// but in testing its convenient to use environment variables.
// var inst, tclock, score, playr, switchr;
// the current instrument
~inst = \ding;
// a fast TempoClock
~tclock = TempoClock.new(8);
// two instruments that take the same arguments
SynthDef.new(\ding, {
arg dur=0.2, hz=880, out=0, level=0.25, pan=0.0;
var snd;
var amp = EnvGen.ar(Env.perc, doneAction:2, timeScale:dur);
snd = SinOsc.ar(hz) * amp * level;
Out.ar(out, Pan2.ar(snd, pan));
}).send(s);
SynthDef.new(\tick, {
arg dur=0.1, hz=880, out=0, level=0.25, pan=0.0;
var snd;
var amp = EnvGen.ar(Env.perc, doneAction:2, timeScale:dur);
snd = LPF.ar(WhiteNoise.ar, hz) * amp * level;
Out.ar(out, Pan2.ar(snd, pan));
}).send(s);
s.sync;
// the "score" is just a nested array of argument values
// there are also many kinds of associative collections in SC if you prefer
~score = [
// each entry:
// midi note offset, note duration in seconds, wait time in beats
[0, 0.4, 2],
[0, 0.4, 1],
[7, 0.2, 1],
[0, 0.2, 1],
[7, 0.15, 1],
[10, 0.5, 2],
[7, 0.1, 1],
[2, 0.3, 1]
];
// a routine that plays the score, not knowing which instrument is the target
~playr = Routine { var note, hz; inf.do({ arg i;
// get the next note
note = ~score.wrapAt(i);
// interpret scale degree as MIDI note plus offset
hz = (note[0] + 60).midicps;
// play the note
Synth.new(~inst, [\hz, hz, \dur, note[1] ], s);
// wait
note[2].wait;
}); }.play(~tclock);
// a routine that randomly switches instruments
~switchr = Routine { var note, hz; inf.do({ arg i;
if(0.2.coin, {
if(~inst == \ding, {
~inst = \tick;
}, {
~inst = \ding;
});
~inst.postln;
});
// wait
1.wait;
}); }.play(~tclock);
}.play; };
答案 1 :(得分:0)
我还要补充说,有一组名为Ctk的扩展名(" Quark"),它包含了SynthDef(进入CtkSynthDef),一个音符的概念(进入CtkNote)和分数(进入CtkScore)促进实时和非实时工作。我觉得它的帮助文件提供的示例(大多数)遵循OP建议的体系结构。
要安装它,请在SuperCollider中运行Quarks.install("Ctk")
。