Как стать автором
Обновить

Программная генерация звуков

Время на прочтение2 мин
Количество просмотров42K
Звук можно представить ввиде бесконечного количества волн различной частоты
и амплитуды. Волны, в свою очередь, могут иметь практически любую форму.
Из самых распространенных и чаще всего используемых можно назвать: синусоидальная (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.
Теги:
Хабы:
Всего голосов 50: ↑40 и ↓10+30
Комментарии40

Публикации

Истории

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань