terça-feira, 10 de junho de 2014

Código-fonte

Código-fonte: functions.h

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

TMRpcm player;

/*
 * AVISO: Código duplicado à vista!
 */

void playNote(MUX mux)
{
  int z_val = mux.readZ() >= 1015;
  int mux_y = mux.getY();
  
  static int active_mux = 0;
  static int active_y = -1;
  
  if (z_val && !player.isPlaying())
  {
    active_y = mux_y;
    active_mux = mux.id();
    
    if (active_mux == 1)
    {
      switch (mux_y)
      {
        case 0:
          player.play("CF3/CF3_C4.wav");
          break;
        case 1:
          player.play("CF3/CF3_Cs4.wav");
          break;
        case 2:
          player.play("CF3/CF3_D4.wav");
          break;
        case 3:
          player.play("CF3/CF3_Ds4.wav");
          break;
        case 4:
          player.play("CF3/CF3_E4.wav");
          break;
        case 5:
          player.play("CF3/CF3_F4.wav");
          break;
        case 6:
          player.play("CF3/CF3_Fs4.wav");
          break;
        case 7:
          player.play("CF3/CF3_G4.wav");
          break;
      }
    }
    else if (active_mux == 2)
    {
      switch (mux_y)
      {
        case 0:
          player.play("CF3/CF3_Gs4.wav");
          break;
        case 1:
          player.play("CF3/CF3_A4.wav");
          break;
        case 2:
          player.play("CF3/CF3_As4.wav");
          break;
        case 3:
          player.play("CF3/CF3_B4.wav");
          break;
        case 4:
          player.play("CF3/CF3_C5.wav");
          break;
        case 5:
          player.play("CF3/CF3_Cs5.wav");
          break;
        case 6:
          player.play("CF3/CF3_D5.wav");
          break;
        case 7:
          player.play("CF3/CF3_Ds5.wav");
          break;
      }
    }
    else if (active_mux == 3)
    {
      switch (mux_y)
      {
        case 0:
          player.play("CF3/CF3_E5.wav");
          break;
        case 1:
          player.play("CF3/CF3_F5.wav");
          break;
        case 2:
          player.play("CF3/CF3_Fs5.wav");
          break;
        case 3:
          player.play("CF3/CF3_G5.wav");
          break;
        case 4:
          player.play("CF3/CF3_Gs5.wav");
          break;
        case 5:
          player.play("CF3/CF3_A5.wav");
          break;
        case 6:
          player.play("CF3/CF3_As5.wav");
          break;
        case 7:
          player.play("CF3/CF3_B5.wav");
          break;
      }
    }
  }
  else if (z_val == 0 && mux_y == active_y && active_mux == mux.id())
  {
    player.stopPlayback();
    active_y = -1;
    active_mux = 0;
  }
}

void toneNote(MUX mux)
{
  int z_val = mux.readZ() >= 1015;
  int mux_y = mux.getY();
  
  static int active_mux = 0;
  static int active_y = -1;
  
  if (z_val)
  {
    active_y = mux_y;
    active_mux = mux.id();
    
    if (active_mux == 1)
    {
      switch (mux_y)
      {
        case 0:
          tone(46, NOTE_C4);
          break;
        case 1:
          tone(46, NOTE_CS4);
          break;
        case 2:
          tone(46, NOTE_D4);
          break;
        case 3:
          tone(46, NOTE_DS4);
          break;
        case 4:
          tone(46, NOTE_E4);
          break;
        case 5:
          tone(46, NOTE_F4);
          break;
        case 6:
          tone(46, NOTE_FS4);
          break;
        case 7:
          tone(46, NOTE_G4);
          break;
      }
    }
    else if (active_mux == 2)
    {
      switch (mux_y)
      {
        case 0:
          tone(46, NOTE_GS4);
          break;
        case 1:
          tone(46, NOTE_A4);
          break;
        case 2:
          tone(46, NOTE_AS4);
          break;
        case 3:
          tone(46, NOTE_B4);
          break;
        case 4:
          tone(46, NOTE_C5);
          break;
        case 5:
          tone(46, NOTE_CS5);
          break;
        case 6:
          tone(46, NOTE_D5);
          break;
        case 7:
          tone(46, NOTE_DS5);
          break;
      }
    }
    else if (active_mux == 3)
    {
      switch (mux_y)
      {
        case 0:
          tone(46, NOTE_E5);
          break;
        case 1:
          tone(46, NOTE_F5);
          break;
        case 2:
          tone(46, NOTE_FS5);
          break;
        case 3:
          tone(46, NOTE_G5);
          break;
        case 4:
          tone(46, NOTE_GS5);
          break;
        case 5:
          tone(46, NOTE_A5);
          break;
        case 6:
          tone(46, NOTE_AS5);
          break;
        case 7:
          tone(46, NOTE_B5);
          break;
      }
    }
  }
  else if (z_val == 0 && mux_y == active_y && active_mux == mux.id())
  {
    noTone(46);
    active_y = -1;
    active_mux = 0;
  }
}

void checkEaster(MUX mux1, MUX mux2)
{
  int z1, z2, y1, y2;
  y1 = mux1.getY();
  z1 = mux1.readZ() >= 1015;
  
  y2 = mux2.getY();
  z2 = mux2.readZ() >= 1015;
  
  if (z1 && z2 && y1 ==0 && y2 == 0)
  {
    noTone(46);
    if (player.isPlaying()) player.stopPlayback();
    digitalWrite(13, !digitalRead(13));
    delay(1000);
  }
}


#endif

Código-fonte: mux.h

#ifndef MUX_H
#define MUX_H

#include <Arduino.h>

