ZXNet эхоконференция «music.zx»


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



от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 1 .W ══════════════════

(c) Иван Рощин, Москва

Fido : 2:5020/689.53
ZXNet : 500:95/462.53
E-mail: asder_ffc@softhome.net
WWW : http://www.ivr.da.ru


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

("Радиолюбитель. Ваш компьютер" 6-8/2001)

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

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

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

┌──────────────────────1/2───────────────────────┐
│ │
│ ┌─────5/6─────┐ ┌─────4/5─────┤
│ │ │ │ │
╔══╧═══╤══╧═══╤══════╤══╧═══╤══════╤══╧═══╤══════╗--┴---┬------┐
║ A │ B │ C │ D │ E │ F │ G ║ A | B |
║ │ │ │ │ │ │ ║ | |
║ ля │ си │ до │ ре │ ми │ фа │ соль ║ ля | си |
╚══╤═══╧══╤═══╧══╤═══╧══╤═══╧══╤═══╧══╤═══╧══╤═══╝--┬---┴--┬---┘
│ │ │ │ │ │ │ │ │
├─8/9──┴15/16─┼─8/9 ─┴─9/10─┼15/16─┴─8/9──┼─9/10─┘ │
│ │ │ │ │
└─────5/6─────┴─────4/5─────┴─────5/6─────┴─────4/5─────┘

Рис. 1

На инструменте, настроенном в соответствии с природным
звукорядом, нельзя было сыграть мелодию, скажем, на тон выше
или ниже. Для игры в другой тональности его надо было
перенастраивать. Чтобы как-то преодолеть это неудобство, в
октаву добавили пять дополнительных звуков - там, где интервал
между основными звуками равнялся целому тону (8/9 или 9/10). Но
это не до конца решило проблему: не из любой тональности в любую
можно было переходить легко и просто.
Около VI-V вв. до н.э. за решение этой задачи взялся Пифагор
(он был не только ученым, но и блестящим музыкантом). Немного
изменив частоты трех из семи нот в октаве и точно рассчитав
частоты дополнительных звуков, он обеспечил музыкантам
возможность переходить из тональности в тональность гораздо
свободнее. Но все-таки некоторая необходимость перенастройки
инструментов оставалась.
В конце XVII века состоялась новая реформа музыкального
строя: немецкий органист Андреас Веркмейстер предложил сделать
соотношения между частотами соседних звуков одинаковыми и
равными 2^(1/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 и др.) используется темперированный звукоряд. Сразу же,
не производя каких-либо вычислений, можно сказать, что этот
звукоряд воспроизводим сопроцессором лишь с определенной
погрешностью. Действительно, отношение частот любых двух
соседних звуков в нем - 2^(1/12) - число иррациональное, и по
определению не может быть представлено в виде частного двух
целых чисел. В то же время любые две частоты, сформированные
сопроцессором, будут относиться друг к другу именно как целые
числа: из формулы (*) непосредственно следует, что F1/F2=k2/k1.
Погрешность можно уменьшить, увеличивая тактовую частоту
сопроцессора [4], но полностью избавиться от нее принципиально
невозможно.


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 2 .W ══════════════════

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

┌──────┬───────────────────────────────────────────────────────┐
│ │ Частота, Гц │
│ ├─────────────┬─────────────────┬───────────────────────┤
│ Нота │ │ │ Наилучшее приближение │
│ │ Натуральный │ Темперированный │ к темперированному │
│ │ звукоряд │ звукоряд │ звукоряду для AY (YM) │
│ │ │ │ при CLK=1,75 МГц │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ A-1 │ 440,0 │ 440,0 │ 439,3 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ B-1 │ 495,0 │ 493,9 │ 494,9 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ C-2 │ 528,0 │ 523,3 │ 523,3 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ D-2 │ 594,0 │ 587,3 │ 588,0 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ E-2 │ 660,0 │ 659,3 │ 658,9 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ F-2 │ 704,0 │ 698,5 │ 696,7 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ G-2 │ 792,0 │ 784,0 │ 781,3 │
├──────┼─────────────┼─────────────────┼───────────────────────┤
│ A-2 │ 880,0 │ 880,0 │ 882,1 │
└──────┴─────────────┴─────────────────┴───────────────────────┘

Таблица 1


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

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

