📄 unadspdlibpipes.pas
字号:
(*
----------------------------------------------
unaDspDLibPipes.pas - DSP DLib pipe components
Voice Communicator components version 2.5 Pro
----------------------------------------------
This source code cannot be used without
proper permission granted to you as a private
person or an entity by the Lake of Soft, Ltd
Visit http://lakeofsoft.com/ for details.
Copyright (c) 2001, 2007 Lake of Soft, Ltd
All rights reserved
----------------------------------------------
created by:
Lake, 15 Mar 2007
modified by:
Lake, Mar 2007
----------------------------------------------
*)
{$I unaDef.inc}
unit
unaDspDLibPipes;
interface
uses
Windows, unaTypes, unaMsAcmApi,
unaDspLibH, unaDspLibAutomation,
Classes, unaVcIDE;
type
{DP:CLASS
Abstract wave DSP DLib pipe.
}
unaDSPDLibWavePipe = class(unavclInOutWavePipe)
private
f_localBuf: pointer;
f_localBufSize: int;
//
f_active: bool; // this property simply stores current active state
//
f_automation: unaDSPLibAutomat;
//
f_processDataInPlace: bool;
protected
{DP:METHOD
Converts DSP DLib output float buffer(s) to PCM plain buffer, and returns its size in bytes.
}
function convertOutFloat2PCM(out buf: pointer): int; virtual;
//
{DP:METHOD
Returns true if component was activated.
}
function isActive(): bool; override;
{DP:METHOD
"Activates" the component.
}
function doOpen(): bool; override;
{DP:METHOD
"Deactivates" the component.
}
procedure doClose(); override;
{DP:METHOD
Applies new format on DSP automation.
}
function applyDeviceFormat(const format: WAVEFORMATEX; isSrc: bool = true): bool; override;
{DP:METHOD
Processes new chunk with DSP automation.
}
function doWrite(data: pointer; len: unsigned; provider: unavclInOutPipe = nil): int; override;
{DP:METHOD
Reads last data processed by DSP automation.
Not yet implemented.
}
function doRead(data: pointer; len: unsigned): unsigned; override;
public
constructor Create(owner: tComponent); override;
procedure AfterConstruction(); override;
procedure BeforeDestruction(); override;
//
{DP:MEHTOD
DSPDLib automation.
}
property automation: unaDSPLibAutomat read f_automation;
//
published
{DP:MEHTOD
Specifies whether data should be processed by conponent "in place", changing the values in provider's buffer.
When set to false data will be processed using local buffer (a bit slowly, but does not touch provider's data).
Must be set to false if provider has more than one consumer.
}
property processDataInPlace: bool read f_processDataInPlace write f_processDataInPlace default true;
{DP:METHOD
DSP components are usually a format providers -- so this property value was changed to be true by default.
}
property isFormatProvider default true;
{DP:METHOD
Specifies whether the component would perform any data processing.
}
property enableDataProcessing;
end;
const
//
c_defNumBands = 10;
type
//
unavcDSPDLib_freqAssignMode = (unafam_manual, unafam_powerOf2);
//
// -- --
//
unavclDSPDLibMultiBand = class(unaDSPDLibWavePipe)
private
f_numBands: uint;
f_freqAssignMode: unavcDSPDLib_freqAssignMode;
//
procedure setNumBands(value: uint);
function getFreq(band: uint): dspl_float;
procedure setFreq(band: uint; const value: dspl_float);
//
function allocateNBuf(n: uint): pFloatArray;
procedure checkFreqMode();
protected
f_dsplObj: dspl_handle;
//
procedure doSetNumBands(value: uint); virtual;
//
{DP:MEHTOD
Usually number of freq equals number of bands, but some classes may override this.
}
function getNumFreq(): int; virtual;
{DP:MEHTOD
In addition makes sure frequencises are correct.
}
function applyDeviceFormat(const format: WAVEFORMATEX; isSrc: bool = true): bool; override;
public
procedure AfterConstruction(); override;
//
{DP:MEHTOD
DSPDLib object.
}
property dsplObj: dspl_handle read f_dsplObj;
{DP:MEHTOD
Frequency value for a specific band.
}
property frequency[band: uint]: dspl_float read getFreq write setFreq;
published
{DP:MEHTOD
Number of bands, 32 max.
}
property numBands: uint read f_numBands write setNumBands default c_defNumBands;
{DP:MEHTOD
Frequences assigment mode.
}
property freqAssignMode: unavcDSPDLib_freqAssignMode read f_freqAssignMode write f_freqAssignMode default unafam_powerOf2;
end;
{DP:CLASS
EQ Pipe.
}
TunavclDSPDLibEQ = class(unavclDSPDLibMultiBand)
private
//
function getGain(band: uint): dspl_float;
procedure setGain(band: uint; const value: dspl_float);
protected
//
procedure doSetNumBands(value: uint); override;
public
constructor Create(owner: tComponent); override;
//
{DP:MEHTOD
Gain value for a specific band.
}
property gain[band: uint]: dspl_float read getGain write setGain;
end;
//
// pointer to array of raw samples for up to 256 bands
punaDspBandRawSamples = ^unaDspBandRawSamples;
unaDspBandRawSamples = array[byte] of pFloatArray;
//
{DP:METHOD
Fired when raw multi-band samples are ready.
}
unavclRawSamplesAvailable = procedure(sender: unavclInOutPipe; numSamples, numBands, channel: uint; samples: punaDspBandRawSamples) of object;
{DP:CLASS
Multi-band Splitter Pipe.
}
TunavclDSPDLibMBSP = class(unavclDSPDLibMultiBand)
private
f_bandPT: array[byte] of bool; // up to 256 bands
//
f_localRaw: array[byte] of unaDspBandRawSamples; // up to 256 channels
f_localFBuf: array[byte] of pFloatArray; // up to 256 channels
f_localFBufSize: array[byte] of int;
//
f_onRawSamplesAvail: unavclRawSamplesAvailable;
//
function getPT(band: uint): bool;
procedure setPT(band: uint; value: bool);
protected
{DP:METHOD
Converts DSP DLib output float buffer(s) to PCM plain buffer, and returns its size in bytes.
}
function convertOutFloat2PCM(out buf: pointer): int; override;
{DP:METHOD
Num of freqs is one less than numBands in MBSP, so we override this function
}
function getNumFreq(): int; override;
public
constructor Create(owner: tComponent); override;
procedure AfterConstruction(); override;
procedure BeforeDestruction(); override;
//
{DP:MEHTOD
Pass-through value for a specific band.
}
property passThrough[band: uint]: bool read getPT write setPT;
published
{DP:MEHTOD
MBSP splits the audio into bands only when processDataInPlace is false, so we make it default.
}
property processDataInPlace default false;
//
{DP:METHOD
Fired when raw multi-band samples are ready.
}
property onRawSamplesAvailable: unavclRawSamplesAvailable read f_onRawSamplesAvail write f_onRawSamplesAvail;
end;
{DP:METHOD
Registers VC DSP DLib components in Delphi IDE components palette.
}
procedure Register();
implementation
uses
unaUtils, unaDspDLib;
var
//
// global root - Delphi implementation of DSP Lib
g_root: unaDspLibAbstract;
{ unaDSPDLibWavePipe }
// -- --
procedure unaDSPDLibWavePipe.AfterConstruction();
begin
inherited; // creates PCM format
//
processDataInPlace := true;
isFormatProvider := true; // by default
end;
// -- --
function unaDSPDLibWavePipe.applyDeviceFormat(const format: WAVEFORMATEX; isSrc: bool): bool;
begin
// there is no inheried implementation to call
//
result := SUCCEEDED(automation.setFormat(format.nSamplesPerSec, format.wBitsPerSample, format.nChannels));
end;
// -- --
procedure unaDSPDLibWavePipe.BeforeDestruction();
begin
inherited;
//
freeAndNil(f_automation);
//
f_localBufSize := 0;
mrealloc(f_localBuf);
end;
// -- --
function unaDSPDLibWavePipe.convertOutFloat2PCM(out buf: pointer): int;
var
p, c: uint;
s: uint;
nSamples: uint;
outBuf: pdspl_float;
f: dspl_float;
//
pcmBits: uint; // local copy of pcmFormat.wBitsPerSample
begin
result := 0;
//
// convert float samples to integer values (if we have to)
if (0 < pcmFormat.nChannels) then begin
//
pcmBits := pcmFormat.wBitsPerSample;
for c := 0 to pcmFormat.nChannels - 1 do begin
//
automation.getOutData(c, outBuf, nSamples);
//
if (1 > nSamples) then
continue; // no out data in this channel?
//
result := nSamples * pcmFormat.nChannels * (1 + (pcmBits - 1) shr 3);
if (f_localBufSize < result) then begin
//
mrealloc(f_localBuf, result);
f_localBufSize := result;
end;
//
p := c;
for s := 0 to nSamples - 1 do begin
//
f := outBuf^;
if (f > 1.0) then
f := 1.0;
//
if (f < -1.0) then
f := -1.0;
//
case (pcmBits) of
8: pArray(f_localBuf)[p] := trunc(f * $FF + $80);
16: pSmallIntArray(f_localBuf)[p] := trunc(f * $7FFF);
24: pInt32Array(f_localBuf)[p] := trunc(f * $7FFFFF);
32: pFloatArray(f_localBuf)[p] := f;
end;
//
inc(outBuf);
inc(p, pcmFormat.nChannels); // go to next sample in same channel
//
end; // for all samples
end; // for all channels
//
buf := f_localBuf;
//
end; // 0 < channels
end;
// -- --
constructor unaDSPDLibWavePipe.create(owner: tComponent);
begin
f_automation := unaDSPLibAutomat.create(g_root);
//
inherited;
end;
// -- --
procedure unaDSPDLibWavePipe.doClose();
begin
inherited;
//
f_active := false;
end;
// -- --
function unaDSPDLibWavePipe.doOpen(): bool;
begin
inherited doOpen(); // it will return false since "device" is nil
result := true;
//
f_active := result;
end;
// -- --
function unaDSPDLibWavePipe.doRead(data: pointer; len: unsigned): unsigned;
begin
// not yet implemeted
result := 0;
end;
// -- --
function unaDSPDLibWavePipe.doWrite(data: pointer; len: unsigned; provider: unavclInOutPipe): int;
var
res: HRESULT;
buf: pointer;
begin
result := 0;
//
if (enableDataProcessing) then begin
//
if (enter()) then begin // we must protect automation and local buffer from MT entering
//
try
// process data, but do not write it into same buffer (if processDataInPlace is false)
res := automation.processChunk(data, len, -1, -1, processDataInPlace);
//
if (SUCCEEDED(res)) then begin
//
// new data is available immediately, convert it to integers and notify
if (not processDataInPlace) then begin
//
result := convertOutFloat2PCM(buf);
onNewData(buf, result, self);
end
else begin
//
result := len;
onNewData(data, result, self);
end;
end;
//
finally
leave();
end;
end;
end
else begin
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -