Приветствую всех. Возникла необходимость программирования 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/sb16doc/sb16doc.html
TermoSINteZ Ещё раз спасибо за перечень команд, там на 55 странице кажется нашел то что меня интересовало. Думаю вопрос можно считать закрытым. 8D
SOA Ну если точно удалось, вы напишите как поступили и как решили проблему, чтобы другие новички, столкнувшись - нашли ответ.
TermoSINteZ OK Если получится то отпишу процедуру с коментами, если вы конечно это имели ввиду. Ну а если вы имели ввиду функцию то тут все просто ставим длину буфера для функции 16 бит и все функция обрабатывается один раз и ее смело можно помещать в цикл обработки большого буфера.
TermoSINteZ К сожелению при попытке использования данной функции возникли некоторые трудности. Распишу по шагам, как на странице 55 перечня команд: 1 Установить бит прерываний для DSP Код (Text): 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 установить частоту дискретизации Код (Text): 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 установить команду, затем тип передачи бит, число передаваемых бит Код (Text): 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 Код (Text): 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 Код (Text): 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. Если я не прав поправьте меня пожалуйста. =(
Вроде бы нашел информацию по программированию DMA. http://wasm.ru/article.php?article=atazen02 www.inversereality.org/files/dmaprogramming.pdf Не знаю поможет или нет :/. P.S. если у когото есть маны по программированию DMA на asm для soundblaster'а plz скажите где скачать.
Нашел еще немного информации по программированию DMA, которую свел в небольшой мануал(пока черновой вариант). По прежнему остаются вопросы по программированию DMA Как запрограммировать прерывания, которыми DMA сигнализирует устройству о завершении транзакции? Как сообщить устройству из какого канала DMA считывать информацию, хотя сам собой напрашивается ответ сообщить ему адрес в виртуальной памяти, где хранится DMA буфер и при получении прерывания считывать буфер, вот только если бы это было реализуемо, то в DMA отпала необходимость и я сообщил бы адрес большого буфера, но информации на этот счет нет. Но стало ясно что программа должна работать в нулевом кольце системы, т.к. при программировании DMA используется команда CLI, которая если я не ошибаюсь может использоваться только в нулевом кольце.
Все мануал считаю окончательно сформированным. Спасибо Jari Kaija программисту из братской финляндии, благодаря мануалу которого удалось разобраться с программированием DMA для DSP и добавить пример программирования.
Пока что удалось накодить следующее и исправить множество ошибок допущенных в предидущем коде Данные Код (Text): 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 Код (Text): 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 битного сэймпла без автоинициализации в моно режиме Код (Text): 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 ENDP 4 устанавливаем частоту дискретизации Код (Text): 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 Устанавливаем команду тип передачи и число бит Код (Text): 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 Код (Text): 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 Код (Text): 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 битного сэймпла из большого буфера Код (Text): 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.