Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11797
Последний выпуск: 19.06.2015

MOD-Player [C++, RealMode]


Пример программы

Простейшая программа, демонстрирующая работу со звуковой платой в защищенном режиме процессора, приведена в листинге 1. В примере решено было ограничиться лишь воспроизведением 8-битного звука, что обусловлено двумя причинами. Первая из них заключается в том, что все необходимые регистры и команды DSP (Digital Signal Processor - цифровой сигнальный процессор) звуковой платы были описаны ранее в статье Д.В. Солдатенкова, и это позволяет сократить объем журнальной публикации. Вторая причина связана с тем, что подавляющее большинство выпускаемых сегодня звуковых плат являются 16-разрядными и совместимы с Sound Blaster лишь на уровне 8-битного звука, т.е. подавляющее большинство звуковых плат, выпускаемых не Creative Labs, не совместимы с Sound Blaster 16, и соответственно 16-битный звук в них реализуется по-другому. Следовательно, стандарта, даже de facto, для воспроизведения 16-битного звука не существует.

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

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

Процедуры выделения и освобождения нижней памяти называются GetSBMem и FreeSBMem соответственно. Для облегчения переноса программы на другой компилятор или в другой язык программирования в листинге 2 приведены ассемблерные варианты этих процедур.

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

Листинг 1. Воспроизведение звука из WAV-файла через звуковую плату Sound Blaster.

 
program playwavp;       {воспроизведение 8-битного звука}
                                        {в защищенном режим
е процессора}
{$D+,L+,I+,R+,S+,V+}
uses dos,winapi;
const
   BlasterPort:word = $220;  {номер порта Sound Blaster}
   BlasterIRQ:word  =    5;  {номер прерывания Sound Blaster}
   BlasterDMAl:word =    1; {номер канала DMA Sound Blaster}
   maxlen = 35000;           {длина звукового буфера}
{   Seg0040 = $40;}
   SouBlas : Boolean = False; {было ли прерывание от SB }

function clock:longint;       {функция определения времени}
begin
   clock := MemL[Seg0040:$6c];
end;

var
    ExitSave:Pointer;  {адрес старой программы выхода в DOS}
    SBold:pointer;{адрес обработчика прерывания Sound Blaster'a}
    SBIRQ:byte;      { номер прерывания Sound Blaster'a }

{$F+}
procedure SBint ; interrupt;   { обработчик прерывания SB }
begin
   SouBlas:=True;
   Port[$20]:=$20;
end;

procedure MyExit; {дополнительная процедура при выходе в DOS}
begin
    ExitProc:=ExitSave;
    SetIntVec(SBIRQ+8,SBold);
end;
{$F-}

procedure IntInit(sbi:byte);  {установка нового вектора} 
                                          &n
bsp;       {прерывания и т.д.}
begin          { sbi - номер аппаратного прерывания SB }
        if sbi < 8 then  SBIRQ:=sbi  else  SBIRQ:=2;
        GetIntVec(SBIRQ+8,SBold);
        SetIntVec(SBIRQ+8,@SBint);  {переопределение}
                                          &n
bsp;             {прерывания SB}
        ExitSave:=ExitProc;  {переопределение}
                                          &n
bsp;       {процедуры выхода}
        ExitProc:=@MyExit;
end;

procedure WriteCommand(Comm:byte);  { процедура записи}
                                          &n
bsp;     {команды в регистр SB }
begin
   while (Port[BlasterPort+$0C] and $80) <> 0 do;
   Port[BlasterPort+$0C]:=Comm;
end;

procedure NotSupport;  { вывод на экран сообщения }
begin
   writeln('Format not supported');
   halt;
end;

var
   longi:longint;    {рабочая ячейка}
   arr1:pointer;     {для выравнивающего массива}
   pusto:word;       {длина выравнивающего массива}
   sndp:pointer;     {для массива звуковых отсчетов}
   DMAPage:byte;     {номер 64K сегмента для записи}
                                           {
в регистр DMA}
   DMAOfs :word;     {смещение звуковой последовательности}
                                           {
в нижней памяти}

procedure GetSBMem; {выделение буфера }
                                         {нижней памят
и для SB/DMA}
begin
   longi := GlobalDosAlloc(16);
   arr1 := ptr(longi and $0FFFF,0); {селектор нижней памяти}
   longi := $FFFF-(((longi shr 16) shl 4) and $ffff)+1;
   pusto := longi;   {столько осталось до начала}
                                           {
следующего 64k сегмента}
   GlobalDosFree(seg(arr1^));
   longi := GlobalDosAlloc(pusto);
   arr1 := ptr(longi and $0FFFF,0);  {селектор нижней}
                                          &n
bsp;             {памяти (выравн.масс.)}
   longi := GlobalDosAlloc(maxlen);
   sndp := ptr(longi and $0FFFF,0);  {селектор нижней}
                                          &n
bsp;             {памяти (для звука)}
   DMAPage := longi shr 28;
   DMAofs := 0;
end;

procedure FreeSBMem; {возвращение нижней памяти в систему}
begin
    GlobalDosFree(seg(sndp^));
    GlobalDosFree(seg(arr1^));
end;

{*****************************************}

const
   dmap : array[0..3]of byte = ($87,$83,$81,$82); {номера}
                                          &n
bsp;                   {регистров DMA}
var
   i : word;      {рабочая ячейка}
   t,friq:word;   {временной параметр/частота дискретизации}
   lenfil:word;   {длина считываемой части звуковых данных}
   snd:file;      {звуковой файл}
   riff:array[0..15]of char; {массив для чтения}
                                          &n
bsp;      {неиспольз. частей заголовка}

Begin    {the main program}
    if paramcount <> 1 then begin
       writeln;
       writeln("  Usage: playwavp filename.wav');
       writeln;
       halt;
    end;
    IntInit(BlasterIRQ);    { переустанавливаем прерывания }
    Assign (snd,paramstr(1));
    Reset (snd,1);
    BlockRead(snd,riff,16);     { $00}
    BlockRead(snd,longi,4);   { $10 длина заголовка}
    BlockRead(snd,i,2);          { $14}
    BlockRead(snd,i,2);          { $16 число каналов}
    if i <> 1 then notsupport;
    BlockRead(snd,friq,2);      { $18 частота дискретизации}
    Seek(snd,longi+$12);       { $1A пропускаем заголовок}
                                          &n
bsp;          {до предпосл.слова}
    BlockRead(snd,i,2);          {     разрядность}
    if i <> 8 then notsupport;
    GetSBMem;         {запрашиваем нижнюю память для звука}
    BlockRead(snd,longi,4);     {  'data'}
    BlockRead(snd,longi,4);     { длина данных}
    if longi > maxlen then lenfil := maxlen else lenfil := longi;
    BlockRead(snd,sndp^,lenfil); {звуковые данные}
    close (snd);
    WriteCommand($D3);          {включаем звук}
    t:=256 - 1000000 div friq;
    WriteCommand($40);      {задаем частоту дискретизации}
    WriteCommand(t);
    Port[$21] := Port[$21] and not (1 shl BlasterIRQ); 
                                          &n
bsp;             {разрешаем прерывание}
    Port[$A]:=BlasterDMAl + 4;     {маскируем DMA }
    Port[$C]:=0;                   {сбрасываем триггер}
    Port[$B]:=BlasterDMAl + $48;   {задаем режим передачи }
    Port[$2] := lo(DMAOfs);        {задаем адрес буфера}
    Port[$2] := hi(DMAOfs);
    Port[dmap[BlasterDMAl]] := DMAPage; {задаем 64k страницу}
    Port[BlasterDMAl*2 + 1]:=lo(lenfil-1); {длина звуковой}
                                          &n
bsp;             {последовательности}
    Port[BlasterDMAl*2 + 1]:=hi(lenfil-1);
    Port[$A]:=BlasterDMAl;         {размаскируем DMA }
    WriteCommand($14);      {начинаем воспроизведение звука}
    WriteCommand(lo(lenfil-1));
    WriteCommand(hi(lenfil-1));
    longi:=clock;    {на всякий случай ограничим по времени}
    while (SouBlas = false) and (longi+50 > clock) do ;
    if not SouBlas then Port[$20]:=$20;   {сбрасываем DMA }
    i:=Port[BlasterPort+$0E];   {сбрасываем Sound Blaster}
    WriteCommand($D1);     {выключаем звук}
    Port[$21] := Port[$21] or (1 shl BlasterIRQ); 
                                          &n
bsp;             {запрещаем прерывание}
    FreeSBMem;         {возвращаем память в систему}
End.

Листинг 2. Процедуры выделения и освобождения 
нижней памяти для звукового буфера

var m1,m2,m3 : word; { флаги процедур выделения памяти: }
{ 4 - успешно, 5 - ошибка, 2 - не выделялась }

procedure GetSBMem; {выделение буфера нижней памяти}
                                         {для SB/DMA}
var j:word;
begin
   j := (longint(maxlen) + 15) div 16; {длина блока}
                                          &n
bsp;               {в параграфах}
   m1 := 2;   m2 := 2;   m3 := 2;
   asm
      mov ax,$0100
      mov bx,j
      int $31      {запрашиваем память}
      rcl m1,1     {запоминаем CF}

      mov bx,$1000
      mov cx,ax
      and cx,$fff
      sub bx,bc      {вычисляем размер до конца сегмента}
      cmp j,bx
      jb @l1       {если достаточно места, уходим}

      push bx
      mov ax,$0101
      int $31      {возвращаем память}

      pop bx
      mov ax,$0100
      int $31      {забираем память до конца 64k-сегмента}
      rcl m2,1     {запоминаем CF}
      mov word ptr [arr1+2],dx  {сохраняем селектор}

      mov ax,$0100
      mov bx,j
      int $31    {запрашиваем память для звукового буфера}
      rcl m3,1   {запоминаем CF}
      mov bx,ax
      mov ax,0
      adc ax,ax
      mov m3,ax   {запоминаем CF}
 @l1:
      mov word ptr [sndp+2],dx    {сохраняем селектор}
      xor dx,dx
      mov word ptr [sndp],dx      {сохраняем смещение}
      mov ax,bx
      shl ax,4
      mov DMAOfs,ax
      shr bx,12
      mov DMAPage,bl
   end;
   if((m1 and 1) or (m2 and 1) or (m3 and 1)) <> 0 then halt;
end;

procedure FreeSBMem; {возвращение нижней памяти в систему}
begin
   asm
      mov ax,$0101
      mov dx,word ptr[sndp+2]
      int $31
   end;
   if m2 = 4 then
   asm
      mov ax,$0101
      mov dx,word ptr[arr1+2]
      int $31
   end;
end;

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог