yoppa.org


Sonic Pi + SuperCollider 1 – Sonic Piで自作Synthをつくる

この講義の前半はSonic Piを使用してライブコーディングを活用した作曲やパフォーマンスについて学びました。そして中盤から後半にかけて、SuperColliderを使用した音響合成の基礎を学んできました。Sonic Piが和声やリズムや旋律といった音楽のマクロな構造を記述するための言語とすると、SuperColliderは波形単位で音を生成するミクロな構造の創作でした。いよいよ今回からは、Sonic PiとSuperColliderを融合して、音のミクロな構造からマクロな構造まで全てを統合していきます。

今回はまず始めの一歩として、SuperColliderで定義した簡単な楽器定義(SynthDef)を、Sonic Piに読み込んで実際に演奏するところまでを解説します。

スライド資料

サンプルコード

//SuperColliderとSonic Piの連携

//基本形
SynthDef("piTest", {
    //出力先のバスを引数で設定
    arg out_bus = 0;
    //440HzのSin波生成
    var mix = SinOsc.ar(440).dup;
    //Envelope生成
    var env = EnvGen.ar(Env.perc(0.0, 1.0, 1.0), doneAction: 2);
    //Envelope適用
    mix = mix * env;
    Out.ar(out_bus, mix);
}
//ファイルの出力先を指定
).writeDefFile("/Users/tado/Desktop/my-synths");

