「PIC AVR 工作室」サイトの日記的なブログです。
サイトに挙げなかった他愛ないことを日記的に書き残してます。
PIC AVR 工作室 ブログ



計算によると明日のはずなので、寒い中ロケハンに
出かけてみた。天気は良かったので、今日は今日で
人出があるだろうと斥候。

お、目つきの悪い人が寄ってきた。


さすがに風をさえぎるものがないので寒いんだけど、
あのくらいの人出ならまぁ、明日天気しだいで
出かけてもイイかなぁ。
GPV予報で明日の天気を調べてみる。
http://weather-gpv.info/

…だめじゃん。あぁ残念。また明日の最新予報で
考え直そう。


さて、昨日のアイデアを形に。
http://ichirowo.com/2011/06/arduino-midi-sound-source/
このサイトのソースを元に、昨日の方針でスケッチを
書き、アレコレと頭を悩ませながら弄っては動かし、
弄っては動かし…。
Arduinoはシミュレータがないのがやっぱり難点。
どこまでがちゃんと動いてて、どこでトラブって
いるのかが判断しかねる…。デバッグ用にLCDは
残しておいたほうがよかったななぁ。MIDI信号が
USARTを使っちゃってるから、変数を眺めたり
全然出来ない…。


でも、アレコレ弄りながらオシロで信号を眺めて
いると、とりあえず信号は出るようになった。
周波数も電圧もそれなりにあってるんだけど、なぜか
圧電スピーカを繋いでも音が出てこない。出てこない
っていうか、極微小のゴソゴソノイズが出ている感じ。
同じ圧電スピーカをtoneで鳴らしてみると…鳴る。

キャリー62500HzのPWMで作ったDDSでは圧電素子を
鳴らすことは出来ないのか?なぜだろう?

仕方ないので、代替案として、1kΩの抵抗と直列に
イヤフォンを繋いで聞いてみる。

…おぉ。鳴ってる。鳴ってるジャン。多少ノイズ
は載ってるものの、正弦波の音だ!

SparkFunのMIDI breakoutシールドでMIDIマスター
キーボードに繋いでみて、和音を鳴らしたり
ベロシティーに変化を付けてみたりする。

…うん。バッチリだな。とりあえず最低限の機能
は盛り込めた感。8オペでも鳴るか試してみる。
…うん。鳴る。ok。

いずれにしても相当スペック的にギリギリアウト
な感じで動かしているので、毎秒20000回の
割り込みでDDS計算しているのに、実際は
そこまで追従してないところはあるだろうな。
音の濁りとかはきっとそこらへんが一番大きな
原因っぽい。実際は10000Hzまでは出ないだろう。
20000回/秒というと、割り込み1回分のクロック
は800ぽっち。出来ることは限られる。

とはいえ、角速度ωの計算はきちんと20000回/秒
で行われているから、音程が狂うってことは
理論上無い。音程は狂わないけど、DDS計算が
部分的に追いついていないので、10000Hzは
出せないだろうな。音程を上げていくと、音色が
徐々にFM変調掛けた様な金属音に近づいていく。


とりあえず動いているスケッチがこれ。参考にした
サイトのスケッチや、以前作ったアセンブラの
プログラムなどを切り貼りして完全にフランケン
状態。読みにくく、汚い。

#include <avr/interrupt.h>
#include <MIDI.h>

const int max_notes = 8;
const int max_velocity = 127;


int d_out = 10;             // pwm out
int led = 13;

int ch;
  
volatile unsigned int tcnt2;

volatile unsigned int op_theta[max_notes];        // angle(theta) for each operator (16bits width)

int op_tone[max_notes];            // each tone read from MIDI
int op_velocity[max_notes];        // each velocity read from MIDI
//int op_chanel[max_notes];          // each chanel of op read from MIDI
int op_bend[max_notes];            // each bend read from MIDI
int op_using[max_notes];           // whether op is in use

char wave_form[] = {
    0x00,0x03,0x06,0x09,0x0C,0x10,0x13,0x16,
    0x19,0x1C,0x1F,0x22,0x25,0x28,0x2B,0x2E,
    0x31,0x33,0x36,0x39,0x3C,0x3F,0x41,0x44,
    0x47,0x49,0x4C,0x4E,0x51,0x53,0x55,0x58,
    0x5A,0x5C,0x5E,0x60,0x62,0x64,0x66,0x68,
    0x6A,0x6B,0x6D,0x6F,0x70,0x71,0x73,0x74,
    0x75,0x76,0x78,0x79,0x7A,0x7A,0x7B,0x7C,
    0x7D,0x7D,0x7E,0x7E,0x7E,0x7F,0x7F,0x7F,
    0x7F,0x7F,0x7F,0x7F,0x7E,0x7E,0x7E,0x7D,
    0x7D,0x7C,0x7B,0x7A,0x7A,0x79,0x78,0x76,
    0x75,0x74,0x73,0x71,0x70,0x6F,0x6D,0x6B,
    0x6A,0x68,0x66,0x64,0x62,0x60,0x5E,0x5C,
    0x5A,0x58,0x55,0x53,0x51,0x4E,0x4C,0x49,
    0x47,0x44,0x41,0x3F,0x3C,0x39,0x36,0x33,
    0x31,0x2E,0x2B,0x28,0x25,0x22,0x1F,0x1C,
    0x19,0x16,0x13,0x10,0x0C,0x09,0x06,0x03,
    0x00,0xFD,0xFA,0xF7,0xF4,0xF0,0xED,0xEA,
    0xE7,0xE4,0xE1,0xDE,0xDB,0xD8,0xD5,0xD2,
    0xCF,0xCD,0xCA,0xC7,0xC4,0xC1,0xBF,0xBC,
    0xB9,0xB7,0xB4,0xB2,0xAF,0xAD,0xAB,0xA8,
    0xA6,0xA4,0xA2,0xA0,0x9E,0x9C,0x9A,0x98,
    0x96,0x95,0x93,0x91,0x90,0x8F,0x8D,0x8C,
    0x8B,0x8A,0x88,0x87,0x86,0x86,0x85,0x84,
    0x83,0x83,0x82,0x82,0x82,0x81,0x81,0x81,
    0x81,0x81,0x81,0x81,0x82,0x82,0x82,0x83,
    0x83,0x84,0x85,0x86,0x86,0x87,0x88,0x8A,
    0x8B,0x8C,0x8D,0x8F,0x90,0x91,0x93,0x95,
    0x96,0x98,0x9A,0x9C,0x9E,0xA0,0xA2,0xA4,
    0xA6,0xA8,0xAB,0xAD,0xAF,0xB2,0xB4,0xB7,
    0xB9,0xBC,0xBF,0xC1,0xC4,0xC7,0xCA,0xCD,
    0xCF,0xD2,0xD5,0xD8,0xDB,0xDE,0xE1,0xE4,
    0xE7,0xEA,0xED,0xF0,0xF4,0xF7,0xFA,0xFD};    // wave form data declaration

//char wave_form[] = {
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
//    0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81};    // wave form data declaration


unsigned int omega_table[] = {
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  0    ,    
  10    ,    
  36    ,    
  62    ,    
  88    ,    
  115    ,    
  141    ,    
  167    ,    
  193    ,    
  220    ,    
  246    ,    
  272    ,    
  298    ,    
  324    ,    
  351    ,    
  377    ,    
  403    ,        //NOTE_B2
  429    ,        //NOTE_C3
  455    ,        //NOTE_CS3
  482    ,        //NOTE_D3
  511    ,        //NOTE_DS3
  541    ,        //NOTE_E3
  573    ,        //NOTE_F3
  606    ,        //NOTE_FS3
  642    ,        //NOTE_G3
  682    ,        //NOTE_GS3
  721    ,        //NOTE_A3
  763    ,        //NOTE_AS3
  809    ,        //NOTE_B3
  859    ,        //NOTE_C4
  908    ,        //NOTE_CS4
  963    ,        //NOTE_D4
  1019,        //NOTE_DS4
  1081,        //NOTE_E4
  1144,        //NOTE_F4
  1212,        //NOTE_FS4
  1285,        //NOTE_G4
  1360,        //NOTE_GS4
  1442,        //NOTE_A4  (1442 * 20000 / 256 / 256 = 440hz)
  1527,        //NOTE_AS4
  1619,        //NOTE_B4
  1714,        //NOTE_C5
  1815,        //NOTE_CS5
  1923,        //NOTE_D5
  2038,        //NOTE_DS5
  2159,        //NOTE_E5
  2287,        //NOTE_F5
  2425,        //NOTE_FS5
  2569,        //NOTE_G5
  2723,        //NOTE_GS5
  2884,        //NOTE_A5
  3054,        //NOTE_AS5
  3237,        //NOTE_B5
  3431,       //NOTE_C6
  3634,       //NOTE_CS6
  3850,       //NOTE_D6
  4080,       //NOTE_DS6
  4322,       //NOTE_E6
  4578,       //NOTE_F6
  4850,       //NOTE_FS6
  5138,       //NOTE_G6
  5443,       //NOTE_GS6
  5767,       //NOTE_A6
  6111,       //NOTE_AS6
  6475,       //NOTE_B6
  6858,       //NOTE_C7
  7265,       //NOTE_CS7
  7697,       //NOTE_D7
  8156,       //NOTE_DS7
  8641,       //NOTE_E7
  9155,       //NOTE_F7
  9699,       //NOTE_FS7
  10276,       //NOTE_G7
  10886,       //NOTE_GS7
  11534,       //NOTE_A7
  12219,       //NOTE_AS7
  12947,       //NOTE_B7
  13717,       //NOTE_C8
  14533,       //NOTE_CS8
  15398,       //NOTE_D8
  16312 };        //NOTE_DS8
// 20000sps ,table = 256samples ,range = 256times(integer=8bits,dicimal=8bits)


/* make timer2 interrupt every 20000hz */

void timer2_set() {
  float prescaler = 0.0;

  TIMSK2 &= ~((1<// prescaler set to 8
  TCCR2B &= ~((1<int)((float)F_CPU * 0.00005 / prescaler) - 1;
  OCR2A = tcnt2;
}


/* timer2 start and stop */

void timer2_start() {
  TCNT2 = 0;
  TIMSK2 |= (1<void timer2_stop() {
  TIMSK2 &= ~(1</* process at timer2 interruption occurred */

ISR(TIMER2_COMPA_vect) {
  int i;
  for (i=0;i/* make timer1 set for pwm output (mode=5 : fast pwm 8 bit) */

void timer1_set() {

  TCCR1B = 0;              // stop timer1

  OCR1BH = 0;              // (high 8 bits as 0)
  OCR1BL = 127;            // set output level as middle of 0..255 as initial value

  TIMSK1 = 0;                // invalid compare match interrapt 
  // and invalid timer1 overflow

  TCCR1A = (1<// use timer1 as mode5
  // fast pwm mode, as top value = 0xFF
  // OC1B is HIGH when count up compare match
  TCCR1B = (1<// non-pre-scaler as clock source
}


/* timer1 : pwm data output on ocr1b */

void timer1_pwm_out(char data1) {
  OCR1BH = 0;
  OCR1BL = data1;            // output data1 for pwm (alalog data)
}


/* calc and output data */

void calc_and_out() {

  long data1;
  int data2;
  int i;

  data1 = 0;
  for (i=0;inoInterrupts();    // atomic access
    data2 = (op_theta[i])>>8;
    interrupts();
    data1 = data1 + (wave_form[data2] * op_velocity[i]);
  }
  timer1_pwm_out(data1 / (max_velocity * max_notes) + 127);
}


/* input data from midi */

void midi_in() {

  int i;
  int data1;
  int data2;

  if (MIDI.read()) {
    switch(MIDI.getType()) {
    case NoteOn:
      data1 = MIDI.getData1();    // note no
      data2 = MIDI.getData2();    // velocity

      if(data2 == 0){
        for (i=0;iif(op_using[i] == data1){
            op_using[i] = 0;
            op_tone[i] = 0;
            op_velocity[i] = 0;
            op_bend[i] = 0;
            break;
          }
        }
        break;
      } 
      else {
        digitalWrite(led,HIGH);
        for (i=0;iif(op_using[i] == 0){
            op_using[i] = data1;
            op_tone[i] = data1;
            op_velocity[i] = data2;
            op_bend[i] = 0;
            break;
          }
        }
        digitalWrite(led,LOW);
      }
      break;
    case NoteOff:
      data1 = MIDI.getData1();    // note no
 
      for (i=0;iif(op_using[i] == data1){
          op_using[i] = 0;
          op_tone[i] = 0;
          op_velocity[i] = 0;
          op_bend[i] = 0;
          break;
        }
      }
      break;
    case PitchBend:
      data2 = MIDI.getData2();
      for (i=0;i//        op_bend[i] = data2 + 19;
      }
      break;
    default:
      break;
    }
  }
}


/*  init variables */

void init_val() {
  int i;

  for (i=0;i//op_chanel[i] = 0;
    op_bend[i] = 0;
    op_using[i] = 0;
  }
}


/***                ***/
/***   main logic   ***/
/***                ***/


void setup() {

  /*  init variables */
  init_val();

  /* pin setting */
  pinMode(d_out, OUTPUT);
  pinMode(led, OUTPUT);

  /* set up timers */
  timer2_set();
  //timer2_stop();
  timer2_start();
  timer1_set();

  /* start up MIDI */
  MIDI.begin();
  Serial.begin(38400);    // for conect to PC
                           // ( comment out if conect direct to MIDI instrument at 31250bps)
  ch = 1;
  MIDI.setInputChannel(ch);    // MIDI channel 
  MIDI.turnThruOff();      // turn off thru-out

}


void loop() {

  /* main loop */
  midi_in();
  calc_and_out();
}



(なんで1行おきになっちゃうんだろう?)

http://www.arduino.cc/playground/Main/MIDILibrary
MIDIライブラリのV3.2を使用。
チャンネルはとりあえず1固定(内部の変数では0固定)。
デジタル10番に、1kΩの抵抗と直列にしてイヤホンを
繋ぐか、LMM386で増幅掛けてからスピーカに繋ぐと
ちゃんと音が出るんだけど、前述の通り圧電スピーカ
はそのままデジタル10番に繋いでも音がボソボソ、
LM386通しても音がボソボソ。原因わからず。
なんだろうねぇ?


本当は全チャンネルからの入力対応にして、
8ポリのどこかが空いていればマッピングさせる
つもりだったんだけど、ArduinoのMIDIライブラリ
は特定のチャンネルだけフィルタリング掛けて、
他のチャンネルは読み捨ててしまっているらしい。

0から順に15まで読み出そうとループ処理を入れて
みても、MIDI信号の断片しか読み出せない…

うーーーーーん。MIDIライブラリを使う以上は
避けられないみたい。扱いがラクチンなんだけど
マルチチャンネル入力が出来ないのはなぁ…
自分で組みなおさないといかんか…


あと、ピッチベンドの処理が怪しいので、ちょっと
ホイールを回すと、その後音程が狂っちゃったり
色々駄目。この辺のバグは後回し。


そのほか、ピアノや弦楽器のようにサステインだけ
はエンベロープ掛けたいんだけど、あとは処理能力
との兼ね合いかなぁ。とりあえず動いたのでこれは
これでfixしておいて、今後の修正は別スケッチに
しよう。

とりあえずここまで。



コメント ( 0 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする