1. 程式人生 > >MIDI控制程式 Aduino平臺 容易遷移到STM8/STM32

MIDI控制程式 Aduino平臺 容易遷移到STM8/STM32

/*
硬體連線:
 5V :  Arduino上的5V連線音效板的VCC
 GND : Arduino上的GND連線音效板上的GND
 D3    Arduino上的軟串列埠的TX引腳(D3引腳)連線音效板上的MIDI引腳
 D4 :  Arduino上的D4引腳連線音效板上的RESET引腳
 */

//軟串列埠庫
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3);//引腳2是RX(沒用到), 引腳3是TX 

byte note = 0;      		//音符變數,表示將要播放的音符,初始值是0,範圍是0-127
byte resetMIDI = 4; 	//數字引腳4,連線到VS1053的復位引腳
byte ledPin = 13;   	//MIDI通訊指示燈
int  instrument = 0;	//樂器號變數,初始值為0

void setup() 
{
  //設定硬串列埠波特率為57600bps,用於連線PC以顯示程式執行狀態
  Serial.begin(57600);
  //設定用於MIDI通訊的軟串列埠,波特率為31250bps
  mySerial.begin(31250);

  //對VS1053進行復位:低電平持續100ms,後拉高並保持
  pinMode(resetMIDI, OUTPUT);   	//復位引腳設定為輸出
  digitalWrite(resetMIDI, LOW); 		//引腳電平拉低
  delay(100);
  digitalWrite(resetMIDI, HIGH);		//引腳電平拉高
  delay(100);
  talkMIDI(0xB0, 0x07, 120);    		//0xB0 是通道訊息, 設定1通道音量接近最大 (127)
}

void loop() {

  //基本的MIDI樂器, GM1,參見VS1053手冊33頁
  //=================================================================
  Serial.println("Basic Instruments");
  talkMIDI(0xB0, 0, 0x00); //預設bank GM1

  //改變不同的樂器,GM1總共有128種樂器,0~127
  for(instrument = 0 ; instrument < 127 ; instrument++) 
  {
    Serial.print(" Instrument: ");
    Serial.println(instrument, DEC);
    talkMIDI(0xC0, instrument, 0); //設定MIDI通道1的樂器為instrument

    //Play notes from F#-0 (30) to F#-5 (90):
    for (note = 30 ; note < 40 ; note++) 
    {
      Serial.print("N:");
      Serial.println(note, DEC);
      
      //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
      noteOn(0, note, 60);
      delay(50);

      //Turn off the note with a given off/release velocity
      noteOff(0, note, 60);
      delay(50);
    }

    delay(100); //Delay between instruments
  }
  //=================================================================


  //Demo GM2 / Fancy sounds
  //=================================================================
  Serial.println("Demo Fancy Sounds");
  talkMIDI(0xB0, 0, 0x78); //Bank select drums 選擇打擊樂器

  //For this bank 0x78, the instrument does not matter, only the note
  for(instrument = 30 ; instrument < 31 ; instrument++) {

    Serial.print(" Instrument: ");
    Serial.println(instrument, DEC);

    talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command 

    //Play fancy sounds from 'High Q' to 'Open Surdo [EXC 6]'
    for (note = 27 ; note < 87 ; note++) {
      Serial.print("N:");
      Serial.println(note, DEC);
      
      //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
      noteOn(0, note, 60);
      delay(100);

      //Turn off the note with a given off/release velocity
      noteOff(0, note, 60);
      delay(100);
    }

    delay(100); //Delay between instruments
  }




  //Demo Melodic
  //=================================================================
  Serial.println("Demo Melodic? Sounds");
  talkMIDI(0xB0, 0, 0x79); //Bank select Melodic
  //These don't sound different from the main bank to me

  //Change to different instrument
  for(instrument = 27 ; instrument < 87 ; instrument++) {

    Serial.print(" Instrument: ");
    Serial.println(instrument, DEC);

    talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command

    //Play notes from F#-0 (30) to F#-5 (90):
    for (note = 30 ; note < 40 ; note++) {
      Serial.print("N:");
      Serial.println(note, DEC);
      
      //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
      noteOn(0, note, 60);
      delay(50);

      //Turn off the note with a given off/release velocity
      noteOff(0, note, 60);
      delay(50);
    }

    delay(100); //Delay between instruments
  }



}

//傳送一個MIDI音符開訊息
//通道範圍0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
  talkMIDI( (0x90 | channel), note, attack_velocity);
}

//傳送一個MIDI音符關訊息
void noteOff(byte channel, byte note, byte release_velocity) {
  talkMIDI( (0x80 | channel), note, release_velocity);
}

//播放一個音符
//不要檢視去看一看數值大於127或者小於127是什麼樣的
void talkMIDI(byte cmd, byte data1, byte data2) {
  digitalWrite(ledPin, HIGH);
  mySerial.write(cmd);
  mySerial.write(data1);

  //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes 
  //有一些命令只有一個位元組。所有小於0xBn的命令有兩個資料位元組
  //(sort of: http://253.ccarh.org/handout/midiprotocol/)
  if( (cmd & 0xF0) <= 0xB0)
    mySerial.write(data2);

  digitalWrite(ledPin, LOW);
}