//音程(note)と音量(amp)を受け取る
SynthDef("piTest", {
    //音程と音量を引数を指定
    arg note = 52, amp = 1, out_bus = 0;
    //音程(MIDI番号)から周波数へ
    var freq = note.midicps;
    //周波数をSin波に適用
    var mix = SinOsc.ar(freq).dup;
    var env = EnvGen.ar(Env.perc(0.0, 1.0, 1.0), doneAction: 2);
    mix = mix * env;
    Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");

//エンベロープとPanを適用
SynthDef("piTest", {
    arg out_bus = 0, note = 52, amp = 1, attack = 0, release = 1, pan=0;
    var freq = note.midicps;
    var mix = SinOsc.ar(freq);
    var env = EnvGen.ar(Env.perc(attack, release, 1.0), doneAction: 2);
    //Panを適用
    mix = Pan2.ar(mix * env, pan);
    Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");

//Moog風楽器
SynthDef("piTest", {
    arg out_bus = 0, note = 52, amp = 1, attack = 0, release = 1, detune = 1.01, pan=0;
    var freq = note.midicps;
    var mix =  MoogFF.ar(
        Pulse.ar([freq,freq*0.5], 0.8),
        freq*2.5,
        128
    );
    var env = EnvGen.ar(Env.perc(attack, release, amp), doneAction: 2);
    mix = Pan2.ar(mix * env, pan);
    Out.ar(out_bus, mix);
}
).writeDefFile("/Users/tado/Desktop/my-synths");


Generative KML – 地球にアルゴリズムで描画する

前回はiPhoneやAndroidで計測したGPSの位置情報をProcessingで描画しました。今回はそれとは逆の発想で、KMLファイルをProcessingから書き出すことで、生成的(Generative)にGoogle Earthに形を描いてみます。KMLファイルの構造を復習した上で、Processingのファイル入出力機能を駆使してKMLファイルを生成します。

スライド資料

サンプルプログラム


openFrameworks – 物理シミュレーション ofxBox2D

今回は物理シミュレーションを行うことができる、ofxBox2DというAddonをとりあげます。

ofxBox2Dは、Box2DというC++で書かれた2Dの物理演算エンジンをopenFrameworksのAddon化したものです。Box2Dは質量、力、速度、摩擦といった古典物理学(ニュートン力学)の演算を高速に行う、物理法則の演算のためのライブラリーで、もともとはC++で書かれていますが、現在では、Java、C#、Python、JavaScriptなど様々な言語に移植されています。ofxBox2Dを使うことで簡単な物理法則を援用したアニメーションだけでなく、2次元のゲームやインタラクティブなコンテンツなどに応用可能です。今回は、ofxBox2Dの導入から、形を定義して物理世界に追加する方法、大量の物体を追加するための工夫などを紹介していきます。

スライド資料

サンプルファイル


SuperCollider基礎 3 – エンベロープ (Envelop)、加算合成、減算合成

今回も引き続きSuperColliderによる音響合成について探求していきます。

まず始めに音の時間的変化であるエンベロープ(Envelope)をSuperColliderで実装してみます。エンベロープを変化させるだけで、例えば同じSin波でも様々に表情が変化します。また音響合成のパラメータにエンベロープを使用することで、時間経過によって複雑に変化する音色のデザインが可能となります。

後半は音の「足し算」「引き算」を行います。音の足し算は加算合成(Additive Synthesis)です。複数の音(例えばSin波)の周波数を変化させてミックスしていくことで音色をデザインしていきます。楽器で例えるとオルガンのような合成方法です。音の引き算は減算合成(Subtractive Syntesis)です。こちらは周波数成分を多く含んだ音(ノイズ、ノコゴリ波、パルスなど)を入力して、特定の周波数帯域のみ通過させます。この特定の周波数帯域のみ通過させる仕組みをフィルター(Filter)と呼びます。SuperColliderには様々なフィルターが存在していてそれぞれ特徴があります。実際に音を聞きながら試していきましょう。

スライド資料

サンプルコード

//エンベロープ (Envelope)

// Env.linen - アタック、サステイン、リリース、レベルで指定
Env.linen(0.05, 0.2, 0.5, 0.7).plot;

SynthDef("EnvTest", {
    var env, out;
    env = Env.linen(0.05, 0.1, 0.5);
    out = SinOsc.ar(440).dup * EnvGen.kr(env, doneAction: 2);
    Out.ar(0, out);
}).play;

// Env.perk - パーカッシブなエンベロープ
Env.perc(0.01, 2.0).plot;

SynthDef("EnvTest", {
    var env, out;
    env = Env.perc(0.01, 2.0);
    out = SinOsc.ar(440).dup * EnvGen.kr(env, doneAction: 2);
    Out.ar(0, out);
}).play;

// Env.triangle - 三角形のエンベロープ
Env.triangle(1, 1).plot;

SynthDef("EnvTest", {
    var env, out;
    env = Env.triangle(1, 1);
    out = SinOsc.ar(440).dup * EnvGen.kr(env, doneAction: 2);
    Out.ar(0, out);
}).play;

// Env.triangle - 三角形のエンベロープ
Env.sine(1, 1).plot;

SynthDef("EnvTest", {
    var env, out;
    env = Env.sine(1, 1);
    out = SinOsc.ar(440).dup * EnvGen.kr(env, doneAction: 2);
    Out.ar(0, out);
}).play;

// Env.new - 完全に自由なエンベロープ生成
// レベルの配列と、時間の配列で指定
Env.new([0, 1, 0.9, 0], [0.1, 0.5, 1],[-5, 0, -5]).plot;

SynthDef("EnvTest", {
    var env, out;
    env = Env.new([0, 1, 0.9, 0], [0.1, 0.5, 1],[-5, 0, -5]);
    out = SinOsc.ar(440).dup * EnvGen.kr(env, doneAction: 2);
    Out.ar(0, out);
}).play;


//加算合成 (Additive Synthesis)

//加算合成基本
SynthDef("AdditiveSynth", {
    var n = 12;
    var out;
    out = Mix.arFill(n,  {
        SinOsc.ar(
            [rrand(40, 2000), rrand(40, 2000)],
            0,
            n.reciprocal * 0.75;
        )
    });
    Out.ar(0, out);
}).play;

//加算合成、全体にエンベロープ
SynthDef("AdditiveSynth", {
    var n = 12;
    var out;
    out = Mix.arFill(n,  {
        SinOsc.ar(
            [rrand(40, 2000), rrand(40, 2000)],
            0,
            n.reciprocal * 0.75;
        )  *  EnvGen.kr(Env.perc(11, 6), doneAction:2);
    });
    Out.ar(0, out);
}).play;


//加算合成、ひとつひとつのSin波にエンベロープ
SynthDef("AdditiveSynth", {
      var n = 12;
      var out;
      out = Mix.arFill(n,{
            SinOsc.ar(
                  [rrand(40, 2000), rrand(40, 2000)],
                  pi.rand,
                  n.reciprocal)
            * EnvGen.kr(Env.sine(rrand(2, 20)),  doneAction: Done.none)
      }) * EnvGen.kr(Env.perc(11, 6), doneAction: Done.freeSelf, levelScale: 0.75);
      Out.ar(0, out);
}).play;


//減算合成 (Subtractive Synthesis)

//減算合成 - LPF ローパスフィルター
SynthDef("SubtractiveSynth", {
    var out;
    out = LPF.ar(
        Saw.ar([80, 81] ),
        [LFNoise0.kr(4, 800, 840), LFNoise0.kr(8, 800, 840)]
    );
    Out.ar(0, out);
}).play;

//減算合成 - RLPF レゾナンス付きローパスフィルター2
SynthDef("SubtractiveSynth", {
    var out;
    out = RLPF.ar(
        Saw.ar([80, 81] ),
        [LFNoise0.kr(4, 800, 840), LFNoise0.kr(8, 800, 840)],
        Saw.kr(0.2, 0.5, 0.2)
    );
    Out.ar(0, out);
}).play;

//減算合成 - RLPF レゾナンス付きローパスフィルター2
SynthDef("SubtractiveSynth", {
    var out;
    out = RLPF.ar(
        Saw.ar([80, 81] ),
        [LFNoise0.kr(4, 800, 840), LFNoise0.kr(8, 800, 840)],
        0.2
    );
    Out.ar(0, out);
}).play;

//減算合成 - RLPF レゾナンス付きローパスフィルター2
SynthDef("SubtractiveSynth", {
    var out;
    out = RLPF.ar(
        Saw.ar([80, 81] ),
        [LFNoise0.kr(4, 800, 840), LFNoise0.kr(8, 800, 840)],
        Saw.kr(0.2, 0.5, 0.2)
    );
    Out.ar(0, out);
}).play;

//減算合成 - RLPF レゾナンス付きローパスフィルター3
SynthDef("SubtractiveSynth", {
    var out;
    out = RLPF.ar(
        Saw.ar([80, 81] ) + Saw.ar([121, 120]) + Saw.ar([161, 160]),
        [LFNoise0.kr(4, 800, 840), LFNoise0.kr(8, 800, 840)],
        Saw.kr([0.2, 0.15], 0.5, 0.2)
    );
    Out.ar(0, out);
}).play

GPS情報をプログラムで描画してみる

前回はGPSの情報をGoogle Earthに読み込む方法を紹介しました。今回はさらに発展させてGPSのデータをもとに独自に形の描画に挑戦します!まず始めに、GPSデータを活用した作品をいくつか紹介します。その上で、独自のGPSによる表現について考えていきます。

今回はProcessinでGPSの軌跡を描画してみます。まずiOSアプリのmyMapsで取得されるGPX形式のデータを解析します。その情報を元にProcessingで座標を解析し様々な方法で描画してみます。

スライド資料

サンプルファイル


CMSを使ってみる – WordPressの使い方とカスタマイズ

企業のホームページや、ニュースなどの情報サイトでは、常に大量のWebページを扱い頻繁に更新しています。このような大規模なWebサイトでは、手作業で1ページずつHTMLとCSSを記述していては膨大な作業量になってしまいます。

現在では多くのWebサイトで「コンテンツマネジメントシステム(Contents Management System = CMS)」と呼ばれる、Webサイトを構成するテキストや画像などのデジタルコンテンツを統合・体系的に管理し、配信など必要な処理を行うシステムを使用しています。CMSを利用することで、簡単にページを追加、更新、管理することが可能となり、またサイト全体のデザインの統一やアクセス解析など、様々な機能を使用することが可能となります。

CMSには無料のもの、有料のもの、サーバー側で使用する言語などに応じて様々なシステムがあります。現在CMSのマーケットシェアは、圧倒的にWordPressというシステムで占められています。2017年11月の時点で、全てのCMSのうちWordPressの割合は約60%という調査結果もあります。

今回は、WordPressの無料ブログ版のサービス WordPress.com を使用してCMSの使い方とカスタマイズの基本について紹介します。

スライド資料


openFrameworks – 3Dグラフィクス、メッシュの操作

この講義では、ここまで主に2次元平面上での描画による表現を扱ってきました。今回は2次元での表現からさらに(文字通り)次元を越えて、3次元空間での表現について考えていきたいと思います。

openFrameworksで3Dグラフィクスを扱う手法はこれまでとさほど変化はありません。なぜなら、openFrameworksの描画の基本はOpenGLで行っています。OpenGLはそもそも3次元のグラフィクスの描画のために開発されたライブラリであり、最初から3次元空間をとり扱うための様々な機能が備わっています。

しかし、3Dの物体を扱うには、これまでとは違った様々な要素が加わります。カメラ(視点)、ライティング、光と影(シェーディング)、奥行の重なりなどといった2次元の平面には無かった様々な技術や概念の理解が必要となります。

スライド資料

サンプルファイル

プログラムのサンプルは、以下からダウンロードしてください。


SuperCollider基礎 2 – 変調合成 (RM, AM, FM)

先週学んだSuperColliderで「楽器」を定義する SynthDef を利用して、様々な音響合成の手法について実際に音を聞きながら学んでいきます。まず今回は、ある信号のパラメーターをもう一つの信号で変化(変調)させる「変調合成」という手法について紹介します。変調合成は、信号の何を変調するのかによって、AM(RM)、FMという種類に分けられます。それぞれの変調合成の音色の違いなどに注意しながら、SuperColliderでの実現のやり方を学んでいきましょう。

スライド資料

コードサンプル

// SuperColliderによる音響合成変調合成1- RMとAM
// RM変調
SynthDef("test-rm",{
    var car, mod, rm;
    mod = SinOsc.ar(880, 0, 1.0);
    car = SinOsc.ar([440,442], 0, 0.5);
    rm = car * mod;
    Out.ar(0, rm);
}).play;


// RM変調2 - マウスでModulatorの周波数を変更
SynthDef("test-rm",{
    var car, mod, rm;
    mod = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 1.0);
    car = SinOsc.ar([440,442], 0, 0.5);
    rm = car * mod;
    Out.ar(0, rm);
}).play;

// RM変調3 - 2つのModulator
SynthDef("test-rm",{
    var car, mod1, mod2, rm;
    car = SinOsc.ar(440, 0, 0.5);
    mod1 = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 1.0);
    mod2 = SinOsc.ar([1/6.1,1/7.9]);
    rm = car * (mod1 * mod2);
    Out.ar(0, rm);
}).play;

// AM変調
SynthDef("test-am",{
    var car, mod, rm;
    mod = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 0.5, 0.5);
    car = SinOsc.ar([440,442], 0, 0.5);
    rm = car * mod;
    Out.ar(0, rm);
}).play;

SynthDef.new("test-am",{
    var car, mod1, mod2, am;
    car = SinOsc.ar(440, 0, 0.5);
    mod1 = SinOsc.ar(MouseX.kr(1, 4000, 1), 0, 0.5, 0.5);
    mod2 = SinOsc.ar([1/8,1/7]);
    am = car * (mod1 * mod2);
    Out.ar(0, am);
}).play;

// AM + LFNoise
(
SynthDef("rand-am",{
    arg freq = 440, amp = 0.5, modFreq = 400;
    var car, mod1, mod2, am;
    car = SinOsc.ar(freq, 0, amp);
    mod1 = SinOsc.ar(LFNoise1.kr(5.reciprocal, modFreq), pi.rand, 0.5, 0.5);
    mod2 = SinOsc.ar(LFNoise1.kr([1/8, 1/7])0, 0.5, 0.5);
    am = car * (mod1 * mod2);
    Out.ar(0, am);
}).add;
)

(
Synth("rand-am", ["freq", 110, "amp", 0.2, "modFreq", 1200]);
Synth("rand-am", ["freq", 220, "amp", 0.2, "modFreq", 200]);
Synth("rand-am", ["freq", 440, "amp", 0.2, "modFreq", 200]);
Synth("rand-am", ["freq", 880, "amp", 0.2, "modFreq", 100]);
Synth("rand-am", ["freq", 1780, "amp", 0.05, "modFreq", 20]);
)

//FM基本
SynthDef("test-fm", {
    arg cfreq = 440, mfreq = 111, index = 200;
    var car, mod;
    mod = SinOsc.ar(mfreq, 0, index);
    car = SinOsc.ar([cfreq, cfreq*1.01] + mod, 0, 0.5);
    Out.ar(0, car);
}).play;

//FMマウスで操作
SynthDef("test-fm",{
    var car, mod;
    mod = SinOsc.ar(MouseX.kr(1, 1000, 1), 0,
        MouseY.kr(1, 10000, 1));
    car = SinOsc.ar([440,442] + mod, 0, 0.5);
    Out.ar(0, car);
}).play;

//FM応用
(
SynthDef("fm1", { arg freq = 440, detune = 2, carPartial = 1, modPartial = 1, index = 3, mul = 0.2;
    var mod, car;
    mod = SinOsc.ar(
        [freq, freq+detune] * modPartial, 0,
        freq * index * LFNoise1.kr(1/10)
    );
    car = SinOsc.ar((freq * carPartial) + mod, 0, mul);
    Out.ar(0, car);
}).add;
)

(
Synth("fm1", ["modPartial", 2.4]);
Synth("fm1", ["modPartial", 2.401]);
Synth("fm1", ["freq", 110, "modPartial", 3.1213, "index", 10]);
Synth("fm1", ["freq", 220, "modPartial", 10.99, "index", 20]);
)
//FM + エフェクト
(
SynthDef("fm2", { arg bus = 0, freq = 440, detune = 2, carPartial = 1, modPartial = 1, index = 3, mul = 0.1;
    var mod, car;
    mod = SinOsc.ar(
        [freq, freq+detune] * modPartial,
        0,
        freq * index * LFNoise1.kr(10.reciprocal).abs
    );
    car = SinOsc.ar((freq * carPartial) + mod, 0, mul);
    Out.ar(bus, car);
}).add;

SynthDef("preDelay", { arg inbus = 2;
    ReplaceOut.ar(
        4,
        DelayN.ar(In.ar(inbus, 1), 0.048, 0.048)
    )
}).add;

SynthDef("combs", {
    ReplaceOut.ar(
        6,
        Mix.arFill(7, { CombL.ar(In.ar(4, 1), 0.1, LFNoise1.kr(Rand(0, 0.1), 0.04, 0.05), 15) })
    )
}).add;

SynthDef("allpass", { arg gain = 0.2;
    var source;
    source = In.ar(6, 1);
    4.do({source = AllpassN.ar(source, 0.050, [Rand(0, 0.05), Rand(0, 0.05)], 1) });
    ReplaceOut.ar(8, source * gain)
}).add;

SynthDef("theMixer", { arg gain = 1;
    ReplaceOut.ar(
        0,
        Mix.ar([In.ar(2, 1), In.ar(8, 2)]) * gain
    )
}).add;
)

(
Synth("fm2", ["bus", 2, "freq", 440, "modPartial", 2.4]);
Synth("fm2", ["bus", 2, "freq", 448, "modPartial", 2.401]);
Synth.tail(s, "preDelay");
Synth.tail(s, "combs");
Synth.tail(s, "allpass");
Synth.tail(s, "theMixer", ["gain", 0.64]);
)

Processing Libraries 1 : ControlP5 – GUIを作成する

screenshot_597

Processingは、その設計思想として、構造をあまり複雑にせず創造的な部分に集中できるよう焦点を絞っています。グラフィクスとモーションを作り、マウスやキーボードといった汎用的な入力デバイスに反応する機能が基本です。しかし、それ以上のことを行うために、Processingではライブラリー (Libraries) というものが用意されています。ライブラリーとは汎用性の高い複数のプログラムを、再利用可能な形でひとまとまりにしたものです。Processingでも用途に応じて様々なライブラリがまとめられ、入手できるようになっています。

Processingのライブラリーには大きく分けて2種類あります。Core LibrariesとContributed Librariesです。Core Librariesは、Processingの開発元からオフィシャルに提供されているライブラリーで、Processingのソフトウェアに付属してきます。Contributed Librariesは、Processingのユーザー達によって公開されている非公式のライブラリーで、別途ダウンロードが必要です。

今回は、ライブラリーの導入として、カスタマイズしたGUIをプログラムに追加するための「Control P5」というライブラリーを取り上げます。ControlP5を活用することで、GUIを様々なパラメータに適用するすることが可能となり、プログラムの調整をインタラクティブに行うことが可能となります。

スライド資料

サンプルコード


KML入門 – 地球に情報を描いてみる

今回は、Google Earthに3Dモデルを配置するのではなく、直接数値を指定して線やポリゴンなどの図形を描く方法について探求していきます。

Google EarthやGoogle Mapsなどの地理情報を扱うアプリケーションに、2Dや3Dの地理データと関連コンテンツを格納するためのKMLという言語があります。KMLはXMLをベースにしたマークアップ言語で、地図上に目印(Placemark)や、線(Path)、ポリゴン(Polygon)、画像のオーバーレイなど様々な方法で直接描画を行うことが可能です。KMLを利用することで、GPSで記録された位置情報など様々なデータを地図に直接ビジュアライズすることが可能です。

今回は、まずこのKMLの基本を理解して、実際にGoogle Earthに描画していきます。

スライド資料

サンプルファイル