class MUX
{
private:
  unsigned A0, A1, A2;
  unsigned Z;
  unsigned Y;
  void initPins();
  static unsigned toBin(const unsigned);
  static unsigned id_counter;
  unsigned _id;
public:  
  MUX(unsigned, unsigned, unsigned, unsigned);
  unsigned readZ();
  unsigned getY();
  void shiftPorts();
  unsigned id();
};

unsigned MUX::id_counter = 0;

MUX::MUX(unsigned A0, unsigned A1, unsigned A2, unsigned Z)
{
  this->A0 = A0;
  this->A1 = A1;
  this->A2 = A2;
  this->Z  = Z;
  Y = 0;
  _id = ++id_counter;
  initPins();
}

unsigned MUX::id()
{
  return _id;
}

void MUX::initPins()
{
  pinMode(this->A0, OUTPUT);
  pinMode(this->A1, OUTPUT);
  pinMode(this->A2, OUTPUT);
  pinMode(this->Z, INPUT);
}

unsigned MUX::toBin(const unsigned number)
{
  int a = number, m = 1, res = 0;
  while (a > 0)
  {
    res += a % 2 * m;
    a /= 2;
    m *= 10;
  }
  return res;
}

unsigned MUX::readZ()
{
  return analogRead(Z);
}

unsigned MUX::getY()
{
  return Y;
}

void MUX::shiftPorts()
{
  Y = (Y + 1) % 8;
  int bin = toBin(Y);
  
  digitalWrite(this->A0, bin % 10);
  digitalWrite(this->A1, bin / 10 % 10);
  digitalWrite(this->A2, bin / 100);
}

#endif

Código-fonte: Piano.ino

#include "notes.h"
#include "mux.h"
#include <SD.h>
#include <SPI.h>
#include <TMRpcm.h>
#include "functions.h"

#define speaker 46
#define SDPin 53

MUX mux1(9, 10, 11, A0);
MUX mux2(22, 24, 26, A1);
MUX mux3(28, 30, 32, A2);

void setup()
{
  Serial.begin(9600);
  pinMode(SDPin, OUTPUT);
  pinMode(speaker, OUTPUT);
  pinMode(13, OUTPUT);
  
  if (!SD.begin(SDPin))
  {
    while (true)
    {
      digitalWrite(13, !digitalRead(13));
      delay(1000);
    }
  }

  digitalWrite(13, HIGH);
  player.speakerPin = speaker;
  player.setVolume(4);
  player.quality(1);
}

void loop()
{
  checkEaster(mux1, mux2);
  
  mux1.shiftPorts();
  if (digitalRead(13))
    playNote(mux1);
  else
    toneNote(mux1);
  
  mux2.shiftPorts();
  if (digitalRead(13))
    playNote(mux2);
  else
    toneNote(mux2);
  
  mux3.shiftPorts();
  if (digitalRead(13))
    playNote(mux3);
  else
    toneNote(mux3);
    
  delayMicroseconds(100);
}

domingo, 8 de junho de 2014

Samples


O que são samples?

Samples ("amostras", em inglês) são trechos de sons gravados de um instrumento para serem usados noutro equipamento ou programa.
Samples geralmente são gravadas de acordo com um padrão para atingir maior realismo na replicação de um efeito e/ou instrumento a ser implementado.

Ok, mas o que isso tem a ver com o projeto?

Estamos desenvolvendo um piano usando o Arduino, certo? Nada mais justo do que usar uma biblioteca de samples para reproduzir sons mais realistas do que aqueles encontrados em teclados mais baratos.

Nós preparamos uma biblioteca especial para o projeto, gravada de um piano de cauda para concertos, um Yamaha CF III.

Como vamos usar essas samples?

Para este projeto, estaremos utilizando uma biblioteca chamada TMRpcm.h, ela torna possível a reprodução de sons. Essas samples no entanto tem que atender alguns requisitos:

- Formato PCM sem compressão, com extensão .wav;
- Taxa de amostragem de 32000 Hz;
- Deve possuir apenas uma faixa (mono).

O Arduino não possui alto falantes, como eu vou ouvir o som?

Vamos usar um Audio Jack, que é um conector P2 fêmea, possibilitando o uso de qualquer caixa de som.

_________________________________________________________________

Mais informações sobre a biblioteca usada pode ser encontrada aqui: https://github.com/TMRh20/TMRpcm/wiki

As samples podem ser encontradas aqui:
https://www.dropbox.com/sh/x97ye327u215fsb/AABNn2TjAxmn1HcY8v_IPLEVa

Multiplexadores




Multiplexador ou MUX é um circuito que codifica múltiplas entradas numa única saída. Multiplexadores são usados quando se necessita um maior número de entradas do que há disponível ou quando o custo para a implementação de mais entradas é maior do que o custo necessário para a utilização de multiplexação.


Neste projeto nós usamos o MUX modelo 4051, que é um multiplexador 8-para-1, confira abaixo o esquema de pinagem do CI:






Os pinos "Y0" a "Y7" representam as entradas; "A0", "A1" e "A2" são pinos correspondentes as chaves de seleção; "E" é o pino que determina se está ativo; "Vss" é o pino que deve ser ligado ao Terra; "Vdd" e "Vee" são pinos que recebem tensões positivas e negativas, respectivamente.


Para o uso como MUX no Arduino, tanto 'E', 'Vee' e 'Vss' devem ser conectados ao Terra(GND). O motivo é simples: para multiplexação nós queremos que o MUX esteja sempre ativo, logo não há necessidade de atribuir uma porta para o pino 'E', podemos deixá-lo no GND. Como possuímos uma fonte de energia não-balanceada no Arduino, o pino 'Vee' fica inutilizado. Por último, o 'Vss' corresponde ao próprio Terra.


As chaves de seleção funcionam de acordo com um modelo binário, mostrado na tabela a seguir: