Главная » Программирование звука » Тестирование нот

0

Следующая короткая программа тестирует классы инструментов и нот, разработаные в этой главе. Сначала определяется простой класс AudioAbstract, который проигрывает  несколько  нот.  Функция  main создает  объект  инструмента  и  просит класс PlayInstrument проиграть одну или несколько нот. Можно легко изменить эту программу и протестировать другие инструменты.

Надо  обратить  внимание  на  то,  как  в  классе  PlayInstrument организована одновременная  работа  с  несколькими  нотами.  Он  обнуляет  буфер  перед  тем,  как попросить  различные  ноты  добавить  в  него  свои  выборки  и  также  проверяет  возвращаемое  AddSamples значение,  чтобы  определить,  закончилась  ли  нота.  Когда это происходит, класс удаляет нотный объект и, наконец, возвращает буферу максимальный объем, чтобы показать, когда закончатся все ноты.

Помните,  что  лишь  немногие  инструменты  прекращают  свое  звучание  моментально   остальные  имеют  небольшой  период  затухания,  поэтому  важно  не  останавливать воспроизведение каждой ноты даже после вызова EndNote.

Листинг 21.16. Программа playnote.cpp

#include "audio.h"

#include "aplayer.h"

// Пробуем подобрать  подходящий проигрыватель  для  Win3 2,

// Macintosh или   UNIX/NAS.

#if defined(_WIN32)

#include "winplayr.h" typedef WinPlayer Player;

#elif defined(macintosh)

#include "macplayr.h" typedef MacPlayer Player;

#else

#include "nasplayr.h" typedef NasPlayer Player;

#endif

#include "instrumt.h"

#include "sampled.h"

#include "au.h"

#include "plucked.h"

#include <cstdlib>

#include <fstream>

class PlayInstrument: public AudioAbstract {

private:

long _samplesRemaining; AbstractInstrument *_instr; AbstractNote *_notes[5]; float _pitches[5];

float _volumes[5];

protected:

void MinMaxChannels(int *min, int *max, int *preferred) {

*min = *max = *preferred = 1;

};

public :

void Init() {

_samplesRemaining = 44100 * 5;       // Воспроизводим

// в течение 5 с.

for(int i=0;i<5;i++) {

_notes[i] = 0;

_pitches[i] = _volumes[i] = 0;

}

}

PlayInstrument(AbstractInstrument *instr) { Init(); _instr = instr;

}

void AddNote(float pitch, float volume) {

int i = 0;

while(_pitches[i] != 0)

i++;

_pitches[i] = pitch;

_volumes[i] = volume;

}

~PlayInstrument() {

for(int i=0;i<5;i++)

if (_notes[i]) delete _notes[i];

}

size_t GetSamples(AudioSample *buffer, size_t numSamples) {

for(size_t s=0; s<numSamples; s++) // Обнуляем  буфер.

buffer[s] = 0; size_t maxSamples = 0; int i;

for(i=0;i<5;i++) {                // При  необходимости

// создаем ноты.

if(_pitches[i] && !_notes[i])  // При  необходимости

// создаем ноту.

_notes[i] = _instr->NewNote(_pitches[i],_volumes[i]);

}

for(i=0;i<5;i++) {                // Воспроизводим

// каждую ноту  в  буфер.

if(_notes[i]) {          // Если   эта  нота существует,

// воспроизводим  ее.

size_t samplesRead = 0;

// Если   пришло   время начать

// затухание…

if((_samplesRemaining >= 0)

&& (static_cast<long>(numSamples) >

_samplesRemaining)) {

_notes[i]->AddSamples(buffer,_samplesRemaining);

_notes[i]->EndNote(0.5);      // Начать затухание

// ноты.

samplesRead

= _samplesRemaining + _notes[i]->AddSamples(

buffer+_samplesRemaining,numSamples-

_samplesRemaining);

} else {

samplesRead = _notes[i]-

>AddSamples(buffer,numSamples);

}

if (samplesRead < numSamples) { // Нота   обработана.

delete _notes[i];           // Удаляем  ее.

_notes[i] = 0;

_pitches[i] = 0;        // He восстанавливать ее!

_volumes[i] = 0;        // He восстанавливать ее!

}

if (samplesRead > maxSamples)

maxSamples = samplesRead;

}

}

_samplesRemaining -= numSamples;

return maxSamples;

};

void SamplingRate(long rate) { AudioAbstract::SamplingRate(rate);

_instr->SamplingRate(rate);

};

};

int main(int argc, char **argv) { bool saveOutput = false; AbstractInstrument *instr = 0;

argv++; argc–;                 // Пропускаем  имя   программы.

// Обработка параметров

// командной  строки.

while ((argc>0) && (**argv == "-")) {

char *p=*argv;

switch(p[1]) {

case "0": // Выбираем инструмент   0.

instr = new SineWaveInstrument;

break;

case "1":       // Выбираем инструмент   1.

instr = new PluckedStringInstrument;

break;

case "p":       // Воспроизводим  выходные данные.

saveOutput = false;

break;

case "а":       // Записываем данные в  файле формата AU.

saveOutput = true;

break;

}

argv++; argc–;

}

if(instr == 0) {instr = new SineWaveInstrument; } PlayInstrument pi(instr);

if (argc == 0) {   // По  умолчанию  просто главная  триада.

pi.AddNote(330.0F, 0.3F); pi.AddNote(440.0F, 0.3F); pi.AddNote(550.0F, 0.3F);

} else {           // Считываем  ноты/громкость

// из  командной строки.

while (argc>0) {

float volume = 1.0/((argc+1)/2);

if(argc>1) {

volume = atof(argv[l]);

argc–;

} pi.AddNote(atof(argv[0]),volume); argc–;

argv+= 2;

}

}

AbstractPlayer *player;

if (saveOutput) {  // Воспроизводим в  файл   AU.

ofstream out("playnote.au"); player = new AuWrite(&pi, out); player->Play();

delete player;

} else {           // Воспроизводим  на   громкоговоритель.

player = new Player(&pi);

player->Play ();

delete player;

}

delete instr;

return 0;

}

Источник: Кинтцель Т.  Руководство программиста по работе со звуком = A Programmer’s Guide to Sound: Пер. с англ. М.: ДМК Пресс, 2000. 432 с, ил. (Серия «Для программистов»).

По теме:

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