樂(lè)譜轉(zhuǎn)化為播放程序的基本方法
我們先來(lái)回顧一下七音依次播放的教程,通過(guò)設(shè)置頻率和持續(xù)時(shí)長(zhǎng)來(lái)控制蜂鳴器的播放。
//定義音階常量
#define Do 262
#define Re 294
#define Mi 330
#define Fa 349
#define Sol 392
#define La 440
#define Si 494
int buzzerPin=8; //定義蜂鳴器針腳
int scale[]={Do,Re,Mi,Fa,Sol,La,Si}; //定義音階數(shù)組
void setup() {
pinMode(buzzerPin,OUTPUT);// 設(shè)置數(shù)字引腳為輸出
}
void loop() {
for(int i=0;i<7;i++){// 使用for循環(huán)依次播放音階數(shù)組中的元素
tone(buzzerPin,scale[i],1000);//依次讀取音階數(shù)組中的音階頻率,并且每個(gè)音階持續(xù)1秒鐘
delay(1000); //等待1000毫秒
noTone(buzzerPin); //停止發(fā)聲
delay(1000); //等待1000毫秒
}
}
既然我們知道了控制音階播放的原理,那我們是不是可以嘗試用這種原理去進(jìn)行作曲呢火架?
//定義音階常量
#define Do 262
#define Re 294
#define Mi 330
#define Fa 349
#define Sol 392
#define La 440
#define Si 494
int buzzerPin=4; //定義蜂鳴器針腳
int scale[]={Do,Re,Mi,Do,Do,Re,Mi,Do,Mi,Fa,Sol,Mi,Fa,Sol}; //定義音階數(shù)組
void setup() {
pinMode(buzzerPin,OUTPUT);// 設(shè)置數(shù)字引腳為輸出
}
void loop() {
for(int i=0;i<14;i++){// 使用for循環(huán)依次播放音階數(shù)組中的元素
tone(buzzerPin,scale[1],1000);//依次讀取音階數(shù)組中的音階頻率,并且每個(gè)音階持續(xù)1秒鐘
delay(500); //等待1000毫秒
tone(buzzerPin,scale[2],1000);
delay(500);
tone(buzzerPin,scale[3],1000);
delay(500);
tone(buzzerPin,scale[4],1000);
delay(500);
tone(buzzerPin,scale[5],1000);
delay(500);
tone(buzzerPin,scale[6],1000);
delay(500);
tone(buzzerPin,scale[7],1000);
delay(500);
tone(buzzerPin,scale[8],1000);
delay(500);
tone(buzzerPin,scale[9],1000);
delay(500);
tone(buzzerPin,scale[10],1000);
delay(500);
tone(buzzerPin,scale[11],1000);
delay(500);
tone(buzzerPin,scale[12],1000);
delay(500);
tone(buzzerPin,scale[13],1000);
delay(500);
tone(buzzerPin,scale[14],1000);
delay(500);
}
}
通過(guò)控制引腳發(fā)出的頻率和持續(xù)長(zhǎng)度來(lái)轉(zhuǎn)換成音調(diào)和節(jié)拍,逐個(gè)音拼湊成一段樂(lè)曲忙菠,僅僅兩句樂(lè)曲就占了如此大的篇幅何鸡,這就暴露出了幾個(gè)問(wèn)題:
優(yōu)點(diǎn):簡(jiǎn)單易懂
缺點(diǎn):1.音符間節(jié)奏難控制
2.程序冗長(zhǎng)編寫(xiě)費(fèi)力
那我們有什么好的方法來(lái)解決呢?
以下代碼可以完美的解決這個(gè)問(wèn)題:
int speakerPin = 9; //蜂鳴器引腳定義
int length = 15; //曲目長(zhǎng)度
char notes[] = "ccggaagffeeddc "; //曲目音階牛欢,最后空格表示結(jié)束
int beats[] ={1,1,1,1,1,1,2,1,1,1,1,1,1,2,4 }; //節(jié)拍
int tempo = 300; //節(jié)奏
void playTone(int tone ,int duration)
{
for (long i= 0;i<duration*1000L;i+=tone*2)
{
digitalWrite(speakerPin,HIGH);
delayMicroseconds(tone);
digitalWrite(speakerPin,LOW);
delayMicroseconds(tone);
}
}
void playNote(char note,int duration)
{
char names[] ={'c','d','e','f','g','a','b','C'};
int tones[]={1915,1700,1519,1432,1275,1136,1010,956};
//利用對(duì)比位的方式來(lái)播放某一個(gè)音階
for(int i = 0;i<8;i++)
{
//將對(duì)比得到的音階高電位時(shí)間長(zhǎng)度傳送給playTone函數(shù)播放
if(names[i]==note)
playTone(tones[i],duration);
}
}
void setup()
{
pinMode(speakerPin,OUTPUT); //引腳設(shè)定為輸出
}
void loop()
{for (int i =0;i<length;i++)
{
if(notes[i] == ' ')
delay (beats[i]*tempo); //rest
else
playNote(notes[i],beats[i]*tempo);
//pause between notes
delay (tempo/2);
}
}
這段代碼的精彩之處就在于可以直觀快捷的控制曲目的節(jié)拍和節(jié)奏骡男,并且可以直接對(duì)音調(diào)發(fā)出的順序進(jìn)行編排。中間通過(guò)自定義了兩個(gè)函數(shù)playTone()和playNote()對(duì)音調(diào)和節(jié)拍進(jìn)行了定義傍睹,使得后期播放效果非常完美隔盛。
1.關(guān)于按鈕
按鈕分為四腳和兩腳按鈕兩種犹菱,兩腳按鈕可以當(dāng)開(kāi)關(guān)使用,而四腳按鈕則是對(duì)腳相斷骚亿,鄰腳相通已亥。在制作蜂鳴器電子琴時(shí)我們將其作為琴鍵。
2.蜂鳴器電子琴的制作
通過(guò)圖示我們可以看到来屠,其實(shí)蜂鳴器電子琴就是通過(guò)七個(gè)按鈕控制七個(gè)引腳的電平變化虑椎,使蜂鳴器發(fā)聲,產(chǎn)生七音俱笛。
#include "pitches.h"
void setup(){
//初始化按鈕連接引腳
pinMode(2,INPUT);
pinMode(3,INPUT);
pinMode(4,INPUT);
pinMode(5,INPUT);
pinMode(6,INPUT);
pinMode(7,INPUT);
pinMode(8,INPUT);
}
void loop (){
//依次讀出各個(gè)按鈕的狀態(tài)
//如果按鈕按下捆姜,則發(fā)出相應(yīng)的音調(diào)
if(digitalRead(2)) tone(10,NOTE_C5,10); //DO 523Hz
if(digitalRead(3)) tone(10,NOTE_D5,10);
if(digitalRead(4)) tone(10,NOTE_E5,10);
if(digitalRead(5)) tone(10,NOTE_F5,10);
if(digitalRead(6)) tone(10,NOTE_G5,10);
if(digitalRead(7)) tone(10,NOTE_A5,10);
if(digitalRead(8)) tone(10,NOTE_B5,10);
}
通過(guò)代碼我們就可以很直觀的了解電子琴的工作原理了,本代碼引用了pitches.h迎膜。
大家可以嘗試制作一下~