HAGIWO KICKに HIHATを加えた Twin Drams

概要

今回は、HAGIWO作品のドラムモジュールを作ることにした。下記の2つの記事を読み進めているうちに、2つのモジュールを一つにまとめられる気がしてきたのでトライしてみたら、思いのほかうまくいった。

ほぼ、HAGIWO作品の丸写しで、工夫したのは2つのモデルを統合するコード。といっても、オリジナルのHAGIWO コードを一部いじっただけ。

HAGIWO KICK and HIHAT

本文

回路図

僭越ながら、HAGIWOさんのブログから回路図を拝借。2つのモデルのI/Oピンを図のように揃えた。
D3ピンをLEDの出力に割り当て、"HIHAT"にあったDecay用のLPF回路はそのまま使っている。LPF回路がないと、"HIHAT"でピー音が出たのでこのようにした。   "KICK"のOUTPUT D10は、LPFを2段階にして-12dBにしている。これを"HIHAT"でもそのまま使う。

schematic Kick schematic hihat

蛇足ながら、KICADで描いた回路図とPCBレイアウト

circuite


kicad of kick and hihat

code

元の2つのコードをトグルスイッチ(D2ピン)で切り換える。"HIHAT"にあったDecay出力とNPNトランジスタ回路の動作をソフトに置き換えた。

// 13_14_kick_or_Hihat.ino
#include <avr/io.h>


const static word fand[180] PROGMEM = {
 0,  17, 34, 52, 69, 86, 103,  120,  137,  154,  171,  187,  203,  219,  234,  250,  264,  279,  293,  307,  321,  334,  347,  359,  371,  383,  394,  404,  414,  424,  433,  441,  449,  456,  463,  469,  475,  480,  485,  489,  492,  495,  497,  498,  499,  500,  499,  498,  497,  495,  492,  489,  485,  480,  475,  469,  463,  456,  449,  441,  433,  424,  414,  404,  394,  383,  371,  359,  347,  334,  321,  307,  293,  279,  264,  250,  234,  219,  203,  187,  171,  154,  137,  120,  103,  86, 69, 52, 34, 17, 0,  -18,  -35,  -53,  -70,  -87,  -104, -121, -138, -155, -172, -188, -204, -220, -235, -250, -265, -280, -294, -308, -322, -335, -348, -360, -372, -384, -395, -405, -415, -425, -434, -442, -450, -457, -464, -470, -476, -481, -486, -490, -493, -496, -498, -499, -500, -500, -500, -499, -498, -496, -493, -490, -486, -481, -476, -470, -464, -457, -450, -442, -434, -425, -415, -405, -395, -384, -372, -360, -348, -335, -322, -308, -294, -280, -265, -250, -235, -220, -204, -188, -172, -155, -138, -121, -104, -87,  -70,  -53,  -35,  -18
};
const static word harm[180] PROGMEM = {
 0,  416,  365,  321,  334,  307,  279,  279,  254,  232,  227,  203,  185,  178,  155,  140,  131,  110,  97, 88, 68, 57, 48, 30, 21, 11, -4, -11,  -21,  -34,  -40,  -48,  -60,  -63,  -71,  -80,  -82,  -88,  -95,  -95,  -101, -104, -103, -107, -109, -106, -109, -107, -103, -104, -101, -95,  -95,  -88,  -82,  -80,  -71,  -63,  -60,  -48,  -40,  -34,  -21,  -11,  -4, 11, 21, 30, 48, 57, 68, 88, 97, 110,  131,  140,  155,  178,  185,  203,  227,  232,  254,  279,  279,  307,  334,  321,  365,  416,  0,  -417, -366, -322, -335, -308, -280, -280, -255, -233, -228, -204, -186, -179, -156, -141, -132, -111, -98,  -89,  -69,  -58,  -49,  -31,  -22,  -12,  3,  10, 20, 33, 39, 47, 59, 62, 70, 79, 81, 87, 94, 94, 100,  103,  102,  106,  108,  105,  108,  106,  102,  103,  100,  94, 94, 87, 81, 79, 70, 62, 59, 47, 39, 33, 20, 10, 3,  -12,  -22,  -31,  -49,  -58,  -69,  -89,  -98,  -111, -132, -141, -156, -179, -186, -204, -228, -233, -255, -280, -280, -308, -335, -322, -366, -417
};
//decay wavetable
const static word decay_table[100] PROGMEM = {
 100,  96, 94, 92, 91, 89, 87, 86, 84, 82, 81, 79, 78, 76, 74, 73, 71, 70, 68, 67, 65, 64, 63, 61, 60, 58, 57, 56, 54, 53, 52, 51, 49, 48, 47, 46, 44, 43, 42, 41, 40, 39, 38, 37, 36, 34, 33, 32, 31, 31, 30, 29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 19, 19, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9,  9,  8,  8,  8,  7,  7,  6,  6,  6,  6,  5,  5,  5,  5,  4,  4,  3,  3,  2,  1
};

// Pin definitions
int TRG = 5;
int SOUT = 10;
int LED = 3;
int TOG = 2;

// Global variables
unsigned int frq = 60000; // Default frequency for Kick waveform
float duty = 0.5;
int wave = 1000;

// Variables for Kick waveform generation
int h = 0;
int i = 0;
byte j = 1;
float k = 1;
int knob_tone_kick = 512;
int knob_harm_kick = 512;
int knob_attack_kick = 512;
int knob_decay_kick = 512;
int CV_harm_kick = 512;

// Variables for Hihat and Noise
//noise setting
unsigned int frq_hihat = 1000; // 周波数
float duty_hihat = 0.5;//pin10 for noise
unsigned int knob_pitch_hihat = 1;//knob AD
unsigned int knob_tone_hihat = 1;//knob AD
unsigned int CV_tone_hihat = 1;//CV AD

//decay setting
unsigned int knob_decay_hihat = 0;//knob AD
unsigned int CV_decay_hihat = 0;//CV AD
unsigned int decay_time_hihat = 0;
unsigned int d_duty_hihat = 100;//pin3 for decay

int i_hihat = 100;//decay wavetable reference
bool before_gate_hihat = 0;//0=no signal,1=gate in
bool gate_hihat = 0;//0=decay out end , 1=during decay out
long trigTimer_hihat = 0;//for generate decay time

bool prev_toggle_state ; // 前回のトグルスイッチの状態
bool isKickMode;

void setup() {
pinMode(SOUT, OUTPUT);
pinMode(TOG, INPUT_PULLUP);
pinMode(LED, OUTPUT);

// 初期トグル状態に応じてモードを設定
isKickMode = digitalRead(TOG) == HIGH;
if (isKickMode) {
  setupKickMode();
} else {
  setupHihatMode();
}
}

void loop() {
bool currentToggleState = digitalRead(TOG) == HIGH;

// トグル状態が変更された場合にモードを切り替え
if (currentToggleState != isKickMode) {
  isKickMode = currentToggleState;

  if (isKickMode) {
    setupKickMode();
  } else {
    setupHihatMode();
  }
}

// モードに応じて適切な出力を生成
if (isKickMode) {
  generateKickWaveform();
} else {
  generateHihatNoise();
}
}

void setupKickMode() {
// Timer1設定
TCCR1A = 0b00100001; // Set Timer1 for PWM mode on Channel B
TCCR1B = 0b00010001; // Set Timer1 prescaler and mode
OCR1A = (unsigned int)(8000000 / frq);
OCR1B = (unsigned int)(8000000 / frq * duty);

// Timer2停止
TCCR2A = 0b00000000; // Stop Timer2
TCCR2B = 0b00000000; // Stop Timer2
}

void setupHihatMode() {
// Timer1設定を保持
TCCR1A = 0b00100001; // Set Timer1 for PWM mode on Channel B
TCCR1B = 0b00010001; // Set Timer1 prescaler and mode
OCR1A = (unsigned int)(8000000 / 1000); // Hihatの基本周波数設定
OCR1B = (unsigned int)(8000000 / 1000 * 0.5); // Hihatのデューティサイクル設定

// Timer2設定
TCCR2A = 0b00100011; // Timer2 をPWMモードで設定
TCCR2B = 0b00001011; // Timer2 をPWMモードで設定
OCR2A = (unsigned int)(8000000 / 20000); // Timer2 の周波数設定
OCR2B = (unsigned int)(8000000 / 20000 * 0.5); // Timer2 のデューティサイクル設定
}

void generateKickWaveform() {
// Implement Kick waveform generation logic here
  static int old_trig_kick = 0;
  static int trig_kick = 0;
  
  old_trig_kick = trig_kick;
  trig_kick = digitalRead(TRG);

  digitalWrite(LED, trig_kick);

  if (old_trig_kick == 0 && trig_kick == 1) {
    h = 0;
    i = 0;
    j = 0;
    k = 1;
  }

  i++;
  if (i > 179) {
    knob_tone_kick = analogRead(0) / 64;
    knob_harm_kick = (1023 - analogRead(1)) / 32;
    knob_decay_kick = analogRead(3) / 16;
    knob_attack_kick = analogRead(5) / 16;
    CV_harm_kick = analogRead(6) / 32;

    knob_harm_kick = knob_harm_kick - CV_harm_kick;

    if (knob_harm_kick >= 31) {
      knob_harm_kick = 31;
    }

    h++;
    i = 0;
    j = j + 5;

    if (knob_decay_kick <= 32) {
      k = k * (98 - (32 - knob_decay_kick)) / 100 - 10 / 100;
    } else {
      if (h < (16 - knob_tone_kick) / 2) {
        k = 0.8 + h / 16 / 5;
      } else {
        k = k * (94 - (knob_decay_kick - 32)) / 100 - 10 / 100;
      }
    }
  }

  delayMicroseconds((knob_tone_kick) * j);

  if (h == 0 && i < knob_attack_kick && knob_attack_kick >= 5) {
    wave = (pgm_read_word(&(fand[random(0, 179)]))) * 32 + (pgm_read_word(&(harm[i]))) * (32 - knob_harm_kick);
  } else if (h <= 1 && i > 25 && i < 90) {
    wave = (pgm_read_word(&(fand[i]))) * (32 + knob_attack_kick / 3) + (pgm_read_word(&(harm[i]))) * (32 - knob_harm_kick);
  } else {
    wave = (pgm_read_word(&(fand[i]))) * 32 + (pgm_read_word(&(harm[i]))) * (32 - knob_harm_kick);
  }

  wave = wave * k;
  wave = wave / 32 + 500;
  duty = (float)wave / 1000;
  OCR1B = (unsigned int)(8000000 / frq * duty);
}

void generateHihatNoise() {
// Implement Hihat and Noise generation logic here
  // Hihat and Noise generation

  before_gate_hihat = gate_hihat;//for gate signal detect

  //------------------decay time setting---------------
  knob_decay_hihat = analogRead(3);
  CV_decay_hihat = analogRead(5);
  decay_time_hihat = (knob_decay_hihat + CV_decay_hihat ) * 5;

  //------------------noise setting-----------
  knob_pitch_hihat = analogRead(1);
  knob_tone_hihat = analogRead(0);
  CV_tone_hihat = analogRead(6);

  //------------------detect gate signal--------------
  gate_hihat = digitalRead(TRG);
  if (before_gate_hihat == 0 && gate_hihat == 1) {
    i_hihat = 0;
  }

  //--------------10pin pwm setting-----------------
  //MAKE SOME NOISE!!
  frq_hihat = random(1 + knob_tone_hihat * 2 + CV_tone_hihat * 2, 2 + knob_tone_hihat * 2 + CV_tone_hihat * 2 + knob_pitch_hihat * 2);
  duty_hihat = (float)random(1, 999) / 1000;

  // TOP値指定
  OCR1A = (unsigned int)(8000000 / frq_hihat );

  //--------------3pin pwm setting-----------------
  // TOP値指定
  OCR2A = (unsigned int)(8000000 / 20000 );

  if (knob_decay_hihat <= 970) {//make decay wave
    if (i_hihat < 99 && (micros() - trigTimer_hihat >= decay_time_hihat)) {
      i_hihat++;
      d_duty_hihat = (pgm_read_word(&(decay_table[i_hihat]))) ;
      trigTimer_hihat = micros();
    }
  } else {//decay knob max = constant output ( no decay )
    d_duty_hihat = 100;
  }

  // Duty比指定
  OCR2B = (unsigned int)(8000000  / 20000 * d_duty_hihat / 300);//300 is magic number

  // D3ピンのデケイ信号でD10ピンのノイズ信号を制御
  OCR1B = (unsigned int)(8000000 / frq_hihat * duty_hihat * d_duty_hihat / 100);
}

完成

ハード構成

  •  電源:+12V (基板上でLODにより +5V を生成)
  •  マイコン:Atmega328P(16MHzのセラロックをつけ、単体使用)

入力

  • analogRead(0): トーン設定(Kick)
  • analogRead(1): ハーモニクス設定(Kick)
  • analogRead(3): ディケイ設定(KickとHihat)
  • analogRead(5): アタック設定(Kick)およびディケイ設定(Hihat)
  • analogRead(6): CV入力(Kickのハーモニクス、Hihatのトーン)

PWM設定

  • Timer1 (Channel A): KickまたはHihatの基本周波数に応じたPWM出力設定
  • Timer1 (Channel B): KickまたはHihatのデューティサイクル設定
  • Timer2 (Channel A): Hihatの基本周波数設定
  • Timer2 (Channel B): ディケイのPWM設定

finished of kick and hihat

実験特性(動画)

関連リンク

Next Post Previous Post
Gemini