Interrupt_Vector:   EQU 0BE00h; Вектор прерываний 
   
    ...
   
    DI
    LD      A, I
    LD      (.SaveInterrupt), A
    LD      A, HIGH Interrupt_Vector
    LD      I, A
    IM      2
    
    ; Заполним буфер "тишины" для CBL
    LD      A, 080h
    LD      HL, BufNoSound
    LD      DE, BufNoSound + 1
    LD      BC, 128 ; для 16 бит 256
    LD      (HL), A
    LDIR
    
    ; Прерывание от CBL
    LD      HL, IM2_CBL
    LD      (Interrupt_Vector OR 0FFh), HL
    
    ; Установим в CBL тишину
    LD      A, 2
    LD      (IM2_CBL.NumberPage), A
    
    ...
    
    EI
    
    ; Включим CBL
    LD      BC, 004Eh
    LD      A, 10011000b ; COVOX-Blaster + Interrupt + 7.8125 KHz
    OUT     (C), A
    
    ...
    
    LD      A, ...
    LD      HL, ...
    LD      BC, ...
    CALL    PlaySound
    
    ...
    
; Ожидаем завершения воспроизведения CBL
.LoopEndSound:
    HALT
    LD      A, (IM2_CBL.NumberPage)
    OR      A
    JR      NZ, .LoopEndSound
    
    ; Выключим CBL
    LD      BC, 004Eh
    XOR     A
    OUT     (C), A
    
    ...
    
    DI
    
; Восстановим вектор прерывания
.SaveInterrupt+*: LD A, 0
    LD      I, A
    IM      1
    EI    
    
.Exit:
    LD      C, DSS.Exit
    RST     10h
    JR      $   
    
BufNoSound: DS 128

; Проиграть звук
; A - Номер страницы с данными для воспроизведения
; HL - Адрес начала данных для воспроизведения в 1й странице (4000h..7FFFh)
; BC - Длина данных для воспроизведения, должна должны быть кратна 128 байтам
PlaySound:
    PUSH    AF, HL
    ; Если нужно ожидать завершение предыдущего воспроизведения, то раскомментировать
    ; LD      A, (IM2_CBL.NumberPage)
    ; OR      A
    ; JR      NZ, .Exit
    LD      (IM2_CBL.NumberPage), A
    LD      (IM2_CBL.AddrSound), HL
    LD      (IM2_CBL.Length), BC
.Exit:
    POP     HL, AF
    RET


IM2_CBL:
    DI
    PUSH    AF
    IN      A, (0FEh)
    RLCA
    JR      NC, .NoSound ; Если прерывание не от CBL
.NumberPage+*: LD A, 0
    OR      A
    JR      Z, .NoSound ; Если нечего играть
    PUSH    BC, DE, HL
    CP      3
    JR      NC, .PlaySound
    DEC     A
    LD      (.NumberPage), A
    
    ;SaveAndSetPage1 .Save_Page_1, (Pages.Data)    
    IN      A, (PAGE_1)
    LD      (.Save_Page_1), A
    LD      A,(Pages.Data)
    OUT     (PAGE_1), A    
    
    LD      HL, BufNoSound
    JR      .CopyData

.PlaySound:
    LD      D, A
    ;SaveAndSetPage1 .Save_Page_1, D
    IN A,   (PAGE_1)
    LD      (.Save_Page_1), A
    LD A,   D
    OUT (PAGE_1), A
.AddrSound+*: LD HL, 0
.CopyData:
    IN      A, (PAGE_3)
    LD      (.Save_Page_3), A
    LD      A, 0FDh
    OUT     (PAGE_3), A    
    
    LD      DE, 0C000h
    ; Запись данных с помощью акселератора 
    LD      B, E
    LD      D, D ; ACC_On_NoDI
    LD      C, 128 ; BC = 128 байт
    LD      L, L; ACC_CopyBlock_Horizontal
    LD      A, (HL)
    LD      (DE), A
    LD      B, B; ACC_Off_NoEI
    
    ;;  Запись данных через порт 4Fh
    ; PUSH    BC, HL
    ; LD      BC, 804Fh
    ; OTIR
    ; POP     HL, BC

    ADD     HL, BC
    LD      (.AddrSound), HL
    OR      A
.Length+*:  LD HL, 0
    SBC     HL, BC
    JR      NZ, .NotEndSound
    LD      A, 2
    LD      (.NumberPage), A
    LD      HL, 512 ; Такая длина, чтобы не было рекурсии
.NotEndSound:
    LD      (.Length), HL

.Exit:
.Save_Page_1+*: LD A, 0
    OUT     (PAGE_1), A
.Save_Page_3+*: LD A, 0
    OUT     (PAGE_3), A

    POP     HL, DE, BC
.NoSound:
    POP     AF
    EI
    RETI

