AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Problem mit mehreren Channels - DASIOHost
Thema durchsuchen
Ansicht
Themen-Optionen

Problem mit mehreren Channels - DASIOHost

Ein Thema von BloodySmartie · begonnen am 13. Mär 2007
Antwort Antwort
BloodySmartie
(Gast)

n/a Beiträge
 
#1

Problem mit mehreren Channels - DASIOHost

  Alt 13. Mär 2007, 14:30
Hallo liebe Mitglieder!

Ich arbeite derzeit an einem Analyzer, welcher ein Frequenzspektrum
mehrerer Kanäle einer ASIO-Soundkarte anzeigen soll. Zuerst begann
ich mit dem BASSASIO SDK, was mit meiner eMagic USB-Soundkarte auch
tadellos funktionierte. Allerdings machte das SDK Probleme beim Testen
mit der eigentlichen Ziel-Hardware, der Hercules 16/12 FW FireWire.
Also stieg ich auf die Nutzung der DASIOHost / Vst - Komponenten um.

Nun stehe ich vor einem neuen Problem. Mit diesen Komponenten kann ich
ausschließlich auf die Daten des ersten Inputkanals zugreifen. Selbst wenn
ich ordentlich versuche auf die Daten des zweiten oder vierten Kanals zuzugreifen, werden
mir nur die Daten des ersten angezeigt.

Mir ist auch aufgefallen, dass selbst das mitgelieferte Analyzer-Beispiel
nicht wirklich multichannelfähig ist. Dieses Problem tritt auf beiden
Soundkarten auf. Ich gehe daher zunächst davon aus, dass es sich um einen
Bug in der Bibliothek handelt.

Weiß vielleicht jemand eine Lösung für mein Problem - eventuell in Form
von Änderungen im Quelltext der DASIOHost.pas?

Quelltext DASIOHost.pas:
Delphi-Quellcode:
unit DASIOHost;
{$R DASIOHost.res}
{$I JEDI.INC}

interface
                   
uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Math, stdctrls, comctrls,
  ASIOlist, OpenASIO, ASIO, DASIOConvert, DDspUtils
  {$IFDEF DELPHI5} ,dsgnintf {$ENDIF};

const
     // private message
     PM_ASIO = WM_User + 1652; // unique we hope
     // ASIO message(s), as wParam for PM_ASIO
     AM_ResetRequest = 0;
     AM_BufferSwitch = 1; // new buffer index in lParam
     AM_BufferSwitchTimeInfo = 2; // new buffer index in lParam
                                      // time passed in MainForm.BufferTime
     AM_LatencyChanged = 3;
     PM_UpdateSamplePos = PM_ASIO + 1; // sample pos in wParam (hi) and lParam (lo)

     PM_BufferSwitch = PM_ASIO + 2;
     PM_BufferSwitchTimeInfo = PM_ASIO + 3;

type
  TConvertOptimization = (coSSE, co3DNow);
  TConvertOptimizations = set of TConvertOptimization;

  TInConvertor = procedure(source: pointer; target: PSingle; frames: longint);
  TOutConvertor = procedure(source: PSingle; target: pointer; frames: longint);

  TSamplePositionUpdateEvent = procedure(Sender: TObject; SamplePosition: Int64) of object;
  TSample2Event = procedure(Sender: TObject; Sample: array of Single) of object;
  TBufferSwitchEvent = procedure(Sender: TObject; InBuffer, OutBuffer: TArrayOfSingleArray) of object;

  TBufferPreFill =(bpfNone, bpfZero, bpfNoise);

  TInputMonitor =(imDisabled, imMono, imStereo, imAll);

  TATFlag =(atSystemTimeValid, atSamplePositionValid, atSampleRateValid,
            atSpeedValid, atSampleRateChanged, atClockSourceChanged);
  TATFlags = set of TATFlag;

  TASIOTimeSub = class(TPersistent)
  private
    FOnChange: TNotifyEvent;
    function GetATInt64(Index: Integer): Int64;
    function GetATdouble(Index: Integer): Double;
    function GetATflags: TATFlags;
    procedure SetATInt64(Index: Integer; Value: Int64);
    procedure SetATdouble(Index: Integer; Value: Double);
    procedure SetATflags(Flags: TATFlags);
  protected
    FBufferTime: TASIOTime;
    procedure Change; dynamic;
    procedure AssignTo(Dest: TPersistent); override;
  public
    property OnChanged: TNotifyEvent read FOnChange write FOnChange;
    constructor Create;
  published
    property SamplePos: Int64 index 0 read GetATInt64 write SetATInt64;
    property Speed : Double index 0 read GetATdouble write SetATdouble; //absolute speed (1. = nominal)
    property SampleRate: Double Index 1 read GetATdouble write SetATdouble;
    property Flags : TATFlags read GetATflags Write SetATflags;
  end;

{$IFDEF DELPHI5}
  TASIOControlPanel = class(TComponentEditor)
  public
    procedure Edit; override;
    procedure ExecuteVerb(Index: Integer); override;
    function GetVerb(Index: Integer): string; override;
    function GetVerbCount: Integer; override;
  end;
{$ENDIF}

  TASIOHost = class(TComponent)
  private
    FActive : Boolean;
    FPreventClipping : Boolean;
    FInBufferPreFill : TBufferPreFill;
    FOutBufferPreFill : TBufferPreFill;
    FDriverIndex : Integer;
    FDriverList : TStrings;
    FDriverName : String;
    FDriverVersion : integer;
    FInputLatency : Integer;
    FOutputLatency : Integer;
    FInputChannels : Integer;
    FOutputChannels : Integer;
    FSampleRate : Double;
    FBufferSize : Cardinal;
    FASIOTime : TASIOTimeSub;
    FOnCreate : TNotifyEvent;
    FOnDestroy : TNotifyEvent;
    FOnReset : TNotifyEvent;
    FOnDriverChanged : TNotifyEvent;
    FOnLatencyChanged : TNotifyEvent;
    FOnSampleRateChanged : TNotifyEvent;
    FOnSample2Output : TSample2Event;
    FOnInput2Sample : TSample2Event;
    FOnUpdateSamplePos : TSamplePositionUpdateEvent;
    FOnBufferSwitch : TBufferSwitchEvent;
    FInputChannelOffset : Word;
    FOutputChannelOffset : Word;
    Fmin, Fmax,
    Fpref, Fgran : Integer;
    FInConvertors : array of TInConvertor;
    FOutConvertors : array of TOutConvertor;

    ASIOdriverlist : TASIODriverList;
    Driver : IOpenASIO;
    BuffersCreated : boolean;
    callbacks : TASIOCallbacks;
    SingleInBuffer : TArrayofSingleArray; // array of PSingleArray;
    SingleOutBuffer : TArrayofSingleArray; // array of PSingleArray;
    UnAlignedBuffer : PASIOBufferInfo;
    InputBuffer : PASIOBufferInfo;
    OutputBuffer : PASIOBufferInfo;
    FInputMonitor : TInputMonitor;
    FConvertOptimizations : TConvertOptimizations;
    procedure SetActive(Value: Boolean);
    procedure SetDriverIndex(Value: Integer);
    function CreateBuffers: Boolean;
    procedure DestroyBuffers;
    procedure BufferSwitch(index: integer);
    procedure BufferSwitchTimeInfo(index: integer; const params: TASIOTime);
    procedure ClipPrevent(const Buffer: TSingleArray; BSize: Integer);
// procedure ClipPrevent(Buffer: PSingleArray; BSize: Integer);
    procedure SetSampleRate(const Value: Double);
    procedure SetDriverName(const s: String);
    procedure SetInputChannelOffset(const w: Word);
    procedure SetOutputChannelOffset(const w: Word);
    procedure SetConvertOptimizations(const co: TConvertOptimizations);
    procedure ReadOnlyCardinal(const i: Cardinal);
    procedure ReadOnlyInteger(const i: Integer);
    procedure ReadOnlyDouble(const d: Double);
  protected
    procedure PMASIO(var Message: TMessage); message PM_ASIO;
    procedure PMUpdateSamplePos(var Message: TMessage); message PM_UpdateSamplePos;
    procedure PMBufferSwitch(var Message: TMessage); message PM_BufferSwitch;
    procedure PMBufferSwitchTimeInfo(var Message: TMessage); message PM_BufferSwitchTimeInfo;
  public
    InputChannelInfos : array of TASIOChannelInfo;
    OutputChannelInfos : array of TASIOChannelInfo;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ControlPanel;
    function GetDriverList: TStrings;
    procedure Reset;
    function GetNumDrivers: integer;
    procedure OpenDriver;
    procedure CloseDriver;
    function CanSampleRate(sampleRate: TASIOSampleRate): TASIOError;
  published
    property Active: Boolean read FActive write SetActive;
    property PreventClipping: Boolean read FPreventClipping write FPreventClipping;
    property PreFillInBuffer: TBufferPreFill read FInBufferPreFill write FInBufferPreFill;
    property PreFillOutBuffer: TBufferPreFill read FOutBufferPreFill write FOutBufferPreFill;
    property DriverName: string read FDriverName write SetDriverName;
    property DriverVersion: integer read FDriverVersion;
    property DriverIndex: Integer read FDriverIndex Write SetDriverIndex default -1;
    property BufferSize: Cardinal read FBufferSize write ReadOnlyCardinal default 0;
    property BufferMinimum: Integer read Fmin write ReadOnlyInteger;
    property BufferMaximum: Integer read Fmax write ReadOnlyInteger;
    property BufferPreferredSize: Integer read Fpref write ReadOnlyInteger;
    property BufferGranularity: Integer read Fgran write ReadOnlyInteger;
    property InputLatency: Integer read FInputLatency write ReadOnlyInteger default 0;
    property InputChannels: Integer read FInputChannels write ReadOnlyInteger default 0;
    property InputChannelOffset : Word read FInputChannelOffset write SetInputChannelOffset default 0;
    property OutputLatency: Integer read FOutputLatency write ReadOnlyInteger default 0;
    property OutputChannels: Integer read FOutputChannels write ReadOnlyInteger default 0;
    property OutputChannelOffset : Word read FOutputChannelOffset write SetOutputChannelOffset default 0;
    property ConvertOptimizations : TConvertOptimizations read FConvertOptimizations write SetConvertOptimizations;
    property SampleRate: Double read FSampleRate write SetSampleRate; //ReadOnlyDouble;
    property ASIOTime: TASIOTimeSub read FASIOTime Write FASIOTime;
    property OnCreate: TNotifyEvent read FOnCreate write FOnCreate;
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
    property OnUpdateSamplePos : TSamplePositionUpdateEvent read FOnUpdateSamplePos write FOnUpdateSamplePos;
    property OnReset : TNotifyEvent read FOnReset write FOnReset;
    property OnDriverChanged : TNotifyEvent read FOnDriverChanged write FOnDriverChanged;
    property OnLatencyChanged : TNotifyEvent read FOnLatencyChanged write FOnLatencyChanged;
    property OnInput2Sample : TSample2Event read FOnInput2Sample write FOnInput2Sample;
    property OnSample2Output : TSample2Event read FOnSample2Output write FOnSample2Output;
    property OnSampleRateChanged : TNotifyEvent read FOnSampleRateChanged write FOnSampleRateChanged;
    property OnBufferSwitch : TBufferSwitchEvent read FOnBufferSwitch write FOnBufferSwitch;
    property InputMonitor : TInputMonitor read FInputMonitor write FInputMonitor default imDisabled;
  end;

var theHost : TASIOHost;
    Handy : HWND;
    PMUpdSamplePos : TMessage;
    PMBufSwitch : TMessage;
    PMBufSwitchTimeInfo : TMessage;

procedure Register;
function ChannelTypeToString(vType: TASIOSampleType): string;

implementation

{$IFNDEF DELPHI5}
uses FastMove;
{$ENDIF}

procedure TASIOHost.ReadOnlyCardinal(const i:Cardinal); begin end;
procedure TASIOHost.ReadOnlyInteger(const i:Integer); begin end;
procedure TASIOHost.ReadOnlyDouble(const d:Double); begin end;

{$IFDEF DELPHI5}
procedure TASIOControlPanel.Edit;
begin
  ExecuteVerb(0);
end;

function TASIOControlPanel.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := 'Control Panel';
  end;
end;

function TASIOControlPanel.GetVerbCount: Integer;
begin
 if (Component as TASIOHost).DriverIndex >= 0
  then Result := 1
  else Result := 0;
end;

procedure TASIOControlPanel.ExecuteVerb(Index: Integer);
begin
 case Index of
  0: if (Component as TASIOHost).DriverIndex >= 0
      then (Component as TASIOHost).ControlPanel;
 end;
end;
{$ENDIF}

constructor TASIOTimeSub.Create;
begin
 FBufferTime.timeInfo.speed := 1;
 FBufferTime.timeInfo.sampleRate := 44100;
 FBufferTime.timeInfo.samplePosition := Int64ToASIOSamples(0);
 Flags:=[atSystemTimeValid, atSamplePositionValid, atSampleRateValid, atSpeedValid];
end;

procedure TASIOTimeSub.Change;
begin
  if Assigned(FOnChange) then FOnChange(Self);
end;

procedure TASIOTimeSub.AssignTo(Dest: TPersistent);
begin
  if Dest is TASIOTimeSub then
    with TASIOTimeSub(Dest) do
    begin
      FBufferTime := Self.FBufferTime;
      Change;
    end
  else inherited AssignTo(Dest);
end;

function TASIOTimeSub.GetATflags :TATFlags;
begin
 result := [];
 if (FBufferTime.timeInfo.flags and kSystemTimeValid) <> 0 then
  result := result + [atSystemTimeValid] else
  result := result - [atSystemTimeValid];
 if (FBufferTime.timeInfo.flags and kSamplePositionValid) <> 0 then
  result := result + [atSamplePositionValid] else
  result := result - [atSamplePositionValid];
 if (FBufferTime.timeInfo.flags and kSampleRateValid) <> 0 then
  result := result + [atSampleRateValid] else
  result := result - [atSampleRateValid];
 if (FBufferTime.timeInfo.flags and kSpeedValid) <> 0 then
  result := result + [atSpeedValid] else
  result := result - [atSpeedValid];
 if (FBufferTime.timeInfo.flags and kSampleRateChanged) <> 0 then
  result := result + [atSampleRateChanged] else
  result := result - [atSampleRateChanged];
 if (FBufferTime.timeInfo.flags and kClockSourceChanged) <> 0 then
  result := result + [atClockSourceChanged] else
  result := result - [atClockSourceChanged];
end;

procedure TASIOTimeSub.SetATflags(Flags:TATFlags);
var temp: Integer;
begin
 temp := 0;
 if (atSystemTimeValid in Flags) then temp:=temp+kSystemTimeValid;
 if (atSamplePositionValid in Flags) then temp:=temp+kSamplePositionValid;
 if (atSampleRateValid in Flags) then temp:=temp+kSampleRateValid;
 if (atSpeedValid in Flags) then temp:=temp+kSpeedValid;
 if (atSampleRateChanged in Flags) then temp:=temp+kSampleRateChanged;
 if (atClockSourceChanged in Flags) then temp:=temp+kClockSourceChanged;
 FBufferTime.timeInfo.flags := temp;
end;

function TASIOTimeSub.GetATdouble(Index :Integer): Double;
begin
 Result := 0;
 case Index of
  0: Result := FBufferTime.timeInfo.speed;
  1: Result := FBufferTime.timeInfo.sampleRate;
 end;
end;

procedure TASIOTimeSub.SetATdouble(Index :Integer; Value: Double);
begin
 case Index of
  0: if Value <> FBufferTime.timeInfo.speed then
  begin
   FBufferTime.timeInfo.speed:=Value;
   Change;
  end;
  1: if Value <> FBufferTime.timeInfo.sampleRate then
  begin
   FBufferTime.timeInfo.sampleRate:=Value;
   Change;
  end;
 end;
end;

function TASIOTimeSub.GetATInt64(Index :Integer): Int64;
begin
 Result := 0;
 case Index of
  0: Result := ASIOSamplesToInt64(FBufferTime.timeInfo.samplePosition);
 end;
end;

procedure TASIOTimeSub.SetATInt64(Index :Integer; Value: Int64);
begin
 case Index of
  0: if Value <> ASIOSamplesToInt64(FBufferTime.timeInfo.samplePosition) then
       begin
        FBufferTime.timeInfo.SamplePosition:=Int64ToASIOSamples(Value);
        Change;
       end;
 end;
end;

function ChannelTypeToString(vType: TASIOSampleType): string;
begin
  Result := '';
  case vType of
    ASIOSTInt16MSB : Result := 'Int16MSB';
    ASIOSTInt24MSB : Result := 'Int24MSB';
    ASIOSTInt32MSB : Result := 'Int32MSB';
    ASIOSTFloat32MSB : Result := 'Float32MSB';
    ASIOSTFloat64MSB : Result := 'Float64MSB';

    // these are used for 32 bit data buffer, with different alignment of the data inside
    // 32 bit PCI bus systems can be more easily used with these
    ASIOSTInt32MSB16 : Result := 'Int32MSB16';
    ASIOSTInt32MSB18 : Result := 'Int32MSB18';
    ASIOSTInt32MSB20 : Result := 'Int32MSB20';
    ASIOSTInt32MSB24 : Result := 'Int32MSB24';

    ASIOSTInt16LSB : Result := 'Int16LSB';
    ASIOSTInt24LSB : Result := 'Int24LSB';
    ASIOSTInt32LSB : Result := 'Int32LSB';
    ASIOSTFloat32LSB : Result := 'Float32LSB';
    ASIOSTFloat64LSB : Result := 'Float64LSB';

    // these are used for 32 bit data buffer, with different alignment of the data inside
    // 32 bit PCI bus systems can more easily used with these
    ASIOSTInt32LSB16 : Result := 'Int32LSB16';
    ASIOSTInt32LSB18 : Result := 'Int32LSB18';
    ASIOSTInt32LSB20 : Result := 'Int32LSB20';
    ASIOSTInt32LSB24 : Result := 'Int32LSB24';
  end;
end;

procedure ASIOBufferSwitch(doubleBufferIndex: longint;
 directProcess: TASIOBool); cdecl;
begin
  directProcess := ASIOFalse;
  case directProcess of
    ASIOFalse :
    begin
     PMBufSwitch.WParam := AM_BufferSwitch;
     PMBufSwitch.LParam := doublebufferindex;
     theHost.Dispatch(PMBufSwitch);
    end;
// PostMessage(Handy, PM_ASIO, AM_BufferSwitch, doubleBufferIndex);
    ASIOTrue : theHost.BufferSwitch(doubleBufferIndex);
  end;
end;

function ASIOBufferSwitchTimeInfo(var params: TASIOTime;
 doubleBufferIndex: longint; directProcess: TASIOBool): PASIOTime; cdecl;
begin
  directProcess := ASIOFalse;
  case directProcess of
    ASIOFalse:
    begin
     theHost.ASIOTime.FBufferTime := params;
     PMBufSwitchTimeInfo.WParam := AM_BufferSwitchTimeInfo;
     PMBufSwitchTimeInfo.LParam := doublebufferindex;
     theHost.Dispatch(PMBufSwitchTimeInfo);
// PostMessage(Handy, PM_ASIO, AM_BufferSwitchTimeInfo, doubleBufferIndex);
      end;
    ASIOTrue: theHost.BufferSwitchTimeInfo(doubleBufferIndex, params);
  end;
  Result := nil;
end;

procedure ASIOSampleRateDidChange(sRate: TASIOSampleRate); cdecl;
begin
 if Assigned(theHost.FOnSampleRateChanged) then
  theHost.FOnSampleRateChanged(theHost);
end;

function ASIOMessage(selector, value: longint;
 message: pointer; opt: pdouble): longint; cdecl;
begin
  Result := 0;
  case selector of
    kASIOSelectorSupported : // return 1 if a selector is supported
      begin
        case value of
          kASIOEngineVersion : Result := 1;
          kASIOResetRequest : Result := 1;
          kASIOBufferSizeChange : Result := 0;
          kASIOResyncRequest : Result := 1;
          kASIOLatenciesChanged : Result := 1;
          kASIOSupportsTimeInfo : Result := 1;
          kASIOSupportsTimeCode : Result := 1;
          kASIOSupportsInputMonitor : Result := 0;
        end;
      end;
    kASIOEngineVersion : Result := 2; // ASIO 2 is supported
    kASIOResetRequest :
      begin
        PostMessage(Handy, PM_ASIO, AM_ResetRequest, 0);
        Result := 1;
      end;
    kASIOBufferSizeChange :
      begin
        PostMessage(Handy, PM_ASIO, AM_ResetRequest, 0);
        Result := 1;
      end;
    kASIOResyncRequest : ;
    kASIOLatenciesChanged :
      begin
        PostMessage(Handy, PM_ASIO, AM_LatencyChanged, 0);
        Result := 1;
      end;
    kASIOSupportsTimeInfo : Result := 1;
    kASIOSupportsTimeCode : Result := 0;
    kASIOSupportsInputMonitor : Result := 0;
  end;
end;

constructor TASIOHost.Create(AOwner: TComponent);
begin
// ValidParentForm(AOwner).Handle
  if AOwner is TForm
   then Handy := TForm(AOwner).Handle
   else Handy := Application.Handle;
  theHost := Self;
  UnAlignedBuffer:=nil;
  InputBuffer := nil;
  OutputBuffer := nil;
  ASIOTime := TASIOTimeSub.Create;
  FDriverList := GetDriverList;
  FConvertOptimizations:=[coSSE,co3DNow];

  // set the callbacks record fields
  callbacks.bufferSwitch := ASIOBufferSwitch;
  callbacks.sampleRateDidChange := ASIOSampleRateDidChange;
  callbacks.ASIOMessage := ASIOMessage;
  callbacks.bufferSwitchTimeInfo := ASIOBufferSwitchTimeInfo;

  // set the driver itself to nil for now
  Driver := nil;
  BuffersCreated := FALSE;

  // and make sure all controls are enabled or disabled
  FDriverIndex := -1;
  FInputMonitor := imDisabled;

  inherited;
  if Assigned(FOnCreate) then FOnCreate(Self);
end;

destructor TASIOHost.Destroy;
begin
//x FOnBufferSwitch := nil;
 callbacks.bufferSwitchTimeInfo := nil;
 if Active then Active := False;
 CloseDriver;
 SetLength(ASIOdriverlist, 0);
 FDriverList.Free;
 ASIOTime.Free;
 inherited;
 if Assigned(FOnDestroy) then FOnDestroy(Self);
end;

////////////////////////////////////////////////////////////////////////////////

function TASIOHost.GetDriverList: TStrings;
var i : Integer;
begin
 Result := TStringList.Create;
 SetLength(ASIOdriverlist, 0);
 ListASIODrivers(ASIOdriverlist);
 for i := Low(ASIOdriverlist) to High(ASIOdriverlist) do
  Result.Add(ASIOdriverlist[i].name);
end;

procedure TASIOHost.SetDriverName(const s:String);
begin
 if FDriverList.IndexOf(s) > -1
  then DriverIndex := FDriverList.IndexOf(s);
end;

procedure TASIOHost.SetInputChannelOffset(const w: Word);
begin
 if (w <> FInputChannelOffset) and (w < FInputChannels)
  then FInputChannelOffset := w;
end;

procedure TASIOHost.SetOutputChannelOffset(const w: Word);
begin
 if (w <> FOutputChannelOffset) and (w < FOutputChannels)
  then FOutputChannelOffset := w;
end;

procedure TASIOHost.SetConvertOptimizations(const co: TConvertOptimizations);
begin
 Use_x87;
 case FPUType of
  fpuSSE: begin
             if coSSE in co then Use_SSE;
            end;
  fpu3DNow: begin
             if co3DNow in co then Use_3DNow;
            end;
 end;
 FConvertOptimizations:=co;
end;

procedure TASIOHost.SetDriverIndex(Value : Integer);
var DrName: array[0..255] of Char;
begin
 if (Value <> FDriverIndex) then
  begin
   if Value < -1 then FDriverIndex := -1 else
   if Value >= FDriverList.Count then FDriverIndex := FDriverList.Count - 1
    else FDriverIndex := Value;
{  if Value < -1 then Value := 0 else
  if Value >= FDriverList.Count then Value := 0
    else FDriverIndex := Value;}

   if FDriverIndex = -1 then
     begin
      FDriverName := '';
      FInputLatency := 0;
      FOutputLatency := 0;
      FInputChannels := 0;
      FOutputChannels := 0;
      FBufferSize := 0;
      CloseDriver;
     end
    else
     begin
      CloseDriver;
      FDriverName := FDriverList[FDriverIndex];
      OpenDriver;
      if Driver <> nil then
      begin
       Driver.GetDriverName(DrName);
       FDriverVersion := Driver.GetDriverVersion;
      end;
     end;
   if assigned(fOnDriverChanged) then OnDriverChanged(self);
  end;
end;

function TASIOHost.CreateBuffers: Boolean;
var i : integer;
    currentbuffer: PASIOBufferInfo;
begin
 if Driver = nil then
 begin
  result := false;
  Exit;
 end;
 if BuffersCreated then DestroyBuffers;
 Driver.GetBufferSize(Fmin, Fmax, Fpref, Fgran);
 if Fmin = Fmax then Fpref := Fmin;
 FBufferSize := Fpref;
 Driver.GetSampleRate(FSampleRate);
 SetSampleRate(FSampleRate);
 Driver.GetChannels(FInputChannels, FOutputChannels);
 GetMem(UnAlignedBuffer, SizeOf(TAsioBufferInfo) * (FInputChannels + FOutputChannels)+16);
 InputBuffer := Ptr(Integer(UnAlignedBuffer)+16-(Integer(UnAlignedBuffer) mod 16));

 SetLength(InputChannelInfos, FInputChannels);
 SetLength(SingleInBuffer, FInputChannels);
 SetLength(FInConvertors, FInputChannels);
 currentbuffer := InputBuffer;
 for i := 0 to FInputChannels - 1 do
  begin
   InputChannelInfos[i].channel := i;
   InputChannelInfos[i].isInput := ASIOTrue;
   Driver.GetChannelInfo(InputChannelInfos[i]);
    case InputChannelInfos[i].vType of
     ASIOSTInt16MSB: FInConvertors[i]:=ToInt16MSB;
     ASIOSTInt24MSB: FInConvertors[i]:=ToInt24MSB;
     ASIOSTInt32MSB: FInConvertors[i]:=ToInt32MSB;
     ASIOSTFloat32MSB: FInConvertors[i]:=ToFloat32MSB;
     ASIOSTFloat64MSB: FInConvertors[i]:=ToFloat64MSB;
     ASIOSTInt32MSB16: FInConvertors[i]:=ToInt32MSB16;
     ASIOSTInt32MSB18: FInConvertors[i]:=ToInt32MSB18;
     ASIOSTInt32MSB20: FInConvertors[i]:=ToInt32MSB20;
     ASIOSTInt32MSB24: FInConvertors[i]:=ToInt32MSB24;
     ASIOSTInt16LSB: FInConvertors[i]:=ToInt16LSB;
     ASIOSTInt24LSB: FInConvertors[i]:=ToInt24LSB;
     ASIOSTInt32LSB: FInConvertors[i]:=ToInt32LSB;
     ASIOSTFloat32LSB: FInConvertors[i]:=ToFloat32LSB;
     ASIOSTFloat64LSB: FInConvertors[i]:=ToFloat64LSB;
     ASIOSTInt32LSB16: FInConvertors[i]:=ToInt32LSB16;
     ASIOSTInt32LSB18: FInConvertors[i]:=ToInt32LSB18;
     ASIOSTInt32LSB20: FInConvertors[i]:=ToInt32LSB20;
     ASIOSTInt32LSB24: FInConvertors[i]:=ToInt32LSB24;
    end;

   SetLength(SingleInBuffer[i], BufferSize * SizeOf(Single));
   FillChar(SingleInBuffer[i][0], BufferSize * SizeOf(Single), 0);
   currentbuffer^.isInput := ASIOTrue;
   currentbuffer^.channelNum := i;
   currentbuffer^.buffers[0] := nil;
   currentbuffer^.buffers[1] := nil;
   inc(currentbuffer);
  end;

 OutputBuffer := currentbuffer;
 SetLength(OutputChannelInfos, FOutputChannels);
 SetLength(SingleOutBuffer, FOutputChannels);
 SetLength(FOutConvertors, FOutputChannels);
 for i := 0 to FOutputChannels - 1 do
  begin
   OutputChannelInfos[i].channel := i;
   OutputChannelInfos[i].isInput := ASIOFalse; // output
   Driver.GetChannelInfo(OutputChannelInfos[i]);
   case OutputChannelInfos[i].vType of
    ASIOSTInt16MSB: FOutConvertors[i]:=FromInt16MSB;
    ASIOSTInt24MSB: FOutConvertors[i]:=FromInt24MSB;
    ASIOSTInt32MSB: FOutConvertors[i]:=FromInt32MSB;
    ASIOSTFloat32MSB: FOutConvertors[i]:=FromFloat32MSB;
    ASIOSTFloat64MSB: FOutConvertors[i]:=FromFloat64MSB;
    ASIOSTInt32MSB16: FOutConvertors[i]:=FromInt32MSB16;
    ASIOSTInt32MSB18: FOutConvertors[i]:=FromInt32MSB18;
    ASIOSTInt32MSB20: FOutConvertors[i]:=FromInt32MSB20;
    ASIOSTInt32MSB24: FOutConvertors[i]:=FromInt32MSB24;
    ASIOSTInt16LSB: FOutConvertors[i]:=FromInt16LSB;
    ASIOSTInt24LSB: FOutConvertors[i]:=FromInt24LSB;
    ASIOSTInt32LSB: FOutConvertors[i]:=FromInt32LSB;
    ASIOSTFloat32LSB: FOutConvertors[i]:=FromFloat32LSB;
    ASIOSTFloat64LSB: FOutConvertors[i]:=FromFloat64LSB;
    ASIOSTInt32LSB16: FOutConvertors[i]:=FromInt32LSB16;
    ASIOSTInt32LSB18: FOutConvertors[i]:=FromInt32LSB18;
    ASIOSTInt32LSB20: FOutConvertors[i]:=FromInt32LSB20;
    ASIOSTInt32LSB24: FOutConvertors[i]:=FromInt32LSB24;
   end;
   SetLength(SingleOutBuffer[i], BufferSize * SizeOf(Single));
   FillChar(SingleOutBuffer[i][0], BufferSize * SizeOf(Single), 0);
   currentbuffer^.isInput := ASIOfalse; // create an output buffer
   currentbuffer^.channelNum := i;
   currentbuffer^.buffers[0] := nil;
   currentbuffer^.buffers[1] := nil;
   inc(currentbuffer);
  end;

 result := (Driver.CreateBuffers(InputBuffer,
  (FInputChannels + FOutputChannels), Fpref, callbacks) = ASE_OK);
 Driver.GetLatencies(FInputLatency, FOutputLatency);
 if Assigned (FOnLatencyChanged) then FOnLatencyChanged(Self);
 Randomize;
