通过鼠标、键盘、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]