k(a)/k(b) = 9/8 (1)
k(b)/k(c) = 16/15 (2)
k(c)/k(d) = 9/8 (3)
k(d)/k(e) = 10/9 (4)
k(e)/k(f) = 16/15 (5)
k(f)/k(g) = 9/8 (6)
k(g)/k(a') = 10/9 (7)

Попробуем подобрать минимальный набор коэффициентов k(a),
k(b),...,k(g), который удовлетворял бы этим соотношениям.
Коэффициенты, как мы помним, должны быть целыми. Чтобы
выполнялось равенство (1), возьмем k(a)=9, k(b)=8. Из (2)
следует, что k(b) должно делиться на 16. Удвоим начальные
значения первых двух коэффициентов, что не изменит соотношения
между ними: k(a)=18, k(b)=16. Тогда k(c)=15. Но k(c) должен
делиться на 9 - этого требует условие (3). Утроим коэффициенты:
k(a)=54, k(b)=48, k(c)=45. Тогда k(d)=45*8/9=40. Из равенства
(4) получаем k(e)=40*9/10=36. Из (5) следует, что k(e) должен
делиться на 16. Для этого умножим коэффициенты на четыре:
k(a)=216, k(b)=192, k(c)=180, k(d)=160, k(e)=144. Тогда k(f)=
144*15/16=135. Ну и, наконец, k(g)=135*9/10=120.
Итак, требуемый набор коэффициентов деления получен: 216,
192,180,160,144,135,120. Первый коэффициент, k(a), соответствует
ноте "ля" - именно она раньше считалась первой нотой октавы. В
буквенных обозначениях нот (A,B,C,D,E,F,G) это сохранилось до
сих пор. Сохранилась и эталонная нота - "ля" первой октавы (440
Гц). Теперь принято начинать октаву с ноты "до". В соответствии
с этим представим набор коэффициентов так, чтобы он начинался с
k(c), а k(a) и k(b) разделим на два и переместим в конец: 180,
160,144,135,120,108,96.
Так как этот набор наименьший, он определяет коэффициенты
для самой высокой октавы, которая будет звучать без искажений.
Удваивая эти коэффициенты, мы получим значения, соответствующие
более низким октавам. Напротив, последовательно деля их на два,
мы получим значения, соответствующие более высоким октавам, - но
каждый раз, когда деление нельзя будет произвести нацело, будет
возникать погрешность.
Произведем вышеописанные действия, учитывая, что коэффици-
енты не должны выходить за пределы диапазона 1..4095. Округлять
получающиеся при делении дробные значения до ближайшего целого
числа пока не будем, чтобы избежать накопления погрешности.
Вычисленные значения сведем в таблицу.

├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ │ │ │ │ 3840 │ 3456 │ 3072 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 2880 │ 2560 │ 2304 │ 2160 │ 1920 │ 1728 │ 1536 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 1440 │ 1280 │ 1152 │ 1080 │ 960 │ 864 │ 768 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 720 │ 640 │ 576 │ 540 │ 480 │ 432 │ 384 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 360 │ 320 │ 288 │ 270 │ 240 │ 216 │ 192 │
╔══════╤══════╤══════╤══════╤══════╤══════╤══════╗
║ 180 │ 160 │ 144 │ 135 │ 120 │ 108 │ 96 ║
╚══════╧══════╧══════╧══════╧══════╧══════╧══════╝
│ 90 │ 80 │ 72 │ 67,5 │ 60 │ 54 │ 48 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 45 │ 40 │ 36 │33,75 │ 30 │ 27 │ 24 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 22,5 │ 20 │ 18 │16,875│ 15 │ 13,5 │ 12 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│11,25 │ 10 │ 9 │8,4375│ 7,5 │ 6,75 │ 6 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│5,625 │ 5 │ 4,5 │4,2188│ 3,75 │3,375 │ 3 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│2,8125│ 2,5 │ 2,25 │2,1094│1,875 │1,6875│ 1,5 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│1,4063│ 1,25 │1,125 │1,0547│ │ │ │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤

Таблица 2


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 3 .W ══════════════════

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

┌──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ C │ D │ E │ F │ G │ A │ B │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ │ │ │ │√3840 │√3456 │√3072 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│√2880 │√2560 │√2304 │√2160 │√1920 │√1728 │√1536 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│√1440 │√1280 │√1152 │ 1080 │√960 │√864 │√768 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│√720 │√640 │√576 │ 540 │√480 │√432 │√384 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 360 │√320 │√288 │ 270 │√240 │ 216 │√192 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 180 │√160 │√144 │ 135 │ 120 │ 108 │√ 96 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 90 │√ 80 │ 72 │▒▒68▒▒│ 60 │ 54 │√ 48 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 45 │ 40 │ 36 │▒▒34▒▒│ 30 │ 27 │ 24 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│▒▒23▒▒│ 20 │ 18 │▒▒17▒▒│ 15 │▒▒14▒▒│ 12 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│▒▒11▒▒│ 10 │ 9 │▒▒8▒▒▒│▒▒8▒▒▒│▒▒7▒▒▒│ 6 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│▒▒6▒▒▒│ 5 │▒▒5▒▒▒│▒▒4▒▒▒│▒▒4▒▒▒│▒▒3▒▒▒│ 3 │
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│▒▒3▒▒▒│▒▒3▒▒▒│▒▒2▒▒▒│▒▒2▒▒▒│▒▒2▒▒▒│▒▒2▒▒▒│▒▒2▒▒▒│
├──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│▒▒1▒▒▒│▒▒1▒▒▒│▒▒1▒▒▒│▒▒1▒▒▒│ │ │ │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┘

Таблица 3

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

Определимся теперь с тактовой частотой сопроцессора. Ее
нетрудно вычислить, зная, что частота ноты "ля" первой октавы
равна 440 Гц, зная коэффициент деления, соответствующий этой
ноте, и используя формулу (***).
Напомню, что октавы именуются в таком порядке (снизу вверх):
субконтроктава, контроктава, большая, малая, первая, вторая,
третья, четвертая и пятая. Первая октава, считающаяся наиболее
употребительной, находится примерно в середине звукоряда.
Где в таблице находится коэффициент, соответствующий ноте
"ля" первой октавы? Очевидно, в столбце "A" - именно таково
буквенное обозначаение этой ноты. А вот в какой строке? Строку
мы можем выбрать сами, руководствуясь тем, чтобы используемые в
мелодии ноты попали на область значений с нулевой погрешностью.
Для примера рассчитаем тактовую частоту сопроцессора, если
первой октаве соответствует пятая сверху строка таблицы.

CLK = 16*440*216 = 1520640 Гц

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

┌─────────────┬─────────────────────────┐
│ тональность │ 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 │
└─────────────┴─────────────────────────┘

Таблица 4


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 4 .W ══════════════════

Итого одиннадцать различных частот, так как три значения
повторяются в таблице дважды (они помечены символом "▐"). Для
того, чтобы можно было смещать диапазон нот с нулевой
погрешностью на октаву вверх или вниз, подстраиваясь под
конкретную мелодию, потребуются еще вдвое большие и вдвое
меньшие значения.
Если требуется исполнять произведения во всех двадцати
четырех тональностях - двенадцати мажорных и двенадцати
минорных - видимо, наиболее оптимально будет сделать так,
чтобы для каждой следующей тональности тактовая частота была
в 2^(1/12) раза больше, чем для предыдущей. При этом потребуется
всего двенадцать различных значений CLK:

┌──────────────────────────────────┬─────────┐
│ тональность │ CLK, Гц │
├──────────────────────────────────┼─────────┤
│ до мажор, ля минор │ 1520640 │
│ до-диез мажор, ля-диез минор │ 1611062 │
│ ре мажор, си минор │ 1706861 │
│ ре-диез мажор, до минор │ 1808356 │
│ ми мажор, до-диез минор │ 1915886 │
│ фа мажор, ре минор │ 2029811 │
│ фа-диез мажор, ре-диез минор │ 2150510 │
│ соль мажор, ми минор │ 2278386 │
│ соль-диез мажор, фа минор │ 2413866 │
│ ля мажор, фа-диез минор │ 2557401 │
│ ля-диез мажор, соль минор │ 2709472 │
│ си мажор, соль-диез минор │ 2870586 │
└──────────────────────────────────┴─────────┘

Таблица 5

Как видим, для проигрывания музыки в различных тональностях
при использовании натурального звукоряда с нулевой погрешностью
требуется аппаратная доработка, позволяющая изменять тактовую
частоту сопроцессора. (Нечто подобное было описано в [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


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 5 .W ══════════════════

Еще в 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" на этом упакованном блоке,
посмотрим его параметры:

┌────────────┬────────────────────────────────────────────────┐
│ PTv3.51z B │First #10FC=4348 bytes: Packed block │
│ code__01 │ │
│█p_blk_01███│Compressor : HRUST 1 │
│ p_blk_02 │Block length : #10FC=4348 │
│ code__02 │Decompressor : No │
│ │Unpacked length: #2F55=12117 │
│ │K=35%, save 65% │
│ │ │

Рис. 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.


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 6 .W ══════════════════

Запускаем 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].
Построенная с помощью такой процедуры частотная таблица
будет полностью совпадать с наилучшим возможным приближением к
теоретически рассчитанным значениям коэффициентов деления.


════════════════════════════════════════════════

С уважением, Иван Рощин.

от: Ivan Roshin
кому: All
дата: 01 Aug 2001
Hello, All!

═══════════════════ 7 .W ══════════════════

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

F(c) = 528/16 = 33 Гц
F(d) = 594/16 = 37,125 Гц
F(e) = 660/16 = 41,25 Гц
F(f) = 704/16 = 44 Гц
F(g) = 792/16 = 49,5 Гц
F(a) = 440/8 = 55 Гц
F(b) = 495/8 = 61,875 Гц

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

k(c) = 3314,3939
k(d) = 2946,1279
k(e) = 2651,5152
k(f) = 2485,7955
k(g) = 2209,596
k(a) = 1988,6364
k(b) = 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.


════════════════════════════════════════════════

С уважением, Иван Рощин.




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
INTRO - Прошел "День программиста".
Железо - XTR Modem: описание и программирование.
Кусать подано - Праздничное меню для тех, кто хочет поесть и выпить за наше здоровье.
Рыбак - это круто.
Юмор - Почему пиво лучше, чем женщины.

В этот день...   20 апреля