2021年7月25日日曜日

Korg SQ-1のGate信号を拡張 GateEXの製作(2)

試作したGateEXは、Korg SQ-1とつないで自作のKIK01にSync信号を送ると、SQ-1のSync信号が疎で特にハットの刻みが少なくイマイチでした。Sync信号の周期を分割してもっと細かくGate信号を送出できるように改良しました。


SQ-1から送られてくるSync信号の間隔を測定し、分割数で割った間隔でタイマ割り込みをかけ、Gate信号を送出するという動作にしました。

ハードウェアの変更は行わず、変更はファームウェアのみです。Gateタイムを設定していたPOTで、分割数を設定するように変更しました。自作のKIK01は信号の立ち上がりしか見ていないのでGateタイムはSQ-1のSync信号と同じく15msに固定しました。

Gateオフのタイミングと分割したGate出力のタイミングを同じMsTimer2でとっています。Gateオフ時に次のGate信号のTimer割り込みを設定しており、図のようにタイマ割り込みまでの待ち時間はInterval - PULSE_WIDTH[ms]となります。

1回目のGate信号送出はSync信号のハードウェア割り込み時となるため、MsTimer2によるタイマ割り込みは2回め以降になります。「1/1」の場合はタイマ割り込みは行われません。

また、前回のファームウェアではDIPスイッチとシーケンスの割当が逆順になっていました。本来は左から右へ再生されるべきが、右から左の順になっていました。意外とわからないものですw

Arduinoのスケッチ <Gate_Sequencer_02.ino>

//
// Gate Sequencer
//   Sync-in -> Gate sequence
//   Split Sync-in
//
// 2021.07.25
//

#include <MsTimer2.h>

#define PIN_SYNC_IN      (2)
#define PIN_GATE_OUT     (12)
#define PIN_GATE_LED     (11)
#define PIN_DIVISION     (A0)

#define CNT_N            (8)
#define PULSE_WIDTH      (15)

byte sequence[CNT_N] = {0};
int cnt = 0;
int division = 1;
int divisionCnt = 0;
int interval = 0;

void gateOff()
{
  digitalWrite(PIN_GATE_OUT, LOW);
  digitalWrite(PIN_GATE_LED, LOW);

  if (divisionCnt > 0) {
    divisionCnt--;
    MsTimer2::set(interval - PULSE_WIDTH, stepOne);
    MsTimer2::start();
  }
}

void stepOne()
{
  digitalWrite(PIN_GATE_OUT, sequence[cnt]);
  digitalWrite(PIN_GATE_LED, sequence[cnt]);

  cnt++;
  if (cnt >= CNT_N) {
    cnt = 0;
  }

  MsTimer2::set(PULSE_WIDTH, gateOff);
  MsTimer2::start();
}

void step()
{
  static uint32_t prevTime = 0;
  
  uint32_t now = millis();
  interval = (now - prevTime) / division;
  prevTime = now;
  divisionCnt = division;

  stepOne();
  divisionCnt--;
}

void setup() {
  pinMode(PIN_SYNC_IN, INPUT);
  pinMode(PIN_GATE_OUT, OUTPUT);
  pinMode(PIN_GATE_LED, OUTPUT);

  // DIP switch
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(PIN_SYNC_IN), step, RISING);
}

void loop() {
  // Read DIP switch
  sequence[0] = !digitalRead(10);
  sequence[1] = !digitalRead(9);
  sequence[2] = !digitalRead(8);
  sequence[3] = !digitalRead(7);
  sequence[4] = !digitalRead(6);
  sequence[5] = !digitalRead(5);
  sequence[6] = !digitalRead(4);
  sequence[7] = !digitalRead(3);

  // Read division
  division = analogRead(PIN_DIVISION) / 256 + 1;  // 1 ~ 4
}

入出力波形

ch1:Sync-in ch2:Gate-out

SQ-1のSpeedを最速にし、GateExのDivisionを1/4に設定。

メモ


オシロで出力波形を観測すると、ジッターというか波形の間隔が揺れることがあります。millis()ではなくmicros()関数、MsTimer2ではなくTimer1を使うようにして(us単位で制御できる)分解能を上げると改善するかもしれません。

ハードウェアを改修するなら、押すとシーケンスの頭から再生し直す(シーケンス・リセット)ボタンがあると良さそうです。SQ-1のシーケンスとは1音単位では同期していますが、フレーズとしてはズレてしまいます。SQ-1側のスタート/ストップで一応は対応できます。

0 件のコメント:

コメントを投稿