sábado, 14 de septiembre de 2013

PIANO CON PROCESSING Y ARDUINO




INTRODUCCIÓN.

La tecnología electrónica está avanzando a pasos agigantados y el propósito de este desarrollo es ofrecer mayor facilidad a los usuarios, debido a que se busca que personas del común puedan desarrollar proyectos electrónicos muy complejos con la menor dificultad posible, en este orden de ideas se han venido implementando una seria de programas que permiten al usuario crear sus propias interfaces de una forma muy sencilla la cual no requiere de un amplio conocimiento en lenguajes de programación debido a que estas se trabajan en código abierto (open sources)  que es una modalidad que permite compartir códigos entre personas y se da la libertad de modificar esto cuando se requiera. En este proyecto se hace uso de la herramienta PROCESSING que es un programa de código abierto que permite hacer interfaces gráficas de una forma muy sencilla, además de esto este programa permite conexiones con medios externos, ya sea para puerto serial o paralelo, y también se puede comunicar con otras tarjetas tales como los ARDUINOS.


DESCRIPCIÓN GENERAL DEL PROYECTO.

En este proyecto se busca implementar un piano virtual, el cual permita a cualquier persona hacer prácticas reales, debido a que este piano será controlado por actuadores externos, lo que quiere decir que mientras en la computadora se observa el piano el usuario estará presionando teclas reales que serán representadas por una serie de pulsadores.
Para lograr esta combinación de hardware y software se usara la conexión Processing-Arduino, que es una posibilidad que ofrecen estos programas para ejecutar programas desde processing sin necesidad de programar en arduino.


DESCRIPCIÓN DEL CÓDIGO Y LAS LIBRERÍAS.
Librería Maxim:

[1] Maxim está diseñada para hacer más fácil el programa de audio multiplataforma para escritorio amd plataformas móviles. Proporciona una única API para crear aplicaciones de audio complejos en Android, iOS y el escritorio, utilizando el WebAudioAPI en combinación con los enfoques tradicionales de Java para la compatibilidad.

[1]Es un trabajo en progreso, pero enormemente simplifica el proceso de instalación inicial de audio y software de escritura de música para plataformas móviles
Algunas notas:

[1]Si está utilizando el modo de javascript, asegúrese de que su navegador admite WebAudioAPI correctamente.

En este proyecto la librería maxim es la que permite hacer reproducciones de los sonidos  o notas que se han guardado, es esta librería que  por medio de sus funciones internas permite controlar acciones sobre el audio que se quiere reproducir, entre estas acciones se pueden mencionar el reproducir un archivo de audio, detenerlo, repetirlo etc.


Librería Arduino:

Esta librería permite realizar la comunicación entre aurduino y processing, gracias a esta a través de processing se pueden configurar los puertos del arduino que se requieran, en este proyecto se configuran alrededor de 26 puertos del arduino con el fin de poder manipular las dos escalas del piano.

Descripción del código fuente:
Función void setup():

En esta función es donde se realizan algunas configuraciones de los pines de entrada o salida y también se declaran o se asignan valores a las variables que se usaran en el programa.

///////declarando los  pines de entrada del arduino. 

                println(Arduino.list());
                   arduino = new Arduino(this, Arduino.list()[0], 57600);
                   arduino.pinMode (Pin2, Arduino.INPUT);
                   arduino.pinMode (Pin3, Arduino.INPUT);

  Este segmento de código permite declarar lo pines del arduino que se emplearan como entradas, en el caso de este proyecto se declaran alrededor de 26 pines de entrada para el arduino con el fin de cubrir por lo menos dos escalas consecutivas del piano y sus respectivas teclas sotenidas o bemoles. Se puede observar en la segunda línea que el arduino está configurado para una transmisión de 57600 baudios.

////imagen de fondo con las dos escalas
                 img = loadImage("piano.jpg");
                 size(img.width, img.height);

Con estas líneas de código, se le asigna a la variable “img” una imagen, en la cual se muestran las dos escalas del piano que se implementaran, además de eso en la segunda línea se toman las dimensiones de la imagen para que sean los límites de la ventana a mostrar, es decir que la interfaz grafica tendrá el tamaño de la imagen.

/////cargando los archivos .wav  en sus respectivas variables.
                 maxim = new Maxim(this);
                player = maxim.loadFile("DO.wav");///selecionando el archivo .wav de la carpeta data
                 player.setLooping(false);
                player2 = maxim.loadFile("RE.wav");
                player2.setLooping(false);
                player3 = maxim.loadFile("MI.wav");
                player3.setLooping(false);

De esta forma es que se declaran las diversas variables que permitirán guardar los diferentes tonos de las escalas a trabajar, lo formatos del audio son .wav, y observe que para cada variable player, player2, etc. Se le asigna una nota específica para usarla cuando se requiera.


Función void draw()

Esta función es el cuerpo del programa, es decir que el programa siempre estará ejecutándola mientras no ocurra algún evento que produzca una salida de esta como por ejemplo si se usa la función del teclado void keyPressed(), cuando una tecla es presionada se ejecutara de inmediato la función del teclado, pero una vez esta termine su operación, se volverá a ejcutar la función void draw().
Esta función es muy importante debido a que el desarrollo del programa se genera dentro de ella.
Ahora se hará una descripción para el funcionamiento de una tecla externa, por lo cual solo se tomara un segmento de código de la función void draw(), porque para las otras teclas el procedimiento es el mismo.

///función donde se ejecuta el programa

void draw()
{
// code that happens every frame  ///ocurre siempre es decir sin tocar ningun boto del mouse
  image(img, 0, 0); //primera linea

 if (arduino.digitalRead(Pin2)==Arduino.HIGH){
          player.play();   //sentencia que inicia el player
          fill(color(90));
          noStroke();
          rect(3, 5, 28, 232);      ///mostrando rectangulo q indica que se presionó una tecla
          rect(3, 143, 45, 95);  }
          else{
        player.stop();
        player.cue(0);}   
.
.
.
}

La primera línea del segmento que código “image(img, 0, 0);”, se encarga de tomar la imagen de las dos escalas y fijarla como fondo para que en la interfaz grafica se vea siempre la imagen del piano. Luego de mostrar la imagen se procede a preguntar si fue pulsado algún pulsador externo conectado al arduino, en este caso el segmento de código muestra que se pregunta por el pin2 el cual está asociado con la tecla Do, que es la primera tecla de izquierda a derecha, cuando este pulsador es presionado, aparecerá en el pin2 un nivel alto, razón suficiente para cumplir con la condición de la sentencia if (arduino.digitalRead(Pin2)==Arduino.HIGH), lo que producirá que se ejecuten las líneas de códigos encerradas por el “if” para cuando la condición es verdadera, la descripción para este evento (pin2=HIGH) seria: se inicia el tono que corresponde a este pulsador (DO) por medio de la sentencia “player.play();”, con la siguiente línea se escoge un color en este caso el gris, por medio de la sentencia “fill(color(90));”, luego se elimina el borde para cualquier figura que se quiera dibujar (en este caso se dibujaran rectángulos) este procedimiento se realiza, debido a que las teclas tienen formas irregulares pero que por fortuna pueden ser representadas por dos rectángulos, se dibujan dos rectángulos, los cuales deben tener diferentes dimensiones y coordenadas, para dibujar estos se hace uso de las siguientes sentencias “rect(3, 5, 28, 232);” y ” rect(3, 143, 45, 95); ” que permiten dibujar rectángulos de forma muy rápida, en resumen, cuando se presiona el pulsador conectado al pin2 del arduino, el arduino trasmite la información al processig por medio del puerto serial, luego se inicia el sonido del tono DO y además se dibuja una sombra sobre la tecla del piano que se está tocando, este suceso se repite mientras que la tecla siga pulsada hasta que se termine de reproducir por completo el sonido guardado en “player”. Luego para cuando el pulsador es soltado, el condicional será una proposición falsa por lo cual ahora se ejecutaran las líneas encerradas por el “else”, lo que dará lugar a que se detenga el sonido que antes se había iniciado, esto por medio de la sentencia “player.stop();”, la siguiente sentencia “player.cue(0);” permite que se reinicie el audio desde el principio, de no ser así, cuando se presione de nuevo la tecla DO, el sonido se reproducirá desde el mismo momento en que fue cortado, lo que se traduce en que al presionas la misma tecla de forma repetida, cada que se presione el sonido se escuchara menos, en resumen, a soltar el pulsador se cortara la reproducción del sonido y además se reiniciara este, con el fin de que al volver a presionar la tecla, el sonido se escuche desde el principio.

Esta es una descripción para el evento de presionar un pulsador externo y luego soltarlo, en este caso se describió para la nota Do, que está asociada con el pulsador conectado al pin2 del arduino. Esta de más hacer una explicación de todos los pulsadores, debido a que la lógica es la misma, lo único que cambia es el sonido a reproducir, las posiciones de los rectángulos que sombrean la tecla presionada y el pin del arduino que asocian los pulsadores externos con una tecla de la interfaz gráfica.



CONCLUSIONES.
·    
     Se pudo comprobar la facilidad que hay cuando se trabaja con el processing, debido a que se pueden encontrar en la web muchas soluciones que son compartidas por personas que ya han realizado pruebas y desarrollados muchas aplicaciones con este programa.

·         No se requiere ser un gran programador para trabajar con el processing, solo basta un poco de imaginación y usar de forma correcta los ejemplos suministrados por el mismo programa o algún código buscado en la web.
·    
       Al desarrollar la práctica, se presentaron algunos inconvenientes los cuales fueron superados gracias a la ayuda prestada por los compañeros de clases, ya que sus recomendaciones fueros de gran ayuda, uno de los tropiezos de mayor magnitud fue la conexión entre el arduino y el processing. 


webgrafía




ANEXOS 









CÓDIGO FUENTE


//The MIT License (MIT) - See Licence.txt for details
//comunicacion serial arduino processing 
import processing.serial.*;
import cc.arduino.*; 
Arduino arduino;
int Pin2= 2;
int Pin3= 3;
int Pin4= 4;
int Pin5= 5;
int Pin6= 6;
int Pin7= 7;
int Pin8= 8;
int Pin9= 9;
//final configuracion comunicacion serial 
//Copyright (c) 2013 Mick Grierson, Matthew Yee-King, Marco Gillies
int burra;
PImage img;
Maxim maxim;
AudioPlayer player;
AudioPlayer player2;
AudioPlayer player3;
AudioPlayer player4;
AudioPlayer player5;

void setup()
{
  
        println(Arduino.list());
       arduino = new Arduino(this, Arduino.list()[0], 57600);
         arduino.pinMode (Pin2, Arduino.INPUT);
           arduino.pinMode (Pin3, Arduino.INPUT);
              arduino.pinMode (Pin4, Arduino.INPUT);
                 arduino.pinMode (Pin5, Arduino.INPUT);
                  arduino.pinMode (Pin6, Arduino.INPUT);
                  arduino.pinMode (Pin7, Arduino.INPUT);
                  arduino.pinMode (Pin8, Arduino.INPUT);
                  arduino.pinMode (Pin9, Arduino.INPUT);
  
  
  img = loadImage("piano.jpg");
  size(img.width, img.height);
  ///size(640, 960);
  
  ////background(255);
  maxim = new Maxim(this);
  player = maxim.loadFile("DO.wav");///selecionando el archivo .wav de la carpeta data
  player.setLooping(false);
  player2 = maxim.loadFile("RE.wav");
  player2.setLooping(false);
  
  player3 = maxim.loadFile("MI.wav");
  player3.setLooping(false);
  
  player4 = maxim.loadFile("FA.wav");
  player4.setLooping(false);
  
  player5 = maxim.loadFile("SOL.wav");
  player5.setLooping(false);
  
  player.volume(1);


}

void draw()
{
// code that happens every frame  ///ocurre siempre es decir sin tocar ningun boto del mouse
  image(img, 0, 0); 
  
  
  
  
  
 if (arduino.digitalRead(Pin2)==Arduino.HIGH){
          player.play();   //sentencia que inicia el player 
          fill(color(90));
          noStroke();
          rect(3, 5, 28, 232);      ///mostrando rectangulo q indica que se presiono una tecla
          rect(3, 143, 45, 95);  }
          else{
        player.stop();
        player.cue(0);}    
     
 if (arduino.digitalRead(Pin5)==Arduino.HIGH){
          player2.play();   //sentencia que inicia el player 
          fill(color(90));
          noStroke();
          rect(58, 5, 28, 232);
          rect(51, 143, 48, 95);   }  
          else{
        player2.stop();
        player2.cue(0);}        
        
  
  if (arduino.digitalRead(Pin6)==Arduino.HIGH){
          player3.play();   //sentencia que inicia el player 
          fill(color(90));
          noStroke();
         rect(111, 5, 31, 232);
          rect(100, 143, 40, 95);      }  
          else{
        player3.stop();
        player3.cue(0);}   
        
  
 if (arduino.digitalRead(Pin7)==Arduino.HIGH){
          player4.play();   //sentencia que inicia el player 
          fill(color(90));
          noStroke();
          rect(142, 5, 31, 232);
          rect(145, 143, 42, 95);          }  
          else{
        player4.stop();
        player4.cue(0);}   
        
        
        
  if (arduino.digitalRead(Pin8)==Arduino.HIGH){
          player5.play();   //sentencia que inicia el player 
          fill(color(90));
          noStroke();
          rect(192, 5, 31, 232);
          rect(187, 143, 44, 95);          }  
          else{
        player5.stop();
        player5.cue(0);}   
        
    
    

   
      
        
        
}

/*void keyPressed() {
      if (key=='a'){       // pregunta si la tecla presionada es 'a'
          player.play();   //sentencia que inicia el player 
          fill(color(0));
          noStroke();
          rect(3, 5, 28, 232);      ///mostrando rectangulo q indica que se presiono una tecla
          rect(3, 143, 45, 95);         
      }
      
      if (key=='s'){       // pregunta si la tecla presionada es 'b'
          player2.play();  //sentencia que inicia el player2 
          fill(color(0));
          noStroke();
          rect(58, 5, 28, 232);
          rect(51, 143, 48, 95);     
      }
      
      if (key=='d'){        // pregunta si la tecla presionada es 'c'
          player3.play();   //sentencia que inicia el player 
          fill(color(0));
          noStroke();
          rect(111, 5, 31, 232);
          rect(100, 143, 40, 95);           
      }
      if (key=='f'){       // pregunta si la tecla presionada es 'd'
          player4.play();  //sentencia que inicia el player2 
          fill(color(0));
          noStroke();
          rect(142, 5, 31, 232);
          rect(145, 143, 42, 95);         
      }
      if (key=='g'){       // pregunta si la tecla presionada es 'e'
          player5.play();  //sentencia que inicia el player2 
          fill(color(0));
          noStroke();
          rect(192, 5, 31, 232);
          rect(187, 143, 44, 95);  
      }


  
}
void keyReleased(){
      if (key=='a'){
          player.cue(0);   ///sentencia que reinicia el player
          player.stop();   ///sentencia que detiene el player
         fill(color(30));
         noStroke();
         rect(3, 5, 28, 232);     
         rect(3, 143, 45, 95); 

      }
      if (key=='s'){
          player2.cue(0);  ///sentencia que reinicia el player2
          player2.stop();  ///sentencia que detiene el player2   
          fill(color(0));
          noStroke();
          rect(58, 5, 28, 232);
          rect(51, 143, 48, 95);     
      }
      if (key=='d'){
          player3.cue(0);   ///sentencia que reinicia el player
          player3.stop();   ///sentencia que detiene el player      
          fill(color(0));
          noStroke();
          rect(111, 5, 31, 232);
          rect(100, 143, 45, 95);     
      }
      if (key=='f'){
          player4.cue(0);  ///sentencia que reinicia el player2
          player4.stop();  ///sentencia que detiene el player2  
          fill(color(0));
          noStroke();
          rect(142, 5, 31, 232);
          rect(145, 143, 42, 95);          
      }
      if (key=='g'){
          player5.cue(0);  ///sentencia que reinicia el player2
          player5.stop();  ///sentencia que detiene el player2 
          fill(color(0));
          noStroke();
          rect(192, 5, 31, 232);
          rect(187, 143, 44, 95);    
      }    
}*/



 AUTOR: Victor Torres

1 comentario: