Вы находитесь на странице: 1из 35

Разработка интерактивных систем

на OpenFrameworks

4. Интерактивный звук

лекции и объявления:
www.uralvision.blogspot.com

вопросы по проектам и программированию:


perevalovds@gmail.com
УрГУ / ИММ весна 2011
Что такое
цифровой звук
Что такое звук вообще
Звук, в широком смысле — упругие волны, продольно распространяющиеся в среде
и создающие в ней механические колебания;
в узком смысле — субъективное восприятие этих колебаний специальными
органами чувств животных или человека.
Как и любая волна, звук характеризуется амплитудой и частотой. (Википедия)

http://blog.modernmechanix.com/mags/qf/c/PopularScience/9-1950/med_sound.jpg
Представление звука
в цифровом виде
Реальный звук захватывается микрофоном, затем подвергается аналого-
цифровому преобразованию.

Оно характеризуется
разрешением по времени - частота дискретизации, [процедура - дискретизация]
разрешением по амплитуде - разрядность. [процедура - квантование]

Амплитуда

Время

http://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Digital.signal.svg/567px-Digital.signal.svg.png
Частота дискретизации
8 000 Гц — телефон, достаточно для речи.

11 025 Гц — игры, сэмплы для электронной музыки.

22 050 Гц — то же, что и 11 025 Гц.

44 100 Гц — многие синтезаторы и библиотеки сэмплов. Audio CD.

48 000 Гц — студии звукозаписи, живые инструменты, вокал. DVD.


96 000 Гц — DVD-Audio (MLP 5.1).

192 000 Гц — DVD-Audio (MLP 2.0).


Разрядность
Разрядность - число бит, используемых для представления отсчетов сигнала при
квантовании (в нашем случае - при квантовании амплитуды).

8 бит сэмплы электронной музыки.

12 бит студийные звуковые эффекты.

16 бит компьютерные игры, плееры, сэмплы, Audio CD.

18 бит студийные звуковые эффекты

24 бит живые звуки, вокал, DVD-Audio

32 бит представление с плавающей точкой, поэтому точность не теряется


для тихих звуков, поэтому используется для внутренней обработки звука.

64 бит также с плавающей точкой, обработка звука.


Представление звука в памяти

Пример
1 секунду 16-битного звука
с частотой дискретизации 44100 Гц
можно представить в виде вектора

X = (x_1, x_2, ..., ..., x_44100),


где 0 <= x_i <= 2^16-1 = 65535.

Представление звуков таких способом - с помощью вектора


- называется PCM (Pulse Code Modulation).
Оно является наиболее распространенным.
Оно аналогично пиксельному представлению изображений.
Фундаментальное различие звука и
изображений
С изображениями очень удобно работать на уровне
пикселов. В частности,

1. два изображения мы считаем одинаковыми, если


значения их пикселов близки.

2. можно изменять изображения, основываясь на


значениях соседних пикселов (например, операция
сглаживания).

Для звука в PCM формате обе возможности неприменимы


Фундаментальное различие звука и
изображений
1. ля 1-й октавы 440.00 Гц

2. она же, сдвинутое по фазе

3. ми 2-й октавы 659.26 Гц

1. + 3.

2. + 3.
Для генерации звуков
использовал Audacity

Последние два звука звучат одинаково. А их функции амплитуды - существенно


различные. Таким образом, человечеcкое ухо воспринимает спектр звука, то есть
состав его частот, а не амплитудное представление звука.
Что легко/трудно делать "прямо" со
звуком в формате PCM
Легко: Изменение и перестановка отдельных отсчетов, без учета соседей
- переставлять кусочки,
- менять громкость кусочков,
- делать реверс - переворот звука от конца к началу,
- смешивать несколько звуков,
- смешивать и менять стерео-каналы,
- делать простейшую компрессию,
- добавлять простейшее эхо.
Сэмплеры, портастудии и студийные программы делают это виртуозно.

Трудно: Учет соседних отсчетов


- сравнивать два звука на похожесть,
- подавлять низкие или высокие частоты,
- добавлять реверберацию.

Это обычно делается не прямо в PCM, а через спектральное представление звука


(оконное преобразование Фурье).
Форматы хранения звука

WAV
wav = заголовок + байты PCM
Хранит звук без потери качества
(аналог в изображениях - bmp)

MP3
Данные с потерями, хорошо подходит для хранения
музыки.
(аналог в изображениях - jpg)

AMR
Данные с потерями, предназначен для хранения речи.
Используется в мобильной телефонии (2011).
(аналог в изображениях - png)
Способы генерации
цифрового звука
Способы генерации цифрового звука
То есть, способы построения PCM-представления некоторого звука или
музыки:

1. Сэмплирование
Используется для производства всей музыки. Устройства - сэмплеры

2. (Субтрактивный) Синтез
Используется преимущественно для современной электронной музыки.
Устройства - синтезаторы.

3. FM-синтез

4. Аддитивный синтез

5. Гранулярный синтез

6. S&S - Sample & Synthesis - сэмплирование, анализ, последующий


синтез - сегодня одна из наиболее лучших технологий воспроизведения
"живых" инструментов.
Сэмплирование
Запись: "Живой звук" - микрофон - АЦП - PCM-формат.

Воспроизведение: PCM-формат - ЦАП - динамик.

Дополнительные возможности: можно менять скорость воспроизведения, тогда


повысится тон и скорость сэмпла.
Современные алгоритмы также позволяют менять тон сэмпла без изменения его
скорости, и наоборот.

Сэмплер
Akai MPC1000

http://josephdbferguson.com/uploads/akai_mpc1000.jpg
(Субтрактивный) Синтез
В докомпьютерное время:
несколько простых волн (прямоугольная, синусоидальная, треугольная) обрабатывались
набором фильтров (НЧ, ВЧ, вырезание нужной частоты).
Полученный шел идет на динамики.

Сейчас:
делается в цифровом виде.
Есть трудности - нужно аккуратно учитывать известные проблемы, связанные с цифровым
представлением звука ("алиасинг").

Синтезатор
Minimoog

http://www.jarrography.free.fr/synths/images/moog_minimoog.jpg
Воспроизведение сэмплов
в openFrameworks
Проект "звуковой ландшафт"

Пользователь тыкает мышью в разные части экрана и


начинает доноситься некоторый звук
http://www.freesound.org/samplesViewSingle.php?id=221

//Объявление переменных
ofSoundPlayer sample; //проигрыватель сэмпла
ofPoint p; //точка и радиус - для рисования кружка
float rad;

void testApp::setup(){
sample.loadSound("sound.wav"); //Загрузка сэмпла из папки bin/data
sample.setVolume(0.5f); //громкость, [0, 1]
sample.setMultiPlay(true); //разрешаем запускать несколько сэмплов
ofSetFrameRate( 60 ); //скорость рисования кадров
ofSetBackgroundAuto( false ); //выключаем стирание фона
ofBackground(255,255,255);
}
Проект "звуковой ландшафт"

void testApp::update(){
ofSoundUpdate(); //обновляем состояние звуковой системы
}

void testApp::draw(){

//если звук играет, рисовать прозрачный кружок


ofEnableAlphaBlending();
if (sample.getIsPlaying()) {
//случайный цвет
ofSetColor(ofRandom(0, 255), ofRandom(0, 255), ofRandom(0, 255), 20);
ofCircle( p.x, p.y, rad );
}
ofDisableAlphaBlending();
}
Проект "звуковой ландшафт"

//нажата мышь
void testApp::mousePressed(int x, int y, int button){

float h = ofGetHeight(); //высота экрана

//вычисляем желаемую скорость воспроизведения сэмпла,


//при этом 1.0 - это оригинальная скорость сэмпла
float speed = (h - y) / h * 3.0;
if ( speed > 0 ) {
sample.play(); //запуск нового сэмпла
sample.setSpeed( speed ); //установка скорости воспроизведения

//запоминаем точку и радиус кружка для рисования


p = ofPoint( x, y );
rad = (3 - speed);
rad = 20 * rad * rad;
}
}
Проект "звуковой ландшафт"
Аддитивный синтез

Аддитивный синтез основан на построении звука с


помощью суммирования множества гармоник (т.е. синусоид
разной частоты) с изменяющейся громкостью.

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


сумму большого числа гармоник с меняющейся громкостью. Но на
практике работа с большим числом гармоник требует больших
вычислительных ресурсов. Хотя, в настоящее время существует
несколько аппаратных и программных аддитивных синтезаторов.
Сценарий проекта
"Аддитивный синтезатор"
Пользователь на белом фоне машет руками перед
камерой. Имеется n гармоник. Экран разделен
на n вертикальных полосок, в каждой считается число
пикселов, яркость которых меньше некоторого порога. Это
число определяет громкость соответствующих гармоник.

Используем n = 20 синусоидальных гармоник, с частотами


100 Гц,
200 Гц,
...
2000 Гц

Гармоники играются с помощью зацикленных сэмплов, у


которых просто меняется громкость.
Текст проекта 1/4

//Объявляем переменные

//видео-граббер для "захвата" видеокадров


ofVideoGrabber grabber;
int w; //ширина кадра
int h; //высота кадра

const int n = 20; //число гармоник


ofSoundPlayer sample[ n ]; //сэмплы гармоник
float volume[ n ]; //громкость гармоник
int N[ n ]; //число пикселов, играющих в этой гармонике

ofSoundPlayer sampleLoop; //сэмпл барабанной петли


Текст проекта 2/4
//Инициализация
void testApp::setup(){

w = 320;
h = 240;
grabber.initGrabber(w, h); //подключение камеры

//загрузка сэмплов гармоник


for (int i=0; i<n; i++) {
int freq = (i+1) * 100;
sample[ i ].loadSound( ofToString(freq) + ".wav"); //файлы называются 100.wav,...
sample[ i ].setVolume(0.0); //громкость
sample[ i ].setLoop(true); //зацикливаем звук
sample[ i ].play(); //запуск звука
}

}
Текст проекта 3/4
//Обновление состояния
void testApp::update(){
grabber.grabFrame(); //захват кадра
if (grabber.isFrameNew()){ //если пришел новый кадр
for (int i=0; i<n; i++) { volume[i] = 0; N[i] = 0; } //сбрасываем гармоники
unsigned char * input = grabber.getPixels(); //пикселы входного изображения
for (int y=0; y<h; y++) {
for (int x=0; x<w; x++) {
//входной пиксел (x, y):
int r = input[ 3 * (x + w * y) + 0 ];
int g = input[ 3 * (x + w * y) + 1 ];
int b = input[ 3 * (x + w * y) + 2 ];
int result = (r + g + b > 400 ) ? 0 : 1; //пороговая обработка
int i = (x * n / w); //в какую гармонику писать результат
volume[ i ] += result;
N[ i ]++;
}}
//устанавливаем новые громкости гармоник
for (int i=0; i<n; i++) {
if ( N[ i ] > 0 ) { volume[ i ] /= N[ i ]; } //нормируем громкости в [0, 1]
sample[ i ].setVolume( volume[ i ] / n ); //громкость.
//Делим на n, иначе будет искажение выходного звука
} } ofSoundUpdate(); //обновляем состояние звуковой системы
}
Текст проекта 4/4
//Рисование
void testApp::draw() {
ofBackground(255,255,255); //задаем цвет фона
float w = ofGetWidth(); //высота и ширина экрана
float h = ofGetHeight();

ofSetColor( 255, 255, 255 ); //иначе картинка кадра нарисуется неверно


grabber.draw(0, 0, w, h); //вывод кадра

//рисование гармоник
ofEnableAlphaBlending(); //включение прозрачности
ofSetColor( 0, 0, 255, 80 ); //синий цвет с непрозрачностью 80
for (int i=0; i<n; i++) {
float harmH = volume[i] * h; //высота столбика гармоники i
ofRect( i * w / n, h - harmH, w / n, harmH );
}
ofDisableAlphaBlending(); //выключение прозрачности
}
Пример исполнения
на "Аддитивном синтезаторе"

http://www.youtube.com/watch?v=y70Oxk1RAOM
Синтез звуков
в openFrameworks
Введение

Синтез звука на openFrameworks осуществляется на самом


нижнем уровне, "побайтово".

Поэтому он пригоден эспериментальных проектов со


звуков.

В сложных проектах удобней использовать специальные


библиотеки типа SndObj (см. расширение oxfSndObj),
либо отдельные программы типа PureData или Max/MSP,
с которыми openFrameworks связывается по протоколу
OSC.
Структура программы
Для синтеза звука обычная структура программы расширяется функцией
audioRequested(). Она вызывается звуковым драйвером, когда требуется
заполнить очередной фрагмент звукового буфера звуком.
Структура программы
в testApp.h, класс testApp добавить:
void audioRequested(float * input, int bufferSize, int nChannels);

в setup() добавить:
ofSoundStreamSetup (2,0,this, 22050, 256, 4);

// 2 выходных канала,
// 0 входных каналов,
// 22050 - частота дискретизации, сэмплов в секунду
// 256 - размер буфера
// 4 - сколько использовать буферов. Влияет на задержку.
//Размер буфера и число буферов - задают баланс между задержкой
получаемого звука и "глиттером", который возникает, если компьютер
недостаточно быстрый.
Структура программы
в testApp.cpp добавить:

void testApp::audioRequested ( float * output, //выходной буфер


int bufferSize, //размер буфера
int nChannels //число каналов
)
{
//Пример генерации звука "белый шум", в два канала
for (int i = 0; i < bufferSize; i++){
output[i*nChannels ] = ofRandomf(); //[-1,1]
output[i*nChannels + 1] = ofRandomf();
}
}
Пример
См. пример audioOutputExample в OpenFrameworks.

Мышь движется
1. вверх-вниз - меняется тон звука.
2. влево-вправо - меняется панорама.
Нажата кнопка мыши - генерируется шум.
Пример синтеза: RubberGravity
Резиновые квадраты при растяжении генерируют звук.

http://www.youtube.com/watch?v=Pz6PO4H1LT0
Домашнее задание

Используя пример audioOutputExample,


добавить в пример с качающимся маятником генерацию
звука.
А именно:
пусть положение маятника по Y задает высоту звука,
а положение маятника по X - панорамирование.

Оценить