📄 unadsplibautomation.pas
字号:
(*
DSP Lib Automation
----------------------------------------------
This source code cannot be used without
proper license granted to you as a private
person or an entity by the Lake of Soft, Ltd
Visit http://lakeofsoft.com/ for more information.
Copyright (c) 2001, 2007 Lake of Soft, Ltd
All rights reserved
----------------------------------------------
modified by:
Lake, Mar 2007
----------------------------------------------
*)
{$i unaDef.inc }
unit
unaDSPLibAutomation;
interface
uses
Windows, unaTypes, unaClasses, unaDSPLibH;
const
//
c_defAutomatSection = 'dsplib.automat';
type
unaDSPLibAutomat = class;
//
// -- unaDSPLibObjectList --
//
unaDSPLibObjectList = class(unaList)
private
f_automat: unaDSPLibAutomat;
protected
procedure releaseItem(index: unsigned; doFree: unsigned); override;
public
constructor create(automat: unaDSPLibAutomat);
end;
//
// -- unaDSPLibAutomat --
//
unaDSPLibAutomat = class(unaObject)
private
f_root: unaDspLibAbstract;
f_gate: unaInProcessGate;
f_objects: unaDSPLibObjectList;
f_objectParams: unaStringList;
//
f_subAutos: unaObjectList;
f_subAutosDirty: bool;
//
f_rate, f_bits, f_channels: int;
f_bitsSHR: int;
//
f_inBuf, f_outBuf: pFloatArray;
f_bufSize: int;
f_multiOutBuf: unaRecordList;
f_multiOutBufSize: int;
//
f_defIni: unaIniAbstractStorage;
f_defSection: string;
//
function isMultiOutID(id: dspl_int): bool;
function isMultiOutObj(obj: dspl_handle): bool;
function bufAllocate(nSamples: int; checkMultiOutOnly: bool = false): HRESULT;
procedure assignBuf2obj(obj: dspl_handle);
procedure convertFloatIn(data: pointer; samples: int; channel: int);
procedure convertFloatOut(data: pointer; samples: int; channel: int);
function processChunkChannel(data: pointer; channel, nSamples: unsigned; forceProcessByMe: bool = false; writeOutput: bool = true): HRESULT;
public
constructor create(root: unaDspLibAbstract);
procedure AfterConstruction(); override;
procedure BeforeDestruction(); override;
//
{DP:MEHTOD
//
Loads the automat configuration from a ini storage.
}
function automatLoad(ini: unaIniAbstractStorage; const sectionName: string = c_defAutomatSection): HRESULT; overload;
{DP:MEHTOD
//
Loads the automat configuration from a string.
}
function automatLoad(const config: string): HRESULT; overload;
//
{DP:MEHTOD
//
Saves the automat configuration.
If unaIniAbstractStorage is nil (default) the one provided in last call of automatLoad() will be used.
If automatLoad() was not called before, the funtion will fail.
//
If sectionName is '' (default) the name provided in automatLoad() will be used.
If automatLoad() was not called before, c_defAutomatSection will be used as section name.
}
function automatSave(ini: unaIniAbstractStorage = nil; const sectionName: string = ''): HRESULT; overload;
{DP:MEHTOD
//
Saves the automat configuration as a string.
}
function automatSave(out config: string): HRESULT; overload;
//
{DP:METHOD
Specifies audio stream format. Only mono streams are supported.
}
function setFormat(rate, bits, channels: int; isSubAuto: bool = false): HRESULT;
{DP:METHOD
Processes an audio chunk. Use channel to specify channel number in a non-mono stream.
Output data will be saved in provided buffer, or in case of multiOut object, output
data can be read using getOutData() method.
//
NOTE: only one automat must be used to process one channel, so do not use one automat to
process left and right channels consequently, this will not provide any good results.
When you do not specify a channel number, automat will create internal automats
one per each channel for non-mono streams.
//
NOTE: multiOut objects will overwrite the output buffers of each other. Currently only
one multiOut object per automat is supported.
}
function processChunk(data: pointer; len: unsigned; channel: int = -1; nSamples: int = -1; writeOutput: bool = true): HRESULT;
//
{DP:METHOD
Returns raw output audio buffer assigned to objects.
}
function getOutData(channel: uint; out data: pdspl_float; out nSamples: uint): HRESULT;
{DP:METHOD
Returns raw output audio buffer assigned to multi-output objects.
Parameter n specifies the number of output stream (band), and must be from 0 to num of outputs - 1.
}
function getMultiOutData(channel: uint; n: uint; out data: pdspl_float; out nSamples: uint): HRESULT;
//
{DP:METHOD
Returns number of audio samples which can be stored in specified number of bytes.
}
function bytes2samples(numBytes: int): int;
//
{DP:METHOD
Returns number of DSPLib objects.
}
function dspl_objCount(): int;
{DP:METHOD
Returns a DSPLib object handle.
}
function dspl_objGet(index: int): dspl_handle;
{DP:METHOD
Creates new DSPLib object of a given type.
}
function dspl_objNew(objID: int): dspl_handle;
{DP:METHOD
Returns the index of a DSPLib object in the list.
}
function dspl_objIndex(obj: dspl_handle): int;
{DP:METHOD
Removes DSPLib object from the list.
}
function dspl_objDrop(index: int): dspl_result;
{DP:METHOD
Exchanges two DSPLib object places.
}
function dspl_objSwap(index1, index2: int): dspl_result;
//
{DP:METHOD
Sets an integer property of a DSPLib object.
}
function dspl_obj_seti(obj: dspl_handle; param_id: int; value: dspl_int): dspl_result;
{DP:METHOD
Sets an integer property of a DSPLib object.
}
function dspl_obj_setf(obj: dspl_handle; param_id: int; value: dspl_float): dspl_result;
{DP:METHOD
Sets an integer property of a DSPLib object.
}
function dspl_obj_setc(obj: dspl_handle; param_id: int; const value: dspl_chunk): dspl_result; overload;
function dspl_obj_setc(obj: dspl_handle; param_id: int; fp: pdspl_float; len: dspl_int): dspl_result; overload;
{DP:METHOD
Returns object parameter value.
}
function dspl_obj_getf(obj: dspl_handle; channel: int; param_id: int; out fp: dspl_float): dspl_result; overload;
//
{DP:METHOD
Abstract DSPLib interface.
}
property root: unaDspLibAbstract read f_root;
end;
implementation
uses
{$IFDEF __SYSUTILS_H_ }
Math,
{$ENDIF}
unaUtils;
{ unaDSPLibObjectList }
// -- --
constructor unaDSPLibObjectList.create(automat: unaDSPLibAutomat);
begin
f_automat := automat;
//
inherited create(false);
end;
procedure unaDSPLibObjectList.releaseItem(index, doFree: unsigned);
var
obj: dspl_handle;
begin
if (0 <> doFree) then begin // mapDoFree() is of no good here, since autoFree is false
//
try
obj := dspl_handle(get(index));
//
if (DSPL_INVALID_HANDLE <> obj) then
f_automat.f_root.destroyObj(obj);
except
end;
end;
//
inherited releaseItem(index, doFree); // items is freed already, so it should not try to release the object once more
end;
{ unaDSPLibAutomat }
// -- --
procedure unaDSPLibAutomat.AfterConstruction();
begin
//
inherited;
end;
// -- --
function unaDSPLibAutomat.automatLoad(const config: string): HRESULT;
var
objId: int;
obj: dspl_handle;
i, j: int;
numObjects: int;
//
numParams: int;
paramID: int;
paramType: char;
paramValue: string;
paramValueC: dspl_chunk;
paramValueF: dspl_float;
paramValueI: dspl_int;
begin
result := HRESULT(-1);
with (unaStringList.create()) do begin
//
try
if (f_gate.enter(3000)) then begin
//
try
text := config;
//
f_objects.clear();
f_objectParams.clear();
//
// load and create objects
numObjects := str2intInt(values['numObjects'], 0);
i := 0;
while (i < numObjects) do begin
//
objId := str2intInt(values['obj.' + int2str(i) + '.id'], 0);
if (0 < objId) then begin
//
obj := dspl_objNew(objId);
if (DSPL_INVALID_HANDLE <> obj) then begin
//
// load object params
numParams := str2intInt(values['obj.' + int2str(i) + '.numParams'], 0);
j := 0;
while (j < numParams) do begin
//
paramID := str2intInt(values['obj.' + int2str(i) + '.param.' + int2str(j) + '.id'], 0);
paramValue := values['obj.' + int2str(i) + '.param.' + int2str(j) + '.value'];
if ('' <> trim(paramValue)) then begin
//
paramType := upCase(paramValue[1]);
paramValue := base64decode(copy(paramValue, 2, maxInt));
end
else
paramType := 'U';
//
if ((0 < paramId) and ('' <> paramValue)) then begin
//
case (paramType) of
'C': begin
// chunk, paramValue is base64 encoded binary data
paramValueC.r_fp := @paramValue[1];
paramValueC.r_len := length(paramValue) div sizeOf(paramValueC.r_fp^);
dspl_obj_setc(obj, paramId, paramValueC);
end;
'F': begin
//
if (length(paramValue) = sizeOf(paramValueF)) then begin
//
move(paramValue[1], paramValueF, sizeOf(paramValueF));
dspl_obj_setf(obj, paramId, paramValueF);
end;
end;
'I': begin
//
if (length(paramValue) = sizeOf(paramValueI)) then begin
//
move(paramValue[1], paramValueI, sizeOf(paramValueI));
dspl_obj_seti(obj, paramId, paramValueI);
end;
end;
else begin
// uknown param type
end;
end;
//
end;
//
inc(j);
end; // while (j < numParams) ...
end
else
f_objects.add(pointer(DSPL_INVALID_HANDLE));
//
end
else
f_objects.add(pointer(DSPL_INVALID_HANDLE));
//
inc(i);
end;
//
//
result := S_OK;
finally
f_gate.leave();
end;
end;
finally
free();
end;
end;
end;
// -- --
function unaDSPLibAutomat.automatLoad(ini: unaIniAbstractStorage; const sectionName: string): HRESULT;
var
v: string;
begin
if (nil <> ini) then begin
//
f_defINI := ini;
//
if ('' <> trim(sectionName)) then
f_defSection := sectionName
else
f_defSection := c_defAutomatSection;
//
v := f_defIni.getSectionAsText(f_defSection);
//
result := automatLoad(v);
end
else
result := HRESULT(-1);
end;
// -- --
function unaDSPLibAutomat.automatSave(out config: string): HRESULT;
var
i, p, s: int;
obj: dspl_handle;
paramCount: int;
paramID: string;
paramValue: string;
begin
result := HRESULT(-1);
config := '';
//
if (f_gate.enter(3000)) then begin
//
try
config := '';
if (lockNonEmptyList(f_objects, 3000)) then begin
//
try
config := 'numObjects=' + int2str(f_objects.count) + #13#10;
//
for i := 0 to f_objects.count - 1 do begin
//
obj := dspl_handle(f_objects.get(i));
config := config + 'obj.' + int2str(i) + '.id=' + int2str(f_root.getID(obj)) + #13#10;
//
paramCount := 0;
//
if (0 < f_objectParams.count) then begin
//
for p := 0 to f_objectParams.count - 1 do begin
//
paramID := f_objectParams.get(p);
s := pos('=', paramID);
if (1 < s) then begin
//
paramValue := copy(paramID, s + 1, maxInt);
paramID := copy(paramID, 1, s - 1);
if (1 = pos(int2str(obj) + '.', paramID)) then begin
//
paramID := copy(paramID, pos('.', paramID) + 1, maxInt);
//
config := config + 'obj.' + int2str(i) + '.param.' + int2str(paramCount) + '.id=' + paramID + #13#10;
config := config + 'obj.' + int2str(i) + '.param.' + int2str(paramCount) + '.value=' + paramValue + #13#10;
//
inc(paramCount);
end;
end;
end; // for ..
end;
//
config := config + 'obj.' + int2str(i) + '.numParams=' + int2str(paramCount) + #13#10;
end;
//
finally
f_objects.unlock();
end;
end;
//
result := S_OK;
finally
f_gate.leave();
end;
end;
end;
// -- --
function unaDSPLibAutomat.automatSave(ini: unaIniAbstractStorage; const sectionName: string): HRESULT;
var
sec: string;
v: string;
begin
if (nil <> f_defINI) then begin
//
if ('' <> trim(sectionName)) then
sec := sectionName
else
if ('' = f_defSection) then
sec := c_defAutomatSection
else
sec := f_defSection;
//
result := automatSave(v);
if (Succeeded(result)) then
f_defIni.setSectionAsText(f_defSection, v);
end
else
result := HRESULT(-1);
end;
// -- --
procedure unaDSPLibAutomat.BeforeDestruction();
begin
inherited;
//
if (f_gate.enter(4000)) then begin
try
bufAllocate(0); // release buffers
//
freeAndNil(f_subAutos);
freeAndNil(f_objectParams);
freeAndNil(f_objects);
freeAndNil(f_multiOutBuf);
finally
f_gate.leave();
end;
end;
//
freeAndNil(f_gate);
end;
// -- --
function unaDSPLibAutomat.bufAllocate(nSamples: int; checkMultiOutOnly: bool): HRESULT;
var
i, j: int;
p: pointer;
n: dspl_int;
obj: dspl_handle;
begin
result := S_OK;
//
// buffers are too small or too large or should be unallocated?
if ( (f_bufSize <> nSamples) or ((0 = nSamples) and (0 < f_bufSize)) or checkMultiOutOnly ) then begin
//
if (f_gate.enter(3000)) then begin
try
if (not checkMultiOutOnly) then begin
//
mrealloc(f_inBuf, sizeOf(f_inBuf[0]) * nSamples);
mrealloc(f_outBuf, sizeOf(f_outBuf[0]) * nSamples);
//
f_bufSize := nSamples;
end;
//
if (0 < f_objects.count) then begin
//
for i := 0 to f_objects.count - 1 do begin
//
obj := dspl_objGet(i);
if (DSPL_INVALID_HANDLE <> obj) then begin
//
if (isMultiOutObj(obj)) then begin
//
// this is multi-out object, check if we have buffers allocated
if (checkMultiOutOnly or (f_multiOutBufSize <> nSamples) ) then begin
//
n := root.geti(obj, DSPL_PID or DSPL_P_OTHER); // number of out buffers
j := 0;
while (j < n) do begin
//
if (j < int(f_multiOutBuf.count)) then begin
// reallocate buffer size
p := f_multiOutBuf.get(j);
mrealloc(p, nSamples * sizeOf(dspl_float));
f_multiOutBuf.setItem(j, p, 0);
end
else
// add new buffer
f_multiOutBuf.add(malloc(nSamples * sizeOf(dspl_float)));
//
inc(j);
end;
//
f_multiOutBufSize := nSamples;
end;
end;
//
assignBuf2Obj(obj);
end;
end;
end;
//
finally
f_gate.leave();
end;
end
else
result := HRESULT(-1);
//
end;
end;
// -- --
function unaDSPLibAutomat.bytes2samples(numBytes: int): int;
begin
result := (numBytes shr f_bitsSHR) div f_channels;
end;
// -- --
procedure unaDSPLibAutomat.convertFloatIn(data: pointer; samples, channel: int);
var
i: int;
p: int;
begin
if (1 = f_channels) and (1 > channel) and (32 = f_bits) then begin
//
// no need to transcode
move(data^, f_inBuf^, samples * sizeOf(f_inBuf[0]));
end
else begin
//
if (channel < f_channels) then begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -