Sintetizador "Embarcado"



O objetivo dessa experiência foi desenvolver algumas técnicas de sintese sonora possíveis de serem executadas com o limite do microprocessador que estamos lidando no momento, o ATMEL de 8 bits (ATMEGA168 e ATMEGA8).


Foram testados a partir de alguns códigos encontrados na base de tutoriais do arduino manipulações de pequenos autofalantes, utilizando a saída "PWM" dos arduinos. As saídas PWM , basicamente falando,são saídas de pulso - essas entradas conseguem gerar um controle em microsegundos de pulso dos valores máximo e mínimo de volagens e com isso manipular algumas técnicas de controle de modulação de freqüencias. A partir disso o que viemos a buscar é um controle sobre modulações do tempo e intensidade desses pulsos podendo gerar formas e padrões interessantes de ondas sonoras. Lembre-se que estas ondas representam esta pressão e descompressão que a voltagem causa nos auto-falantes.




(Para saber um pouco mais sobre PWM veja este link).

Alguns Exemplos utilizando Arduino



Oscilador Simples com Potenciomêtro





      
int speakerOut = 9;      // autofalante
int analogPin = 0;   // entrada de potenciometro
int val = 0;         // valor atual do potencometro

void setup()
{
  pinMode(speakerOut, OUTPUT);   // sets the pin as output
}

void loop()
{
  val = (analogRead(analogPin)*8);   // read the input pin
 
      digitalWrite(speakerOut, HIGH);
      delayMicroseconds(val);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(val);   
}



Uma pequena modificação foi feita para tentar criar uma textura no periodo da onda. A mudança é sutil mas da alguma noção de manipulação de timbre







      
int speakerOut = 9;      // autofalante
int analogPin = 0;   // entrada de potenciometro
int val = 0;         // valor atual do potencometro

void setup()
{
  pinMode(speakerOut, OUTPUT);   // sets the pin as output
}

void loop()
{
  val = (analogRead(analogPin)*8);   // read the input pin
 
      digitalWrite(speakerOut, HIGH);
      delayMicroseconds(val);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(val);
       digitalWrite(speakerOut, HIGH);
      delayMicroseconds(val*0.5);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(val*0.5);
      digitalWrite(speakerOut, HIGH);
      delayMicroseconds(val*0.25);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(val*0.25);
        delayMicroseconds(val*0.125);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(val*0.125);
   
}



Esta próxima tentativa utiliza a possibilidade de escrita analógica na porta PWM, varrendo uma escala linear de valores durante o ciclo do loop da função. Com isso cria-se uma espécie de envelope "triangular" na onda que começa a gerar novas idéias.

          
int speakerOut = 9;      // saida do autofalante
int analogPin = 0;   // potenciometro
int val = 0;         // valor a ser atualizado pelo potenciometro

void setup()
{
  pinMode(speakerOut, OUTPUT);   // setando o pino como saida
}

void loop()
{
  int i=0;
 
for (int i=0; i <= 255; i++){
      analogWrite(speakerOut, i);
      delayMicroseconds(analogRead(analogPin));

// experimente tambem a volta retirando os comentarios
//for (int i=255; i >= 0; i--){
//      analogWrite(speakerOut, i);
//      delayMicroseconds(analogRead(analogPin));




   } 












Código de melodia


O primeiro código utilizado foi para uso direto do saída PWM ligado no auto-falante. Você liga o cabo de entrada "positiva" do auto-falante na saída 9 e o negativo do auto-falante na saída terra (gnd) do arduino.

O código utilizado para melodia foi o seguinte:



/* Play Melody
 * -----------
 *
 * Programa para tocar uma melodia simples escrita em vetores
 *
 *  Tons são manipulados por um funcao que escreve em microssegundos valores HIGH(>5v) e LOW(<5v)
 *   usando o recurso PWM, para determinar as frequencias
 *
 *  Cada nota tem uma fequencia criada pela variação do periodo de vibração
 *  vibration, measured in microseconds. We'll use pulse-width
 *  modulation (PWM) to create that vibration.

 * We calculate the pulse-width to be half the period; we pulse 
 *  the speaker HIGH for 'pulse-width' microseconds, then LOW 
 *  for 'pulse-width' microseconds.
 *  This pulsing creates a vibration of the desired frequency.
 *
 * (cleft) 2005 D. Cuartielles for K3
 * Refactoring and comments 2006 clay.shirky@nyu.edu
 * See NOTES in comments at end for possible improvements
 */

// TONES  ==========================================
// Comeca definindo a relacao entre 
//       nota, periodo, &  frequencia. 
#define  c     3830    // 261 Hz 
#define  d     3400    // 294 Hz 
#define  e     3038    // 329 Hz 
#define  f     2864    // 349 Hz 
#define  g     2550    // 392 Hz 
#define  a     2272    // 440 Hz 
#define  DD     12400    // calcular
#define  b     2028    // 493 Hz 
#define  C     1912    // 523 Hz 
// Define uma nota especial, 'R', para representar a pausa
#define  R     0

// SETUP ============================================
// Seta a saida do pino PWM (digital 9, 10 or 11)
int speakerOut = 9;
// Se quiser fazer um debug via serial? 1 para sim, 0 para nao
int DEBUG = 1;

void setup() { 
  pinMode(speakerOut, OUTPUT);
  if (DEBUG) { 
    Serial.begin(9600); // Seta saida serial se quisermos debugar pelo computador
  } 
}

// MELODY and TIMING  =======================================
//  melody[] eh um vetor de notas, relativo a um vetor de beats[], 
//  que seta o valor de cada nota na mesma posicao (maor numero, maior nota) 
int melody[] = {  C,  b,  g, R,  C,  f, DD,  e,  b, R,  d,  g, a, C };
int beats[]  = { 16, 16, 16, 64,  8,  8, 32, 16, 16, 64, 16, 16, 8, 8 }; 
int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.

// seta o tempo geral
long tempo = 12000;
// Seta a pausa entre as notas
int pause = 250;
// Variacao do lop pra acrescentar valor na pausa
int rest_count = 100; //<-GAMBIARRA - veja as notas no fim do codigo

// Inicializando variaveis
int tone = 0;
int beat = 0;
long duration  = 0;

// PLAY TONE  ==============================================
// Pulsa o falante para tocar um tom particular
void playTone() {
  long elapsed_time = 0;
  if (tone > 0) { // if this isn't a Rest beat, while the tone has 
    //  played less long than 'duration', pulse speaker HIGH and LOW
    while (elapsed_time < duration) {

      digitalWrite(speakerOut,HIGH);
      delayMicroseconds(tone / 2);

      // DOWN
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(tone / 2);

      // Keep track of how long we pulsed
      elapsed_time += (tone);
    } 
  }
  else { // Rest beat; loop times delay
    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
      delayMicroseconds(duration);  
    }                                
  }                                 
}

// LET THE WILD RUMPUS BEGIN =============================
void loop() {
  // Set up a counter to pull from melody[] and beats[]
  for (int i=0; i<MAX_COUNT; i++) {
    tone = melody[i];
    beat = beats[i];

    duration = beat * tempo; // Set up timing

    playTone(); 
    // A pause between notes...
    delayMicroseconds(pause);

    if (DEBUG) { // If debugging, report loop, tone, beat, and duration
      Serial.print(i);
      Serial.print(":");
      Serial.print(beat);
      Serial.print(" ");    
      Serial.print(tone);
      Serial.print(" ");
      Serial.println(duration);
    }
  }
}

/*
 * NOTES
 *  Este programa propoe um tom a partir de um pulso de 'duracao' em microsegundos.
 *  Gambiarra! Na verdade ele segura esta duracao em microsegundos _mais_
 *  alguma sobrecarga do tempo de execucao (o que pode chegar a 
 *  3000 microsegundos) _mais_ uma sobrecarga do loop e das duas funcoes digitalWrite()
 *  
 *  Como resulatado o tom de 'duracao' toca muito mais lento que o resto da 
 *  tal 'duracao.' rest_count creates a loop variable to bring 'rest' beats 
 *  in line with 'tone' beats of the same length. 
 * 
 * rest_count will be affected by chip architecture and speed, as well as 
 *  overhead from any program mods. Past behavior is no guarantee of future 
 *  performance. Your mileage may vary. Light fuse and get away.
 *  
 */




















Última alteração: 26/12/2008 às 21:27, por: vitoriamario