製作モジュール一覧

2018年7月10日火曜日

Arduino EGの構想

Arduinoとアナログ処理部の組み合わせでエンベロープ・ジェネレーターを製作することにしました。

シミュレーション回路図

前回のシミュレーションでは「InvAttack」のスイッチング動作をAVRの3-State Bufferで行いましたが、一応MOS-FETでスイッチングしておくことにしました。

「Attack」信号がHになる時間は、AVRのADCで出力レベルを監視して制御しますが、シミュレーションでは固定しています。

過渡解析

Gate信号V(gate)からADSRエンベロープV(out)を作り出しています。

ブレッドボード配線図


ArduinoはAruduino Pro Mini(5V/16MHz版)を使用しました。

MOS-FET M1はシミュレーション回路図では2N7002になっていますが、2N7000を使いました。パッケージが違うだけで特性はほとんど同じです。

出力バッファ用のOPAMPは単電源OPAMPのNJM13404を使用しました。

A、R、Dとラベルを貼ってあるところの抵抗は10kΩ程度のPOTを使いますが、手持ちがないので固定抵抗で代用しました。Rsustainは10kΩ/Aです。

「GateIn」信号はSQR FG から出力しました。

Rattack=4.7kΩ
Rdecay=2.2kΩ
Rrelease=2.2kΩ


ch1:GateIn(D2) ch2:OUT

細かいパラメータは少々異なりますが、だいたいシミュレーションと同じような波形が出力されました。

Rattack=10kΩ
Rdecay=10kΩ
Rrelease=2.2kΩ


ch1:GateIn(D2) ch2:OUT

Rattack=1kΩ
Rdecay=1kΩ
Rrelease=1kΩ


ch1:GateIn(D2) ch2:OUT

Arduinoのスケッチ <Arduino_EG.ino>

/*
 * Arduino EG
 *
 * 2018.07.10
 *
 */

#define UART_TRACE  (0)
#define PIN_CHECK   (0)

#define TITLE_STR1  ("Arduino EG")
#define TITLE_STR2  ("20180710")

const int ThresholdPin = 0;

const int GateInPin = 2;

const int AttackPin = 4;
const int InvAttackPin = 5;
const int GateOutPin = 6;

const int LedPin = 13;

#if (PIN_CHECK)
const int CheckPin = 10;
#endif

enum EG_STATE {
  ST_ATTACK,
  ST_DECAY,
  ST_RELEASE
};

volatile enum EG_STATE state = ST_RELEASE;

void GateIn()
{
  bool isGateOn = digitalRead(GateInPin);
  
#if (UART_TRACE)
  Serial.println(isGateOn);
#endif

  if (isGateOn) {
    state = ST_ATTACK;
    digitalWrite(LedPin, HIGH);
  }
  else {
    state = ST_RELEASE;
    digitalWrite(LedPin, LOW);
  }
}

void setup()
{
  pinMode(AttackPin, OUTPUT);
  pinMode(InvAttackPin, OUTPUT);
  pinMode(GateOutPin, OUTPUT);
  pinMode(LedPin, OUTPUT);

  pinMode(GateInPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(GateInPin), GateIn, CHANGE);

#if (PIN_CHECK)
  pinMode(CheckPin, OUTPUT);
#endif

#if (UART_TRACE)
  Serial.begin(115200);
  Serial.println(TITLE_STR1);
  Serial.println(TITLE_STR2);
  delay(1000);
#endif
}

void loop()
{
  int th = analogRead(ThresholdPin);

  if (state == ST_ATTACK && th > 683) {
    state = ST_DECAY;
  }
  
#if (UART_TRACE)
  Serial.print(th);
  Serial.print("\t");
  Serial.println(state);
#endif

  switch (state) {
  case ST_ATTACK:
    digitalWrite(GateOutPin, HIGH);
    digitalWrite(InvAttackPin, LOW);
    digitalWrite(AttackPin, HIGH);
    break;
  case ST_DECAY:
    digitalWrite(AttackPin, LOW);
    digitalWrite(InvAttackPin, HIGH);
    break;
  case ST_RELEASE:
    digitalWrite(AttackPin, LOW);
    digitalWrite(GateOutPin, LOW);
    break;
  }
}


Github:
https://github.com/ryood/Arduino_EG

メモ:


Arduinoの処理能力と配線次第ですが、2系統エンベロープを出力できるかも?

エンベロープ・ジェネレーターの構想 その4 ステップ波形をLPFに通す。

NucleoでADSRの設定値を線形補間してDACから出力し、LPFを通したときはダメダメな波形になってしまいましたが、ステップ波形をLPFに通すとアナログADSR波形になりました。

シミュレーション回路図

過渡応答

この場合、1つのLPFを通しているので、Attack、Decay、Releaseの時定数が同じものになっています。(Susutain Levelは元のステップ波形で設定できています。)

これをADSRエンベロープ・ジェネレーターとして使うためには、A、D、Rでステートを分けて、それぞれ別のLPFを通してやる必要があります。

よくよく考えてみると、これは今実験中の「アナログ処理部」とほとんど同じ仕組みに帰着します。

簡易型のエンベロープ・ジェネレーターなら同じLPFを使ってもいいかもしれません。VST Plug-inでよくあるOne Knobみたいな(^q^;

2018年7月7日土曜日

エンベロープ・ジェネレーターの構想 その3 コンデンサの充電でAttack Timeを決める。

マイコン+Analog回路で検討しました。

Gate信号からADSRエンベロープを作り出すには、なんとかしてAttack Timeを決める必要があります。555タイマーを使ったエンベロープ・ジェネレーターはコンデンサの充放電でAttack Timeを決めています。

555タイマーのワン・ショットタイマー

555タイマーのブロック図

555の6ピンのTHRESに充電されるコンデンサをつなぎ、3本の抵抗で分圧された電位(2/3 * VCC)に達した時フリップ・フロップにリセットがかかり、7ピンのDISCHを通してコンデンサが放電されます。

Arduino Unoで実験


マイコン+Analog回路でこれと同じことができるかテストしました。

シミュレーション回路図

過渡解析

「Gate」にはGate信号を入力します。「GATE」からC1に充電され「OUT」の電圧が徐々に上がります。充電の速度は「Rattack」の抵抗値で決まります。

配線図


OUT(コンデンサの充電電圧)をArduinoのADC(A0)に接続して監視します。

Gate信号はプッシュスイッチで手動で発生させました。

10k/AのPOTを調節するとコンデンサの充電速度が変わり、Attack Timeを可変できます。

Arduinoのスケッチ <Arduino_EG_Charge_Test.ino>

/*
 * Arduino EG Charge Test
 *
 * 2018.07.05
 *
 */

#define TITLE_STR1  ("Arduino EG Charge Test")
#define TITLE_STR2  ("20180705")

const int ThresholdPin = 0;

const int GateInPin = 2;

const int GateOutPin = 4;
const int DischargePin = 5;

const int CheckPin = 7;

volatile bool isGateOn = false;

void GateIn()
{
  isGateOn = !digitalRead(GateInPin);
  //Serial.println(isGateOn);

  if (isGateOn) {
    // GateOutPin
    digitalWrite(GateOutPin, HIGH);

    // DischaregePin
    pinMode(DischargePin, INPUT); // Hi-Z
  }
  else {
    // GateOutPin
    digitalWrite(GateOutPin, LOW);

    // DischaregePin
    pinMode(DischargePin, OUTPUT);
    digitalWrite(DischargePin, LOW);  // Sink
  }
}

void setup()
{
  pinMode(GateOutPin, OUTPUT);
  pinMode(DischargePin, INPUT); // Hi-Z

  pinMode(GateInPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(GateInPin), GateIn, CHANGE);
  
  pinMode(CheckPin, OUTPUT);

  Serial.begin(115200);
  Serial.println(TITLE_STR1);
  Serial.println(TITLE_STR2);
  delay(1000);
}

void loop()
{
  int th = analogRead(ThresholdPin);
  Serial.println(th);

  if (isGateOn && th < 683) {
    digitalWrite(CheckPin, HIGH);
  }
  else {
    digitalWrite(CheckPin, LOW);
  }
}

AVRのI/Oピンのバッファは3-State Bufferで、ArduinoだとpinModeをINPUTにするとHi-Z(スイッチOFF)になります。

loop()内でanalogRead()でOUT(コンデンサの充電電圧)を監視して、(2 / 3) * 1024 = 683に達したことが識別できているかどうかをCheckPinのH/Lで測定できるようにしました。

オシロで測定


ch1:CheckPin(D7) ch2:OUT

Gate信号がHになった時にコンデンサへの充電が開始され、ch2の電圧が徐々に上がります。このときch1:CheckPin(D7)がHになります。

ch2が3.5V付近になったときにch1がLに切り替わり、Gate信号からAttack Timeを作ることができました。

この実験ではGate信号がLになった時に放電していますが、これを前回のシミュレーションのように、Attack Timeの終了時に放電を開始し、Sustain Levelに向かって放電してやればADSRエンベロープを作ることができそうです。

Arduino Pro Miniなどを使えば、555タイマーを使うよりも(自作する)回路規模は小さくて済みそうです。