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

0

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

Листинг 4.12. Программа sinewave.h

#ifndef SINEWAVE_H_INCLUDED

#define SINEWAVE_H_INCLUDED

#include "audio.h"

class SineWave: public AudioAbstract {

};

#endif

Листинг 4.13. Программа sinewave.cpp

#include "audio.h"

#include "sinewave.h"

#include <cmath>

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

соответствующее сообщение MinMaxXxxxx. Поскольку объект класса всегда будет первым в цепочке, мне даже не придется вызывать родительские методы AudioAbstract::MinMaxXxxxx

Листинг 4.14. Члены класса SineWave

protected:

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

*min = *max = *preferred = 1;

};

Основная  задача,  стоящая  перед  нами  при  разработке  класса  SineWave,  такая же, что и при разработке любого модуля обработки звука, подменить метод GetSamples так, чтобы результатом его применения были аудиоданные. B нашем классе SineWave это очень просто. При инициализации объекта класса SineWave строится  таблица  выборок  для  волны  частотой  1  Гц.  Выбирая  из  этой  таблицы значения  с  шагом,  равным  требуемой  частоте,  вы  получаете  на  выходе  соответствующие  данные.  Основной  задачей  метода  GetSamples являются  тщательные вычисления, необходимые для того, чтобы при последовательных вызовах возвращались данные, взятые из правильно указанной области.

Листинг 4.14. Члены класса SineWave (продолжение)

protected:

size_t GetSamples(AudioSample *buff, size_t bytesWanted);

Листинг 4.15. Реализация класса SineWave

size_t SineWave::GetSamples(AudioSample *buff, size_t samplesWanted)

{

AudioSample *p = buff; long samplesCopied = 0; while((samplesWanted > 1) ) {

*p = sine[pos];

pos += frequency;

if (pos > length) pos = length;

samplesWanted -; samplesCopied ++; p++;

}

return samplesCopied;

}

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

Листинг 4.14. Члены класса SineWave (продолжение)

private:

AudioSample *sine; // Таблица  моментальных значений  синусоиды.

int length;          // Длина   вышеупомянутой  таблицы.

int pos;           // Текущее положение в  таблице.

int frequency;     // Требуемая частота  выходного сигнала,

public:

void Frequency(int f) { frequency = f; }

private:

void Init(void) {

sine = (AudioSample *)0;

length=0; pos=0; frequency=1;

}

public:

SineWave(void):AudioAbstract() { Init(); } SineWave(int f):AudioAbstract() {

Init(); Frequency(f);

};

~SineWave(void) {

if (sine) delete [] sine;

}

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

Листинг 4.14. Члены класса SineWave (продолжение)

private:

void BuildTable(long rate);

Листинг 4.15. Реализация класса SineWave (продолжение)

void SineWave::BuildTable(long rate) {

if (sine) {delete [] sine;}

length = rate;

sine = new AudioSample[length];

double scale = 2.0*(3.14159265358)/

static_cast<double>(length);

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

sine[i] = int(32767 * sin(static_cast<double>(i)*scale)

);

}

}

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

Листинг 4.14. Члены класса SineWave (продолжение)

public:

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

}

Глава 5. Объекты-проигрыватели

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

По теме:

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