Відтворення файлів MOD

Тепер, коли ми знаємо, як читати файли, пора подумати про те, як їх програвати Оскільки клас ModRead є спадкоємцем класу AudioAbstract, йому необхідна реалізація методу GetSamples Найпростіше реалізувати метод PlayBeat, який програє один такт в буфер (або в два буфера для стереозвуку) Потім GetSamples копіює дані з цього буфера, щоб відповісти на запит, викликаючи у міру потреби PlayBeat для наступного заповнення буфера

Лістинг 2310 Члени класу МоdRеаd (продовження)

public:

size_t GetSamples(AudioSample *buffer, size_t numSamples)

Метод PlayBeat відтворює відліки стереозаписи одночасно в два буфера, і GetSamples повинен відповідним чином чергувати відліки

Лістинг 233 Програма modcpp (продовження)

size_t ModRead::GetSamples(AudioSample *buff, size_t length) {

int requestedLength = length

do {

switch(Channels()) {

case 1: / / Моно: копіюємо і перетворюємо

while ((_sampleLength &gt 0)&amp&amp(length &gt 0)) {

*buff++ = *_sampleStartLeft++

_sampleLength–

length–

}

break

case 2: / / Стерео: значення для каналів

/ / Чергуються

while ((_sampleLength &gt 0)&amp&amp(length &gt 0)) {

*buff++ = *_sampleStartLeft++

*buff++ = *_sampleStartRight++

_sampleLength–

length-=2

}

break

/ / Внутрішня помилка

default: cerr &lt&lt &quotInternal error\n"

exit (1) / / Такого не буває

}

if (length> 0) / / Ще потрібні дані

PlayBeat () / / Генеруємо наступний такт

if (_sampleLength == 0) break / / Більше немає даних

} while (length&gt0)

return requestedLength-length

}

Буферизація ускладнюється двома обставинами По-перше, окремі семпли є монофонічними, однак іноді необхідно здійснювати їх відтворення поперемінно то в правому, то в лівому каналі По-друге, довжина такту може змінюватися під час відтворення: різні ефекти змінюють тривалість такту

Щоб реалізувати відтворення в стереорежимі, я визначив два буфера один на кожен канал Процедура відтворення вибирає відповідний буфер залежно від каналу, на якому здійснюється відтворення При роботі в монорежиме обидва буфера ідентичні Крім того, описані змінні для зберігання покажчика початку і довжини області даних, що показують, скільки даних залишається в буфері

Лістинг 2310 Члени класу ModRead (продовження)

private:

AudioSample * _sampleBufferLeft / / Лівий канал AudioSample * _sampleBufferRight / / Правий канал int _sampleBufferSize

AudioSample * _sampleStartLeft / / Позиція

/ / В sampleBufferLeft

AudioSample *_sampleStartRight

int _sampleLength / / Довжина області даних

/ / В буферах відліків

void SetSampleBufferSize()

Лістинг 2311 Ініціалізація змінних класу ModRead

_sampleBufferLeft = 0

_sampleBufferRight = 0

_sampleBufferSize = 0

_sampleLength = 0

Метод SetSampleBufferSize викликається при будь-якій зміні тривалості такту Він відповідає за оновлення буферів для того, щоб гарантувати наявність досить великий області вільного місця Він може обчислити необхідний розмір за поточною частоті дискретизації і двома параметрами сінxpoнізаціі MOD: _ticksPerMinute і _ticksPerBeat O6paтіте увагу, що з метою підвищення точності я вважаю кількість тиків в хвилину, а не в секунду

Лістинг 2310 Члени класу ModRead (продовження)

private:

int _ticksPerMinute / / Тиків на хвилину int _ticksPerBeat

int _samplesPerBeat

int _samplesPerTick / / Це апроксимація

Як згадувалося раніше, значення за замовчуванням 50 тиків в секунду і 6 ти-

ков на такт

Лістинг 2311 Ініціалізація змінних класу ModRead (продовження)

_ticksPerMinute = 50 * 60

_ticksPerBeat = 6

Для простоти будемо вважати, що в методі SetSampleBufferSiz лівий буфер використовується для відтворення в монорежиме, а потім, при необхідності, налаштовує правий буфер Він заново обчислює значення samplesPerBeat і samplesPerTick для використання усередині класу Зауважте, що значення samplesPerTick необовязково в точності кратно samplesPerBeat Програма, в якій повний такт необхідно програти за один тик, стає складніше, зате це забезпечує більш точну загальну синхронізацію

Лістинг 233 Програма modcpp (продовження)

/ / Переконаємося, що буфер відліків досить великий void ModRead :: SetSampleBufferSize () {

_samplesPerBeat = SamplingRate() * _ticksPerBeat * 60

/ _ticksPerMinute

_samplesPerTick = _samplesPerBeat / _ticksPerBeat

if (_sampleBufferLeft &amp&amp (_sampleBufferSize &gt=

_samplesPerBeat))

return

if (_sampleBufferRight == _sampleBufferLeft)

_sampleBufferRight = 0

if (_sampleBufferLeft)

delete [] _sampleBufferLeft

_sampleBufferLeft = new AudioSample[_samplesPerBeat]

switch(Channels()) {

/ / При моносігнале обидва канали використовують один і той же буфер

case 1: _sampleBufferRight = _sampleBufferLeft break

case 2:

if (_sampleBufferRight)

delete [] _sampleBufferRight

_sampleBufferRight = new AudioSample[_samplesPerBeat]

break

default:

/ / Неприпустиме число каналів:

cerr &lt&lt &quotIllegal number of channels: &quot

&lt&lt Channels()

&lt&lt &quot\n"

exit(1)

}

_sampleBufferSize = _samplesPerBeat

_sampleStartLeft = _sampleBufferLeft

_sampleStartRight = _sampleBufferRight

_sampleLength = 0 / / B буфері зараз порожньо

}

