⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unadsplibautomation.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 2 页
字号:

(*

	  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 + -