|
Antwort |
BloodySmartie
(Gast)
n/a Beiträge |
#1
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. |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |