ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Среда
10 июля
348611 Топик полностью
fk0, легенда (22.08.2012 16:31, просмотров: 137) ответил Vladimir Ljaschko на Вопрос по С, торможу. Генерация мелодий.
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]