Piano Toca Discos

PIANO TOCADISCOS – Grupo 26

Integrantes:

  • Antonio Alcojor Patilla
  • Iván Motos Montalbán

Descripción del proyecto:

En este proyecto hemos hecho que dos disqueteras reproduzcan música, ya sea a través de un piano pintado a lápiz en un papel o bien mediante archivos MIDI que reciben las disqueteras con la ayuda de un programa Java externo.

Al final tenemos un Arduino que, si se encuentra conectado únicamente a la red eléctrica, es capaz de reproducir música en las disqueteras a través de las pulsaciones que recibe por el piano de papel, Mientras que, si se conecta también por USB, es capaz de recibir archivos MIDI parseados por un programa Java y transferirlos a las disqueteras para reproducir dicha música.

Componentes:

  • 1 Arduino Nano
  • 2 disqueteras
  • 1 módulo MB102 de alimentación, necesario para suministrar constantemente 5V a las disqueteras, cosa que el Arduino enchufado por USB no es capaz de hacer. Este módulo alimenta también a Arduino
  • 1 folio
  • Resistencias
  • Cables
  • Clips
  • 1 lápiz

Fases del proyecto:

Para desarrollar el proyecto de una forma incremental y poder organizar correctamente el trabajo, decidimos dividir el trabajo en 4 fases, las cuales detallamos a continuación con los problemas encontrados en ellas.

Fase 1

En esta fase nos centramos en conseguir que Arduino detectase las pulsaciones ejercidas sobre las diferentes teclas del piano de papel, basándonos en la capacitancia del cuerpo humano. El trabajo en esta fase fue sencillo, si bien hubo que controlar la sensibilidad, ya que Arduino detectaba las pulsaciones sobre una tecla en un extremo del folio si pulsabas en el otro extremo.



Fase 2

En esta fase nos centramos en conseguir que las disqueteras consiguieran emitir notas musicales atendiendo a las pulsaciones que recibían desde el teclado del ordenador.


Para ello, nos basamos en que una disquetera de 3.5 pulgadas posee 80 pistas, haciendo ruido al pasar de una a otra. Si hacemos que pase de unas pistas a otras consecutivamente y ajustamos la frecuencia, la disquetera emite sonidos que se asemejan a las notas musicales.


El principal problema encontrado en esta fase fue el del voltaje. Arduino es capaz de alimentar a pequeños componentes como LEDs, resistencias, potenciómetros… pero no era capaz de suministrar constantemente los 5V que necesitaban las resistencias. Por ello, decidimos usar el módulo MB102, el cual se encargaría de alimentar a todos los componentes (Arduino incluido) para su correcto funcionamiento.





Fase 3

En esta fase nos centramos en juntar lo conseguido en la fase 1 con lo logrado en la fase 2, es decir, que Arduino detectase qué tecla estamos pulsando y, en función de ello, le pase la información a las disqueteras sobre qué sonido deben emitir. Las pruebas en la fase 2 fueron con una única disquetera, por lo que en esta fase tuvimos que encargarnos de sincronizar ambas disqueteras y que emitieran el mismo sonido con la misma entrada.


El problema en esta fase fue el estado de la disquetera que añadimos, la cual estaba defectuosa, no se escuchaba del todo bien (el volumen era muy bajo) y se quedaba a veces como atascada.



Fase 4

La última fase fue bastante más complicada, y se basaba en, con Arduino conectado por USB y a la red a través del módulo de alimentación, lograr que las disqueteras reprodujesen una canción sacada de un archivo MIDI. Para ello, contamos con la ayuda de un programa Java base que tuvimos que retocar, llamado MoppyDesk, que leía los archivos MIDI y los parseaba pasando la información a las disqueteras, mientras nosotros podemos controlar la velocidad a la que transfiere esos datos.


Intentamos realizar también una alternancia automática entre los dos modos del piano. Para ello tomamos un tiempo de referencia, en nuestro caso 5 segundos. Si en esos 5 segundos Arduino no recibe nada por el Serial, entonces es que no está reproduciendo ningún archivo MIDI, por lo tanto debe reaccionar a las pulsaciones del teclado.

Esta fase fue más compleja debido al retoque de código que tuvimos que hacer en un programa que no había sido programado por nosotros, además de que hay ciertas notas que, por su escala o por ir demasiado juntas, no las detecta el programa y no consigue transferirlas correctamente a la disquetera.


Por último, se da la circunstancia de que normalmente los archivos MIDI tienen varias pistas con varios instrumentos que, juntos, reproducen la canción. Como nosotros disponemos únicamente de dos disqueteras que, en paralelo, emiten el mismo sonido, debíamos usar otro programa externo para transformar los MIDI en canciones de un solo canal



Código

#include <TimerOne.h>



const int  stepPins [] = {3, 5}; // 20 on floppy
const int  directionPins [] = {2, 4}; // 18 on floppy
const int MAX_FLOPPYS = 2;
const boolean goBackwards = LOW;
const boolean goForwards = HIGH;
const int PERIOD_TIME = 40;
int currentPosition1 = 0;
boolean dir1;
int ticks1 = 0;
const int maxValue = 80;
const int minValue = 0;
int delayedTime = 5;
int currentNote1 = 0;
int currentStandBy = 0;
int const MAX_STANDBY = 20;
int notes [] = {
  9091, 8099, //A2 B2
  7645, 6811, 6068, 5727, 5102 , 4545, 4050, //C3 D3 E3 F3 G3 A4 B4 /* Las buenas */
  3822, 3405, 3034, 2863, 2551 //C4 D4 E4 F4 G4
};
const int notesLength = 14;
const int START_KEYBOARD_PIN = 6;
const int END_KEYBOARD_PIN = 15;
const int CUT_OFF_ITERATIONS = 20;
const int KEY_NUMBER = (END_KEYBOARD_PIN + 1) – START_KEYBOARD_PIN;
//One for each pin of the arduino
int keyResistances [KEY_NUMBER];
boolean isPcConnected = false;
const int MAX_TIME_WITHOUT_SERIAL = 2000; //5s esperando el serial, si no viene nada vuelve al modo teclado
unsigned long timeWithoutSerial;
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < MAX_FLOPPYS; i++) {
    pinMode(stepPins[i], OUTPUT);
    pinMode(directionPins[i], OUTPUT);
  }
  keyboardReset();
  reset();
  calculateNotes();
  Timer1.initialize(PERIOD_TIME);
  Timer1.attachInterrupt(tick);
  timeWithoutSerial = millis();
  delay(500);
}
void loop() {
  if (!isPcConnected) {
    if (!Serial.available()) {
      int key = getPressedKeys();
      if (key != 0) {
        currentStandBy = 0;
      }
      selectNote(key);
    } else {
      isPcConnected = true;
      timeWithoutSerial = millis();
    }
    delay(5);
  } else {
    if (!readFromPc()) {
      if (millis() – timeWithoutSerial > MAX_TIME_WITHOUT_SERIAL) {
        isPcConnected = false;
      }
    } else {
      timeWithoutSerial = millis();
      isPcConnected = true;
    }
    delay(50);
  }
  
}
boolean readFromPc() {
  if (Serial.available()) {
    int result = Serial.read() << 8 | Serial.read();
    currentNote1 = result;
    return true;
  } else {
    return false;
  }
}
int getPressedKeys () {
  bool any = false;
  for (int i = 0; i < KEY_NUMBER; i++) {
    if (i == 7) continue; //pin 13
    if (isKeyTouched(START_KEYBOARD_PIN + i)) {
      return START_KEYBOARD_PIN + i;
    }
  }
  return 0;
}
boolean isKeyTouched(int pin) {
  return isKeyTouched(pin, false);
}
boolean isKeyTouched (int pin, boolean isSetUp) {
  int s = 0;
  for (int i = 0; i < CUT_OFF_ITERATIONS; i++) {
    s += digitalRead(pin) == HIGH ? 0 : 1;
    if (!isSetUp && keyResistances[pin – START_KEYBOARD_PIN] < s) {
      return true;
    }
  }
  if (isSetUp) {
    keyResistances[pin – START_KEYBOARD_PIN] = 0.4 * CUT_OFF_ITERATIONS;
  }
  return false;
}
void selectNote(int key) {
  int lastNote = currentNote1;
  switch (key) {
    case START_KEYBOARD_PIN :
      currentNote1 = notes[2];
      break;
    case START_KEYBOARD_PIN +1  :
      currentNote1 = notes[3];
      break;
    case START_KEYBOARD_PIN + 2 :
      currentNote1 = notes[4];
      break;
    case START_KEYBOARD_PIN + 3:
      currentNote1 = notes[5];
      break;
    case START_KEYBOARD_PIN + 4 :
      currentNote1 = notes[6];
      break;
    case START_KEYBOARD_PIN + 5 :
      currentNote1 = notes[7];
      break;
    case START_KEYBOARD_PIN + 6:
      currentNote1 = notes[8];
      break;
    //Se salta el 13
    case START_KEYBOARD_PIN + 8 :
      currentNote1 = notes[9];
      break;
    case START_KEYBOARD_PIN + 9 :
      currentNote1 = notes[10];
      break;
    case START_KEYBOARD_PIN + 10 :
      currentNote1 = notes[11];
      break;
    case START_KEYBOARD_PIN + 11 :
      currentNote1 = notes[12];
      break;
    default:
      currentStandBy++;
      if (currentStandBy > MAX_STANDBY) {
        currentNote1 = 0;
      }
      break;
  }
}
void tick() {
  if (currentNote1 > 0) {
    ticks1++;
    if (ticks1 >= currentNote1) {
      if ((currentPosition1 > maxValue)) {
        dir1 = !dir1;
        currentPosition1 = minValue;
      }
      for (int i = 0; i < MAX_FLOPPYS; i++) {
        moveFloppy(stepPins[i], directionPins[i], dir1);
      }
      currentPosition1++;
      ticks1 = 0;
    }
  }
}
void calculateNotes () {
  for (int i = 0; i < notesLength; i++) {
    notes[i] /= PERIOD_TIME;
  }
}
void moveFloppy(int stepPin, int directionPin, boolean directionMotor) {
  digitalWrite(directionPin, directionMotor);
  digitalWrite(stepPin, HIGH);
  digitalWrite(stepPin, LOW);
}
void reset() {
  for (int j = 0; j <= MAX_FLOPPYS; j++) {
    for (int i = 0; i < maxValue*2; i++) {
      moveFloppy(stepPins[j], directionPins[j], goBackwards);
    }
  }
  currentPosition1 = 0;
  dir1 = goForwards;
}
void keyboardReset() {
  for (int i = 0; i < KEY_NUMBER; i++) {
    if (i == 7) continue; //El pin 13
    isKeyTouched(START_KEYBOARD_PIN + i, true);
    pinMode(START_KEYBOARD_PIN + i, INPUT);
  }
}

Mejoras

Posibles mejoras a este proyecto pueden ser:
  • Modularizar mejor el programa para poder añadir de forma aún más fácil más disqueteras y más notas. Para ello, sobre todo con las notas, es muy posible requerir de más de un Arduino por falta de salidas
  • Hacer que haya disqueteras que reproduzcan sonidos de otros canales de los archivos MIDI, para hacer que suene mejor la música.
  • Conseguir que el programa Java transfiera las notas correctamente a las disqueteras.

Resultado final

Vídeos demostrativos



Conclusión

Este proyecto con Arduino nos ha hecho familiarizarnos con la construcción de un sistema pensado para solucionar un problema concreto mediante el entorno de Arduino. Ha sido una experiencia bastante divertida y entretenida, y hemos visto como con Arduino y un poco de maña se pueden realizar cosas bastante trabajadas y originales.


También te podría gustar...

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *