aa develop

開発と成長

Minimの使い方

ここではProcessingで音を扱うためのライブラリであるMinimについて解説します。

スピーカーから音を鳴らす

まずはMinimの基本的な使い方を確認していきましょう。 次のコードはスピーカーから440Hzのサイン波を鳴らすものです。

/*
* sample01
*/

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

Minim minim;
AudioOutput out;
Oscil oscil;

void setup(){
  size(512, 200);
  minim = new Minim(this);
  out = minim.getLineOut();
  oscil = new Oscil(440, 1.0, Waves.SINE);
  oscil.patch(out);
}

void draw(){
  background(0);
  stroke(255);
  for(int i = 0; i < out.bufferSize() - 1; i++){
    line(i, 50 + out.left.get(i) * 50, i + 1,  50 + out.left.get(i + 1) * 50);
    line(i, 150 + out.right.get(i) * 50, i + 1,  150 + out.right.get(i + 1) * 50);
  }
}

このコードを順に解説していきます。

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

はじめにMinimのライブラリを読み込みます。 これはメニューの次のところを選択することで自動で入力されます。

「Sketch」->「Import Libary」->「minim」

Minim minim;
AudioOutput out;
Oscil oscil;

次に音を鳴らすために必要な変数を宣言します。 これらのクラスについては後ほど説明します。

void setup(){
  size(512, 200);
  minim = new Minim(this);
  out = minim.getLineOut();
  oscil = new Oscil(440, 1.0, Waves.SINE);
  oscil.patch(out);
}

setup関数ではまず、Minimクラスのインスタンスを作成します。 これはMinimを使う場合には必ず作成します。 AudioOutputはMinimで音を出力するために作成します。 Oscilは、サイン波や三角波矩形波などの波を作成するためのインスタンスです。 第1引数が周波数、第2引数が振幅(音量)、第3引数が波の種類です。 このOscilをAudioOutputにパッチして(繋げて)います。 これにより波を音としてスピーカーから出力できます。 このパッチングがMinimでいろいろな音を鳴らす上での肝となります。 引数を変更すると音程や音量が変化するのがわかると思います。

Oscilで作成できる波の種類には以下のものがあります。

void draw(){
  background(0);
  stroke(255);
  for(int i = 0; i < out.bufferSize() - 1; i++){
    line(i, 50 + out.left.get(i) * 50, i + 1,  50 + out.left.get(i + 1) * 50);
    line(i, 150 + out.right.get(i) * 50, i + 1,  150 + out.right.get(i + 1) * 50);
  }
}

draw関数内では、出力している音の波形をステレオの左右ごとに描画しています。

ファイルから音を再生する

今度は、ローカルにあるサウンドファイルをMinimを用いてProcessing上で鳴らしてみましょう。 次のコードでは、マウスクリックでサウンドファイルを頭から再生します。 サウンドファイルはソースファイルと同じディレクトリに置いてください。

/*
* sample02
*/

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

Minim minim;
AudioPlayer player;

void setup(){
  size(512, 200);
  minim = new Minim(this);
  player = minim.loadFile("sound.mp3");
}

void mousePressed(){
  player.rewind();
  player.play();
}

void draw(){
  background(0);
  stroke(255);
  for(int i = 0; i < player.bufferSize() - 1; i++){
      float x1 = map(i, 0, player.bufferSize(), 0, width);
      float x2 = map(i + 1, 0, player.bufferSize(), 0, width);
      line(x1, 50 + player.left.get(i) * 50, x2, 50 + player.left.get(i + 1)*50);
      line(x1, 150 + player.right.get(i) * 50, x2, 150 + player.right.get(i + 1)*50);
  }
}

ファイルを再生するには、AudioPlayerインスタスンスをminim.loadFile()により作成します。 mousePressed関数内では、はじめにrewind()でサウンドファイルの頭に再生位置を移動させ、play()で再生を始めます。 AudioPlayerでは、同じファイルを何度も再生するにはrewind()でサウンドファイルを巻き戻す必要があります。

マイクから入力した音をスピーカーから出力する

PCについているマイクから音を入力して、それをそのままスピーカーから鳴らすコードです。

/*
* sample03
*/

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

Minim minim;
AudioOutput out;
LiveInput in;

void setup(){
  size(512, 200);
  minim = new Minim(this);
  out = minim.getLineOut();
  AudioStream inputStream = minim.getInputStream(
                            out.getFormat().getChannels(),
                            out.bufferSize(),
                            out.sampleRate(),
                            out.getFormat().getSampleSizeInBits());
  in = new LiveInput(inputStream);
  in.patch(out);
}

void draw(){
  background(0);
  stroke(255);
  strokeWeight(1);
  for(int i = 0; i < out.bufferSize() - 1; i++){
    line(i, 50 + out.left.get(i) * 50, i + 1, 50 + out.left.get(i + 1) * 50);
    line(i, 150 + out.right.get(i) * 50, i + 1, 150 + out.right.get(i + 1) * 50);
  }
}

マイクから音を入力するには、LiveInputクラスを使います。 LiveInputを先述したAudioOutput型変数に直接パッチすることで出力しています。 PCのスピーカーから音をそのまま出力するとハウリングする可能性があるので、その場合はイヤフォンを使うなどしてください。 LiveInputとAudioOutの間に音を加工する処理を入れるとエフェクターになります。 MinimにはLiveInputの他にAudioInputという音を入力するためのクラスがありますが、LiveInputのほうが入力した音を加工することが簡単にできます。

Instrumentインターフェースを使う

最後にInstrumentインターフェースの使い方を説明します。 Instrumentインターフェースを使うことで音を鳴らす一連の処理をまとめることができます。 以下のコードでは、マウスクリックに応じてドレミを鳴らします。

/*
* sample04
*/

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

Minim minim;
AudioOutput out;

void setup(){
  size(512, 200);
  minim = new Minim(this);
  out = minim.getLineOut();
}

void mousePressed(){
  out.playNote(0.0, 0.5, new MyInstrument(Frequency.ofPitch("C4").asHz(), 0.5));
  out.playNote(0.5, 1.0, new MyInstrument(Frequency.ofPitch("D4").asHz(), 0.75));
  out.playNote(1.5, 1.5, new MyInstrument(Frequency.ofPitch("E4").asHz(), 1.0));
}

void draw(){
  background(0);
  stroke(255);
  strokeWeight(1);
  for(int i = 0; i < out.bufferSize() - 1; i++){
    line(i, 50 + out.left.get(i) * 50, i + 1, 50 + out.left.get(i + 1) * 50);
    line(i, 150 + out.right.get(i) * 50, i + 1, 150 + out.right.get(i + 1) * 50);
  }
}

class MyInstrument implements Instrument{
  Oscil oscil;
  MyInstrument(float frequency, float amplitude){
    oscil = new Oscil(frequency, amplitude, Waves.SINE);
  }
  
  void noteOn(float duration){
    oscil.patch(out);
  }
  
  void noteOff(){
    oscil.unpatch(out);
  } 
}

Instrumentインターフェースはimplementsで自作クラスに継承します。 自作クラスにはnoteOn関数とnoteOff関数を作成する必要があります。 noteOn関数は音を鳴らし始めるときに行うパッチングなどの処理を書きます。 noteOff関数は音を鳴らし終えるときに行うパッチを外す処理などを書きます。 このように作成したクラスはplayNoteメソッドに引数として渡します。 playNoteメソッドの第1引数はnoteOnを始めるまでの時間(秒)、第2引数はnoteOnを始めてからnoteOffで終わるまでの時間(秒)です。 第2引数はnoteOn関数に渡される引数(duration)になります。

この記事はProcessingで楽器を作ろうの第1回目です。

[参考]