Главная » Processing » Делаем драм-машину в Processing

0

Теперь, когда вы умеете анализировать и визуализировать аудиофайл, мы попробуем сдать музыкальный инструмент. Начнем с построния программируемой драм-машины с 16-шаговым секвенсором по типу известных TR-808 и TR-909 драм-машин от Roland. На сайте Vintage Synth Explorer вы можете узнать все об этих устройствах: at http:// www.vintagesynth.com/roland/808.php.

Как это делается

Начните с создания новог скетча и сохранения его под именем drum_machine.pde. Добавьте к скетчу новую вкладку и сохраните ее как Button.pde. В ней мы напишем простой класс Button, чтобы вы могли включать и выключать кнопку. Этот класс будет также управлять проигрыванием аудио.

class Button

{

float x; float y; float w; float h;

boolean isOn;

Button( float _x, float _y )

{

x = _x; y = _y; w = 20;

h = 20;

isOn = false;

}

void render()

{

if ( isOn == true ) { fill( 255, 0, 0 );

} else {

fill( 255 );

}

rect( x, y, w, h );

}

void pressButton( int _x, int _y )

{

if ( _x > x && _x < x + w && _y > y && _y < y + h ) { isOn = !isOn;

}

}

}

В основном окне скетча нужно импортировать библиотеку minim и объявлить несколько переменных. Для загрузки звуков я использовал класс AudioSample вместо AudioPlayer потому, что он позволяет включать звуки по команде. Для каждого звука нам нужен массив объектов Button. В функции setup() мы загрузим несколько звуков и заполним массив кнопок типичными ритмами барабана.

import ddf.minim.*;

import ddf.minim.signals.*; import ddf.minim.analysis.*; import ddf.minim.effects.*;

Minim minim; AudioSample samples[];

Button[] bd;

Button[] sn; Button[] oh; Button[] ch;

int playhead; void setup()

{

size( 640, 200 );

minim = new Minim( this ); samples = new AudioSample[4];

samples[0] = minim.loadSample( "bd.aif" ); samples[1] = minim.loadSample( "sn.aif" ); samples[2] = minim.loadSample( "oh.aif" ); samples[3] = minim.loadSample( "ch.aif" );

frameRate( 8 );

playhead = 0;

bd = new Button[16];

for ( int i = 0; i < bd.length; i++ ) { bd[i] = new Button( 125 + i * 30, 50 ); if ( i % 4 == 0 ) {

bd[i].isOn = true;

}

}

sn = new Button[16];

for ( int i = 0; i < sn.length; i++ ) { sn[i] = new Button( 125 + i * 30, 80 ); if ( i % 8 – 4 == 0 ) {

sn[i].isOn = true;

}

}

oh = new Button[16];

for ( int i = 0; i < oh.length; i++ ) { oh[i] = new Button( 125 + i * 30, 110 ); if ( i % 2 == 1 ) {

oh[i].isOn = true;

}

}

ch = new Button[16];

for ( int i = 0; i < ch.length; i++ ) { ch[i] = new Button( 125 + i * 30, 140 ); if ( i % 2 == 0 ) {

ch[i].isOn = true;

}

}

}

В функции draw() мы сделаем указатель секвенсора, идущий за кнопками. Когда это будет закончено, мы запрограммируем включение аудио в случае активации кнопки и перемещение указателя на новую позицию.

void draw()

{

background( 255 );

// draw playhead fill( 0 );

rect( 120 + playhead * 30, 45, 30, 120 );

// draw buttons fill( 0 );

text( "*** PROCESSING DRUM MACHINE v1.0 ***", 125, 30 );

text( "Bassdrum", 20, 65 );

text( "Snare", 20, 95 );

text( "Open Hi-hat", 20, 125 );

text( "Closed Hi-hat", 20, 155 );

for ( int i = 0; i < bd.length; i++ ) { bd[i].render();

}

for ( int i = 0; i < sn.length; i++ ) { sn[i].render();

}

for ( int i = 0; i < oh.length; i++ ) { oh[i].render();

}

for ( int i = 0; i < ch.length; i++ ) { ch[i].render();

}

// play samples

if ( bd[playhead].isOn ) { samples[0].trigger();

}

if ( sn[playhead].isOn ) { samples[1].trigger();

}

if ( oh[playhead].isOn ) { samples[2].trigger();

}

if ( ch[playhead].isOn ) { samples[3].trigger();

}

// move playhead playhead++;

if ( playhead >= 16 ) { playhead = 0;

}

}

Функция mousePressed() использутся для переключения кнопок. С каждым кликом ми программа пройдется по массиву кнопок и с помощью метода pressButton() для каждого объекта Button определит, нажата ли кнопка. Если это так, метод изменит состояние кнопки.

void mousePressed()

{

for ( int i = 0; i < bd.length; i++ ) { bd[i].pressButton( mouseX, mouseY );

}

for ( int i = 0; i < sn.length; i++ ) { sn[i].pressButton( mouseX, mouseY );

}

for ( int i = 0; i < oh.length; i++ ) { oh[i].pressButton( mouseX, mouseY );

}

for ( int i = 0; i < ch.length; i++ ) { ch[i].pressButton( mouseX, mouseY );

}

}

И наконец нам нужно закрыть все аудиофайлы и остановить объект Minim с помощью функции stop().

void stop()

{

samples[0].close();

samples[1].close();

samples[2].close();

samples[3].close(); minim.stop();

super.stop();

}

Когда вы запустите пример, перед вами будет работающая драм-машина. Нажимайте на кнопки и создавайте ваши собственные ритмы.

Как это работает

В этом примере я использовал класс AudioSample вместо AudioPlayer. Это несколько иной класс – он держит в памяти весь аудиофайл, поэтому его лучше применять с небольшими аудиофайлами. Этот формат идеален для коротких звуков барабана. Для проигрывания файла есть метод trigger().

В функции setup() я установил значение переменной frameRate равной 8. Если вы зададите меньшее число, ритм будет медленнее, если более высокое – быстроее. На данный момент это то, что нужно, ведь наш инструмент очень прост. Для создания более профессионального инструмента нужно проигрывать звуки на основе определенного временного интервала; это будет немного сложнее.

Указатель передвигается с каждым кадром и возвращается в 0 по достижении последнего шага секвенсора. Следующий фрагмент кода проверяет, нажата ли какая-либо кнопка и включает соответствующий нажатой кнопке звук.

if ( bd[playhead].isOn ) { samples[0].trigger();

}

В классе Button существует метод pressButton(). Этот метод срабатывает для всех кнопок, когда мы кликаем мышью. Код в условии if представляет собой простую схему проверки, находится ли координата _x и _y в области кнопки. Величины _x и _y являются, по сути, переменными mouseX и mouseY, проходящими в функции mousePressed().

void pressButton( int _x, int _y )

{

if ( _x > x && _x < x + w && _y > y && _y < y + h ) { isOn = !isOn;

}

}

Источник: Ян Вантомм, Processing 2: креативное программирование, перевод с английского Александры Мишутиной, Published by Packt Publishing Ltd., 2012, BIRMINGHAM – MUMBAI.

По теме:

  • Комментарии