
    4. Программирование звука в кодах

   Простейший пример воспроизведения  зву-
кового сигнала в кодах был приведен в пре-
дыдущей главе. В принципе, это  единствен-
ный спсоб получения звука, но оформить его
можно  по-разному.  Например, как  универ-
сальную подпрограмму:
1415.
 10            DI                 ; запрет прерываний
 20  BEEP      LD      A,B        ; A=цвет бордюра
 30            SET     4,A        ; бит D4=1
 40            OUT     (254),A    ; вывод A в порт 254
 50            PUSH    HL         ; сохранение HL
 60  LOOP1     DEC     HL         ; HL=HL-1
 70            LD      A,H        ; HL=
 80            OR      L          ;    0 ?
 90            JR      NZ,LOOP1   ; если нет, то цикл
100            POP     HL         ; восстановление HL
110            LD      A,C        ; A=цвет эффекта
120            OUT     (254),A    ; вывод A в порт 254
130            PUSH    HL         ; сохранение HL
140  LOOP2     DEC     HL         ; HL=HL-1
150            LD      A,H        ; HL=
160            OR      L          ;    0 ?
170            JR      NZ,LOOP2   ; если нет, то цикл
180            POP     HL         ; восстановление HL
190            DEC     DE         ; DE=DE-1
200            LD      A,D        ; DE=
210            OR      E          ;    0 ?
220            JR      NZ,BEEP    ; если нет, то цикл
230            EI                 ; разрешение прерываний
240            RET                ; возврат в бейсик
2
   Перед вызовом этой подпрограммы необхо-
димо занести в регистровую пару HL  часто-
ту, в  DE - длительность, в  B - цвет бор-
дюра, а в C - цвет эффекта (если Вы хотите
видеть бордюр  однотонным, то  значение  C
должно быть равно B). Кроме  того, если  к
регистру B  прибавить  8  (установить  бит
D3), то вместе с  динамиком  сигнал  будет
подаваться на магнитофон.
   Можно сделать эту программу универсаль-
ной несколько в другом смысле:
1415.
 10            DI                 ; запрет прерываний
 20            LD      A,(23624)  ; A=
 30            SRL     A          ;   цвет
 40            SRL     A          ;   бор-
 50            SRL     A          ;   дюра
 60  BEEP      XOR     16         ; инвертирование бита D4
 70            OUT     (254),A    ; вывод A в порт 254
 80            LD      C,A        ; сохранение A
 90            PUSH    HL         ; сохранение HL
100  PAUSE     DEC     HL         ; HL=HL-1
110            LD      A,H        ; HL=
120            OR      L          ;    0 ?
130            JR      NZ,PAUSE   ; если нет, то цикл
140            POP     HL         ; восстановление HL
150            DEC     DE         ; DE=DE-1
160            LD      A,D        ; DE=
170            OR      E          ;    0 ?
180            LD      A,C        ; восстановление A
190            JR      NZ,BEEP    ; если DE<>0, то цикл
200            EI                 ; разрешение прерываний
210            RET                ; возврат в бейсик
2
   Этой подпрограмме надо передать  только
частоту в регистре HL и длительность в DE,
а  цвет бордюра  сохраняется  тот, который
был при ее вызове (если только он  не  был
установлен оператором OUT).
   Примерно такая же подпрограмма  имеется
в ПЗУ ZX-Spectrum. Она расположена с адре-
са 949 (#03B5).  Параметры,как  и  раньше,
передаются в регистрах HL и DE. Их  значе-
ния можно рассчитать  по  следующим форму-
лам:

       HL=INT(437500/f-30.125+.5)
       DE=INT(f*t+.5)

где f - частота в Гц, а t - время в сек.
   Частоту  нот  для  пятой  октавы  можно
взять из таблицы 2.  Чтобы  ноту  повысить
или понизить  на октаву, ее  частоту  надо
соответственно умножить или  разделить  на
2. Причем, при делении значения получаются
немного точнее, чем при умножении.
   При генерации  звука  всеми  способами,
приведенными  выше, необходимо  учитывать,
что чем выше тон, тем  короче  будет  дли-
тельность.
   Если  Вы  хотите  при  программировании
звука в кодах использовать привычные пара-
метры оператора BEEP, то  Вы  можете  вос-
пользоваться  подпрограммой  ПЗУ, располо-
женной по адресу  1016 (#03F8).  Правда, с
ней связаны некоторые трудности.
   Дело в том, что параметры ей передаются
через стек калькулятора, а  засунуть  туда
дробное или отрицательное число не  так-то
просто.
   Чтобы обойти это неудобство, существует
три основных способа. Первый - хранить не-
обходимые значения в стандартной  пятибай-
товой форме и помещать их в стек с помощью
специальной  подпрограммы  ПЗУ.  Второй  -
хранить эти значения в символьной форме  и
помещать их в стек с помощью  другой  спе-
циальной подпрограммы ПЗУ.  И третий - не-
множко изменить систему параметров  и  за-
няться вычислениями.
   Первый способ не годится из-за  слишком
большого объема  расходуемой памяти.  Вто-
рой - по той же причине, плюс слишком мед-
ленная его работа. Остается третий способ.
Он вполне подходит и его можно легко  осу-
ществить.
   Пусть длительности задаются в сотых до-
лях секунды, а  высоты нот, как  раньше, в
полутонах выше или ниже ДО первой  октавы.
Такая система параметров  позволяет  полу-
чать ноты длительностью до 2,55  секунд  с
частотами в диапазоне от -60 до 69 (как  в
бейсике). Длительность  ноты  будет  зада-
ваться в регистре C, а высота - в регистре
B.
   Вот  подпрограмма,  осуществляющая  все
вышеописанное:
1412.
 10         PUSH    BC         ; сохранение BC
 20         LD      A,C        ; A=C (длительность)
 30         CALL    11560      ; поместить A в стек калькулятора
 40         LD      A,100      ; A=100
 50         CALL    11560      ; поместить A в стек калькулятора
 60         RST     40         ; вызов калькулятора
 70         DEFB    5,56       ; деление длительности на 100
 80         POP     BC         ; восстановление BC
 90         LD      A,B        ; A=B (частота)
100         BIT     7,A        ; A - отрицательное ?
110         JR      NZ,MINUS   ; если да, то перейти на MINUS
120         CALL    11560      ; иначе поместить A в стек каль-
                                 кулятора
130         JP      1016       ; вызов подпрограммы воспроизве-
                                 дения
140  MINUS  NEG                ; в A - абсолютное значение
150         CALL    11560      ; поместить A в стек калькулятора
160         RST     40         ; вызов калькулятора
170         DEFB    27,56      ; изменение знака
180         JP      1016       ; вызов подпрограммы воспроизве-
                                 дения

   Если Ваш  ассемблер  не  "переваривает"
отрицательные числа (бывают  такие  "штуч-
ки"), то необходимые значения  можно  рас-
считать по следующей формуле: n=256-x, где
x - абсолютная  величина  значения, а  n -
результат.
