Geração de acorde

Faz o que o AlxDroidDev falou: ligue mais de um alto-falante no Arduino e gere, em cada um deles, um tom. Se as caixas estiverem dispostas de forma adequada, acontecerá a interferência dos tons gerados em cada um deles e daí você vai ter, no final, o acorde que quer.

Acordes no violão, pelo que sei, precisam de dois, três ou quatro notas musicais simultâneas. Para cada nota você precisará de um alto-falante.

Olá, a ideia é justamente essa, gerar uma nota em cada auto-falante simultaneamente, e juntas, estas formariam um acorde, mas pelo que pesquisei o Arduíno UNO só consegue gerar uma frequência por vez e não em todos os auto-falantes juntos.

O trecho do código que postei é justamente do exemplo citado pelo AlxDroidDev, e no final do exemplo tem a observação que só é possível gerar uma nota por vez e não notas simultâneas.

É possível formar acordes a partir de 2 notas, exemplo: Dó, Sol (Dó maior) ou com mais Dó, Ré#, Sol (Dó menor)e por ai vai. As regras de formação de acorde são simples.

Uma outra coisa que notei é que se você usa uma porta PWM e um auto-falante, pode gerar interferência inibindo a produção de som em alguns casos, em um teste usando led RGB, controle remoto e um piezo, fiquei extremamente frustrado.

Então não use o tone(), faça o seu próprio código gerar três tons simultâneos:

unsigned long firstC = 0;
unsigned long E = 0;
unsigned long secondC = 0;

int firstCState = HIGH;
int EState = HIGH;
int secondCState = HIGH;

void generateTones() {
    if (millis() - firstC > 15) {
        firstC = millis();
        firstCState = firstCState == HIGH? LOW : HIGH;
        digitalWrite(7, firstCState);
    }

    if (millis() - E > 12) {
        E = millis();
        EState = EState == HIGH? LOW ? HIGH;
        digitalWrite(8, EState);

    if (millis() - secondC > 7) {
        secondC = millis();
        secondCState = secondCState == HIGH? LOW : HIGH;
        digitalWrite(9, secondCState);
    }
}

void setup {
    pinMode(7, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(9, OUTPUT);
}

void loop {
    generateTones();
}

Opa eu também já testei, não funciona. Deve ser mesmo uma limitação de hardware pois no próprio exemplo do multitone diz que não é possível tocar mais de uma nota ao mesmo tempo.
Depois de ver o depoimento do AlxDroidDev, acredito que seja possível fazer apenas no MEGA2560 pois ele deve ter uma capacidade de processamento maior para conseguir gerar mais de um tom ao mesmo tempo.

Se não funciona no ATmega328, porque achas que um processador igual a correr à mesma frequência vai fazer melhor? Importas-te de explicar?

Em princípio deves saber de música, mas que é que sabes de coisas como Séries de Fourier? Como tu disseste são duas notas ao mesmo tempo... logo são duas frequências distintas... se vires a série de fourier talvez percebas o que se passa com um acorde e como gerá-lo. Aviso já que não é simples.

Eu precisaria entender como o Arduino usa as postas PWM para fazer os cálculos e gerar as frequências para te dar esta resposta, em teoria eu acredito que a outra placa deva ter um controle melhor dos recursos por ter mais portas PWM. Tirei esta conclusão por observação ao ver que funciona no Mega.

Irei dar uma estudada na Séries de Fourier, valew ...

Lá está... e se reparares, consegues gerar vários sinais PWM com as portas do ATmega328... suficientes, diria eu para gerar um acorde. Logo, apesar de conseguires mais "tons" no mega2560, o mega328 também serve para provar o que pretendes.

Experimenta ver como funcionam os timers e saídas de PWM e vais chegar lá. :slight_smile:

bubulindo

"The tone() command works by taking over one of the Atmega's internal timers, setting it to the frequency you want, and using the timer to pulse an output pin. Since it's only using one timer, you can only play one note at a time."

Pesquisei sobre a Séries de Fourier, vi que ela é usada apenas para definir o intervalo harmônico de acordes, ela foi utilizada para classificar as notas.

O que preciso no caso, como o Arduino não toca mais de uma nota ao mesmo tempo é saber se há alguma forma de calcular a frequência de um determinado acorde, exemplo:

Dó = 263.63 Hz
Mi = 329.63 Hz
Sol = 391.99 Hz

Queria saber se é possível algo do tipo

Dó maior = (Dó+Mi+Sol)/3

Só que no caso da 329 Hz, um mi desafinado

Vou ver o que acho, se achar uma solução posto por ai.

bubulindo:
Em princípio deves saber de música, mas que é que sabes de coisas como Séries de Fourier? Como tu disseste são duas notas ao mesmo tempo... logo são duas frequências distintas... se vires a série de fourier talvez percebas o que se passa com um acorde e como gerá-lo. Aviso já que não é simples.

Rapaz, depois de passar o resto do dia estudando eu consegui entender que a Serie de Fourier não só foi o que definiu a classificação dos acordes como também tem a resposta para criar o encapsulamento de frequências.
Fiz um teste usando o Audacity, ele tem um gerador de tom, gerei duas notas e combinei as frequências ai pude compreender o que acontece com a onda.
Em teoria pode ser reproduzido através de algum algorítimo tenebroso pelo que notei, vamos ver se eu consigo desenvolver, afinal tenho que ter uma distração ...

Se tiver novidades eu posto aqui ...

spiderpoison:
Rapaz, depois de passar o resto do dia estudando eu consegui entender que a Serie de Fourier não só foi o que definiu a classificação dos acordes como também tem a resposta para criar o encapsulamento de frequências.
Fiz um teste usando o Audacity, ele tem um gerador de tom, gerei duas notas e combinei as frequências ai pude compreender o que acontece com a onda.
Em teoria pode ser reproduzido através de algum algorítimo tenebroso pelo que notei, vamos ver se eu consigo desenvolver, afinal tenho que ter uma distração ...

Se tiver novidades eu posto aqui ...

Eu não disse que era simples. Gerar essas frequências com PWM é difícil, logo o melhor é começares a estudar timers e gerares tu o pwm. Já agora, dá uma vista de olhos sobre como não usar a digitalWrite() já que isso vai atrasar e muito o algoritmo.

Abraço e mete aqui o resultado.

bubulindo - Então em teoria eu consegui entender como proceder e para gerar os acordes, fiz algumas interações em um fórum de música onde participo também e peguei alguns detalhes técnicos, se quiser dar uma lida: Frequência de um acorde - Cifra Club .
Estou desenvolvendo o algorítimo, vou ver se faço ele de forma visual para conferir os resultados usando alguma linguagem que permita eu desenhar gráficos e depois tento portar a função para o arduino desenvolvendo a função para gerar meu pulso.
Legal a dica do "como não usar o digitalWrite()", talvez eu esteja fazendo alguns erros em outros projetos por causa desse detalhe.

abraços ...

Já que estás numa de aprender coisas úteis... tens aqui como fazer o set, reset e toggle de bits em C.

http://nepsweb.co.uk/docs/bitTwiddle.pdf

Eu tenho umas macros algures nuns ficheiros de código... quando as descobrir posto aqui.

O segredo para a tua aplicação é perceber como fazer o timer disparar uma interrupção e alterar o estado do pino o mais rápido possível. Para isso tens de estudar como funcionam os timers e como fazer as contas para acertar a temporização. :slight_smile:

Você pode tentar dessa forma, como descrito pelo cara do seu post de fórum Cifrasclub, se quiser um acorde resultante da interferência de três senóides puras (uma senóide para cada nota do acorde, por exemplo):

#include <math.h>

#define PWMPERIOD 1.0/490.0
#define OMEGAC 2.0 * 3.14159 * 263.63
#define OMEGAE 2.0 * 3.14159 * 329.63
#define OMEGAG 2.0 * 3.14159 * 391.99

unsigned long time = 0;

void setup() {}

void loop() {
    double amplitude = 255.0 / 3.0 * (
        sin(OMEGAC * PWMPERIOD * time) +
        sin(OMEGAE * PWMPERIOD * time) +
        sin(OMEGAG * PWMPERIOD * time));

    analogWrite(3, (int)amplitude); // ligar o alto-falante no pino 3

    time++;
}

neuron_upheava - Legal, acredito que seja por ai mesmo, preciso apenas de tempo para fazer os testes práticos, mas em teoria seria isso.

bubulindo - com certeza irei estudar ...

valeu pessoal

neuron_upheava

Aproveitei um tempo livre e dei uma olhada na sua fórmula, acredito que seja quase isso mas a amplitude deve ser calculada mais ou menos assim:

double amplitude = OMEGAC + OMEGAE * sin(2* time) + OMEGAG * sin(3* time) ;

Fiz o teste simulando valores no link abaixo:
http://ocw.mit.edu/ans7870/18/18.06/javademo/FourierSeries/

A periódica com essa fórmula que passou não retorna um agrupamento das frequências como visualizei em um editor de WAV gerando os tons e juntando as faixas, já usando esta fórmula ele desenha a periódica idêntica a somatória feita no editor WAV.

Neste link que eu passei da para simular os resultados.

Pessoal acho que cheguei a uma solução, ainda preciso acertar algumas coisas no projeto acertar a duração das notas, mas basicamente eu consegui misturar as frequências da seguinte forma.

void toca(int n1, int n2, int n3){
for (int i=0;i<100;i++){
digitalWrite(3,HIGH);
delayMicroseconds(n1);
digitalWrite(3,LOW);
delayMicroseconds(n1);
digitalWrite(3,HIGH);
delayMicroseconds(n2);
digitalWrite(3,LOW);
delayMicroseconds(n2);
digitalWrite(3,HIGH);
delayMicroseconds(n3);
digitalWrite(3,LOW);
delayMicroseconds(n3);
}
}

void setup(){
pinMode(3,OUTPUT);
}

void loop(){
toca(1915,1519,1275);
delay(100);
toca(1915,1607,1275);
delay(1000);
}

o 'n', a duracao do pulso pode ser calculado usando essa referência:
http://arduino.cc/playground/Portugues/LearningMelody

Teoricamente o programa gera um acorde 'Dó Maior' e um 'Dó Menor'

spiderpoison:
neuron_upheava
A periódica com essa fórmula que passou não retorna um agrupamento das frequências como visualizei em um editor de WAV gerando os tons e juntando as faixas, já usando esta fórmula ele desenha a periódica idêntica a somatória feita no editor WAV.

Você usou as frequências 263,63 Hz, 329,63 Hz e 391,99 Hz? Usou senóides em cada frequência e somou? Por que pegou o OMEGA de cada frequência e usou como amplitude? Sim, porque se multiplicar um valor à senóide, esse valor é a amplitude dela.

Para sua informação, uma senóide de amplitude A e frequência f é descrita matematicamente por A sen (2 pi f t)

E a interferência de várias senóides é dada pela soma algébrica delas

Esquece séries de Fourier por enquanto e volta para o começo da parte 2 do volume 2 do Tipler ou o capítulo 17 do Halliday, por favor

Por enquanto o mais próximo que cheguei:

#define C 1897
#define Ds 1607
#define E 1517
#define G 1276

void toca(int f1, int f2, int f3, int duracao){
duracao=duracao/10;
int i=0;
while (i<duracao){
digitalWrite(3,HIGH);
delayMicroseconds(f1/2);
digitalWrite(3,LOW);
delayMicroseconds(f1/2);
digitalWrite(3,HIGH);
delayMicroseconds(((f2+f1)/2)^2);
digitalWrite(3,LOW);
delayMicroseconds(((f2+f1)/2)^2);
digitalWrite(3,HIGH);
delayMicroseconds(((f3+f2)/2)^3);
digitalWrite(3,LOW);
delayMicroseconds(((f3+f2)/2)^3);
i++;
}
}

void setup(){
pinMode(3,OUTPUT);
Serial.begin(9600);
}

void loop(){
toca(C,E,G,1000);
toca(C,Ds,G,1000);
}

resultados:

Dó maior - http://flxsys.com.br/do_maior_arduino.mp3
Dó maior e dó menor - http://flxsys.com.br/arduino_teste.mp3
440Hz -referência - http://flxsys.com.br/la_arduino.mp3

esperado:
http://flxsys.com.br/do_maior_gerador.mp3

bubulindo:
Eu tenho umas macros algures nuns ficheiros de código... quando as descobrir posto aqui.

Hoje tive tempo para brincar com o ATmega16... e descobri as tais macros.

#define SetB(PORT, BIT)	((PORT) |= 1<< (BIT))
#define ClrB(PORT, BIT)	((PORT) &= 1<< (BIT))
#define TogB(PORT, BIT)	((PORT) ^= 1<< (BIT))

Isto usa-se assim

SetB(PORTA, 0); //coloca o bit 0 do porto A a 1

ClrB(PORTB, 3); //coloca o bit 3 do porto B a 0

Hum, legal, vamos ver se entendi ... você define que as as portas irão usar um determinado timmer?
Mas ainda estou perdido ... sobre como usar