Вы не зашли.
Приветствую всех.
Возникла необходимость программирования DSP звуковой карты, в книге В. Несвижский "Программирование аппаратных средств в Windows" имеется некоторый материал, откуда понятно что DSP надо программировать через порты 2x6h; 2xAh; 2xCh; 2xEh.
Меня конкретно интересуют функции порта 2xCh.
В книге есть небольшой список функций, но их оказалось не достаточно.
Пожалуйста помогите достать как можно более полный список функций для этого порта(2xCh).
SOA
Эм... Ну вообще то, этото порт используется для записи команд или данных.
Но он легко гуглится :)
Перечень команды можн найти тут: http://irlp.kc6hur.net/SoundBlaster.pdf
Некоторое пособие по кодингу нашлось тут: http://articles.org.ru/docum/soundbl.php
В принципе вам надо бы сказать что же вы хотите сделать, более конкретно, каких вам функций не хватило например. Тогда вам подскажут гораздо более точно.
TermoSINteZ
У меня по google получилось найти только то что в прикрепленном файле отсюда http://www.dcee.net/Files/Programm/Sound/.
Спасибо за перечень команд!
Я пытаюсь написать простенький плеер с возможностью регулировки звука покачто только для wav файлов.
Поэтому у меня возникла необходимость написания процедур воспроизведения звука как минимум с 8 битным, 16 битным и в перспективе 24 битным сэймплом.
С написанием функции для воспроизведения 8 битного сэймпла проблем не возникло, я использовал функцию 10h и воспроизвожу звук в цикле по биту из буфера, длина которого расчитывается так чтоб его хвататало на 1 секунду.
Но вот для воспроизведения 16 битного сэймпла я функцию пока не нашел чтоб была подобной функции 10h для 8 битного. В наличии покачто только функции с использованием DMA где размер буфера не может превышать 64Кб и воспроизводится на автомате из этого же буфера, а не как в 10h по одному байту, вследствие чего проблематично поставить в цикл данную функцию. Можно конечно использовать функции паузы, или еще как то ухищряться, но это не то что мне нужно.
P.S. то что находится в прикрепленном файле можно посмотреть в более читабельном виде здесь
http://homepages.cae.wisc.edu/~brodskye … 16doc.html
Отредактировано SOA (04-08-2010 15:54:31)
TermoSINteZ
Ещё раз спасибо за перечень команд, там на 55 странице кажется нашел то что меня интересовало.
Думаю вопрос можно считать закрытым.
8D
SOA
Ну если точно удалось, вы напишите как поступили и как решили проблему, чтобы другие новички, столкнувшись - нашли ответ.
TermoSINteZ
OK
Если получится то отпишу процедуру с коментами, если вы конечно это имели ввиду.
Ну а если вы имели ввиду функцию то тут все просто ставим длину буфера для функции 16 бит и все функция обрабатывается один раз и ее смело можно помещать в цикл обработки большого буфера.
Отредактировано SOA (25-07-2010 14:24:03)
Да, именно это и имел ввиду. Ну или хотя бы на словах подробно, как решалась задача.
TermoSINteZ
К сожелению при попытке использования данной функции возникли некоторые трудности. Распишу по шагам, как на странице 55 перечня команд:
1 Установить бит прерываний для DSP
Enable_16_bit_Interrupt proc ; процедура устанавливающая прерывание DSP для 16 битного сэймпла Push edx and bl,11110000b add bl,Fh ; сохраняем в bx номер порта 2xFh mov dl,82h ; номер регистра хранящего бит прерываний для DSP call Write_DSP ; вызываем этот регистр(функцию) in Restore_int_mode,bx ; сохраняем предидущее значение бита прерываний для DSP @cikl mov dl,82h ; номер регистра хранящего бит прерываний для DSP call Write_DSP ; вызываем этот регистр(функцию) mov dl,2h ; устанавливаем второй бит call Write_DSP ; записываем в порт 2xF значение 00000010b in dl,bx ; проверяем установился ли бит cmp dl,2h jne @cikl Pop edx ret Enable_16_bit_Interrupt ENDP
2 разрешить прерывания (я их не запрещал)
3 запрограммировать DMA контроллер для 16 битного DMA mode transfer (к сожелению информации в мануале не оказалось, вернее она слишком скудная для программирования контроллера динамического доступа к памяти)
4 установить частоту дискретизации
Set_DSP_Sampling_Rate proc ; процедура устанавливающая частоту дискретизации в моем случае не важна push edx and bl,11110000b add bl,Ch ; сохраняем в bx номер порта 2xCh mov dl,41h ; режим воспроизведения call Write_DSP mov dl,ACh ; Старший байт значения частоты call Write_DSP mov dl,44h ; младший байт значения частоты call Write_DSP ; частота дискретизации равна 44100Гц но в моём случае не важна pop edx ret Set_DSP_Sampling_Rate ENDP
5 установить команду, затем тип передачи бит, число передаваемых бит
Set_Transfer_mode proc ; процедура устанавливающая тип передачи бит и размер буфера push edx and bl,11110000b add bl,Ch ; сохраняем в bx номер порта 2xCh mov dl,B0h ; 16 битное воспроизведение call Write_DSP mov dl,30h ; 16 битное стерео call Write_DSP mov dl,1h ; младший байт числа сэймплов, которые будут обработаны call Write_DSP mov dl,0h ; старший байт числа сэймплов, которые будут обработаны call Write_DSP pop edx ret Set_Transfer_mode ENDP
6 Восстановить бит прерываний для DSP
Restore_interrupt_mode proc ; процедура востанавливающая значение бита прерывания для DSP Push edx and bl,11110000b add bl,Fh ; сохраняем в bx номер порта 2xFh @cikl mov dl,82h ; номер регистра хранящего бит прерываний для DSP call Write_DSP ; вызываем этот регистр(функцию) mov dl,Restore_int_mode ; востанавливаем значение бита прерываний для DSP call Write_DSP ; записываем в порт 2xFh значение 00000010b in dl,bx ; проверяем установился ли бит cmp dl,Restore_int_mode jne @cikl pop edx ret Restore_interrupt_mode ENDP
Write_DSP proc ; процедура записи в порт DSP 2xCh @cikl1: ; проверяем готовность порта 2xch к приему данных in dl,bx ; считываем в dl значение в порте 2xch bt dl,7 jc @cikl1 out bx,dl ; записываем команду в порт 2xch ret Write_DSP ENDP
После этих инструкций на 56 странице идет следующий текст после таблички The transfer begins here. The DSP will generate an interrupt after transferring the programmed number of samples.
Я так понимаю что после 5 пункта DSP должен считать из памяти DMA заданное число бит, после чего будет сгенерировано прерывание. Но т.к. DMA остался незапрограммированным, то нет возможности передать через него функции информацию.
Получается все упирается в пункт 3.
Если я не прав поправьте меня пожалуйста. =(
Отредактировано SOA (25-07-2010 19:27:17)
Вроде бы нашел информацию по программированию DMA.
http://wasm.ru/article.php?article=atazen02
www.inversereality.org/files/dmaprogramming.pdf
Не знаю поможет или нет :/.
P.S. если у когото есть маны по программированию DMA на asm для soundblaster'а plz скажите где скачать.
Отредактировано SOA (26-07-2010 07:15:26)
SOA
если у когото есть маны по программированию DMA на asm для soundblaster'а plz скажите где скачать.
кажется в "Ассемблер Зубков С.В." было
wsd
Спасибо!
Отредактировано SOA (26-07-2010 13:37:11)
Нашел еще немного информации по программированию DMA, которую свел в небольшой мануал(пока черновой вариант).
По прежнему остаются вопросы по программированию DMA
Как запрограммировать прерывания, которыми DMA сигнализирует устройству о завершении транзакции?
Как сообщить устройству из какого канала DMA считывать информацию, хотя сам собой напрашивается ответ сообщить ему адрес в виртуальной памяти, где хранится DMA буфер и при получении прерывания считывать буфер, вот только если бы это было реализуемо, то в DMA отпала необходимость и я сообщил бы адрес большого буфера, но информации на этот счет нет.
Но стало ясно что программа должна работать в нулевом кольце системы, т.к. при программировании DMA используется команда CLI, которая если я не ошибаюсь может использоваться только в нулевом кольце.
Отредактировано SOA (04-08-2010 15:26:29)
Все мануал считаю окончательно сформированным.
Спасибо Jari Kaija программисту из братской финляндии, благодаря мануалу которого удалось разобраться с программированием DMA для DSP и добавить пример программирования.
Пока что удалось накодить следующее и исправить множество ошибок допущенных в предидущем коде
Данные
title PlayBuf for 32 byte
.486P
.MODEL FLAT, Stdcall
PUBLIC PlayByte
PUBLIC PlayWord
PUBLIC ResetDSP
.DATA
EXTRN bufsize: DWORD ; Перемнная хранящая количество элементов массива
EXTRN numchannels: WORD ; Переменная хранящая количество каналов fmt.numchannels
EXTRN vol: BYTE ; Переменная которая контроллирует громкость звука
adres DWORD ? ; Переменная хранящая адрес нулевого элемента массива
delay WORD ? ; Переменная содержащая задержку в мкс
Restore_int_mode byte ? ; переменная хранящая тип прерывания DSP который был ранее1Установить бит прерываний для DSP
Enable_16_bit_Interrupt proc ; процедура устанавливающая бит прерывания для DSP Push eax and dl,11110000b add dl,0Fh ; сохраняем в bx номер порта 2xFh mov al,82h ; адрес регистра хранящего бит прерываний в карте регистров микшера out dx,al ; вызываем этот регистр(функцию) in al,dx ; сохраняем предидущее значение бита прерываний для DSP mov Restore_int_mode,al cikl8: mov al,82h ; номер регистра хранящего бит прерываний для DSP out dx,al ; вызываем этот регистр(функцию) mov al,2h ; устанавливаем второй бит (прерывание для 16 битного сэймпла) out dx,al ; записываем в порт 2xF значение 00000010b in al,dx ; проверяем установился ли бит cmp al,2h jne cikl8 Pop eax ret Enable_16_bit_Interrupt ENDP
2 пропускаем разрешение прерываний так как мы их не запрещали
3 Программируем DMA контроллер для 16 битного сэймпла без автоинициализации в моно режиме
Program_DMA_chanel_5 proc ; Программируем 5 порт DMA
push eax edx
;Отключаем 5 канал, который будем использовать для передачи
mov dx,0D4h ; адрес Single mask register для 16 битного DMA
mov al,5h ; команда отключения 5 канала
out dx,al
;Перезагружаем регистр flip-flop для DMA2
mov dx,0D8h ; адрес регистра flip-flop для 16 битного DMA
mov al,0h
out dx,al
;Устанавливаем значение Mode регистра
mov dx,0D6h ; Адрес mode регистра для DMA2
mov al,01001001b ; программируем mode регистр
out dx,al
;Передаем в Offset port значение указателя
mov dx,0C4h ; Адрес offset port для 5 канала
push eax ebx ecx
bt ebx,16
jc next1 ; если 16 бит равен 1
jmp next2 ; если не равен 1
next1:
mov cl,1
shr ebx,cl ; делим указатель на 2
next2:
mov ax,bx ; помещаем младшую часть делимого в ax
mov edx,ebx
shr edx,16 ; помещаем старшую часть делимого в dx
mov bx,65535
div bx
out dx,al ; Передаем в порт младший бит часного
mov al,ah
out dx,al ; Передаем в порт старший бит часного
pop ecx ebx eax
;Передаем в Block size регистр значение 1= 2 байтам т.к. передаваемое значение всегда на меньше
mov dx,0C6h ; Адрес Block size регистра
mov al,01h
out dx,al
;***************************************************************************
;Передаем в page port значение номера страницы
mov dx,8Bh ; Адрес page port для 5 канала
push eax ebx
mov ax,bx ; помещаем младшую часть делимого в ax
mov edx,ebx
shr edx,16 ; помещаем старшую часть делимого в dx
mov bx,65535; получаем номер страницы
div bx
out dx,al ; передаем в page порт номер страницы
pop ebx eax
;***************************************************************************
;Включаем 5 канал
mov dx,0D4h ; Адрес Single mask register для 16 битного DMA
mov al,1h ; Команда включения 5 канала
out dx,al
pop edx eax
ret
Program_DMA_chanel_5 ENDP4 устанавливаем частоту дискретизации
Set_DSP_Sampling_Rate proc ; процедура устанавливающая частоту дискретизации в моем случае не важна push eax and dl,11110000b add dl,Ch ; сохраняем в bx номер порта 2xCh mov al,41h ; режим воспроизведения call Write_DSP mov al,0ACh ; Старший байт значения частоты call Write_DSP mov al,44h ; младший байт значения частоты call Write_DSP ; частота дискретизации равна 44100Гц но в моём случае не важна pop eax ret Set_DSP_Sampling_Rate ENDP
5 Устанавливаем команду тип передачи и число бит
Set_Transfer_mode proc ; процедура устанавливающая тип передачи бит и размер буфера push eax and dl,11110000b add dl,Ch ; сохраняем в bx номер порта 2xCh mov al,0B0h ; 16 битное воспроизведение call Write_DSP mov al,10h ; 16 битное моно call Write_DSP mov al,1h ; младший байт числа сэймплов, которые будут обработаны call Write_DSP mov al,0h ; старший байт числа сэймплов, которые будут обработаны call Write_DSP pop eax ret Set_Transfer_mode ENDP
6 Востанавливаем бит прерываний для DSP
Restore_interrupt_mode proc ; процедура востанавливающая значение бита прерывания для DSP Push eax and dl,11110000b add dl,0Fh ; сохраняем в bx номер порта 2xFh cikl9: mov al,82h ; номер регистра хранящего бит прерываний для DSP out dx,al ; вызываем этот регистр(функцию) mov al,Restore_int_mode ; востанавливаем значение бита прерываний для DSP out dx,al ; записываем в порт 2xFh значение 00000010b in al,dx ; проверяем установился ли бит cmp al,Restore_int_mode jne cikl9 pop eax ret Restore_interrupt_mode ENDP
Процедура записи в порт DSP
Write_DSP proc ; процедура записи в порт DSP 2xCh push eax cikl3: ; проверяем готовность порта 2xch к приему данных in al,dx ; считываем в al значение в порте 2xch bt ax,7 jc cikl3 pop eax out dx,al ; записываем команду в порт 2xch ret Write_DSP ENDP
Процедура воспроизведения 16 битного сэймпла из большого буфера
PlayWord Proc ; Процедура проигрывания wav файла с длинной сэймпла word
PUSH EAX EBX EDX ECX
push ebp
mov ebp,esp ; Поместили в bp указатель на вершину стека
mov dx,[ebp+18] ; Поместили в dx номер порта который предварительно сохранили под delphi
; 18 потому что eax+ebx+edx+ecx+bp=18 байт
mov ebx,[ebp+20]
mov adres,ebx ; adres указывает на область памяти где хранится нулевой элемент массива
; используем ebx потому что переменная типа DWORD
mov ax,[ebp+24]
mov delay,ax
POP ebp
call ResetDSP
call Enable_16_bit_Interrupt ; Устанавливаем прерывания для DSP
call Set_DSP_Sampling_Rate ; Устанавливаем частоту дискретизации для DSP
mov ecx,bufsize ; проигрываем буфер обмена
and dl,11110000b
add dl,Ch ; установили в bx номер порта 2xCh
cikl2: ; воспроизводим два бита
call Program_DMA_chanel_5 ; Программируем DMA для DSP
call Set_Transfer_mode ; Программируем тип передачи и длинну буфера для DSP
;Теперь мы должны что то услышать
push eax ecx edx
mov ah,86h ; номер функции задержки
xor ecx,ecx ; старшее слово таймера задержки
mov dx,delay ; младшее слово таймера задержки
int 15h ; подождать некоторое время
pop edx ecx eax
lea ebx,[ebx+numchannels]
lea ebx,[ebx+numchannels] ; увеличиваем указатель два раза потому что тип word
loop cikl2
call Restore_interrupt_mode ; Востанавливаем бит прерывания для DSP
POP ECX EDX EBX EAX
add esp,8 ; т.к. мы поместили 8 байт в стек перед выполнением процедуры
; номер порта+adres+delay
ret
PlayWord ENDPПока что интересует вопрос можно ли считать 32 битный указатель типа pointer из delphi линейным адресом, потому что от этого зависит работа процедуры инициализации DMA контроллера.
Если выражаться более точно то правильность значений в порте Offset и порте Page port DMA контроллера.
Кто в курсе пишите, ну и конечно если ошибки увидите ругайте:)
Ниже прикрепляю asm файл для tasm.
Отредактировано SOA (04-08-2010 15:50:51)