понедельник, 22 августа 2011 г.

[Из песочницы] Программная генерация звуков


Звук можно представить ввиде бесконечного количества волн различной частоты

и амплитуды. Волны, в свою очередь, могут иметь практически любую форму.

Из самых распространенных и чаще всего используемых можно назвать: синусоидальная (sine), квадратная (square), пилообразная(saw), треугольная (triangle), и шум (noise). Сначала попробуем разобраться с основными параметрами волны: период и амплитуда.







Частота (измеряется в герцах) — количество периодов в секунду. Например при частоте 44100Hz количество периодов равно 44100. Теперь когда основные термины изучены перейдем непосредственно к алгоритму генерации волн.



1) Sine волна



float samplerate; // частота сэмпла

float wavefrequency; // частота волны

float wavevolume; // громкость волны



float period=samplerate/wavefrequency/2; //вычисляем период волны

float pi=3.14; //число pi

int n;



for(int a=0;a<samplelenght;a++) //устанавливаем цикл на длину сэмпла

{

n=wavevolume*sin(a*pi/period); //вычисление sine-волны

buffer[a]=n; //заносим вычисленное значение в буфер

}




Например нам надо получить 16-килобайтный синусоидальный звук частотой 1000Hz и при этом качество сэмпла должно быть 44100Hz, тогда наши параметры будут иметь следующие значения: samplerate=44100, wavefrequency=1000, samplelenght=16384.



Особенного пояснения требует параметр wavevolume. Издавна известно, что качество звука пропорционально зависит от его битности (8-bit, 16-bit, 24-bit и т.д.). Для 8-bit — значение от 0..255, для 16-ти – 0...65536, для 24-х – 0...16777216. Какой выбрать? Смотря какая у вас задача, но меньше 16-ти я бы не посоветовал (хотя бывают и исключения – когда надо сократить объем сэмпла взамен качеству).



2) Пилообразная волна (saw)



float sr_2m=samplerate/wavefrequency; //Вычисляем период

int c=0; //Специальная переменная для проверки

//на окончание периода



for(int a=0;a<samplelenght;a++) //цикл на длину сэмпла

{

if(c>=sr_2m) c=0; //если период закончился, то начать следующий

buffer[a]=wavevolume*(c/period)-wavevolume; //вычисление волны

c++;

}




3) Треугольная (triangle)



float period=samplerate/wavefrequency/2; //вычисляем период волны

int c=period*2;

int c2=-1;

float sr_2m=period;

float sr=samplerate/wavefrequency/4;



for(int a=0;a<samplelenght;a++)

{

if(c>sr_2m) c=sr_2m,c2=-1;

if(c<0) c=0,c2=1;

buffer[a]=wavevolume*(c/sr)-wavevolume;

c+=c2;

}






4) Шум (noise)



srand(wavevolume);

s1=mv.samplerate/wor,psc=s1+1,wov>>=7;



if(tabcnt==0)

{

for(ps=0;ps<mv.samplelenght;ps++)

{

if(psc>s1)

{

psc-=s1;

n=256*((rand()%(wov+1))-wov/2);

}

buffer[ps]=n;

psc++;

}

}





Теперь усложним задачу — сложим две волны разной частоты и амплитуды.





char buffer[16384];



float tone1=65,tone2=131;

float samplerate=44100/2; // Частота дискретизации

int a,b,amp1=128,amp2=64;



for(a=0;a<16384;a++)

{

b=amp1*sin(a*pi/samplerate/tone1)+amp2*sin(a*pi/samplerate/tone2);

if(b>128) b=128;

if(b<-128) b=-128;

buffer[a]=b;

}






С таким сэмплом уже можно писать мелодии. В принципе, это основа wave

synthesis при помощи которой можно создать любой звук.



И напоследок пара советов:



1) Для получения более насыщенного звука складывайте волны с различными

формами: sine+square, triangle+saw, или вот такой вот монстр: saw+square+

triangle+saw.

2) Перкусия (hat) лучше всего получается путем сложения noise+sine.









Источник: Хабрахабр - Работа со звуком
Оригинальная страница: [Из песочницы] Программная генерация звуков

Комментариев нет:

Отправить комментарий