Музыка на Arduino 2 Picaxe коллекция

Музыка на Arduino 2
Picaxe коллекция

Как написать действительно простую программу

В Сети большинство программ исполнения мелодий для Arduino основано на одном достаточно неудачном примере, как например в книге Джереми Блума "Изучаем Arduino. Инструменты и методы технического волщебства", глава 5. blum_ch5.zip В этой программе задаются два массива типа int. Массив notes[] содержит частоты нот в герцах, а массив times[] - длительности нот в миллисекундах. Причём частоы нот определяются с помощью #define из файла pitches.h, что вроде бы должно облегчить написание программы (программист пишет названия нот, а не частоты). Длина мелодии задаётся переменной i - программист должен (в уме) посчитать число нот. Для коротких мелодий такая программа выглядит неплохо. Но что получится, если кто-то захочет написать более длинную мелодию ?

Ясно, что каждая нота при таком подходе занимает 4 байта. Допустим, в мелодии 200 нот, значит она займёт 800 байт. Легко уменьшить массив times[] - достаточно написать вместо int - char и разделить значения массива на 125 (длительность самой короткой ноты). Сложнее с массивом нот - но здесь можно с помощью #define заменить частоты нот на их порядковые номера. Таким образом в этом примере ноты кодируются числами 0 - 14 (0 - пауза и 2 октавы нот без диезов), а длительности - числами 1 - 4. Кроме того, используя ключевое слово PROGMEM можно добиться, чтобы массивы не переписывались в RAM.

"He's A Pirate" / "Pirates of the Caribbean"

ROM RAM
оригинальная 3322 байт 844 байт
оптимимзированная 1612 байт 9 байт

Загрузить melody_pirate.zip

Таким образом, лишь слегка отредактировав исходный текст, я уменьшил результирующий код программы более чем в два раза. Но можно уменьшить код мелодий ещё сильнее, выделив для ноты не 2, а только 1 байт. Пример таких мелодий я нашел на сайте www.picaxe.com

Два последних архива на этой странице содержат коды, написанные на PICAXE BASIC, но эти коды могут быть легко переведены на любой язык. Один байт кода соответствует одной ноте в формате:

БитыПеременная
3-0note - нота (0-11) или пауза (12)
5-4ioctave - октава (0-2)
7-6ilen - длительность (1/8,1/4,1/2,1)

Такое кодирование имеет недостатки. Отсутствуют 1/16 ноты и ноты с точкой, кроме того такой код тяжело использовать при ручном наборе нот по сравнению с форматом PLAY Quick Basic. Для кодирования в формате PICAXE (из рингтонов Nokia RTTTL) требуется специальная программа-wizard. Но зато для такого формата - "одна нота - один байт" очень легко написать декодер:

#include "notes.h"
//Octave frequancy table for 12 notes (including with # notes)
const PROGMEM unsigned int freqtab[]={200,211,224,238,252,267,283,300,318,337,358,379};
//Length of 1/8 note in milliseconds
//Possible values: from 125 (fast) to 250 (slow)
#define SPEED 125
//Place your beeper pin number here
const int buzzer = 8;

const unsigned char coct[]={1,2,0,1}; //note octaves
const unsigned char clen[]={2,1,8,4}; //note durations: 1/4, 1/8, 1, 1/2
unsigned int freq,durat;

//This function plays note. See zip file for source
void toneWithDelay (uint8_t _pin, unsigned int frequency, unsigned long duration)
{
...
}

void decod(unsigned char d)
{unsigned char note,ioctave,ilen;
 note=d & 15;ioctave=(d >> 4) & 3;ilen=(d >> 6) & 3;
 durat=SPEED*(unsigned int)(clen[ilen]);
 if (note != 12) freq=pgm_read_word(freqtab+note)  << coct[ioctave];else freq=0;
}

void play(const unsigned char *melody)
{unsigned char d;unsigned int i;
 for (i=0;d=pgm_read_byte(melody+i), d != 255;i++) {decod(d);toneWithDelay(buzzer,freq,durat);} 
}

void setup()
{
 pinMode(buzzer,OUTPUT);play(notes);
}

void loop()
{}

Для того чтобы не путаться с большим количеством мелких файлов, я упаковал данные мелодий в программы ringtv.exe и ringxmas.exe, написанные на Visual Basic 6. Просто выбираете мелодию и нажимаете кнопку - музыкальный код записывается в файл notes.h Исходный текст этих программ на Visual Basic 6 также содержится в архиве.

Исправлено 5 августа 2019 RTTTL конвертер с примерами рингтонов добавлен в архив.

Загрузить скетч Музыка PICAXE для Arduino и мелодии