Программирование Sound Blaster

=== Программирование Sound Blaster ===
Sound Blaster воспроизводит как синтезированный звук так и оцифровые звуки.
В этом файле будет расмотрено программирование воспроизведения цифровых
выборок через Sound Blaster DSP.
Порты ввода/вывода SoundBlaster DSP
Чип DSP ( Цифровой Звуковой Процессор ) программируется через пять портов,
которые определяются через базовый адрес Sound Blaster:
 2x6h - DSP Сброс
 2xAh - DSP Чтение
 2xCh - DSP Запись (команды/данные) ,
 состояние буфера записи DSP( Бит 7 )
 2xEh - Состояние буфер чтения DSP ( Бит 7 ),
	 подтверждение прерывания DSP
Пятый порт только для Sound Blaster 16
 2xFh - подтверждение прерывания DSP с 16 битами
Где x = 1 для базового адреса 210h.
 x = 2 для базового адреса 220h.
 .
 .
 x = 6 для базового адреса 260h.
Сброс DSP
Необходимо сбросить DSP прежде, чем начать работу с ним. Сброс осуществляется
по следующему алгоритму:
 1) Запишите 1 в порт сброса (2x6)
 2) Ждите 3 микросекунды
 3) Запишите 0 в порт сброса (2x6)
 4) Читайте порт состояния буфера чтения (2xE) пока бит 7 = 1
 5) Опрашивайте порт данных чтения (2xA) пока вы не получите AAh.
Для сброса DSP требуется около 100 мкс. Если после этого вы не получили
AAh. Значит, либо нет звуковой платы, или задан был неверный базовый
адрес.
Пример:
#define MAX_BASE_SB 5
int bases[MAX_BASE_SB]={ 0x220, 0x230, 0x240, 0x250, 0x260 };
int	baseAddrSB=0x220;
	// Прочитать
unsigned char pascal ReadSB
 (void)
{
unsigned int value;
while (!(inp((baseAddrSB+0xE)) & 0x80));
value = inp((baseAddrSB+0xA));
return value;
}
	// Проверить наличие
char pascal CheckSB
	( void )
{
int i, j;
for ( j=0; j<MAX_BASE_SB; j++ )
{
baseAddrSB=bases[j];
outportb(baseAddrSB+6,1);
delay(10);
outportb(baseAddrSB+6,0);
delay(10);
for(i=0; i<30000; i++ )
 if ( ReadSB()==0xAA )
		return 1;
}
return 0;
}
Запись в DSP
Значение можно записыть в DSP с следующей процедурой:
 1) Читайте порт состояния буфера записи DSP (2xCh) пока бит 7 = 0
 2) Запишите значение в порт записи (2xCh)
Пример:
void pascal WriteSB
	(unsigned char value)
{
while (inp(baseAddrSB+0xC) & 0x80);
outp(baseAddrSB+0xC, value);
}
Чтение DSP
Значение можно прочитать из DSP с следующей процедурой:
 1) Читайте порт состояния буфера чтения (2xE) пока бит 7 = 1
 2) Читайте значение из порта чтения (2xA)
Пример: см. выше.
Прямой режим вывода на DAC
DAC - это та часть платы которая преобразовывает значение выборки амплитуды
( то есть 0 - 255 ) к звуку. Чтобы генерировать квадратную звуковую волну
с максимальной громкостью вы должны чередовать запись 0/255 на DAC.
Только 8-разрядный DAC доступен в прямом режиме. В прямом режиме
программа ответственна за выбор определенного времени между выборками,
DAC может выводить звуковые выборки с такой скоростью с какой программа
способна это делать.
Команды DSP для программирования DAC в прямом режиме:
10h - вывести данные на DAC без DMA 8 бит. Для использования команды
 необходимо:
 1) Выдать 10h
 2) Записать байт данных.
 3) Продолжить через время T до окончания.
D1h - Включить воспроизведение звука.
D3h - Выключить воспроизведение звука.
20h - получить данные из ADC 8 бит.
Пример программирования DAC в прямом режиме:
#define WRITE_DATA_SB 0x10
#define ON_SOUND_SB	0xD1
#define OFF_SOUND_SB	0xD3
void main
	( void )
{
long i;
char ch;
if ( CheckSB()==1 )
	printf("S O U N D B L A S T E R !!!!\n");
else {
	printf("Увы, Увы, У в ы ...\n");
	return;
	}
WriteSB(ON_SOUND_SB);
ch=0;
for ( i=0; i<100000L; i++ )
{
 WriteSB(WRITE_DATA_SB);
 WriteSB(ch);
 if ( ch==0 ) ch=255;
 else ch=0;
}
WriteSB(OFF_SOUND_SB);
}
Программирование DAC с DMA
DAC можно также запрограммировать, чтобы он принимал значения посланные ему
через DMA.
Команды DAC:
14h - Включение вывода на DAC 8 Бит 4KHz - > 23 KHz. Затем младший
 байт длины, потом старший.
	WriteSB(DMA_8_BIT_DAC);
	WriteSB(lo(len));
	WriteSB(hi(len));
24h - Включение записи с ADC 8 Бит 4KHz - > 23 KHz
74h - Включение вывода на DAC 4 Бит ADPCM 4KHz - > 12 KHz
75h - Включение вывода на DAC 4 Бит ADPCM с 4KHz - > 12 KHz с байтом ссылки
76h - Включение вывода на DAC 2.6 Бит ADPCM 4KHz - > 13 KHz
77h - Включение вывода на DAC 2.6 Бит ADPCM с 4KHz - > 13 KHz с байтом ссылки
16h - Включение вывода на DAC 2 Бит ADPCM 4KHz - > 11 KHz
17h - Включение вывода на DAC 2 Бит ADPCM с 4KHz - > 11 KHz с байтом ссылки
ADPCM ( Адаптивная Импульсно-кодовая Модуляция) - это звуковая методика
сжатия, где различие между последовательными выборками сохраняется скорее
чем их фактические значения. В режимах с байтами ссылки, первый байт -
фактическое начальное значение. Наличие режимов с и без байтов ссылки значит
что вы можете выводить последовательные блоки без наличия байта ссылки.
Bxh - программмирование режима DMA с 16 битным цифровым звуком.
 ( Только для SB16 )
 Командная последовательность:
 Команда, Режим, Lo(Length-1), Hi(Length-1):
 Первый байт команды состоит:
 D7 D6 D5 D4 D3 D2 D1 D0
 --+--+--+--+---+----+-----+--
 1 0 1 1 A/D A/I FIFO 0
 ---------------+----+-----+--
 0=D/A 0=SC 0=off
 1=A/D 1=AI 1=on
 Общие команды:
	 B8 - одиночный цикл с 16-битной записи звука
 B0 - одиночного цикла с 16-битным воспроизведением
 BE - автоинициализируемая 16-битная запись
 B6 - автоинициализируемое 16-битной воспроизведение
 Режим:
 D7 D6 D5 D4 D3 D2 D1 D0
 ---+--+-------+-----+--+--+--+--
 0 0 Стерео Знак 0 0 0 0
		0-Моно 0-без
		1-Стерео 1-со знаком
Cxh - программирование режим DMA с 8-битным цифровым звуком.
 ( Только для SB16 )
 Те же самые команды, что для 16-бит.
 C8 - одиночный цикл с 8-битной записи звука
	 C0 - одиночного цикла с 8-битным воспроизведением
	 CE - автоинициализируемая 8-битная запись
 C6 - автоинициализируемое 8-битной воспроизведение
FIFO используется чтобы удалять несогласованности в тот период выборки,
когда звуковая плата не способна получить DMA, когда это требуется.
Без FIFO плата делает попытку захвата DMA в точно тот момент, когда
требуется выборка. Если другое устройство с более высоким приоритетом
обращается к DMA, звуковая плата ожидает и скорость выборки может
уменьшаться. FIFO позволяет во время выборки с DMA быть более гибким DSP
без потери звукового качества. FIFO очищается всякий раз, когда команда
посылается DSP. В режиме одиночного цикла, DSP постоянно перепрограммируется.
С FIFO DSP может еще содержать данные, который не были выданы, когда
команда очистила DAC. Чтобы избежать этого, FIFO должен быть переключен
в режим с одиночным циклом. Затем, снова переведен в автоинициализируемый
режим, когда DSP не перепрограммируется.
1Ch - Включение вывода на DAC 8 Бит 4KHz - > 23 KHz с автоинциализацией
90h - Включение вывода на DAC 8 бит 4kHz - > 44 KHz с автоинициализацией
48h - Установить длину блока на пересылку перед посылкой 91h, 99h
 сначала младший байт затем старший длину.
