ZX Forum
#04
19 ноября 1997 |
|
Мир звуков Спектрума - глава 4.6: Обработка внешних сигналов - оцифровка.
4.6. Обработка внешних сигналов ZX-Spectrum предоставляет программистам довольно интересную возможность - считы- вать и сохранять в памяти звуковые сигна- лы, подаваемые на его магнитофонный вход. Эти фрагменты можно воспроизводить с раз- личной скоростью, что, несомненно, очень интересно. Правда, качество полученного таким образом звука оставляет желать луч- шего, а его максимальная длительность ограничивается несколькими десятками се- кунд (просто-напросто кончаются 48K ОЗУ!) Но перейдем от слов к делу. Вот подпро- грамма, записывающая звук в память: 1415. 10 DI ; запрет прерываний 20 LD HL,25000 ; HL=адрес сохранения звука 30 LD DE,35000 ; DE=длительность звука 40 LOOP1 LD B,8 ; B=счетчик битов 50 LOOP2 SLA (HL) ; скроллинг значения в памяти 60 IN A,(254) ; ввести значение из порта 254 70 BIT 6,A ; проверить бит магнитофона 80 JR Z,NOSIGN ; если 0, то перейти на NOSIGN 90 SET 0,(HL) ; установить бит D0 в памяти 100 NOSIGN LD C,3 ; C=задержка 110 PAUSE DEC C ; C=C-1 120 JR NZ,PAUSE ; если C<>0, то цикл 130 DJNZ LOOP2 ; продолжить цикл обработки байта 140 INC HL ; HL=HL+1 150 DEC DE ; DE=DE-1 160 LD A,D ; DE= 170 OR E ; 0 ? 180 JR NZ,LOOP1 ; если нет, то цикл 190 EI ; разрешение прерываний 200 RET ; возврат 2 А это подпрограмма воспроизведения: 1415. 10 DI ; запрет прерываний 20 LD HL,25000 ; HL=адрес сохраненного звука 30 LD DE,35000 ; DE=длительность звука 40 NOP ; резерв 50 XOR A ; A=цвет бордюра (0) 60 LOOP3 LD B,8 ; B=счетчик битов 70 LOOP4 AND 239 ; сброс бита D4 регистра A 80 RLC (HL) ; скроллинг данных через флаг CY 90 JR NC,NOSGN ; если флаг CY=0, то перейти на NOSGN 100 OR 16 ; установка бита D4 регистра A 110 NOSGN OUT (254),A ; вывод A в порт 254 120 LD C,3 ; C=задержка 130 PAUS2 DEC C ; C=C-1 140 JR NZ,PAUS2 ; если C<>0, то цикл 150 DJNZ LOOP4 ; продолжить цикл обработки байта 160 INC HL ; HL=HL+1 170 LD C,A ; сохранение A 180 DEC DE ; DE=DE-1 190 LD A,D ; DE= 200 OR E ; 0 ? 210 LD A,C ; восстановление A 220 JR NZ,LOOP3 ; если DE<>0, то цикл 230 EI ; разрешение прерываний 240 RET ; возврат 2 Адреса данных и их длина должны совпа- дать в этих двух подпрограммах. Обратите также внимание на то, что они используют 35 Кб памяти с адреса 25000. Поэтому в этой области ОЗУ не должно быть никаких данных. Сами подпрограммы тоже должны рас- полагаться где-нибудь в другом месте. Оп- тимальным вариантом будет такой: перену- меруйте строки второй подпрограммы начи- ная с 210 и с шагом 10 (если Вы работаете в GENS4 - введите для этих целей команду N210,10); соедините то, что получилось, с первой подпрограммой и введите следующие строки: 1415. 7 ORG 24900 20 LD HL,BUFFER 30 LD DE,LENGTH 220 LD HL,BUFFER 230 LD DE,LENGTH 450 LENGTH EQU 35000 ; LENGTH=35000 460 BUFFER NOP ; здесь располагается буфер 2 Проследите также, чтобы ассемблер рас- полагался приблизительно с адреса 40000. В любом случае он будет стерт из памяти при вызове подпрограммы ввода звука. Поэтому не стоит вызывать ее из обреченного ассем- блера. Еще одно важное замечание: при исполь- зовании этих подпрограмм следите, чтобы выражение BUFFER+LENGTH не было больше 65535, иначе часть звуковых данных просто не запишется, а вместо них Вы услышите шум. В строке 100 первой подпрограммы и в строке 120 второй в регистр C заносится задержка между выборками данных. Если эти два значения равны, то звук будет вос- производиться с реальной скоростью. Если второе число меньше первого, то звук бу- дет ускорен, а если больше - замедлен. Причем, чем меньше задержка в подпрограм- ме ввода, тем выше качество вводимого сиг- нала, но меньше его длительность. Байт резерва в подпрограмме воспроизве- дения предназначен для переворачивания звука, то есть проигрывания его с конца на начало. Для включения этого эффекта надо заменить операцию NOP в этом байте на ADD HL,DE, а INC HL в строке 160 на DEC HL. Существует и другой способ записи зву- ка. Он основан на подсчете звуковых им- пульсов. Перед первым способом он не имеет никаких особых преимуществ, за исключе- нием возможности незначительного пониже- ния уровня шума. Вот подпрограмма, записы- вающая звук вторым способом: 1415. 10 DI ; запрет прерываний 20 LD HL,25000 ; HL=адрес сохранения звука 30 LD DE,35000 ; DE=длительность звука 40 LD BC,511 ; C - буфер, B - счетчик 50 LOOP1 IN A,(254) ; ввод значения из порта 254 60 EXX ; смена набора регистров 70 LD B,1 ; B=задержка 80 PAUSE DJNZ PAUSE ; задержка 90 EXX ; смена набора регистров 100 BIT 6,A ; проверить бит магнитофона 110 LD A,0 ; A=0 120 JR NZ,SIGN ; если бит D6=1, то перейти на SIGN 130 DEC A ; A=255 140 SIGN CP C ; A=C (предыдущему значению) ? 150 JR NZ,WRITE ; если нет, то перейти на WRITE 160 INC B ; B=B+1 (счетчик импульсов) 170 JR NZ,LOOP1 ; если B<>0, то цикл 180 WRITE DEC B ; B=B-1 190 JR NZ,POKE ; если B<>0, то перейти на POKE 200 LD B,2 ; B=2 210 CPL ; инвертирование A 220 LD C,A ; C=A 230 JR LOOP1 ; перейти на LOOP1 240 POKE INC B ; B=B+1 250 LD (HL),B ; запись значения в память 260 LD B,1 ; B=1 270 LD C,A ; C=A 280 INC HL ; HL=HL+1 290 DEC DE ; DE=DE-1 300 LD A,D ; DE= 310 OR E ; 0 ? 320 JR NZ,LOOP1 ; если нет, то цикл 330 EI ; разрешение прерываний 340 RET ; возврат 2 В строке 20 задается адрес сохранения звука, в строке 30 - длительность вводимо- го звука, в строке 70 - задержка между вы- борками сигнала. Строки 180 - 240 обеспечивают шумопони- жение. В регистре C сохраняется значение пре- дыдущей выборки, а регистр B служит счет- чиком одинаковых выборок. А вот подпрограмма воспроизведения: 1415. 10 DI ; запрет прерываний 20 LD HL,25000 ; HL=адрес сохраненного звука 30 LD DE,35000 ; DE=длительность звука 40 NOP ; резерв 50 XOR A ; A=цвет бордюра (0) 60 LOOP2 LD B,(HL) ; B=очередная длительность 70 LOOP3 OUT (254),A ; вывод A в порт 254 80 EXX ; смена набора регистров 90 LD B,1 ; B=задержка 100 PAUS2 DJNZ PAUS2 ; задержка 110 EXX ; смена набора регистров 120 CALL 124 ; компенсационная 130 BIT 0,(HL) ; задержка 140 DJNZ LOOP3 ; цикл 150 LD B,(HL) ; B=текущая длительность 160 DEC B ; B= 170 INC B ; 0 ? 180 JR Z,CONT ; если да, то перейти на CONT 190 XOR 16 ; инвертирование бита D4 200 CONT INC HL ; HL=HL+1 210 DEC DE ; DE=DE-1 220 LD B,A ; сохранение A 230 LD A,D ; DE= 240 OR E ; 0 ? 250 LD A,B ; восстановление A 260 JR NZ,LOOP2 ; если DE<>0, то цикл 270 EI ; разрешение прерываний 280 RET ; возврат 2 В строке 20 задается адрес сохраненно- го звука, в строке 30 - его длительность, а в строке 90 - задержка между выборками (она же - скорость воспроизведения). Байт резерва, как и раньше, предназна- чен для обратного воспроизведения. Для включения этого эффекта надо заменить операцию NOP в этом байте на ADD HL,DE, а INC HL в строке 200 на DEC HL. Строки 120 и 130 нужны только для вре- менной синхронизации с подпрограммой запи- си звука (по адресу 124 находится команда RET). Все сказанное относительно задержки ме- жду выборками и распределения памяти для подпрограмм, использующих первый способ записи, справедливо и для подпрограмм, ис- пользующих второй способ. Особенностью подпрограмм второго типа является то, что длительность записываемо- го звука зависит не только от объема выде- ленной памяти, но и от самого звука. Чем меньше перепадов уровней в записываемом звуке (иными словами - чем меньше его сре- дняя частота), тем более продолжительный звук можно записать. Например, если запи- сывать одну "тишину", то памяти хватит на несколько минут! Вы можете произвольно менять адрес и длину запоминаемого звука, но при этом необходимо быть предельно осторожным и не испортить жизненно важные области ОЗУ, та- кие как стек или системные переменные бей- сика. Звук, записанный этими подпрограммами, можно сохранить на ленте или диске с по- мощью обычных команд записи, а затем за- гружать по мере надобности. Так как даже не очень длинный звуковой фрагмент занимает в памяти много места, возникает естественное желание как-нибудь его сократить. Спешу Вас обрадовать - это возможно! Звуковые данные очень хорошо компрессируются по любому алгоритму. Для этого можно использовать даже экранные компрессоры. Неплохо было бы их немного модифицировать для такого использования, но, если Вы не сможете это сделать, дам несколько советов. Во-первых, без измене- ния компрессора можно сжимать только те файлы, размер которых меньше или равен 6912 байтам (если какой-либо компрессор отказывается принимать файлы с длиной от- личной от 6912 б., то дополните их до дан- ного размера нулями). Во-вторых, обычно компрессоры при распаковке картинки поме- щают ее прямо в область экрана. Поэтому придется данные перемещать оттуда в их "родной" адрес. Это можно сделать с по- мощью следующей подпрограммы: 1415. 10 LD HL,16384 ; 20 LD DE,16385 ; очистка 30 LD BC,6911 ; 40 LD (HL),L ; экрана 50 LDIR ; 60 CALL DECOMP ; вызов декомпрессора 70 LD HL,16384 ; HL=откуда перемещать 80 LD DE,ADDR ; DE=куда перемещать 90 LD BC,LENGTH ; BC=сколько перемещать 100 LDIR ; перемещение данных 110 CALL 3435 ; вызов подпрограммы CLS 120 RET ; возврат 2 Данные будут на экране такое короткое время, что Вы, скорее всего, этого и не заметите (при достаточно быстрой процедуре декомпрессии). И в заключение приведу текст программы на бейсике, загружающей и воспроизводящей звук с оптимальными параметрами: 10 CLEAR VAL "24899": PRINT "Wait please..." 20 FOR A=VAL "24900" TO VAL "24972": READ D: POKE A,D: NEXT A 30 CLS: PRINT "Press any key, then speak...": PAUSE NOT PI 40 CLS: RANDOMIZE USR VAL "24900" 50 CLS: PRINT "Press any key to replay...": PAUSE NOT PI 60 CLS: RANDOMIZE USR VAL "24934": GOTO VAL "30" 70 DATA 243,33,141,97,17,114,158,6,8,203,38,219,254,203,119, 40,2,203,198,14,1,13,32,253,16,239,35,27,122,179,32, 231,251,201 80 DATA 243,33,141,97,17,114,158,0,62,7,6,8,230,239,203,6,48, 2,246,16,211,254,14,1,13,32,253,16,239,35,27,79,122, 179,121,32,229,251,201 Если Вы захотите включить воспроизведе- ние "наоборот", вставьте в эту программу следующую строку: 45 POKE VAL "24941",VAL "25": POKE VAL "24963",VAL "43" Для отключения этого эффекта удалите данную строку и перезапустите программу. Непривычная запись чисел в этой прог- рамме приводит к экономии памяти. Так, выражение "24900" занимает 11 байт, а "VAL "24900"" - только 8 ("NOT PI" равняется нулю).
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября