Возникла одна идея.
Использовать ВМЕСТО звуковухи "РС-спикер"
Это было возможно (вполне)
Есть два способа достижения этого:
Википедия писал(а):Имеются два способа управления динамиком.
Программируемый таймер, генерирующий прямоугольную звуковую волну заданной частоты без участия центрального процессора. Это позволяет проигрывать простые одноголосые звуковые сигналы. Если программа зависала во время проигрывания звука, таймер продолжал работать, выдавая одну ноту, пока компьютер не перезагрузят.
И прямое управление мембраной через порт 61h с дискретностью в 1 бит. Подавая с большой частотой то 0, то 1, с помощью широтно-импульсной модуляции можно синтезировать низкокачественный оцифрованный звук — правда, за счёт существенного использования ресурсов процессора. Этим в своё время широко пользовались трекеры и некоторые игры (Metal Mutant). Все подобные программы не работают в многозадачных операционных системах.
Драйвер разрабатываю для Win XP.
Считаю, второй способ на уровне ядра вполне возможен.
По обоим вопросам есть определенные наработки:
По обоим СПРАВКА И ПРИМЕРЫ:
Код: Выделить всё
- 31 -
Таймер и генерация звука
Программируемый таймер 8253
Для задания временных интервалов и формирования сигналов с
различными временными параметрами в IBM PC/XT применяется
программируемый таймер 8253 (отечественный аналог КР580ВН53), в
AT - 8254. С точки зрения программиста они идентичны. В состав
таймера входят: буфер шины данных, схема управления
вводом-выводом и три независимых канала, каждый из которых
содержит регистр режима, схему управления каналом, буфер и
16-разрядный счетчик.
Программирование канала осуществляется путем вывода
управляющих слов в регистр режима каналов и начального значения
в его счетчики. Каждый канал имеет управляющий вход GATE и выход
OUT и может работать в одном из следующих шести режимов.
Режим 0 (прерывание терминального счета). После записи
управляющего слова в регистр режима канала на выходе ОUT
устанавливается напряжение низкого уровня; загрузка счетчика не
изменяет это состояние. Затем начинается декремент счетчика
(последовательное вычитание из него единицы). В момент, когда
счетчик обнулится, на выходе OUT установливается напряжение
высокого уровня и сохраняется до загрузки счетчика новым
значением. Счет возможен только при наличие сигнала высокого
уровня на входе GATE. Низкий уровень этого сигнала или
ниспадающий фронт запрещают счет.
Перезагрузка счетчика во время приводит к следующему:
загрузка младшего байта останавливает текущий счет, загрузка
старшего байта запускает новый цикл счета. Минимально допустимое
значение счетчика равно 2.
Режим 1 (ждущий мультивибратор). На выходе OUT формируется
отрицательный импульс длительностью t=n*T, где n - число,
загруженное в счетчик, T - период тактовых импульсов. Низкий
уровень на выходе OUT устанавливается со следующего такта после
подачи на вход GATE сигнала высокого уровня.
Загрузка в счетчик нового числа не влияет на длительность
текущего импульса, а учитывается при следующем запуске.
Перезапуск счетчика производится нарастающим фронтом входа GATE
(без перезагрузки счетчика). Минимальное допустимое n=1.
Режим 2 (генератор частоты). Каждый раз после достижения
счетчиком нуля на выходе OUT появляется отрицательный импульс с
длительностью один такт. Перезагрузка счетчика сказывается
только после перезапуска счетчика. При исчезновении сигнала
высокого уровня на входе GATE прекращается счет и на выход OUT
подается напряжение высокого уровня. Перезапуск счетчика
происходит при наличии на входе GATE сигнала высокого уровня.
Режим 3 (генератор меандра). Аналогичен режиму 2, но
положительный уровень выходного сигнала занимает первый
- 32 -
полупериод, а отрицательный - второй полупериод. Точнее, если n
(начальное значение счетчика) четно, то длительность
положительного и отрицательного полупериодов равна n*T/2; если
же n нечетно - то (n+1)*T/2 и (n-1)*Т/2 соотвественно. Низкй
уровень сигнала на входе GATE запрещает счет, на выходе OUT
устанавливается сигнал высокого уровня. Высокий уровень GATE
разрешает счет, а нарастание его запускает счетчик начального
состояния. Отметим, что n=3 в этом режиме недопустимо.
Режим 4 (счетчик событий). По окончании отсчета числа,
загруженного в счетчик, на выходе OUT формируется отрицательный
импульс длительностью один такт. Запись в счетчик во время счета
младшего байта не влияет на текущий счет, а запись старшего
байта перезапускает счетчик. Низкий уровень входа GATE запрещает
счет, высокий - разрешает. Минимальное допустимое значение
счетчика равно 1.
Режим 5 (счетчик событий с автозагрузкой). Отличие от
режима 4 состоит в том, что каждое нарастание сигнала на входе
GATE перезапускает счетчик. Перезагрузка счетчика не влияет на
текущий цикл, однако следующий цикл определяется вновь
занесенным числом.
Временные диаграммы режимов таймера приведены на следующем
рисунке:
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=5 ----------¬n=4 ----------
WR ¦L----- L-----
¦ ----------¬ ---------
GATE +-------- L----
+-----¬ ----------¬ ---
OUT ¦ L------------ L----------------
¦
n ¦ 5 4 3 2 1 0 4 3 2 2 1 0
L-------------------------------------------------
Режим 0
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=4 -------¬n=5 ----------
WR ¦L----- L-----
¦ ----------¬ --¬ ----------
GATE +---------- L----- L-----
+----------¬ --------¬ ---
OUT ¦ L-------- L----------------
¦
n ¦ 4 3 2 1 0 5 4 3 5 4 3 2 1 0
L-------------------------------------------------
Режим 1
- 33 -
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=4 ---¬n=3 ----------
WR ¦L----- L-----
¦ ----------¬ ----------
GATE +------- L-----
+----------¬ -----¬ ------¬ ----------¬ ---
OUT ¦ L-- L-- L-- L--
¦
n ¦ 4 3 2 1 0 3 2 1 0 3 2 1 0 3 2 1 0
L-------------------------------------------------
Режим 2
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=4 ----------¬n=5 ----------
WR ¦L----- L-----
¦ ----------¬ ----
GATE +------ L----
+----------¬ ------¬ ------¬ ---------
OUT ¦ L----- L----- L-----
¦
n ¦ 4 3 2 1 0 4 3 2 1 0 4 3 2 1 0 5 5 4
L-------------------------------------------------
Режим 3
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=4 ----------¬n=5 ----------
WR ¦L----- L-----
+----------¬ ----------
GATE ¦ L----
+----------¬ ----------¬ --
OUT ¦ L-- L--
¦
n ¦ 4 3 2 1 0 5 5 4 3 2 1 0
L-------------------------------------------------
Режим 4
¦-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬-¬
CLK +-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L-L
__ +¬n=4 ----------
WR ¦L-----
¦ ---------¬ --¬ ----------
GATE +---------- L---- L----
+----------¬ ----------¬ -------
OUT ¦ L-- L--
¦
n ¦ 4 3 2 1 0 4 3 4 3 2 1 0
L-------------------------------------------------
Режим 5
- 34 -
В IBM PC таймер имеет базовый адрес 40h и следующие
программируемые регистры:
Адрес Операция Назначение
----------
40h запись Загрузка счетчика канала 0
чтение Чтение счетчика канала 0
41h запись Загрузка счетчика канала 1
чтение Чтение счетчика канала 1
42h запись Загрузка счетчика канала 2
чтение Чтение счетчика канала 2
43h запись Запись управляющего слова
в регистр режима канала
----------
Управляющее слово имеет следующий формат:
7 6 5 4 3 2 1 0
--T--T--T--T--T--T--T--¬
¦ ¦ ¦ ¦ ¦ Биты Маска
L-+--+--+--+--+T-+--+-T- ---- -------
¦ ¦ ¦ L> 0: 0 = двоичный код, а & 1
¦ ¦ ¦ 1 = двоично-десятичный код
¦ ¦ L-------> 1-3: режим работы канала: а & 0Eh
¦ ¦ 000 - режим 0
¦ ¦ 001 - режим 1
¦ ¦ X10 - режим 2
¦ ¦ X11 - режим 3
¦ ¦ 100 - режим 4
¦ ¦ 101 - режим 5
¦ L--------------> 4-5: вид загрузки счетчика: а & 30h
¦ 00 - "защелкивание"
¦ (биты 0-3 безразличны)
¦ 01 - только младший байт
¦ 10 - только старший байт
¦ 00 - младший байт, затем старший
L--------------------> 6-7: номер канала: a & C0h
00 - канал 0
01 - канал 1
10 - канал 2
11 - запрещенная комбинация
Существует два способа чтения текущего значения счетчика
канала.
1. Чтение с остановом счетчика. Для обеспечения стабильных
показаний необходимо приостановить работу канала либо подачей
сигнала низкого уровня на вход GATE (кроме режима 1), либо
блокированием тактовых импульсов.
2. Чтение "на лету". Для считывания счетчика без остановки
процесса счета используется посылка в порт 43h управляющего
- 35 -
слова в режиме "защелкивания" (см. выше). Это управляющее слово
фиксирует текущее значение счетчика и Вы можете считать его
младший байт, а затем старший байт.
Таймер на системной плате IBM PC
В IBM PC каналы таймера имеют следующее назначение.
Канал Назначение Режим
----------
0 системные часы (IRQ0) 3, счетчик=0 (65536)
1 запрос для канала 0 ПДП
(регенерация памяти) 2, счетчик=18
2 генератор звука --
----------
Тактовая частота каждого канала равна 1,19318 МГц, т. е.
каждый такт имеет длительность 0,84 мсек. Вход GATE каналов 0 и
1 всегда имеют высокий уровень, поэтому счет на этих каналах
разрешен всегда. Вход GATE канала 2 управляется битом 0 порта PB
интерфейса 8255 (см. гл. 5), связанного с портом 61h.
При начальной загрузке BIOS инициализирует канал 0 для
работы в режиме 3 со счетчиком 0 (т. е. 65536 декрементов на
цикл счета). Поэтому частота системных часов равна
1,19 МГц/65536 = 18.2 Гц
и прерывание IRQ0, связанное с вектором Int 8, происходит 18,2
раз в секунду, т. е. каждые 55 мсек.
Вы можете перепрограммировать канал 0, но тогда
- BIOS не сможет отслеживать текущее время и дату;
- нарушится работа с гибкими дисками, т. к. включение и
выключение их двигателей отсчитывается по текущему времени.
Канал 1 работает в режиме 2 со счетчиком 18, поэтому
регенерация памяти происходит каждые 18 мсек. Перепрог-
раммировать его нельзя, т. к. это приведет к потере данных в
ОЗУ.
Программирование канала 2 описано в следующем пункте.
- 36 -
Генерация звука
На вход звукогенератора поступает логическое "И" двух
сигналов: выхода OUT 2-го канала таймера и содержимого бита 1
порта РВ интерфейса 8255. Поэтому простейший способ генерации
звука состоит в программировании канала 2 таймера так, чтобы он
выдавал прямоугольный импульс заданной частоты, лежащий в
звуковом диапазоне (20 Гц - 20 КГц). Для этого следует
использовать режим таймера 3 с подходящим начальным значением
счетчика. Если затем установить биты 0 и 1 порта РВ, то импульс
начнет поступать на вход звукогенератора (бит 0 - это вход GATE
канала 2, разрешающий счет, а бит 1 - разрешение выдачи выхода
OUT на вход звукогенератора). Для выключения звука достаточно
сбросить биты 0 - 1 в РВ. Преимущество этого метода состоит в
том, что, запустив генерацию звука, ЦП может выполнять другие
действия. Значение счетчика 2-го канала вычисляется по формуле
n=1193181/f=1234DDh/f (1193181 - тактовая частота таймера в Гц,
f - требуемая частота звука).
Пример:
;
; подпрограмма генерации звука
; Вход: АX= частота звука в Гц
;
Sound proc near
push ax ;сохранить регистры
push bx
push dx
mov bx,ax ;частота
mov ax,34DDh
mov dx,12h ;(dx,ax)=1193181
cmp dx,bx ;если bx < 18Гц, то выход
jnb Done ;чтобы избежать переполнения
div bx ;ax=(dx,ax)/bx
mov bx,ax ;счетчик таймера
in al,61h ;порт РВ
or al,3 ;установить биты 0-1
out 61h,al
mov al,00001011b ;управляющее слово таймера:
;канал 2, режим 3, двоичное слово
mov dx,43h
out dx,al ;вывод в регистр режима
dec dx
mov al,bl
out dx,al ;младший байт счетчика
mov al,bh
out dx,al ;старший байт счетчика
Done:
pop dx ;восстановить регистры
pop bx
pop ax
ret
Sound endp
;
- 37 -
;подпрограмма выключения звука
;
No_Sound proc near
push ax
in al,61h ;порт РВ
and al,not 3 ;сброс битов 0-1
out 61h,al
pop ax
ret
No_Sound endp
Для генерации музыки можно использовать следующий алгоритм.
Пусть octave - номер октавы (1, 2, ...); note - номер ноты в
октаве (до=1, до#=2, ..., си=12). Тогда:
f := 32.625;
for i := 1 to oktave do f := 2*f;
for i := 1 to note do f := 1.059463094*f
Sound (round(f));
Второй способ генерации звука состоит в том, чтобы
генерировать звуковые импульсы не выходом таймера, а установкой
и сбросом бита 1 в регистре РВ. Для управления задержками можно
использовать программный цикл, например:
;
; Программа генерации звука
; Вход: N=количество импульсов
; FREQ=длительность импульса
;
in al,61h ;порт РВ
and al,not ;сброс бита 0
mov dx,N
Repeat:
or al,2
out 61h,al ;установить бит 1
mov cx,FREQ
Wait_On:
loop Wait_On
and al,not 2 ;сбросить бит 1
out 61h,al
mov cx,FREQ
Wait_Off:
loop Wait_Off
dec dx
jnz Repeat
Программирование этого способа основано на следующих
формулах. Если Т - длительность звучания в сек, f - частота
звука в Гц, а t - тактовая частота процессора ПЭВМ, то
N=T*f; FREQ=t/(34*f).
Константа 34 объясняется тем, что длительность каждого из
циклов Wait_on и Wait_off приблизительно равна (17*cx) машинных
- 38 -
тактов.
Неудобство этого метода состоит в том, что ЦП полностью
занят генерацией звука - любое прерывание испортит временную
диаграмму звукового сигнала. Однако он обеспечивает точную
подстройку частоты и позволяет создавать несимметричные импульсы
варьированием задержек в циклах Wait_on и Wait_off.
Сама вся эта книжка как сделать по сути комп(и как его настроить) - кому интересно - вот (в кодировке 866)
По-второму методу - это (пример на асме) Файл-пример работы со спикером по другому методу.
Сейчас напряженно думаю - по какому из двух путей пойти? По-первому - довольно-таки просто, но вот не обеспечивает данный подход гибкости - нужен сквенсор звуков(программный, для определения частоты звука и его длительности), и значит, разные подпрограммы для решения одной задачи - включения\выключения динамика, а еще нужно будет заблокировать прерывания (кто не блокировал прерывания в соотв. драйвере для WIN 3.1 - тот поймет, при обычном проигрывании шло жуткое и противненькое шипение, а при движении мышью/нажатием клавиши - вообще ппц, ибо нет звука, один гром и свист
)По второму - тоже нужно запрещение прерываний и еще тоже сквенсор - программный ШИМ.
С прерываниями двольно-таки просто - команда RDTSC и подсчет прошедших тактов, после опредееленного числа их - разрешение прерываний и вызов Windows API Sleep(0), чтоб обеспечить многозадачность.
Что посоветуете - какой способ избрать? И как сделать сам драйвер, с какими системными и\или прикладными прогами и\или структурами должен работать драйвер, чтобы программы и система "поверила" в то, что это и есть драйвер звука и направила поток на него?
Сообщения рода "это геморно, иди в школу, а не проще ли пользоваться звуковухой и не е*ать мозги себе и окружающим?" и пр. считаются за ОФФТОПИК, и будут БЕСПОЩАДНО караться модератором, ибо здесь не помойка, а тематический раздел.
За любые полезные советы - заранее спасибо!
почитайте для начала про архитектуру PC ... Это вам не микроконтроллеры...