91h - Включение вывода на DAC 8 бит 4kHz - > 44 KHz стерео
99h - Включение записи с ADC 8 бит 4kHz - > 44 KHz стерео
	WriteSB(SET_LEN_DMA_8_BIT);
	WriteSB(lo(len));
	WriteSB(hi(len));
	WriteSB(DMA_8_BIT_DAC_HI);
D0h - остановить 8-битный DMA
D4h - возобновить 8-битный DMA
D5h - остановить 16-битный DMA
D6h - возобновить 16-битный DMA
 Эти команды пригодны как и для автоинциализированного режима,
 так и для одиночных циклов.
D9h - Выход из авто инициализируемого режима DMA с 16 битами
 после окончания текущего блока.
DAh - Выход из авто инициализируемого режима DMA с 8 битами
 после окончания текущего блока.
E1h - Получить номер версии DSP. После посылки этой команды, прочитайте
 из DSP два байта. Первый байт - главный номер версии и второй
 байт - малый номер версии. Версия 4.00 - это SB16.
	 Версия I Стерео I Частота I FIFO I 16 бит
	 --------+--------+----------+------+--------
 < 2.00 I - I до 21379 I - I -
 >= 2.00 I - I до 21379 I + I -
	>= 2.01 I - I до 43478 I + I -
	>= 3.00 I + I до 43478 I + I -
	>= 3.01 I + I до 43478 I + I +
Пример определения версии:
int pascal VersionSB
	( void )
{
char ch, ch1;
WriteSB(0xE1);
ch=ReadSB();
ch1=ReadSB();
verSB=ch<<8 | ch1;
if ( verSB>=0x200 )
	Fifo=1;
if ( verSB>=0x201 )
	MaxFrequency=1;
if ( verSB>=0x300 )
	Stereo=1;
if ( verSB>=0x301 )
	SixteenBit=1;
return verSB;
}
Программирование DMA
Контроллер DMA (Прямого Доступа В память) управляет пересылками данных
между устройствами ввода/вывода и памятью без использования центрального
процессора. IBM совместимая ЭВМ имеет два контроллера DMA один для
пересылок с 8 битами и другой для пересылок с 16 битами. Контроллер DMA,
вместе с внешним регистром страницы, способен на перемещение блоков по 64 КБ.
Ниже приведена информация по программированию DMA.
 Адреса портов для адреса DMA и регистров счета.
 Контроллер I Адрес I Функция
 ---------------+---------+-----------------
 DMA 1 I 00 I Канал 0 адреса
 c 8 битами I 01 I Канал 0 счета
 Подчиненный I 02 I Канал 1 адрес
		 I 03 I Канал 1 счета
 I 04 I Канал 2 адреса
 I 05 I Канал 2 счета
 I 06 I Канал 3 адреса
		 I 07 I Канал 3 счета
 --------------+---------+------------------
 DMA 2 I C0 I Канал 4 адреса
 с 16 битами I C2 I Канал 4 счета
 Ведущий I C4 I Канал 5 адреса
 I C6 I Канал 5 счета
 I C8 I Канал 6 адреса
		 I CA I Канал 6 счета
		 I CC I Канал 7 адреса
 I CE I Канал 7 счета
 Адреса портов для регистров управления
 Адрес I ОперацияI Функция
 DMAC1 DMAC2 I I
 ------------+---------+-----------------------------------
 0A D4 I Запись I регистр маски
 0B D6 I Запись I регистр режима
 0C D8 I Запись I регистр сброс байта flip-flop
 Адреса портов для младших регистров страницы
 Адрес I Функция
 --------+-----------------------------------
 81 I 2 Канал DMA с 8 битами
 82 I 3 Канал DMA с 8 битами
 83 I 1 Канал DMA с 8 битами
 87 I 0 Канал DMA с 8 битами
 89 I 6 Канал DMA с 16 битами
 8A I 7 Канал DMA с 16 битами
 8B I 5 Канал DMA с 16 битами
 Бита регистра режима
 БИТ I Функция
 ---------+----------------------------------
 Биты 7:6 I Биты выбора Режима
 00 I Выбранный Режим запроса
 01 I Одиночный выбранный режим
 10 I Выбранный блочный режим
 11 I Каскадный выбранный режим
 ---------+----------------------------------
 Бит 5 I Бит приращения / декремента Адреса
 1 I Выбранный Декремент адреса
	0 I Выбранное Приращение адреса
 ---------+----------------------------------
 Бит 4 I Авто инициализация
 1 I Автоинициализация включена
 0 I Одиночный
 ---------+----------------------------------
 Биты 3:2 I Биты Пересылки
 00 I Проверите пересылку
 01 I Запишите пересылку ( К памяти )
 10 I Читайте пересылку ( Из памяти )
 11 I Запрещенный
 ** I Игнорируется если биты 7:6 = 11
 ---------+----------------------------------
 Биты 1:0 I Биты выбора Канала
 00 I Выберите канал 0 (4)
 01 I Выберите канал 1 (5)
 10 I Выберите канал 2 (6)
 11 I Выберите канал 3 (7)
 Биты маски записи
 БИТ I Функция
 ----------+-----------------------------------
 Биты 7:3 I Неиспользуемый ( Набор к 0 )
 I
 Бит 2 I Установить/сбросить бит маски
 1 I Установить бит маски ( Отключите канал )
 0 I Сбросить бит маски ( Доступен канал )
 ----------+------------------------------------
 Биты 1:0 I Биты выбора Канала
 00 I канал 0 (4)
 01 I канал 1 (5)
 10 I канал 2 (6)
 11 I канал 3 (7)
DMAC2 используется для работы с 16 битами и DMAC1 используется для
работы с 8 битами. Вот пример программирования DMA:
 1) Вычислите абсолютный линейный адрес вашего буфера
	 LinearAddr = MK_SEG( Buf ) * 16L + MK_OFF ( Buf );
 2) Отключите канал DMA звуковой платы установкой бита маски
	outp(MaskPort, 1 + ( DMAChannel % 4 ));
 3) Очистите указатель байта flip-flop
	outp(ClrPort, DMAChannel );
 4) Запишите режим DMA для пересылки
 Биты выбора режима должны устанавливаться в 00h для режима запроса.
 Адрес бита +/- должен устанавливаться в 0 для приращения адреса.
 Бит автоинициализации должен устанавливаться соответственно.
 Биты пересылки должны устанавливаться в 10h для воспроизведения и
 01h для записи. Выбор канала должен устанавливаться так же как и на
 канал DMA звуковой платы.
	outp(ModePort, Mode + ( DMAChannel % 4 ));
 Некоторые часто используемые режимы:
	48h + Канал - одиночный цикл воспроизведение
	58h + Канал - автоинициализируемое воспроизведение
	44h + Канал - запись одиночного цикла
	54h + Канал - автоинициализируемая запись
 5) Запишите смещение буфера, младший байт затем старший байт. Для
 шестнадцати разрядных данных, смещение должно быть в словах от начала
 128k-байтной страницы, для 8-битных от 64K. Самый простой метод для
 вычисления смещения с 16 битами - это разделить линейный адрес на
 два перед вычислением смещения.
	#define lo(value) (unsigned char)((value) & 0x00FF)
	#define hi(value) (unsigned char)((value) >> 8)
	if ( SixteenBit==1 )
	 BufOffset= ( LinearAddr / 2 ) % 65536;
	else BufOffset= LinearAddr % 65536;
	outp(BaseAddrPort, lo(BufOffset));
	outp(BaseAddrPort, hi(BufOffset));
 6) Запишите длину пересылки в соответствующий порт счета, младший
 байт затем старший байт. Для пересылки с 8 битами, запишите
 длину в байтах минус единица. Для пересылки с 16 битами, запишите
 номер длину в словах минус единица.
	if ( SixteenBit==1 )
		TransferLength/=2;
	outp(CountPort, lo(TransferLength-1));
	outp(CountPort, hi(TransferLength-1));
 7) Запишите страницу буфера в регистр страницы DMA.
	outp(PagePort, ( LinearAddr / 65536));
 8) Включите DMA звуковой платы очистив соответствующий бит маски
	outp(MaskPort, DMAChannel % 4);
Пример :
int MaskPort, ClrPort, ModePort, ModeDMA, CountPort, PagePort,
	BaseAddrPort;
int pageports[4]={ 0x87, 0x83, 0x81, 0x82 };
MaskPort=0x0A; ClrPort=0xC; ModePort=0xB;
ModeDMA=0x48+DMAChannel;
CountPort=1+DMAChannel*2;
BaseAddrPort=DMAChannel*2;
PagePort=pageports[DMAChannel];
outportb(MaskPort, 4 + DMAChannel);
outportb(ClrPort, DMAChannel );
outportb(ModePort, ModeDMA );
outportb(BaseAddrPort,lo(aligned_physical));
outportb(BaseAddrPort,hi(aligned_physical));
outportb(PagePort,(unsigned char)((aligned_physical>>16)&0xFF));
outportb(CountPort,lo(len-1));
outportb(CountPort,hi(len-1));
outportb(MaskPort, DMAChannel );
Установка частоты выборки
Для версии Sound Blaster ниже 4.00 установка частоты выборки выполняется
посылкой DSP команды 40h. При этом частота преобразуется к константе времени
по формуле:
 4KHz - > 23 KHz:
	Time Constant = 256 - (1,000,000 / sampling rate)
		 = 256 - (1,000,000 / 8,000 )
		 = 131
 4KHz - > 44 KHz:
	Time Constant = (MSByte of) 65536 - (256,000,000 / sampling rate)
		 = (MSByte of) 65536 - (256,000,000 / 44,100)
		 = (MSByte of) 59731
		 = (MSByte of) 0E953h
		 = 0E9h
void pascal RateSB
	( unsigned int rate )
{
unsigned char tc;
if ( MaxFrequency==0 )
{
 if ( rate<5000 ) rate=5000;
 if ( rate>22528 ) rate=22528;
 tc = (unsigned char)(256 - (1000000/rate));
}
else
{
 if ( rate<5000 ) rate=5000;
 if ( rate>45056 ) rate=45056;
 tc = (unsigned char)(hi((unsigned int)(65536-(256000000L/rate))));
}
WriteSB(TIME_CONSTANT);
WriteSB(tc);
}
В отличие от этого SB16 программируется фактической частотой выборки.
Команда 41h используется для воспроизведения, а 42h используется для записи.
 if ( Play==1 )
	 WriteSB ( 0x41 );
 else WriteSB ( 0x42 );
 WriteSB ( hi( frequency ) );
 WriteSB ( lo( frequency ) );
Алгоритм цифрового ввода/вывода звука
Чтобы записывать или воспроизводить звук, вы должны использовать следующую
последовательность:
 1) Распределите буфер который не пересекает границу 64 Kb
 2) Установите программу обработки прерывания.
 3) Запрограммируйте контроллер DMA для фоновой пересылки
 4) Установите частоту выборки
 5) Запишите команду I/O в DSP
 6) Запишите режим пересылки I/O в DSP
 7) Запишите размер блока в DSP ( Младший байт/Старший байт )
После этого сразу начнется запись или воспроизведение звука.
Выделение памяти под буфер DMA:
data=(char far *)farmalloc(131000L);
if ( data==NULL )
{
	printf("Нет места под буфер DMA\n");
	return 0;
}
physical=((unsigned long)FP_OFF(data))+(((unsigned long)FP_SEG(data))<<4);
aligned_physical=physical+0x0FFFFL;
aligned_physical&=0xF0000L;
aligned=MK_FP((unsigned )((aligned_physical >> 4) & 0xFFFF),0);
Ниже приведены примеры последовательностей для программирования SB
с помощью DMA.
Нормальная частота, воспроизведение:
 1) Записать D1h в 2xCh
 2) Установить обработчик прерывания
 3) Записать 40h в 2xCh
 4) Записать константы времени в 2xCh
 5) Запрограммировать DMA
 6) Записать 14h в 2xCh
 7) Записать длину выборки
 8) Обслуживать прерывания, до окончания выборки
 9) Восстановить старый обработчик
 10) Записать D3h в 2xCh
При этом можно записывать любые команды в DSP, пока идет воспроизведение.
Повышенная частота, воспроизведение:
 1) Записать D1h в 2xCh
 2) Установить обработчик прерывания
 3) Записать 40h в 2xCh
 4) Записать константы времени в 2xCh
 5) Запрограммировать DMA
 6) Записать 48h в 2xCh
 7) Записать длину выборки
 8) Записать 91h в 2xCh
 9) Обслуживать прерывания, до окончания выборки
 10) Восстановить старый обработчик
 11) Записать D3h в 2xCh
Нормальная частота, запись звука:
 1) Установить обработчик прерывания
 2) Записать 40h в 2xCh
 3) Записать константы времени в 2xCh
 4) Запрограммировать DMA
 5) Записать 24h в 2xCh
 6) Записать длину выборки
 7) Обслуживать прерывания, до окончания выборки
 8) Восстановить старый обработчик
При этом можно посылать любые команды в DSP, пока идет запись.
Повышенная частота, запись:
 1) Установить обработчик прерывания
 2) Записать 40h в 2xCh
 3) Записать константы времени в 2xCh
 4) Запрограммировать DMA
 5) Записать 48h в 2xCh
 6) Записать длину выборки
 7) Записать 99h в 2xCh
 8) Обслуживать прерывания, до окончания выборки
 9) Восстановить старый обработчик
Конец цифрового ввода/вывода звука
Когда пересылка закончена генерируется прерывание. Фактический номер
прерывания зависит от установки IRQ на плате Sound Blaster:
 IRQ I Прерывание
 -----+------------
 2 I 0Ah
 3 I 0Bh
 5 I 0Dh
 7 I 0Fh
Для обслуживания прерывания необходимо выполнить:
 1) подтвердите прием прерывания от DSP прочитав порт (2xEh) один раз для
 8-битного звука, или порт 2xF для 16-битного звука.
 2) Вывод следующего буфера, если есть.
 3) Выведите значение 20h ( EOI ) в порт контроллера прерывания 20h,
 а если IRQ8-15(прерывания 70h-77h), то записать 20h в A0h.
Установка прерывания :
DMA_complete = 0;
disable();
OldIRQ = getvect(0x08 + SbIRQ);
setvect(0x08 + SbIRQ,SBHandler);
enable();
Обработчик прерывания :
static void far interrupt SBHandler( void )
{
enable();
DMA_complete = 1;
// подтведить
inportb(baseAddrSB+0xE);
outportb(0x20,0x20);
}
Инициализация обработчика :
DMA_complete = 0;
im = inportb(0x21);
tm = ~(1 << SbIRQ);
outportb(0x21,im & tm);
enable();
Сброс обработчика :
disable();
setvect(0x08 + SbIRQ,OldIRQ);
i = inportb(0x21);
outportb(0x21, i | (1 << SbIRQ));
enable();
Воспроизведение файла выборки:
f = fopen(argv[1],"rb");
raw = ( char far * ) farmalloc(32000L);
if ( f == 0 || raw==0 )
{
	printf("Не могу открыть файл выборки - %s\n",argv[1]);
	printf("Нет памяти\n",argv[1]);
	ResetSB();
	return;
}
printf("Воспроизведение выборки ...\n");
WriteSB(ON_SOUND_SB);
RateSB(22222);
len=fread(raw,1,32000,f);
while ( 1 )
{
	if ( len==0 ) break;
	PlaySB(raw,len);
	len=fread(raw,1,32000,f);
	while ( StatePlaySB()==0 )
		if ( kbhit() ) { getch(); goto Fin; }
}
Fin:
if ( f!=0 ) fclose(f);
if ( raw!=0 ) farfree(raw);
ResetSB();
Стерео звук
При воспроизведении стерео звуков необходимо посылать 2 байта DSP, первый
для левого канала, второй для правого. Необходимо так же указать SB,
что вы воспроизводите стерео звук, через регистры миксера.
Миксер Sound Blaster
Ниже приведена информация для SbPro.
Порт 2x4h - индексный порт миксера, 2x5h - порт данных (чтения/записи).
void pascal WriteMixerSB
	( char index, char val )
{
outportb(baseAddrSB+4,index);
outportb(baseAddrSB+5,val);
}
char pascal ReadMixerSB
	( char index )
{
outportb(baseAddrSB+4,index);
return inportb(baseAddrSB+5);
}
Регистр Сброса Данных используется для инициализации миксера. Установите
этот регистр в 0 перед изменением любого из других регистров миксера.
void pascal ResetMixerSB
	( void )
{
WriteMixerSB(0,0); // RESET
}
Регистр записи определяет источник звука и тип фильтра.
	 Индекс = 0Ch
		7 6 5 4 3 2 1 0
 --------+-------+---+---+----
 \---+---/ \-+-/
 /---/ I
 I I
		 В Фильтре ADC Источник
		 000 - Низкие 00 - Микрофон 1
		 001 - Высокие 01 - CD
		 010 - Нет Фильтра 10 - Микрофон 2
				 11 - Линейный вход
#define SOURCE_MIC1	0
#define SOURCE_CD	1
#define SOURCE_MIC2	2
#define SOURCE_LINE	3
void pascal InputMixerSB
	( char sou, char filtr )
{
char val;
val=(sou<<1)&0x6;
val|=(filtr<<3)&0x38;
WriteMixerSB(0xC,val);
}
Регистр воспроизведения служит для установки фильтра и стерео звука.
	 Индекс = 0Eh
		7 6 5 4 3 2 1 0
 --------+---------------+----
 I I
 I I
	 0 - Использовать фильтр 0 - моно
	 1 - Без фильтра 1 - Stereo
#define MONO	0
#define STEREO	1
#define USE_FILTER	0
#define BYPASS_FILTER	1
void pascal OutputMixerSB
	( char st, char filtr )
{
char val;
val=(st==1)?2:0;
val|=(filtr==1)?0x20:0;
WriteMixerSB(0xE,val);
}
Регистр общей громкости:
	 Индекс = 22h
		7 6 5 4 3 2 1 0
 /-----------+---+-----------\
 \-----+-----/ \-----+-----/
 I I
		 Громкость Громкость
		 Лево Право
void pascal MasterVolumeSB
	( char left, char right )
{
char val;
val=right&0xf;
val|=(left<<4)&0xf0;
WriteMixerSB(0x22,val);
}
Регистр громкости DSP:
	 Индекс = 04h
		7 6 5 4 3 2 1 0
 /-----------+---+-----------\
 \-----+-----/ \-----+-----/
 I I
		 Громкость Громкость
		 Лево Право
void pascal VoiceVolumeSB
	( char left, char right )
{
char val;
val=right&0xf;
val|=(left<<4)&0xf0;
WriteMixerSB(0x04,val);
}
Регистр громкости FM синтезатора:
	 Индекс= 26h
		7 6 5 4 3 2 1 0
 /-----------+---+-----------\
 \-----+-----/ \-----+-----/
 I I
		 Громкость Громкость
 Лево Право
void pascal FMVolumeSB
	( char left, char right )
{
char val;
val=right&0xf;
val|=(left<<4)&0xf0;
WriteMixerSB(0x26,val);
}
Регистр громкости CD:
	 Индекс = 28h
		7 6 5 4 3 2 1 0
 /-----------+---+-----------\
 \-----+-----/ \-----+-----/
 I I
		 Громкость Громкость
 Лево Право
void pascal CDVolumeSB
	( char left, char right )
{
char val;
val=right&0xf;
val|=(left<<4)&0xf0;
WriteMixerSB(0x28,val);
}
Регистр громкости линейного входа:
	 Индекс = 2Eh
		7 6 5 4 3 2 1 0
 /-----------+---+-----------\
 \-----+-----/ \-----+-----/
 I I
		 Громкость Громкость
 Лево Право
void pascal LineVolumeSB
	( char left, char right )
{
char val;
val=right&0xf;
val|=(left<<4)&0xf0;
WriteMixerSB(0x2E,val);
}
Регистр громкости микрофона:
	 Индекс = 0Ah
		7 6 5 4 3 2 1 0
 --------------------+-------\
 \---+---/
 I
				 Громкость микрофона.
void pascal MicVolumeSB
	( char vol )
{
char val;
val=vol&0x7;
WriteMixerSB(0xA,val);
}
Примечание:
 Данный документ составлен Анисимовым С.Ю. 08/1995.
 
 Данными для составления этого документа послужила информация
 из различных источников. Поэтому автор не несет ответственность
 за неверную информацию, и за повреждения техники и тел при
 использовании этого документа.
 
С наилучшими пожеланиями, для всех любителей программировать Sound Blaster !
			 Vale !
Source: http://pmg.org.ru/gamedev/sb.htm
ID: 02257