SSブログ

Arduino互換テストボードのMaruduinoでMIDI演奏にチャレンジ [ATmarquino Arduino]

※著作権表記及び署名の改竄以外はご自由にお使いください。
※ところでヘッダー情報の4分音符の分解能とデルタタイムを使っての時間指定の計算ってどうすればいいのでしょう?。
※デルタタイムを引数としてdelay関数を使って次のイベントまでの待ち時間を生成していますが、この為delayの引数の時間とそれ以外の処理時間の累積となって、実はテンポがいい加減です。さて、どうしたものかね。
※スケッチ改良しました。多分大体テンポは合っているかと思う。

Img_1953.jpg



前からMIDIをやってみたいとは思っていたんです。

ただMIDIに関すると言うか音楽全般に関する知識は皆無、音符とか読めませんし、そんな状態なので結構苦労しています。Arduinoの例題をベースにスケッチを書いてみましたが、まだまだバグバグで、しかも複数トラックを持つフォーマットには対応していません。
ですが、楽器を鳴らせるのは楽しいですな。

現状はキーを押すとMIDI出力するとかそう言ったものではなく、MIDIファイルをROM化して、それを流しています。
本当はMIDIファイルをそのまま垂れ流す程度で済むかと思っていましたが、そうではないんですね。データを送るタイミングとかはこちらでコントロールする必要が有るみたい。

あ、ちなみに物理的な接続はやけに簡単です。

スケッチとバイナリーデータをCソースに変換するプログラムも一応。
※MIDIのフォーマット0のみに対応




Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



新 裏口からのMIDI入門―「楽器が弾けない」「楽譜が読めない」初心者必見! (I・O BOOKS)

新 裏口からのMIDI入門―「楽器が弾けない」「楽譜が読めない」初心者必見! (I・O BOOKS)

  • 作者: 御池 鮎樹
  • 出版社/メーカー: 工学社
  • 発売日: 2009/11
  • メディア: 単行本



SANWA SUPPLY KB-MID01-18 MIDIケーブル

SANWA SUPPLY KB-MID01-18 MIDIケーブル

  • 出版社/メーカー: サンワサプライ
  • メディア: エレクトロニクス


/*
 MIDI player
 
 The circuit:
 * digital in 1 connected to MIDI jack pin 5
 * MIDI jack pin 2 connected to ground
 * MIDI jack pin 4 connected to +5V through 220-ohm resistor
 Attach a MIDI cable to the jack, then to a MIDI synth, and play music.

 created 13 Jun 2006
 modified 2 Jul 2009
 by Tom Igoe 
 
 http://www.arduino.cc/en/Tutorial/MIDI
 
 */
#include <LiquidCrystal.h>
#include  <avr/pgmspace.h>

/*************************************************************************/
/* defines                                                               */
/*************************************************************************/
#define  DI13     13
#define  DI12     12
#define  DI11     11
#define  DI10     10
#define  DI9      9
#define  DI8      8
#define  DI7      7
#define  DI6      6
#define  DI5      5
#define  DI4      4
#define  DI3      3
#define  DI2      2
#define  DI1      1
#define  DI0      0
#define  AN0      14
#define  AN1      15
#define  AN2      16
#define  AN3      17
#define  AN4      18
#define  AN5      19
#define  PWM11    DI11
#define  PWM10    DI10
#define  PWM9     DI9
#define  PWM6     DI6
#define  PWM5     DI5
#define  PWM3     DI3

typedef struct 
{
  struct
  {
    unsigned char chunk[4];
    unsigned char len[4];
    unsigned char format[2];
    unsigned char tracks[2];
    unsigned char period[2];
  } header;  

  struct
  {
    unsigned char type[4];
    unsigned char len[4];
    unsigned char data[4];
  } track;  
} MIDI;

static unsigned long swap_l( unsigned char src[] );
static unsigned short swap_w( unsigned char src[] );

extern const unsigned char PROGMEM midi_data[];
LiquidCrystal lcd(DI2,DI3,DI4,DI5,DI6,DI7);
unsigned long data_len;
unsigned short period;
PGM_P ptr;

void setup()
{
  MIDI *midi = (MIDI *)malloc( sizeof(MIDI) );

  memcpy_P( midi, midi_data, sizeof(MIDI) );
  data_len = swap_l(midi->track.len);
  period = swap_w(midi->header.period);

  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print( period );

  //  Set MIDI baud rate:
  Serial.begin(31250);
//  Serial.begin(38400);

  free( midi );
}

void loop()
{
  unsigned char c;
  unsigned long temp,delta_time,old_time,new_time;

  ptr = (PGM_P)(((MIDI *)midi_data)->track.data);
  old_time = 0;

  while( 1 )
  {
    delta_time = 0;
    c = pgm_read_byte_near(ptr++);
    if( c == 0x00 ) {}
    else
    {
      while( 1 )
      {
        delta_time <<= 7;
        delta_time |= c & 0x7f;
        if( c & 0x80 )
          c = pgm_read_byte_near(ptr++);
        else
          break;
      }
    }

#if 1
    lcd.setCursor(4,1);
    lcd.print( "     " );
    lcd.setCursor(4,1);
    lcd.print( delta_time );
#endif

    if( old_time == 0 )
      new_time = 0;
    else
      new_time = millis();

    temp = (delta_time * 1000 * 10) / period / 35;
    if( temp <= (new_time - old_time) )
      temp = 0;
    else
      temp -= new_time - old_time;

    delay( temp );
    old_time = new_time;

    if( event() == (-1) )
    {
      delay( 10000UL );
      break;
    }
  }
}

int event()
{
  unsigned char c;
  int ret = 0;
  
  c = pgm_read_byte_near(ptr++);  //
  switch( c & 0xf0 )
  {
    case 0xf0 :
      if( c == 0xff )
        ret = meta();
      else
      {
        if( c == 0xf0 )
        {
          c = pgm_read_byte_near(ptr++);  //
          for( int i = c; i > 0; i-- )
		  {
            c = pgm_read_byte_near(ptr++);  //
		  }
        }
        else
        {
          c = pgm_read_byte_near(ptr++);  //
          for( int i = c; i > 0; i-- )
		  {
            c = pgm_read_byte_near(ptr++);  //
		  }
        }
      }
      break;

    case 0x80 :  // 3bytes pattern
    case 0x90 :  // 3bytes pattern
    case 0xa0 :  // 3bytes pattern
    case 0xb0 :  // 3bytes pattern
    case 0xe0 :  // 3bytes pattern

      lcd.setCursor(8,1);
      lcd.print( "        " );
      lcd.setCursor(8,1);

      Serial.print(c,BYTE);
      lcd.print( c,HEX );
      lcd.print( ":" );

      c = pgm_read_byte_near(ptr++);
      Serial.print(c,BYTE);
      lcd.print( c,HEX );
      lcd.print( ":" );

      c = pgm_read_byte_near(ptr++);
      Serial.print(c,BYTE);
      lcd.print( c,HEX );
      break;

    default :  // 2bytes pattern
      lcd.setCursor(8,1);
      lcd.print( "        " );
      lcd.setCursor(8,1);

      Serial.print(c,BYTE);
      lcd.print( c,HEX );
      lcd.print( ":" );

      c = pgm_read_byte_near(ptr++);
      Serial.print(c,BYTE);
      lcd.print( c,HEX );
      break;
  }

  return ret;
}

int meta()
{
  unsigned char c,len;
  int ret = 0;

  c = pgm_read_byte_near(ptr++);
  switch( c )
  {
    case 0x00 :
      Serial.print(0xff,BYTE);Serial.print(c,BYTE);
      c = pgm_read_byte_near(ptr++);
      Serial.print(c,BYTE);
      break;
    case 0x01 :
    case 0x02 :
    case 0x03 :
    case 0x04 :
    case 0x05 :
    case 0x06 :
      Serial.print(0xff,BYTE);Serial.print(c,BYTE);
      len = pgm_read_byte_near(ptr++);
      Serial.print(len,BYTE);

      lcd.setCursor(0,0);
      lcd.print( "                " );
      lcd.setCursor(0,0);
      for( ;len > 0; len-- )
      {
        c = pgm_read_byte_near(ptr++);
        Serial.print(c, BYTE);
        lcd.print( c );
      }
      break;

    case 0x2f :
      Serial.print(0xff,BYTE);Serial.print(c,BYTE);
      c = pgm_read_byte_near(ptr++);
      Serial.print(c,BYTE);
      ret = (-1);
      break;

    case 0x51 :
    case 0x58 :
    case 0x59 :
      Serial.print(0xff,BYTE);Serial.print(c,BYTE);
      len = pgm_read_byte_near(ptr++);
      Serial.print(len,BYTE);
      for( ;len > 0; len-- )
      {
        c = pgm_read_byte_near(ptr++);
        Serial.print(c, BYTE);
      }
      break;

    default :
      break;
  }

  return ret;
}

static unsigned long swap_l( unsigned char src[] )
{
  unsigned long temp = 0;

  temp += src[0];
  temp <<= 8;
  temp += src[1];
  temp <<= 8;
  temp += src[2];
  temp <<= 8;
  temp += src[3];

  return temp;
}

static unsigned short swap_w( unsigned char src[] )
{
  unsigned short temp = 0;

  temp += src[0];
  temp <<= 8;
  temp += src[1];

  return temp;
}


/* ------------------------------------------------------------------------ */
/* バイナリファイルをCソースファイルに変換するプログラム					*/
/*                                                                          */
/*                                  Copyright (C) 2004- by hamayan			*/
/* ------------------------------------------------------------------------ */
#include <stdio.h>
#include <string.h>
#include <time.h>

/* ------------------------------------------------------------------------ */
/* メインね!																*/
/* ------------------------------------------------------------------------ */
int main( int argc, char *argv[] )
{
	char	str[32];
	int		i,c;
	long	length;
	FILE	*in,*out;
	time_t	timer;
	struct	tm	*tblock;

	if( argc != 3 )
	{
		fprintf( stderr, "Argument Missmatch.\r\n" );
		return EOF;
	}

	if( (in = fopen( argv[1], "rb" )) == NULL )
	{
		fprintf( stderr, "Image File Open Error.\r\n" );
		return EOF;
	}
	if( (out = fopen( argv[2], "wb" )) == NULL )
	{
		fprintf( stderr, "Output File Open Error.\r\n" );
		fclose( in );
		return EOF;
	}

	/*ヘッダー部の出力*/
	fprintf( out, "/* ------------------------------------------------------------------------ */\r\n" );
	fprintf( out, "/* Binary data file convert to C source file program.                       */\r\n" );
	fprintf( out, "/*                                             designed by hamayan          */\r\n" );
	fprintf( out, "/*                                             Copyright(C) hamayan         */\r\n" );
	fprintf( out, "/*                                             since 2004 -                 */\r\n" );
	fprintf( out, "/* ------------------------------------------------------------------------ */\r\n" );

	/*ヘッダーファイルの取り込み*/
	fprintf( out, "#include\t<avr/pgmspace.h>\r\n" );

	/*変換後のデータ表現*/
	fprintf( out, "const unsigned char PROGMEM midi_data[] =\r\n" );
	fprintf( out, "{\r\n" );
	do
	{
		fprintf( out, "\t" );
		for( i = 0; i < 16; i++ )
		{
			if( (c = fgetc( in )) == EOF ) break;
			fprintf( out, "0x%02X,", c );
		}
		fprintf( out, "\r\n" );
	} while( c != EOF );
	fprintf( out, "};\r\n\r\n" );

	/*フッター部の出力*/
	fprintf( out, "/* ------------------------------------------------------------------------ */\r\n" );
	fprintf( out, "/*                                             designed by hamayan          */\r\n" );
	fprintf( out, "/*                                             Copyright(C) hamayan         */\r\n" );
	fprintf( out, "/*                                             since 2004 -                 */\r\n" );
	fprintf( out, "/* ------------------------------------------------------------------------ */\r\n" );

	fclose( in );
	fclose( out );

	return 0;
}

/* ------------------------------------------------------------------------ */
/*                                  Copyright (C) 2004- by hamayan			*/
/* ------------------------------------------------------------------------ */


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。