Компьютер - электронное устройство, которое не заменит человека до тех пор, пока не научится смеяться шуткам начальника и сваливать свои собственные ошибки на соседний компьютер.




    PUSH DS ;сохраняем регистр
      MOV AX,SEG MELODY2 ;сегмент процедуры
      MOV DS,AX ;помещаем в DS
      MOV DX,OFFSET MELODY2 ;смещение процедуры
      MOV AL,1CH ;номер вектора прерывания
      MOV AH,25H ;функция установки вектора
      INT 21H ;изменение вектора
      POP DS ;восстановление регистра ; ;---программа работает дальше, постоянно вызывая процедуру ; ;---в конце программы восстанавливаем вектор прерывания
      MOV DX,0FF53H ;восстанавливаем оригинальные
      MOV AX,0F000H ;значения для вектора 1CH
      MOV DS,AX ;
      MOV AL,1CH ;номер прерывания
      MOV AH,25H ;функция установки вектора
      INT 21H ;восстанавливаем вектор
      RET ;
;---это само прерывание MELODY2 PROC FAR
      PUSH AX ;сохраняем изменяемые регистры
      PUSH BX ;
      PUSH CX ;
      PUSH DX ;
      PUSH DI ;
      PUSH SI ;
      PUSH DS ;
      MOV AX,SS:[114] ;берем начальный DS со стека
      MOV DS,AX ;восстанавливаем его
      CMP SOUND_NOW?,1 ;нужен ли звук?
      JE PLAY_IT ;если нет, то выход из прерывания
      JMP NOT_NOW ; PLAY_IT: CMP FIRST_NOTE?,0 ;это первая нота?
      JE TIME_CHECK ;если нет, то на установку времени

;---инициализация PORT_B EQU 61H ;определяем имена портов COMMAND_REG EQU 43H ; LATCH2 EQU 42H ;
      IN AL,PORT_B ;берем статус порта B
      OR AL,00000011B ;разрешаем динамик и таймер
      OUT PORT_B,AL ;посылаем байт обратно
      MOV SI,0 ;указатель на строки
      MOV AL,0B6H ;инициализация канала 2 таймера
      OUT COMMAND_REG,AL ;посылаем в командный регистр
      MOV FIRST_NOTE?,0 ;сбрасываем флаг первой ноты ;---ищем ноту, получаем ее частоту, посылаем в канал 2 NEXT_NOTE: LEA BX,MELODY ;берем смещение строки мелодии
      MOV SI,WHICH_NOTE ;указатель на текущую ноту
      MOV AL,[BX][SI] ;код текущей ноты строки
      CMP AL,0FFH ;проверяем признак конца
      JE NO_MORE ;если да, то на конец
      CBW ;иначе в словный формат
      ;получаем частоту
      MOV BX,OFFSET FREQUENCY ;смещение таблицы частот
      DEC AX ;начинаем отсчет с нуля
      SHL AX,1 ;умножаем на 2, т.к. словная
      MOV DI,AX ;адресуемся через DI
      MOV DX,[BX][DI] ;получаем частоту из таблицы
      ;начинаем исполнение ноты
      MOV AL,DL ;готовим младший байт частоты
      OUT LATCH2,AL ;посылаем в регистр задвижки
      MOV AL,DH ;готовим старший байт
      OUT LATCH2,AL ;посылаем его ;---пустой цикл, определяющий длительность нот TIME_IT: MOV AH,0 ;фнукция чтения счетчика
      INT 1AH ;получаем значение счетчика
      MOV BX,OFFSET BEAT ;смещение строки длин нот
      MOV CL,[BX][SI] ;длительность текущей ноты
      MOV CH,0 ;
      MOV BX,DX ;младшее слово значения счетчика
      ADD BX,CX ;добавляем длину в импульсах
      MOV END_NOTE,BX ;запоминаем время окончания TIME_CHECK: MOV AH,0 ;функция чтения счетчика
      INT 1AH ;читаем счетчик
      CMP DX,END_NOTE ;сравниваем с нужным
      JNE NOT_NOW ;если неравно, то выходим
      MOV SI,WHICH_NOTE ;иначе, берем следующую ноту
      INC SI ;увеличиваем номер ноты
      MOV WHICH_NOTE,SI ;запоминаем его
      JMP NEXT_NOTE ;начинаем следующую ноту ;---завершение процедуры NO_MORE: IN AL,PORT_B ;берем статус порта B
      AND AL,0FCH ;выключаем динамик
      OUT 61H,AL ;возвращаем байт
      MOV SOUND_NOW?,0 ;восстанавливаем переменные
      MOV FIRST_NOTE?,1 ;

NOT_NOW: POP DS ;восстанавливаем регистры
      POP SI ;
      POP DI ;
      POP DX ;
      POP CX ;
      POP BX ;
      POP AX ;
      IRET ;возврат из прерывания MELODY2 ENDP


2.2.7 Создание плавного перехода тонов.



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

      Высокий уровень.

      В Бейсике надо просто поместить оператор SOUND [2.2.2] в цикл, используя очень малые длины тонов. При каждом новом проходе цикла надо увеличивать частоту. Смотрите [2.2.8], где приведен пример использования оператора PLAY для более быстрых переходов.
100 FOR N = 1 TO 500 STEP 15 110 SOUND 400 + N,1 120 NEXT

      Низкий уровень.

      Проще всего использовать метод генерации звука, управляемый микросхе