PLAY("CDEFGABAGFEDC"), или плеер MML на С

Формат строки — последовательность команд:
- Tn — темп (n=32..255). n=120 (по умолчанию) соответствует длительности целой ноты 2 сек;
- Ln — длительность нот по умолчанию. 1 — целая, 2 — 1/2, ..., 64 — 1/64;
- On — выбор текущей октавы (n=0..8, 0-суб-контр октава, 8 — 5я октава);
- <,> — сдвиг текущей октавы вниз/вверх;
- Vn — громкость (диапазон n зависит от реализации, обычно 1..15);
- C,D,E,F,G,A,B — ноты До… Си, после ноты может указываться ее длительность 1..64 и модификаторы:
- # или + — повышение на полтона (диез, sharp);
- - — понижение на полтона (бемоль, flat);
- . — увеличение длительности на пол-интервала (dot);
- & — слияние соседних нот (tie);
- Rn или Pn — пауза;
Частоты нот рассчитываются относительно Ля 2й октавы (440Гц) по формуле F = 440 * 2 ^ ((n — 49)/12), n=1..88 для клавиш пианино;
Генератор частот 9ти октав (от суб-контр до 5й) на Javascript:
var s = [];
for (var i=-48-9; i<=48+2; i++) {
s.push(Math.floor(4400 * Math.pow(2, i/12) + 0.5) / 10.0);
s.push(",");
if (((i-2) % 12) == 0) s.push("\n");
}
alert( s.join("") );
Проверить можно тут: jsfiddle.net/.
Библиотека написана на С, и позволяет в реальном времени парсить/воспроизводить несколько каналов MML.
.h: codetidy.com/4079/
.c: codetidy.com/4080/
Пример использования и генератор Raw (44100/Signed 16-bit) / Ogg: docs.google.com/open?id=0B4EdBOyGBHKnWkF1YnRQS2hNZkE
Настройка и применение:
#define MML_CHANNELS 1 //количество каналов
#define MML_BUF_SIZE 0 //размер приемного буфера каналов (0 если не используется)
Запуск воспроизведения строки:
setup_mml(); //настройка параметров каналов по умолчанию
mml_play_s(
0, //номер канала
//строка для воспроизведения
"d+16 d16 d8 d+16 d16 d8 d+16 d16 d8 b-4b-16 a16 g8 g16 f16 e-8 e-16 d16 c8 c4d16 c16 c8 d16 c16 c8 d16 c16 c8 a4a16 g16 f+8 f+16 e-16 d8 d16 c16 < b-8 b-4 >b-16 a16 a8 > c8 < f+8 a8 g8 d4b-16 a16 a8 > c8 < f+8 a8 g8 b-8 a16 g16 f16 e-16d2 c+2 d4 c+4 d8 r8 r8",
0, //=0 - не копировать строку во внутренний буфер
MML_FMT_MODERN //формат - современный
);
Для обработки каналов нужно вызывать функцию mml_update(); с частотой 1кГц.
Для воспроизведения звука нужно определить callback-функции задания частоты и громкости на соответствующем канале (пример для опубликованного недавно DDS-генератора):
//задать частоту <strong>freq</strong> (с точностью 0.1Гц) для канала <strong>с</strong>
void mml_set_freq(U8 c, U16 freq) {
audio_gen_set_tone(0, c, AUDIO_GEN_SINE, freq, 1);
}
//задать громкость <strong>vol</strong> для канала <strong>с</strong>
void mml_set_vol(U8 c, U8 vol) {
//смасштабировать в диапазон 0..128
audio_gen_set_volume(0, c, (vol - MML_VOL_MIN)*(AUDIO_GEN_VOLUME_MAX / (MML_VOL_MAX - MML_VOL_MIN)));
}
Пример настройки таймера 3 и вывода PB0 STM32 на выдачу меандра заданной частоты:
TIM_TimeBaseInitTypeDef snd_TIM_TimeBaseStructure;
TIM_OCInitTypeDef snd_TIM_OCInitStructure;
GPIO_InitTypeDef snd_GPIO_InitStructure;
void setup_sound(void) {
// initialize GPIO
GPIO_StructInit(&snd_GPIO_InitStructure);
snd_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
snd_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
snd_GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &snd_GPIO_InitStructure);
//enable TIM3 clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
}
void mml_set_freq(U8 c, U16 freq) {
if (freq == 0) {
TIM_Cmd(TIM3, DISABLE);
snd_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &snd_GPIO_InitStructure);
} else {
snd_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &snd_GPIO_InitStructure);
/* Time Base configuration */
snd_TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
snd_TIM_TimeBaseStructure.TIM_Prescaler = 0;
snd_TIM_TimeBaseStructure.TIM_ClockDivision = 0;
snd_TIM_TimeBaseStructure.TIM_Period = ((F_CPU * 10) / (freq << 1)) - 1;// TimerPeriod;
snd_TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &snd_TIM_TimeBaseStructure);
snd_TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
snd_TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
snd_TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC3Init(TIM3, &snd_TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
}
- +7
- 29 ноября 2012, 02:34
- reptile
- 1
Файлы в топике:
ul_audio_mml.zip
Комментарии (4)
RSS свернуть / развернуть