Заняття 3. Граємо музику

Спочатку складемо схему для виконання завдання. Нас цілком влаштує попередня схема, за винятком того, що світлодіод ми замінимо динаміком (Рис. 3.1). Завантажуємо скетч з попереднього заняття і можна буде прослухати, як звучить “Україна” азбукою Морзе. Для контролера нема принципової різниці в тому, що саме до нього підключено. Тому на базі нього можна створювати практично необмежену кількість різноманітних корисних пристроїв.

Рис. 3.1: Підключення динаміка до Arduino

Тепер спробуємо зробити так, щоб динамік відтворив найпростішу мелодію. Наприклад, “В траве сидел кузнечик” з відомого мультфільму про незнайку, ноти до цієї мелодії наведені на Рис. 3.2

Рис. 3.2: Ноти до мелодії


Рис. 16: Ноти до мелодії
В цій мелодії використовуються ноти “Ля – A”, “Мі – E”, “Соль – G”, “Соль# – GS”, “Сі – B”, “До – C”. Треба записати їх частоту в вигляді констант скетчу.

#define NOTE_E4 330
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_C5 523

Тепер програємо перші чотири такти з використання функції tone(pin, frequency, duration), де pin — номер цифрового контакту, frequency — частота ноти, duration її довжина в мілісекундах.

Між нотами потрібна пауза довжиною приблизно на 30% – більше довжини самої ноти. Тепер створимо власну функцію, яка буде програвати ноту. Це буде функція з двома параметрами, а саме назва ноти, та її довжина. Також використаємо константу для позначення контакту, на який буде виводитись музика

#define MELODY_PIN 8
void note(int noteName, int duration)
{
int noteDuration = 1000 / duration;
tone(MELODY_PIN, noteName, noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
}

Тут ми бачимо дещо нове, а саме в описанні параметрів використовується зарезервоване слово “int”. Це означає, що параметри являють собою цілі числа. Далі ми познайомимось з іншими видами змінних та параметрів. А поки запам’ятаємо, що int — це цілі числа в діапазоні від -32768 до 32767, під які виділяється 2 байти, або 16 біт в оперативній пам’яті контролера.

Також ми бачимо новий запис всередині функції, який до того ще не використовувався.

int noteDuration = 1000 / duration;

Це має назву оголошення змінної, тобто ми виділяємо ділянку пам’яті з назвою “noteDuration”, в якій будемо зберігати значення типу int, і коли воно нам знадобиться, ми зможемо викликати його по імені змінної, а саме “noteDuration”. Після знаку “=” виконується арифметична дія, а саме 1000 ділиться на параметр “duration”, який був згаданий у заголовку функції. Результат цієї дії буде записаний у ділянку пам’яті noteDuration. Параметр duration може приймати значення 1, 2, 4, 8, 16, 32 відповідно для цілої, половинки, четвертинки, восьмої, шістнадцятої та тридцять другої нот. Такий запис набагато коротший та зручніший ніж задавати довжину кожної ноти у мілісекундах. Як ви вже здогадалися, у змінній noteDuration задається саме довжина звучання ноти у мілісекундах. Зверніть увагу, що результатом ділення цілого числа на ціле є також ціле число, дробова частина відкидається. Для зберігання дробових чисел використовуються змінні інших типів. Крім того, якщо всередині якогось блоку програми (наприклад функції) була оголошена змінна з використанням конструкції: тип_змінної, назва_змінної (як в нашому прикладі “int noteDuration”), при повторному її використанні назву типу цієї змінної не вказується, а вказується просто її назва.

Далі ми розраховуємо затримку між нотами, оголосивши для цього нову змінну pauseBetweenNotes. Зверніть увагу, що при виконанні арифметичної дії у цьому рядку ціле число буде помножено на дробове 1.3, але результат все одно буде приведений до цілого числа, так як при оголошенні змінної ми використали цілий тип int.

 int pauseBetweenNotes = noteDuration * 1.30;

У наступному рядку встановлюється затримка після програної ноти за допомогою вже знайомої нам функції delay();

Тепер ми готові програти перші чотири куплети мелодії. Скетч для цього буде виглядати так:

#define MELODY_PIN 8
#define NOTE_E4  330
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_C5  523

void setup()
{
 note(NOTE_A4, 4);
 note(NOTE_E4, 4); 
 note(NOTE_A4, 4);
 note(NOTE_E4, 4); 
 note(NOTE_A4, 4);
 note(NOTE_GS4, 4);
 note(NOTE_GS4, 2);
 note(NOTE_GS4, 4);  
 note(NOTE_E4, 4); 
 note(NOTE_GS4, 4);
 note(NOTE_E4, 4); 
 note(NOTE_GS4, 4);
 note(NOTE_A4, 4);
 note(NOTE_A4, 2);
 note(NOTE_A4, 4);
 noTone(MELODY_PIN);
}

void loop()
{
}

void note(int noteName, int duration) 
{
    int noteDuration = 1000 / duration;
    tone(MELODY_PIN, noteName, noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
}

В скетчі була використана нова функція noTone(). Вона припиняє виведення звуку на вказаний контакт. Після одного програвання музика припинила грати, так як ми використали стандартну функцію setup(), яка виконується один раз. Якщо є бажання прослухати мелодію ще раз, для цього достатньо перезавантажити контролер кнопкою “RESET”. Зазвичай, на контролері з кнопок є тільки вона єдина.

Тепер можна самостійно спробувати вивести будь-які інші такти мелодії, чи спробувати вивести іншу мелодію. Але для цього нам можуть знадобитись інші ноти, крім тих, що ми вже вказали. Так як їх досить багато, то зручно було би виділити їх у окремий файл. І в мережі інтернет вже можна знайти такий файл в готовому вигляді під назвою “pitches.h”, який можна завантажити і перемістити у теку зі скетчем. Після цього достатньо лише підключити цей файл до скетчу директивою #include “pitches.h”. У файлі вказані частоти всіх нот, які є на клавіатурі фортепіано. Зміст файлу наведено нижче.

 /*************************************************
 * Public Constants
 *************************************************/

#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

Додаткове завдання. Змініть темп програвання нот. Спочатку спробуйте пришвидчити мелодію, а потім сповільнити.