ъБРЙУШ ЪЧХЛБ
Alexander.
.model tiny
.code
.386
org 100h
Channels equ byte ptr 1
Frequency equ word ptr 22050
dSize equ word ptr 30000
;Смещения регистров относительно базового адреса
offRESET equ byte ptr 06h
offREAD equ byte ptr 0Ah
offWRST equ byte ptr 0Ch
offAVAIL equ byte ptr 0Eh
;Используемые форматы данных - Число бит на отсчет, способ кодирования
sb8bitPCM equ byte ptr 14h
sb4bitADPCM equ byte ptr 74h
sb4bitADPCMR equ byte ptr 75h
sb3bitADPCM equ byte ptr 76h
sb3bitADPCMR equ byte ptr 77h
sb2bitADPCM equ byte ptr 16h
sb2bitADPCMR equ byte ptr 17h
;Определение адресов портов
sbBASE equ word ptr 220h
sbIRQ equ byte ptr 05h
sbDMA equ byte ptr 01h
sbHDMA equ byte ptr 03h
sbRESET equ word ptr sbBASE+offRESET
sbREAD equ word ptr sbBASE+offREAD
sbWRST equ word ptr sbBASE+offWRST
sbAVAIL equ word ptr sbBASE+offAVAIL
start:
call pInit
;Вычисление программного прерывания и установка нового обработчика прерывания
mov al,sbIRQ
cmp al,08h
jl short thenif0
add al,68h
jmp short endif0
thenif0:
add al,08h
endif0:
;Запоминание в OldVecOffs, OldVecSeg вектора прерывания
mov ah,35h
int 21h
mov word ptr OldVecOffs,bx
mov word ptr OldVecSeg,es
mov bx,cs
mov es,bx
;Установка адреса нового обработчика прерываний
mov dx,Offset SBHandler
mov ah,25h
int 21h
;Вычисление маски IRQ и установка 8259-IC
xor ax,ax
mov al,sbIRQ
mov ch,08h
div ch
mov cl,ah
mov bx,01h
shl bx,cl
mov word ptr IRQMask,bx
not bx
in ax,21h
and ax,bx
out 21h,ax
mov al,sbIRQ
cmp al,08h
jl short endif1
in ax,0A1h
and ax,bx
out 0A1h,ax
endif1:
mov dx,offset strread
mov ah,9
int 21h
mov ah,08h
int 21h
push offset data
push word ptr sb8bitPCM
push word ptr Frequency
push word ptr Channels
push word ptr dSize
call pReadSample
waitl:
mov al,sbLOADDATA
not al
or al,al
jnz waitl
call pSpeakerOn
mov dx,offset strwrite
mov ah,9
int 21h
mov ah,08h
int 21h
push offset data
push word ptr sb8bitPCM
push word ptr Frequency
push word ptr Channels
push word ptr dSize
call pPlaySample
waitl1:
mov al,sbLOADDATA
not al
or al,al
jnz waitl1
call pCloseSB
mov dx,offset yesno
mov ah,09h
int 21h
readkey:
mov ah,08h
int 21h
cmp al,79h
jz short dispdata
cmp al,6Eh
jz short exit
jmp readkey
dispdata:
mov ax,013h
int 10h
mov ax,0A000h
mov es,ax
std
mov di,dsize
push di
mainbl5:
call pclrscr
pop dx
mov cx,m320
cmp dx,cx
jl short mainbl3
sub dx,cx
jmp short mainbl4
mainbl3:
mov cx,dx
xor dx,dx
mainbl4:
push dx
push cx
push 0h
mov byte ptr color,30h
mov si,word ptr pozdat1
call pdraw
mov word ptr pozdat1,si
pop cx
push 102
mov byte ptr color,40h
mov si,word ptr pozdat2
call pdraw
mov word ptr pozdat2,si
mov ah,08h
int 21h
mov dx,[esp]
or dx,dx
jnz mainbl5
pop dx
mov ax,cs
mov es,ax
cld
mov ax,0003h
int 10h
exit:
mov ax,4C00h
int 21h
pWriteDSP proc
mov dx,sbWRST
Busy1:
in al,dx
or al,al
js Busy1
mov al,bl
out dx,al
ret
pWriteDSP endp
pReadDSP proc
mov dx,sbAVAIL
Busy:
in al,dx
or al,al
jns Busy
sub dl,04h
in al,dx
ret
pReadDSP endp
pReadADC proc
mov bl,20h
call pWriteDSP
call pReadDSP
mov bl,al
ret
pReadADC endp
pWriteDAC proc
push bx
mov bl,10h
call pWriteDSP
pop bx
call pWriteDSP
ret
pWriteDAC endp
pSpeakerOn proc
mov bl,0D1h
call pWriteDSP
ret
pSpeakerOn endp
pSpeakerOff proc
mov bl,0D3h
call pWriteDSP
ret
pSpeakerOff endp
pInit proc
mov dx,sbRESET
mov al,01h
out dx,al
sub al,al
out dx,al
Delay:
dec al
jnz Delay
sub cx,cx
Empty:
mov dx,sbAVAIL
in al,dx
or al,al
jns short NextAttempt
sub dl,04h
in al,dx
cmp al,0AAh
je short ResetOK
NextAttempt:
loop Empty
mov ax,4cffh
int 21h
ResetOK:
ret
pInit endp
pclrscr proc
mov cx,320*50+1
xor eax,eax
push di
mov di,320*200
rep stosd
pop di
ret
pclrscr endp
pdraw proc
xor bx,bx
mainbl6:
xor ax,ax
lodsb
not al
mul mc
div m100
xor ah,ah
push bx
mov bx,[esp]+4
add ax,bx
pop bx
mul word ptr m320
add ax,bx
mov di,ax
mov byte ptr es:[di],20h
mov ax,90
mov dx,[esp]+2
add ax,dx
mul word ptr m320
add ax,bx
mainbl8:
add di,m320
cmp di,ax
jnl short mainbl7
mov dl,color
mov byte ptr es:[di],dl
jmp mainbl8
mainbl7:
inc bx
loop mainbl6
ret 2
pdraw endp
;Проигрывание выборки
pReadSample proc
;Сброс флага готовности
mov byte ptr sbLOADDATA,00h
;Уменьшение размера выборки
Dec word ptr [esp+2]
;Установка чипа DMA
;Начальный адрес данных
mov bx,cs
shl bx,04h
add bx,word ptr [esp+10]
;Номер физической страницы данных
mov dx,word ptr [esp+10]
shr dx,04h
mov cx,cs
add dx,cx
shr dx,0Ch
;Сброс маски DMA 1
mov al,05h
out 0Ah,al
;Сброс триггера байтов
mov al,00h
out 0Ch,al
;Запись в регистр режима
mov al,45h
out 0Bh,al
;Запись младших разрядов начального адреса данных
mov al,bl
out 02h,al
;Запись старших разрядов начального адреса данных
mov al,bh
out 02h,al
;Запись в регистр страниц
mov ax,dx
out 83h,ax
;Установка младших разрядов счетчика данных
mov al,byte ptr [esp+2]
out 03h,al
;Установка старших разрядов счетчика данных
mov al,byte ptr [esp+3]
out 03h,al
;Установка маски на первый канал DMA
mov al,01h
out 0Ah,al
;Установка частоты проигрывания
mov bl,40h
call pWriteDSP
mov ax,4240h
mov dx,000Fh
div word ptr [esp+6]
not ax
mov bl,al
call pWriteDSP
;Установка типа проигрывания (8-бит)
mov bl,24h
call pWriteDSP
mov bl,byte ptr [esp+2]
call pWriteDSP
mov bl,byte ptr [esp+3]
call pWriteDSP
ret 10
pReadSample endp
;Проигрывание выборки
pPlaySample proc
;Сброс флага готовности
mov byte ptr sbLOADDATA,00h
;Уменьшение размера выборки
Dec word ptr [esp+2]
;Установка чипа DMA
;Начальный адрес данных
mov bx,cs
shl bx,04h
add bx,word ptr [esp+10]
;Номер физической страницы данных
mov dx,word ptr [esp+10]
shr dx,04h
mov cx,cs
add dx,cx
shr dx,0Ch
;Сброс маски DMA 1
mov al,05h
out 0Ah,al
;Сброс триггера байтов
mov al,00h
out 0Ch,al
;Запись в регистр режима
mov al,49h
out 0Bh,al
;Запись младших разрядов начального адреса данных
mov al,bl
out 02h,al
;Запись старших разрядов начального адреса данных
mov al,bh
out 02h,al
;Запись в регистр страниц
mov ax,dx
out 83h,ax
;Установка младших разрядов счетчика данных
mov al,byte ptr [esp+2]
out 03h,al
;Установка старших разрядов счетчика данных
mov al,byte ptr [esp+3]
out 03h,al
;Установка маски на первый канал DMA
mov al,01h
out 0Ah,al
;Установка частоты проигрывания
mov bl,40h
call pWriteDSP
mov ax,4240h
mov dx,000Fh
div word ptr [esp+6]
not ax
mov bl,al
call pWriteDSP
;Установка типа проигрывания (8-бит)
mov bl,byte ptr [esp+8]
call pWriteDSP
mov bl,byte ptr [esp+2]
call pWriteDSP
mov bl,byte ptr [esp+3]
call pWriteDSP
ret 10
pPlaySample endp
pCloseSB proc
;Восстановление вектора прерываний
mov dx,OldVecOffs
mov ax,OldVecSeg
mov ds,ax
mov ah,25h
int 21h
mov bx,cs
mov ds,bx
mov bx,IRQMask
in ax,21h
or ax,bx
out 21h,ax
mov al,sbIRQ
cmp al,08h
jl short endif2
in ax,0A1h
or ax,bx
out 0A1h,ax
endif2:
ret
pCloseSB endp
;Обработчик прерывания SB
SBHandler:
mov dx,sbAVAIL
in al,dx
;Флаг основной программы, инициализирующий загрузку данных
mov byte ptr sbLOADDATA,0FFh
;Е01 - конец прерывания, разрешение прерывания
mov al,20h
out 20h,al
mov al,sbIRQ
cmp al,08h
jl short endif3
mov al,0A0h
out 0A0h,al
endif3:
iret
;флаг готовности
sbLOADDATA db 00h
m320 dw 320
m16 dw 16
mc db 35
m100 db 100
pozdat1 dw offset data[dsize]
pozdat2 dw offset dataout[dsize]
strread db 'Press any key to begin riding data from SB ',13,'$'
strwrite db 'Press any key to begin writing data to SB ',13,'$'
yesno db 'Dispay data? (Y/N) ',13,'$'
IRQMask dw ?
OldVecOffs dw ?
OldVecSeg dw ?
firstb db ?
color db ?
data db dsize dup (?)
dataout db dsize dup (?)
;datpak db dsize dup (?)
end start
pPlaySample??? И там, и там написано Проигрывание выборки, да и по коду похоже. Одно считывание куска, а другая процедура - непосредственно отсылание на SB, так что-ли??? (Хотя мне собственно проигрывание звуков не надо, но все же). Ну вот.
Ничего, если я вопросы буду задовать по ходу разбирания с прогой?
Да и еще, нет ли у вас какой-нибудь документации по этому поводу. Теоретической или практической.
Спасибо.
Долго не мог ответить. Тем не менее - большое спасибо за прогу. Я ее просмотрел, правда не все понял. За запись, я так понял, отвечают pReadDSP и pReadADC? Потом, чем отличаются pReadSample и
pPlaySample??? И там, и там написано Проигрывание выборки, да и по коду похоже. Одно считывание куска, а другая процедура - непосредственно отсылание на SB, так что-ли??? (Хотя мне собственно проигрывание звуков не надо, но все же). Ну вот.
Ничего, если я вопросы буду задовать по ходу разбирания с прогой?
Да и еще, нет ли у вас какой-нибудь документации по этому поводу. Теоретической или практической.
Спасибо.
Процедуры pReadDSP и pWriteDSP осуществляют чтение и запись команд/данных в DSP (Digital Sound Processor) соответственно.
Прежде, чем рассказать о прцедурах pReadADC и pWriteDAC, поясню причину их существования. У звуковой карты есть два основных режима работы - прямая передача данных и работа через DMA канал.
В первом случае программа постоянно передает данные на воспроизведение/запись (побайтно), при этом она (программа) сама заботится о стабильности частоты подачи (сбора) данных. С одной стороны этот режим проще в работе со звуковой картой, но с другой стороны урезаются возможности программы - она должна постоянно следить за звуковой картой и ни чем больше не заниматься.
Второй режим (режим DMA) немного сложнее при использовании (нужно много выставлять всяких настроек), зато за воспроизведением/записью следит сама звуковуха. В моменты воспроизведения/записи программа может заниматься другими делами. Прежние версии вышеприведенной программы я писал используя первый режим работы звуковухи, но потом переделал её на работу с вторым режимом (первый меня не устраивал).
Так вот, возвращаясь назад к pReadADC, pWriteDAC, эти процедуры есть не что иное как остатки от старой версии программы (первого режима). Как видно, обращения к ним нигде в программе не возникают, следовательно их можно просто выкинуть.
Процедуры pReadSample и pPlaySample отличаются своей работой - одна читает массив данных из звуковухи, а другая - передает данные на воспроизведение. Если посмотреть на их код, то он выглядит практически одинаково, но отличия в них все-таки есть (буквально в нескольких байтах, эти-то байты и устанавливают режим работы звуковой карты - запись/воспроизведение). При желании процедуры можно объеденить в одну, но я в силу каких-то причин это не сделал (в силу каких причин не помню. Может лень было :-)))). А по поводу комментария к процедурам - просто опечатка.
Если будут вопросы - задавай.
При составлении программы я пользовался одним пдфником, который могу выслать по e-mail. Есть одно неудобство - пдфник на английском :-).
При составлении программы я пользовался одним пдфником, который могу выслать по e-mail. Есть одно неудобство - пдфник на английском :-).
Английский не проблема (ну по крайней мере не особо большая :) ). Если не трудно, то мыль на <filarmony@rambler.ru>