Eletrônica digital com Arduino – Buzzer, parte 3 – gerando frequências de notas

Já vimos como alterar a frequência das notas tocadas através da função tone() do Arduino, assim como vimos o modo de controlar o tempo de duração da frequência gerada. Agora vamos gerar frequências conforme o tom de cada nota. Primeiro, fazemos um define das frequências, mas antes vou explicar cifras, para quem não toca nenhum instrumento.
As notas musicais são 7: Dó, Ré, Mi, Fá, Sol, La, Si. na cifra, sua representação é:
C,D,E,F,G,A,B. Então, nosso define começa em Si, como se pode notar abaixo.
As notas podem ter meio tom acima ou abaixo. Meio tom acima se chama Sustenido e meio tom abaixo se chama Bemol. Porém Mi e Si não tem sustenido; meio tom acima corresponde à próxima nota (na ordem, Fá e Dó). A representação em cifra seria # para sustenido e b para bemol, mas por motivos de programação, usaremos S para representar sustenido.
Outro detalhe importante; Fá sustenido é o mesmo que Sol bemol, pois é o meio tom entre as duas notas, portanto representaremos meios tons apenas com sustenido.

Por fim, a escala musical pode ter várias vezes a mesma nota, sendo chamada de “oitavas”. Quanto mais baixa a frequência, mais “grosso” é o som, chamado de grave e quanto mais alta a frequência, mais “fino” é som, chamado de agudo. No exemplo temos algumas oitavas, então pode-se escolher o quão grave ou agudo será sua música.

Ainda vale citar que esse código abaixo não é meu, mas o achei bom o suficiente para ser usado como exemplo introdutório. O único problema e que nem todos os tons serão tocados devidamente dependendo da voltagem e modelo do buzzer, mas como temos várias oitavas, basta testar a partir de qual a geração do tom fica melhor para você.

//Notas musicais
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978

As notas também tem tempo. Em partitura, as notas são representadas conforme seu tempo, diretamente em seu desenho sobre as linhas (pauta), e ao início da linha há um símbolo que representa onde começa a primeira nota (Dó), chamado de Clave, mas não vamos entrar em detalhes de partituras, apenas vamos representar os tempos de uma nota, que pode ser 1, 1/2, 1/4, 1/8, 1/16. Como pode-se notar, usaremos float para lidar com as notas, uma vez que 1 tempo é a única nota inteira.

#define WHOLE 1
#define HALF 0.5
#define QUARTER 0.25
#define EIGHTH 0.125
#define SIXTEENTH 0.0625

Devemos criar então o float para o tempo e o int para o tom:

float sinVal;
int toneVal;

Agora vamos entrar em um exemplo que ainda não havia sido citado, mas vem bem a calhar explicá-lo nessa aplicação
Alocando endereço na memória
Quando criamos uma variável (por exemplo) int x, o programa se encarrega de procurar na memória um endereço livre onde possa ser reservado para guardar quaisquer valores atribuidos à variável x. Mas as vezes precisamos de vários endereços de memória porque queremos alocar vários valores. Dependendo do contexto, é melhor usar uma variável que se encarregará de guardar todos os valores desejados, por exemplo, melody, que deverá guardar a melodia de nossa música. O modo de alocar vários endereços com apenas uma variável é simples:
int variavel[] = {1,2,3,4,5};
Desse modo a variável se encarrega de alocar o que está dentro de chaves, chamado de array.
É possível alocar um endereço de tamanho fixo, de maneira tão simples quanto:
int variavel[5];

Desse modo, 5 endereçamentos de memória serão alocados para guardar valores do tipo int.

Atenção: Quando alocamos 5 endereçamentos de memória, para acessá-lo deve-se iniciar na posição 0 e o quinto valor estará na posição 4!

Agora vamos definir nossa melodia e a duração de cada uma das notas:

// notes in the melody:
int melody[] = { NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
int noteDurations[] = {4,8,8,4,4,4,4,4 };

Agora vamos ao setup do Arduino:


void setup(){
for (int thisNote = 0; thisNote < 8; thisNote++) {

// para calcular a duracao da nota, pegue um segundo e divida-o pelo tipo dela.
// 1000 milésimos eh igual a 1 segundo
//ex.: um quarto de nota = 1000 / 4, um oitavo de nota = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(8, melody[thisNote]*4,noteDuration);

// para distinguir as notas, ajuste um tempo minimo entre elas.
// a duracao da nota + 30% funcionara bem:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// para de tocar o tom:
noTone(8);
}
}

Esse loop fará a música ser tocada uma vez e depois disso nada mais acontecerá, pois não há nenhum código no loop, ou seja, a música não se repetirá:

void loop(){

}

Farei um video dessa música tocando. Infelizmente na época em que o experimentei não gravei video, mas fico devendo e atualizo nesse post.

[ATUALIZADO]
Eis o video:

Para o próximo post pretendo controlar LED RGB com potenciômetros. Será uma tarefa bem interessante, mas depois disso pretendo controlar o LED RGB com 3 sensores de temperatura e a cor variará conforme as variações de temperatura em cada um dos sensores. Essa é uma boa maneira de gerar cores randômicas sem um algorítmo de geração de números randômicos.
Boa diversão e até o próximo post!

Comments

comments

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.

Um comentário em “Eletrônica digital com Arduino – Buzzer, parte 3 – gerando frequências de notas

Deixe uma resposta