Приветствую Вас Гость | RSS

Меню сайта

Реклама

Категории раздела
Speaker [7]
Аудио [51]
Видео [11]
Джойстик [2]
Запись звука [5]
Микрофон [3]

Наш опрос
Оцените мой сайт
Всего ответов: 30

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа

Главная » Статьи » Мультимедиа » Аудио

Низкоуровневые процедуры обработки звука

Ниже приведен код, обрабатывающий аудиосигнал, получаемый со входа звуковой карты (SoundBlaster). Надеюсь он поможет разобраться вам с этой сложной темой.

Включенный в код модуль RECUNIT делает всю изнурительную работу по извлечению звука со входа звуковой карты.


var
WaveRecorder: TWaveRecorder;

...

WaveRecorder := TwaveRecorder(2048, 4); // 4 размером 2048 байт

{ Устанавливает параметры дискретизации }
with WaveRecorder.pWavefmtEx do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := 1;
nSamplesPerSec := 20000;
wBitsPerSample := 16;
nAvgBytesPerSec := nSamplesPerSec * (wBitsPerSample div 8) * nChannels;
end;

// Затем используем вариантную запись, поскольку я не знаю
// как получить адрес самого объекта

WaveRecorder.SetupRecord(@WaveRecorder);

// Начинаем запись
WaveRecorder.StartRecord;

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

// Заканчиваем запись
WaveRecorder.StopRecord;
WaveRecorder.Destroy;


{
Имя файла: RECUNIT.PAS V 1.01
Создан: Авг 19 1996 в 21:56 на IBM ThinkPad
Ревизия #7: Авг 22 1997, 15:01 на IBM ThinkPad
-John Mertus

Данный модуль содержит необходимые процедуры для записи звука.

Версия 1.00 - первый релиз
1.01 - добавлен TWaveInGetErrorText
}


{-----------------Unit-RECUNIT---------------------John Mertus---Авг 96---}

unit RECUNIT;

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

interface

uses

Windows, MMSystem, SysUtils, MSACM;

{ Ниже определен класс TWaveRecorder для обслуживания входа звуковой }
{ карты. Ожидается, что новый класс будет производным от TWaveRecorder }
{ и перекроет TWaveRecorder.ProcessBuffer. После начала записи данная }
{ процедура вызывается каждый раз при наличии в буфере аудио-данных. }

const

MAX_BUFFERS = 8;

type

PWaveRecorder = ^TWaveRecorder;
TWaveRecorder = class(TObject)
constructor Create(BfSize, TotalBuffers: Integer);
destructor Destroy; override;
procedure ProcessBuffer(uMsg: Word; P: Pointer; n: Integer);
virtual;

private
fBufferSize: Integer;
// Размер буфера
BufIndex: Integer;
fTotalBuffers: Integer;

pWaveHeader: array[0..MAX_BUFFERS - 1] of PWAVEHDR;
hWaveHeader: array[0..MAX_BUFFERS - 1] of THANDLE;
hWaveBuffer: array[0..MAX_BUFFERS - 1] of THANDLE;
hWaveFmtEx: THANDLE;
dwByteDataSize: DWORD;
dwTotalWaveSize: DWORD;

RecordActive: Boolean;
bDeviceOpen: Boolean;

{ Внутренние функции класса }
function InitWaveHeaders: Boolean;
function AllocPCMBuffers: Boolean;
procedure FreePCMBuffers;

function AllocWaveFormatEx: Boolean;
procedure FreeWaveFormatEx;

function AllocWaveHeaders: Boolean;
procedure FreeWaveHeader;

function AddNextBuffer: Boolean;
procedure CloseWaveDeviceRecord;

public
{ Public declarations }
pWaveFmtEx: PWaveFormatEx;
WaveBufSize: Integer;
// Размер поля nBlockAlign
InitWaveRecorder: Boolean;
RecErrorMessage: string;
QueuedBuffers,
ProcessedBuffers: Integer;
pWaveBuffer: array[0..MAX_BUFFERS - 1] of lpstr;
WaveIn: HWAVEIN;
{ Дескриптор Wav-устройства }

procedure StopRecord;
function 477576218068 StartRecord: Boolean;
Function477576218068 SetupRecord(P: PWaveRecorder): Boolean;

end;

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

implementation

{-------------TWaveInGetErrorText-----------John Mertus---14-Июнь--97--}

function TWaveInGetErrorText(iErr: Integer): string;

{ Выдает сообщения об ошибках WaveIn в формате Pascal }
{ iErr - номер ошибки }
{ }
{**********************************************************************}
var

PlayInErrorMsgC: array[0..255] of Char;

begin

waveInGetErrorText(iErr, PlayInErrorMsgC, 255);
TWaveInGetErrorText := StrPas(PlayInErrorMsgC);
end;

{-------------InitWaveHeaders---------------John Mertus---14-Июнь--97--}

function TWaveRecorder.AllocWaveFormatEx: Boolean;

{ Распределяем формат большого размера, требуемый для инсталляции ACM-в}
{ }
{**********************************************************************}
var

MaxFmtSize: UINT;

begin

{ maxFmtSize - сумма sizeof(WAVEFORMATEX) + pwavefmtex.cbSize }
if (acmMetrics(0, ACM_METRIC_MAX_SIZE_FORMAT, maxFmtSize) <> 0) > then
begin
RecErrorMessage := 'Ошибка получения размера формата максимального сжатия';
AllocWaveFormatEx := False;
Exit;
end;

{ распределяем структуру WAVEFMTEX }
hWaveFmtEx := GlobalAlloc(GMEM_MOVEABLE, maxFmtSize);
if (hWaveFmtEx = 0) then
begin
RecErrorMessage := 'Ошибка распределения памяти для структуры WaveFormatEx';
AllocWaveFormatEx := False;
Exit;
end;

pWaveFmtEx := PWaveFormatEx(GlobalLock(hWaveFmtEx));
if (pWaveFmtEx = nil) then
begin
RecErrorMessage := 'Ошибка блокировки памяти WaveFormatEx';
AllocWaveFormatEx := False;
Exit;
end;

{ инициализация формата в стандарте PCM }
ZeroMemory(pwavefmtex, maxFmtSize);
pwavefmtex.wFormatTag := WAVE_FORMAT_PCM;
pwavefmtex.nChannels := 1;
pwavefmtex.nSamplesPerSec := 20000;
pwavefmtex.nBlockAlign := 1;
pwavefmtex.wBitsPerSample := 16;
pwavefmtex.nAvgBytesPerSec := pwavefmtex.nSamplesPerSec *
(pwavefmtex.wBitsPerSample div 8) * pwavefmtex.nChannels;
pwavefmtex.cbSize := 0;

{ Все успешно, идем домой }
AllocWaveFormatEx := True;
end;

{-------------InitWaveHeaders---------------John Mertus---14-Июнь--97--}

function TWaveRecorder.InitWaveHeaders: Boolean;

{ Распределяем память, обнуляем заголовок wave и инициализируем }
{ }
{**********************************************************************}
var

i: Integer;

begin

{ делаем размер буфера кратным величине блока... }
WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign);

{ Устанавливаем wave-заголовки }
for i := 0 to fTotalBuffers - 1 do
with pWaveHeader[i]^ do
begin
lpData := pWaveBuffer[i];
// адрес буфера waveform
dwBufferLength := WaveBufSize; // размер, в байтах, буфера
dwBytesRecorded := 0; // смотри ниже
dwUser := 0; // 32 бита данных пользователя
dwFlags := 0; // смотри ниже
dwLoops := 0; // смотри ниже
lpNext := nil; // зарезервировано; должен быть ноль
reserved := 0; // зарезервировано; должен быть ноль
end;

InitWaveHeaders := TRUE;
end;

{-------------AllocWaveHeader----------------John Mertus---14-Июнь--97--}

function TWaveRecorder.AllocWaveHeaders: Boolean;

{ Распределяем и блокируем память заголовка }
{ }
{***********************************************************************}
var

i: Integer;

begin

for i := 0 to fTotalBuffers - 1 do
begin
hwaveheader[i] := GlobalAlloc(GMEM_MOVEABLE or GMEM_SHARE or
GMEM_ZEROINIT, sizeof(TWAVEHDR));

if (hwaveheader[i] = 0) then
begin
{ Примечание: Это может привести к утечке памяти, надеюсь скоро исправить }
RecErrorMessage := 'Ошибка распределения памяти для wave-заголовка';
AllocWaveHeaders := FALSE;
Exit;
end;

pwaveheader[i] := GlobalLock(hwaveheader[i]);
if (pwaveheader[i] = nil) then
begin
{ Примечание: Это может привести к утечке памяти, надеюсь скоро исправить }
RecErrorMessage := 'Не могу заблокировать память заголовка для записи';
AllocWaveHeaders := FALSE;
Exit;
end;

end;

AllocWaveHeaders := TRUE;
end;

{---------------FreeWaveHeader---------------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.FreeWaveHeader;

{ Просто освобождаем распределенную AllocWaveHeaders память. }
{ }
{***********************************************************************}
var

i: Integer;

begin

for i := 0 to fTotalBuffers - 1 do
begin
if (hWaveHeader[i] <> 0) then
begin
GlobalUnlock(hwaveheader[i]);
GlobalFree(hwaveheader[i]);
hWaveHeader[i] := 0;
end
end;
end;

{-------------AllocPCMBuffers----------------John Mertus---14-Июнь--97--}

function TWaveRecorder.AllocPCMBuffers: Boolean;

{ Распределяем и блокируем память waveform. }
{ }
{***********************************************************************}
var

i: Integer;

begin

for i := 0 to fTotalBuffers - 1 do
begin
hWaveBuffer[i] := GlobalAlloc(GMEM_MOVEABLE or GMEM_SHARE, fBufferSize);
if (hWaveBuffer[i] = 0) then
begin
{ Здесь возможна утечка памяти }
RecErrorMessage := 'Ошибка распределения памяти wave-буфера';
AllocPCMBuffers := False;
Exit;
end;

pWaveBuffer[i] := GlobalLock(hWaveBuffer[i]);
if (pWaveBuffer[i] = nil) then
begin
{ Здесь возможна утечка памяти }
RecErrorMessage := 'Ошибка блокирования памяти wave-буфера';
AllocPCMBuffers := False;
Exit;
end;
pWaveHeader[i].lpData := pWaveBuffer[i];
end;

AllocPCMBuffers := TRUE;
end;

{--------------FreePCMBuffers----------------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.FreePCMBuffers;

{ Освобождаем использованную AllocPCMBuffers память. }
{ }
{***********************************************************************}
var

i: Integer;

begin

for i := 0 to fTotalBuffers - 1 do
begin
if (hWaveBuffer[i] <> 0) then
begin
GlobalUnlock(hWaveBuffer[i]);
GlobalFree(hWaveBuffer[i]);
hWaveBuffer[i] := 0;
pWaveBuffer[i] := nil;
end;
end;
end;

{--------------FreeWaveFormatEx--------------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.FreeWaveFormatEx;

{ Просто освобождаем заголовки ExFormat headers }
{ }
{***********************************************************************}
begin

if (pWaveFmtEx = nil) then
Exit;
GlobalUnlock(hWaveFmtEx);
GlobalFree(hWaveFmtEx);
pWaveFmtEx := nil;
end;

{-------------TWaveRecorder.Create------------John Mertus-----Авг--97--}

constructor TWaveRecorder.Create(BFSize, TotalBuffers: Integer);

{ Устанавливаем wave-заголовки, инициализируем указатели данных и }
{ и распределяем буферы дискретизации }
{ BFSize - размер буфера в байтах }
{ }
{**********************************************************************}
var

i: Integer;
begin

inherited Create;
for i := 0 to fTotalBuffers - 1 do
begin
hWaveHeader[i] := 0;
hWaveBuffer[i] := 0;
pWaveBuffer[i] := nil;
pWaveFmtEx := nil;
end;
fBufferSize := BFSize;

fTotalBuffers := TotalBuffers;
{ распределяем память для структуры wave-формата }
if (not AllocWaveFormatEx) then
begin
InitWaveRecorder := FALSE;
Exit;
end;

{ ищем устройство, совместимое с доступными wave-характеристиками }
if (waveInGetNumDevs < 1) then
begin
RecErrorMessage := 'Не найдено устройств, способных записывать звук';
InitWaveRecorder := FALSE;
Exit;
end;

{ распределяем память wave-заголовка }
if (not AllocWaveHeaders) then
begin
InitWaveRecorder := FALSE;
Exit;
end;

{ распределяем память буфера wave-данных }
if (not AllocPCMBuffers) then
begin
InitWaveRecorder := FALSE;
Exit;
end;

InitWaveRecorder := TRUE;

end;

{---------------------Destroy----------------John Mertus---14-Июнь--97--}

destructor TWaveRecorder.Destroy;

{ Просто освобождаем всю память, распределенную InitWaveRecorder. }
{ }
{***********************************************************************}

begin

FreeWaveFormatEx;
FreePCMBuffers;
FreeWaveHeader;
inherited Destroy;
end;

{------------CloseWaveDeviceRecord-----------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.CloseWaveDeviceRecord;

{ Просто освобождаем (закрываем) waveform-устройство. }
{ }
{***********************************************************************}
var

i: Integer;

begin

{ если устройство уже закрыто, то выходим }
if (not bDeviceOpen) then
Exit;

{ работа с заголовками - unprepare }
for i := 0 to fTotalBuffers - 1 do
if (waveInUnprepareHeader(WaveIn, pWaveHeader[i], sizeof(TWAVEHDR)) <> 0)
then

RecErrorMessage := 'Ошибка в waveInUnprepareHeader';

{ сохраняем общий объем записи и обновляем показ }
dwTotalwavesize := dwBytedatasize;

{ закрываем входное wave-устройство }
if (waveInClose(WaveIn) <> 0) then
RecErrorMessage := 'Ошибка закрытия входного устройства';

{ сообщаем вызвавшей функции, что устройство закрыто }
bDeviceOpen := FALSE;

end;

{------------------StopRecord-----------------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.StopRecord;

{ Останавливаем запись и устанавливаем некоторые флаги. }
{ }
{***********************************************************************}
var

iErr: Integer;

begin

RecordActive := False;
iErr := waveInReset(WaveIn);
{ прекращаем запись и возвращаем стоящие в очереди буферы }
if (iErr <> 0) then
begin
RecErrorMessage := 'Ошибка в waveInReset';
end;

CloseWaveDeviceRecord;
end;

{--------------AddNextBuffer------------------John Mertus---14-Июнь--97--}

function TWaveRecorder.AddNextBuffer: Boolean;

{ Добавляем буфер ко входной очереди и переключаем буферный индекс. }
{ }
{***********************************************************************}
var

iErr: Integer;

begin

{ ставим буфер в очередь для получения очередной порции данных }
iErr := waveInAddBuffer(WaveIn, pwaveheader[bufindex], sizeof(TWAVEHDR));
if (iErr <> 0) then
begin
StopRecord;
RecErrorMessage := 'Ошибка добавления буфера' + TWaveInGetErrorText(iErr);
AddNextBuffer := FALSE;
Exit;
end;

{ переключаемся на следующий буфер }
bufindex := (bufindex + 1) mod fTotalBuffers;
QueuedBuffers := QueuedBuffers + 1;

AddNextBuffer := TRUE;
end;

{--------------BufferDoneCallBack------------John Mertus---14-Июнь--97--}

procedure BufferDoneCallBack(
hW: HWAVE;
// дескриптор waveform-устройства
uMsg: DWORD; // посылаемое сообщение
dwInstance: DWORD; // экземпляр данных
dwParam1: DWORD; // определяемый приложением параметр
dwParam2: DWORD; // определяемый приложением параметр
); stdcall;

{ Вызывается при наличии у wave-устройства какой-либо информации, }
{ например при заполнении буфера }
{ }
{***********************************************************************}
var

BaseRecorder: PWaveRecorder;
begin

BaseRecorder := Pointer(DwInstance);
with BaseRecorder^ do
begin
ProcessBuffer(uMsg, pWaveBuffer[ProcessedBuffers mod fTotalBuffers],
WaveBufSize);

if (RecordActive) then
case uMsg of
WIM_DATA:
begin
BaseRecorder.AddNextBuffer;
ProcessedBuffers := ProcessedBuffers + 1;
end;
end;
end;
end;

{------------------StartRecord---------------John Mertus---14-Июнь--97--}

function TWaveRecorder.StartRecord: Boolean;

{ Начало записи. }
{ }
{***********************************************************************}
var

iErr, i: Integer;

begin

{ начало записи в первый буфер }
iErr := WaveInStart(WaveIn);
if (iErr <> 0) then
begin
CloseWaveDeviceRecord;
RecErrorMessage := 'Ошибка начала записи wave: ' +
TWaveInGetErrorText(iErr);

end;

RecordActive := TRUE;

{ ставим в очередь следующие буферы }
for i := 1 to fTotalBuffers - 1 do
if (not AddNextBuffer) then
begin
StartRecord := FALSE;
Exit;
end;

StartRecord := True;
end;

{-----------------SetupRecord---------------John Mertus---14-Июнь--97--}

function TWaveRecorder.SetupRecord(P: PWaveRecorder): Boolean;

{ Данная функция делает всю работу по созданию waveform-"записывателя". }
{ }
{***********************************************************************}
var

iErr, i: Integer;

begin

dwTotalwavesize := 0;
dwBytedatasize := 0;
bufindex := 0;
ProcessedBuffers := 0;
QueuedBuffers := 0;

{ открываем устройство для записи }
iErr := waveInOpen(@WaveIn, WAVE_MAPPER, pWaveFmtEx,
Integer(@BufferDoneCallBack),

Integer(P), CALLBACK_FUNCTION + WAVE_ALLOWSYNC);
if (iErr <> 0) then
begin
RecErrorMessage := 'Не могу открыть входное устройство для записи: ' + ^M
+

TWaveInGetErrorText(iErr);
SetupRecord := FALSE;
Exit;
end;

{ сообщаем CloseWaveDeviceRecord(), что устройство открыто }
bDeviceOpen := TRUE;

{ подготавливаем заголовки }

InitWaveHeaders();

for i := 0 to fTotalBuffers - 1 do
begin
iErr := waveInPrepareHeader(WaveIn, pWaveHeader[I], sizeof(TWAVEHDR));
if (iErr <> 0) then
begin
CloseWaveDeviceRecord;
RecErrorMessage := 'Ошибка подготовки заголовка для записи: ' + ^M +
TWaveInGetErrorText(iErr);
SetupRecord := FALSE;
Exit;
end;
end;

{ добавляем первый буфер }
if (not AddNextBuffer) then
begin
SetupRecord := FALSE;
Exit;
end;

SetupRecord := TRUE;
end;

{-----------------ProcessBuffer---------------John Mertus---14-Июнь--97--}

procedure TWaveRecorder.ProcessBuffer(uMsg: Word; P: Pointer; n:
Integer);

{ Болванка процедуры, вызываемой при готовности буфера. }
{ }
{***********************************************************************}
begin
end;

end.
Категория: Аудио | Добавил: Skinner (07.07.2008)
Просмотров: 377 | Рейтинг: 0.0/0
  Delphi Lab   Главная   Регистрация   Вход  
Интересная Цитата

Поиск

Магазин


Copyright MyCorp © 2025 Хостинг от uCoz