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

0

Легче  всего  рассматривать  музыкальный  инструмент  как  некий  объект,  воспроизводящий  звук.  Однако  это  не  вполне  соответствует  действительности.  Проблема,   возникающая   во   многих   объектно-ориентированных   разработках,   заключается  в  том,  что  один  инструмент  может  воспроизводить  множество  различных звуков  одновременно  и  сложно  спроектировать  этот  объект,  который  естественным образом поддерживал бы такой режим работы. Более удачный подход представить  инструмент  как  средство  генерации  нотных  объектов,  которые  можно  заставить воспроизводить звук.

Реализация  этого  подхода  на  C++  требует  определения  двух  взаимосвязанных классов.  Классы  AbstractInstrument и  AbstractNote определят  основные  возможности объектов инструментов и нот. Типы инструментов и нот, которые могут использоваться на практике, будут определены позже.

Листинг 20.1. Программа instrumt.h

#ifndef  INST_H_INCLUDED

#define INST_H_INCLUDED

#include "audio.h"

class AbstractInstrument {

private:

long _samplingRate;

public:

virtual void SamplingRate(long samplingRate) {

_samplingRate = samplingRate;

}

virtual long SamplingRate() { return _samplingRate; }

public:

virtual ~AbstractInstrument() {};

virtual AbstractNote * NewNote(float pitch, float volume) = 0;

};

#endif

Класс   AbstractInstrument имеет   только   одну   нетривиальную   функцию-

член NewNote. Это не должно удивлять. Если провести аналогию со скрипкой

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

Единственная  общая  черта  всех  инструментальных  типов  заключается  в  том, что они генерируют ноты, наверное, несколько одновременно. B связи с этим любой инструментальный класс для создания подходящего нотного объекта применяет метод NewNote. Особенность его в том, что вы запрашиваете ноту у конкретного инструмента, а потом даете команду, чтобы она проигралась в буфер. Это могут быть несколько нот, проигрываемых одним инструментом одновременно.

Ноты

Все  ноты  обладают  определенными  свойствами,  которые  выражены  в  базовом классе  AbstractNote.  Важнейшее  заключается  в  том,  что  нота  может  воспроизвести  себя  в  «предоставленный»  вами  буфер.  Так  как  обычно  звучат  несколько нот  одновременно,  а  результаты  воспроизведения  накладываются,  лучше  придерживаться  соглашения,  в  соответствии  с  которым  ноты  проигрываются  путем  добавления  их  выходной  информации  в  буфер.  Это  уменьшает  количество  необходимых  операций  копирования.  Следует  удостовериться,  что  общая  громкость  всех нот,  проигрываемых  в  один буфер,  меньше  единицы,  в  противном  случае  возникнут переполнение и искажение.

По  умолчанию  повторные  вызовы  для  одной  и  той  же  ноты  продолжают  ее проигрывание.  Метод  Restart может  использоваться  для  повторного  запуска  (restart)  ноты.  Метод  Pitch устанавливает  требуемую  выходную  частоту,  например, Pitch (440) используется для проигрывания ноты Ля 440 Гц. Метод Volume принимает значение между 0 и 1 для установки относительной громкости.

Листинг 20.2. Описание класса AbstractNote

class AbstractNote {

protected:

AbstractNote() {};                   // Определяется, кто  может

// создавать  объекты

// этого класса.

public:

virtual ~AbstractNote() {};          // Удалять  можно  всем.

virtual size_t AddSamples(AudioSample *buffer, size_t samples)

= 0;

virtual void Restart() = 0;          // Перезапуск  ноты.

virtual void EndNote(float) = 0;     // Остановка

// воспроизведения ноты.

virtual void Pitch(float) = 0,     // Задается  высота тона

// в герцах.

virtual float Pitch() = 0;           // Получена высота  тона.

virtual void Volume(float) = 0;      // Устанавливается уровень.

(0,0-1,0)

virtual float Volume() = 0;    // Считывается  текущий уровень.

};

Объявление   стандартного   конструктора   AbstractNote  () как   protected означает,  что  вы  не  создадите  без  привлечения  дополнительных  средств  объект AbstractNote,  так  как  только  производные  классы  могут  вызывать  конструктор. Особенность заключается в том, что мы просим инструмент создать для нас ноту. Ha практике нотные классы сильно зависят от данных, хранящихся в классе инструмента,  который  самостоятельно  способен  проинициализировать  ноту  должным образом.

Для  простоты  используются  числа  с  плавающей  точкой  для  задания  высоты и  громкости.  Арифметика  этих  чисел  обычно  используется  только  при  создании ноты, поэтому их можно применять даже на медленных машинах (это практически  не  влияет  на  производительность).  Для  инициализации  новой  ноты  требуется небольшое  количество  операций  с  плавающей  точкой.  Значительную  часть  времени  выполнения  музыкальной  программы  занимает  подпрограмма  AddSamples, создатели  которой  обычно  полагаются  на  быструю  целочисленную  арифметику или на вычисления с фиксированной точкой.

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

По теме:

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