通过鼠标、键盘、MIDI、音频输入等进行互动
让我们现在先打开localhost服务器:
( Server.default=s=Server.local; s.boot; )
MouseX/Y
运用鼠标作为一个控制器是一个与patch互动的快速简单的方式
// 基于参数的变化方式 // warp可以是'linear'或'exponential' MouseX.kr(leftval, rightval, warp) MouseY.kr(topscreenval, bottomscreenval, warp)
比较以下听力测试(小心,它们有点刺耳)
{SinOsc.ar(MouseX.kr(20,20000, 'linear'),0,0.1)}.play
和
{SinOsc.ar(MouseY.kr(20,20000, 'exponential'),0,0.1)}.play
指数映射(exponential mapping)运用整个萤幕的空间面积,比线性那种强太多!
如果你想将一个控制器限制在一个离散的(discrete)范围内,那么你可以使用Index UGen
// indexing signal将之保持在一个范围内 // 数组必须是FloatArray,因此你才能将之建成[0,1,2].asSignal Index.kr(array, indexing signal)
//有三种不同的状态
(
var vals, buf, s;
s=Server.local;
vals= [100,200,300];
buf=Buffer(s, vals.size, 1); //Buffers将在本文后半部分说明
// 分配并设置值
s.listSendMsg( buf.allocMsg( buf.setnMsg(0, vals) ));
{SinOsc.ar(Index.ar(buf.bufnum, MouseX.kr(0, vals.size+1)),0,0.2)}.play
) // 萤幕的左、中、右部
(
var vals, buf, s;
var numharm,basefreq;
numharm=11; //和声的数量
basefreq=66; //序列的基准频率
s=Server.local;
vals= basefreq*(Array.series(numharm,1,1));
buf=Buffer(s, vals.size, 1);
// 分配并设置值
s.listSendMsg( buf.allocMsg( buf.setnMsg(0, vals) ));
{SinOsc.ar(Index.kr(buf.bufnum,MouseX.kr(0,numharm)),0,0.1)}.play
)
鼠标也可以被用来做触发器
(
{
var trig,mx;
mx=MouseX.kr(0.0,1.0);
// 这个UGen比较mx与krate为0.5的持续信号的值
trig= mx>0.5;
SinOsc.ar(440,0,0.1*trig)
}.play;
)
( // 在一个给定的范围触发
{
var trig,mx,my;
mx=MouseX.kr(0.0,1.0);
my=MouseY.kr(0.0,1.0);
// 在此,if是一个UGen,*与逻辑和相等
trig= if((mx>0.3) * (mx<0.5) * (my>0.3) * (my<0.7),1,0);
SinOsc.ar(440,0,0.1*trig)
}.play;
)
为了展示一个更深入展示这个原理的例子,这里我要使用我最喜欢的SC patch(James McCartney所写)之一:
(
// 弹奏吉他
// 使用鼠标弹奏琴弦
{
var pitch, mousex, out;
pitch = [ 52, 57, 62, 67, 71, 76 ]; // e a d g b e弦
mousex = MouseX.kr;
out = Mix.fill(pitch.size, { arg i;
var trigger, pluck, period, string;
// 从0.25到0.75放置触发点
trigger = HPZ1.kr(mousex > (0.25 + (i * 0.1))).abs;
pluck = PinkNoise.ar(Decay.kr(trigger, 0.05));
period = pitch.at(i).midicps.reciprocal;
string = CombL.ar(pluck, period, period, 4);
Pan2.ar(string, i * 0.2 - 0.5);
});
LPF.ar(out, 12000);
LeakDC.ar(out);
}.play;
)
键盘
你可以通过设置动作函数用键盘触发东西。这通常由GUI完成,但接下来是一个根据你输入的文本(也就是敲击键盘)来发声的例子:
(
var doc;
SynthDef("typeofsound",{Out.ar(0,Line.kr(1,0,0.1,doneAction:2)*VarSaw.ar(Rand(100,1000),0,Rand(0.1,0.8),0.1))}).send(s);
doc = Document.current; //this text window you're reading from!
doc.keyDownAction_({arg ...args;
[args[1],args[3]].postln;
Synth("typeofsound");
});
)
//关闭之
(
Document.current.keyDownAction_(nil);
)
MIDI
要使用你的MIDI界面,你必须预置:
MIDIClient.init
要获取新进的MIDI信息,查看MIDIIn帮助文档。
用户为特定的MIDI信息建立收回(callback)函数。
要向外发送MIDI信息,查看MIDIOut帮助文档。
音频输入(AudioIn)
要获得当前的音频流,使用简单的AudioIn UGen
{ AudioIn.ar([1,2],0.5) }.play; //立体声输入
{ AudioIn.ar(1,0.5) }.play; // mono on input channel 1
因此,为实时音频建立效果器就变得很简单了:
(
{ //环调制器
SinOsc.ar(MouseX.kr(0.001,110,'exponential' ))*AudioIn.ar([1,2],0.5)
}.play; // 立体声输入
)
SuperCollider对实时音频有一个振幅(Amplitude)追踪器和音调(Pitch)追踪器
(
//使用输入的振幅控制脉冲的振幅
//使用耳机以防止反馈
{
Pulse.ar(90, 0.3, Amplitude.kr(AudioIn.ar(1)))
}.play
)
你可以设置一个输入阀值以避免拾取到背景噪音
(
{
var input,inputAmp,threshhold,gate;
var basefreq;
input = AudioIn.ar(1,0.1);
inputAmp = Amplitude.kr(input);
threshhold = 0.02; // 噪音门限
gate = Lag.kr(inputAmp > threshhold, 0.01);
(input * gate)
}.play;
)

尽管你只需使用默认值就好,但音调追踪器有很多输入引数。它返回两个输出——被跟踪的频率以及一个显示其实否被锁定在某个周期上的信号。
如果你在Mac机上,你需要换回internal服务器来使用.scope——你可以同时开启internal和localhost服务器,但你可能还需要点击一下-> default按钮。
Server.internal.boot;
展示输出——K2A确保将控制率(control rate)信号转换为音频率(audio rate),因为一个合成器的最终输出必须为音频率。
(
{
var freq, hasFreq;
# freq, hasFreq = Pitch.kr(AudioIn.ar(1,0.1));
[K2A.ar(freq*0.001), K2A.ar(hasFreq)]
}.scope
)
(
{
var in, amp, freq, hasFreq, out;
in = Mix.ar(AudioIn.ar([1,2]));
amp = Amplitude.kr(in, mul: 0.4);
# freq, hasFreq = Pitch.kr(in);
out = Mix.ar( LFTri.ar(freq * [0.5, 1, 2]) ) * amp;
6.do({
out = AllpassN.ar(out, 0.040, [0.040.rand,0.040.rand], 2)
});
out
}.play
)
(
{
var in, amp, freq, hasFreq, out;
in = AudioIn.ar(1);
amp = Amplitude.kr(in, mul: 0.4);
# freq, hasFreq = Pitch.kr(in);
out=if(hasFreq,Pulse.ar(freq,0.5,0.1),SinOsc.ar(freq,0,0.1));
6.do({
out = AllpassN.ar(out, 0.040, [0.040.rand,0.040.rand], 2)
});
out
}.play
)
有一些起始的探测器(onset detector)可能会有帮助。
[PV_HainsworthFoote]
[PV_JensenAndersen]
触发TGains UGen:
s.sendMsg(\b_allocRead, 10, "sounds/a11wlk01.wav");
(
var fftbuf;
fftbuf=Buffer.alloc(s,2048,1);
{
var b = 10, source1, detect;
source1= AudioIn.ar(1);
detect= PV_HainsworthFoote.ar(FFT(fftbuf.bufnum,source1), 1.0, 0.0, 0.7, 0.01);
TGrains.ar(2, detect, b, LFNoise0.kr(10,0.2,1.0), MouseX.kr(0,BufDur.kr(b)), MouseY.kr(0.1,0.5), LFNoise0.kr(10,1.0), 0.5, 2);
}.play
)
录音缓冲(RecordBuf)
如果你想录、用实地的声音,RecordBuf UGen将帮到你。你需要建立一个缓冲区以存储录下的采样数据。(下载示范mp3)
(
var b;
// 分配在local服务器的1秒单声道缓冲
b=Buffer.alloc(s,44100,1);
{
// 持续在一个循环中录音,录到我们刚才申明过的buffer中
// 每个录音循环繁殖于旧的数据之上
RecordBuf.ar(AudioIn.ar(1), b.bufnum, 0, 1.0, MouseX.kr(0.0,1.0), 1, 1, 1);
// 在一个循环中回放捕捉到的buffer, 向后
PlayBuf.ar(1, b.bufnum,MouseY.kr(0.0,-1.0), 1,0,1);
}.play;
)
对于跳舞音乐来说,你也许需要将捕捉的buffer同步到它的tempo,你还可以优化它,比如加入用户界面以选择何时录入buffer…
同样还有控制来自绘图板或游戏杆的工具,尽管这在我们之后学习了GUI和OSC响应后才会更有意义。
[SC2DTabletSlider]
[HIDDeviceService]
你可能同样喜欢尝试
[MouseButton]
[KeyState]
