Processingでファミコン風の矩形波を鳴らす


こんな感じの音が出ます。

矩形波とは
squarewave
だいたいこんなよーな形の波形です。
音はいわゆるピコピコ音というやつで、ゲームウォッチやファミコン、ゲームボーイなど、PCエンジン手前くらいまでのほとんどのゲーム機での音は矩形波です。

なぜ矩形波が多く使われているかというと、スイッチのON/OFFだけで音を出すことができるから。
上の画像ではチューニングの基本とされる「ラ」の音(440Hz)を出していますが、
↓こういう回路を作って、スイッチをものすごい勢いで連打すれば、マイコンやPCなどなくてもこの音は出せます。
circuit_wavetest
ただし、1秒間に440連打しないと無理です。高橋名人(16Hz)にもファミコンロッキー(50Hz)にも無理でしょう。

矩形波は波が最大の時(HIGH)と最小(LOW)の時の比率(Duty比といいます)が1:1です。
Arduinoのtone()関数で出力できるのは矩形波です。つまり、HIGHとLOWは同じ間隔で鳴っています。

さて、次に、矩形波の音色を多少いじったものをパルス波と言います。
pulsewave
こんな感じで、HIGH/LOWの長さが違います。↑の画像だとHIGHが長くLOWが短くなっていますが、もちろん逆も可能。

ファミコン・ゲームボーイでメインとなる音は、この矩形波とパルス波の中間の性能を持っています。
HIGH/LOWの比率が「12.5:87.5」「25:75」「50:50」(←矩形波)「75:25」の4種類。
聴き比べてみると、意外と音色は変わるものです。

ということで、とりあえずProcessingを使って矩形波とパルス波を鳴らしてみました。ついでにサイン波と三角波も出せるようにしてあります。
マウスクリックで波形が替えられます。
マウスカーソルのX軸がパルス波の幅、Y軸がボリュームです。

import ddf.minim.*;
import ddf.minim.signals.*;

Minim minim;
AudioOutput out;
SineWave sine;
SquareWave square;
PulseWave pulse;
TriangleWave tri;
int wavetype = 0;

void setup()
{
  // Screen Init.
  size(600, 200);
  frameRate(60);
  smooth();
  strokeWeight(1);

  // minim Init.
  minim = new Minim(this);
  out = minim.getLineOut(Minim.MONO);
  sine = new SineWave(440, 0.5, out.sampleRate());
  pulse = new PulseWave(440, 0.5, out.sampleRate());
  square = new SquareWave(440, 0.5, out.sampleRate());
  tri = new TriangleWave(440, 0.5, out.sampleRate());
  
  // sine wave output
  out.addSignal(sine);
}

void draw()
{
  // BG-Black FG-Green
  background(0);
  stroke(0, 255, 0);
  translate(0, height/2);

  // Oscilloscope like View 
  float oldx, oldy, x, y;
  oldx = oldy = 0;
  for (int i = 0; i < out.bufferSize() - 1; i++)
  {
    x = map(i, 0, out.bufferSize(), 0, width);
    y = map(out.mix.get(i), 0, 1.0, 0, height/2);

    line(oldx, oldy, x, y);
    oldx = x;
    oldy = y;
  }
}

void mouseMoved()
{
  // X-pos as Pulse width
  float pulse_width = map(mouseX, 0, width, 1, 30);
  pulse.setPulseWidth(pulse_width);

  // Y-pos as Volume
  float amp = map(mouseY, 0, height, 1.0, 0.0);
  sine.setAmp(amp);
  pulse.setAmp(amp);
  square.setAmp(amp);
  tri.setAmp(amp);
}

void mousePressed()
{
  // Wave type Switch
  out.clearSignals();
  if (mouseButton == LEFT){
    ++wavetype;
   if (wavetype > 3)
     wavetype = 0;
  }else if (mouseButton == RIGHT){
    --wavetype;
    if (wavetype < 0)
      wavetype = 3;
  }
  switch (wavetype){
    case 0:
      out.addSignal(sine);
      break;
    case 1:
      out.addSignal(pulse);
      break;
    case 2:
      out.addSignal(square);
      break;
    case 3:
      out.addSignal(tri);
      break;
  }
}

void stop()
{
  out.close();
  minim.stop();
  super.stop();
}

以下のページを参考にしました。ありがとうございます。
computer graphics 3.2 サイン波の視覚化
ddf.minim.signals Class Oscillator


コメントを残す