音遊び日記

ハードウェアとソフトウェアの両面から”音”で遊んだ事を備忘録として書いています。

C言語を使ったエフェクター 第二回:歪み

 

1. はじめに

 第一回では準備段階としてwavファイルの入出力について扱いました。今回からは実践としてエフェクターを実装していきます。まずはエフェクターの基本である歪みから扱います。

 

2. 歪みの原理

  歪みエフェクターといってもオーバードライブ、ディストーション、ファズと種類がありますが、音の処理としては「とりあえず音を増幅して音割れさせる」だけです。しかもそれぞれの言葉の定義はあいまいであり、メーカーがディストーションと言えばディストーションだし、オーバードライブと言って売り出せばオーバードライブなのです。

 一応回路図を見るとある程度それぞれ傾向はありますが、音割れさせるという点で共通のため、回路でやっている処理は回路が処理できないレベルまで増幅させる事です。ほとんどのエフェクターは9V電源を使います。よって内部昇圧しない限り0~9Vの間の信号しか扱う事が出来ません。よって図1のように増幅しすぎると音割れが起きるのです、これが歪みの原理です。

f:id:hsy221:20180901225828j:plain

         図1 歪みの原理

 ではソフトウェアではこれをどのように実装するか、最も簡単な方法としてハードクリッピングとソフトクリッピングがあります。

 

2.1 ハードクリッピング

  図1で示したように、「信号がある一定値以上もしくは一定値以下になったらその値に丸め込む」手法です。最も簡単なアルゴリズムですが、如何にもディジタル臭い音になります。増幅率を大きくすると方形波に近づき、ファズっぽい音になります。横軸に入力信号の変位、縦軸に出力信号の変位をとると図2のような関数になります。

f:id:hsy221:20180904235237j:plain

 図2 ハードクリッピングのグラフ

 変位が0に近い領域では入力に対して出力が比例して増幅しています(1.5倍)。変位が±0.666…の時、出力信号が±1となりこれより変位の絶対値が大きい領域では飽和して±1に丸め込まれています。

 

2.2 ソフトクリッピング

   ハードクリッピングでは、飽和するまで比例して増幅しますが、ソフトクリッピングでは飽和する直前から徐々に歪み始めます。グラフにすると図3のようになります。

f:id:hsy221:20180905221918j:plain

 図3 ソフトクリッピング

 このようなグラフをその形からs型関数と呼びます。図3はその中でもなじみのありそうなarctan関数を使った関数です。式にすると以下のようになります。aはゲインと呼ばれグラフのカーブの傾きを決めるパラメータとなり、図3ではa=15としています。

f:id:hsy221:20180905222653j:plain

 s型関数には他にもtanhシグモイド関数などがあります。ググれば沢山出てくるので調べてみてください。この関数を使って歪ませると図4のようになります。

f:id:hsy221:20180905223208j:plain

  図4 ソフトクリッピング波形

 波形のエッジが丸くなっているのがわかりますね。ハードクリッピングを使うとこのエッジが鋭くなるわけなので、増幅率を大きくするとほぼ方形波となってしまう事がわかると思います。

 

3. ソースコード

  arctan関数を使った歪みエフェクターソースコードは以下のようになります。通常ただ歪ませるだけでは音量が歪ませる前に比べてかなり大きくなります。そのため音量を揃えるために、歪ませた後に音量を小さくする処理をします。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "header\audioio.h"

int main(int argc, char *argv[])
{
  //変数宣言
  WAV_PRM prm_in, prm_out;
  double *data_in, *data_out;
  int n;
  double gain, level;
  char filename[64];
 
  //コマンドライン引数が違う場合
  if(argc != 2) {
    printf("引数が違います\n");
    exit( 1 );
  }
 
  //各種パラメータ入力
  printf("gain : ");
  scanf("%lf", &gain);
  printf("level [%%] : ");
  scanf("%lf", &level);
  printf("output file name : ");
  scanf("%s", filename);
  level = level / 100;

  //wavファイルの読み込み
  data_in = audio_read(&prm_in, argv[1]);

  //パラメータコピーとメモリ確保
  prm_out.fs = prm_in.fs;
  prm_out.bits = prm_in.bits;
  prm_out.L = prm_in.L;
  data_out = calloc(prm_out.L, sizeof(double));
 
  //歪み処理
  for (n = 0; n < prm_out.L; n++) {
    //歪み
    data_out[n] = atan(gain * data_in[n]) / (M_PI / 2.0);
    //音量調整
    data_out[n] *= level;
  }
 
  //書き込み
  audio_write(data_out, &prm_out, filename);

  //メモリ解放
  free(data_in);
  free(data_out);

  return 0;
  }

 

5. まとめ

  エフェクター実装の手始めとして歪みを実装してみました。基本原理はとても単純ですがなぜこんなに沢山の歪みエフェクターが存在するのか。その理由は、実際に回路で組むと信号の立ち上がりと立ち下がりで歪み特性が違ったり、周波数帯域によって歪み特性が違ったり。。。様々な理由で回路構成によってそのエフェクターの「色」が出るからです。

 またほとんどのエフェクターは歪み回路だけではなく、回路の都合上、もしくは意図的にフィルタ回路が入っています。大体のエフェクターにはトーンつまみが付いていますよね?これが回路設計者の腕の見せ所であり、歪みエフェクターの奥深さでもあります(私には難しくてあきらめました…)。

 その内ディジタルフィルタについても触れるので、その後くらいでこの歪みにも「色」を付けていきたいと思います。