fbpixel
Criar um controlador MIDI com o Arduino

Criar um controlador MIDI com o Arduino

Neste projeto, vamos construir uma caixa MIDI para podermos testar os instrumentos sintetizadores CoolSoft e tocar algumas notas. Vamos utilizar três sensores para modificar as mensagens MIDI. É livre de acrescentar elementos para criar um controlador MIDI mais completo.

Pré-requisitos: criar uma interface MIDI com o Arduino

Equipamento

  • Arduino UNO
  • potenciómetro
  • codificador rotativo
  • teclado analógico 4×4

Características

Para testar a comunicação MIDI e o sintetizador. Vamos definir algumas funções simples:

  • Utilizando o teclado, vamos enviar notas musicais
  • Le potenciómetro permet d’ajuster la vitesse de la note
  • E o codificador modificará o instrumento sintetizado

N.B.: Escolhemos um teclado analógico para este projeto porque é fácil de ligar para podermos testar rapidamente o sintetizador. A desvantagem é que só se pode premir uma tecla de cada vez. Para um controlador MIDI mais eficaz, podes optar por um teclado digital ou por botões de arcada que te dêem feedback sobre as notas tocadas.

Diagrama

N.B.: Para facilitar a leitura, retirámos o ecrã de 7 segmentos. Pode encontrar a ligação neste tutorial.

Descrição do código

Em primeiro lugar, vamos definir funções para gerir cada um dos sensores.

Para o teclado 4×4, atribuímos a cada tecla um identificador que corresponde a uma nota. Criamos uma função que devolve o identificador quando uma tecla é premida.

const int valThresh[nbABtn] = {1000, 900, 820, 750, 660, 620, 585, 540, 500, 475, 455, 425, 370, 300, 260, 200};
const int pitches[nbABtn] = {50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80 }
int getABtn() { /* function getABtn */
 //// Read button states from keypad
 int val = analogRead(abtnPin);
 if (val <= 200) {
   return 0;
 } else {
   for (int i = 0; i < 16; i++) {
     if (val > valThresh[i]) {
       delay(100);
       return i + 1;
     }
   }
 }
}

Definimos uma função readPot que modificará o valor da velocidade em função do valor do potenciómetro velVal.

void readPot(){
  velVal = map(int(analogRead(potPin) / 10) * 10, 0, 1023, 0, 127);
  if (oldVel != velVal) {
    //Serial.println(velVal);
    velocity = velVal;
  }
  oldVel = velVal;
}

A função que gere o codificador permite-nos modificar o instrumento musical (identificador rotVal entre 0 e 127).

void readRotary( ) { /* function readRotary */
  ////Test routine for Rotary
  // gestion position
  clkState = digitalRead(clkPin);
  if ((clkLast == LOW) && (clkState == HIGH)) {//rotary moving
    if (digitalRead(dtPin) == HIGH) {
      rotVal = rotVal - 1;
      if ( rotVal < 0 ) {
        rotVal = 0;
      }
    }
    else {
      rotVal++;
      if ( rotVal > 127 ) {
        rotVal = 127;
      }
    }
    MIDImessage(prgmChg, rotVal, 0);
    number = rotVal;
    for (int i = 0; i < NUM_OF_DIGITS; i++)
    {
      digit_data[i] = number % 10;
      number /= 10;
    }
    delay(200);

  }
  clkLast = clkState;

  //gestion bouton
  swState = digitalRead(swPin);
  if (swState == LOW && swLast == HIGH) {
    delay(100);//debounce
  }
  swLast = swState;
}

Uma vez tida em conta a modificação do instrumento, o seu valor é visualizado no módulo 7 Segmento.

void Display(int id, unsigned char num)
{
  digitalWrite(latch, LOW);
  shiftOut(data, cs, MSBFIRST, table[num]);
  digitalWrite(latch, HIGH);
  for (int j = 0; j < NUM_OF_DIGITS; j++) digitalWrite(dPins[j], LOW);
  digitalWrite(dPins[id], HIGH);
}

void updateDigits() {
  for (int j = 0; j < NUM_OF_DIGITS; j++){
    Display(j, digit_data[j]);
    delay(2);
  }
}

Finalmente, voltamos à função que nos permite enviar mensagens MIDI

void MIDImessage(byte command, byte MIDInote, byte MIDIvelocity) {
  Serial.write(command);//send note on or note off command
  Serial.write(MIDInote);//send pitch data
  if (command == noteON || command == noteOFF) {
    Serial.write(MIDIvelocity);//send velocity data
  }
}

Tudo o que falta é enviar a mensagem quando um botão é premido

void readAbtn() { /* function readAbtn */
  //// Read button states from keypad
  btnId = getABtn();
  if (btnId) {
    if (lastBtnId != btnId) {
      MIDImessage(noteOFF, pitches[lastBtnId - 1], velocity);
    }
    MIDImessage(noteON, pitches[btnId - 1], velocity); //turn note on
    lastBtnId = btnId;
  }
}

Código completo da MIDIbox

byte velocity = 50;//velocity of MIDI notes, must be between 0 and 127
byte noteON = 144;// = 10010000 , Note On
byte noteOFF = 128;// = 10000000 , Note Off
byte pitchBend = 224; // = 11100000, Pitch Bender Change
byte polyKey = 160; // = 10100000, Polyphonic Key Pressure
byte overallPr = 208; // = 11010000, Overall Pressure
byte prgmChg = 192; // = 11000000, Program Change
byte ctrlChg = 176; // = 10110000,  Control Change

//Keypad
#define nbABtn 16
const int abtnPin = A1;
const int valThresh[nbABtn] = {1000, 900, 820, 750, 660, 620, 585, 540, 500, 475, 455, 425, 370, 300, 260, 200};
const int pitches[nbABtn] = {50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80 };
bool btnPressed = false;

//Potentiometer
const int potPin = A0; // Pin connected to sensor
int velVal = 0, oldVel = 0; // Analog value from the sensor

//rotary var
const int clkPin  = 53;
const int dtPin  = 51;
const int swPin  = 49;
int rotVal  = 0, btnId = 0, lastBtnId = 0;
bool clkState  = LOW;
bool clkLast  = HIGH;
bool swState  = HIGH;
bool swLast  = HIGH;

//4x7Segment
#define NUM_OF_DIGITS 4
int latch = 4; //74HC595  pin 9 STCP
int cs = 5; //74HC595  pin 10 SHCP
int data = 3; //74HC595  pin 8 DS
int dPins[4] = {8, 9, 10, 11};
//  DP G F E D C B A
//0: 1 1 0 0 0 0 0 0 0xc0
//1: 1 1 1 1 1 0 0 1 0xf9
//2: 1 0 1 0 0 1 0 0 0xa4
//3: 1 0 1 1 0 0 0 0 0xb0
//4: 1 0 0 1 1 0 0 1 0x99
//5: 1 0 0 1 0 0 1 0 0x92
//6: 1 0 0 0 0 0 1 0 0x82
//7: 1 1 1 1 1 0 0 0 0xf8
//8: 1 0 0 0 0 0 0 0 0x80
//9: 1 0 0 1 0 0 0 0 0x90
unsigned char table[] =
{0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
int digit_data[NUM_OF_DIGITS] = {0};
unsigned int number = 0;
unsigned long previousUpdate = 0, updateTime = 200;

void setup() {
  Serial.begin(115200);
  pinMode(potPin, INPUT);

  pinMode(clkPin, INPUT);
  pinMode(dtPin, INPUT);
  pinMode(swPin, INPUT_PULLUP);

  pinMode(latch, OUTPUT);
  pinMode(cs, OUTPUT);
  pinMode(data, OUTPUT);
  for (int j = 0; j < NUM_OF_DIGITS; j++) pinMode(dPins[j], OUTPUT);
}

void loop() {
  readRotary();
  updateDigits();
  readAbtn();
  readPot();
}

void MIDImessage(byte command, byte MIDInote, byte MIDIvelocity) {
  Serial.write(command);//send note on or note off command
  Serial.write(MIDInote);//send pitch data
  if (command == noteON || command == noteOFF) {
    Serial.write(MIDIvelocity);//send velocity data
  }
}


void readAbtn() { /* function readAbtn */
  //// Read button states from keypad
  btnId = getABtn();
  if (btnId) {
    if (lastBtnId != btnId) {
      MIDImessage(noteOFF, pitches[lastBtnId - 1], velocity);
    }
    MIDImessage(noteON, pitches[btnId - 1], velocity); //turn note on
    lastBtnId = btnId;
  }
}

int getABtn() { /* function getABtn */
  //// Read button states from keypad
  int val = analogRead(abtnPin);
  if (val <= 200) {
    return 0;
  } else {
    for (int i = 0; i < 16; i++) {
      if (val > valThresh[i]) {
        delay(100);
        return i + 1;
      }
    }
  }
}

//Potentiometer
void readPot(){
  velVal = map(int(analogRead(potPin) / 10) * 10, 0, 1023, 0, 127);
  if (oldVel != velVal) {
    //Serial.println(velVal);
    velocity = velVal;
  }
  oldVel = velVal;
}

//7Segment
void Display(int id, unsigned char num)
{
  digitalWrite(latch, LOW);
  shiftOut(data, cs, MSBFIRST, table[num]);
  digitalWrite(latch, HIGH);
  for (int j = 0; j < NUM_OF_DIGITS; j++) digitalWrite(dPins[j], LOW);
  digitalWrite(dPins[id], HIGH);
}

void updateDigits() {
  for (int j = 0; j < NUM_OF_DIGITS; j++)
  {
    Display(j, digit_data[j]);
    delay(2);
  }
}

//rotary
void readRotary( ) { /* function readRotary */
  ////Test routine for Rotary
  // gestion position
  clkState = digitalRead(clkPin);
  if ((clkLast == LOW) && (clkState == HIGH)) {//rotary moving
    if (digitalRead(dtPin) == HIGH) {
      rotVal = rotVal - 1;
      if ( rotVal < 0 ) {
        rotVal = 0;
      }
    }
    else {
      rotVal++;
      if ( rotVal > 127 ) {
        rotVal = 127;
      }
    }
    MIDImessage(prgmChg, rotVal, 0);
    number = rotVal;
    for (int i = 0; i < NUM_OF_DIGITS; i++)
    {
      digit_data[i] = number % 10;
      number /= 10;
    }
    delay(200);

  }
  clkLast = clkState;

  //gestion bouton
  swState = digitalRead(swPin);
  if (swState == LOW && swLast == HIGH) {
    delay(100);//debounce
  }
  swLast = swState;
}

Resultados

Para testar o código, é necessário abrir os programas hairless e VirtualMIDISynth como descrito neste artigo.

Se tudo estiver corretamente configurado, deverá ouvir sons provenientes do computador quando premir as teclas do teclado.

Também pode alterar a velocidade da nota tocando no potenciómetro.

Entre duas notas tocadas, pode então selecionar outro instrumento sintetizador utilizando o codificador rotativo.

Próximas etapas

  • Utilização de LEDs ou botões iluminados
  • Gestão da entrada MIDI para acender os LEDs
  • Utilização de um ecrã OLED para um menu mais completo

Fontes

Usar um buzzer com o Arduino

Usar um buzzer com o Arduino

É possível emitir sons com um microcontrolador ligando um buzzer a uma de suas saídas. Quando criamos uma interface de usuário, é interessante que ela possa dar feedbacks conforme as ações realizadas, seja através da exibição de uma imagem, de uma luz que se acende ou muda de cor ou da emissão de um som. Veremos neste tutorial como usar um buzzer (ou campainha piezoelétrica) para emitir sons com o Arduino.

Material

  • Computador
  • Arduino UNO
  • Cabo USB A Macho/B Macho
  • Buzzer

Princípio de funcionamento

Um buzzer é uma espécie de campainha de baixa potência que emite um som de acordo com a frequência e a amplitude da vibração. Ele permite tocar notas e criar melodias simples. Para reproduzir sons mais complexos, como música ou vozes, é necessário usar uma caixa de som com um amplificador áudio que reproduza um arquivo de áudio salvo num cartão SD.

Para reproduzir arquivos áudio, veja este tutorial.

Esquema

Como o buzzer é de baixa potência, pode ser conectado diretamente ao microcontrolador, em qualquer um de seus pinos de saída. Neste tutorial, conectamos o terminal – do buzzer ao GND, e o terminal + à saída digital 2.

Código

Cada nota corresponde a uma frequência registrada no arquivo pitches.h. Para tocar uma melodia, vamos colocar as notas numa tabela e especificar os intervalos entre cada nota. Para criar o arquivo pitches, clique na seta à direita do nome do esboço, depois clique em “criar nova aba. Em seguida, copie e cole o código com a definição das notas.

Arquivo .ino

//Libraries
#include "pitches.h" //https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody

//Parameters
const int buzPin  = 2;

void setup() {
  //Init Serial USB
  Serial.begin(9600);
  Serial.println(F("Initialize System"));
}

void loop() {
  playPassed();
  delay(1000);
  playFailed();
  delay(2000);
}

void playPassed() { /* function playPassed */
  ////Play 'ON' Sound
  int melodyOn[] = {NOTE_C5, NOTE_C6, NOTE_D5, NOTE_A6};
  int durationOn = 200;
  for (int thisNote = 0; thisNote < 4; thisNote++) {
    tone(buzPin, melodyOn[thisNote], durationOn);
    delay(200);
  }
}

void playFailed() { /* function playFailed */
  ////Play 'OFF' Sound
  int melodyOff[] = {NOTE_C3, NOTE_D3};
  int durationOff = 200;
  for (int thisNote = 0; thisNote < 2; thisNote++) {
    tone(buzPin, melodyOff[thisNote], durationOff);
    delay(200);
  }
}

Arquivo pitches.h

/*************************************************

 * Public Constants

 *************************************************/

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

Resultado

Modifique as notas, o tamanho das tabelas e os intervalos para criar as melodias que deseja.

Aplicações

  • Criar um teclado interativo com feedback sonoro
  • Criar um robô que emite sons, como o R2-D2

Fontes

Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie

Dê voz ao seu projeto Arduino

Dê voz ao seu projeto Arduino

Para tornar o seu projeto Arduino mais interativo, pode ser divertido colocar sons que correspondam a certas ações. Neste tutorial, veremos como reproduzir um arquivo de áudio WAV gravado num cartão SD com o Arduino

Pré-requisitos: Ler e escrever num cartão SD, Criar ou modificar um arquivo de áudio para o Arduino

Material

  • Computador
  • Arduino UNO
  • Cabo USB para ligar o Arduino ao computador
  • Shield ou módulo de cartão SD
  • Amplificador de áudio ou módulo transistor
  • Caixa de som

Esquema de ligação

O esquema de ligação pode variar em função dos componentes utilizados. Algumas informações podem ajudar na adaptação deste tutorial ao seu projeto. No nosso exemplo, o pino CS (Chip Select) do módulo de cartão SD está ligado ao pino 10 para comunicar com a placa Arduino. Este pino pode variar em função do shield utilizado e do local onde se liga o pino. Para mais informações sobre como ligar o módulo de cartão SD, leia este artigo. Na placa Arduino UNO, apenas o pino 9 é compatível com a biblioteca TMRpcm.h. Verifique a documentação (5, 6, 11 ou 46 para Mega; 9 para Uno, Nano, etc.). Dependendo da caixa de som utilizada, é preferível alimentá-la por uma fonte de tensão externa, para não danificar a placa Arduino.

Código para reproduzir um arquivo de áudio

Coloque o arquivo WAV no cartão SD e insira o cartão no módulo SD Card. Em seguida, carregue o código a seguir na placa Arduino. Para reproduzir o arquivo de áudio, utilizaremos a biblioteca TMRPcm.h, que permite reproduzir arquivos de áudio WAV de forma assíncrona a partir de um cartão SD. Neste exemplo, o arquivo de áudio é reproduzido a cada segundo.

Funções para conhecer:

  • tmrpcm.play(char*) para reproduzir o arquivo
  • tmrpcm.setVolume(int) para definir o volume da caixa de som
  • tmrpcm.stopPlayback() ou tmrpcm.disable() para parar a reprodução
  • tmrpcm.isPlaying() para saber se o arquivo está sendo reproduzido

Para mais informações, consulte a documentação.

//Libraries
#include <SD.h>
#include <TMRpcm.h>

//Constants
#define SD_ChipSelectPin 10//4 
const int speakerPin = 9;
char* file = "bonjour.wav";

//Variables
unsigned long previousTime = 0;
unsigned long interval = 1000;
//Objects
TMRpcm tmrpcm;
/*******************************************************************
                                 MAIN
*******************************************************************/
void setup() {
  /* function setup */
  Serial.begin(9600);
  //Init sd shield
  if (!SD.begin(SD_ChipSelectPin)) {
    Serial.println("SD fail");
    return;
  }

  //Init speaker
  tmrpcm.speakerPin = speakerPin;
  tmrpcm.setVolume(3);
}

void loop() {
  /* function loop */
  if (millis() - previousTime > interval) {
    activateOutput();
    previousTime = millis();
  }
}
/*******************************************************************
                                 FUNCTIONS
 *******************************************************************/
void activateOutput() {
  /* function activateOutput */
  Serial.println("Play sound");
  tmrpcm.play(file);
  while (tmrpcm.isPlaying()) {} //wait until file is played
  //delay(1000);tmrpcm.stopPlayback(); // or wait 1sec and stop music
}

Obs: Na função activateOutput(), é possível optar por não esperar que o arquivo seja lido para executar outras ações. Para isso, basta comentar a linha com while. Agora já pode reproduzir qualquer som com a sua placa Arduino.

Fonte

Próximos passos

Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie

Usar um Microfone com o Arduino

Usar um Microfone com o Arduino

É possível dotar o seu microcontrolador do sentido da audição ligando-o a um microfone. O microfone capta as vibrações no ar e transforma-as num sinal elétrico que pode ser analisado e processado com um algoritmo. Neste tutorial, veremos como detectar um nível sonoro utilizando o microcontrolador.

Material

  • Computador
  • Arduino UNO
  • Cabo USB A Macho/B Macho
  • Microfone

Princípio de funcionamento

O sensor utilizado neste tutorial é um microfone condensador elétrico. Ele é composto por duas superfícies, uma fixa e a outra móvel. As vibrações do ar geram o movimento da membrana móvel, causando a variação do potencial elétrico detectado pelo sensor, que então envia um sinal elétrico para o microcontrolador. Existem vários modelos de microfone com diferentes sensibilidades, para detectar sons mais ou menos fortes. O modelo mais adequado varia conforme o uso que se pretende fazer. Verifique a documentação do módulo.

Obs: Este tipo de módulo não permite gravar ou analisar sons complexos, mas principalmente níveis sonoros.

Esquema

O microfone requer pouca potência e pode ser alimentado diretamente no pino de 5V do Arduino. Ele devolve um valor analógico que é enviado para uma entrada analógica do microcontrolador. Dependendo do modelo, o módulo pode conter um potenciômetro para ajustar a sensibilidade do microfone.

  • AUD no pino A0
  • Vcc no pino 5V
  • GND no pino GND

Código

Para medir o nível sonoro, usamos a função AnalogRead(), como para a maioria dos sensores analógicos.

//Parameters
const int micPin  = A0;

//Variables
int micVal  = 0;

void setup() {
  //Init Serial USB
  Serial.begin(9600);
  Serial.println(F("Initialize System"));
  //Init Microphone
  pinMode(micPin, INPUT);
}

void loop() {
  readMicrophone();
}

void readMicrophone( ) { /* function readMicrophone */
  ////Test routine for Microphone
  micVal = analogRead(micPin);
  Serial.print(F("mic val ")); Serial.println(micVal);
  if (micVal > 600) {
    Serial.println("mic detected");
  }
}

Resultado

Depois de carregar o código no microcontrolador, podemos ver o valor analógico mudar conforme o ruído ambiente. Tente bater palmas, estalar os dedos ou falar para ver como o microfone se comporta. Isso ajudará a determinar o nível necessário para desencadear uma ação.

Aplicações

  • Ativar uma lâmpada batendo palmas
  • Criar um alarme ativado pelo ruído

Fontes

Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie

Gerar sons com uma interface MIDI Arduino

Gerar sons com uma interface MIDI Arduino

Para gerar sons sintéticos e criar música usando uma interface no seu computador, é possível transformar o Arduino num dispositivo MIDI.

Material

  • Computador
  • Arduino com entrada USB

Introdução ao protocolo MIDI

O MIDI (Musical Instrument Digital Interface) é um protocolo de comunicação entre instrumentos eletrônicos, controladores e software de música. Ele consiste em enviar uma série de bytes (comando e depois dados) a uma velocidade (baudrate) de 31250 para especificar o tipo de mensagem (tocar nota, parar nota, mudar de programa, etc.) e as informações associadas (nota tocada, programa selecionado, etc.). Veja aqui um resumo das mensagens MIDI.

Código para enviar mensagens MIDI com o Arduino

Veremos como enviar mensagens MIDI através da porta serial. Neste exemplo, enviaremos sucessivos comandos de notas como se apertássemos as teclas de um piano. Para tal, enviamos as seguintes informações, nesta ordem::

  • Comando noteOn ou Off para tocar a nota ou pará-la
  • a nota tocada ou o tom
  • a velocidade com a qual a tecla é pressionada

No protocolo MIDI, há um grande número de mensagens para realizar diferentes ações, como mudar de instrumento, modular notas, etc.

 int velocity = 100;//velocity of MIDI notes, must be between 0 and 127
 //higher velocity usually makes MIDI instruments louder
 
 int noteON = 144;//144 = 10010000 in binary, note on command
 int noteOFF = 128;//128 = 10000000 in binary, note off command

void setup() {
  Serial.begin(115200);
}

void loop() {
  for (int note=50;note<70;note++) {//from note 50 (D3) to note 69 (A4)
    MIDImessage(noteON, note, velocity);//turn note on
    delay(300);//hold note for 300ms
    MIDImessage(noteOFF, note, velocity);//turn note off
    delay(200);//wait 200ms until triggering next note
  }
}

void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}

Carregue o código acima no microcontrolador Arduino antes de prosseguir.

Obs: a velocidade da comunicação MIDI é de 31250. Neste exemplo, utilizaremos um conversor MIDI / Serial. Com isso poderemos utilizar qualquer baudrate.

Configuração da geração de som MIDI com o Windows

Configurar um instrumento MIDI virtual

Para gerar som, precisamos de um software de síntese sonora ou de uma DAW (Digital Audio Workstation). As DAWs podem ser um pouco complicadas de utilizar. Neste tutorial, usaremos um sintetizador de som virtual muito simples, o CoolSoft Virtual MIDI Synth.

  • Faça o download do software CoolSoft e instale-o.
  • Na aba MIDI Mapper, selecione VirtualMIDISynth como dispositivo padrão do Windows Media Player.
  • Na aba Opções, selecione o dispositivo de saída de áudio.
  • Clique em “Aplicar”.

Para que o software de síntese funcione, é necessário utilizar uma base de som (SoundFont) para converter as mensagens MIDI em sons vindos de um piano, por exemplo. Há uma lista de SoundFonts disponível na página CoolSoft. Em seguida, basta fazer o download do arquivo .sf2 desejado e adicioná-lo na interface CoolSoft.

Configuração do conversor Serial / MIDI

A comunicação MIDI é um protocolo específico diferente da comunicação USB. Para que as mensagens MIDI enviadas pelo Arduino via USB sejam levadas em conta, é necessário um conversor Serial / MIDI

Para tal, usamos o software Hairless Midi to Serial Bridge, que permite converter mensagens seriais em mensagens MIDI.

  • Faça o download do software Hairless e abra-o.
  • Selecione o Arduino conectado ao seu PC na lista suspensa “Serial Port” (Porta Serial)
  • Depois, selecione VirtualMIDISynth na lista suspensa”MIDI Out”.

Se ativar o Debug MIDI messages, poderá ver rolarem as notas tocadas e as suas velocidades .

Se a saída de áudio do seu computador estiver ligada, ouvirá as notas musicais.

Obs: Não é possível carregar o código para o Arduino se a opção Serial <->MIDI Bridge On estiver selecionada.

Depois de criar a sua primeira interface MIDI com o Arduino, já pode dar os seus primeiros passos na síntese sonora.

Aplicações

  • Criar um controlador MIDI com o Arduino, botões e potenciômetros.

Fontes