RSS    

   Курсовая работа: Программа воспроизведения произвольного звукового файла с использованием звукового адаптера (формат - wav)

бит 2: 16-битное воспроизведение через DMA

бит 3: 16-битное чтение через DMA

бит 4: динамик включен

биты 5-6: не определены

бит 7: ТС модифицирована (может быть ноль, если предыдущая команда 40h пыталась

установить неподдерживаемую частоту)

0FCh: дополнительная информация (SB16).

Возвращает дополнительный байт состояния текущей DMA-операции:

бит 1: синхронный режим (одновременная запись и воспроизведение)

бит 2:8-битный режим с автоинициализацией

бит 4: 16-битный режим с автоинициализацией

0FDh: последняя выполненная команда (SB16).

Возвращает последнюю успешную команду DSP.

Программирование контроллера DMA

Контроллер DMA используется для обмена данными между внешними устройствами и памятью. Он нужен в работе с жесткими дисками и дисководами, звуковыми платами и другими устройствами, работающими со значительными объемами данных. Начиная с PC AT, в компьютерах присутствуют два DMA-контроллера - 8-битный (с каналами 0, 1, 2 и 3) и 16-битный (с каналами 4, 5, 6 и 7). Канал 2 используется для обмена данными с дисководами, канал 3 - для жестких дисков, канал 4 теряется при каскадировании контроллеров, а назначение остальных каналов может варьироваться.

DMA позволяет выполнить чтение или запись блока данных, начинающегося с линейного адреса, который описывается как 20-битное число для первого DMA-контроллера и как 24-битное для второго, то есть данные для 8-битного DMA должны располагаться в пределах первого мегабайта памяти, а для второго - в пределах первых 16 Мб. Старшие четыре бита для 20-битных адресов и старшие 8 бит для 24-битных адресов хранятся в регистрах страниц DMA, адресуемых через порты 80h - 8Fh:

порт 81h: страничный адрес для канала 2 (биты 3-0 = биты 19-16 адреса)

порт 82h страничный адрес для канала 3 (биты 3-0 = биты 19-16 адреса)

порт 83h: страничный адрес для канала 1 (биты 3-0 = биты 19-16 адреса)

порт 87h: страничный адрес для канала 0 (биты 3-0 = биты 19-16 адреса)

порт 89h: страничный адрес для канала 6 (биты 7-0 = биты 23-17 адреса)

порт 8Аh: страничный адрес для канала 7 (биты 7-0 = биты 23-17 адреса)

порт 8Bh: страничный адрес для канала 5 (биты 7-0 = биты 23-17 адреса)

Страничный адрес определяет начало 64/128-килобайтного участка памяти, с которым будет работать данный канал, поэтому при передаче данных через DMA обязательно надо следить за тем, чтобы не было выхода за границы этого участка, то есть чтобы не было попытки пересечения адреса 1000h:0, 2000h:0, 3000h:0 для первого DMA или 2000h:0, 4000h:0, 6000h:0 для второго.

Младшие 16 бит адреса записывают в следующие порты:

00h: биты 15-0 адреса блока данных для канала 0

01h: счетчик переданных байт канала 0

02h - 03 h: аналогично для канала 1

04h - 05h: аналогично для канала 2

06h - 07h: аналогично для канала 3

(для этих портов используются две операции чтения/записи - сначала передаются

биты 7-0, затем биты 15-8)

0C0h: биты 8-1 адреса блока данных для канала 4 (бит 0 адреса всегда равен нулю)

0C1h: биты 16-9 адреса блока данных для канала4

0С2 h: младший байт счетчика переданных слов канала 4

0C3h: старший байт счетчика переданных слов канала 4

0C4h - 0C7h: аналогично для канала 5

0C8h - 0CBh: аналогично для канала 5

0CCh - 0CFh: аналогично для канала 5

(эти порты рассчитаны на чтение/запись целыми словами)

Каждый из указанных двух DMА-контроллеров также имеет собственный набор управляющих регистров - регистры первого контроллера адресуются через порты 08h - 0Fh, а второго - через 0D0 - 0DFh:

порт 08h/0D0h для чтения: регистр состояния DMA

бит 7, 6, 5, 4: установлен запрос на DMA на канале 3/7, 2/6, 1/5, 0/4

бит 3, 2, 1, 0; закончился DMA на канале 3/7, 2/6, 1/5, 0/4

порт 08h/D0h для записи: регистр команд DMA (устанавливается BIOS)

бит 7: сигнал DACK использует высокий уровень

бит 6: сигнал DREQ использует высокий уровень

бит 5: 1/0: расширенный/задержанный цикл записи

бит 4: 1/0: приоритеты сменяются циклически/фиксировано

бит 3: сжатие во времени

бит 2: DMА-контроллер отключен

бит 1: разрешен захват канала 0 (для режима память-память)

бит 0: включен режим память-память (канал 0 - канал 1)

порт O9h/0D2h для записи: регистр запроса DMA

бит 2: 1/0: установка/сброс запроса на DMA

биты 1-0: номер канала (00, 01, 10, 11 - 0/4, 1/5, 2/6, 3/7)

порт 0Ah/0D4h для записи: регистр маски канала DMA

бит 2: 1/0: установка/сброс маскирующего бита

биты 1-0: номер канала (00, 01, 10, И - 0/4, 1/5, 2/6, 3/7)

порт 0Bh/OD6h для записи: регистр режима DMA

биты 7-6:

00 - передача по запросу

01 - одиночная передача (используется для звука)

10 - блочная передача (используется для дисков)

11 - канал занят для каскадирования

бит 5: 1/0: адреса уменьшаются/увеличиваются

бит 4: режим автоинициализации

биты 3-2:

00 - проверка

01 - запись

10 - чтение

биты 1-0: номер канала (00, 01, 10, 11 - 0/4, 1/5, 2/6, 3/7)

порт 0Ch/0D8k для записи: сброс переключателя младший/старший байт

Для чтения/записи 16-биткых значений из/в 8-битные порты 00h-08h. Очередной байт, переданный в эти порты, будет считаться младшим, а следующий за ним - старшим.

порт 0Dh/0DAh для записи: сброс контроллера DMA

Любая запись сюда приводит к полному сбросу DMA-контроллера, так что его надо инициализировать заново.

порт 0Dh/0DAh для чтения: последний переданный байт/слово.

порт 0Eh/0DCh для записи: любая запись снимает маскирующие биты со всех каналов

порт 0Fh/0DEh для записи: регистр маски всех каналов:

биты 3-0: маскирующие биты каналов 3/7, 2/6, 1/5, 0/4

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

Описание функции Open_file

open_file proc near

mov ax, 3D00h ;Выполнить функцию DOS 3Dh: AH=3Dh, установим

режим доступа AL=00 – открыть для чтения

mov dx, offset filename ;Заносим в dx смещение filename и

теперь в DS:DX –полный адрес ASCIZ-

строки с именем файла

int 21h ;Передать управление операц. системе и открыть

файл для чтения

jc error_exit ; если не удалось открыть файл, перейти на

метку error_exit

mov bx, ax ; заносим идентификатор файла в BX,

необходимо для команды 42h

mov ax, 4200h ;Команда для перемещения указателя чтения/записи AH=42h,

AL=0 – от начала файла

mov cx, 0 ; CX:DX - новое значение указателя

mov dx, 38h ; по этому адресу начинаются данные в tada.wav

int 21h ; переместим файловый указатель

mov ah, 3Fh ; Чтение из файла AH=3Fh

mov cx, 27459 ; считать 27459 байтов в файле tada.wav

push ds ;заносим считанные данные в стек

mov dx, ds

and dx, 0F000h ; выровняем буфер на границу 4K-страницы

add dx, 1000h ; складываем dx и 1000h, необход. для DMA

mov ds, dx

mov dx, 0 ; DS:DX - адрес буфера

int 21h ; чтение файла

pop ds ; выгрузить из стека данные в ds

ret

error_exit: ; если не удалось открыть файл

mov ah, 9 ; AH=09h

mov dx, offset notopenmsg ; DS:DX = адрес сообщения об

; ошибке

int 21h ; вывод строки на экран

int 20h ; конец программы

notopenmsg db 'Could not open file', 0Dh, 0Ah ; сообщение об

; ошибке

db 'Exiting', 0Dh, 0Ah, '$'

open_file endp

Для компиляции будем использовать компилятор и линковщик Tasm и Tlink соответственно:

tasm /m wavdma.asm

tlink /t /x wavdma.obj

Код исходной программы(начало)

В этом примере задействован обычный DMA-режим работы, в котором звуковая плата проигрывает участок данных, вызывает прерывание и, пока обработчик прерывания подготавливает новый буфер данных, программирует DMA и звуковую плату для продолжения воспроизведения, проходит некоторое время, что может звучать как щелчок. Этого можно избежать, если воспользоваться режимом автоинициалиэации, позволяющим обойтись без остановок во время воспроизведения.

FILESPEC equ 'C:\WINDOWS\MEDIA\TADA.WAV'

SBPORT equ 220h

SBIRQ equ 5 ; только IRQ0-IRQ7

.model tiny

.code

.186

org 100h ; COM-программа

start:

call dsp_reset ; инициализация DSP

jc no_blaster

mov bl, 0D1h ; команда 0D1h

call dsp_write ; включить звук

call open_file ; прочитать файл в буфер

call hook_sbirq ; перехватить прерывание

mov bl, 40h ; команда 40h

call dsp_write ; установка скорости передачи

mov bl, 0B2h ; константа для 11025Hz/Stereo

call dsp_write

call program_dma ; начнём DMA-передачу данных

main_loop: ; основной цикл

cmp byte ptr finished_flag, 0

je main_loop ; выход когда байт finished_flag = 1

call restore_sbirq ; восстановить прерывание

no_blaster:

ret

old_sbirq dd ? ; адрес старого обработчика

finished_flag db 0 ; флаг окончания работы

filename db FILESPEC, 0 ; имя файла

; обработчик прерывания звуковой карты

; устанавливает флаг finished_flag в 1

sbirq_handler proc far

push ax

mov byte ptr cs:finished_flag, 1 ; установить флаг

mov al, 20h ; послать команду EOI

Код исходной программы(продолжение)

out 20h, al ; в контроллер прерываний

pop ax

iret

sbirq_handler endp

; процедура dsp_reset

; сброс и инициализация DSP

dsp_reset proc near

mov dx, SBPORT+6 ; порт 226h - регистр сброса DSP

mov al, 1 ; запись в него единицы запускает инициализацию

out dx, al

mov cx, 40 ; небольшая пауза

dsploop:

in al, dx

loop dsploop

mov al, 0 ; запись нуля завершает инициализацию

out dx, al ; теперь DSP готов к работе

add dx, 8 ; порт 22Eh - бит 7 при чтении указывает на

занятость

mov cx, 100 ; буфера записи DSP

check_port:

in al, dx ; прочитаем состояние буфера записи

and al, 80h ; если бит 7 ноль

jz port_not_ready ; порт ещё не готов

sub dx, 4 ; иначе: порт 22Ah - чтение данных из DSP

in al, dx

add dx, 4 ; порт снова 22Eh

cmp al, 0AAh ; проверим, что DSP возвращает 0AAh при

; чтении - это сигнал его готовности к

; работе

je good_reset

port_not_ready:

loop check_port ; повторить проверку на 0AAh 100 раз

bad_reset:

stc ; если Sound Blaster не откликается

ret ; вернуться с CF=1

good_reset:

clc ; если инициализация прошла успешно

ret ; вернуться с CF=0

dsp_reset endp

; процедура dsp_write

; посылает байт из BL в DSP

dsp_write proc near

mov dx, SBPORT+0Ch ; порт 22Ch - ввод данных/команд DSP

write_loop: ; подождём готовности буфера записи DSP

in al, dx ; прочитаем порт 22Ch

Код исходной программы(продолжение)

and al, 80h ; и проверим бит 7

jnz write_loop ; если он не ноль - подождём ещё

mov al, bl ; иначе:

out dx, al ; пошлём данные

ret

dsp_write endp

; процедура hook_sbirq

; перехватывает прерывание звуковой карты и разрешает его

hook_sbirq proc near

mov ax, 3508h+SBIRQ ; AH=35h, AL=номер прерывания

int 21h ; получим адрес старого обработчика

mov word ptr old_sbirq, bx ; и сохраним его

mov word ptr old_sbirq+2, es

mov ax, 2508h+SBIRQ ; AH=25h, AL=номер прерывания

mov dx, offset sbirq_handler ; установим новый обработчик

int 21h

mov cl, 1

shl cl, SBIRQ

not cl ; построим битовую маску

in al, 21h ; прочитаем OCW1

and al, cl ; разрешим прерывание

out 21h, al ; запишем OCW1

ret

hook_sbirq endp

; процедура restore_sbirq

; восстановим обработчик и запретим прерывание

restore_sbirq proc near

mov ax, 3508h+SBIRQ ; AH=25h AL=номер прерывания

lds dx, dword ptr old_sbirq

int 21h ; восстановим обработчик

mov cl, 1

shl cl, SBIRQ ; построим битовую маску

in al, 21h ; прочитаем OCW1

or al, cl ; запретим прерывание

out 21h, al ; запишем OCW1

ret

restore_sbirq endp

; процедура open_file

; открывает файл filename и копирует звуковые данные из него, ;считая что это - tada.wav, в буфер buffer

open_file proc near

mov ax, 3D00h ; AH=3Dh AL=00

mov dx, offset filename ; DS:DX - ASCIZ-строка с именем файла

int 21h ; открыть файл для чтения

jc error_exit ; если не удалось открыть файл - выйти

mov bx, ax ; идентификатор файла в BX

Код исходной программы(продолжение)

mov ax, 4200h ; AH=42h, AL=0

mov cx, 0 ; CX:DX - новое значение указателя

mov dx, 38h ; по этому адресу начинаются данные в tada.wav

int 21h ; переместим файловый указатель

mov ah, 3Fh ; AH=3Fh

mov cx, 27459 ; это - длина данных в файле tada.wav

push ds

mov dx, ds

and dx, 0F000h ; выровняем буфер на границу 4K-страницы

add dx, 1000h ; для DMA

mov ds, dx

mov dx, 0 ; DS:DX - адрес буфера

int 21h ; чтение файла

pop ds

ret

error_exit: ; если не удалось открыть файл

mov ah, 9 ; AH=09h

mov dx, offset notopenmsg ; DS:DX = адрес сообщения об

; ошибке

int 21h ; вывод строки на экран

int 20h ; конец программы

notopenmsg db 'Could not open file', 0Dh, 0Ah ; сообщение об

; ошибке

db 'Exiting', 0Dh, 0Ah, '$'

open_file endp

; процедура program_dma

; настраивает канал 1 DMA

program_dma proc near

mov al, 5 ; замаскируем канал 1

out 0Ah, al

xor al, al ; обнулим счётчик

out 0Ch, al

mov al, 49h ; установим режим передачи

; (используйте 59h для автоинициализации)

out 0Bh, al

push cs

pop dx

and dh, 0F0h

add dh, 10h ; вычислим адрес буфера

xor ax, ax

out 02h, al ; запишем младшие 8 бит

out 02h, al ; запишем следующие 8 бит

mov al, dh

shr al, 4

out 83h, al ; запишем старшие 4 бита

mov ax, 27459 ; длина данных в tada.wav

dec ax ; DMA требует длину-1

Код исходной программы(заключение)

out 03h, al ; запишем младшие 8 бит длины

mov al, ah

out 03h, al ; запишем старшие 8 бит длины

mov al, 1

out 0Ah, al ; снимем маску с канала 1

mov bl, 14h ; команда 14h

call dsp_write ; 8-битное простое DMA-воспроизведение

mov bx, 27459 ; размер данных в tada.wav

dec bx ; минус 1

call dsp_write ; запишем в DSP младшие 8 бит длины

mov bl, bh

call dsp_write ; и старшие

ret

program_dma endp

end start

Заключение

С момента рождения языка Assembler прошло много времени, появились новые языки и в особенности языки высокого уровня. И казалось бы что такой неудобный, грамосткий, трудно отлаживаемый язык Assembler исчезнет на всегда. Но время показало обратное – он до сих пор пользуется большой популярностью. Ведь благодаря ему можно написать высоко скоростной код, использующий полностью возможности операционной системы, взаимодействовать с внешними устройствами на уровне портов и многое другое. Программирование современных звуковых плат – весьма сложное занятие, требующее уверенное владение языком. В данной работе я попытался описать и показать методы работы со звуковой картой.

Список литературы

Assembler для DOS, Windows и UNIX. – Зубков С.В. ”ДМК” Москва 2000г.

Искусство программирования на Ассемблере. – Голубь Н.Г. ”DiaSoft” 2002г.

Ассемблер для Windows. – Пирогов В.Ю. 2002г.

Windows Assembly Language and Systems Programming.- Barry Kauler. (перевод).

Секреты системного программирования в Windows 98. - Мэтт Питрек. К., 1996

Сайт www.wasm.ru.

Для подготовки данной работы были использованы материалы с сайта http://referat.ru/


Страницы: 1, 2, 3


Новости


Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

                   

Новости

Обратная связь

Поиск
Обратная связь
Реклама и размещение статей на сайте
© 2010.