Простейший пример воспроизведения звукового сигнала в кодах был приведён в предыдущей статье. В принципе, это единственный способ получения звука, но оформить его можно по-разному. Например, как универсальную подпрограмму:
Assembler Z80:
10 DI ; запpет пpеpываний
20 BEEP LD A,B ; A=цвет боpдюpа
30 SET 4,A ; бит D4=1
40 OUT (254),A ; вывод A в поpт 254
50 PUSH HL ; сохpанение 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 в поpт 254
130 PUSH HL ; сохpанение 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 ; pазpешение пpеpываний
240 RET ; возвpат в бейсик

Перед вызовом этой подпрограммы необходимо занести в регистровую пару HL частоту, в DE - длительность, в B - цвет бордюра, а в C - цвет эффекта (если Вы хотите видеть бордюр однотонным, то значение C должно быть равно B). Кроме того, если к регистру B прибавить 8 (установить бит D3), то вместе с динамиком сигнал будет подаваться на магнитофон. Можно сделать эту программу универсальной несколько в другом смысле:
Assembler Z80:
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 ; возврат в бейсик

Этой подпрограмме надо передать только частоту в регистре HL и длительность в DE, а цвет бордюра сохраняется тот, который был при её вызове (если только он не был установлен оператором OUT).
Примерно такая же подпрограмма имеется в ПЗУ ZX-Spectrum. Она расположена с адреса 949 (#03В5). Параметры,как и раньше, передаются в регистрах HL и DE. Их значения можно рассчитать по следующим формулам:
HL=INT(437500/f-30.125+.5) DE=INT(f*t+.5)
- где f - частота в Гц, at- время в сек.
Частоту нот для пятой октавы можно взять из таблицы 2. Чтобы ноту повысить или понизить на октаву, её частоту надо соответственно умножить или разделить на 2. Причем, при делении значения получаются немного точнее, чем при умножении.
1769859735739.png

При генерации звука всеми способами, приведенными выше, необходимо учитывать, что чем выше тон, тем короче будет длительность.
Если Вы хотите при программировании звука в кодах использовать привычные параметры оператора ВЕЕР, то Вы можете воспользоваться подпрограммой ПЗУ, расположенной по адресу 1016 (#03F8). Правда, с ней связаны некоторые трудности.
Дело в том, что параметры ей передаются через стек калькулятора, а засунуть туда дробное или отрицательное число не так-то просто.
Чтобы обойти это неудобство существует три основных способа. Первый - хранить необходимые значения в стандартной пятибайтовой форме и помещать их в стек с помощью специальной подпрограммы ПЗУ. Второй - хранить эти значения в символьной форме и помещать их в стек с помощью другой специальной подпрограммы ПЗУ. И третий - немножко изменить систему параметров и заняться вычислениями.
Первый способ не годится из-за слишком большого объема расходуемой памяти. Второй - по той же причине, плюс слишком медленная его работа. Остается третий способ. Он вполне подходит и его можно легко осуществить.
Пусть длительности задаются в сотых долях секунды, а высоты нот, как раньше, в полутонах выше или ниже ДО первой октавы. Такая система параметров позволяет получать ноты длительностью до 2.55 секунд с частотами в диапазоне от -60 до 69 (как в бейсике). Длительность ноты будет задаваться в регистре C, а высота - в регистре B.
Вот подпрограмма, осуществляющая все вышеописанное:
Assembler Z80:
10 PUSH BC ; сохpанение BC
20 LD A,C ; A=C (длительность)
30 CALL 11560 ; поместить A в стек калькулятоpа
40 LD A,100 ; A=100
50 CALL 11560 ; поместить A в стек калькулятоpа
60 RST 40 ; вызов калькулятоpа
70 DEFB 5,56 ; деление длительности на 100
80 POP BC ; восстановление BC
90 LD A,B ; A=B (частота)
100 BIT 7,A ; A - отpицательное ?
110 JR NZ,MINUS ; если да, то пеpейти на MINUS
120 CALL 11560 ; иначе, поместить A в стек калькулятоpа
130 JP 1016 ; вызов подпpогpаммы воспpоизведения
140 MINUS NEG ; в A - абсолютное значение
150 CALL 11560 ; поместить A в стек калькулятоpа
160 RST 40 ; вызов калькулятоpа
170 DEFB 27,56 ; изменение знака
180 JP 1016 ; вызов подпpогpаммы воспpоизведения

Если Ваш ассемблер не "переваривает" отрицательные числа (бывают такие "штучки"), то необходимые значения можно рассчитать по следующей формуле: n=256-x, - где x - абсолютная величина значения, а n- результат.