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 - результат.