Как сделать калькулятор в Delphi?

Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.

Как Delphi реализует многоплатформенную разработку?

Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...

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

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

Ниже приведен код, обрабатывающий аудиосигнал, получаемый со входа звуковой карты (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

.

Другое по теме:

Категории

Статьи

Советы

Copyright © 2024 - All Rights Reserved - www.delphirus.com