end;

procedure TASIOHost.DestroyBuffers;
var b: Byte;
begin
 if (Driver = nil) then Exit;
 if BuffersCreated then
  begin
   FreeMem(UnAlignedBuffer);
   UnAlignedBuffer:=nil;
   InputBuffer := nil;
   OutputBuffer := nil;
   Driver.DisposeBuffers;
   for b := 0 to FInputChannels - 1 do SetLength(SingleInBuffer[b], 0);
   for b := 0 to FOutputChannels - 1 do SetLength(SingleOutBuffer[b], 0);
   BuffersCreated := FALSE;
   SetLength(SingleInBuffer, 0);
   SetLength(SingleOutBuffer, 0);
   SetLength(InputChannelInfos, 0);
   SetLength(OutputChannelInfos, 0);
  end;
end;

procedure TASIOHost.OpenDriver;
begin
 if Driver <> nil then CloseDriver;
 if FDriverIndex >= 0 then
 begin
  if OpenASIOCreate(ASIOdriverlist[FDriverIndex].id, Driver) then
   begin
    if (Driver <> nil) then
     if not Succeeded(Driver.Init(Handy))
      then Driver := nil; // RELEASE
   end;
 end;
 if Driver = nil then raise Exception.Create('ASIO Driver Failed!');
 CreateBuffers;
end;

procedure TASIOHost.CloseDriver;
begin
 if Driver <> nil then
 begin
  if BuffersCreated then DestroyBuffers;
  Driver := nil; // RELEASE;
 end;
 FInputLatency := -1;
 FOutputLatency := -1;
 FInputChannels := 0;
 FOutputChannels := 0;
 FSampleRate := 0;
end;

procedure TASIOHost.ControlPanel;
begin
 if Driver <> nil then Driver.ControlPanel;
end;

procedure TASIOHost.Reset;
begin
 OpenDriver; // restart the driver
 if Assigned (FOnReset) then FOnReset(Self);
end;

procedure TASIOHost.PMASIO(var Message: TMessage);
var inp, outp: integer;
begin
 case Message.WParam of
  AM_ResetRequest:
   begin
    OpenDriver; // restart the driver
    if Assigned (FOnReset) then FOnReset(Self);
   end;
  AM_BufferSwitch: BufferSwitch(Message.LParam); // process a buffer
  AM_BufferSwitchTimeInfo: BufferSwitchTimeInfo(Message.LParam,
   ASIOTime.FBufferTime); // process a buffer with time
  AM_LatencyChanged:
   begin
    if (Driver <> nil) then Driver.GetLatencies(inp, outp);
    if Assigned (FOnLatencyChanged) then FOnLatencyChanged(Self);
   end;
 end;
end;

procedure TASIOHost.PMUpdateSamplePos(var Message: TMessage);
var Samples: TASIOSamples;
begin
 Samples.hi := Message.wParam;
 Samples.lo := Message.LParam;
 if Assigned(FOnUpdateSamplePos)
  then FOnUpdateSamplePos(Self,ASIOSamplesToInt64(Samples));
end;

procedure TASIOHost.BufferSwitch(index: integer);
begin
 if Driver = nil then exit;
 FillChar(ASIOTime.FBufferTime, SizeOf(TASIOTime), 0);
 // get the time stamp of the buffer, not necessary if no
 // synchronization to other media is required
 if Driver.GetSamplePosition(ASIOTime.FBufferTime.timeInfo.samplePosition,
  ASIOTime.FBufferTime.timeInfo.systemTime) = ASE_OK then
   ASIOTime.Flags := ASIOTime.Flags + [atSystemTimeValid,atSamplePositionValid];
 BufferSwitchTimeInfo(index, ASIOTime.FBufferTime);
end;

procedure TASIOHost.ClipPrevent(const Buffer: TSingleArray; BSize: Integer);
var i : Integer;
// x1, x2 : single;
begin
 for i := 0 to BSize - 1 do
  begin
{
  x1 := f_abs(Buffer^[i] + 1);
  x2 := f_abs(Buffer^[i] - 1);
  Buffer^[i] := 0.5 * (x1 - x2);
}

   if Buffer[i] > 1 then Buffer[i] := 1
   else if Buffer[i] < -1 then Buffer[i] := -1;
  end;
end;

procedure TASIOHost.BufferSwitchTimeInfo(index: integer;
 const params: TASIOTime);
var i, j : Integer;
    currentbuffer : PASIOBufferInfo;
    PChannelArray : Pointer;
begin
 PMUpdSamplePos.wParam := params.timeInfo.samplePosition.hi;
 PMUpdSamplePos.LParam := params.timeInfo.samplePosition.lo;
 Dispatch(PMUpdSamplePos);

 currentbuffer := InputBuffer;
 for j := 0 to FInputChannels - 1 do
 begin
  if FInBufferPreFill = bpfZero then
   FillChar(SingleInBuffer[j][0], BufferSize * SizeOf(Single), 0)
  else if FInBufferPreFill = bpfNoise then
   for i := 0 to BufferSize - 1 do
    SingleInBuffer[j][i] := 2 * Random - 1
  else begin
   PChannelArray := currentbuffer^.buffers[Index];
   if Assigned(PChannelArray)
    then FInConvertors[j](PChannelArray, PSingle(SingleInBuffer[j]), BufferSize);
   inc(currentbuffer);
  end;
 end;

 if PreventClipping then
  for j := 0 to FInputChannels - 1 do ClipPrevent(SingleInBuffer[j], BufferSize);

 for j := 0 to FOutputChannels - 1 do
  begin
   case FOutBufferPreFill of
    bpfZero: FillChar(SingleOutBuffer[j][0], BufferSize * SizeOf(Single), 0);
    bpfNoise: for i := 0 to BufferSize - 1 do SingleOutBuffer[j][i] := 2 * Random - 1;
   end;
  end;

 case FInputMonitor of
  imMono:
   Move(SingleInBuffer[FInputChannelOffset][0], SingleOutBuffer[FOutputChannelOffset][0], BufferSize * SizeOf(Single));
  imStereo:
   for j := 0 to 1 do
    Move(SingleInBuffer[FInputChannelOffset + j][0], SingleOutBuffer[FOutputChannelOffset + j][0], BufferSize * SizeOf(Single));
  imAll:
   for j := 0 to min(FInputChannels, FOutputChannels) - 1 do
    Move(SingleInBuffer[j][0], SingleOutBuffer[j][0], BufferSize * SizeOf(Single));
 end;

 if Assigned(FOnBufferSwitch) then
  FOnBufferSwitch(Self, SingleInBuffer, SingleOutBuffer);

 if PreventClipping then
 for j := 0 to FOutputChannels - 1 do ClipPrevent(SingleOutBuffer[j] ,BufferSize);

 currentbuffer := OutputBuffer;
 for j := 0 to FOutputChannels - 1 do
 begin
  PChannelArray := currentbuffer^.buffers[Index];
  if assigned(PChannelArray)
   then FOutConvertors[j](PSingle(SingleOutBuffer[j]),PChannelArray, BufferSize);
  inc(currentbuffer);
 end;
 if Driver <> nil then Driver.OutputReady;
end;

procedure TASIOHost.SetSampleRate(const Value: Double);
begin
 FSampleRate := Value;
 ASIOTime.SampleRate := Value;
 if Driver <> nil then Driver.SetSampleRate(Value);
end;

procedure TASIOHost.SetActive(Value: Boolean);
var currentbuffer : PASIOBufferInfo;
    i : Integer;
begin
 if Driver = nil then exit;
 if FActive = Value then exit;
 if Value = True then
  begin
   FActive := (Driver.Start = ASE_OK);
   if FActive = False then
    raise Exception.Create('ERROR: Could not start ASIO driver!');
  end
 else
  begin
   FActive := False;
   Driver.Stop;
   if bufferscreated then
   begin
    currentbuffer := OutputBuffer;
    for i := 0 to FOutputChannels - 1 do
     begin
      FillChar(currentbuffer^.buffers[0]^, BufferSize * 8, 0);
      inc(currentbuffer);
     end;
   end;
 end;
end;

procedure Register;
begin
  RegisterComponents('Audio', [TASIOHost]);
  {$IFDEF DELPHI5}
  RegisterComponentEditor(TASIOHost,TASIOControlPanel);
  {$ENDIF}
end;

function TASIOHost.GetNumDrivers: integer;
begin
 result := length(ASIOdriverlist);
end;

function TASIOHost.CanSampleRate(sampleRate: TASIOSampleRate): TASIOError;
begin
 if Driver <> nil then
  result := Driver.CanSampleRate(sampleRate)
 else
  result := ASE_NotPresent;
end;

procedure TASIOHost.PMBufferSwitch(var Message: TMessage);
begin
 BufferSwitch(Message.LParam);
end;

procedure TASIOHost.PMBufferSwitchTimeInfo(var Message: TMessage);
begin
 BufferSwitchTimeInfo(Message.LParam, ASIOTime.FBufferTime);
end;

initialization

PMUpdSamplePos.Msg := PM_UpdateSamplePos;
PMBufSwitch.Msg := PM_BufferSwitch;
PMBufSwitchTimeInfo.Msg := PM_BufferSwitchTimeInfo;

end.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:47 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz