SuperCollider:互动

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

K2A
K2A比对

尽管你只需使用默认值就好,但音调追踪器有很多输入引数。它返回两个输出——被跟踪的频率以及一个显示其实否被锁定在某个周期上的信号。

如果你在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]

Be Sociable, Share!

发表评论

电子邮件地址不会被公开。 必填项已用*标注