yoppa.org


immediate bitwave

前橋工科大学 – サウンドプログラミング 2023

TidalCycles応用 2 – オリジナルの楽器を作成する

ここまでは、TidalCyclesを使用して主にリズムやメロディーなど音のパターンや構造を記述することに注力してきました。使用する音色 (楽器) はSuperDirtであらかじめ用意されたサンプルとシンセを呼び出して使用してきました。

今回はTidalCycleの応用として、自分のオリジナルの音色でTidalCylesから演奏する方法について解説します。

サンプルファイルの追加はとても簡単です。SuperDirtで指定されたフォルダ (Dirt-Samples) 以下に新しくフォルダを作成してそこにサウンドファイルを追加するだけでオリジナルのサンプルを演奏することが可能となります。

オリジナルのSynthの追加は少し複雑です。SuperColliderの”SynthDef”で新規の楽器を定義して、それをTidalCyclesから呼び出します。この方法を用いるとオリジナルのSuperColliderの楽器を演奏することが可能となります。

独自のサンプルやSynthを演奏することで、よりオリジナリティーのあるパフォーマンスが可能となります!

スライド資料

アンケート

本日の講義に参加した方は下記のアンケートに答えてください。

SuperColliderの基本

// 関数の定義、値の出力
{"Hello World"}.value;

// 関数の定義、音の出力(Sin波)
{SinOsc.ar()}.play;

// Sin波の周波数の指定 (220Hz)
{SinOsc.ar(220)}.play;

// 左右2chに
{SinOsc.ar([220, 220])}.play;

// 左右の音を微妙にずらす
{SinOsc.ar([220, 222])}.play;

// 別の波形1: ノコギリ波
{Saw.ar([220, 222])}.play;

// 別の波形2: 矩形波
{Pulse.ar([220, 222])}.play;

// 別の波形3: ホワイトノイズ
{WhiteNoise.ar([1.0, 1.0])}.play;

// 別の波形3: ピンクノイズ
{PinkNoise.ar([1.0, 1.0])}.play;

// 2つの音を混ぜる1
// そのまま足して2で割る
(
{
    (SinOsc.ar([220, 222]) + SinOsc.ar([330, 333])) * 0.5
}.play;
)

// 2つの音を混ぜる2
// 変数に格納
(
{
    var sig1, sig2;
    sig1 = SinOsc.ar([220, 222]);
    sig2 = SinOsc.ar([330, 333]);
    (sig1 + sig2) * 0.5;
}.play;
)

// 2つの音を混ぜる2
// 変数に格納、違う波形で
(
{
    var sig1, sig2;
    sig1 = SinOsc.ar([220, 222]);
    sig2 = Saw.ar([330, 333]);
    (sig1 + sig2) * 0.5;
}.play;
)

// 関数を作成して後から演奏
(
var func;
func = {
    var sig1, sig2;
    sig1 = SinOsc.ar([220, 222]);
    sig2 = Saw.ar([330, 333]);
    (sig1 + sig2) * 0.5;
};
func.play;
)

// エンベロープ (音量の変化)
(
{
    var sig, env;
    sig = Saw.ar([220, 222]);
    env = EnvGen.kr(Env.perc());
    sig * env;
}.play;
)

// 楽器 (Synth) にする
(
SynthDef("mySynth",
    {
        var sig, env;
        sig = Saw.ar([220, 222]);
        env = EnvGen.kr(Env.perc());
        Out.ar(0, sig * env);
}).add
)
Synth("mySynth");

// 楽器 (Synth) に引数をつける
// 周波数を指定
(
SynthDef("mySynth",
    {
        arg freq = 440;
        var sig, env;
        sig = Saw.ar([freq, freq * 1.01]);
        env = EnvGen.kr(Env.perc());
        Out.ar(0, sig * env);
}).add
)
Synth("mySynth", ["freq", 220]);
Synth("mySynth", ["freq", 110]);
Synth("mySynth", ["freq", 55]);

// いろいろ引数として指定できるように
// 周波数(freq), 長さ(length), フィルタ周波数(lpfFreq)
(
SynthDef("mySynth",
    {
        arg freq = 440, length = 1.0, lpfFreq = 800, gain = 1.5;
        var sig, env, out;
        sig = Saw.ar([freq, freq * 1.01]);
        env = EnvGen.kr(Env.perc(releaseTime: length));
        out = RLPF.ar(sig * env, lpfFreq, 0.3) * gain;
        Out.ar(0, out);
}).add
)
Synth("mySynth", ["freq", 220, "length", 2.0, "lpfFreq", 800]);
Synth("mySynth", ["freq", 110, "length", 4.0, "lpfFreq", 600]);
Synth("mySynth", ["freq", 55, "length", 12.0, "lpfFreq", 600]);

// SuperDirt用の楽器へ
(
SynthDef("mySynth",
    {
        arg out = 0, freq = 440, length = 1.0, pan = 0.5;
        var sig, env;
        sig = Saw.ar([freq, freq * 1.01]);
        env = EnvGen.kr(Env.perc(releaseTime: length));
        OffsetOut.ar(out, DirtPan.ar(sig, ~dirt.numChannels, pan, env));
}).add
)

SuperDirt用のSynthDefサンプル

SynthDef("superp5str", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	gate=1, pitch1 = 2, voice = 0.5, cutoff= 20000, rq=0.5|
	var sound;
	var env = EnvGen.ar(Env.pairs([[0,0],[0.07,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -1), timeScale:sustain, doneAction:2);
	var lfo, pulse, filter;
	freq = freq / 2.0;
	lfo = LFTri.kr(pitch1*[1,1.01],Rand(0,2.0)!2);
	pulse = Pulse.ar(freq*[1,1.01],lfo*voice+0.5);
	filter = RLPF.ar(pulse,cutoff,rq);
	sound = Mix(filter) * 0.5;
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("superlaser", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	voice = 0.03, pitch1 = 4, gate=1|
	var sound;
	var env = EnvGen.ar(Env.pairs([[0,0],[0.07,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -1), timeScale:sustain, doneAction:2);
	var osc1, freqenv, ampenv;
	freqenv = EnvGen.ar(Env([pitch1,0.1,1,1],[voice,0.01,1.0]));
	osc1 = LFTri.ar(freq*freqenv);
	sound = osc1*0.5;
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("superost", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	gate = 1, lforate = 3, lfowidth= 0.1|
	var sound;
	var env = EnvGen.ar(Env.adsr(0.01,0.05,0.5,0.1), gate, doneAction:2, timeScale:sustain);
	var lfo, pulse, filter;
	freq = freq / 2.0;
	lfo = LFTri.kr(lforate,Rand(0,2.0)!3);
	pulse = Pulse.ar(freq*[1,1.01,0.5],lfo*lfowidth+0.5);
	sound = Mix(pulse);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("superbass", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	gate=1, cutoff= 800, rq=0.2|
	var sound;
	var env = EnvGen.ar(Env.adsr(0.01,0.0,0.9,0.05),gate,doneAction:2, timeScale:sustain);
	var osc, filter, filterenv;
	freq = freq / 4.0;
	osc = Saw.ar(freq);
	filterenv = EnvGen.ar(Env.adsr(0.0,0.5,0.2,0.2),gate,doneAction:2);
	filter =  RLPF.ar(osc,cutoff*filterenv+100,rq);
	sound = Mix(filter);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("supermoog2", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	gate=1, attackTime= 0.2, fenvamount=1.0, cutoff= 10000, voice=2.0|
	var sound;
	var env = EnvGen.ar(Env.pairs([[0,0],[0.07,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -1), timeScale:sustain, doneAction:2);
	var osc, filter, filterenv;
	freq = freq / 4.0;
	freq = [freq, freq * 1.001];
	osc = Mix(Pulse.ar(freq.lag(0.05)*[1.0,1.001,2.0],Rand(0.45,0.5)!3,0.33));
	filterenv = EnvGen.ar(Env.adsr(attackTime,0.0,1.0,0.2),gate,doneAction:2);
	filter =  MoogFF.ar(osc,cutoff*(1.0+(fenvamount*filterenv)), 2.0);
	sound = (filter * voice).distort;
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("superwho", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	amp = 0.5, gate=1, cutoff=8000, rq=0.8|
	var sound, fx;
	var env = EnvGen.ar(Env.pairs([[0,0],[0.07,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -1), timeScale:sustain, doneAction:2);
	var osc, filter;
	var basefreq =  (((freq/2.0).cpsmidi)+[0,0.1]).midicps;
	osc = Mix.fill(10,{|i| SinOsc.ar(basefreq*(i+1),0.0,(0.25+(0.75*LFNoise0.kr(10.1+i,0.5,0.5)))/(1.0+(0.5*i)))})*0.2;
	filter =  BLowPass.ar(osc,2000+(amp*cutoff),rq);
	sound = Mix(filter);
	fx = BLowPass.ar(BLowPass.ar(sound,SinOsc.ar(0.25,0,5000,5500),0.4),(200+(5000*SinOsc.ar(4.01,0.5,0.5,0.5))),0.6);
	sound = (sound * 0.7) + (fx * 0.3);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;

SynthDef("superrhodes", {|out, speed=1, decay=0, sustain=0.1, pan, accelerate, freq,
	gate=1, lforate = 4.85, lfowidth= 0.5, cutoff= 2000, rq=0.5|
	var sound;
	var pulse, filter, env;
	pulse = Pulse.ar(freq*[1,33.5.midiratio],[0.2,0.1],[0.7,0.3]);
	env = EnvGen.ar(Env.adsr(0.0,1.0,0.8,3.0),gate,doneAction:2, timeScale:sustain);
	filter = BLowPass4.ar(pulse,(cutoff*(env.squared))+200+freq,rq);
	sound = Mix(filter);
	OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, pan, env));
}).add;