Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Частотная таблица с нулевой погрешностью

Радиолюбитель. Ваш компьютер» 6/2001, «Радиомир. Ваш компьютер» 7,8/2001 (под псевдонимом BV_Creator)).
Дата последнего редактирования: 14.02.2003.

Экскурс в историю
К дням сегодняшним
Проблема получает неожиданное решение
От теории к практике
Процедура построения частотной таблицы
Литература

Музыка — это бессознательное упражнение души в арифметике.
Г.Лейбниц

Экскурс в историю

Давно было замечено, что частоты, находящиеся между собой в простых числовых соотношениях, наиболее приятны для слуха. Основываясь на этом, древние музыканты настраивали свои инструменты так, чтобы соотношения звуков в октаве представляли собой соотношения небольших целых чисел (рис. 1). Будем называть такой звукоряд природным.

Рис. 1

На инструменте, настроенном в соответствии с природным звукорядом, нельзя было сыграть мелодию, скажем, на тон выше или ниже. Для игры в другой тональности его надо было перенастраивать. Чтобы как-то преодолеть это неудобство, в октаву добавили пять дополнительных звуков — там, где интервал между основными звуками равнялся целому тону (8/9 или 9/10). Но это не до конца решило проблему: не из любой тональности в любую можно было переходить легко и просто.

Около VI—V вв. до н.э. за решение этой задачи взялся Пифагор (он был не только учёным, но и блестящим музыкантом). Немного изменив частоты трёх из семи нот в октаве и точно рассчитав частоты дополнительных звуков, он обеспечил музыкантам возможность переходить из тональности в тональность гораздо свободнее. Но всё-таки некоторая необходимость перенастройки инструментов оставалась.

В конце XVII века состоялась новая реформа музыкального строя: немецкий органист Андреас Веркмейстер предложил сделать соотношения между частотами соседних звуков одинаковыми и равными 21/12. С одной стороны, это было полным и окончательным решением проблемы перехода из тональности в тональность без перенастройки инструмента. С другой стороны, после этой реформы в октаве не осталось ни одного целочисленного соотношения — каждая нота немного фальшивила. Поэтому многих музыкантов поначалу возмутило предложение Веркмейстера. Но в конце концов соображения удобства перевесили, и такой звукоряд (называемый темперированным) используется и по сей день.

К дням сегодняшним

После изобретения Веркмейстером своего звукоряда прошло почти три столетия, когда не менее великий изобретатель, сэр Клайв Синклер, выпустил свой знаменитый ZX Spectrum 128 с музыкальным сопроцессором.

Частота на выходе каждого из трёх имеющихся в сопроцессоре генераторов тона получается путём деления тактовой частоты на 16 и последующего деления на целое число в диапазоне 1—4095. Это число называется коэффициентом деления.

Ниже приведены формулы, связывающие тактовую частоту сопроцессора (CLK), коэффициент деления (k) и частоту на выходе (F). Пользуясь ими, можно вычислить каждую из этих трёх величин по двум другим, значения которых известны.

F = CLK/(16 k) (*)
k = [CLK/(16 F) + 0.5] (**)
CLK = 16 F k (***)

Во всех музыкальных редакторах для ZX Spectrum, которые я видел (Sound Tracker, ASC Sound Master, Pro Tracker, Pro Sound Creator и др.) используется темперированный звукоряд. Сразу же, не производя каких-либо вычислений, можно сказать, что этот звукоряд воспроизводим сопроцессором лишь с определённой погрешностью. Действительно, отношение частот любых двух соседних звуков в нём — 21/12 — число иррациональное, и по определению не может быть представлено в виде частного двух целых чисел. В то же время любые две частоты, сформированные сопроцессором, будут относиться друг к другу именно как целые числа: из формулы (*) непосредственно следует, что F1/F2=k2/k1.

Погрешность можно уменьшить, увеличивая тактовую частоту сопроцессора [4], но полностью избавиться от неё принципиально невозможно.

В темперированном звукоряде и так каждая нота немного фальшивит, а когда заложенная в нём погрешность складывается с погрешностью его реализации на сопроцессоре (табл. 1), результат не может удовлетворить даже невзыскательного слушателя.

Табл. 1
Нота Частота, Гц
Натуральный
звукоряд
Темперированный
звукоряд
Наилучшее приближение
к темперированному
звукоряду для AY (YM)
при CLK=1,75 МГц
A–1440,0440,0439,3
B–1495,0493,9494,9
C–2528,0523,3523,3
D–2594,0587,3588,0
E–2660,0659,3658,9
F–2704,0698,5696,7
G–2792,0784,0781,3
A–2880,0880,0882,1

Проблема получает неожиданное решение

Любые две частоты, сформированные сопроцессором, относятся друг к другу как целые числа. Да ведь это как раз то, что нужно для реализации природного звукоряда!

Посмотрим на рис. 1 и, учитывая, что между коэффициентом деления и частотой на выходе сопроцессора существует обратная зависимость, выпишем соотношения коэффициентов деления для нот от «ля» одной октавы до «ля» следующей октавы:

ka/kb  = 9/8, (1)
kb/kc  = 16/15, (2)
kc/kd  = 9/8, (3)
kd/ke  = 10/9, (4)
ke/kf  = 16/15, (5)
kf/kg  = 9/8, (6)
kg/ka'  = 10/9. (7)

Попробуем подобрать минимальный набор коэффициентов ka, kb, …, kg, который удовлетворял бы этим соотношениям.

Коэффициенты, как мы помним, должны быть целыми. Чтобы выполнялось равенство (1), возьмём ka=9, kb=8. Из (2) следует, что kb должно делиться на 16. Удвоим начальные значения первых двух коэффициентов, что не изменит соотношения между ними: ka=18, kb=16. Тогда kc=15. Но kc должно делиться на 9 — этого требует условие (3). Утроим коэффициенты: ka=54, kb=48, kc=45. Тогда kd=45*8/9=40. Из равенства (4) получаем ke=40*9/10=36. Из (5) следует, что ke должно делиться на 16. Для этого умножим коэффициенты на четыре: ka=216, kb=192, kc=180, kd=160, ke=144. Тогда kf=144*15/16=135. Ну и, наконец, kg=135*9/10=120.

Итак, требуемый набор коэффициентов деления получен: 216, 192, 180, 160, 144, 135, 120. Первый коэффициент, ka, соответствует ноте «ля» — именно она раньше считалась первой нотой октавы. В буквенных обозначениях нот (A, B, C, D, E, F, G) это сохранилось до сих пор. Сохранилась и эталонная нота — «ля» первой октавы (440 Гц). Теперь принято начинать октаву с ноты «до». В соответствии с этим представим набор коэффициентов так, чтобы он начинался с kc, а ka и kb разделим на два и переместим в конец: 180, 160, 144, 135, 120, 108, 96.

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

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

Табл. 2
384034563072
2880256023042160192017281536
1440128011521080960864768
720640576540480432384
360320288270240216192
18016014413512010896
90807267,5605448
45403633,75302724
22,5201816,8751513,512
11,251098,43757,56,756
5,62554,54,21883,753,3753
2,81252,52,252,10941,8751,68751,5
1,40631,251,1251,0547

Теперь, учитывая, что коэффициенты должны быть целыми, выполним округление. Округлённые значения пометим подчёркиванием. Заодно выделим жирным шрифтом значения, кратные 16 (зачем это нужно, я объясню в дальнейшем).

Табл. 3
CDEFGAB
38403456 3072
288025602304 2160192017281536
144012801152 1080960864768
720640576540 480432384
360320288270 240216192
180160144135 12010896
90807268 605448
4540363430 2724
23201817151412
111098876
655 4433
3322222
11 11

Что можно сказать, взглянув на эту таблицу? Она содержит 84 значения коэффициентов, соответствующие 84 нотам. Это 11 полных октав и две неполные. 59 нот звучат абсолютно точно, а оставшиеся 25 — фальшивые. В начале таблицы имеется непрерывный участок из 41 ноты, звучащих без погрешностей. Это почти шесть октав — такого диапазона достаточно для проигрывания значительной части музыкальных произведений.

Зачем мы отмечали в таблице значения, кратные 16? Вспомним, что сопроцессор может формировать звуки не только с помощью генераторов тона, но и с помощью генератора огибающей. Частота тона зависит от делителя частоты тона, а частота огибающей, соответственно, от делителя частоты огибающей. Разница в том, что при работе генератора огибающей тактовая частота вначале делится не на 16, а на 256. Как видим, частота огибающей регулируется более грубо, нежели частота тона. Из-за этого звуки, получаемые с помощью генератора огибающей, обычно довольно сильно фальшивят, и музыканты избегают их использовать. Так вот, отмеченные нами значения соответствуют звукам, которые могут быть получены с помощью генератора огибающей без какой-либо погрешности! Как нетрудно догадаться, значение делителя огибающей при их воспроизведении будет ровно в 16 раз меньше, чем значение в таблице. С помощью генератора огибающей можно получать точные звуки и в более низких октавах, вплоть до нижней границы слышимости, ведь значение делителя огибающей может находиться в диапазоне 1—65535.


Определимся теперь с тактовой частотой сопроцессора. Её нетрудно вычислить, зная, что частота ноты «ля» первой октавы равна 440 Гц, зная коэффициент деления, соответствующий этой ноте, и используя формулу (***).

Напомню, что октавы именуются в таком порядке (снизу вверх): субконтроктава, контроктава, большая, малая, первая, вторая, третья, четвёртая и пятая. Первая октава, считающаяся наиболее употребительной, находится примерно в середине звукоряда.

Где в таблице находится коэффициент, соответствующий ноте «ля» первой октавы? Очевидно, в столбце «A» — именно таково буквенное обозначение этой ноты. А вот в какой строке? Строку мы можем выбрать сами, руководствуясь тем, чтобы используемые в мелодии ноты попали на область значений с нулевой погрешностью.

Для примера рассчитаем тактовую частоту сопроцессора, если первой октаве соответствует пятая сверху строка таблицы:

CLK = 16*440*216 = 1520640 Гц.

Если бы мы выбрали не пятую, а четвёртую строку сверху, то значение CLK было бы вдвое больше. А если шестую строку сверху, то вдвое меньше.

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

Если мы хотим иметь возможность проиграть любую мелодию, начиная с любого звука октавы (о чём, собственно, и мечтали древние музыканты), и если считать базовым значением тактовой частоты 1520640 Гц, то нам понадобится такой набор частот:

Табл. 4
ТональностьCLK, Гц
до мажор1520640
ре мажор1520640*9/8 = 1710720
ми мажор1710720*10/9 = 1900800
фа мажор1900800*16/15 = 2027520
соль мажор2027520*9/8 = 2280960
ля мажор2280960*10/9 = 2534400
си мажор2534400*9/8 = 2851200
ля минор1520640#
си минор1520640*9/8 = 1710720#
до минор1710720*16/15 = 1824768
ре минор1824768*9/8 = 2052864
ми минор2052864*10/9 = 2280960#
фа минор2280960*16/15 = 2433024
соль минор2433024*9/8 = 2737152

Итого одиннадцать различных частот, так как три значения повторяются в таблице дважды (они помечены символом «#»). Для того, чтобы можно было смещать диапазон нот с нулевой погрешностью на октаву вверх или вниз, подстраиваясь под конкретную мелодию, потребуются ещё вдвое большие и вдвое меньшие значения.

Если требуется исполнять произведения во всех двадцати четырёх тональностях — двенадцати мажорных и двенадцати минорных — видимо, наиболее оптимально будет сделать так, чтобы для каждой следующей тональности тактовая частота была в 21/12 раза больше, чем для предыдущей. При этом потребуется всего двенадцать различных значений CLK:

Табл. 5
ТональностьCLK, Гц
до мажор, ля минор1520640
до-диез мажор, ля-диез минор1611062
ре мажор, си минор1706861
ре-диез мажор, до минор1808356
ми мажор, до-диез минор1915886
фа мажор, ре минор2029811
фа-диез мажор, ре-диез минор2150510
соль мажор, ми минор2278386
соль-диез мажор, фа минор2413866
ля мажор, фа-диез минор2557401
ля-диез мажор, соль минор2709472
си мажор, соль-диез минор2870586

Как видим, для проигрывания музыки в различных тональностях при использовании натурального звукоряда с нулевой погрешностью требуется аппаратная доработка, позволяющая изменять тактовую частоту сопроцессора. (Нечто подобное было описано в [4], только в нашем случае возможных значений CLK должно быть не два, а больше, и переключение должно осуществляться не вручную, а посредством записи определённого значения в определённый порт.) Если же вы не собираетесь изменять эту частоту, и она равна 1750000 Гц (как в моём «Пентагоне», да и во многих других моделях спектрум-совместимых компьютеров), то вы сможете исполнять музыку лишь в некоторой средней тональности между ре мажор и ре-диез мажор (или между си минор и до минор), как следует из табл. 5.

От теории к практике

С помощью чего вы будете сочинять и проигрывать музыку? Очевидно, с помощью музыкального редактора. Наиболее популярным редактором в настоящее время является Pro Tracker (далее PT) — о нём и поговорим.

Доступный в PT диапазон — восемь октав: от контроктавы до пятой октавы. В редакторе они обозначаются цифрами от 1 до 8. Сопоставим им первые восемь полных строк из таблицы 3. В этих строках подчёркнуты лишь пять значений из 56 — а значит, только пять нот будут фальшивыми: F–6, F–7, C–8, F–8 и A–8 (номера октав здесь указаны так, как принято в PT). Все остальные ноты будут звучать с нулевой погрешностью.

Информация о том, какой коэффициент деления соответствует каждой ноте, содержится внутри PT в специальной таблице (её называют частотной). Под каждое значение коэффициента отводится два байта; количество коэффициентов — 12*8=96, отсюда размер таблицы — 192 байта.

Создадим нужную нам частотную таблицу с помощью ассемблера. Значения коэффициентов, как уже упоминалось, будем брать из первых восьми полных строк таблицы 3. Так как при использовании натурального звукоряда дополнительные звуки (C#, D#, F#, G#, A#) не нужны, сделаем соответствующие им коэффициенты нулевыми.

ORG #8000

DW  2880,0,2560,0,2304,2160,0,1920,0,1728,0,1536
DW  1440,0,1280,0,1152,1080,0,960,0,864,0,768
DW  720,0,640,0,576,540,0,480,0,432,0,384
DW  360,0,320,0,288,270,0,240,0,216,0,192
DW  180,0,160,0,144,135,0,120,0,108,0,96
DW  90,0,80,0,72,68,0,60,0,54,0,48
DW  45,0,40,0,36,34,0,30,0,27,0,24
DW  23,0,20,0,18,17,0,15,0,14,0,12

Этот текст надо откомпилировать и записать объектный код в файл «table.C». Ну а если вы не умеете пользоваться ассемблером, можете создать файл с частотной таблицей в любом hex-редакторе по нижеприведённому дампу:

#0000: 400B 0000 000A 0000 0009 7008 0000 8007
#0010: 0000 C006 0000 0006 A005 0000 0005 0000
#0020: 8004 3804 0000 C003 0000 6003 0000 0003
#0030: D002 0000 8002 0000 4002 1C02 0000 E001
#0040: 0000 B001 0000 8001 6801 0000 4001 0000
#0050: 2001 0E01 0000 F000 0000 D800 0000 C000
#0060: B400 0000 A000 0000 9000 8700 0000 7800
#0070: 0000 6C00 0000 6000 5A00 0000 5000 0000
#0080: 4800 4400 0000 3C00 0000 3600 0000 3000
#0090: 2D00 0000 2800 0000 2400 2200 0000 1E00
#00A0: 0000 1B00 0000 1800 1700 0000 1400 0000
#00B0: 1200 1100 0000 0F00 0000 0E00 0000 0C00

Ещё в PT есть так называемая таблица огибающих (она нужна только при написании музыки — проигрывать уже написанную можно и без неё). В ней содержатся значения коэффициентов из частотной таблицы, делённые на восемь. Каждое значение хранится в одном байте; если оно не умещается в байте (т.е. больше 255), то в таблицу помещается число 255. Вся таблица занимает 96 байтов.

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

Ассемблерный текст, описывающий таблицу огибающих, будет выглядеть следующим образом:

ORG #8000

DB  255,0,255,0,255,255,0,240,0,216,0,192
DB  180,0,160,0,144,135,0,120,0,108,0,96
DB  90,0,80,0,72,68,0,60,0,54,0,48
DB  45,0,40,0,36,34,0,30,0,27,0,24
DB  23,0,20,0,18,17,0,15,0,14,0,12
DB  11,0,10,0,9,8,0,8,0,7,0,6
DB  6,0,5,0,5,4,0,4,0,3,0,3
DB  3,0,3,0,2,2,0,2,0,2,0,2

Полученный после компиляции объектный код (его дамп приведён ниже) запишем в файл «envelope.C».

#0000: FF00 FF00 FFFF 00F0 00D8 00C0 B400 A000
#0010: 9087 0078 006C 0060 5A00 5000 4844 003C
#0020: 0036 0030 2D00 2800 2422 001E 001B 0018
#0030: 1700 1400 1211 000F 000E 000C 0B00 0A00
#0040: 0909 0008 0007 0006 0600 0500 0504 0004
#0050: 0003 0003 0300 0300 0202 0002 0002 0002

К сожалению, в PT (впрочем, как и в любом другом известном мне музыкальном редакторе для ZX Spectrum) не предусмотрена возможность использования частотной таблицы, определённой пользователем. В нём имеются лишь четыре заранее рассчитанные таблицы для различных тактовых частот сопроцессора. Можно заменить одну из них на нужную нам, но для этого придётся изрядно потрудиться. Рассмотрим этот процесс подробнее.

Нам потребуется Pro Tracker 3.51 (это последняя версия на момент написания этой статьи; у вас может быть и другая версия — в этом случае действуйте по аналогии), монитор-отладчик STS любой версии, упаковщик HRUST версии 1.2 или 1.3 и моя программа BestView версии 2.9 или выше.

Чтобы избежать повреждения какой-либо ценной информации, все операции будем проводить на отдельном чистом диске. Скопируем PT на этот диск и изменим имя файла на «PTv3.51z», чтобы его легко можно было отличить от оригинального. Буква «z» — от слова «zero» — «ноль»; это намёк на то, что используется таблица с нулевой погрешностью.

Теперь из четырёх имеющихся в редакторе таблиц надо выбрать ту, которую мы будем заменять на свою. Пусть это будет таблица «1.750000 Hz» (в PT 3.4 она называлась «ASM OR PSC»).

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

Известно, что в модуле, откомпилированном с плеером, частотная таблица находится по смещению #200 от начала. Создадим такой модуль, содержащий интересующую нас таблицу. Для этого сразу после запуска PT установим в setup параметр «Frequency table» равным 1.750000 Hz (по умолчанию именно это значение там и стоит), выберем пункт «Compiler» и в появившемся окне выберем «Save compiled song». Запишем модуль, например, под именем «test».

Затем с помощью BestView просмотрим дамп этого модуля. По смещению #200 там будет следующее:

#0200: 100D 550C A40B FC0A 5F0A CA09 3D09 B808
#0210: 3B08 C507 5507 EC06 8806 2A06 D205 7E05
#0220: 2F05 E504 9E04 5C04 1D04 E203 AB03 7603
...... .......................................

Приступим к поиску этой таблицы в PT. Нажмём комбинацию клавиш «CS+A» на файле «PTv3.51z». Из появившегося списка распознанных блоков нас интересует «p_blk_01» — таблица находится именно там. Нажав «Z» на этом упакованном блоке, посмотрим его параметры:

Рис. 2

Далее с помощью клавиши «L» проскроллируем файловую панель вправо, чтобы узнать трек-секторный адрес блока: #01/#02.

Нажав «SS+Enter», распакуем блок на диск под именем «unpack1». Выведем дамп распакованного блока с помощью «CS+Enter» и, зная, с какой последовательности байтов начинается таблица, попробуем её найти. Как выясняется, она находится по смещению #47F.

Таблицу огибающих легко отыскать, зная, что несколько первых байтов в ней равны #FF, а следующие байты соответствуют элементам частотной таблицы, только на три октавы выше. Она находится по смещению #3BF.

Ну что ж, можно заменять эти таблицы на свои. Запускаем STS и загружаем распакованный блок на адрес #8000. Частотную таблицу загрузим из файла «table.C» на адрес #8000+#47F=#847F. Таблицу огибающих загрузим из файла «envelope.C» на адрес #8000+#3BF=#83BF. Запишем изменённый блок под тем же именем «unpack1», start=#8000, length=#2F55. Осталось упаковать его и записать внутрь PT.

Запускаем HRUST, упаковываем блок без распаковщика и записываем его в файл с именем «unpack1*.C». Если длина упакованного блока в секторах не превосходит #11 секторов, то всё в порядке. В нашем случае это так и есть. А вот если блок оказался длиннее (скажем, если вы вставляли какую-либо другую таблицу, плохо пакующуюся), то он не уместится в отведённое ему внутри PT место. Тогда придётся обнулить внутри распакованного блока что-нибудь ненужное (например, ещё одну частотную таблицу — она идёт сразу же за первой) и перепаковать его.

Запишем упакованный блок внутрь файла «PTv3.51z». Трек-секторный адрес начала блока нам известен. Запускаем STS, загружаем файл «unpack1*.C» на адрес #8000 и записываем #11 секторов с #8000 на трек #01, сектор #02.

Всё! Теперь таблица «1.750000 Hz» в редакторе — ваша! Можете запустить редактор и оценить звучание.

Уже переделанный таким образом Pro Tracker 3.51 вы можете получить, обратившись ко мне по одному из указанных в начале статьи адресов.

Для игры в до мажоре или ля миноре тактовая частота сопроцессора, как мы уже рассчитывали, будет равна 1520640 Гц. Меняя её, как описано в предыдущем разделе, вы сможете играть в других тональностях, используя те же клавиши, что, на мой взгляд, весьма удобно. Можно, впрочем, для каждой тональности хранить свой экземпляр редактора со сдвинутыми соответствующим образом таблицами.

Да, кстати: для изменения тактовой частоты сопроцессора при работающем PT, очевидно, придётся либо использовать ручной переключатель, либо, в случае изменения частоты путём записи значения в порт, доработать PT, чтобы эта функция была в нём реализована.

Процедура построения частотной таблицы

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

Ниже приведён текст этой процедуры. Входные параметры: в HL указывается адрес, по которому расположены коэффициенты для нот нижней октавы (они хранятся в специальном формате с повышенной точностью — подробнее см. ниже), а в DE указывается адрес, по которому будет располагаться построенная таблица. Длина процедуры — 40 байтов, длина исходных данных — 12*2=24 байта. По сравнению с длиной частотной таблицы (192 байта) это весьма мало.

MAKE_FT    LD   B,12

M1         PUSH BC
           LD   C,(HL)
           INC  HL
           PUSH HL
           LD   B,(HL)

           PUSH DE
           EX   DE,HL
           LD   DE,23
           LD   XH,8

M2         SRL  B
           RR   C
           LD   A,C
           ADC  A,D     ;=ADC 0
           LD   (HL),A
           INC  HL
           LD   A,B
           ADC  A,D     ;=ADC 0
           LD   (HL),A
           ADD  HL,DE
           DEC  XH
           JR   NZ,M2

           POP  DE
           INC  DE
           INC  DE
           POP  HL
           INC  HL
           POP  BC
           DJNZ M1

           RET

Обратите внимание на то, как осуществляется деление на два. Если делать его простым сдвигом, отбрасывая выдвинутый разряд, процедуру можно было бы сильно упростить. Но абсолютная погрешность при этом достигала бы единицы младшего разряда. Чтобы минимизировать погрешность, деление производится с округлением: если выдвинутый при сдвиге бит равен единице (а значит, дробная часть результата больше или равна 0,5), к результату прибавляется единица; если же выдвинутый бит был равен нулю (дробная часть меньше 0,5), результат остаётся каким был. Как видим, в этом случае абсолютная погрешность не будет превосходить половины младшего разряда, т.е. будет вдвое меньше.

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

Значения коэффициентов для нижней октавы хранятся с повышенной точностью — с одним дополнительным разрядом: если точное значение коэффициента — k1, то хранится значение [k1*2].

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

Рассмотрим использование этой процедуры на примере: попробуем создать частотную таблицу для натурального звукоряда при тактовой частоте сопроцессора 1,75 МГц. Как мы помним, самая низкая октава в PT — контроктава; вычислим частоты нот этой октавы, учитывая, что они в восемь раз меньше, чем частоты соответствующих нот первой октавы и в шестнадцать раз меньше, чем частоты нот второй октавы — а их значения мы возьмём из табл. 1.

Fc  = 528/16  = 33 Гц,
Fd  = 594/16  = 37,125 Гц,
Fe  = 660/16  = 41,25 Гц,
Ff  = 704/16  = 44 Гц,
Fg  = 792/16  = 49,5 Гц,
Fa  = 440/8  = 55 Гц,
Fb  = 495/8  = 61,875 Гц.

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

kc  = 3314,3939,
kd  = 2946,1279,
ke  = 2651,5152,
kf  = 2485,7955,
kg  = 2209,596,
ka  = 1988,6364,
kb  = 1767,6768.

Исходные данные для процедуры построения таблицы удобно получить, умножив целую часть этих коэффициентов на два и прибавив 1, если дробная часть больше или равна 0,5:

TABL_TEST  DW 3314*2+0
           DW 0
           DW 2946*2+0
           DW 0
           DW 2651*2+1
           DW 2485*2+1
           DW 0
           DW 2209*2+1
           DW 0
           DW 1988*2+1
           DW 0
           DW 1767*2+1

Ну а само построение осуществится следующими командами (в предположении, что таблица будет сформирована с адреса #8000):

           LD   HL,TABL_TEST
           LD   DE,#8000
           CALL MAKE_FT

Если вы захотите использовать эту частотную таблицу при написании музыки в PT, то вам ещё понадобится рассчитать таблицу огибающих. Вот как это можно сделать с наименьшими затратами времени. Если заменить в процедуре MAKE_FT команду LD XH,8 на LD XH,11, то с адреса (DE+72) будут сформированы 96 значений коэффициентов для таблицы огибающих. Правда, после этого их ещё надо «уплотнить», ведь, как уже упоминалось в предыдущем разделе, каждый коэффициент должен храниться в одном байте, и значения, большие 255, должны быть заменены на 255. Это удобно выполнить с помощью нижеприведённой процедуры. Входные параметры: HL — адрес частотной таблицы, увеличенный на 72; DE — адрес, по которому будет сформирована таблица огибающих.

           LD   B,96
M1         LD   A,(HL)
           INC  HL
           INC  (HL)
           DEC  (HL)
           JR   Z,M2
           LD   A,#FF
M2         LD   (DE),A
           INC  HL
           INC  DE
           DJNZ M1
           RET

Между прочим, в [1] приводится мнение, что «электронный» оттенок компьютерной музыки во многом обусловлен именно строгой темперацией, которую проходят в компьютере любые инструменты. Попробуйте проверить, так ли это. Напишите модуль с использованием полученной таблицы, а потом запишите его в двух вариантах: откомпилированным с плеером и без плеера. При проигрывании в BestView модуля, откомпилированного без плеера, будет использована стандартная темперированная частотная таблица, а при проигрывании модуля, откомпилированного с плеером, будет использована таблица, взятая непосредственно из модуля. Обе таблицы рассчитаны для одной и той же тактовой частоты сопроцессора (1,75 МГц), что обеспечит подходящие условия для сравнения звучания.

Литература

  1. А.Шипилов. «Хорошо темперированный PC». «Компьютерра» 46/1997.
  2. С.Газарян. «В мире музыкальных инструментов». Москва, «Просвещение», 1985.
  3. Л.И.Филиппов. «Основы теории музыки в современном изложении». Москва, Издательство МЭИ, 1999.
  4. С.Рюмик. «„Правильные“ и „неправильные“ CLK музыкального сопроцессора». «Радиолюбитель. Ваш компьютер» 11/2000.

Другие мои статьи об AY-музыке:

1. 

«Правильное изменение частоты огибающей в Pro Tracker 3». «Радиолюбитель. Ваш компьютер» 10,11/2000.

2. 

«Некоторые особенности музыкального сопроцессора». «Радиолюбитель. Ваш компьютер» 11/2000 (под псевдонимом BV_Creator).

3. 

«Оптимизация на примере intro „Start“». «Радиомир. Ваш компьютер» 7—10/2001.

(В этой статье можно найти сведения о программировании проигрывания музыки.)

4. 

«Повышение степени сжатия музыкальных модулей». «Радиомир. Ваш компьютер» 7/2002.

5. 

«Построение таблицы громкости в плеере Pro Tracker 3». «Радиомир. Ваш компьютер» 4/2004.

Страница Ивана Рощина > Статьи >