Acordió MIDI

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

Matriu de botons

Un acordió cromàtic té 21 botons per a la mà dreta i 8 botons per a l'esquerra. Per tant 29 botons (i 30 si comptem amb el botó que allibera l'aire). El primer problema que ens plantegem si volem fer un controlador MIDI d'acordeó és com podem controlar tots aquests botons.

Hi ha vàries solucions:

No serveix perquè només es pot utilitzar un botó al mateix temps, i aquest no és el cas d'un acordió MIDI.

Utilitzant els pins analògics en comptes dels digitals podem detectar quants botons tenim pitjats al mateix temps. Pot ser un tema interessant a provar:

Exemple de codi per evitar rebots en els botons:

Veig que per als botons s'utilitzen optoacobladors, amb la qual cosa no és necessari controlar el rebot dels botons.

Button64Shield, ttymidi

Amb el button shield puc recollir la informació de quan apreto les tecles. Per enviar missatges MIDI des de l'Arduino:

Per recollir la informació que s'envia pel port sèrie i convertir-ho a missatges MIDI:

Una altra possibilitat és en comptes d'utilitzar és ttymidi llegir directament el port sèrie i fer un client de JACK. Quan vaig fer el projecte del sensor de temperatura em vaig basar en aquest codi:

Primer de tot instal.lo ttymidi

./ttymidi -s /dev/ttyUSB0 -v -n my_weird_controller

To install the ardumidi library, just copy its folder into Arduino's sketchbook/libraries directory

Però la ardumidi library em dóna problemes d'instal.lació. Provaré la Arduino MIDI Library:

En el fitxer MIDI.h està definit:

#define MIDI_BAUDRATE			31250

i per tant el ttymidi haurà de llegir a aquest baudrate, però

$ ./ttymidi -s /dev/ttyUSB0 -b 31250 -v -n controlador
Baud rate 31250 is not supported.

Canvio el valor a MIDI.h per 115200, i aleshores ja funciona. (ara bé, també podria canviar el ttymidi amb l'opció -b 31250, però no sé perquè no funciona). (per al ttymidi el baudrate de 115200 és el valor per defecte).

$ ./ttymidi -s /dev/ttyUSB0  -v -n controlador
Serial  0x90 Note on            000 042 127
Serial  0x80 Note off           000 042 000
Serial  0x90 Note on            000 042 127

Ara ja puc arrencar el fluidsynth i fer les connexions pertinents (el meu client alsa es diu 'controlador'):

$ /usr/bin/fluidsynth -v -s  -l -j -a alsa -m alsa_seq -l /usr/share/sounds/sf2/Unison.sf2

El codi bàsic que estic fent servir l'he agafat de la carpeta examples/ de la llibreria MIDI:

#include <MIDI.h>
/*
  Basic I/O MIDI tutorial
  by Franky
  28/07/2009
*/

#define LED 13   		// LED pin on Arduino board

void setup() {
  pinMode(LED, OUTPUT);
  MIDI.begin(1);            	// Launch MIDI with default options
}

void loop() {
  //if (MIDI.read()) {
    digitalWrite(LED,HIGH);     // Blink the LED
    MIDI.sendNoteOn(42,127,1);  // Send a Note (pitch 42, velo 127 on channel 1)
    delay(1000);		// Wait for a second
    MIDI.sendNoteOff(42,0,1);   // Stop the note
    digitalWrite(LED,LOW);  
  delay(1000);  	
  //}
}

Ara que ja funciona enviar missatges MIDI, ja puc provar el Button Shield. Primer de tot m'he d'assegurar que els exemples bàsics que vénen amb el Button64Shield funciona. Jo escolleixo el mode SPI, doncs necessito el port sèrie per enviar els missatges MID. El codi mínim per enviar un NoteOn quan apreto una tecla i un NoteOff quan faig un release és: prova_buttonshield.ino

//  This demo is only for the SPI connection mode.

#include <MIDI.h>

// VARIABLE INITS
//*******************************************************************************************************************

volatile uint8_t   Button    = 0;                      // Required for 64 Button Shield (SPI Only)

// Set-Up
//*******************************************************************************************************************
void setup()
{
  
  Serial.begin(115200);                                // Only used to send data to PC for this DEMO
  
  delay(1000);
  attachInterrupt(0, SPI64B, FALLING);                 // Required for 64 Button Shield (SPI Only)
  MIDI.begin(1);            	                       // Launch MIDI with default options
}

// Main Loop
//*******************************************************************************************************************

void loop()
{
  
  if(Button > 0)                              // If Button is > 0, then it was pressed or released (SPI only)
  {
    //Serial.print("Button: ");
    if(Button > 128)                          // Example of how to decode the button press
    {
    Button = Button - 128;                    // A pressd button is the button number + 128
    //Serial.print(Button, DEC);
    MIDI.sendNoteOn(60,127,1);  // Send a Note (pitch 60, velo 127 on channel 1)
    //Serial.print(" - Pressed");
    }else
    {
    //Serial.print(Button, DEC);                // A released button is from 1 to 64
    //Serial.print(" - Released");
    MIDI.sendNoteOff(60,0,1);   // Stop the note
    }
    //Serial.println(" ");
    Button = 0;
  }
  
}

//*******************************************************************************************************************
// Required for 64 Button Shield (SPI Only)			                           Functions & Subroutines
//*******************************************************************************************************************
//
// This void is called if the Interrupt 0 is triggered (digital pin 2).
//

void SPI64B()
{
  Button = 0;
  
  volatile uint8_t  val  = 0;
  volatile uint8_t  clk  = 0;
  
  #define  DataInPin   3
  #define  ClkPin      4

  clk = digitalRead(ClkPin);
  while(clk == LOW)
  {
    clk = digitalRead(ClkPin);
  }

  for(volatile int i =0; i<8;i++)
  {   
    val = digitalRead(DataInPin);
    clk = digitalRead(ClkPin); 
    
    while(clk == HIGH)
    {
      clk = digitalRead(ClkPin);
    }

    if(val == HIGH)
    {
      Button = Button +1;
    }
    
    if(i != 7)
    {
      Button = Button << 1;
    }
    else
    {
      break;
    }

    clk = digitalRead(ClkPin);
    
    while(clk == LOW)
    {
      clk = digitalRead(ClkPin);
    }

  }
}    // End  of SPI64B void
// -------------------------------------------------------------------------------------------------------------


Fixem-nos que he de comentar el Serial.print("Button pressed: ");, doncs no puc enviar aquesta informació pel port sèrie, doncs he d'enviar els missatges MIDI.

Ara el següent pas és no utilitzar ttymidi, sinó fer el meu client JACK que llegeixi el port sèrie (si és que no vull dependre de ttymidi, que potser ja em va bé de dependre de ttymidi per simplicitat).

Pressió de l'aire. Breath sensor

Com es comenta a

es pot utilitzar un sensor de pressió baromètric digital com el BMP085. Però a Sparkfun.com aquest ha estat substituït pel SEN-11282 (20$): https://www.sparkfun.com/products/11282

Per llegir la pressió del sensor amb l'Arduino es pot mirar aquest codi: https://github.com/accordion-mega/AccordionMega/blob/master/bmp085.pde

El BMP085 es trova més barato per EBay i des de València:

Jo crec que per l'acordió MIDI se n'haurien d'utilitzar dos: per detectar una pressió i una depressió. Però potser no... D'altra banda, si utilitza l'entrada I2C només se'n pot utilitzar un... (TBD)

Aquí s'utilitzen dos sensors de pressió:

Breath sensor: Aquesta pot ser una manera molt simple fent servir un microfon de condensador. Podria anar bé.

Breath sensor amb un micròfon condensador (electret)

Sensor bufera.png

micròfon condensador = electret

En aquest últim link són 4 enllaços, on s'explica la configuració bàsica (#1), i després utilitzar un opamp per donar més senyal (similar al breakout que es pot comprar a Sparkfun).

El micròfon condensador que tinc no dóna molt bona resposta. Seria interessant provar amb d'altres micros, i amb d'altres valors de resistència.

Per estudiar la resposta del microfon a les bufades, és interessant bolcar a un fitxer de text les dades sèrie, per poder fer una gràfica. El script python que ho fa:

llegir.py (sudo):

import serial

addr  = '/dev/ttyUSB0'
baud  = 9600
fname = 'accel.dat'
fmode = 'r+w'
reps  = 10000

with serial.Serial(addr,baud) as port, open(fname,fmode) as outf:
    for i in range(reps):
        x = port.read(size=1)
        print x
        outf.write(x)
        outf.flush()

Obtinc el fitxer accel.dat, que netejo al fitxer dades.txt, i aleshores amb el Calc puc fer el diagrama. Per fer el diagrama ben fet he de fer la diferència entre una mostra i l'anterior; el valor absolut; una suavització de per exemple les 5 dades anteriors. Crec que d'aquesta manera és el més correcte. La gràfica que surt és força correcta. La gràfica s'ha obtingut ficant un delay de 10ms (una mostra cada 10ms). De totes maneres s'ha d'evitar ficar delays a dis el codi.

El sketch de l'arduino simple és:

    int fsrAnalogPin = 0;
    int fsrReading; // the analog reading from the FSR resistor divider
    
    void setup(void) {
    Serial.begin(9600); // We'll send debugging information via the Serial monitor
    }
    
    void loop(void) {
    fsrReading = analogRead(fsrAnalogPin);
    //Serial.print("Analog reading = ");
    Serial.println(fsrReading);
    delay(10);
    }

Com veiem, hi ha un delay(10) que fa que esigui malgastant el temps del processador. Però de fet en el projecte final del controlador MIDI hauran de passar moltes coses: llegir la bufera, llegir les tecles, enviar missatges MIDI,... i per tant el sketch s'ha de fer sota la filosofia de programació conduïda per events, que ho documento en una altra banda (Arduino:_programació_dirigida_per_events).

electret més el.laborat

L'anterior configuració és una mica pobra per connectar directament el micro a l'arduino. Aquest breakout que val 8$ ja porta l'amplificació, de manera que es pot connectar fàcilment al ADC de l'arduino. De totes maneres, he de tenir present que jo no vull amplificar audio, sinó bufera, i per tant potser no em cal amplificar el senyal i ja en tinc prou amb la configuració d'una sola resistència que tingui el valor adequat.

He comprat a spikenzielabs.com un Electret Microphone Amplifier-MAX4466 with Adjustable Gain (model SPL-ADA-1063). De fet bé d'Adafruit. Segur que la resposta és millor, tenint en compte que porta incorporada l'amplificació. De totes maneres, he de tenir en compte que jo no vull amplificar el so, sinó senzillament la pressió d'aire, i no m'interessa un electret que agafi tot el soroll extern.

Solenoid

Pot ser interessant per activar la vàlvula d'aire utilitzar un solenoide. He comprat a spikenzielabs.com un solenoide de 5V (model ROB-11015) que s'activa directament amb els pins de l'arduino sense cap més necessitat d'electrònica. La pega és que aquest solenoide és tot o res. Podria utilitzar dos o tres solenoides per tenir diferents aixetes d'aire: deixar entrar/passar més aire o menys.

Sortida MIDI

Aquí ja es va discutir com enviar missatges MIDI amb l'arduino a través d'un connector MIDI:

però una altra possibilitat és alimentar directament els missatges a l'ordinador a través de USB: projecte ttymidi:

Projectes d'Acordió MIDI


creat per Joan Quintana Compte, setembre 2013

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines