unit DMRBindings; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses Classes, SysUtils, DynLibs; const DMR_ABI_VERSION = 1; DMR_AMBE_BITS = 96; DMR_PCM_SAMPLES = 160; type TDMRMbeResult = packed record ErrorsC0: LongInt; ErrorsTotal: LongInt; end; PDMRMbeResult = ^TDMRMbeResult; function DMRLoad: Boolean; procedure DMRUnload; function DMRLoaded: Boolean; function DMRLastError: string; function DMRMbeCreate(UVQuality: Integer): Pointer; procedure DMRMbeDestroy(Decoder: Pointer); procedure DMRMbeReset(Decoder: Pointer); function DMRMbeDecode(Decoder: Pointer; Bits: PByte; PCM: PSingle; ResultInfo: PDMRMbeResult): Integer; implementation type TAbiVersion = function: LongWord; cdecl; TMbeCreate = function(UVQuality: LongInt): Pointer; cdecl; TMbeDestroy = procedure(Decoder: Pointer); cdecl; TMbeReset = procedure(Decoder: Pointer); cdecl; TMbeDecode = function(Decoder: Pointer; Bits: PByte; PCM: PSingle; ResultInfo: Pointer): LongInt; cdecl; var GLib: TLibHandle = dynlibs.NilHandle; GLastError: string = ''; GAbiVersion: TAbiVersion = nil; GMbeCreate: TMbeCreate = nil; GMbeDestroy: TMbeDestroy = nil; GMbeReset: TMbeReset = nil; GMbeDecode: TMbeDecode = nil; function Symbol(const Name: PChar): Pointer; begin Result := GetProcedureAddress(GLib, Name); if Result = nil then GLastError := 'Missing DMR symbol: ' + string(Name); end; function DMRLoad: Boolean; const {$IFDEF WINDOWS} Names: array[0..0] of string = ('ewsdr_dmr.dll'); {$ELSE} {$IFDEF DARWIN} Names: array[0..0] of string = ('libewsdr_dmr.dylib'); {$ELSE} Names: array[0..1] of string = ('libewsdr_dmr.so', 'libewsdr_dmr.so.1'); {$ENDIF} {$ENDIF} var i: Integer; LocalName: string; begin if GLib <> dynlibs.NilHandle then Exit(True); GLastError := ''; for i := Low(Names) to High(Names) do begin LocalName := ExtractFilePath(ParamStr(0)) + Names[i]; GLib := LoadLibrary(LocalName); if GLib = dynlibs.NilHandle then GLib := LoadLibrary(Names[i]); if GLib <> dynlibs.NilHandle then Break; end; if GLib = dynlibs.NilHandle then begin GLastError := 'Optional EWSDR DMR library not found'; Exit(False); end; GAbiVersion := TAbiVersion(Symbol('ewsdr_dmr_abi_version')); GMbeCreate := TMbeCreate(Symbol('ewsdr_dmr_mbe_create')); GMbeDestroy := TMbeDestroy(Symbol('ewsdr_dmr_mbe_destroy')); GMbeReset := TMbeReset(Symbol('ewsdr_dmr_mbe_reset')); GMbeDecode := TMbeDecode(Symbol('ewsdr_dmr_mbe_decode')); if not Assigned(GAbiVersion) or not Assigned(GMbeCreate) or not Assigned(GMbeDestroy) or not Assigned(GMbeReset) or not Assigned(GMbeDecode) then begin DMRUnload; Exit(False); end; if GAbiVersion() <> DMR_ABI_VERSION then begin GLastError := Format('Unsupported EWSDR DMR ABI: %d', [GAbiVersion()]); DMRUnload; Exit(False); end; Result := True; end; procedure DMRUnload; begin GAbiVersion := nil; GMbeCreate := nil; GMbeDestroy := nil; GMbeReset := nil; GMbeDecode := nil; if GLib <> dynlibs.NilHandle then begin UnloadLibrary(GLib); GLib := dynlibs.NilHandle; end; end; function DMRLoaded: Boolean; begin Result := GLib <> dynlibs.NilHandle; end; function DMRLastError: string; begin Result := GLastError; end; function DMRMbeCreate(UVQuality: Integer): Pointer; begin if Assigned(GMbeCreate) then Result := GMbeCreate(UVQuality) else Result := nil; end; procedure DMRMbeDestroy(Decoder: Pointer); begin if Assigned(GMbeDestroy) and (Decoder <> nil) then GMbeDestroy(Decoder); end; procedure DMRMbeReset(Decoder: Pointer); begin if Assigned(GMbeReset) and (Decoder <> nil) then GMbeReset(Decoder); end; function DMRMbeDecode(Decoder: Pointer; Bits: PByte; PCM: PSingle; ResultInfo: PDMRMbeResult): Integer; begin if not Assigned(GMbeDecode) then Exit(-1); Result := GMbeDecode(Decoder, Bits, PCM, ResultInfo); end; end.