Метод PlayBeat

Метод PlayBeat, по суті, є ядром всього класу B ньому відстежується поточний такт, різні ноти відтворюються в потрібні буфери відліків і накладаються всі нотні ефекти Залишилася частина даної глави присвячена в основному розгляду окремих частин цього великого методу

PlayBeat також відповідає за програвання нот у відповідних каналах C кожним каналом асоціюється деяка кількість інформації про статус, тому використовується структура ModChannel

Лістинг 2310 Члени класу ModRead (продовження)

private:

/ / Живі на поточний момент ноти enum {numberChannels = 4}

ModChannel _channel[numberChannels]

void PlayBeat () / / Відтворюємо наступний такт

/ / В sampleBuffer

Статусна інформація для кожного каналу включає в себе основні параметри нот (період, інструмент і гучність) і попередні значення для кожного ефекту Всередині файлу формату MOD нульове значення інструменту або нульова довжина періоду означають, що повинні бути збережені попередній інструмент або період Багато ефекти використовують ту ж саму угоду

Лістинг 2312 Члени класу ModChannel

public:

ModNoteData _currentNote

int _currentVolume ModNote *_liveNote

unsigned char _defaultParameter[ModNoteData::effectCount] ModChannel()

~ModChannel()

Лістинг 233 Програма modcpp (продовження)

ModChannel::ModChannel() {

_liveNote = NULL

for(int i0=0i0&ltModNoteData::effectCounti0++)

_defaultParameter [i0] =0

}

ModChannel::~ModChannel() {

if (_liveNote) delete _liveNote

}

Подивимося, як це працює Метод PlayBeat спочатку переходить на наступний такт, потім переглядає всі його ноти для накладення глобальних ефектів (змінюють глобальні параметри, такі як порядок програвання або темп) Після цього він може підготувати буфери відліків і, нарешті, здійснити відтворення нот в буфери

Лістинг 233 Програма modcpp (продовження)

/* Відтворюємо даний такт * /

void ModRead::PlayBeat() { AudioSample *sampleBuffer

if (_songAdvance()) return

for(int ch0=0ch0&ltnumberChannelsch0++) { ModNoteData currentNote = _songThisNote(ch0) switch(currentNote_effect) {

default: break

SetSampleBufferSize()

memset(_sampleBufferLeft, 0, sizeof(_sampleBufferLeft[0]) * _samplesPerBeat)

if (Channels()==2)

memset(_sampleBufferRight, 0, sizeof(_sampleBufferRight[0]) * _samplesPerBeat)

/ / Налаштовуємо кожен канал і здійснюємо

/ / Відтворення

for(int ch=0ch&ltnumberChannelsch++) {

switch(ch) {

case 0: case 3: case 4: case 7:

sampleBuffer = _sampleBufferLeft break

case 1: case 2: case 5: case 6: default:

sampleBuffer = _sampleBufferRight break

}

ModNoteData currentNote = _songThisNote(ch)

/ / Якщо код інструменту або величина періоду не рівні 0,

/ / Починаємо нову ноту

if (   (currentNote_instrument = 0)

|| (currentNote_period = 0)) {

/ / По-перше, звіряємо параметри за замовчуванням

/ / З попередньої ноти

if (currentNote_instrument == 0)

currentNote_instrument =

_channel[ch]_currentNote_instrument

if (currentNote_period == 0)

currentNote_period =

_channel[ch]_currentNote_period

if (currentNote_instrument &gt= numInstruments) {

/ / Неприпустимий номер інструменту

cerr &lt&lt &quotIllegal instrument number &quot

&lt&lt int(currentNote_instrument) &lt&lt &quot.\n"

break

}

} Else {/ / B інакше продовжити виконання

/ / Попередній ноти currentNote_instrument =

_channel[ch]_currentNote_instrument

currentNote_period = _channel[ch]_currentNote_period

}

if (_channel[ch]_liveNote) {

ModNote &ampcurrentLiveNote = *_channel[ch]_liveNote

int defaultParameter

=

_channel[ch]_defaultParameter[currentNote_effect] int thisParameter = currentNote_parameter switch(currentNote_effect) {

default:

/ / Внутрішня помилка: неприпустимий код ефекту

cerr &lt&lt &quotInternal error: illegal effect code\n"

break

}

/ / Зберігаємо поточний (оновлений) параметр

/ / В якості нового за замовчуванням

_channel[ch]_defaultParameter[currentNote_effect]

=thisParameter

}

/ / Зберігаємо значення за замовчуванням до наступного

/ / Рази

_channel[ch]_currentNote = currentNote

}

/ / Встановлюємо значення змінних для методу

// GetSamples

_sampleLength = _samplesPerBeat

_sampleStartLeft = _sampleBufferLeft

_sampleStartRight = _sampleBufferRight

}

Зазвичай установка нової ноти передбачає створення такої для відповідного інструменту Якщо використовується який-небудь з ефектів (тремоло або вібрато), він повинен бути скасований Найбільш важливе відмінність полягає в способі обробки ефекту поступової зміни висоти B цьому випадку нам необхідно зберегти цільове значення висоти тону і використовувати інструмент і період, задані для останньої ноти цього каналу

Лістинг 2313 Налаштування параметрів нової ноти

if (currentNote_instrument = 0) {

if ( (currentNote_effect == ModNoteData::tremolo)

&amp&amp ((_channel[ch]_defaultParameter[ModNoteData::tremolo] &amp 4)==0) )

_channel[ch]_currentTremolo = 0

if ( (currentNote_effect == ModNoteData::vibrato)

||(currentNote_effect == ModNoteData::vibratoPlusVolumeSlide)) {

if ((_channel[ch]_defaultParameter[ModNoteData::vibrato] &amp 4)==0)

_channel[ch]_currentVibrato = 0

}

if (currentNote_effect == ModNoteData::pitchSlide) {

if (currentNote_period) {

_channel[ch]_pitchGoal = currentNote_period

} else if (_channel[ch]_pitchGoal == 0) {

/ / Прикладної мети немає, так що ігноруємо цей

/ / Ефект

currentNote_effect = ModNoteData::none

currentNote_parameter = 0

}

/ / Розміщуємо реальне ставлення період / інструмент

/ / В currentNote

currentNote_period = _channel[ch]_currentNote_period

currentNote_instrument =

_channel[ch]_currentNote_instrument

}

/ / Зауваження: це не просто інакше. if (currentNote_effect = ModNoteData :: pitchSlide) {

if (_channel[ch]_liveNote) delete _channel[ch]_liveNote

_channel[ch]_liveNote =

_instrument[currentNote_instrument]-&gt NewModNote(currentNote_period)

}

}

Відтворення з ефектами

Найпростіший випадок відсутність ефектів Він найчастіше зустрічається і від-

особисто обробляється класом SampledInstrument

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів

case ModNoteData::none: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 0: арпеджіо

Даний ефект реалізує швидке програвання трійки нот Параметр розглядається як два полубайтаx  іуТри програються ноти це поточна нота, поточна нота плюс x півтонів і поточна нота плюс у напівтонів Для виконання відповідного зсуву нот я попередньо розрахував просту таблицю (див лістинг 2314)

Відзначимо одну непримітну деталь: значення змінної samplesPerBeat може без остачі не ділитися на величину samplesPerTick, так що нам слід подбати про останній тику Цикл обчислень за samplesPerTick і умова закінчення сформовані таким чином, що ми впевнені, що цикл закінчується одним тиком раніше Після цього можна програти samplesPerBeat-l тиків, що в точності відповідає частини, що залишилася такту

B відміну від багатьох інших ефектів, арпеджіо з нульовим параметромне означає,що потрібно використовувати значення, підставляється за умовчанням Навпаки, це означає, що всі три ноти однакові, тобто ефект відсутній

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::arpeggio:

{ const float halfTones[] = {

00F,     105946309F, 112246205F, 118920712F,

125992105F, 133483985F, 141421356F, 149830708F,

158740105F, 168179283F, 178179744F, 188774863F,

20F,     211892619F, 224492410F, 237841423F} AudioSample *currentSampleBuffer = sampleBuffer

float pitches[3] currentLiveNoteSetModPeriod(currentNote_period) pitches[0] = currentLiveNotePitch()

pitches[1] = pitches[0] *

halfTones[(thisParameter&gt&gt4)&amp0xF]

pitches[2] = pitches[0] * halfTones[(thisParameter&amp0xF)]

int currentPitch = 0

int i

for(i=0i&lt_samplesPerBeat-_samplesPerTick*3/

2i+=_samplesPerTick) {

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

if (++currentPitch &gt 2) currentPitch = 0

currentLiveNotePitch(pitches[currentPitch])

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

currentLiveNotePitch (pitches [0]) / / Скидаємо

/ / Початкове

/ / Значення висоти

/ / Тону

}

break

Ефект 1: наростаюче ковзання

Наростаюче ковзання, також відоме якнаростаюче портаменто (Portamento up), збільшує висоту тону після кожного тика, але не на початку або кінці кожного такту Параметр являє собою 8-бітове число, яке віднімається із значення періоду на кожному тику Згадаймо, що зменшення періоду відповідає збільшенню висоти

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::slideUp:

{

if (thisParameter == 0) thisParameter = defaultParameter AudioSample *currentSampleBuffer = sampleBuffer

int i

for(i=0i&lt_samplesPerBeat-_samplesPerTick*3/2

i+=_samplesPerTick) {

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick) currentSampleBuffer += _samplesPerTick currentNote_period -= thisParameter currentLiveNoteSetModPeriod(currentNote_period)

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

}

break

Ефект 2: спадаюче ковзання

Це в точності те ж саме, що і наростаюче ковзання, за винятком того, що висота зменшується (а період збільшується)

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::slideDown:

{

if (thisParameter == 0) thisParameter = defaultParameter AudioSample *currentSampleBuffer = sampleBuffer

int i = 0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick) currentSampleBuffer += _samplesPerTick currentNote_period += thisParameter currentLiveNoteSetModPeriod(currentNote_period)

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

}

break

Ефект З: плавна зміна висоти

Плавне зміна висоти, також відома яктонального портаменто (Tonal portamento), розглядає зазначену ноту як мета, до якої треба прийти Існуюча нота поступово змінюється до тих пір, поки не буде отримана зазначена нота Можна продовжувати зміна висоти, що не вказуючи нової ноти і не повторюючи параметрів: нульове значення параметра означає, що повинні використовуватися попередні значення

Аргумент являє собою 8-бітну величину, яка додається до періоду або віднімається з нього Якщо період досяг цільового значення, його зміна припиняється, й для подальшого використання ефектунеобхіднознову задати нове цільове значення

Лістинг 2312 Члени класу ModChannel (продовження)

public:

int _pitchGoal / / Поточний заданий період для ефекту

/ / Плавної зміни висоти тону

Лістинг 2315 Ініціалізація змінних класу ModChannel

_pitchGoal = 0

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::pitchSlide:

{

if (thisParameter == 0) thisParameter = defaultParameter AudioSample *currentSampleBuffer = sampleBuffer

int i = 0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

if (_channel[ch]_pitchGoal == 0) {

/ / Нічого не робимо

} else if (currentNote_period &gt

_channel[ch]_pitchGoal) {

currentNote_period -= thisParameter

if (currentNote_period &lt= _channel[ch]_pitchGoal) {

currentNote_period = _channel[ch]_pitchGoal

_channel[ch]_pitchGoal = 0

}

} else {

currentNote_period += thisParameter

if (currentNote_period &gt= _channel[ch]_pitchGoal) {

currentNote_period = _channel[ch]_pitchGoal

_channel[ch]_pitchGoal = 0

}

}

currentLiveNoteSetModPeriod(currentNote_period)

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

}

break

Ефект 4: вібрато

Вібрато це періодична зміна висоти тону Воно реалізується через використання 64-елементної хвильової форми для зміни періоду на кожному тику Параметр представляє собою два полубайта Старший напівбайт визначає швидкість переміщення по хвильової формі, молодший амплітуду змін

Можливо, ви звернули увагу на те, що ефекти, що змінюють період, спочатку змінюють значення змінної currentNote_period, використовуваної потім для завдання періоду Це було зроблено для того, щоб його нові дані зберігалися протягом декількох тактів B випадку з вібрато важливо зберегти базове значення періоду, щоб наступне застосування зазначеного ефекту починалося з тієї ж відправної точки З цієї причини в програмі не оновлюється значення currentNote_period

Лістинг 2312 Члени класу МоdСhаnnеl (продовження)

public:

const float * _vibratoWaveform / / Поточна форма хвилі

int _currentVibrato / / Позиція в хвильової формі

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::vibrato:

{

if (thisParameter == 0)

thisParameter = defaultParameter int step = (thisParameter &gt&gt 4)&amp0xF int amplitude = (thisParameter&amp0xF)*2

AudioSample *currentSampleBuffer = sampleBuffer

/ / Налаштовуємо вібрато

currentLiveNoteSetModPeriod(currentNote_period

+int(_channel[ch]_vibratoWaveform[_channel[ch]_currentVibrato]

*amplitude) )

/ / Зупинити вібрато

_channel[ch]_currentVibrato += step

_channel[ch]_currentVibrato &amp= 63

int i=0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

/ / Встановлюємо генератор

currentLiveNoteSetModPeriod(currentNote_period

+int(_channel[ch]_vibratoWaveform[_channel[ch]_currentVibrato]

*amplitude))

/ / Зупинити вібрато

_channel[ch]_currentVibrato += step

_channel[ch]_currentVibrato &amp = 63

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

}

break

Ефект 5: плавний зсув по висоті

з одночасним плавним зрушенням за рівнем

Даний ефект комбінує плавну зміну висоти (ефект 3) і послідовну зміну гучності Параметр для плавної зміни висоти береться з діючого значення за замовчуванням, в той час як параметр розглянутого ефекту визначає зміну гучності

Зміна висоти задається незвичайним способом Якщо старший напівбайт не дорівнює нулю, значить він визначає значення, додаємо до гучності на кожному тику Якщо старший напівбайт дорівнює нулю, то молодший визначає значення, відємник із значення гучності на кожному тику Для ефекту плавної зміни гучності немає діючого значення за замовчуванням Нульовий параметр еквівалентний нульового параметру для ефекту плавної зміни висоти (тобто просто продовжується застосування попереднього ефекту плавної зміни висоти без зміни гучності)

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::pitchSlidePlusVolumeSlide:

{

int portParameter

=

_channel[ch]_defaultParameter[ModNoteData::pitchSlide]

/ / Ні значення за замовчуванням для плавного зсуву рівня

int volumeChange = (thisParameter &amp 0xF0) (thisParameter &gt&gt 4) &amp 0xF :

-(thisParameter &amp 0xF)

AudioSample *currentSampleBuffer = sampleBuffer

int i = 0

for( i&lt_samplesPerBeat-_samplesPerTicki + =_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

/ / Налаштовуємо гучність

currentLiveNoteSetModVolume(_channel[ch]_currentVolume

+volumeChange)

/ / Зрушуємо висоту тону,

if (_channel[ch]_pitchGoal == 0) {

/ / Нічого не робимо

} else if (currentNote_period &gt

_channel[ch]_pitchGoal) {

currentNote_period -= portParameter

if (currentNote_period &lt= _channel[ch]_pitchGoal) {

currentNote_period = _channel[ch]_pitchGoal

_channel[ch]_pitchGoal = 0

}

} else {

currentNote_period += _channel[ch]_pitchGoal

if (currentNote_period &gt= _channel[ch]_pitchGoal) {

currentNote_period = _channel[ch]_pitchGoal

_channel[ch]_pitchGoal = 0

}

}

currentLiveNoteSetModPeriod(currentNote_period)

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeat-i)

}

break

Ефект 6: вібрато плюс зсув по гучності

Як і у випадку з ефектом 5, тут йде використання попереднього виклику ефекту вібрато з одночасною зміною гучності

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::vibratoPlusVolumeSlide:

{

/ / Прочитуємо параметри з останнього дзвінка вібрато int vibratoParameter

=

_channel[ch]_defaultParameter[ModNoteData::vibrato]

int step = (vibratoParameter &gt&gt 4)&amp0xF

int amplitude = (vibratoParameter&amp0xF)*2

/ / Для зсуву рівня немає значень, використовуваних

/ / За замовчуванням

int volumeChange = (thisParameter &amp 0xF0) (thisParameter &gt&gt 4) &amp 0xF :

-(thisParameter &amp 0xF) AudioSample *currentSampleBuffer = sampleBuffer

/ / Налаштовуємо вібрато

currentLiveNoteSetModPeriod(currentNote_period

+int(_channel[ch]_vibratoWaveform[_channel[ch]_currentVibrato]

*amplitude))

/ / Крок вібрато

_channel[ch]_currentVibrato += step

_channel[ch]_currentVibrato &amp= 63

int i=0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

/ / Налаштовуємо рівень

currentLiveNoteSetModVolume(_channel[ch]_currentVolume

+volumeChange)

/ / Налаштовуємо вібрато

currentLiveNoteSetModPeriod(currentNote_period

+int(_channel[ch]_vibratoWaveform[_channel[ch]_currentVibrato]

*amplitude))

/ / Крок вібрато

_channel[ch]_currentVibrato += step

_channel[ch]_currentVibrato &amp= 63

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeat-i)

}

break

Ефект 7: тремоло

Ефект тремоло дуже схожий на вібрато, за винятком того, що замість зміни періоду відбувається зміна гучності Є одна особливість амплітуда множиться на 4, а не на 2

Лістинг 2312 Члени класу ModChannel (продовження)

public:

const float * _tremoloWaveform / / Використовувана хвильова форма

int _currentTremolo / / Положення в цій хвильової

/ / Формі

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::tremolo:

/ / Застосовано ефект тремоло cerr << "Effect tremolo exercised. \ N";

{

if (thisParameter == 0)

thisParameter = defaultParameter

int step = (thisParameter &gt&gt 4)&amp0xF

int amplitude = (thisParameter&amp0xF)*2*2 AudioSample *currentSampleBuffer = sampleBuffer

/ / Встановлюємо гучність

currentLiveNoteSetModVolume(_channel[ch]_currentVolume

+int(_channel[ch]_tremoloWaveform[_channel[ch]_currentTremolo]

*amplitude))

/ / Крок тремоло

_channel[ch]_currentTremolo += step

_channel[ch]_currentTremolo &amp= 63

int i=0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

/ / Встановлюємо гучність

currentLiveNoteSetModVolume(_channel[ch]_currentVolume

+int(_channel[ch]_tremoloWaveform[_channel[ch]_currentTremolo]

*amplitude))

/ / Крок тремоло

_channel[ch]_currentTremolo += step

_channel[ch]_currentTremolo &amp= 63

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeat-i)

}

break

Ефект 8: не використовується

Ефекту з порядковим номером 8 немає

Ефект 9: зміна зсуву в семплі

Ефект дозволяє вам змінювати в семплі положення точки, з якої починається відтворення ноти Ця можливість може використовуватися для створення ряду корисних ефектів Наприклад, ви могли б зберегти кілька звуків ударних інструментів в одному семплі і для формування різних звуків починати відтворення з різних точок Крім того, ви можете помякшити звучання інструменту, пропустивши період початкової атаки

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setSampleOffset: currentLiveNoteRestart() currentLiveNoteSetSampleOffset(thisParameter*512) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 10: плавна зміна гучності

Я вже говорив, що параметр для ефекту плавної зміни гучності задається дещо незвичним способом Як і більшість ефектів, застосування яких здійснюється на кожному тику, зміни гучності не відбувається на початку або кінці такту

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::volumeSlide:

{

AudioSample *currentSampleBuffer = sampleBuffer

int volumeChange = (thisParameter &amp 0xF0) (thisParameter &gt&gt 4) &amp 0xF :

-(thisParameter &amp 0xF)

int i = 0

for(i&lt_samplesPerBeat-_samplesPerTicki+=_samplesPerTick)

{

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerTick)

currentSampleBuffer += _samplesPerTick

_channel[ch]_currentVolume += volumeChange

currentLiveNoteSetModVolume(_channel[ch]_currentVolume)

}

currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeat-i)

}

break

Ефект 11: дальній перехід

Далекий перехід, також званийпереходом позиції(Positionjump), головним чином використовується для створення зациклених (програються нескінченну кількість разів) музичних творів Він може використовуватися і для завершення програвання поточного трафарету, однак у таких випадках зазвичай застосовується ближній перехід (ефект 13)

Далекий перехід обробляється на початку методу PlayBeat, так як він впливає на весь процес відтворення Програвання здійснюється так само, як і для none

Лістинг 2316 Накладення глобальних ефектів для поточної ноти

case ModNoteData::farJump:

_songNextIndex (currentNote_parameter) / / Переходимо

/ / На цей трафарет

_songNextBeat (0) / / На такті 0

break

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::farJump: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 12: налаштування гучності

Цей ефект просто встановлює гучність вказаним значенням Зауважимо, що він перевизначає використовується за умовчанням значення гучності для даного інструменту

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setVolume:

currentLiveNoteSetModVolume(thisParameter)

_channel[ch]_currentVolume=thisParameter currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 13: розрив трафарету (ближній перехід)

Близький перехід, також відомий якрозрив трафарету (Pattern break), використовується для передчасного переривання відтворення поточного трафарету Параметр являє собою двійковій-десяткове число, що застосовується для завдання такту, з якого має розпочатися відтворення наступного трафарету Зазвичай цей параметр дорівнює нулю Незважаючи на те що 64-тактовий трафарет підходить для музичного розміру 4:4, такий трафарет менш придатний для розмірів 3:4, 6:8 чи інших Близький перехід корисний для передчасного закінчення відтворення трафарету Це дозволяє створити враження, що довжина трафарету відмінна від стандартної

Лістинг 2316 Накладення глобальних ефектів для поточної ноти

(Продовження)

case ModNoteData::smallJump:

_songAdvanceNextIndex () / / Перехід на наступний трафарет

_songNextBeat((currentNote_parameter&gt&gt4)*10

+ (CurrentNote_parameter & 0x0F)) / / Ha цьому такті

break

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::smallJump: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/0: установка фільтра

Якщо перший напівбайт цього 12-бітного ефекту дорівнює 14, то другий напів-

байт задає ефект, а третій значення аргументу

Ефект установки фільтра активує або дезактивує фільтр низьких (до

4000 Гц) частот фірми Amiga для вихідного сигналу Так як моделювання фільтра програмним способом забирає багато часу і доступно не на всіх звукових картах, цей ефект не надто поширений і нечасто реалізується

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setFilter:

/ / Ефект установки фільтра не реалізований

cerr &lt&lt &quotEffect setFilter not implemented\n" currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/1: повільний наростаючий зсув

Даний ефект використовується для реалізації невеликих коригувань періоду B відміну від звичайного ефекту наростаючого зсуву, цей ефект оновлює значення періоду один раз на початку такту Він часто використовується для створення ефекту плавної зміни висоти тону, звідси і назва

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::pitchUp:

/ / Ефект підвищення висоти тону реалізований

cerr &lt&lt &quotEffect pitchUp exercised\n" currentNote_period -= thisParameter currentLiveNoteSetModPeriod(currentNote_period) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/2: повільний спадаючий зрушення

Це те ж саме, що і повільний наростаючий зсув, за винятком того,

що відбувається зменшення висоти (збільшення періоду)

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::pitchDown:

/ / Ефект пониження тону реалізований

cerr &lt&lt &quotEffect pitchDown exercised\n" currentNote_period += thisParameter currentLiveNoteSetModPeriod(currentNote_period) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/3: гліссандо

Даний ефект впливає на роботу ефекту 3 (плавний перехід однієї ноти в іншу) Якщо параметр не дорівнює нулю, при послідовних зверненнях до цього ефекту буде завжди відтворюватися найближча нота Якщо параметр дорівнює нулю, то буде плавно змінюватися тривалість періоду

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setGlissando:

/ / Ефект установки гліссандо не реалізований.

cerr &lt&lt &quotEffect setGlissando not implemented\n" currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/4: налаштування хвильової форми вібрато

Ефекти вібрато і тремоло використовують 64-елементну хвильову форму Можна застосовувати три хвильові форми: синусоїдальну, прямокутну і пилкоподібну Ці три форми вибираються відповідно числами 0, 1 і 2 Крім

того, аргумент рівний трьом призначений для випадкового вибору однієї з цих форм Проте, так як цей варіант майже ніколи не використовується, я зробив його еквівалентним варіанту 0 Якщо будь-яке з цих значень збільшити на 4, буде обрана та ж хвильова форма, але не відбуватиметься повторна ініціалізація ефекту на початку кожної нової ноти

Лістинг 2312 Члени класу ModChannel (продовження)

public:

static const float _waveform[3][64]

/ / Бібліотека хвильових форм

Лістинг 2317 Хвильові форми для вібрато і тремоло

/ / Хвильові форми для вібрато (зміна висоти тону)

/ / І тремоло (зміна рівня)

static float vibratoTremoloWaveforms[3][64] = {

/ / Синусоїда

{00F, 09802F,19509F,29028F,38268F,47140F,55557F,

.63439F,70711F,77301F,83147F,88192F,92388F,95694F,

.98079F,99518F,100000F,99518F,98079F,95694F,92388F,

.88192F,83147F,77301F,70711F,63439F,55557F,47140F,

.38268F,29028F,19509F,09802F,-00000F,-09802F,-19509F,

-29028F,-38268F,-47140F,-55557F,-63439F,-70711F,

-77301F,

-83147F,-88192F,-92388F,-95694F,-98079F,-99518F,-10F,

-99518F,-98079F,-95694F,-92388F,-88192F,-83147F,

-77301F,

-70711F,-63439F,-55557F,-47140F,-38268F,-29028F,

-19509F,

-09802F },

/ / Прямокутна хвиля: 32×1, потім 32x-1

{10F, 10F, 10F, 10F, 10F, 10F, 10F, 10F,

10F, 10F, 10F, 10F, 10F, 10F, 10F, 10F,

10F, 10F, 10F, 10F, 10F, 10F, 10F, 10F,

10F, 10F, 10F, 10F, 10F, 10F, 10F, 10F,

-10F,-10F,-10F,-10F,-10F,-10F,-10F,-10F,

-10F,-10F,-10F,-10F,-10F,-10F,-10F,-10F,

-10F,-10F,-10F,-10F,-10F,-10F,-10F,-10F,

-10F,-10F,-10F,-10F,-10F,-10F,-10F,-10F },

/ / Пилкоподібня хвиля: 0 -> 1, потім -1 -> 0

{00F, 03125F,06250F,09375F,12500F,15625F,18750F,

.21875F,25000F,28125F,31250F,34375F,37500F,40625F,

.43750F,46875F,50000F,53125F,56250F,59375F,62500F,

.65625F,68750F,71875F,75000F,78125F,81250F,84375F,

.87500F,90625F,93750F,96875F

-10F,-96875F,-93750F,-90625F,-87500F,-84375F,-81250F,

-78125F,-75000F,-71875F,-68750F,-65625F,-62500F,

-59375F,

-56250F,-53125F,-50000F,-46875F,-43750F,-40625F,

-37500F,

-34375F,-31250F,-28125F,-25000F,-21875F,-18750F,

-15625F,

-12500F,-09375F,-06250F,-03125F }

}

Лістинг 2315 Ініціалізація змінних класу ModChannel

(Продовження)

_vibratoWaveform = &amp(vibratoTremoloWaveforms[0][0])

_currentVibrato = 0

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setVibrato:

/ / Реалізовано ефект установки Vibrato

cerr &lt&lt &quotEffect setVibrato exercised\n"

/ / Результат випадкового вибору завжди 0

if ((thisParameter &amp 3) == 3) thisParameter &amp = 4

_channel[ch]_vibratoWaveform

= &amp(vibratoTremoloWaveforms[thisParameter &amp 0x3][0]) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/5: точна настройка

Цей ефект дозволяє змінювати параметр точного налаштування для кожної ноти

Використовується рідко

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setFinetune:

/ / Ефект setFinetune не реалізований

cerr &lt&lt &quotEffect setFinetune not implemented\n" currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/6: зациклення трафарету

Якщо параметр дорівнює нулю, то цей ефект відзначає початок циклу Якщо параметр не дорівнює нулю, то відзначається кінець циклу B розглянутому випадку параметр визначає кількість необхідних повторень циклу

Лістинг 2316 Накладення глобальнихеффектов для поточної ноти (продовження)

case ModNoteData::patternLoop:

/ / Підтримка циклічних ефектів для трафаретів

/ / Не реалізована

cerr &lt&lt &quotLoop pattern effect not implemented\n"

break

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::patternLoop: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/7: налаштування параметрів хвильової форми тремоло

Цей ефект ідентичний ефекту налаштування параметрів хвильової форми виб-

Рато (ефект 14/4), але впливає на хвильову форму тремоло

Лістинг 2315 Ініціалізація змінних класу ModChannel

(Продовження)

_tremoloWaveform = &amp(vibratoTremoloWaveforms[0][0])

_currentTremolo = 0

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setTremolo:

/ / Ефект налаштування тремоло реалізований

cerr &lt&lt &quotEffect setTremolo exercised\n"

/ / При випадковому виборі завжди 0

if ((thisParameter &amp 3) == 3) thisParameter &amp= 4

_channel[ch]_tremoloWaveform

= &amp(vibratoTremoloWaveforms[thisParameter &amp 0x3][0]) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/8: не використовується

Ефекту з таким номером немає

Ефект 14/9: повторний запуск

Серію швидких ударів в барабан або дріб можна отримати шляхом періодичної ініціалізації ноти під час такту Ефект повторного запуску використовує параметри, що задають частоту повторної ініціалізації ноти (в тиках) B своїй програмі я обчислюю величину samplesPerTick кількість відліків, які необхідно програти до наступної повторної ініціалізації

Лістинг 2314 Воспроізведеніеноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::retrigger:

/ / Перезапуск ноти кілька разів

{

if (thisParameter == 0) thisParameter = defaultParameter AudioSample *currentSampleBuffer = sampleBuffer

int samplesPerNote = _samplesPerTick * thisParameter

int i=0

for(i&lt_samplesPerBeat-samplesPerNote-_samplesPerTick/2

;i+=samplesPerNote) {

currentLiveNoteAddSamples(currentSampleBuffer,samplesPerNote) currentSampleBuffer += samplesPerNote currentLiveNoteRestart()

} currentLiveNoteAddSamples(currentSampleBuffer,_samplesPerBeati)

}

break

Ефект 14/10: збільшення гучності

Вельми нагадує ефект повільного висхідного зсуву (ефект 14/1), але змінює гучність

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::volumeUp:

_channel[ch]_currentVolume += thisParameter currentLiveNoteSetModVolume(_channel[ch]_currentVolume) currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/11: зменшення гучності

To ж, що і попередній ефект, тільки рівень знижується

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::volumeDown:

/ / Ефект зменшення гучності реалізований

cerr &lt&lt &quotEffect volumeDown exercised\n"

currentLiveNoteSetModVolume(_channel[ch]_currentVolumethisParameter)

currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat)

break

Ефект 14/12: укорочення нот

Гучність ноти зменшується до нуля після програвання заданої кількості тиків Важливо продовжувати програвання ноти після зменшення гучності, так як в наступному такті гучність знову може збільшитися Хоча для такого інструменту, як фортепіано, застосування цього ефекту малорезультативно, 14/12 також може використовуватися для добування одного барабанного удару з семпла

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::cutNote:

/ / Відтворюємо parameter тактів, потім знижуємо рівень

/ / До 0 і продовжуємо відтворення

cerr &lt&lt &quotEffect cutNote exercised\n"

{

if (thisParameter == 0) thisParameter = defaultParameter

int playSamples = _samplesPerTick * thisParameter

if (playSamples &lt _samplesPerBeat) {

currentLiveNoteAddSamples(sampleBuffer, playSamples)

_channel[ch]_currentVolume = 0

currentLiveNoteSetModVolume(_channel[ch]_currentVolume)

currentLiveNoteAddSamples(sampleBuffer+playSamples,

_samplesPerBeat-playSamples)

} Else {/ / Відтворити такт цілком

currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat)

}

}

break

Ефект 14/13: затримка відтворення ноти

Ефект затримки відтворення ноти не починає програвання ноти до тих пір, поки не пройде задану кількість тиків Деякі нові формати MOD злегка перекривають однойменні цей ефект: зміна ноти не відбуватиметься, поки не пройде задану кількість тактів При цьому потрібно продовження програвання попередньої ноти на початку такту

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::delayNote:

{

if (thisParameter == 0) thisParameter = defaultParameter

int skipSamples = _samplesPerTick * thisParameter

if (skipSamples &lt _samplesPerBeat)

currentLiveNoteAddSamples(sampleBuffer+skipSamples,

_samplesPerBeat-skipSamples)

}

break

Ефект 14/14: затримка відтворення трафарету

Цей ефект змушує перед програванням чергового такту повторити програвання попереднього задане число разів Зауважимо, що глобальні ефекти попереднього такту не використовуються He ясно, що має відбуватися, якщо в одному і тому ж такті зустрічаються кілька подібних ефектів

Для реалізації даного ефекту я додав в статусну інформацію каналу

змінну delayPatternCount Мінлива приймає негативне значення, якщо ефект затримки не присутня Якщо значення змінної позитивно, воно показує залишився кількість повторень Якщо воно дорівнює нулю, значить ефект повністю реалізований і можна переходити до програвання поточного такту

Лістинг 2312 Члени класу ModChannel (продовження)

public:

int _delayPatternCount / /> = 0, якщо задіяний ефект

/ / Затримки відтворення

/ / Трафарету

Лістинг 2315 Ініціалізація переменнихкласса МоdСhаnnеl

(Продовження)

_delayPatternCount = -1

Лістинг 2316 Накладення глобальнихеффектовдля поточної ноти

(Продовження)

case ModNoteData::delayPattern:

/ / Затримка трафарету це, по суті, цикл в один такт

if (_channel [ch0] _delayPatternCount <0) {/ / Починаємо

/ / Новий цикл

/ / Затримки

_channel[ch0]_delayPatternCount =

currentNote_parameter

}

if (_channel [ch0] _delayPatternCount> 0) {/ / Позитивний

/ / Рахунок

_songBack()

_channel [ch0] _delayPatternCount- / / Рахунок

/ / Затримується

} else {

_channel[ch0]_delayPatternCount = -1

/ / Більше затримка

/ / Не потрібна

}

break

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::delayPattern: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 14/15: інвертуючий цикл

Цей ефект є гарним прикладом винахідливості, що проявляється програмістами при розробці цікавих звукових ефектів Він задає два циклу: перший звичайний цикл відтворення, що вибирає і що програє відліки другий цикл переміщення по звуковим даними на більш повільній швидкості, при якому відбувається інвертування значень відліків Реалізуються два цікавих ефекту: звукові дані змінюються в міру відтворення, і деяка область звукових даних інвертується Точний ефект варіюється залежно від довжини області повторення звукових даних і швидкості циклу инвертирования По суті, звук комбінується із змінною прямокутної хвилею

Параметр приймає значення приросту з табл 237 Ha кожному тику це прирощення додається до лічильника Коли значення лічильника перевищує 128, наступна вибірка області повторення інвертується Після досягнення кінця області повторення цикл триває з її початку Ця процедура триває доти, поки активізований ефект инвертирующего циклу

Через свою складність цей ефект реалізується не часто

Таблиця 237 Прирости для ефекту инвертирующего циклу

Параметр0

1

2

3

4

5      6      7      8      9       10    11    12    13    14    15

Прирощення0

5

6

7

8

10    11    13    16    19    22    26    32    43    64    128

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::invertLoop:

/ / Ефект инвертирующего циклу не реалізований

cerr &lt&lt &quotEffect invertLoop not implemented\n" currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Ефект 15: установка швидкості

Програвачі MOD використовують два параметри, повязаних зі швидкістю Перший частота проходження тиків, другий кількість тиків на такт Параметр, залежно від свого значення, реалізує різні ефекти:

 ‰  ÐμÑ Ð »Ð ¸  Р¿Ð ° Ñ € Ð ° Ð ¼ ÐμÑ, Ñ € Â Ñ € Ð ° Ð ² ÐμÐ ½  Р½ ул ÑŽ,  Р² Ð ¾ Ñ Ð ¿Ñ € Ð ¾ Ð ¸ Ð · Ð ² ÐμÐÐμÐ ½ Ð ¸ Ðμ  Р¼ уР· Ñ ​​<Ð º Ð ° Ð »ÑŒÐ ½ Ð ¾ Ð ³ Ð ¾   Р¿Ñ € Ð ¾ Ð ¸ Ð · Ð ² ÐμÐ'ÐμÐ ½ Ð ¸ Ñ Ð ¿Ñ € Ð ¸ Ð ¾ Ñ Ñ, Ð ° Ð ½ Ð ° Ð ² л Ð ¸ Ð ² Ð ° ÐμÑ, Ñ Ñ;

 ‰  ÐμÑ Ð »Ð ¸ Ð ¿Ð ° Ñ € Ð ° Ð ¼ ÐμÑ, Ñ € Ð ¼ ÐμÐ ½ ÑŒÑÐμ Ð ¸ л Ð ¸ Ñ € Ð ° Ð ² ÐμÐ ½ 32, Ð ¾ Ð ½ Ð ¾ Ð ¿Ñ € ÐμÐÐμÐ »Ñ ÐμÑ, Ð º Ð ¾ л Ð ¸ Ñ ​​‡ ÐμÑ Ñ, Ð ² Ð ¾ Ñ, Ð ¸ Ð º Ð ¾ Ð ² Ð ½ Ð ° Ñ, Ð ° Ð º Ñ,

 ‰  ÐμÑ Ð »Ð ¸ Ð ¿Ð ° Ñ € Ð ° Ð ¼ ÐμÑ, Ñ € Ð ± Ð ¾ л ÑŒÑÐμ 32, Ð ¾ Ð ½ Ð · Ð ° ÐÐ ° ÐμÑ, Ð º Ð ¾ Ð »Ð ¸ Ñ ‡ ÐμÑ Ñ, Ð ² Ð ¾ Ñ, Ð ¸ Ð º Ð ¾ Ð ² Ð ² Ñ ÐμÐ º уР½ Ðу, Ð ¿Ñ € Ð ¸ Ñ Ñ, Ð ¾ Ð ¼

використовується угоду, що значення 125 являє стандартну ско-

рость прямування тиків 50 тиків в секунду

Лістинг 2316 Накладення глобальнихеффектов для поточної ноти (продовження)

case ModNoteData::setTempo:

if (currentNote_parameter == 0) {/ / Зупинити пісню

/ / Застосована установка

/ / Нульового темпу

cerr &lt&lt &quotSet tempo 0 exercised\n"

_songStop()

_sampleLength = 0

return

} else if (currentNote_parameter &lt= 32) {

/ / Встановлюємо

/ / Кількість тиків на біт

_ticksPerBeat = currentNote_parameter

} Else {/ / Встановлюємо швидкість

_ticksPerMinute = 50L * 60 * currentNote_parameter/125

}

break

}

}

Лістинг 2314 Відтворення ноти currentLiveNote

з накладенням ефектів (продовження)

case ModNoteData::setTempo: currentLiveNoteAddSamples(sampleBuffer,_samplesPerBeat) break

Джерело: Кінтцель Т Керівництво програміста по роботі зі звуком = A Programmers Guide to Sound: Пер з англ М: ДМК Пресс, 2000 432 с, іл (Серія «Для програмістів»)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*