src.caxapa.ru куда-то делось. Вкладываю как есть. ВНИМАНИЕ! ГОВНОКОД! ГОВНОКОД! ГОВНОКОД! В тексте программы используются запятые и многое др. Разбирает формат монофических мелодий от мобильников. На выходе частота и длительность. Умеет играть мурку -- последнее самое ценное. Говнокод объявляется public domain.
#include <stdint.h>
/* TODO сделать external, конверсия частоты тона в такты таймера, обязательно макросом */
#define DEFNOTE(freq) ((2*freq*256L*256L+FSAMPLE/2) / FSAMPLE)
#define MELODY_MAX_VOL 15
extern uint_fast8_t melody_vol; /* громкость 0..15 в заголовке мелодии */
/* получить длительность и частоту (в тактах таймера) следующей ноты,
* в конце проигрывания возвращается 0 */
uint_fast8_t melody_next(clock_t *duration, unsigned *xfreq);
/* разбор текста мелодии (вызвать вначале) */
void melody_new(const char *melody);
/* vim: set foldmethod=marker foldmarker={{{,}}} */
/* $Id$ */
/* \file парсер мелодий в соответствующем формате... */
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#ifdef __AVR_GCC__
static size_t strspn(const char *s, const char *accept)
{
size_t n = 0;
while (*s!=0 && strchr(accept, *s)!=NULL) n++, s++;
return n;
}
#include <avr/pgmspace.h> // XXX
#else /* not AVR */
#define PROGMEM
#endif
#ifndef TEST
#include "melody.h"
#else
#define DEFNOTE(v) v
#define MELODY_MAX_VOL 15
#endif
/*
freq :== 'A' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B' | '-' | 'P'
duration :== 1 | 2 | 4 | 8 | 16 | 32
octave :== 0-3 | 4-7 | -1..-2 (non standard)
mod :== '#', '.' (1.5), ';' (2), '&' (2.5)
note :== [duration] [mod] note [mod] [octave]
name :== [^:]*
info :== [a-z]=[0-9]+...
where d=default duration (4), o=default octave (6),
b=tempo (63 per min. as default), v=volume (0..15),
s=style (1 -- normal, 2 -- continous, 3 -- staccatto).
melody :== name ':' info ':' note [ ' ' note]...
*/
/*! частоты нот... */
static const PROGMEM unsigned notes[] = {
DEFNOTE(262), DEFNOTE(277), /* C, C# */
DEFNOTE(294), DEFNOTE(311), /* D, D# */
DEFNOTE(330), /* E */
DEFNOTE(349), DEFNOTE(370), /* F, F# */
DEFNOTE(392), DEFNOTE(415), /* G, G# */
DEFNOTE(440), DEFNOTE(466), /* A, A# */
DEFNOTE(494) /* B */
};
static const char *delim = " ,\t\n\v\r"; /*! разделители в мелодии */
static const char *numbers = "0123456789";
/* настройки специфичные для динамика, мин. и макс октавы */
#define MIN_OCTAVE -1
#define MAX_OCTAVE 4
/* устанавливается в melody_new() */
static int_fast8_t def_octave; /* октава по-умолчанию */
static uint_fast8_t def_duration; /* длительность в 1/N ноты по-умолчанию */
static clock_t tempo; /* длительность одной полной ноты */
enum e_style { normal=1, continous=2, staccatto=3 };
static enum e_style style; /* стиль звучания */
uint_fast8_t melody_vol; /* громкость 0..15 в заголовке мелодии */
static const char *mel_start; /* начало мелодии (после второго ':') */
static const char *mel_idx; /* текущая проигрываемая нота */
/*! разбор следующей ноты мелодии (после вызова melody_new()),
* возвращает 0 в конце мелодии, иначе устанавливает длительность (clock_t)
* и частоту `xfreq` (тактов таймера) или 0 для паузы */
uint_fast8_t melody_next(clock_t *duration, unsigned *xfreq)
{
unsigned d; /* длительность, муз. тактов */
uint_fast8_t sharp; /* наличие диеза */
uint_fast8_t mult; /* длительность ноты = mult/2 */
int_fast8_t note; /* номер ноты, -1 -- пауза */
int octave; /* октава MIN_OCTAVE..MAX_OCTAVE */
clock_t notetm; /* время звучания новой ноты */
/* установка аргументов по-умолчанию */
d=def_duration;
sharp=0;
mult=2;
octave=def_octave;
note=-1;
mel_idx+=strspn(mel_idx, delim); /* пропуск пробелов перед нотой */
if (mel_idx[0] == '$') { /* '$' -- признак незацикливания/конца мелодии */
/* конец */
return 0;
}
if (mel_idx[0] == 0)
mel_idx=mel_start; /* зацикливание */
/* разбор длительности */
if (sscanf(mel_idx, "%u", &d)==1) {
mel_idx+=strspn(mel_idx, "+-");
mel_idx+=strspn(mel_idx, numbers);
}
/* разбор модификаторов */
#define parse_mod() do { \
if (mel_idx[0] == '#') { sharp=1; mel_idx++; continue; } \
else if (mel_idx[0] == '.') { mult=3; mel_idx++; continue; } \
else if (mel_idx[0] == ';') { mult=4; mel_idx++; continue; } \
else if (mel_idx[0] == '&') { mult=5; mel_idx++; continue; } \
} while(0);
parse_mod();
/* разбор ноты */
do {
const char *notes="CCDDEFFGGAAB-P";
const char *p=strchr(notes, toupper(mel_idx[0]));
if (p==NULL) break; /* ошибка разбора ноты -- пауза XXX */
note=p-notes; if (note >= 12) note=-1;
mel_idx++;
} while(0);
/* разбор модификаторов повторно */
parse_mod();
#undef parse_mod
/* разбор октавы */
if (sscanf(mel_idx, "%d", &octave)==1) {
mel_idx+=strspn(mel_idx, "+-");
mel_idx+=strspn(mel_idx, numbers);
}
/* проверка правильности параметров, исправление */
if (d==0 || strchr("\001\002\004\010\020\040", d)==NULL) d=def_duration;
if (octave<MIN_OCTAVE || octave>MAX_OCTAVE) octave=def_octave;
/* вычисление времени звучания новой ноты */
notetm=tempo*mult/(d*2);
switch (style) {
case continous: break;
case staccatto:
notetm-=notetm/4; break;
default: /* normal */
notetm-=notetm/8;
}
*duration=notetm;
/* установка частоты звучания, если не пауза */
if (note>=0) {
unsigned t; /* период ноты, тактов таймера */
if (note==4 || note==11) sharp=0; /* игнорировние # */
#ifdef __AVR_GCC__
t=pgm_read_word(¬es[note+sharp]); /* XXX AVR specific! */
#else
t=notes[note+sharp];
#endif
octave=-octave; // FIXME!!!
// printf("o=%d\n", octave);
if (octave>0) t=t>>octave;
else if (octave<0) t=t<<octave;
*xfreq=t;
return 1;
}
else {
/* пауза */
*xfreq=0;
return 1;
}
}
/*! разбор заголовка мелодии задаваемой строкой-аргументом */
void melody_new(const char *melody)
{
/* разбор параметров мелодии */
const char *s; // TODO?
unsigned v, d, t;
int o;
/* параметры мелодии по-умолчанию */
def_octave=1, def_duration=4, tempo=(60*CLOCKS_PER_SEC)/63,
melody_vol=MELODY_MAX_VOL/2, style=normal;
/* пропуск имени мелодии и разбор параметров */
if (s=strchr(melody, ':'), s==NULL) mel_start=melody;
else if (mel_start=strchr(++s, ':'), mel_start==NULL) mel_start=s;
else {
do { /* разбор до след. ':' */
s+=strspn(s, delim); /* пропуск пробелов */
if (s[0]=='o' || s[0]=='O') { /* octave: 0..7 */
//int o;
s++, s+=strspn(s, delim);
if (s[0] == '=' && sscanf(++s, "%d", &o) == 1) {
s+=strspn(s, delim);
s+=strspn(s, "+-"); s+=strspn(s, numbers);
if (o<=MAX_OCTAVE && o>=MIN_OCTAVE) { def_octave=o; }
}}
else if (s[0]=='v' || s[0]=='V') { /* volume: 0..15 */
//unsigned v;
s++, s+=strspn(s, delim);
if (s[0] == '=' && sscanf(++s, "%u", &v) == 1) {
s+=strspn(s, delim);
s+=strspn(s, "+-"); s+=strspn(s, numbers);
if (v <= MELODY_MAX_VOL) { melody_vol = v; }
}}
else if (s[0]=='d' || s[0]=='D') {
//unsigned d;
s++, s+=strspn(s, delim);
if (s[0] == '=' && sscanf(++s, "%u", &d) == 1) {
s+=strspn(s, delim);
s+=strspn(s, "+-"); s+=strspn(s, numbers);
if (d!=0 && strchr("\001\002\004\010\020\040", d)!=NULL) {
def_duration=d;
}
}}
else if (s[0]=='b' || s[0]=='B') {
//unsigned t;
s++, s+=strspn(s, delim);
if (s[0] == '=' && sscanf(++s, "%u", &t) == 1) {
s+=strspn(s, delim);
s+=strspn(s, "+-"); s+=strspn(s, numbers);
if (t>=30 && t<=255) { tempo=60*CLOCKS_PER_SEC/t; }
}}
else if (s[0]=='s' || s[0]=='S') {
//unsigned v;
s++, s+=strspn(s, delim);
if (s[0] == '=' && sscanf(++s, "%u", &v) == 1) {
s+=strspn(s, delim);
s+=strspn(s, "+-"); s+=strspn(s, numbers);
if (v==normal || v==continous || v==staccatto) { style=v; }
}}
else { /* пропуск до пробела или ':' */
while (s[0]!=':' && s[0]!=0 && strchr(delim, s[0])==NULL) s++;
}
} while (s[0]!=':' && s[0]!=0);
if (s[0]==':') s++;
mel_start=s;
}
mel_idx = mel_start;
}
[ZX]
-
- Из маво древнего:Pain[] = {{ 8b1 8_n 8_f2 8b18g2 8_n 8_f2 8ne28_f2 8_n 8ne2 8_f28g2 8g2 8_f2 8ne28b1 8_n 8_f2 8b18g2 8_n 8_f2 8ne28d2 8_n 8ne2 8d28_c2 8_c2 8d2 8_c2 0,0}},/*FugaBach[] = {{16ne2 16_d2 16ne2 16b1 16g1 16g2 16_f2 Trashy(1678 знак., 24.08.2012 14:08,
)
- Нечеловеческая музыка. - Apтём(25.08.2012 00:43)
- Bach_Fuga,Grig_Hall_Of_Mountain_King,Freestyler,Pain,Bach_joly.Мне больше нравились Баховские вещи. - Trashy(24.08.2012 14:11,
)
- Спасибо! Моя версия заработала в простейшем виде, а дальше "этуазизм" приугас - объяснили риск использования в приборе мелодии с количеством нот больше двух - могут начать судиться авторы или правоприемники этой мелодии. Может, в самом деле Мурку Vladimir Ljaschko(12 знак., 24.08.2012 12:59)
- у мну при входе в тестовый режим лезгинка играется - музыка народная, слова тоже :) - RED_DRAGON(24.08.2012 13:43)
- А как же барабан? Без барабана лезгинка не вставляет ;) - Гудвин(24.08.2012 19:47)
- у мну при входе в тестовый режим лезгинка играется - музыка народная, слова тоже :) - RED_DRAGON(24.08.2012 13:43)
- Проигрывать так: fk0(411 знак., 22.08.2012 16:39)
- "Ты кто такой? Мурку давай!" - POV(22.08.2012 16:44)
- Из маво древнего:Pain[] = {{ 8b1 8_n 8_f2 8b18g2 8_n 8_f2 8ne28_f2 8_n 8ne2 8_f28g2 8g2 8_f2 8ne28b1 8_n 8_f2 8b18g2 8_n 8_f2 8ne28d2 8_n 8ne2 8d28_c2 8_c2 8d2 8_c2 0,0}},/*FugaBach[] = {{16ne2 16_d2 16ne2 16b1 16g1 16g2 16_f2 Trashy(1678 знак., 24.08.2012 14:08,