ZX-Ревю 1993 №5-6 1992 г.

Применение ассемблера для создания быстроработающих программ - Музыкальные и звуковые эффекты.


6. МУЗЫКАЛЬНЫЕ И ЗВУКОВЫЕ ЭФФЕКТЫ

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

Интегральная форма записи действительных чисел.

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

1. Переводим число в его эквивалент в двоичной системе счисления.

Например:

11,375 = 1011,011.

Напомним, что в двоичной системе счисления

0,5 = 0,1

0,25 = 0,01

0,125 = 0,001 и т.д.

2. Определяем экспоненту числа. Для этого перемещаем десятичную точку влево или вправо, пока не дойдём до крайней единицы справа или слева. При этом считаем число шагов перемещений. Экспонента будет равна 128 плюс число шагов. Если движение производилось влево, то оно считается положительным, а если вправо - то отрицательным. В нашем примере получим после четырех шагов вправо:

.1011011

и, следовательно, экспонента равна 128+4 = 132.

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

В нашем примере число было положительным и поэтому после смены состояния бита оно будет иметь вид:

.00110110

4. Определяем мантиссу числа. Для этого, не обращая внимание на десятичную точку, добавим справа определенное количеств нулей, чтобы получить 32-х разрядное число. Теперь распределим 32 разряда числа между четырьмя байтами и определим значение каждого байта:

00110100 (54) 00000000 (0)

00000000 (0) 00000000 (0)

Таким образом, 5-байтное представление числа 11,375 будет иметь следующий вид:

132 54 0 0 0

Если Вы хотите проверить все вышесказанное, то Вам необходимо ввести короткую программу, позволяющую считывать 5 последовательных байтов (например, через PEEK) из участка памяти, где записаны переменные BASIC-программы. Значения переменных в этой области хранятся именно в 5-ти байтной форме.

Теперь вернемся к главной теме этой главы. Операнды BASIC-команды BEEP, определяющие длительность и тональность звука, записываются в калькуляторный стек. Калькуляторный стек оперирует и хранит числа, записанные именно в 5-байтной форме. Поэтому, чтобы написать программу в машинных кодах для получения звука или музыки, необходимо значение этих операндов занести в калькуляторный стек именно в 5-байтной форме.

Процедура ВЕЕР, находящаяся по адресу 1016, извлекает эти два числа с калькуляторного стека и воспроизводит звуковой сигнал в соответствии со значениями этих чисел. Например, для получения эффекта, аналогичного команде БЕЙСИКа ВЕЕР .1,11, необходимо числа 0.1 и 11 вначале перевести в их 5-байтную форму:

0.1 = 125 76 204 204 204

11 = 132 48 0 0 0

Теперь необходимо передать последовательно эти 10 байтов на калькуляторный стек. Как это сделать, показано в программе 6.1. Здесь используется команда передачи блока LDIR. При этом в регистровую пару HL записывается адрес начала этих 10 байтов в памяти, а в регистровую пару DE - адрес вершины стека, который постоянно хранится в системной переменой STKEND (23653). В регистровую пару ВС записывается число перемещаемых байтов. Процедура ВЕЕР извлекает два числа в 5-байтной форме с вершины стека и адрес вершины стека восстанавливается, т.е. становится таким же, как и до записи туда чисел.

Листинг 6.1

ORG 23760

23760

ED

5B

65

5C

LD DE, (23653)

В DE установили то, что

хранится в STKEND

23764

21

E4

5C

LD HL,DATA

В HL - адрес наших 10 байтов

23767

01

0A

00

LD BC,10

В BC - количество пересылаемых байтов

23770

ED

B0

LDIR

Переброска данных на машинный

стек калькулятора

23772

ED

53

65

5C

LD (23653),DE

Переустановили новое значение STKEND

23776

CD

F8

03

CALL 1016

Вызов процедуры BEEP

23779

C9

RET

Выход

23780

DATA

DEFM 125, 76, 204,

204, 204 ;Число 0.1

23785

DEFM 132, 48, 0, 0,

0 ;Число 11

Другой способ передачи чисел на стек калькулятора основан на использовании команды LD A, n и процедуры ПЗУ STACK_A, находящейся по адресу 11560, если передаются целые числа в диапазоне 0.. .255.

Если надо передать целые числа из диапазона 0.65535, то можно воспользоваться переброской через регистровую пару ВС и вызов процедуры ПЗУ STACK_BC, находящейся по адресу 11563. В программе 6.2 показано, как можно передать в калькуляторный стек число 11, используя регистр А.

Листинг 6.2

ORG 23760

23760

ED

5B

65

5C

LD DE,(23653)

В DE установили то, что

хранится в STKEND

23764

21

E9

5C

LD HL,DATA

В HL - адрес наших 10 байтов

23767

01

05

00

LD BC,5

В BC - количество пересылаемых байтов

23770

ED

B0

LDIR

Переброска данных на машинный

стек калькулятора

23772

ED

53

65

5C

LD (23653),DE

Переустановили новое значение STKEND

23776

3E

0B

LD A,11

В аккумуляторе число 11

23778

CD

28

2D

CALL 11560

Число 11 помещено на вершину

стека калькулятора

23781

CD

F8

03

CALL 1016

Вызов процедуры BEEP

23784

C9

RET

Выход

23785

DATA

DEFM 125, 76, 204,

204, 204 ;Число 0.1

Упакованная форма записи действительных чисел.

Теперь познакомимся с записью чисел с плавающей запятой в упакованной форме и с использованием кода калькулятора 52DEC для работы с числами, находящимися на калькуляторном стеке в этой форме.

Перевод 5-байтного числа в упакованную форму включает в себя следующие этапы:

1. Начиная с пятого байта, убираем все числа, равные нулю до тех пор, пока не выйдем на ненулевое число или не достигнем второго байта 5-байтной записи числа.

2. Определяем число удаленных байтов k и рассчитываем число g = 3-k.

3. Вычитаем 80 из числа, записанного в первом байте и, если результат больше или равен 64, то переходим к п.6.

4. Меняем значение экспоненты (число в первом байте) на число: экспонента минус 80 плюс g*64.

5. Переходим к п.7.

6. Экспонента числа занимает 2 байта. Значение первого байта равно g*64, а второго 80.

7. Записываем оставшиеся байты после модифицированной экспоненты.

Для выполнения обратного перехода необходимо:

1. Разделить значение первого байта на 64.

2. Если будет остаток от деления, то экспонента будет равна 80+остаток.

3. Если остатка от деления на 64 не будет, то экспонента равна 80 плюс значение второго байта.

4. Частное от деления на 64 используется для определения количества последующих байтов, это количество равно частному от деления плюс 1.

Например, для числа 11 упакованная форма имеет вид:

52 48

Делим 52 на 64 и получаем: частное = 0, а остаток = 52. Значит, после экспоненты, равной 80+52 = 132, следует только 0+1= 1 байт. В упакованной форме записи он равен 48. Следовательно, 5-байтная запись числа 11 будет иметь вид:

132 48 0 0 0

Программа 6.3 показывает, как может использоваться упакованная форма для реализации команды ВЕЕР .1,11 в машинных кодах.

Листинг 6.3

МАШ.КОД

EF 34 ED 4C CC CC CC 34 34 30 38

CD FB 03 C9

АДРЕС

23760

23761 23767

23770

23771 23784

АССЕМБЛЕР ORG 23760 RST 40 stk_data stk_data endcalc CALL 1016 RET

КОММЕНТАРИЙ

Включение калькулятора. На стеке 0.1 На стеке 0.1, 11 Выключение калькулятора. Вызов процедуры BEEP. Выход.

Для получения различных звуковых эффектов можно использовать процедуру ВЕЕР с точкой входа 949. При этом значения длительности и тональности звука подаются не на стек калькулятора, а соответственно в регистровые пары DE и HL.

Программа 6.4 показывает, как можно программно менять тональность звука, используя процедуру ВЕЕР в цикле. При этом будет меняться и длительность, потому что длительность звучания является функцией значений, записанных в регистровых парах HL и DE.

Листинг 6.4

АДРЕС

МАШ

.КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

06

FF

LD B,255

Инициализация счётчика.

23762

21

01

00

LD HL,1

Инициализация высоты тона.

23765

11

01

00

LOOP LD DE,1

Инициализация длительности звука

23768

E5

PUSH HL

Надо предохранить HL и BC

23769

C5

PUSH BC

от порчи процедурой BEEP.

23770

CD

B5

03

CALL 949

Вызов процедуры BEEP.

23773

C1

POP HL

23774

E1

POP BC

23775

23

INC HL

Повышение высоты тона.

23776

10

F3

DJNZ LOOP

Повтор цикла.

23778

C9

RET

Выход из процедуры.

Существует ещё один метод воспроизведения звука в компьютерах Spectrum. Для этого нужно знать частоту смены высокого и низкого уровня для каждой ноты и отправлять сигнал прямо на динамик, минуя процедуры ПЗУ. Этот метод можно использовать в игровых программах для создания "белого шума", эффекта взрыва и т.д. При этом используется команда OUT (254),A. Причем этой командой можно не только управлять работой динамика, но и менять цвет рамки экрана (цвет BORDER).

1. Если только нулевой бит регистра A включен, то BORDER - синий.

2. Если только первый бит регистра A включен, то BORDER - красный.

3. Если только второй бит регистра A включен, то BORDER - зеленый.

4. Если бит 4 регистра A включен, то на динамик компьютера идет высокий сигнал, а

если этот бит сброшен - то низкий.

Понятно, что если периодически менять состояние 4-го бита регистра A и использовать команду OUT (254),А, то частота звука из динамика будет пропорциональна частоте смены состояния 4-го бита. Для создания "белого шума" период чередования состояния 4-го бита должен быть случайным, но при использовании стандартной процедуры генерации случайных чисел, программа будет выполняться слишком медленно. Поэтому лучше использовать в качестве случайных чисел содержимое в каких-то ячейках памяти и, тем самым, переключать уровень сигнала на динамике (см. программу 6.5). В этой программе в одном цикле трижды используется команда OUT (254),А,

а также ряд команд NOP, что необходимо для создания временной задержки.

Длительность звука ограничена. Для этого используется команда

CP 60

Цвет BORDER также меняется случайным образом, чтобы этот цвет оставался постоянным, необходимо переписать биты 3-5 с системной переменной BORDER в биты 0-2 регистра А.

Листинг 6.5

ORG 23760

23760

21

00 00

LD HL,00

Мы начинаем брать данные для "белого шума" прямо из ПЗУ.

23763

7E

L1 LD A,(HL)

Очередной байт из ПЗУ.

23764

00

NOP

Пауза.

23765

D3

FE

OUT (254)

A

Выдача сигнала на динамик.

23757

00

NOP

23758

00

NOP

23769

D3

FE

OUT (254)

A

23771

00

NOP

23772

00

NOP

23773

D3

FE

OUT (254)

A

23775

00

NOP

23776

23

INC HL

Переход к следующей ячейке ПЗУ

23777

7C

LD A,H

23778

FE

3C

CP 60

Проверка на конец работы.

23780

20

ED

JR NZ,L1

Возврат к началу цикла.

23782

C9

RET

Выход из процедуры.

Если Вы хотите поэкспериментировать с созданием музыки, используя этот метод, то вам необходимо помнить, что каждую 1/50 секунды ваша программа будет прерываться процедурой сканирования клавиатуры. Поэтому, чтобы сохранить частоту звука, необходимо в начале программы запретить прерывания командой DI, а в конце программы вновь разрешить их командой EI. Кстати, именно поэтому невозможно прервать выполнение команды ВЕЕР клавишей BREAK.

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

(Продолжение следует)




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



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

Похожие статьи:
От редакции - Газета круто изменилась.
Bytefall`97 - День второй.
Приложение - Где можно приобрести магнитофонные кассеты с записями песен Сопротивления?
Gameland - О конкурсе нелепых (или корявых) игр для ZX Spectrum - Crap Games Competition.
Гамлїт, принц Датський - Украинский Гамлет.

В этот день...   24 ноября