Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

【Arduino MIDIドラムシーケンサ④】スイッチでリズムパターン切り替え

前回作成したドラムシーケンサでは1パターンのリズムしか演奏できませんでした。今回はタクトスイッチを使ってチャンネル1~4まで切り替えることで4種類のリズムパターンを演奏できるようにしてみました。
jakejake.hatenablog.com

配線

デジタルピンの3, 4, 5, 8にタクトスイッチを接続しました。タクトスイッチを押すとGNDにつながる(LOWになる)ようにします。

コード

主な追加個所はbyte Getchannelとboolean GetRTMの部分です。byte Getchannelはタクトスイッチの押下を監視し、boolean GetRTMはチャンネル、拍、楽器ごとのドラムパターンを出力します。

// Arduino MIDI Drum sequencer 
// Sending MIDI messages to the host PC.
// DAW: Waveform Free
//
// Author: Tara-chang
// 
// Revision History:
// Date        |    Author    |  Change
// ---------------------------------------------------
// 2021-05-09  |  Tara-chang  |  Initial Release
// 2021-05-09  |  Tara-chang  |  Added LCD and Trimpot to tempo control 
// 2021-05-16  |  Tara-chang  |  Added BUTTONS to change channel 

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <MIDI.h> 
MIDI_CREATE_DEFAULT_INSTANCE();

#define CRUSH 49 //C#3
#define KICK 36 //C2
#define CLAP 39 //D#2
#define SNARE 38 //D2
#define RIDE 51 //D#3
#define HITOM 50 //D3
#define MIDTOM 48 //C3
#define LOWTOM 45 //A2
#define OPHIHAT 46 //A#2
#define CLHIHAT 42//F#2

int DRUM[] = {SNARE, KICK, CLHIHAT, CRUSH};
const byte NUM_DRUM = sizeof(DRUM)/sizeof(DRUM[0]);
const byte NUM_BEAT = 8;

boolean RTM[NUM_DRUM][NUM_BEAT] = {
  {0,0,1,0,0,0,1,0},//SNARE
  {1,1,0,0,1,1,0,0},//KICK
  {1,1,1,1,1,1,1,1},//CLHIHAT
  {1,0,0,0,1,0,0,0}//RIDE
  };

boolean RTM2[NUM_DRUM][NUM_BEAT] = {
  {0,1,0,1,0,1,0,1},//SNARE
  {1,0,0,0,1,1,1,0},//KICK
  {1,0,1,0,1,0,1,0},//CLHIHAT
  {1,0,0,0,1,0,0,0}//RIDE
  };

boolean RTM3[NUM_DRUM][NUM_BEAT] = {
  {0,0,0,0,1,0,0,0},//SNARE
  {1,1,1,1,1,1,1,1},//KICK
  {0,0,0,0,0,0,0,0},//CLHIHAT
  {1,0,0,0,1,0,0,0}//RIDE
  };

boolean RTM4[NUM_DRUM][NUM_BEAT] = {
  {1,1,1,1,1,1,1,1},//SNARE
  {1,0,1,0,1,0,1,0},//KICK
  {0,0,0,0,0,0,0,0},//CLHIHAT
  {1,0,1,0,1,0,1,0}//RIDE
  };  
  
boolean RTM5[NUM_DRUM][NUM_BEAT] = {
  {1,1,1,1,1,1,1,1},//SNARE
  {1,0,1,0,1,0,1,0},//KICK
  {0,0,0,0,0,0,0,0},//CLHIHAT
  {1,0,1,0,1,0,1,0}//RIDE
  };  

byte nt = 0;
byte in = 0;
byte i = 0;
int BPM = 0; //X beats/60sec = 60/X sec/beat
int interval = 295;//60/double(BPM)*(NUM_BEAT/4)*1000; // 

boolean changed = 1;
int trimpot = 300;
int now_trimpot = 300;
#define INT_MIN 200
#define INT_MAX 1000
#define TRM_MIN 0 
#define TRM_MAX 1023
byte LEDPIN[] = {11, 12, 13, 10};
byte BUTPIN[] = {3, 4, 5, 8};
byte NUM_BUTPIN = sizeof(BUTPIN)/sizeof(BUTPIN[0]);
byte NUM_LEDPIN = sizeof(LEDPIN)/sizeof(LEDPIN[0]);
byte CHANNELS[] = {1,2,3,4};
byte NUM_CHANNELS = sizeof(CHANNELS)/sizeof(CHANNELS[0]);
byte NOW_CHANNEL = 1;
byte CHANNEL = 1;
byte nowchannel;

void setup()
{ 
  for (i=0;i<NUM_BUTPIN;i++){   
    pinMode(BUTPIN[i], INPUT);
    digitalWrite(BUTPIN[i], HIGH);     
  }
  for (i=0;i<NUM_LEDPIN;i++){   
    pinMode(LEDPIN[i], OUTPUT);
    digitalWrite(LEDPIN[i], LOW);     
  }
  
  Serial.begin(115200);
  MIDI.begin(4); //
  lcd.init();
  lcd.backlight();
  lcd.clear();
}

void loop(){

  NOW_CHANNEL = Getchannel(CHANNEL);  
  for (nt = 0; nt < NUM_BEAT; nt++){
    for (in = 0; in < NUM_DRUM; in++){    
      //String text = "(in,nt)=("+String(in)+","+String(nt)+")"+String(RTM[in][nt]);
           
      if (GetRTM(CHANNEL, in, nt)){
      MIDI.sendNoteOn(DRUM[in],127,1);  // (pitch, velocity, channel)         
      MIDI.sendNoteOff(DRUM[in],0,1);   //        
      }
    }
    delay(now_trimpot*(4/double(NUM_BEAT))); 
    }

    now_trimpot = map(analogRead(0), TRM_MAX, TRM_MIN, INT_MAX, INT_MIN);
    if ((now_trimpot!= trimpot)||(CHANNEL!=NOW_CHANNEL)){  
      trimpot = now_trimpot;
      CHANNEL = NOW_CHANNEL;
      changed = 1;
    }
    else{
      //Serial.println("trimpot changed");
    }         

    if(changed){
        BPM = 1/double(trimpot)*60*1000;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(BPM);
        lcd.setCursor(0, 1);
        lcd.print(CHANNEL);
        changed=0;
    }
      
//  OLD_CHANNEL = NOW_CHANNEL;
}

byte Getchannel(byte oldchannel){
    nowchannel = oldchannel;
    for (i=0;i<NUM_BUTPIN;i++){
      if ((digitalRead(BUTPIN[i])==LOW)){
        nowchannel = CHANNELS[i];
      }
      else{
        //nowchannel = oldchannel;
      }    
    }
    return nowchannel;
}

boolean GetRTM(byte nowchannel, byte in, byte nt){
    if(nowchannel==1){
      return RTM[in][nt];
    }
    else if(nowchannel==2){
      return RTM2[in][nt];
    }
    else if(nowchannel==3){
      return RTM3[in][nt];
    }
    else if(nowchannel==4){
      return RTM4[in][nt];
    }
    else{
      return RTM[in][nt]; 
    }
}

課題

・トリムポットのAnalogRead変動によりBPMが微妙にふら付いてしてしまうので変更必要。
・各チャンネルごとのBPMを別々に設定したい。
・16分音符に増量したほうがメタル・パンク的には楽しそう。
・音がショボい。ドラムプラグインをもうちょっと良いの使いたいかも。