Стартовый пул
This commit is contained in:
834
acs/Src/classes/acs_audio.pas
Normal file
834
acs/Src/classes/acs_audio.pas
Normal file
@@ -0,0 +1,834 @@
|
||||
(*
|
||||
this file is a part of audio components suite
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
|
||||
$Log: acs_audio.pas,v $
|
||||
Revision 1.12 2006/07/07 15:51:19 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.11 2006/07/04 18:38:32 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.10 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.4 2006/01/02 18:54:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2006/01/01 18:46:40 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/26 17:31:38 z0m3ie
|
||||
fixed some problems in acs_dsfiles
|
||||
fixed some problems in acs_vorbis
|
||||
reworked all buffers
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.14 2005/12/18 17:01:54 z0m3ie
|
||||
delphi compatibility
|
||||
|
||||
Revision 1.13 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.12 2005/11/28 21:57:24 z0m3ie
|
||||
mostly FileOut fixes
|
||||
moved PBuffer to PBuffer8
|
||||
set all to dynamically Buffering
|
||||
|
||||
Revision 1.11 2005/11/27 16:50:33 z0m3ie
|
||||
add ACS VolumeQuerry
|
||||
make ACS_VolumeQuerry localizeable
|
||||
some little errorfixes (buffersize for linuxdrivers was initially 0)
|
||||
make TAudioIn workable
|
||||
|
||||
Revision 1.10 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.9 2005/09/23 14:04:58 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.8 2005/09/18 19:28:59 z0m3ie
|
||||
more progress on driver handling
|
||||
|
||||
Revision 1.7 2005/09/16 17:34:29 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.6 2005/09/15 20:59:37 z0m3ie
|
||||
start translate the documentation in the source for pasdoc
|
||||
|
||||
Revision 1.5 2005/09/14 21:19:37 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.3 2005/09/13 20:14:52 z0m3ie
|
||||
driver handling classes (basic audio class)
|
||||
*)
|
||||
|
||||
{
|
||||
@abstract(this unit introduces the base classes for acs)
|
||||
@author(Andrei Borovsky (2003-2005))
|
||||
@author(Christian Ulrich (2005))
|
||||
}
|
||||
|
||||
unit acs_audio;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
ACS_Types, ACS_Classes,Classes,ACS_Strings,SysUtils;
|
||||
|
||||
type
|
||||
{ Audio Formats used in DeviceInfo record
|
||||
format constants mask : af<SampleRate><Mono/Stereo><BitsPerSample>
|
||||
where 1, 2, 4 means sample rate of 11025, 22050, and 44100 Hz respectively
|
||||
M, S means mono or stereo, 08, 16 means 8 or 16 bits per sample.
|
||||
For example, af4S16 corresponds to 44100 Hz stereo 16 bit format.
|
||||
}
|
||||
|
||||
TACSAudioFormat = (af1M08, af1M16, af1S08, af1S16, af2M08, af2M16, af2S08, af2S16,
|
||||
af4M08, af4M16, af4S08, af4S16);
|
||||
TACSAudioFormats = set of TACSAudioFormat;
|
||||
TACSBaseAudioOut = class;
|
||||
TACSBaseAudioIn = class;
|
||||
|
||||
{ This record is used to get an deviceinfo from the Drivers
|
||||
}
|
||||
TACSDeviceInfo = record
|
||||
DeviceName : String;
|
||||
DrvVersion : LongWord;
|
||||
Formats : TACSAudioFormats;
|
||||
Stereo : Boolean;
|
||||
end;
|
||||
|
||||
{ This introduces an base class for the drivers
|
||||
}
|
||||
|
||||
{ TAudioOut }
|
||||
|
||||
{ TACSAudioOut }
|
||||
|
||||
TACSAudioOut = class(TComponent)
|
||||
private
|
||||
FDriver: string;
|
||||
FOutput : TACSBaseAudioOut;
|
||||
FInput : TACSCustomInput;
|
||||
FOnDone: TACSOutputDoneEvent;
|
||||
FOnProgress: TACSOutputProgressEvent;
|
||||
FOnThreadException: TACSThreadExceptionEvent;
|
||||
FLatency : Integer;
|
||||
FBufferSize : Integer;
|
||||
function GetBufferSize: Integer;
|
||||
function GetBusy: Boolean;
|
||||
function GetDelay: Integer;
|
||||
function GetPriority: TTPriority;
|
||||
function GetProgress: real;
|
||||
function GetStatus: TACSOutputStatus;
|
||||
function GetSuspend: Boolean;
|
||||
function GetTE: Integer;
|
||||
procedure SetBufferSize(const AValue: Integer);
|
||||
procedure SetDelay(const AValue: Integer);
|
||||
procedure SetPriority(const AValue: TTPriority);
|
||||
procedure SetSuspend(const AValue: Boolean);
|
||||
|
||||
procedure ThreadException(Sender : TComponent;E : Exception);
|
||||
procedure OutputDone(Sender : TComponent);
|
||||
procedure OutputProgress(Sender : TComponent);
|
||||
protected
|
||||
FBaseChannel: Integer;
|
||||
FVolume: Byte;
|
||||
|
||||
procedure SetInput(Input : TACSCustomInput);
|
||||
|
||||
procedure SetDevice(Ch : Integer);virtual;
|
||||
function GetDeviceInfo : TACSDeviceInfo;virtual;
|
||||
function GetDeviceCount : Integer;virtual;
|
||||
procedure SetDriver(Driver : string);virtual;
|
||||
|
||||
function GetDriverName(idx : Integer) : string;
|
||||
function GetDriversCount : Integer;
|
||||
|
||||
procedure Done;
|
||||
function DoOutput(Abort : Boolean):Boolean;
|
||||
procedure Prepare;
|
||||
public
|
||||
constructor Create(AOwner: TComponent);override;
|
||||
destructor Destroy;override;
|
||||
{ The result returns an deviceinfo record that can be used to enumerate devices
|
||||
just set device property from 0 to DeviceCount-1 and read deviceInfo to
|
||||
enumerate all Devices from current Driver
|
||||
}
|
||||
property DeviceInfo : TACSDeviceInfo read GetDeviceInfo;
|
||||
{ Returns the count of devices supported by actual driver
|
||||
}
|
||||
property DeviceCount : Integer read GetDeviceCount;
|
||||
{ This can be used to enumerate the Drivers
|
||||
just use Driverscount as index it returns the DriverName
|
||||
}
|
||||
property Drivers[idx : Integer] : string read GetDriverName;
|
||||
{ Returns the total count of avalible drivers
|
||||
}
|
||||
property DriversCount : Integer read GetDriversCount;
|
||||
{ pauses the output.
|
||||
}
|
||||
procedure Pause;virtual;
|
||||
{ Resumes previously paused output.
|
||||
}
|
||||
procedure Resume;virtual;
|
||||
{ This is the most important method in the output components.
|
||||
After an input component has been assigned, call Run to start audio-processing chain.
|
||||
}
|
||||
procedure Run;
|
||||
{ Stops the running output process.
|
||||
}
|
||||
procedure Stop;
|
||||
{ Output components perform output in their own threads.
|
||||
Use this property to set the priority for the thread.
|
||||
}
|
||||
property ThreadPriority : TTPriority read GetPriority write SetPriority;
|
||||
{ Read Progress to get the output progress in percents.
|
||||
This value is meaningful only after the input component has been set
|
||||
and only if the input component can tell the size of its stream.
|
||||
}
|
||||
property Progress : real read GetProgress;
|
||||
{ This property indicates the output component's current status. Possible values are:
|
||||
|
||||
tosPlaying: the component is working;
|
||||
|
||||
tosPaused: the component is paused (the Pause method was called);
|
||||
|
||||
tosIdle: the component is idle;
|
||||
}
|
||||
property Status : TACSOutputStatus read GetStatus;
|
||||
property TimeElapsed : Integer read GetTE;
|
||||
property Latency : Integer read FLatency;
|
||||
published
|
||||
{ The output buffer size in bytes default is 4000
|
||||
}
|
||||
property Buffersize : Integer read GetBufferSize write SetBufferSize;
|
||||
{ use this property to set an driver, on create of this component the driver
|
||||
with lowest latency is used for default
|
||||
}
|
||||
property Driver : string read FDriver write SetDriver stored True;
|
||||
{ Use this property to set the output device
|
||||
}
|
||||
property Busy : Boolean read GetBusy;
|
||||
property Device : Integer read FBaseChannel write SetDevice stored True;
|
||||
property Volume : Byte read FVolume write FVolume;
|
||||
property Input : TACSCustomInput read FInput write SetInput;
|
||||
{ Use this property to set the delay (in milliseconds) in output thread.
|
||||
This property allows the user to reduce the stress the output thread puts
|
||||
on the CPU (especially under Windows).
|
||||
Be careful with this property when using TAudioOut component.
|
||||
Assigning too large values to it can cause dropouts in audio playback.
|
||||
}
|
||||
property Delay : Integer read GetDelay write SetDelay;
|
||||
property SuspendWhenIdle : Boolean read GetSuspend write SetSuspend;
|
||||
property OnDone : TACSOutputDoneEvent read FOnDone write FOndone;
|
||||
property OnProgress : TACSOutputProgressEvent read FOnProgress write FOnProgress;
|
||||
property OnThreadException : TACSThreadExceptionEvent read FOnThreadException write FOnThreadException;
|
||||
end;
|
||||
|
||||
{ TAudioIn }
|
||||
|
||||
TACSAudioIn = class(TACSCustomInput)
|
||||
private
|
||||
FInput : TACSBaseAudioIn;
|
||||
FDriver : string;
|
||||
function GetBPS : Integer;override;
|
||||
function GetCh : Integer;override;
|
||||
function GetSR : Integer;override;
|
||||
procedure SetDevice(Ch : Integer);
|
||||
function GetDeviceInfo : TACSDeviceInfo;
|
||||
function GetTotalTime : real;override;
|
||||
function GetDriverName(idx : Integer) : string;
|
||||
function GetDriversCount : Integer;
|
||||
procedure SetDriver(Driver : string);
|
||||
protected
|
||||
FBPS: Integer;
|
||||
FChan: Integer;
|
||||
FFreq: Integer;
|
||||
FRecTime: Integer;
|
||||
FBaseChannel: Integer;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer;override;
|
||||
procedure Init;override;
|
||||
procedure Flush;override;
|
||||
{ The result returns an deviceinfo record that can be used to enumerate devices
|
||||
just set device property from 0 to DeviceCount-1 and read deviceInfo to
|
||||
enumerate all Devices from current Driver
|
||||
}
|
||||
property DeviceInfo : TACSDeviceInfo read GetDeviceInfo;
|
||||
{ This can be used to enumerate the Drivers
|
||||
just use Driverscount as index it returns the DriverName
|
||||
}
|
||||
property Drivers[idx : Integer] : string read GetDriverName;
|
||||
{ Returns the total count of avalible drivers
|
||||
}
|
||||
property DriversCount : Integer read GetDriversCount;
|
||||
published
|
||||
{ use this property to set an driver, on create of this component the driver
|
||||
with lowest latency is used for default
|
||||
}
|
||||
property Driver : string read FDriver write SetDriver stored True;
|
||||
{ Use this property to set the output device
|
||||
}
|
||||
property Device : Integer read FBaseChannel write SetDevice stored True;
|
||||
{ Use this property to set the number of bits per sample for the input audio stream.
|
||||
Possible values are 8 and 16.
|
||||
}
|
||||
property InBitsPerSample : Integer read GetBPS write FBPS stored True;
|
||||
{ Use this property to set the number of channels for the input audio stream.
|
||||
Possible values are 1 (mono) and 2 (stereo).
|
||||
}
|
||||
property InChannels : Integer read GetCh write FChan stored True;
|
||||
{ Use this property to set the sample rate for the input audio stream.
|
||||
Possible values are determined by the soundcard hardware.
|
||||
}
|
||||
property InSampleRate : Integer read GetSR write FFreq stored True;
|
||||
{ This property allow you to set the record duration time in seconds.
|
||||
If you assign -1 to this property TAudioIn will never stop recording by itself.
|
||||
In both cases you can stop recording at any time by calling Stop method of
|
||||
the respective output component.
|
||||
}
|
||||
property RecTime : Integer read FRecTime write FRecTime stored True;
|
||||
end;
|
||||
|
||||
{ This class is an abstract base class for the drivers
|
||||
}
|
||||
|
||||
{ TBaseAudioOut }
|
||||
|
||||
TACSBaseAudioOut = class(TACSCustomOutput)
|
||||
private
|
||||
FDriver: string;
|
||||
FOutput : TACSAudioOut;
|
||||
protected
|
||||
FBaseChannel: Integer;
|
||||
FVolume: Byte;
|
||||
procedure SetDevice(Ch : Integer);virtual;abstract;
|
||||
function GetDeviceInfo : TACSDeviceInfo;virtual;abstract;
|
||||
function GetDeviceCount : Integer;virtual;abstract;
|
||||
public
|
||||
constructor Create(AOwner: TComponent);override;
|
||||
destructor Destroy;override;
|
||||
property DeviceInfo : TACSDeviceInfo read GetDeviceInfo;
|
||||
property DeviceCount : Integer read GetDeviceCount;
|
||||
property Buffersize : Integer read FBufferSize write FBufferSize;
|
||||
published
|
||||
property Device : Integer read FBaseChannel write SetDevice stored True;
|
||||
property Volume : Byte read FVolume write FVolume;
|
||||
end;
|
||||
|
||||
{ This class is an abstract base class for the drivers
|
||||
}
|
||||
|
||||
{ TBaseAudioIn }
|
||||
|
||||
TACSBaseAudioIn = class(TACSCustomInput)
|
||||
private
|
||||
FInput : TACSAudioIn;
|
||||
FDriver : string;
|
||||
protected
|
||||
FBPS: Integer;
|
||||
FChan: Integer;
|
||||
FFreq: Integer;
|
||||
FRecTime: Integer;
|
||||
FBaseChannel: Integer;
|
||||
procedure SetDevice(Ch : Integer);virtual;abstract;
|
||||
function GetDeviceInfo : TACSDeviceInfo;virtual;abstract;
|
||||
function GetDeviceCount : Integer;virtual;abstract;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
property DeviceInfo : TACSDeviceInfo read GetDeviceInfo;
|
||||
published
|
||||
property Device : Integer read FBaseChannel write SetDevice stored True;
|
||||
property InBitsPerSample : Integer read GetBPS write FBPS stored True;
|
||||
property InChannels : Integer read GetCh write FChan stored True;
|
||||
property InSampleRate : Integer read GetSR write FFreq stored True;
|
||||
property RecTime : Integer read FRecTime write FRecTime stored True;
|
||||
end;
|
||||
|
||||
TACSAudioOutClass = class of TACSBaseAudioOut;
|
||||
TACSAudioInClass = class of TACSBaseAudioIn;
|
||||
|
||||
TACSOutDriverinfo = record
|
||||
DriverName : string;
|
||||
Latency : Integer;
|
||||
DrvClass : TACSAudioOutClass;
|
||||
end;
|
||||
|
||||
TACSInDriverinfo = record
|
||||
DriverName : string;
|
||||
Latency : Integer;
|
||||
DrvClass : TACSAudioInClass;
|
||||
end;
|
||||
|
||||
{ This procedure must be used to register drivers to the system
|
||||
just call them at initialization of the driver main unit
|
||||
}
|
||||
procedure RegisterAudioOut(DrvName : string;OutClass : TACSAudioOutClass;Latency : Integer);
|
||||
{ This procedure must be used to register drivers to the system
|
||||
just call them at initialization of the driver main unit
|
||||
}
|
||||
procedure RegisterAudioIn(DrvName : string;InClass : TACSAudioInClass;Latency : Integer);
|
||||
|
||||
var
|
||||
OutDriverInfos : array of TACSOutDriverInfo;
|
||||
InDriverInfos : array of TACSInDriverInfo;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TAudioOut }
|
||||
|
||||
function TACSAudioOut.GetDelay: Integer;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
Result := FOutput.GetDelay
|
||||
else
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetBufferSize: Integer;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
Result := FOutput.BufferSize
|
||||
else
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetBusy: Boolean;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
Result := FOutput.Busy;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetPriority: TTPriority;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException(strNoDriverselected);
|
||||
Result := FOutput.GetPriority;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetProgress: real;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FOutput.GetProgress;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetStatus: TACSOutputStatus;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
Result := tosUndefined
|
||||
else
|
||||
Result := FOutput.Status;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetSuspend: Boolean;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
Result := FOutput.GetSuspend;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetTE: Integer;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FOutput.GetTE;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetBufferSize(const AValue: Integer);
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.BufferSize := AValue;
|
||||
FBufferSize := AValue;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetDelay(const AValue: Integer);
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.SetDelay(AValue);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetPriority(const AValue: TTPriority);
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.SetPriority(AValue);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetSuspend(const AValue: Boolean);
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.SetSuspend(AValue);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.ThreadException(Sender: TComponent; E: Exception);
|
||||
begin
|
||||
if Assigned(FOnThreadException) then
|
||||
FOnThreadException(Sender,E);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.OutputDone(Sender: TComponent);
|
||||
begin
|
||||
if Assigned(FOnDone) then
|
||||
FOnDone(Sender);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.OutputProgress(Sender: TComponent);
|
||||
begin
|
||||
if Assigned(FOnProgress) then
|
||||
FOnProgress(Sender);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetInput(Input: TACSCustomInput);
|
||||
begin
|
||||
FInput := Input;
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Input := Input;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetDevice(Ch: Integer);
|
||||
begin
|
||||
FBaseChannel := ch;
|
||||
if Assigned(FOutput) then
|
||||
FOutput.SetDevice(ch);
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetDeviceInfo : TACSDeviceInfo;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
Result := FOutput.DeviceInfo;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetDeviceCount : Integer;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FOutput.GetDeviceCount;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.SetDriver(Driver: string);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
if Driver = '' then
|
||||
exit;
|
||||
if Assigned(Foutput) then
|
||||
FOutput.Free;
|
||||
FOutput := nil;
|
||||
for i := 0 to length(OutDriverInfos)-1 do
|
||||
if OutDriverInfos[i].DriverName = Driver then
|
||||
begin
|
||||
FOutput := OutDriverInfos[i].DrvClass.Create(nil);
|
||||
try
|
||||
FOutput.SetDevice(FBaseChannel);
|
||||
except
|
||||
FOutput.SetDevice(0);
|
||||
end;
|
||||
FDriver := OutDriverInfos[i].DriverName;
|
||||
FLatency := OutDriverInfos[i].Latency;
|
||||
if Assigned(FInput) then
|
||||
FOutput.Input := FInput;
|
||||
FOutput.OnDone := OutputDone;
|
||||
FOutput.OnProgress := OutputProgress;
|
||||
Foutput.OnThreadException := ThreadException;
|
||||
Foutput.Buffersize := FBuffersize;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetDriverName(idx: Integer): string;
|
||||
begin
|
||||
if (idx < 0) or (idx > length(OutDriverInfos)-1)then
|
||||
exit;
|
||||
Result := OutDriverInfos[idx].DriverName;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.GetDriversCount: Integer;
|
||||
begin
|
||||
Result := length(OutDriverInfos);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Done;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Foutput.Done;
|
||||
end;
|
||||
|
||||
function TACSAudioOut.DoOutput(Abort: Boolean): Boolean;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.DoOutput(Abort);
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Prepare;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.Prepare;
|
||||
end;
|
||||
|
||||
constructor TACSAudioOut.Create(AOwner: TComponent);
|
||||
var
|
||||
lowestindex,lowest,minlat,i : Integer;
|
||||
tmp : string;
|
||||
exc: Boolean;
|
||||
label retry;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
minlat := 0;
|
||||
retry:
|
||||
lowest := 99999;
|
||||
for i := 0 to length(OutDriverInfos)-1 do
|
||||
if (OutDriverInfos[i].Latency < lowest) and (OutDriverInfos[i].Latency > minlat) then
|
||||
begin
|
||||
lowest := OutDriverInfos[i].Latency;
|
||||
lowestindex := i;
|
||||
end;
|
||||
if lowest < 99999 then
|
||||
begin
|
||||
try
|
||||
SetDriver(OutDriverInfos[lowestindex].DriverName);
|
||||
exc := false;
|
||||
except
|
||||
minlat := lowest+1;
|
||||
exc := true;
|
||||
end;
|
||||
if exc then
|
||||
goto retry;
|
||||
end
|
||||
else
|
||||
FDriver := 'No Driver';
|
||||
end;
|
||||
|
||||
destructor TACSAudioOut.Destroy;
|
||||
begin
|
||||
FOutput.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Pause;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.Pause;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Resume;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.Resume;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Run;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FOutput.Run;
|
||||
end;
|
||||
|
||||
procedure TACSAudioOut.Stop;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Stop;
|
||||
end;
|
||||
|
||||
{ TACSAudioIn }
|
||||
|
||||
function TACSAudioIn.GetBPS: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FInput.GetBPS;
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetCh: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FInput.GetCh;
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetSR: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FInput.GetSr;
|
||||
end;
|
||||
|
||||
procedure TACSAudioIn.SetDevice(Ch: Integer);
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FInput.SetDevice(Ch);
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetDeviceInfo : TACSDeviceInfo;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
//TODO: Complete
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetTotalTime : real;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FInput.GetTotalTime;
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetDriverName(idx: Integer): string;
|
||||
begin
|
||||
if (idx < 0) or (idx > length(InDriverInfos)-1)then
|
||||
exit;
|
||||
Result := InDriverInfos[idx].DriverName;
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetDriversCount: Integer;
|
||||
begin
|
||||
Result := length(InDriverInfos);
|
||||
end;
|
||||
|
||||
procedure TACSAudioIn.SetDriver(Driver: string);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
if Assigned(FInput) then
|
||||
FInput.Free;
|
||||
for i := 0 to length(InDriverInfos)-1 do
|
||||
if InDriverInfos[i].DriverName = Driver then
|
||||
begin
|
||||
FDriver := InDriverInfos[i].DriverName;
|
||||
FInput := InDriverInfos[i].DrvClass.Create(nil);
|
||||
FInput.SetDevice(FBaseChannel);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TACSAudioIn.Create(AOwner: TComponent);
|
||||
var
|
||||
lowestindex,lowest,i : Integer;
|
||||
minlat: Integer;
|
||||
exc: Boolean;
|
||||
label retry;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
minlat := 0;
|
||||
retry:
|
||||
lowest := 99999;
|
||||
for i := 0 to length(InDriverInfos)-1 do
|
||||
if (InDriverInfos[i].Latency < lowest) and (InDriverInfos[i].Latency > minlat) then
|
||||
begin
|
||||
lowest := InDriverInfos[i].Latency;
|
||||
lowestindex := i;
|
||||
end;
|
||||
if lowest < 99999 then
|
||||
begin
|
||||
try
|
||||
SetDriver(InDriverInfos[lowestindex].DriverName);
|
||||
exc := false;
|
||||
except
|
||||
minlat := lowest+1;
|
||||
exc := true;
|
||||
end;
|
||||
if exc then
|
||||
goto retry;
|
||||
end
|
||||
else
|
||||
FDriver := 'No Driver';
|
||||
end;
|
||||
|
||||
destructor TACSAudioIn.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSAudioIn.GetData(Buffer: Pointer; BufferSize: Integer): Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
Result := FInput.GetData(Buffer,BufferSize);
|
||||
end;
|
||||
|
||||
procedure TACSAudioIn.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FInput.Init;
|
||||
end;
|
||||
|
||||
procedure TACSAudioIn.Flush;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoDriverselected);
|
||||
FInput.Flush;
|
||||
end;
|
||||
|
||||
procedure RegisterAudioOut(DrvName : string;OutClass : TACSAudioOutClass;Latency : Integer);
|
||||
begin
|
||||
Setlength(OutDriverInfos,length(OutdriverInfos)+1);
|
||||
OutDriverInfos[length(OutDriverInfos)-1].DriverName := DrvName;
|
||||
OutDriverInfos[length(OutDriverInfos)-1].Latency := Latency;
|
||||
OutDriverInfos[length(OutDriverInfos)-1].DrvClass := OutClass;
|
||||
end;
|
||||
|
||||
procedure RegisterAudioIn(DrvName : string;InClass : TACSAudioInClass;Latency : Integer);
|
||||
begin
|
||||
Setlength(InDriverInfos,length(IndriverInfos)+1);
|
||||
InDriverInfos[length(InDriverInfos)-1].DriverName := DrvName;
|
||||
InDriverInfos[length(InDriverInfos)-1].Latency := Latency;
|
||||
InDriverInfos[length(InDriverInfos)-1].DrvClass := InClass;
|
||||
end;
|
||||
|
||||
{ TACSBaseAudioOut }
|
||||
|
||||
constructor TACSBaseAudioOut.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSBaseAudioOut.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TBaseAudioIn }
|
||||
|
||||
constructor TACSBaseAudioIn.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSBaseAudioIn.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
Setlength(OutDriverInfos,0);
|
||||
Setlength(InDriverInfos,0);
|
||||
|
||||
finalization
|
||||
|
||||
Setlength(OutDriverInfos,0);
|
||||
Setlength(InDriverInfos,0);
|
||||
|
||||
end.
|
413
acs/Src/classes/acs_audiomix.pas
Normal file
413
acs/Src/classes/acs_audiomix.pas
Normal file
@@ -0,0 +1,413 @@
|
||||
(*
|
||||
this file is a part of audio components suite.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
|
||||
$Log: acs_audiomix.pas,v $
|
||||
Revision 1.6 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/09/15 20:59:37 z0m3ie
|
||||
start translate the documentation in the source for pasdoc
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.3 2005/08/23 19:45:51 z0m3ie
|
||||
changed to Version 2.31
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
*)
|
||||
|
||||
{
|
||||
@abstract(this unit introduces the base classes for acs)
|
||||
@author(Andrei Borovsky (2003-2005))
|
||||
@author(Christian Ulrich (2005))
|
||||
}
|
||||
|
||||
{$hints off}
|
||||
unit acs_audiomix;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Types, ACS_Classes, ACS_Strings;
|
||||
|
||||
const
|
||||
BUF_SIZE = $100000;
|
||||
|
||||
type
|
||||
TACSAudioMixerMode = (amMix, amConcatenate, amRTMix, amCustomMix);
|
||||
TACSAudioMixer = class(TACSCustomInput)
|
||||
private
|
||||
FInput1, FInput2 : TACSCustomInput;
|
||||
BufStart, BufEnd : Integer;
|
||||
ByteCount : Cardinal; // add by leozhang
|
||||
FVolume1, FVolume2 : Byte;
|
||||
EndOfInput1, EndOfInput2 : Boolean;
|
||||
InBuf1, InBuf2 : array[1..BUF_SIZE] of Byte;
|
||||
Buisy : Boolean;
|
||||
FMode : TACSAudioMixerMode;
|
||||
FInput2Start: Cardinal;
|
||||
FLock : Boolean;
|
||||
FFgPlaying : Boolean;
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
procedure SetInput1(aInput : TACSCustomInput);
|
||||
procedure SetInput2(aInput : TACSCustomInput);
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
property FgPlaying : Boolean read FFgPlaying;
|
||||
published
|
||||
property Input1 : TACSCustomInput read FInput1 write SetInput1;
|
||||
property Input2 : TACSCustomInput read FInput2 write SetInput2;
|
||||
property Mode : TACSAudioMixerMode read FMode write FMode;
|
||||
property Input2Start :Cardinal read FInput2Start write FInput2Start;
|
||||
property Volume1 : Byte read FVolume1 write FVolume1;
|
||||
property Volume2 : Byte read FVolume2 write FVolume2;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
procedure MixChannels16(Buf1, Buf2 : PACSBuffer16; Vol1, Vol2, InSize : Integer);
|
||||
var // optimized by leozhang
|
||||
i, tmp : Integer;
|
||||
V1,V2: Real;
|
||||
begin
|
||||
V1 := Vol1 / 127;
|
||||
V2 := Vol2 / 127;
|
||||
for i := 0 to (Insize shr 1) - 1 do
|
||||
begin
|
||||
if Buf2[i] = 0 then
|
||||
begin
|
||||
Buf2[i] := Round(Buf1[i] * V1);
|
||||
end else
|
||||
if Buf1[i] = 0 then
|
||||
begin
|
||||
Buf2[i] := Round(Buf2[i] * V2);
|
||||
end else
|
||||
Buf2[i] := Round(Buf1[i] * V1) + Round(Buf2[i] * V2);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TACSAudioMixer.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FVolume1 := 127;
|
||||
FVolume2 := 127;
|
||||
FInput2Start := 0;
|
||||
end;
|
||||
|
||||
destructor TACSAudioMixer.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSAudioMixer.GetBPS;
|
||||
begin
|
||||
if not Assigned(FInput1) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput1.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSAudioMixer.GetCh;
|
||||
begin
|
||||
if not Assigned(FInput1) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result:= FInput1.Channels;
|
||||
end;
|
||||
|
||||
function TACSAudioMixer.GetSR;
|
||||
begin
|
||||
if not Assigned(FInput1) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput1.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSAudioMixer.Init;
|
||||
var
|
||||
In2StartByte : Cardinal; // add by zhangl.
|
||||
begin
|
||||
Buisy := True;
|
||||
FPosition := 0;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
EndOfInput1 := False;
|
||||
EndOfInput2 := False;
|
||||
if not Assigned(FInput1) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if FMode = amRTMix then
|
||||
begin
|
||||
FInput1.Init;
|
||||
FSize := FInput1.Size;
|
||||
if Assigned(FInput2) then
|
||||
begin
|
||||
FInput2.Init;
|
||||
FFgPlaying := True;
|
||||
end else EndOfInput2 := True;
|
||||
FLock := False;
|
||||
end else
|
||||
begin
|
||||
if not Assigned(FInput2) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput1.Init;
|
||||
FInput2.Init;
|
||||
case FMode of
|
||||
amMix :
|
||||
if FInput1.Size > FInput2.Size then FSize := FInput1.Size
|
||||
else FSize := FInput2.Size;
|
||||
amConcatenate :
|
||||
FSize := FInput1.Size + FInput2.Size; //determine the size of the output stream in bytes
|
||||
amCustomMix:
|
||||
// add by leozhang
|
||||
begin
|
||||
In2StartByte := Round(Int((FInput2Start * FInput2.SampleRate) /1000) *
|
||||
(FInput2.Channels) * ((FInput2.BitsPerSample) shr 3));
|
||||
ByteCount := In2StartByte;
|
||||
if Cardinal(FInput1.Size) > In2StartByte + FInput2.Size then
|
||||
FSize := FInput1.Size
|
||||
else
|
||||
FSize := In2StartByte + FInput2.Size;
|
||||
FLock := False;
|
||||
end;
|
||||
// leozhang
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
procedure TACSAudioMixer.Flush;
|
||||
begin
|
||||
FInput1.Flush;
|
||||
if (FMode <> amRTMix) or Assigned(FInput2) then
|
||||
FInput2.Flush;
|
||||
Buisy := False;
|
||||
end;
|
||||
function TACSAudioMixer.GetData;
|
||||
var
|
||||
l1, l2 : Integer;
|
||||
InSize : Integer;
|
||||
begin
|
||||
if not Buisy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
if EndOfInput1 and EndOfInput2 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if (FMode = amRTMix) and EndOfInput1 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
BufStart := 1;
|
||||
case Mode of
|
||||
amMix :
|
||||
begin
|
||||
l1 := 0;
|
||||
l2 := 0;
|
||||
FillChar(InBuf1[1], BUF_SIZE, 0);
|
||||
FillChar(InBuf2[1], BUF_SIZE, 0);
|
||||
if not EndOfInput1 then
|
||||
begin
|
||||
l1 := FInput1.GetData(@InBuf1[1], BUF_SIZE);
|
||||
InSize := l1;
|
||||
while (InSize <> 0) and (l1 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput1.GetData(@InBuf1[l1+1], BUF_SIZE - l1);
|
||||
Inc(l1, InSize);
|
||||
end;
|
||||
if InSize = 0 then EndOfInput1 := True;
|
||||
end;
|
||||
if not EndOfInput2 then
|
||||
begin
|
||||
l2 := FInput2.GetData(@InBuf2[1], BUF_SIZE);
|
||||
InSize := l2;
|
||||
while (InSize <> 0) and (l2 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput2.GetData(@InBuf2[l2+1], BUF_SIZE - l2);
|
||||
Inc(l2, InSize);
|
||||
end;
|
||||
if InSize = 0 then EndOfInput2 := True;
|
||||
end;
|
||||
if (l1 = 0) and (l2 = 0) then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if l1 > l2 then BufEnd := l1 else BufEnd := l2;
|
||||
MixChannels16(@InBuf1[1], @InBuf2[1], FVolume1, FVolume2, BufEnd);
|
||||
end;
|
||||
amConcatenate :
|
||||
begin
|
||||
if not EndOfInput1 then
|
||||
begin
|
||||
l1 := FInput1.GetData(@InBuf2[1], BUF_SIZE);
|
||||
if l1 = 0 then EndOfInput1 := True
|
||||
else BufEnd := l1;
|
||||
end;
|
||||
if EndOfInput1 then
|
||||
begin
|
||||
l2 := FInput2.GetData(@InBuf2[1], BUF_SIZE);
|
||||
if l2 = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end
|
||||
else BufEnd := l2;
|
||||
end;
|
||||
end;
|
||||
// add by leo.zhang
|
||||
amCustomMix:
|
||||
begin
|
||||
l1 := 0;
|
||||
l2 := 0;
|
||||
FillChar(InBuf1[1], BUF_SIZE, 0);
|
||||
FillChar(InBuf2[1], BUF_SIZE, 0);
|
||||
if not EndOfInput1 then
|
||||
begin
|
||||
l1 := FInput1.GetData(@InBuf1[1], BUF_SIZE);
|
||||
InSize := l1;
|
||||
while (InSize <> 0) and (l1 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput1.GetData(@InBuf1[l1+1], BUF_SIZE - l1);
|
||||
Inc(l1, InSize);
|
||||
end;
|
||||
if InSize = 0 then EndOfInput1 := True;
|
||||
end;
|
||||
if not (FLock or EndOfInput2) then
|
||||
begin
|
||||
FLock := True;
|
||||
if ByteCount > BUF_SIZE then
|
||||
begin
|
||||
ByteCount := ByteCount - BUF_SIZE;
|
||||
l2 := BUF_SIZE; InSize := l2;
|
||||
end else
|
||||
begin
|
||||
l2 := FInput2.GetData(@InBuf2[ByteCount+1],BUF_SIZE - ByteCount);
|
||||
InSize := l2;
|
||||
if ByteCount <> 0 then
|
||||
begin
|
||||
Inc(l2,ByteCount);
|
||||
InSize := l2;
|
||||
ByteCount := 0;
|
||||
end;
|
||||
while (InSize <> 0) and (l2 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput2.GetData(@InBuf2[l2+1], BUF_SIZE - l2);
|
||||
Inc(l2, InSize);
|
||||
end;
|
||||
end;
|
||||
if InSize = 0 then EndOfInput2 := True;
|
||||
FLock := False;
|
||||
end;
|
||||
if (l1 = 0) and (l2 = 0) then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if l1 > l2 then BufEnd := l1 else BufEnd := l2;
|
||||
MixChannels16(@InBuf1[1], @InBuf2[1], FVolume1, FVolume2, BufEnd);
|
||||
end;
|
||||
// leo.zhang.
|
||||
amRTMix :
|
||||
begin
|
||||
l1 := 0;
|
||||
l2 := 0;
|
||||
FillChar(InBuf1[1], BUF_SIZE, 0);
|
||||
FillChar(InBuf2[1], BUF_SIZE, 0);
|
||||
if not EndOfInput1 then
|
||||
begin
|
||||
l1 := FInput1.GetData(@InBuf1[1], BUF_SIZE);
|
||||
InSize := l1;
|
||||
while (InSize <> 0) and (l1 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput1.GetData(@InBuf1[l1+1], BUF_SIZE - l1);
|
||||
Inc(l1, InSize);
|
||||
end;
|
||||
if InSize = 0 then EndOfInput1 := True;
|
||||
end;
|
||||
if not (FLock or EndOfInput2) then
|
||||
begin
|
||||
FLock := True;
|
||||
l2 := FInput2.GetData(@InBuf2[1], BUF_SIZE);
|
||||
InSize := l2;
|
||||
while (InSize <> 0) and (l2 < BUF_SIZE) do
|
||||
begin
|
||||
InSize := FInput2.GetData(@InBuf2[l2+1], BUF_SIZE - l2);
|
||||
Inc(l2, InSize);
|
||||
end;
|
||||
if InSize = 0 then
|
||||
begin
|
||||
EndOfInput2 := True;
|
||||
FFGPlaying := False;
|
||||
FInput2.Flush;
|
||||
FInput2 := nil;
|
||||
end;
|
||||
FLock := False;
|
||||
end;
|
||||
if (l1 = 0) and (l2 = 0) then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if l1 > l2 then BufEnd := l1 else BufEnd := l2;
|
||||
MixChannels16(@InBuf1[1], @InBuf2[1], FVolume1, FVolume2, BufEnd);
|
||||
end;
|
||||
end; // case end.
|
||||
end; // endif.
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InBuf2[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
Inc(FPosition, Result);
|
||||
end; // procedure end.
|
||||
procedure TACSAudioMixer.SetInput1;
|
||||
begin
|
||||
if Buisy then
|
||||
raise EACSException.Create(strBusy);
|
||||
FInput1 := aInput;
|
||||
end;
|
||||
procedure TACSAudioMixer.SetInput2;
|
||||
begin
|
||||
if not Buisy then FInput2 := aInput
|
||||
else
|
||||
if FMode = amRTMix then
|
||||
begin
|
||||
if FFgPlaying then
|
||||
begin
|
||||
while Flock do;
|
||||
FLock := True;
|
||||
Input2.Flush;
|
||||
end;
|
||||
FInput2 := aInput;
|
||||
Finput2.Init;
|
||||
Flock := False;
|
||||
FFgPlaying := True;
|
||||
EndOfInput2 := False;
|
||||
end else
|
||||
raise EACSException.Create(strNotinFBMode);
|
||||
end;
|
||||
|
||||
end.
|
321
acs/Src/classes/acs_cdrom.pas
Normal file
321
acs/Src/classes/acs_cdrom.pas
Normal file
@@ -0,0 +1,321 @@
|
||||
(*
|
||||
this file is a part of audio components suite
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
|
||||
Special thanks to Thomas Grelle <grelle@online.de> for improving this unit.
|
||||
|
||||
$Log: acs_cdrom.pas,v $
|
||||
Revision 1.11 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.10 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.2 2005/12/26 17:31:38 z0m3ie
|
||||
fixed some problems in acs_dsfiles
|
||||
fixed some problems in acs_vorbis
|
||||
reworked all buffers
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.7 2005/12/18 17:01:54 z0m3ie
|
||||
delphi compatibility
|
||||
|
||||
Revision 1.6 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.5 2005/11/28 21:57:24 z0m3ie
|
||||
mostly FileOut fixes
|
||||
moved PBuffer to PBuffer8
|
||||
set all to dynamically Buffering
|
||||
|
||||
Revision 1.4 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/09/15 20:59:38 z0m3ie
|
||||
start translate the documentation in the source for pasdoc
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.6 2005/09/09 21:33:42 z0m3ie
|
||||
linux corrections
|
||||
|
||||
Revision 1.5 2005/09/08 22:18:59 z0m3ie
|
||||
completed akrip based CDIn
|
||||
|
||||
Revision 1.4 2005/09/07 20:53:22 z0m3ie
|
||||
begon to add MPEG and WMA support using DirectX
|
||||
|
||||
Revision 1.3 2005/09/04 17:59:37 z0m3ie
|
||||
moving CDIn support to AKRip mostly
|
||||
begon to add mpegin support for Win with mpg123
|
||||
|
||||
Revision 1.2 2005/08/28 20:31:17 z0m3ie
|
||||
linux restructuring for 2.4
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
Revision 1.5 2005/08/22 20:17:02 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
*)
|
||||
|
||||
{
|
||||
@abstract(this unit introduces the base classes for acs)
|
||||
@author(Andrei Borovsky (2003-2005))
|
||||
@author(Christian Ulrich (2005))
|
||||
}
|
||||
|
||||
|
||||
unit acs_cdrom;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Classes,ACS_Strings,ACS_Types
|
||||
{$IFDEF MSWINDOWS}
|
||||
,Windows, MMSystem, akrip32
|
||||
{$ELSE}
|
||||
,baseunix,cd_rom
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
type
|
||||
{$IFDEF MSWINDOWS}
|
||||
{$IFDEF FPC}
|
||||
TAuxCaps = AUXCAPS;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
TACSCDStatus = (cdsNotReady, cdsReady, cdsPlaying, cdsPaused);
|
||||
TACSTrackType = (ttAudio, ttData);
|
||||
TACSCDInfo = (cdiNoDisc, cdiDiscAudio, cdiDiscData, cdiDiscMixed, cdiUnknown);
|
||||
TACSMCN = array[0..13] of Char;
|
||||
|
||||
TACSCDMSF = record
|
||||
Minute : Byte;
|
||||
Second : Byte;
|
||||
Frame : Byte;
|
||||
end;
|
||||
PACSCDMSF = ^TACSCDMSF;
|
||||
|
||||
TACSCDTrackInfo = record
|
||||
TrackStart: TACSCDMSF;
|
||||
TrackLength : TACSCDMSF;
|
||||
TrackType : TACSTrackType;
|
||||
end;
|
||||
|
||||
TACSCDPosition = record
|
||||
Track : Integer;
|
||||
MSF : TACSCDMSF;
|
||||
end;
|
||||
|
||||
const
|
||||
|
||||
EndOfDisc : TACSCDPosition = (Track : 100; MSF : (Minute : 0; Second : 0; Frame : 0));
|
||||
CD_FRAMESIZE_RAW = 2352;
|
||||
BUF_SIZE = 50; // 75 frames - 1 sec
|
||||
|
||||
var
|
||||
AppPath : String;
|
||||
WinPath : String;
|
||||
|
||||
type
|
||||
|
||||
{ This is the cdreader component of acs it reads in windows with aspi
|
||||
and linux direct from device
|
||||
}
|
||||
|
||||
TACSCDIn = class(TACSCustomInput)
|
||||
private
|
||||
FBuffer : array of byte;
|
||||
FCurrentDrive : Integer;
|
||||
FStartTrack, FEndTrack : Integer;
|
||||
FStartPos, FEndPos: TACSCDPosition;
|
||||
FRipEnd : Integer;
|
||||
FCDDBId: Longint;
|
||||
{$IFDEF LINUX}
|
||||
FOpened : Integer;
|
||||
FCurPos,FEndMSF : TACSCDMSF;
|
||||
FDrivesCount : Integer;
|
||||
_cd_fd : Integer;
|
||||
BufSize : Integer;
|
||||
{$ELSE}
|
||||
FToc: TOC;
|
||||
FCDList: CDLIST;
|
||||
FCDHandle : HCDROM;
|
||||
FPlaying : Boolean;
|
||||
FRipStart : LongInt;
|
||||
FiBuffer : PTRACKBUF;
|
||||
{$ENDIF}
|
||||
procedure OpenCD;
|
||||
procedure CloseCD;
|
||||
function GetStatus : TACSCDStatus;
|
||||
function GetNumTracks : Integer;
|
||||
function GetTrackInfo(const vIndex : Integer) : TACSCDTrackInfo;
|
||||
procedure SetST(Track : Integer);
|
||||
procedure SetET(Track : Integer);
|
||||
procedure SetSP(Pos : TACSCDPosition);
|
||||
procedure SetEP(Pos : TACSCDPosition);
|
||||
function GetSize : Integer;
|
||||
function GetInfo : TACSCDInfo;
|
||||
function GetDrivesCount : Integer;
|
||||
procedure SetCurrentDrive(Value : Integer);
|
||||
function GetDriveName : String;
|
||||
function GetCDDBID : LongInt;
|
||||
function GetTotalTime : real; override;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
procedure Eject;
|
||||
procedure CloseTray;
|
||||
property DiscInfo: TACSCDInfo read GetInfo;
|
||||
property Status: TACSCDStatus read GetStatus;
|
||||
property Tracks[const vIndex : Integer] : TACSCDTrackInfo read GetTrackInfo;
|
||||
property TracksCount : Integer read GetNumTracks;
|
||||
property DriveName : String read GetDriveName;
|
||||
property DrivesCount : Integer read GetDrivesCount;
|
||||
property StartPos : TACSCDPosition read FStartPos write SetSP;
|
||||
property EndPos : TACSCDPosition read FEndPos write SetEP;
|
||||
property CDDBId : LongInt read GetCDDBID;
|
||||
published
|
||||
property CurrentDrive : Integer read FCurrentDrive write SetCurrentDrive;
|
||||
property StartTrack: Integer read FStartTrack write SetSt;
|
||||
property EndTrack: Integer read FEndTrack write SetET;
|
||||
end;
|
||||
|
||||
function MSFToStr(const MSF : TACSCDMSF) : String;
|
||||
procedure Frames2MSF(Frames : Integer; var MSF : TACSCDMSF);
|
||||
function MSF2Frames(const MSF : TACSCDMSF) : Integer;
|
||||
|
||||
{$IFDEF LINUX}
|
||||
var
|
||||
DrivesCount : Integer;
|
||||
DrivesPaths : array of string;
|
||||
|
||||
procedure CountDrives;
|
||||
{$ENDIF}
|
||||
|
||||
implementation
|
||||
|
||||
{$I ACS_CDROM.inc}
|
||||
|
||||
function MSFToStr(const MSF : TACSCDMSF) : String;
|
||||
var
|
||||
sep : String;
|
||||
sec, min : Integer;
|
||||
begin
|
||||
min := MSF.Minute;
|
||||
if MSF.Frame > 37 then
|
||||
begin
|
||||
sec := MSF.Second + 1;
|
||||
if sec = 60 then
|
||||
begin
|
||||
Inc(min);
|
||||
sec := 0;
|
||||
end;
|
||||
end
|
||||
else sec := MSF.Second;
|
||||
if sec<10 then sep := ':0'
|
||||
else sep := ':';
|
||||
Result := IntToStr(min) + sep + IntToStr(sec);
|
||||
end;
|
||||
|
||||
procedure Frames2MSF(Frames : Integer; var MSF : TACSCDMSF);
|
||||
var
|
||||
Temp : Integer;
|
||||
begin
|
||||
Temp := Frames div 75;
|
||||
MSF.Minute := Temp div 60;
|
||||
MSF.Second := Temp mod 60;
|
||||
MSF.Frame := Frames mod 75;
|
||||
end;
|
||||
|
||||
function MSF2Frames(const MSF : TACSCDMSF) : Integer;
|
||||
begin
|
||||
Result := ((MSF.Minute * 60) + MSF.Second) * 75 + MSF.Frame;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetBPS : Integer;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetCh : Integer;
|
||||
begin
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetSR : Integer;
|
||||
begin
|
||||
Result := 44100;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetTotalTime : real;
|
||||
begin
|
||||
if (SampleRate = 0) or (Channels = 0) or (BitsPerSample = 0) then
|
||||
Exit;
|
||||
Result := Size/(SampleRate*Channels*(BitsPerSample shr 3));
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetCDDBID: LongInt;
|
||||
FUNCTION prg_sum(n: integer): integer;
|
||||
VAR
|
||||
buf: STRING;
|
||||
ib: Integer;
|
||||
BEGIN
|
||||
buf := IntToStr(n);
|
||||
Result := 0;
|
||||
FOR ib := 1 TO Length(buf) DO
|
||||
Result := Result + (StrToInt(Copy(Buf, ib, 1)));
|
||||
END;
|
||||
VAR
|
||||
i, N, L: Longint;
|
||||
CDM: TACSCDMSF;
|
||||
BEGIN
|
||||
N := 0;
|
||||
L := 0;
|
||||
FOR i := 0 TO GetNumTracks-1 DO
|
||||
BEGIN
|
||||
WITH Tracks[i].TrackStart DO
|
||||
BEGIN
|
||||
N := N + prg_sum((minute * 60) + second + 2);
|
||||
L := L + MSF2Frames(Tracks[i].TrackLength);
|
||||
// adjust the length of last audio track if a data track is following
|
||||
IF (i > 0) AND (i = TracksCount - 2) AND (Tracks[i + 1].TrackType = ttData) THEN
|
||||
inc(L, 152 * 75);
|
||||
END;
|
||||
END;
|
||||
Frames2MSF(L, CDM);
|
||||
L := CDM.Minute * 60 + CDM.Second;
|
||||
Result := ((N MOD $0FF) SHL 24) XOR (L SHL 8) XOR TracksCount;
|
||||
FCDDBId := Result;
|
||||
end;
|
||||
|
||||
{$IFDEF LINUX}
|
||||
initialization
|
||||
CountDrives;
|
||||
{$ENDIF}
|
||||
|
||||
end.
|
1376
acs/Src/classes/acs_classes.pas
Normal file
1376
acs/Src/classes/acs_classes.pas
Normal file
File diff suppressed because it is too large
Load Diff
910
acs/Src/classes/acs_converters.pas
Normal file
910
acs/Src/classes/acs_converters.pas
Normal file
@@ -0,0 +1,910 @@
|
||||
(*
|
||||
this file is a part of audio components suite.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
|
||||
$Log: acs_converters.pas,v $
|
||||
Revision 1.6 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.5 2006/07/04 18:38:32 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.2 2006/01/01 18:46:40 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/09/15 20:59:38 z0m3ie
|
||||
start translate the documentation in the source for pasdoc
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.4 2005/09/01 19:55:48 z0m3ie
|
||||
again Delphi corrections
|
||||
|
||||
Revision 1.3 2005/08/31 20:30:39 z0m3ie
|
||||
Mixer Channelname work now
|
||||
minior corrections for Converters
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
*)
|
||||
|
||||
{
|
||||
@abstract(this unit introduces the base classes for acs)
|
||||
@author(Andrei Borovsky (2003-2005))
|
||||
@author(Christian Ulrich (2005))
|
||||
}
|
||||
|
||||
unit acs_converters;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Types, ACS_Procs, ACS_Classes, ACS_Strings, Math;
|
||||
|
||||
const
|
||||
BUF_SIZE = $8000;
|
||||
|
||||
KERNEL_WIDTH = 64;
|
||||
|
||||
SD_BUF_SIZE = 2048;
|
||||
|
||||
type
|
||||
|
||||
TACSMSConverterMode = (msmMonoToBoth, msmMonoToLeft, msmMonoToRight);
|
||||
|
||||
TDA = array[0..63] of Double;
|
||||
PDA = ^TDA;
|
||||
|
||||
|
||||
TACSRateConverter = class(TACSCustomConverter)
|
||||
private
|
||||
FOutSampleRate : Integer;
|
||||
WantedSize : Integer;
|
||||
EndOfInput : Boolean;
|
||||
remainder : Integer;
|
||||
InBufM, OutBufM : PACSBuffer16;
|
||||
InBufS, OutBufS : PACSStereoBuffer16;
|
||||
DAM : array of Double;
|
||||
DAS : array of TACSStereoSampleD;
|
||||
Kernel : array of Double;
|
||||
FKernelWidth : Integer;
|
||||
FFilterWindow : TACSFilterWindowType;
|
||||
Tail : Pointer;
|
||||
LBS : TACSStereoSample16;
|
||||
function ConvertFreqs16Mono(InSize : Integer): Integer;
|
||||
function ConvertFreqs16Stereo(InSize : Integer): Integer;
|
||||
procedure SetOutSampleRate(aSR : Integer);
|
||||
procedure SetKernelWidth(aKW : Integer);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property FilterWindow : TACSFilterWindowType read FFilterWindow write FFilterWindow;
|
||||
property KernelWidth : Integer read FKernelWidth write SetKernelWidth;
|
||||
property OutSampleRate : Integer read FOutSampleRate write SetOutSampleRate;
|
||||
end;
|
||||
|
||||
TACSMSConverter = class(TACSCustomConverter)
|
||||
private
|
||||
WantedSize : Integer;
|
||||
EndOfInput : Boolean;
|
||||
InOutBuf : array[1..BUF_SIZE] of Byte;
|
||||
FMode : TACSMSConverterMode;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property Mode : TACSMSConverterMode read FMode write FMode;
|
||||
end;
|
||||
|
||||
TACSSampleConverter = class(TACSCustomConverter)
|
||||
private
|
||||
WantedSize : Integer;
|
||||
EndOfInput : Boolean;
|
||||
InOutBuf : array[1..BUF_SIZE] of Byte;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
end;
|
||||
|
||||
TACSStereoBalance = class(TACSCustomConverter)
|
||||
private
|
||||
FBalance : Single;
|
||||
procedure SetBalance(a : Single);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property Balance : Single read FBalance write SetBalance;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
function TACSRateConverter.ConvertFreqs16Mono(InSize : Integer): Integer;
|
||||
var
|
||||
i, step, j, k, s, m : Integer;
|
||||
D : Double;
|
||||
TailMono : PACSBuffer16;
|
||||
TailMonoD : PACSDoubleArray;
|
||||
begin
|
||||
TailMono := Tail;
|
||||
s := InSize shr 1;
|
||||
if FInput.SampleRate > FOutSampleRate then
|
||||
begin
|
||||
step := FInput.SampleRate - FOutSampleRate;
|
||||
j := 0;
|
||||
if remainder < 0 then remainder := FOutSampleRate;
|
||||
for i := 0 to s - 1 do
|
||||
begin
|
||||
if remainder > FOutSampleRate then Dec(remainder, FOutSampleRate)
|
||||
else begin
|
||||
D := 0;
|
||||
for k := 0 to FKernelWidth - 1 do
|
||||
if i-k >= 0 then
|
||||
D := D + InBufM[i-k]*Kernel[FKernelWidth - 1 - k]
|
||||
else
|
||||
D := D + TailMono[FKernelWidth-1+i-k]*Kernel[FKernelWidth - 1 - k];
|
||||
OutBufM[j] := Round(D);
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
end;
|
||||
for i := 0 to FKernelWidth-2 do TailMono[i] := InBufM[i+s-FKernelWidth+1]
|
||||
end else
|
||||
begin
|
||||
TailMonoD := Tail;
|
||||
FillChar(DAM[0], Length(DAM)*8, 0);
|
||||
for i := 0 to FKernelWidth-2 do
|
||||
begin
|
||||
DAM[i] := TailMonoD[i];
|
||||
TailMonoD[i] := 0;
|
||||
end;
|
||||
Step := Finput.SampleRate;
|
||||
j := 0;
|
||||
if remainder < 0 then remainder := 0;
|
||||
while remainder < FOutSampleRate do
|
||||
begin
|
||||
m := Round(((FOutSampleRate - remainder)*LBS.Left + remainder*InBufM[0])/FOutSampleRate);
|
||||
for k := 0 to FKernelWidth-1 do
|
||||
DAM[j+k] := DAM[j+k] + m*Kernel[k];
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
Dec(remainder, FOutSampleRate);
|
||||
for i := 0 to s - 2 do
|
||||
begin
|
||||
while remainder < FOutSampleRate do
|
||||
begin
|
||||
m := Round(((FOutSampleRate - remainder)*InBufM[i] + remainder*InBufM[i+1])/FOutSampleRate);
|
||||
for k := 0 to FKernelWidth-1 do
|
||||
DAM[j+k] := DAM[j+k] + m*Kernel[k];
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
Dec(remainder, FOutSampleRate);
|
||||
end;
|
||||
LBS.Left := InBufM[s-1];
|
||||
for i := 0 to j-1 do
|
||||
OutBufM[i] := Round(DAM[i]);
|
||||
for i := 0 to FKernelWidth-2 do TailMonoD[i] := DAM[i+j];
|
||||
end;
|
||||
Result := j shl 1;
|
||||
end;
|
||||
|
||||
function TACSRateConverter.ConvertFreqs16Stereo(InSize : Integer): Integer;
|
||||
var
|
||||
i, step, j, k, s, m1, m2 : Integer;
|
||||
D1, D2 : Double;
|
||||
TailStereo : PACSStereoBuffer16;
|
||||
TailStereoD : PACSStereoBufferD;
|
||||
begin
|
||||
TailStereo := Tail;
|
||||
s := InSize shr 2;
|
||||
if FInput.SampleRate > FOutSampleRate then
|
||||
begin
|
||||
step := FInput.SampleRate - FOutSampleRate;
|
||||
j := 0;
|
||||
if remainder < 0 then remainder := FOutSampleRate;
|
||||
for i := 0 to s - 1 do
|
||||
begin
|
||||
try
|
||||
if remainder > FOutSampleRate then Dec(remainder, FOutSampleRate)
|
||||
else begin
|
||||
D1 := 0;
|
||||
D2 := 0;
|
||||
for k := 0 to FKernelWidth - 1 do
|
||||
if i-k >= 0 then
|
||||
begin
|
||||
D1 := D1 + InBufS[i-k].Left*Kernel[FKernelWidth - 1 - k];
|
||||
D2 := D2 + InBufS[i-k].Right*Kernel[FKernelWidth - 1 - k];
|
||||
end else
|
||||
begin
|
||||
D1 := D1 + TailStereo[FKernelWidth-1+i-k].Left*Kernel[FKernelWidth - 1 - k];
|
||||
D2 := D2 + TailStereo[FKernelWidth-1+i-k].Right*Kernel[FKernelWidth - 1 - k];
|
||||
end;
|
||||
OutBufS[j].Left := Round(D1);
|
||||
OutBufS[j].Right := Round(D2);
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
for i := 0 to FKernelWidth-2 do TailStereo[i] := InBufS[i+s-FKernelWidth+1]
|
||||
//Move(InBufS[s-FKernelWidth+1], TailStereo[0], FKernelWidth-1);
|
||||
end else
|
||||
begin
|
||||
TailStereoD := Tail;
|
||||
FillChar(DAS[0], Length(DAS)*16, 0);
|
||||
for i := 0 to FKernelWidth-2 do
|
||||
begin
|
||||
DAS[i] := TailStereoD[i];
|
||||
TailStereoD[i].Left := 0;
|
||||
TailStereoD[i].Right := 0;
|
||||
end;
|
||||
Step := Finput.SampleRate;
|
||||
j := 0;
|
||||
if remainder < 0 then remainder := 0;
|
||||
while remainder < FOutSampleRate do
|
||||
begin
|
||||
m1 := Round(((FOutSampleRate - remainder)*LBS.Left + remainder*InBufS[0].Left)/FOutSampleRate);
|
||||
m2 := Round(((FOutSampleRate - remainder)*LBS.Right + remainder*InBufS[0].Right)/FOutSampleRate);
|
||||
for k := 0 to FKernelWidth-1 do
|
||||
begin
|
||||
DAS[j+k].Left := DAS[j+k].Left + m1*Kernel[k]; //InBufS[i].Left*Kernel[k];
|
||||
DAS[j+k].Right := DAS[j+k].Right + m2*Kernel[k]; //InBufS[i].Right*Kernel[k];
|
||||
end;
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
Dec(remainder, FOutSampleRate);
|
||||
for i := 0 to s - 2 do
|
||||
begin
|
||||
while remainder < FOutSampleRate do
|
||||
begin
|
||||
m1 := Round(((FOutSampleRate - remainder)*InBufS[i].Left + remainder*InBufS[i+1].Left)/FOutSampleRate);
|
||||
m2 := Round(((FOutSampleRate - remainder)*InBufS[i].Right + remainder*InBufS[i+1].Right)/FOutSampleRate);
|
||||
for k := 0 to FKernelWidth-1 do
|
||||
begin
|
||||
DAS[j+k].Left := DAS[j+k].Left + m1*Kernel[k]; //InBufS[i].Left*Kernel[k];
|
||||
DAS[j+k].Right := DAS[j+k].Right + m2*Kernel[k]; //InBufS[i].Right*Kernel[k];
|
||||
end;
|
||||
Inc(j);
|
||||
Inc(remainder, step);
|
||||
end;
|
||||
Dec(remainder, FOutSampleRate);
|
||||
end;
|
||||
LBS := InBufS[s-1];
|
||||
for i := 0 to j-1 do
|
||||
begin
|
||||
OutBufS[i].Left := Round(DAS[i].Left);
|
||||
OutBufS[i].Right := Round(DAS[i].Right);
|
||||
end;
|
||||
for i := 0 to FKernelWidth-2 do TailStereoD[i] := DAS[i+j];
|
||||
end;
|
||||
Result := j shl 2;
|
||||
end;
|
||||
|
||||
procedure Convert16To8(InOutBuf : PACSBuffer8; InSize : Integer);
|
||||
var
|
||||
i : Integer;
|
||||
P : PACSBuffer16;
|
||||
begin
|
||||
P := @InOutBuf[0];
|
||||
for i := 0 to (Insize shr 1) -1 do
|
||||
InOutBuf[i] := Hi(P[i]+$8000);
|
||||
end;
|
||||
|
||||
procedure Convert8To16(InOutBuf : PACSBuffer8; InSize : Integer);
|
||||
var
|
||||
i : Integer;
|
||||
P : PACSBuffer16;
|
||||
begin
|
||||
P := @InOutBuf[0];
|
||||
for i := Insize - 1 downto 0 do P[i] := (InOutBuf[i] shl 8) - $8000;
|
||||
end;
|
||||
|
||||
procedure ConvertStereoToMono16(InOutBuf : PACSBuffer16; InSize : Integer);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
for i := 0 to (Insize shr 2) - 1 do
|
||||
begin
|
||||
InOutBuf[i] := (InOutBuf[i shl 1] + InOutBuf[(i shl 1)+1]) div 2;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure ConvertMonoToStereo16(InOutBuf : PACSBuffer16; InSize : Integer; Mode : TACSMSConverterMode);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
case Mode of
|
||||
msmMonoToBoth :
|
||||
for i := (Insize shr 1) - 1 downto 0 do
|
||||
begin
|
||||
InOutBuf[i shl 1] := InOutBuf[i];
|
||||
InOutBuf[(i shl 1)+1] := InOutBuf[i];
|
||||
end;
|
||||
msmMonoToLeft :
|
||||
for i := (Insize shr 1) - 1 downto 0 do
|
||||
begin
|
||||
InOutBuf[i shl 1] := 0;
|
||||
InOutBuf[(i shl 1)+1] := InOutBuf[i];
|
||||
end;
|
||||
msmMonoToRight :
|
||||
for i := (Insize shr 1) - 1 downto 0 do
|
||||
begin
|
||||
InOutBuf[i shl 1] := InOutBuf[i];
|
||||
InOutBuf[(i shl 1)+1] := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GCD(a, b : Integer) : Integer;
|
||||
var
|
||||
p, q, r : Integer;
|
||||
begin
|
||||
p := a;
|
||||
q := b;
|
||||
r := p mod q;
|
||||
while r <> 0 do
|
||||
begin
|
||||
p := q;
|
||||
q := r;
|
||||
r := p mod q;
|
||||
end;
|
||||
Result := q;
|
||||
end;
|
||||
|
||||
constructor TACSRateConverter.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FOutSampleRate := 22050;
|
||||
FKernelWidth := 30;
|
||||
FFilterWindow := fwBlackman;
|
||||
end;
|
||||
|
||||
destructor TACSRateConverter.Destroy;
|
||||
begin
|
||||
Kernel := nil;
|
||||
DAS := nil;
|
||||
DAM := nil;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSRateConverter.GetBPS : Integer;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TACSRateConverter.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSRateConverter.GetSR : Integer;
|
||||
begin
|
||||
Result := FOutSampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSRateConverter.Init;
|
||||
var
|
||||
Ratio : Single;
|
||||
TailSize : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
InputLock := False;
|
||||
FBusy := True;
|
||||
FPosition := 0;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
EndOfInput := False;
|
||||
Ratio := FOutSampleRate/Finput.SampleRate;
|
||||
if Ratio > 1. then
|
||||
WantedSize := (Trunc(BUF_SIZE/Ratio) shr 2) * 4
|
||||
else WantedSize := BUF_SIZE;
|
||||
if Finput.Channels = 1 then
|
||||
begin
|
||||
GetMem(InBufM, WantedSize);
|
||||
GetMem(OutBufM, BUF_SIZE);
|
||||
if Ratio < 1. then
|
||||
TailSize := (KernelWidth-1)*2
|
||||
else
|
||||
begin
|
||||
SetLength(DAM, (BUF_SIZE div 2)+KernelWidth);
|
||||
TailSize := (KernelWidth-1)*8;
|
||||
end;
|
||||
FillChar(DAM[0], Length(DAM)*Sizeof(DAM[0]), 0);
|
||||
end else
|
||||
begin
|
||||
GetMem(InBufS, WantedSize);
|
||||
GetMem(OutBufS, BUF_SIZE);
|
||||
if Ratio < 1. then
|
||||
TailSize := (KernelWidth-1)*4
|
||||
else
|
||||
begin
|
||||
SetLength(DAS, (BUF_SIZE div 4)+KernelWidth);
|
||||
TailSize := (KernelWidth-1)*16;
|
||||
end;
|
||||
end;
|
||||
GetMem(Tail, TailSize);
|
||||
FillChar(Tail^, TailSize, 0);
|
||||
FSize := Round(FInput.Size*Ratio);
|
||||
remainder := -1;
|
||||
if Ratio > 1. then Ratio := 1/Ratio;
|
||||
Ratio := Ratio*0.4;
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
CalculateSincKernel(@Kernel[0], Ratio, FKernelWidth, FFilterWindow);
|
||||
end;
|
||||
|
||||
procedure TACSRateConverter.Flush;
|
||||
begin
|
||||
FreeMem(Tail);
|
||||
FInput.Flush;
|
||||
if Finput.Channels = 1 then
|
||||
begin
|
||||
FreeMem(InBufM);
|
||||
FreeMem(OutBufM);
|
||||
end else
|
||||
begin
|
||||
FreeMem(InBufS);
|
||||
FreeMem(OutBufS);
|
||||
end;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSRateConverter.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
l : Integer;
|
||||
InSize : Integer;
|
||||
P : PACSBuffer8;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
if EndOfInput then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
BufStart := 1;
|
||||
if FInput.Channels = 1 then P := Pointer(InBufM)
|
||||
else P := Pointer(InBufS);
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@P[0], WantedSize);
|
||||
InputLock := False;
|
||||
if l = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
InSize := l;
|
||||
while (l<>0) and (InSize < WantedSize) do
|
||||
begin
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@P[InSize], WantedSize - InSize);
|
||||
InputLock := False;
|
||||
Inc(InSize, l);
|
||||
end;
|
||||
if l = 0 then
|
||||
begin
|
||||
EndOfInput := True;
|
||||
if InSize < FKernelWidth*2 then
|
||||
begin // stop buffer corruption?
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
if Self.Channels = 1 then
|
||||
begin
|
||||
BufEnd := ConvertFreqs16Mono(InSize);
|
||||
end else
|
||||
begin
|
||||
BufEnd := ConvertFreqs16Stereo(InSize);
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
if FInput.Channels = 1 then P := Pointer(OutBufM)
|
||||
else P := Pointer(OutBufS);
|
||||
Move(P[BufStart-1], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
// FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
constructor TACSMSConverter.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSMSConverter.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSMSConverter.GetBPS : Integer;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TACSMSConverter.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if FInput.Channels = 1 then Result := 2
|
||||
else Result := 1;
|
||||
end;
|
||||
|
||||
function TACSMSConverter.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSMSConverter.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
FBusy := True;
|
||||
FPosition := 0;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
InputLock := False;
|
||||
EndOfInput := False;
|
||||
if FInput.Channels = 2 then WantedSize := BUF_SIZE else
|
||||
WantedSize := BUF_SIZE shr 1;
|
||||
if FInput.Channels = 2 then
|
||||
FSize := FInput.Size shr 1
|
||||
else FSize := FInput.Size shl 1;
|
||||
end;
|
||||
|
||||
procedure TACSMSConverter.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSMSConverter.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
l : Integer;
|
||||
InSize : Integer;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
if EndOfInput then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
BufStart := 1;
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@InOutBuf[1], WantedSize);
|
||||
InputLock := False;
|
||||
if l = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
InSize := l;
|
||||
while (l<>0) and (InSize < WantedSize) do
|
||||
begin
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@InOutBuf[InSize+1], WantedSize - InSize);
|
||||
InputLock := False;
|
||||
Inc(InSize, l);
|
||||
end;
|
||||
if l = 0 then EndOfInput := True;
|
||||
if FInput.Channels = 2 then
|
||||
begin
|
||||
ConvertStereoToMono16(@InOutBuf[1], InSize);
|
||||
BufEnd := InSize shr 1;
|
||||
end else
|
||||
begin
|
||||
ConvertMonoToStereo16(@InOutBuf[1], InSize, FMode);
|
||||
BufEnd := InSize shl 1;
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InOutBuf[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
// FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
constructor TACSSampleConverter.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSSampleConverter.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSSampleConverter.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if FInput.BitsPerSample = 16 then Result := 8
|
||||
else Result := 16;
|
||||
end;
|
||||
|
||||
function TACSSampleConverter.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result:= FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSSampleConverter.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSSampleConverter.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
FBusy := True;
|
||||
FPosition := 0;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
InputLock := False;
|
||||
EndOfInput := False;
|
||||
if FInput.BitsPerSample = 16 then WantedSize := BUF_SIZE else
|
||||
WantedSize := BUF_SIZE shr 1;
|
||||
if FInput.BitsPerSample = 16 then
|
||||
FSize := FInput.Size shr 1
|
||||
else FSize := FInput.Size shl 1;
|
||||
end;
|
||||
|
||||
procedure TACSSampleConverter.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSSampleConverter.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
l : Integer;
|
||||
InSize : Integer;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
if EndOfInput then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
BufStart := 1;
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@InOutBuf[1], WantedSize);
|
||||
InputLock := False;
|
||||
if l = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
InSize := l;
|
||||
while (l<>0) and (InSize < WantedSize) do
|
||||
begin
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
l := Finput.GetData(@InOutBuf[InSize+1], WantedSize - InSize);
|
||||
InputLock := False;
|
||||
Inc(InSize, l);
|
||||
end;
|
||||
if l = 0 then EndOfInput := True;
|
||||
if FInput.BitsPerSample = 16 then
|
||||
begin
|
||||
Convert16To8(@InOutBuf[1], InSize);
|
||||
BufEnd := InSize shr 1;
|
||||
end else
|
||||
begin
|
||||
Convert8To16(@InOutBuf[1], InSize);
|
||||
BufEnd := InSize shl 1;
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InOutBuf[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
// Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
procedure TACSRateConverter.SetOutSampleRate(aSR : Integer);
|
||||
begin
|
||||
if (aSR > 0) {and (not Busy)} then FOutSampleRate := aSR;
|
||||
end;
|
||||
|
||||
procedure TACSRateConverter.SetKernelWidth;
|
||||
begin
|
||||
if (aKW > 1) and (not Busy) then FKernelWidth := aKW;
|
||||
end;
|
||||
|
||||
constructor TACSStereoBalance.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FBalance := 0.5;
|
||||
end;
|
||||
|
||||
destructor TACSStereoBalance.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSStereoBalance.SetBalance;
|
||||
begin
|
||||
if (a >= 0) and (a <=1) then FBalance := a;
|
||||
end;
|
||||
|
||||
function TACSStereoBalance.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSStereoBalance.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
function TACSStereoBalance.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSStereoBalance.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
FBusy := True;
|
||||
if FInput.Channels = 2 then FSize := FInput.Size
|
||||
else FSize := FInput.Size*2;
|
||||
FPosition := 0;
|
||||
InputLock := False;
|
||||
end;
|
||||
|
||||
procedure TACSStereoBalance.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSStereoBalance.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
WantedSize, i : Integer;
|
||||
P16 : PACSBuffer16;
|
||||
P8 : PACSBuffer8;
|
||||
Diff : Double;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
if FInput.Channels = 2 then WantedSize := BufferSize
|
||||
else WantedSize := BufferSize shr 1;
|
||||
Result := Finput.GetData(Buffer, WantedSize);
|
||||
InputLock := False;
|
||||
if Result = 0 then Exit;
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
if FInput.BitsPerSample = 8 then
|
||||
begin
|
||||
P8 := Buffer;
|
||||
for i := Result*2-1 downto 1 do P8[i] := P8[i shr 1];
|
||||
end else
|
||||
begin
|
||||
P16 := Buffer;
|
||||
for i := Result-1 downto 1 do
|
||||
P16[i] := P16[i shr 1];
|
||||
end;
|
||||
Result := Result*2;
|
||||
end;
|
||||
if FInput.BitsPerSample = 8 then
|
||||
begin
|
||||
P8 := Buffer;
|
||||
if FBalance > 0.5 then
|
||||
begin
|
||||
Diff := 1-Balance;
|
||||
for i := 0 to (Result shr 1) -1 do
|
||||
P8[i*2] := Round(P8[i*2]*Diff);
|
||||
end else
|
||||
begin
|
||||
for i := 0 to (Result shr 1) -1 do
|
||||
P8[i*2+1] := Round(P8[i*2+1]*FBalance);
|
||||
end;
|
||||
end else
|
||||
begin
|
||||
P16 := Buffer;
|
||||
if FBalance > 0.5 then
|
||||
begin
|
||||
Diff := 1-Balance;
|
||||
for i := 0 to (Result shr 2) -1 do
|
||||
P16[i*2] := Round(P16[i*2]*Diff);
|
||||
end else
|
||||
begin
|
||||
for i := 0 to (Result shr 2) -1 do
|
||||
P16[i*2+1] := Round(P16[i*2+1]*FBalance);
|
||||
end;
|
||||
end;
|
||||
FPosition := Round(FSize/FInput.Size)*FInput.Position;
|
||||
end;
|
||||
|
||||
end.
|
674
acs/Src/classes/acs_file.pas
Normal file
674
acs/Src/classes/acs_file.pas
Normal file
@@ -0,0 +1,674 @@
|
||||
(*
|
||||
this file is a part of audio components suite.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
|
||||
$Log: acs_file.pas,v $
|
||||
Revision 1.11 2006/08/03 17:31:09 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.10 2006/07/09 16:40:34 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.9 2006/07/07 15:51:19 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.8 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.3 2006/01/01 18:46:40 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/26 17:31:38 z0m3ie
|
||||
fixed some problems in acs_dsfiles
|
||||
fixed some problems in acs_vorbis
|
||||
reworked all buffers
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.10 2005/12/18 17:01:54 z0m3ie
|
||||
delphi compatibility
|
||||
|
||||
Revision 1.9 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.8 2005/10/05 20:26:36 z0m3ie
|
||||
Linux changes
|
||||
|
||||
Revision 1.7 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.6 2005/09/15 20:59:38 z0m3ie
|
||||
start translate the documentation in the source for pasdoc
|
||||
|
||||
Revision 1.5 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.4 2005/09/13 20:14:25 z0m3ie
|
||||
driver handling classes (basic audio class)
|
||||
|
||||
Revision 1.3 2005/09/13 04:37:30 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/09/13 04:04:50 z0m3ie
|
||||
First release without Components for Fileformats
|
||||
only TFileIn and TFileOut are Visible
|
||||
*)
|
||||
|
||||
{
|
||||
@abstract(this unit introduces the base classes for acs)
|
||||
@author(Christian Ulrich (2005))
|
||||
|
||||
this unit introduces basic fileformat support
|
||||
}
|
||||
|
||||
unit acs_file;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, ACS_Classes, Dialogs, SysUtils, ACS_Strings;
|
||||
|
||||
type
|
||||
TACSFileInClass = class of TACSCustomFileIn;
|
||||
TACSFileOutClass = class of TACSCustomFileOut;
|
||||
|
||||
TACSFileCapTyp = (fcLoad,fcSave);
|
||||
TACSFileCapTyps = set of TACSFileCapTyp;
|
||||
|
||||
{ TACSFileFormat }
|
||||
|
||||
TACSFormatClass = class of TComponent;
|
||||
|
||||
TACSFileFormat = class
|
||||
public
|
||||
FileClass : TACSFormatClass;
|
||||
Extension : String;
|
||||
Description : String;
|
||||
end;
|
||||
|
||||
{ To this List all Filefomats must be added,
|
||||
use initialization section of your format units to add your format to acs
|
||||
so the user must only add your unit to the uses clausle to have support for
|
||||
your fileformat.
|
||||
}
|
||||
|
||||
{ tacsfileformatslist }
|
||||
|
||||
tacsfileformatslist = class (tlist)
|
||||
public
|
||||
destructor Destroy; override;
|
||||
procedure Add(const Ext, Desc: String; AClass: TACSFormatClass);
|
||||
function FindExt(ext : string;Typs : TACSFileCapTyps) : TACSFormatClass;
|
||||
function FindFromFileName(const fileName : String;Typs : TACSFileCapTyps) : TACSFormatClass;
|
||||
procedure Remove(AClass: TACSFormatClass);
|
||||
procedure BuildFilterStrings(var descriptions: String;Typs : TACSFileCapTyps);
|
||||
end;
|
||||
|
||||
{ This class is an wrapper for all fileformats
|
||||
}
|
||||
|
||||
{ TFileIn }
|
||||
|
||||
TACSFileIn = CLASS(TACSCustomFileIn)
|
||||
private
|
||||
FEndSample: Integer;
|
||||
FFileName: string;
|
||||
FInput : TACSCustomFileIn;
|
||||
FDialog : TOpenDialog;
|
||||
FLoop: Boolean;
|
||||
FStartSample: Integer;
|
||||
FTotalSamples: Integer;
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
function GetTime : Integer;
|
||||
function GetValid : Boolean;
|
||||
function GetTotalTime : real; override;
|
||||
procedure Reset; override;
|
||||
procedure SetFileName(const AValue : String);
|
||||
function GetSize : Integer;
|
||||
function GetPosition : Integer;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy;override;
|
||||
procedure Open;
|
||||
|
||||
procedure Flush; override;
|
||||
procedure Init; override;
|
||||
function Seek(SampleNum : Integer) : Boolean; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer;override;
|
||||
function SetStartTime(Minutes, Seconds : Integer) : Boolean;
|
||||
function SetEndTime(Minutes, Seconds : Integer) : Boolean;
|
||||
procedure Jump(Offs : real);
|
||||
property Time : Integer read GetTime;
|
||||
property TotalSamples : Integer read FTotalSamples;
|
||||
property Valid : Boolean read GetValid;
|
||||
property Size : Integer read GetSize;
|
||||
property Position : Integer read GetPosition;
|
||||
published
|
||||
property EndSample : Integer read FEndSample write FEndSample;
|
||||
property FileName : string read FFileName write SetFileName;
|
||||
property Loop : Boolean read FLoop write FLoop;
|
||||
property StartSample : Integer read FStartSample write FStartSample;
|
||||
end;
|
||||
|
||||
|
||||
{ This class is an wrapper for all fileformats
|
||||
}
|
||||
|
||||
{ TFileOut }
|
||||
|
||||
TACSFileOut = class(TComponent)
|
||||
private
|
||||
FBufferSize: Integer;
|
||||
FFileMode: TACSFileOutputMode;
|
||||
FFileName: string;
|
||||
FOnDone: TACSOutputDoneEvent;
|
||||
FOnProgress: TACSOutputProgressEvent;
|
||||
FOnThreadException: TACSThreadExceptionEvent;
|
||||
FOutput : TACSCustomFileOut;
|
||||
FDialog : TSaveDialog;
|
||||
FInput : TACSCustomInput;
|
||||
{$IFDEF LINUX}
|
||||
FAccessMask : Integer;
|
||||
{$ENDIF}
|
||||
function GetDelay: Integer;
|
||||
function GetPriority: TTPriority;
|
||||
function GetProgress: real;
|
||||
function GetStatus: TACSOutputStatus;
|
||||
function GetTE: Integer;
|
||||
procedure SetDelay(const AValue: Integer);
|
||||
procedure SetPriority(const AValue: TTPriority);
|
||||
|
||||
procedure ThreadException(Sender : TComponent;E : Exception);
|
||||
procedure OutputDone(Sender : TComponent);
|
||||
procedure OutputProgress(Sender : TComponent);
|
||||
protected
|
||||
FBaseChannel: Integer;
|
||||
procedure SetInput(vInput : TACSCustomInput);
|
||||
procedure Done;
|
||||
function DoOutput(Abort : Boolean):Boolean;
|
||||
procedure Prepare;
|
||||
procedure SetFileMode(aMode : TACSFileOutputMode); virtual;
|
||||
procedure SetFileName(const AValue: string);
|
||||
public
|
||||
destructor Destroy;override;
|
||||
procedure Open;
|
||||
property Buffersize : Integer read FBufferSize write FBufferSize;
|
||||
procedure Pause;virtual;
|
||||
procedure Resume;virtual;
|
||||
procedure Run;
|
||||
procedure Stop;
|
||||
property Delay : Integer read GetDelay write SetDelay;
|
||||
property ThreadPriority : TTPriority read GetPriority write SetPriority;
|
||||
property Progress : real read GetProgress;
|
||||
property Status : TACSOutputStatus read GetStatus;
|
||||
property TimeElapsed : Integer read GetTE;
|
||||
{$IFDEF LINUX}
|
||||
property AccessMask : Integer read FAccessMask write FAccessMask;
|
||||
{$ENDIF}
|
||||
published
|
||||
property FileMode : TACSFileOutputMode read FFileMode write SetFileMode;
|
||||
property FileName : string read FFileName write SetFileName;
|
||||
property Input : TACSCustomInput read FInput write SetInput;
|
||||
property OnDone : TACSOutputDoneEvent read FOnDone write FOndone;
|
||||
property OnProgress : TACSOutputProgressEvent read FOnProgress write FOnProgress;
|
||||
property OnThreadException : TACSThreadExceptionEvent read FOnThreadException write FOnThreadException;
|
||||
end;
|
||||
|
||||
var
|
||||
FileFormats : TACSFileFormatsList;
|
||||
|
||||
implementation
|
||||
|
||||
{ TFileIn }
|
||||
|
||||
function TACSFileIn.GetBPS: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetCh: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetSR: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetTime: Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.Time;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetValid: Boolean;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.Valid;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetTotalTime: real;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
exit;
|
||||
Result := FInput.TotalTime;
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.Reset;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FInput.Reset;
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.SetFileName(const AValue: string);
|
||||
begin
|
||||
FFileName := AValue;
|
||||
if Assigned(FInput) then
|
||||
FInput.Free;
|
||||
FInput := nil;
|
||||
if AValue = '' then
|
||||
exit;
|
||||
FInput := TACSFileInClass(FileFormats.FindFromFileName(AValue,[fcLoad])).Create(nil);
|
||||
if Assigned(FInput) then
|
||||
FInput.FileName := FFilename;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetSize: Integer;
|
||||
begin
|
||||
Result := 1;
|
||||
if Assigned(FInput) then
|
||||
Result := FInput.Size;
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetPosition: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
if Assigned(FInput) then
|
||||
Result := FInput.Position;
|
||||
end;
|
||||
|
||||
constructor TACSFileIn.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSFileIn.Destroy;
|
||||
begin
|
||||
if Assigned(FInput) then
|
||||
FInput.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.Open;
|
||||
var
|
||||
desc : string;
|
||||
begin
|
||||
FDialog := TOpenDialog.Create(nil);
|
||||
FileFormats.BuildFilterStrings(desc,[fcLoad]);
|
||||
FDialog.Filter := desc;
|
||||
if FDialog.Execute then
|
||||
begin
|
||||
if Assigned(FInput) then
|
||||
FInput.Free;
|
||||
FInput := TACSFileInClass(FileFormats.FindFromFileName(FDialog.FileName,[fcLoad])).Create(nil);
|
||||
FFileName := FDialog.FileName;
|
||||
if Assigned(FInput) then
|
||||
FInput.FileName := FFilename;
|
||||
end;
|
||||
FDialog.Free;
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.Flush;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FInput.Flush;
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FInput.Init;
|
||||
end;
|
||||
|
||||
function TACSFileIn.Seek(SampleNum : Integer): Boolean;
|
||||
begin
|
||||
if not Assigned(Finput) then
|
||||
EACSException.Create(strnoFileOpened);
|
||||
FInput.Seek(SampleNum);
|
||||
end;
|
||||
|
||||
function TACSFileIn.GetData(Buffer: Pointer; BufferSize: Integer): Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result:=FInput.GetData(Buffer, BufferSize);
|
||||
end;
|
||||
|
||||
function TACSFileIn.SetStartTime(Minutes, Seconds: Integer): Boolean;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.SetStartTime(Minutes,Seconds);
|
||||
end;
|
||||
|
||||
function TACSFileIn.SetEndTime(Minutes, Seconds: Integer): Boolean;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FInput.SetEndTime(Minutes,Seconds);
|
||||
end;
|
||||
|
||||
procedure TACSFileIn.Jump(Offs: real);
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FInput.Jump(Offs);
|
||||
end;
|
||||
|
||||
{ TACSFileOut }
|
||||
|
||||
procedure TACSFileOut.SetFileName(const AValue: string);
|
||||
begin
|
||||
if FFileName=AValue then exit;
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Free;
|
||||
FOutput := nil;
|
||||
FOutput := TACSFileOutClass(FileFormats.FindFromFileName(AValue,[fcSave])).Create(nil);
|
||||
if Assigned(FOutput) then
|
||||
begin
|
||||
FOutput.FileName:=AValue;
|
||||
foutput.FileMode := FFileMode; //GAK:20060731
|
||||
FOutput.Input := FInput;
|
||||
FOutput.OnDone := OutputDone;
|
||||
FOutput.OnProgress := OutputProgress;
|
||||
Foutput.OnThreadException := ThreadException;
|
||||
ffilename := avalue;//GAK:20060731
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Done;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Done;
|
||||
end;
|
||||
|
||||
function TACSFileOut.DoOutput(Abort: Boolean): Boolean;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FOutput.DoOutput(Abort);
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Prepare;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Prepare;
|
||||
end;
|
||||
|
||||
function TACSFileOut.GetDelay: Integer;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
result := FOutput.Delay;
|
||||
end;
|
||||
|
||||
function TACSFileOut.GetPriority: TTPriority;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FOutput.ThreadPriority;
|
||||
end;
|
||||
|
||||
function TACSFileOut.GetProgress: real;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FOutput.Progress;
|
||||
end;
|
||||
|
||||
function TACSFileOut.GetStatus: TACSOutputStatus;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FOutput.Status;
|
||||
end;
|
||||
|
||||
function TACSFileOut.GetTE: Integer;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
Result := FOutput.TimeElapsed;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.SetDelay(const AValue: Integer);
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Delay := AValue;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.SetPriority(const AValue: TTPriority);
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.ThreadPriority := AValue;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.ThreadException(Sender : TComponent;E: Exception);
|
||||
begin
|
||||
if Assigned(OnThreadException) then
|
||||
OnThreadException(Sender,E);
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.OutputDone(Sender: TComponent);
|
||||
begin
|
||||
if Assigned(OnDone) then
|
||||
OnDone(Sender);
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.OutputProgress(Sender: TComponent);
|
||||
begin
|
||||
if Assigned(OnProgress) then
|
||||
OnProgress(Sender);
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.SetInput(vInput: TACSCustomInput);
|
||||
begin
|
||||
FInput := vInput;
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Input := FInput;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.SetFileMode(aMode: TACSFileOutputMode);
|
||||
begin
|
||||
//GAK:20060731 changed whole of this method, as it was stopping component loading/creating
|
||||
if amode <> ffilemode then
|
||||
begin
|
||||
FFileMode := amode;
|
||||
if Assigned(FOutput) then FOutput.FileMode := aMode;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Open;
|
||||
var
|
||||
desc : string;
|
||||
|
||||
begin
|
||||
FDialog := TSaveDialog.Create(nil);
|
||||
FileFormats.BuildFilterStrings(desc,[fcSave]);
|
||||
FDialog.Filter := desc;
|
||||
if FDialog.Execute then
|
||||
begin
|
||||
FOutput := TACSFileOutClass(FileFormats.FindFromFileName(FDialog.FileName,[fcSave])).Create(nil);
|
||||
FileName := FDialog.FileName;
|
||||
foutput.FileMode := ffilemode;
|
||||
FOutput.Input := FInput;
|
||||
FInput := FInput;
|
||||
FOutput.OnDone := OutputDone;
|
||||
FOutput.OnProgress := OutputProgress;
|
||||
Foutput.OnThreadException := ThreadException;
|
||||
end;
|
||||
FDialog.Free;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Pause;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Pause;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Resume;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Resume;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Run;
|
||||
begin
|
||||
if not Assigned(FOutput) then
|
||||
raise EACSException.Create(strNoFileOpened);
|
||||
FOutput.Run;
|
||||
end;
|
||||
|
||||
procedure TACSFileOut.Stop;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Stop;
|
||||
end;
|
||||
|
||||
destructor TACSFileOut.Destroy;
|
||||
begin
|
||||
if Assigned(FOutput) then
|
||||
FOutput.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TACSFileFormatsList }
|
||||
|
||||
destructor tacsfileformatslist.Destroy;
|
||||
var
|
||||
i: integer;
|
||||
begin
|
||||
for i:= 0 to Count-1 do
|
||||
TACSFileFormat(Items[i]).Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSFileFormatsList.Add(const Ext, Desc: String;AClass: TACSFormatClass);
|
||||
var
|
||||
newRec : TACSFileFormat;
|
||||
begin
|
||||
newRec:=TACSFileFormat.Create;
|
||||
with newRec do
|
||||
begin
|
||||
Extension:=LowerCase(Ext);
|
||||
FileClass:=AClass;
|
||||
Description:=Desc;
|
||||
end;
|
||||
inherited Add(newRec);
|
||||
end;
|
||||
|
||||
function TACSFileFormatsList.FindExt(ext: string;Typs : TACSFileCapTyps): TACSFormatClass;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
ext:=LowerCase(ext);
|
||||
for i:=Count-1 downto 0 do
|
||||
with TACSFileFormat(Items[I]) do
|
||||
begin
|
||||
if ((fcLoad in Typs) and (TACSFileFormat(Items[I]).FileClass.InheritsFrom(TACSCustomFileIn))) or ((fcSave in Typs) and (TACSFileFormat(Items[I]).FileClass.InheritsFrom(TACSCustomFileOut))) then
|
||||
if Extension=ext then
|
||||
begin
|
||||
Result:=TACSFileFormat(Items[I]).FileClass;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result:=nil;
|
||||
end;
|
||||
|
||||
function TACSFileFormatsList.FindFromFileName(const fileName: String;Typs : TACSFileCapTyps): TACSFormatClass;
|
||||
var
|
||||
ext : String;
|
||||
begin
|
||||
ext:=ExtractFileExt(Filename);
|
||||
System.Delete(ext, 1, 1);
|
||||
Result:=FindExt(ext,Typs);
|
||||
if not Assigned(Result) then
|
||||
raise EACSException.CreateFmt(strUnknownExtension, [ext]);
|
||||
end;
|
||||
|
||||
procedure TACSFileFormatsList.Remove(AClass: TACSFormatClass);
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
for i:=Count-1 downto 0 do begin
|
||||
if TACSFileFormat(Items[i]).FileClass.InheritsFrom(AClass) then
|
||||
begin
|
||||
TACSFileFormat(Items[i]).Free;
|
||||
Delete(i);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSFileFormatsList.BuildFilterStrings(var descriptions : String;Typs : TACSFileCapTyps);
|
||||
var
|
||||
k, i : Integer;
|
||||
p : TACSFileFormat;
|
||||
filters : string;
|
||||
begin
|
||||
descriptions:='';
|
||||
filters := '';
|
||||
k:=0;
|
||||
for i:=0 to Count-1 do
|
||||
begin
|
||||
p:=TACSFileFormat(Items[i]);
|
||||
if ((fcLoad in Typs) and (p.FileClass.InheritsFrom(TACSCustomFileIn))) or ((fcSave in Typs) and (p.FileClass.InheritsFrom(TACSCustomFileOut))) then
|
||||
with p do
|
||||
begin
|
||||
if k<>0 then
|
||||
begin
|
||||
descriptions:=descriptions+'|';
|
||||
filters := filters+';';
|
||||
end;
|
||||
descriptions:=descriptions+Description+' (*.'+Extension+')|'+'*.'+Extension;
|
||||
filters := filters+'*.'+Extension;
|
||||
Inc(k);
|
||||
end;
|
||||
end;
|
||||
descriptions := strAllFormats+'|'+filters+'|'+descriptions;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
FileFormats := TACSFileFormatsList.Create;
|
||||
|
||||
finalization
|
||||
|
||||
FileFormats.Free;
|
||||
|
||||
end.
|
||||
|
772
acs/Src/classes/acs_filters.pas
Normal file
772
acs/Src/classes/acs_filters.pas
Normal file
@@ -0,0 +1,772 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_filters.pas,v $
|
||||
Revision 1.4 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
unit acs_filters;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Types, ACS_Procs, ACS_Classes, ACS_Strings, Math;
|
||||
|
||||
const
|
||||
BUF_SIZE = $4000;
|
||||
|
||||
type
|
||||
|
||||
TACSFilterType = (ftBandPass, ftBandReject, ftHighPass, ftLowPass, ftAllPass);
|
||||
|
||||
TACSBWFilter = class(TACSCustomConverter)
|
||||
private
|
||||
a3 : array[0..2] of Double;
|
||||
b2 : array[0..1] of Double;
|
||||
x0, x1, y0, y1 : array[0..1] of Double;
|
||||
FLowFreq, FHighFreq : Integer;
|
||||
FAmplification : Word;
|
||||
FFilterType : TACSFilterType;
|
||||
InBuf : array[1..BUF_SIZE] of Byte;
|
||||
procedure SetHighFreq(aFreq : Integer);
|
||||
procedure SetLowFreq(aFreq : Integer);
|
||||
procedure SetAmplification(Ampl : Word);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property Amplification : Word read FAmplification write SetAmplification;
|
||||
property FilterType : TACSFilterType read FFilterType write FFilterType;
|
||||
property HighFreq : Integer read FHighFreq write SetHighFreq;
|
||||
property LowFreq : Integer read FLowFreq write SetLowFreq;
|
||||
end;
|
||||
|
||||
TACSSincFilter = class(TACSCustomConverter)
|
||||
private
|
||||
Lock : Boolean;
|
||||
Kernel : array of Double;
|
||||
DA : PACSDoubleArray;
|
||||
DAS : PACSStereoBufferD;
|
||||
inBuf : array[1..BUF_SIZE] of Byte;
|
||||
FFilterType : TACSFilterType;
|
||||
FKernelWidth : Integer;
|
||||
FLowFreq, FHighFreq : Integer;
|
||||
FWindowType : TACSFilterWindowType;
|
||||
procedure SetFilterType(aFT : TACSFilterType);
|
||||
procedure SetKernelWidth(aKW : Integer);
|
||||
procedure SetWindowType(aWT : TACSFilterWindowType);
|
||||
procedure SetHighFreq(aFreq : Integer);
|
||||
procedure SetLowFreq(aFreq : Integer);
|
||||
procedure CalculateFilter;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
procedure GetKernel(var K : PACSDoubleArray);
|
||||
published
|
||||
property FilterType : TACSFilterType read FFilterType write SetFilterType;
|
||||
property HighFreq : Integer read FHighFreq write SetHighFreq;
|
||||
property KernelWidth : Integer read FKernelWidth write SetKernelWidth;
|
||||
property LowFreq : Integer read FLowFreq write SetLowFreq;
|
||||
property WindowType : TACSFilterWindowType read FWindowType write SetWindowType;
|
||||
end;
|
||||
|
||||
TACSConvolver = class(TACSCustomConverter)
|
||||
private
|
||||
Lock : Boolean;
|
||||
Kernel : array of Double;
|
||||
DA : PACSDoubleArray;
|
||||
DAS : PACSStereoBufferD;
|
||||
inBuf : array[1..BUF_SIZE] of Byte;
|
||||
FKernelWidth : Integer;
|
||||
FAllPass : Boolean;
|
||||
procedure SetKernelWidth(a : Integer);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
procedure SetKernel(K : PACSDoubleArray; Inverted : Boolean);
|
||||
property KrenelWidth : Integer read FKernelWidth write SetKernelWidth;
|
||||
published
|
||||
property AllPass : Boolean read FAllPass write FAllPass;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
constructor TACSBWFilter.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FFilterType := ftBandPass;
|
||||
FAmplification := 1;
|
||||
end;
|
||||
|
||||
destructor TACSBWFilter.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSBWFilter.GetBPS : Integer;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TACSBWFilter.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSBWFilter.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSBWFilter.SetHighFreq;
|
||||
begin
|
||||
if FFilterType = ftLowPass then
|
||||
FHighFreq := 0
|
||||
else FHighFreq := aFreq;
|
||||
end;
|
||||
|
||||
procedure TACSBWFilter.SetLowFreq;
|
||||
begin
|
||||
if FFilterType = ftHighPass then
|
||||
FLowFreq := 0
|
||||
else FLowFreq := aFreq;
|
||||
end;
|
||||
|
||||
procedure TACSBWFilter.SetAmplification;
|
||||
begin
|
||||
if Ampl > 0 then FAmplification := Ampl;
|
||||
end;
|
||||
|
||||
procedure TACSBWFilter.Init;
|
||||
var
|
||||
C, D : Double;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
if ((FHighFreq - FlowFreq) < 0) or (((FHighFreq - FlowFreq) * 2) >= FInput.SampleRate) then
|
||||
begin
|
||||
FInput.Flush;
|
||||
raise EACSException.Create(strIllegalFrequency);
|
||||
end;
|
||||
FBusy := True;
|
||||
FPosition := 0;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
FSize := FInput.Size;
|
||||
x0[0] := 0.0;
|
||||
x0[1] := 0.0;
|
||||
x1[0] := 0.0;
|
||||
x1[1] := 0.0;
|
||||
y0[0] := 0.0;
|
||||
y0[1] := 0.0;
|
||||
y1[0] := 0.0;
|
||||
y1[1] := 0.0;
|
||||
case FFilterType of
|
||||
ftBandPass :
|
||||
begin
|
||||
C := 1 / Tan(Pi * (FHighFreq-FLowFreq+1) / FInput.SampleRate);
|
||||
D := 2 * Cos(2 * Pi * ((FHighFreq+FLowFreq) shr 1) / FInput.SampleRate);
|
||||
a3[0] := 1 / (1 + C);
|
||||
a3[1] := 0.0;
|
||||
a3[2] := -a3[0];
|
||||
b2[0] := -C * D * a3[0];
|
||||
b2[1] := (C - 1) * a3[0];
|
||||
end;
|
||||
ftBandReject: // This doesn't seem to work well
|
||||
begin
|
||||
C := Tan(Pi * (FHighFreq-FLowFreq+1) / FInput.SampleRate);
|
||||
D := 2 * Cos(2 * Pi * ((FHighFreq+FLowFreq) shr 1) / FInput.SampleRate);
|
||||
a3[0] := 1 / (1 + C);
|
||||
a3[1] := -D * a3[0];
|
||||
a3[2] := a3[0];
|
||||
b2[0] := a3[1];
|
||||
b2[1] := (1 - C) * a3[0];
|
||||
end;
|
||||
ftLowPass:
|
||||
begin
|
||||
C := 1 / Tan(Pi * FLowFreq / FInput.SampleRate);
|
||||
a3[0] := 1 / (1 + Sqrt(2) * C + C * C);
|
||||
a3[1] := 2 * a3[0];
|
||||
a3[2] := a3[0];
|
||||
b2[0] := 2 * (1 - C * C) * a3[0];
|
||||
b2[1] := (1 - Sqrt(2) * C + C * C) * a3[0];
|
||||
end;
|
||||
ftHighPass:
|
||||
begin
|
||||
C := Tan(Pi * FHighFreq / FInput.SampleRate);
|
||||
a3[0] := 1 / (1 + Sqrt(2) * C + C * C);
|
||||
a3[1] := -2 * a3[0];
|
||||
a3[2] := a3[0];
|
||||
b2[0] := 2 * (C * C - 1) * a3[0];
|
||||
b2[1] := (1 - Sqrt(2) * C + C * C) * a3[0];
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSBWFilter.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSBWFilter.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
i : Integer;
|
||||
InBufMono : PACSBuffer16;
|
||||
InBufStereo : PACSStereoBuffer16;
|
||||
arg, res : Double;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
BufStart := 1;
|
||||
BufEnd := FInput.GetData(@InBuf[1], BUF_SIZE);
|
||||
if BufEnd = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if Self.Channels = 1 then
|
||||
begin
|
||||
InBufMono := @InBuf[1];
|
||||
for i := 0 to (BufEnd shr 1) - 1 do
|
||||
begin
|
||||
arg := InBufMono[i];
|
||||
res := a3[0] * arg + a3[1] * x0[0] + a3[2] * x1[0] -
|
||||
b2[0] * y0[0] - b2[1] * y1[0];
|
||||
InBufMono[i] := Round(res);
|
||||
x1[0] := x0[0];
|
||||
x0[0] := arg;
|
||||
y1[0] := y0[0];
|
||||
y0[0] := res;
|
||||
InBufMono[i] := FAmplification * InBufMono[i];
|
||||
end;
|
||||
end else
|
||||
begin
|
||||
InBufStereo := @InBuf[1];
|
||||
for i := 0 to (BufEnd shr 2) - 1 do
|
||||
begin
|
||||
arg := InBufStereo[i].Left;
|
||||
res := a3[0] * arg + a3[1] * x0[0] + a3[2] * x1[0] -
|
||||
b2[0] * y0[0] - b2[1] * y1[0];
|
||||
InBufStereo[i].Left := Round(res);
|
||||
x1[0] := x0[0];
|
||||
x0[0] := arg;
|
||||
y1[0] := y0[0];
|
||||
y0[0] := res;
|
||||
arg := InBufStereo[i].Right;
|
||||
res := a3[0] * arg + a3[1] * x0[1] + a3[2] * x1[1] -
|
||||
b2[0] * y0[1] - b2[1] * y1[1];
|
||||
InBufStereo[i].Right := Round(res);
|
||||
x1[1] := x0[1];
|
||||
x0[1] := arg;
|
||||
y1[1] := y0[1];
|
||||
y0[1] := res;
|
||||
InBufStereo[i].Right := FAmplification * InBufStereo[i].Right;
|
||||
InBufStereo[i].Left := FAmplification * InBufStereo[i].Left;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InBuf[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
// Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
constructor TACSSincFilter.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FKernelWidth := 31;
|
||||
FWindowType := fwBlackman;
|
||||
FLowFreq := 8000;
|
||||
FHighFreq := 16000;
|
||||
DA := nil;
|
||||
DAS := nil;
|
||||
end;
|
||||
|
||||
destructor TACSSincFilter.Destroy;
|
||||
begin
|
||||
Kernel := nil;
|
||||
if DA <> nil then FreeMem(DA);
|
||||
if DAS <> nil then FreeMem(DAS);
|
||||
Inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.CalculateFilter;
|
||||
var
|
||||
Kernel1, Kernel2 : array of Double;
|
||||
CutOff : Double;
|
||||
i, j : Integer;
|
||||
Sum : Double;
|
||||
begin
|
||||
if csDesigning in ComponentState then Exit;
|
||||
if not Assigned(FInput) then Exit;
|
||||
if (FLowFreq > FInput.SampleRate/2) or (FHighFreq > FInput.SampleRate/2) then
|
||||
raise EACSException.Create(strCutofftolow);
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
case FilterType of
|
||||
ftLowPass:
|
||||
begin
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
CutOff := FLowFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel[0], CutOff, FKernelWidth, FWindowType);
|
||||
end;
|
||||
ftHighPass:
|
||||
begin
|
||||
if not Odd(FKernelWidth) then Inc(FKernelWidth);
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
CutOff := FHighFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel[0], CutOff, FKernelWidth, FWindowType);
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel[i] := -Kernel[i];
|
||||
Kernel[(FKernelWidth shr 1)] := Kernel[(FKernelWidth shr 1)] + 1;
|
||||
end;
|
||||
ftBandPass:
|
||||
begin
|
||||
if not Odd(FKernelWidth) then Inc(FKernelWidth);
|
||||
SetLength(Kernel1, FKernelWidth);
|
||||
CutOff := FLowFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel1[0], CutOff, FKernelWidth, FWindowType);
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel1[i] := -Kernel1[i];
|
||||
Kernel1[(FKernelWidth shr 1)] := Kernel1[(FKernelWidth shr 1)] + 1;
|
||||
SetLength(Kernel2, FKernelWidth);
|
||||
CutOff := FHighFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel2[0], CutOff, FKernelWidth, FWindowType);
|
||||
SetLength(Kernel, 2*FKernelWidth);
|
||||
FillChar(Kernel[0], Length(Kernel)*SizeOf(Double), 0);
|
||||
for i := 0 to KernelWidth - 1 do
|
||||
for j := 0 to KernelWidth - 1 do
|
||||
Kernel[i+j] := Kernel[i+j] + Kernel1[i]*Kernel2[j];
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
Kernel1 := nil;
|
||||
Kernel2 := nil;
|
||||
end;
|
||||
ftBandReject:
|
||||
begin
|
||||
if not Odd(FKernelWidth) then Inc(FKernelWidth);
|
||||
SetLength(Kernel1, FKernelWidth);
|
||||
CutOff := FHighFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel1[0], CutOff, FKernelWidth, FWindowType);
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel1[i] := -Kernel1[i];
|
||||
Kernel1[(FKernelWidth shr 1)] := Kernel1[(FKernelWidth shr 1)] + 1;
|
||||
SetLength(Kernel2, FKernelWidth);
|
||||
CutOff := FLowFreq/FInput.SampleRate;
|
||||
CalculateSincKernel(@Kernel2[0], CutOff, FKernelWidth, FWindowType);
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel[i] := Kernel1[i] + Kernel2[i];
|
||||
Kernel1 := nil;
|
||||
Kernel2 := nil;
|
||||
end;
|
||||
ftAllPass :
|
||||
begin
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
FillChar(Kernel[0], Length(Kernel)*SizeOf(Double), 0);
|
||||
Kernel[FKernelWidth shr 1] := 1;
|
||||
end;
|
||||
end;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.SetFilterType;
|
||||
begin
|
||||
FFilterType := aFT;
|
||||
if Busy then CalculateFilter;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.SetKernelWidth;
|
||||
begin
|
||||
if aKW > 2 then
|
||||
if not Busy then FKernelWidth := aKW;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.SetWindowType;
|
||||
begin
|
||||
FWindowType := aWT;
|
||||
if Busy then CalculateFilter;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.SetHighFreq;
|
||||
begin
|
||||
if aFreq > 0 then
|
||||
FHighFreq := aFreq;
|
||||
if csDesigning in ComponentState then Exit;
|
||||
if Assigned(Finput) then
|
||||
if FHighFreq > Finput.SampleRate div 2 then
|
||||
FHighFreq := Finput.SampleRate div 2;
|
||||
if FHighFreq < FLowFreq then
|
||||
FLowFreq := FHighFreq;
|
||||
if Busy then CalculateFilter;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.SetLowFreq;
|
||||
begin
|
||||
if aFreq > 0 then
|
||||
FLowFreq := aFreq;
|
||||
if csDesigning in ComponentState then Exit;
|
||||
if Assigned(Finput) then
|
||||
if FlowFreq > Finput.SampleRate div 2 then
|
||||
FLowFreq := Finput.SampleRate div 2;
|
||||
if FHighFreq < FLowFreq then
|
||||
FHighFreq := FLowFreq;
|
||||
if Busy then CalculateFilter;
|
||||
end;
|
||||
|
||||
function TACSSincFilter.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSSincFilter.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSSincFilter.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.Init;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Lock := False;
|
||||
InputLock := False;
|
||||
FBusy := True;
|
||||
FInput.Init;
|
||||
FPosition := 0;
|
||||
CalculateFilter;
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
GetMem(DA, ((BUF_SIZE div 2)+FKernelWidth-1)*SizeOf(Double));
|
||||
FillChar(DA[0], ((BUF_SIZE div 2)+FKernelWidth-1)*SizeOf(Double), 0);
|
||||
end else
|
||||
begin
|
||||
GetMem(DAS, ((BUF_SIZE div 2)+(FKernelWidth-1)*2)*SizeOf(Double));
|
||||
FillChar(DAS[0], ((BUF_SIZE div 2)+(FKernelWidth-1)*2)*SizeOf(Double), 0);
|
||||
end;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
FSize := FInput.Size;
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
if DA <> nil then FreeMem(DA);
|
||||
if DAS <> nil then FreeMem(DAS);
|
||||
DA := nil;
|
||||
DAS := nil;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSSincFilter.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
i, j, NumSamples : Integer;
|
||||
InBufMono : PACSBuffer16;
|
||||
InBufStereo : PACSStereoBuffer16;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
BufStart := 1;
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
BufEnd := FInput.GetData(@InBuf[1], BUF_SIZE);
|
||||
InputLock := False;
|
||||
if BufEnd = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
InBufMono := @InBuf[1];
|
||||
NumSamples := BufEnd div 2;
|
||||
for i := 0 to NumSamples-1 do
|
||||
for j := 0 to FKernelWidth-1 do
|
||||
DA[i+j] := DA[i+j] + InbufMono[i]*Kernel[j];
|
||||
for i := 0 to NumSamples-1 do
|
||||
InBufMono[i] := Round(DA[i]);
|
||||
BufEnd := NumSamples*2;
|
||||
FillChar(DA[0], NumSamples*SizeOf(Double), 0);
|
||||
Move(DA[NumSamples], DA[0], (FKernelWidth-1)*SizeOf(Double));
|
||||
end else
|
||||
begin
|
||||
InBufStereo := @InBuf[1];
|
||||
NumSamples := BufEnd div 4;
|
||||
for i := 0 to NumSamples-1 do
|
||||
for j := 0 to FKernelWidth-1 do
|
||||
begin
|
||||
DAS[i+j].Left := DAS[i+j].Left + InbufStereo[i].Left*Kernel[j];
|
||||
DAS[i+j].Right := DAS[i+j].Right + InbufStereo[i].Right*Kernel[j];
|
||||
end;
|
||||
for i := 0 to NumSamples-1 do
|
||||
begin
|
||||
InBufStereo[i].Left := Round(DAS[i].Left);
|
||||
InBufStereo[i].Right := Round(DAS[i].Right);
|
||||
end;
|
||||
BufEnd := NumSamples*4;
|
||||
FillChar(DAS[0], NumSamples*2*SizeOf(Double), 0);
|
||||
for i := 0 to FKernelWidth-2 do
|
||||
begin
|
||||
DAS[i] := DAS[NumSamples+i];
|
||||
DAS[NumSamples+i].Left := 0;
|
||||
DAS[NumSamples+i].Right := 0;
|
||||
end;
|
||||
//Move(DAS[NumSamples], DAS[0], (FKernelWidth-1)*2*SizeOf(Double));
|
||||
end;
|
||||
Lock := False;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InBuf[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
end;
|
||||
|
||||
procedure TACSSincFilter.GetKernel;
|
||||
begin
|
||||
K := @Kernel[0];
|
||||
end;
|
||||
|
||||
constructor TACSConvolver.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FKernelWidth := 31;
|
||||
if csDesigning in ComponentState then Exit;
|
||||
SetLength(Kernel, FKernelWidth);
|
||||
FillChar(Kernel[1], Length(Kernel)*SizeOf(Double), 0);
|
||||
DA := nil;
|
||||
DAS := nil;
|
||||
end;
|
||||
|
||||
destructor TACSConvolver.Destroy;
|
||||
begin
|
||||
Kernel := nil;
|
||||
if DA <> nil then FreeMem(DA);
|
||||
if DAS <> nil then FreeMem(DAS);
|
||||
Inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSConvolver.SetKernelWidth;
|
||||
begin
|
||||
if a > 2 then
|
||||
if not Busy then FKernelWidth := a;
|
||||
end;
|
||||
|
||||
function TACSConvolver.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSConvolver.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSConvolver.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSConvolver.Init;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Lock := False;
|
||||
InputLock := False;
|
||||
FBusy := True;
|
||||
FInput.Init;
|
||||
FPosition := 0;
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
GetMem(DA, ((BUF_SIZE div 2)+FKernelWidth-1)*SizeOf(Double));
|
||||
FillChar(DA[0], ((BUF_SIZE div 2)+FKernelWidth-1)*SizeOf(Double), 0);
|
||||
end else
|
||||
begin
|
||||
GetMem(DAS, ((BUF_SIZE div 2)+(FKernelWidth-1)*2)*SizeOf(Double));
|
||||
FillChar(DAS[0], ((BUF_SIZE div 2)+(FKernelWidth-1)*2)*SizeOf(Double), 0);
|
||||
end;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
FSize := FInput.Size;
|
||||
end;
|
||||
|
||||
procedure TACSConvolver.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
if DA <> nil then FreeMem(DA);
|
||||
if DAS <> nil then FreeMem(DAS);
|
||||
DA := nil;
|
||||
DAS := nil;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSConvolver.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
i, j, NumSamples : Integer;
|
||||
InBufMono : PACSBuffer16;
|
||||
InBufStereo : PACSStereoBuffer16;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamNotopen);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
BufStart := 1;
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
BufEnd := FInput.GetData(@InBuf[1], BUF_SIZE);
|
||||
InputLock := False;
|
||||
if BufEnd = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if not FAllPass then
|
||||
begin
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
InBufMono := @InBuf[1];
|
||||
NumSamples := BufEnd div 2;
|
||||
for i := 0 to NumSamples-1 do
|
||||
for j := 0 to FKernelWidth-1 do
|
||||
DA[i+j] := DA[i+j] + InbufMono[i]*Kernel[j];
|
||||
for i := 0 to NumSamples-1 do
|
||||
InBufMono[i] := Round(DA[i]);
|
||||
BufEnd := NumSamples*2;
|
||||
FillChar(DA[0], NumSamples*SizeOf(Double), 0);
|
||||
Move(DA[NumSamples], DA[0], (FKernelWidth-1)*SizeOf(Double));
|
||||
end else
|
||||
begin
|
||||
InBufStereo := @InBuf[1];
|
||||
NumSamples := BufEnd div 4;
|
||||
for i := 0 to NumSamples-1 do
|
||||
for j := 0 to FKernelWidth-1 do
|
||||
begin
|
||||
DAS[i+j].Left := DAS[i+j].Left + InbufStereo[i].Left*Kernel[j];
|
||||
DAS[i+j].Right := DAS[i+j].Right + InbufStereo[i].Right*Kernel[j];
|
||||
end;
|
||||
for i := 0 to NumSamples-1 do
|
||||
begin
|
||||
InBufStereo[i].Left := Round(DAS[i].Left);
|
||||
InBufStereo[i].Right := Round(DAS[i].Right);
|
||||
end;
|
||||
BufEnd := NumSamples*4;
|
||||
FillChar(DAS[0], NumSamples*2*SizeOf(Double), 0);
|
||||
for i := 0 to FKernelWidth-2 do
|
||||
begin
|
||||
DAS[i] := DAS[NumSamples+i];
|
||||
DAS[NumSamples+i].Left := 0;
|
||||
DAS[NumSamples+i].Right := 0;
|
||||
end;
|
||||
//Move(DAS[NumSamples], DAS[0], (FKernelWidth-1)*2*SizeOf(Double));
|
||||
end;
|
||||
end;
|
||||
Lock := False;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(InBuf[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
FPosition := Round(FInput.Position*(FSize/FInput.Size));
|
||||
end;
|
||||
|
||||
procedure TACSConvolver.SetKernel;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
if not Inverted then
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel[i] := K[i]
|
||||
else
|
||||
for i := 0 to FKernelWidth - 1 do
|
||||
Kernel[i] := K[FKernelWidth - 1-i];
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
207
acs/Src/classes/acs_indicator.pas
Normal file
207
acs/Src/classes/acs_indicator.pas
Normal file
@@ -0,0 +1,207 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_indicator.pas,v $
|
||||
Revision 1.2 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:33 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
|
||||
unit acs_indicator;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, ACS_Types, ACS_Classes, ACS_Procs, ACS_Strings;
|
||||
|
||||
type
|
||||
|
||||
TACSSoundIndicator = class(TACSCustomConverter)
|
||||
private
|
||||
Lock : Boolean;
|
||||
Window : array[0..1023] of Double;
|
||||
FValues : array[0..31] of Double;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure GetValues(var Values : array of Double);
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
constructor TACSSoundIndicator.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
HannWindow(@Window, 1024, True);
|
||||
end;
|
||||
|
||||
destructor TACSSoundIndicator.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSSoundIndicator.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSSoundIndicator.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSSoundIndicator.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSSoundIndicator.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
FBusy := True;
|
||||
FInput.Init;
|
||||
FSize := FInput.Size;
|
||||
FillChar(FValues[0], SizeOf(Double)*32, 0);
|
||||
Lock := False;
|
||||
FPosition := 0;
|
||||
end;
|
||||
|
||||
procedure TACSSoundIndicator.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSSoundIndicator.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
i, j, k, NumSamples : Integer;
|
||||
P : Pointer;
|
||||
P8 : PACSBuffer8;
|
||||
P16 : PACSBuffer16;
|
||||
PS8 : PACSStereoBuffer8;
|
||||
PS16 : PACSStereoBuffer16;
|
||||
DA : array[0..63] of Double;
|
||||
C1 : array[0..63] of TACSComplex;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
Result := FInput.GetData(Buffer, BufferSize);
|
||||
InputLock := False;
|
||||
FPosition := Finput.Position;
|
||||
if Result = 0 then Exit;
|
||||
if Lock then Exit;
|
||||
Lock := True;
|
||||
k := Result;
|
||||
GetMem(P, k);
|
||||
Move(Buffer^, P^, k);
|
||||
if FInput.BitsPerSample = 8 then
|
||||
begin
|
||||
if FInput.Channels = 1 then NumSamples := k
|
||||
else NumSamples := k shr 1;
|
||||
end else
|
||||
begin
|
||||
if FInput.Channels = 1 then NumSamples := k shr 1
|
||||
else NumSamples := k shr 2;
|
||||
end;
|
||||
for i := 0 to (NumSamples div 64) - 1 do
|
||||
begin
|
||||
if FInput.BitsPerSample = 8 then
|
||||
begin
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
P8 := P;
|
||||
for j := 0 to 63 do DA[j] := P8[i*64+j];
|
||||
end else
|
||||
begin
|
||||
PS8 := P;
|
||||
for j := 0 to 63 do DA[j] := (PS8[i*64+j].Left+PS8[i*64+j].Right)/2;
|
||||
end
|
||||
end else
|
||||
begin
|
||||
if FInput.Channels = 1 then
|
||||
begin
|
||||
P16 := P;
|
||||
for j := 0 to 63 do DA[j] := P16[i*64+j];
|
||||
end else
|
||||
begin
|
||||
PS16 := P;
|
||||
for j := 0 to 63 do DA[j] := (PS16[i*64+j].Left+PS16[i*64+j].Right)/2;
|
||||
end
|
||||
end;
|
||||
MultDoubleArrays(@Window[0], @DA[0], 64);
|
||||
for j := 0 to 63 do
|
||||
begin
|
||||
C1[j].Re := DA[j];
|
||||
C1[j].Im := 0;
|
||||
end;
|
||||
ComplexFFT(@C1, 64, 1);
|
||||
LgMagnitude(@C1[0], @DA[0], 64, 0);
|
||||
try
|
||||
for j := 0 to 31 do FValues[j]:=FValues[j]+DA[j];
|
||||
except
|
||||
for j := 0 to 31 do FValues[j] := 0;
|
||||
end;
|
||||
end;
|
||||
for j := 0 to 31 do FValues[j]:=FValues[j]/(NumSamples div 64);
|
||||
FreeMem(P);
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
procedure TACSSoundIndicator.GetValues;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
for i := 0 to 31 do Values[i] := FValues[i]*0.4; //ValCount;
|
||||
for i := 0 to 31 do FValues[i] := 0;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
end.
|
547
acs/Src/classes/acs_misc.pas
Normal file
547
acs/Src/classes/acs_misc.pas
Normal file
@@ -0,0 +1,547 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_misc.pas,v $
|
||||
Revision 1.4 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.2 2005/09/13 04:04:50 z0m3ie
|
||||
First release without Components for Fileformats
|
||||
only TFileIn and TFileOut are Visible
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.9 2005/09/07 20:53:22 z0m3ie
|
||||
begon to add MPEG and WMA support using DirectX
|
||||
|
||||
Revision 1.8 2005/09/04 17:59:37 z0m3ie
|
||||
moving CDIn support to AKRip mostly
|
||||
begon to add mpegin support for Win with mpg123
|
||||
|
||||
Revision 1.7 2005/08/28 18:35:53 z0m3ie
|
||||
created Delphi package for 2.4
|
||||
more Mixer stuff
|
||||
updated some things for Delphi
|
||||
|
||||
Revision 1.6 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
unit acs_misc;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Types, ACS_Classes, ACS_Strings
|
||||
{$IFDEF LINUX}
|
||||
,baseunix, LibAO
|
||||
{$ENDIF};
|
||||
|
||||
const
|
||||
BUF_SIZE = $4000;
|
||||
|
||||
type
|
||||
TACSOnBufferDone = procedure(Sender : TComponent) of object;
|
||||
|
||||
TACSAudioProcessorInitEvent = procedure(Sender : TComponent; var TotalSize : Integer) of object;
|
||||
TACSAudioProcessorFlushEvent = procedure(Sender : TComponent) of object;
|
||||
|
||||
TACSGetParameterEvent = procedure(Sender : TComponent; var Param : Integer) of object;
|
||||
|
||||
TACSGetRealParameterEvent = procedure(Sender : TComponent; var Param : real) of object;
|
||||
|
||||
TACSGetDataEvent = procedure(Sender : TComponent; Data : Pointer; var n : Integer) of object;
|
||||
|
||||
TACSMemoryIn = class(TACSCustomInput)
|
||||
private
|
||||
FBuffer : PACSBuffer8;
|
||||
FDataSize : Integer;
|
||||
FOnBufferDone : TACSOnBufferDone;
|
||||
Busy : Boolean;
|
||||
BufStart, BufEnd : Integer;
|
||||
FBPS, FSR, FChan : Integer;
|
||||
function GetBuffer : Pointer;
|
||||
procedure SetBuffer(v : Pointer);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
property DataBuffer : Pointer read GetBuffer write SetBuffer;
|
||||
property DataSize : Integer read FDataSize write FDataSize;
|
||||
published
|
||||
property GlobalSize : Integer read FSize write FSize;
|
||||
property InBitsPerSample : Integer read GetBPS write FBPS;
|
||||
property InChannels : Integer read GetCh write FChan;
|
||||
property InSampleRate : Integer read GetSR write FSR;
|
||||
property OnBufferDone : TACSOnBufferDone read FOnBufferDone write FOnBufferDone;
|
||||
end;
|
||||
|
||||
TACSAudioProcessor = class(TACSCustomConverter)
|
||||
private
|
||||
FOnInit : TACSAudioProcessorInitEvent;
|
||||
FOnFlush : TACSAudioProcessorFlushEvent;
|
||||
FOnGetData : TACSGetDataEvent;
|
||||
FOnGetSampleRate : TACSGetParameterEvent;
|
||||
FOnGetBitsPerSample : TACSGetParameterEvent;
|
||||
FOnGetChannels : TACSGetParameterEvent;
|
||||
FOnGetTotalTime : TACSGetRealParameterEvent;
|
||||
FOnGetSize : TACSGetParameterEvent;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
function GetTotalTime : real; override;
|
||||
public
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property OnFlush : TACSAudioProcessorFlushEvent read FOnFlush write FOnFlush;
|
||||
property OnGetBitsPerSample : TACSGetParameterEvent read FOnGetBitsPerSample write FOnGetBitsPerSample;
|
||||
property OnGetChannels : TACSGetParameterEvent read FOnGetChannels write FOnGetChannels;
|
||||
property OnGetData : TACSGetDataEvent read FOnGetData write FOnGetData;
|
||||
property OnGetSampleRate : TACSGetParameterEvent read FOnGetSampleRate write FOnGetSampleRate;
|
||||
property OnGetSize : TACSGetParameterEvent read FOnGetSize write FOnGetSize;
|
||||
property OnGetTotalTime : TACSGetrealParameterEvent read FOnGetTotalTime write FOnGetTotalTime;
|
||||
property OnInit : TACSAudioProcessorInitEvent read FOnInit write FOnInit;
|
||||
end;
|
||||
|
||||
TACSNULLOut = class(TACSCustomOutput)
|
||||
private
|
||||
Buf : array[0..BUF_SIZE-1] of Byte;
|
||||
protected
|
||||
procedure Done; override;
|
||||
function DoOutput(Abort : Boolean):Boolean; override;
|
||||
procedure Prepare; override;
|
||||
end;
|
||||
|
||||
TACSInputItem = class(TCollectionItem)
|
||||
protected
|
||||
FInput : TACSCustomInput;
|
||||
function GetOwner : TPersistent; override;
|
||||
published
|
||||
property Input : TACSCustomInput read FInput write FInput;
|
||||
end;
|
||||
|
||||
TACSInputItems = class(TOwnedCollection)
|
||||
end;
|
||||
|
||||
TACSInputChangedEvent = procedure(Sender : TComponent; var Index : Integer; var Continue : Boolean) of object;
|
||||
|
||||
TACSInputList = class(TACSCustomInput)
|
||||
private
|
||||
FCurrentInput : Integer;
|
||||
FInputItems : TACSInputItems;
|
||||
Lock : Boolean;
|
||||
FOnInputChanged : TACSInputChangedEvent;
|
||||
FIndicateProgress : Boolean;
|
||||
procedure SetCurrentInput(aInput : Integer);
|
||||
procedure SetInputItems(aItems : TACSInputItems);
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
property CurrentInput : Integer read FCurrentInput write SetCurrentInput;
|
||||
published
|
||||
property IndicateProgress : Boolean read FIndicateProgress write FIndicateProgress;
|
||||
property InputItems : TACSInputItems read FInputItems write SetInputItems;
|
||||
property OnInputChanged : TACSInputChangedEvent read FOnInputChanged write FOnInputChanged;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF LINUX}
|
||||
|
||||
var
|
||||
AOInitialized : Integer = 0;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
constructor TACSMemoryIn.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FSize := -1;
|
||||
end;
|
||||
|
||||
destructor TACSMemoryIn.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSMemoryIn.GetBPS : Integer;
|
||||
begin
|
||||
if (FBPS in [8, 16]) = False then FBPS := 16;
|
||||
Result := FBPS;
|
||||
end;
|
||||
|
||||
function TACSMemoryIn.GetCh : Integer;
|
||||
begin
|
||||
if (FChan in [1..2]) = False then FChan := 1;
|
||||
Result := FChan;
|
||||
end;
|
||||
|
||||
function TACSMemoryIn.GetSR : Integer;
|
||||
begin
|
||||
if (FSR < 4000) or (FSR > 48000) then FSR := 8000;
|
||||
Result := FSR;
|
||||
end;
|
||||
|
||||
procedure TACSMemoryIn.Init;
|
||||
begin
|
||||
FPosition := 0;
|
||||
BufEnd := FDataSize;
|
||||
BufStart := 1;
|
||||
Busy := True;
|
||||
end;
|
||||
|
||||
procedure TACSMemoryIn.Flush;
|
||||
begin
|
||||
Busy := False;
|
||||
FDataSize := 0;
|
||||
end;
|
||||
|
||||
function TACSMemoryIn.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
if not Assigned(FBuffer) then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
BufStart := 1;
|
||||
if FDataSize = 0 then
|
||||
begin
|
||||
if Assigned(FOnBufferDone) then FOnBufferDone(Self)
|
||||
else
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
BufEnd := FDataSize;
|
||||
if FDataSize = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(FBuffer[BufStart-1], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
Inc(FPosition, Result);
|
||||
Dec(FDataSize, Result);
|
||||
end;
|
||||
|
||||
function TACSMemoryIn.GetBuffer : Pointer;
|
||||
begin
|
||||
Result := Pointer(FBuffer);
|
||||
end;
|
||||
|
||||
procedure TACSMemoryIn.SetBuffer;
|
||||
begin
|
||||
FBuffer := PACSBuffer8(v);
|
||||
end;
|
||||
|
||||
function TACSAudioProcessor.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnGetBitsPerSample) then FOnGetBitsPerSample(Self, Result) else
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSAudioProcessor.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnGetSampleRate) then FOnGetSampleRate(Self, Result) else
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
function TACSAudioProcessor.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnGetChannels) then FOnGetChannels(Self, Result) else
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSAudioProcessor.GetTotalTime : real;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnGetTotalTime) then FOnGetTotalTime(Self, Result) else
|
||||
Result := FInput.TotalTime;
|
||||
end;
|
||||
|
||||
function TACSAudioProcessor.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := BufferSize;
|
||||
if Assigned(FOnGetData) then FOnGetData(Self, Buffer, Result)
|
||||
else Result := FInput.GetData(Buffer, BufferSize);
|
||||
Inc(FPosition, Result);
|
||||
// if Result = 0 then
|
||||
// Result := Result shl 1;
|
||||
end;
|
||||
|
||||
procedure TACSAudioProcessor.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnInit) then FOnInit(Self, FSize)
|
||||
else
|
||||
begin
|
||||
FInput.Init;
|
||||
if Assigned(FOnGetSize) then FOnGetSize(Self, FSize)
|
||||
else FSize := Finput.Size;
|
||||
end;
|
||||
FBusy := True;
|
||||
FPosition := 0;
|
||||
end;
|
||||
|
||||
procedure TACSAudioProcessor.Flush;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
if Assigned(FOnFlush) then FOnFlush(Self)
|
||||
else FInput.Flush;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
procedure TACSNULLOut.Prepare;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
FInput.Init;
|
||||
end;
|
||||
|
||||
function TACSNULLOut.DoOutput(Abort : Boolean):Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
if not Busy then Exit;
|
||||
if Abort or (not CanOutput) then
|
||||
begin
|
||||
Result := False;
|
||||
Exit;
|
||||
end;
|
||||
if Finput.GetData(@Buf[0], BUF_SIZE) > 0 then Result := True
|
||||
else
|
||||
begin
|
||||
Result := False;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSNULLOut.Done;
|
||||
begin
|
||||
FInput.Flush;
|
||||
end;
|
||||
|
||||
function TACSInputItem.GetOwner : TPersistent;
|
||||
begin
|
||||
Result := Collection;
|
||||
end;
|
||||
|
||||
constructor TACSInputList.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FInputItems := TACSInputItems.Create(Self, TACSInputItem);
|
||||
FPosition := 0;
|
||||
FSize := -1;
|
||||
FIndicateProgress := True;
|
||||
end;
|
||||
|
||||
destructor TACSInputList.Destroy;
|
||||
begin
|
||||
FInputItems.Free;
|
||||
Inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSInputList.SetCurrentInput;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
if aInput <> 0 then
|
||||
if (aInput < 0) or (aInput >= FInputItems.Count) then
|
||||
raise EACSException.Create(Format(strListIndexOOB,[aInput]));
|
||||
if Busy then
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
I.Input.Flush;
|
||||
I := TACSInputItem(InputItems.Items[aInput]);
|
||||
I.Input.Init;
|
||||
if FIndicateProgress then
|
||||
FSize := I.Input.Size
|
||||
else FSize := -1;
|
||||
FPosition := 0;
|
||||
Lock := False;
|
||||
end;
|
||||
FCurrentInput := aInput;
|
||||
end;
|
||||
|
||||
function TACSInputList.GetBPS : Integer;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
if Busy then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
Result := I.Input.BitsPerSample;
|
||||
end else
|
||||
if InputItems.Count > 0 then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[0]);
|
||||
Result := I.Input.BitsPerSample;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSInputList.GetCh : Integer;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
if Busy then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
Result := I.Input.Channels;
|
||||
end else
|
||||
if InputItems.Count > 0 then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[0]);
|
||||
Result := I.Input.Channels;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSInputList.GetSR : Integer;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
if Busy then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
Result := I.Input.SampleRate;
|
||||
end else
|
||||
if InputItems.Count > 0 then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[0]);
|
||||
Result := I.Input.SampleRate;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSInputList.Init;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
if Busy then
|
||||
raise EACSException.Create(strBusy);
|
||||
if InputItems.Count = 0 then
|
||||
raise EACSException.Create(strNoInputItems);
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
if not Assigned(I.Input) then
|
||||
raise EACSException.Create(Format(strNoInputAssigned,[FCurrentInput]));
|
||||
FBusy := True;
|
||||
I.Input.Init;
|
||||
if FIndicateProgress then
|
||||
FSize := I.Input.Size
|
||||
else FSize := -1;
|
||||
FPosition := 0;
|
||||
end;
|
||||
|
||||
procedure TACSInputList.Flush;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
I.Input.Flush;
|
||||
FCurrentInput := 0;
|
||||
Lock := False;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSInputList.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
I : TACSInputItem;
|
||||
Continue : Boolean;
|
||||
begin
|
||||
while Lock do;
|
||||
Lock := True;
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
Result := I.Input.GetData(Buffer, BufferSize);
|
||||
while Result = 0 do
|
||||
begin
|
||||
if FCurrentInput < InputItems.Count -1 then
|
||||
begin
|
||||
I.Input.Flush;
|
||||
Inc(FCurrentInput);
|
||||
Continue := True;
|
||||
if Assigned(FonInputChanged) then
|
||||
FonInputChanged(Self, FCurrentInput, Continue);
|
||||
if Continue then
|
||||
begin
|
||||
I := TACSInputItem(InputItems.Items[FCurrentInput]);
|
||||
if not Assigned(I.Input) then
|
||||
raise EACSException.Create(Format(strNoInputAssigned,[FCurrentInput]));
|
||||
I.Input.Init;
|
||||
if FIndicateProgress then
|
||||
FSize := I.Input.Size
|
||||
else FSize := -1;
|
||||
FPosition := 0;
|
||||
Result := I.Input.GetData(Buffer, BufferSize);
|
||||
end else Break;
|
||||
end else Break;
|
||||
end;
|
||||
if FIndicateProgress then
|
||||
FPosition := I.Input.Position;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
procedure TACSInputList.SetInputItems;
|
||||
begin
|
||||
FInputItems.Assign(aItems);
|
||||
end;
|
||||
end.
|
262
acs/Src/classes/acs_mixer.pas
Normal file
262
acs/Src/classes/acs_mixer.pas
Normal file
@@ -0,0 +1,262 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.4.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_mixer.pas,v $
|
||||
Revision 1.2 2005/12/30 12:54:42 z0m3ie
|
||||
some error checks
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.2 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.11 2005/09/01 19:55:48 z0m3ie
|
||||
again Delphi corrections
|
||||
|
||||
Revision 1.10 2005/08/31 20:30:39 z0m3ie
|
||||
Mixer Channelname work now
|
||||
minior corrections for Converters
|
||||
|
||||
Revision 1.9 2005/08/31 14:37:59 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.8 2005/08/31 14:33:16 z0m3ie
|
||||
fixed delphi issue with TControlEntry
|
||||
|
||||
Revision 1.7 2005/08/30 22:10:55 z0m3ie
|
||||
Mixer mostly completed
|
||||
|
||||
Revision 1.6 2005/08/29 21:46:43 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.5 2005/08/28 20:31:18 z0m3ie
|
||||
linux restructuring for 2.4
|
||||
|
||||
Revision 1.4 2005/08/28 18:35:53 z0m3ie
|
||||
created Delphi package for 2.4
|
||||
more Mixer stuff
|
||||
updated some things for Delphi
|
||||
|
||||
Revision 1.3 2005/08/26 17:12:56 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/08/26 17:03:20 z0m3ie
|
||||
begon to make acs resourcestring aware
|
||||
more advanced tmixer for windows
|
||||
restructured tmixer its better handleable now
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
|
||||
unit acs_mixer;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Classes, ACS_Strings
|
||||
{$IFDEF MSWINDOWS}
|
||||
,MMSystem,Windows,Dialogs
|
||||
,Math
|
||||
{$ELSE}
|
||||
,Soundcard, baseunix
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
type
|
||||
TACSMixerChannel = (mcUnknown,
|
||||
mcVolume,
|
||||
mcTreble,
|
||||
mcBass,
|
||||
mcSynth,
|
||||
mcPCM,
|
||||
mcSpeaker,
|
||||
mcLine,
|
||||
mcMic,
|
||||
mcCD,
|
||||
mcIMix,
|
||||
mcAltPCM,
|
||||
mcRecLev,
|
||||
mcDigital,
|
||||
mcMonitor,
|
||||
mcHeadphone,
|
||||
mcTelephone);
|
||||
|
||||
{$IFDEF MSWINDOWS}
|
||||
const
|
||||
FirstSource = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED - MIXERLINE_COMPONENTTYPE_SRC_FIRST ;
|
||||
LastSource = MIXERLINE_COMPONENTTYPE_SRC_ANALOG - MIXERLINE_COMPONENTTYPE_SRC_FIRST ;
|
||||
FirstDest = MIXERLINE_COMPONENTTYPE_DST_FIRST;
|
||||
LastDest = MIXERLINE_COMPONENTTYPE_DST_LAST;
|
||||
|
||||
type
|
||||
{$IFDEF LCL}
|
||||
TMixerLine = MIXERLINE;
|
||||
TMixerCaps = MIXERCAPS;
|
||||
TMixerControl = MIXERCONTROL;
|
||||
TMixerLineControls = MIXERLINECONTROLS;
|
||||
TMixerControlDetails = MIXERCONTROLDETAILS;
|
||||
{$ENDIF}
|
||||
|
||||
TDataArray = ARRAY[FirstSource .. LastSource] OF MIXERCONTROLDETAILS_UNSIGNED;
|
||||
PDataArray = ^TDataArray;
|
||||
PControlEntry = ^TControlEntry;
|
||||
TControlEntry = RECORD
|
||||
IsInited : Boolean;
|
||||
CHandle : Thandle;
|
||||
CDestination : INTEGER;
|
||||
CID : INTEGER;
|
||||
CName : String[MIXER_SHORT_NAME_CHARS];
|
||||
CConnect : INTEGER;
|
||||
CCControls : INTEGER;
|
||||
CControlTyp : INTEGER;
|
||||
CKanal : INTEGER;
|
||||
CControl : INTEGER;
|
||||
CComponentTyp : DWORD;
|
||||
CMin, Cmax : INTEGER;
|
||||
Cdetails : TDataArray;
|
||||
CMultItems : INTEGER;
|
||||
CcSteps : DWORD;
|
||||
END;
|
||||
{$ENDIF}
|
||||
|
||||
TACSMixerLevel = record
|
||||
case Word of
|
||||
1 :
|
||||
(
|
||||
Left, Right : Byte;
|
||||
);
|
||||
2 : (Main : Byte;);
|
||||
end;
|
||||
|
||||
{ TACSMixer }
|
||||
|
||||
TACSMixer = class(TComponent)
|
||||
private
|
||||
FDevNum : Integer;
|
||||
FChannels : array of TACSMixerChannel;
|
||||
{$IFDEF LINUX}
|
||||
_mix_fd : Integer;
|
||||
FFileName : String;
|
||||
{$ELSE}
|
||||
FMixer : HMixer;
|
||||
FMixerCaps : TMixerCaps;
|
||||
FControls : array of TControlEntry;
|
||||
FMuteControls : array of TControlEntry;
|
||||
{$ENDIF}
|
||||
FMixerName : String;
|
||||
function GetRecSource : Integer;
|
||||
function GetVolume(vChannel : integer) : TACSMixerLevel;
|
||||
procedure SetVolume(vChannel : integer; vLevel : TACSMixerLevel);
|
||||
procedure SetRecSource(vChannel : integer);
|
||||
procedure SetDevNum(Num : Integer);
|
||||
function GetChannel(Num : Integer) : TACSMixerChannel;
|
||||
function GetDevCount : Integer;
|
||||
function GetChannelCount : Integer;
|
||||
function GetChannelName(vChannel : Integer) : string;
|
||||
function GetMute(vChannel : integer) : Boolean;
|
||||
procedure SetMute(vChannel : integer; Mute : Boolean);
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function IsStereo(vChannel : Integer) : Boolean;
|
||||
function IsRecordable(vChannel : Integer) : Boolean;
|
||||
property Channel[vChannel : Integer] : TACSMixerChannel read GetChannel;
|
||||
property Level[vChannel : Integer] : TACSMixerLevel read GetVolume write SetVolume;
|
||||
property Mute[vChannels : Integer] : Boolean read GetMute write SetMute;
|
||||
property ChannelName[vChannel : Integer] : string read GetChannelName;
|
||||
property RecordSource : Integer read GetRecSource write SetRecSource;
|
||||
property DevCount : Integer read GetDevCount;
|
||||
property Channelcount : Integer read GetChannelCount;
|
||||
published
|
||||
property DevNum : Integer read FDevNum write SetDevNum stored True;
|
||||
property MixerName : String read FMixerName;
|
||||
end;
|
||||
|
||||
var
|
||||
MixersCount : Byte;
|
||||
|
||||
function ChannelToStr(ch : TACSMixerChannel) : String;
|
||||
|
||||
implementation
|
||||
|
||||
{$I ACS_Mixer.inc}
|
||||
|
||||
function ChannelToStr(ch : TACSMixerChannel) : String;
|
||||
begin
|
||||
case ch of
|
||||
mcVolume: Result := strMixerVolume;
|
||||
mcTreble: Result := strMixerTreble;
|
||||
mcBass: Result := strMixerBass;
|
||||
mcSynth: Result := strMixerSynth;
|
||||
mcPCM: Result := strMixerPCM;
|
||||
mcSpeaker: Result := strMixerSpeaker;
|
||||
mcLine: Result := strMixerLine;
|
||||
mcMic: Result := strMixerMic;
|
||||
mcCD: Result := strMixerCD;
|
||||
mcIMix: Result := strMixerIMix;
|
||||
mcAltPCM: Result := strMixerAlt;
|
||||
mcRecLev: Result := strMixerRec;
|
||||
mcUnknown: Result := strMixerUnknown;
|
||||
else Result := IntToStr(Integer(ch));
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TACSMixer.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
if MixersCount > 0 then
|
||||
SetDevNum(0);
|
||||
end;
|
||||
|
||||
function TACSMixer.GetChannel(Num: Integer): TACSMixerChannel;
|
||||
begin
|
||||
if (Num < 0) or (Num > (length(FChannels)-1)) then
|
||||
exit;
|
||||
Result := FChannels[Num];
|
||||
end;
|
||||
|
||||
function TACSMixer.GetDevCount : Integer;
|
||||
begin
|
||||
Result := MixersCount;
|
||||
end;
|
||||
|
||||
function TACSMixer.GetChannelCount : Integer;
|
||||
begin
|
||||
result := length(FChannels);
|
||||
end;
|
||||
|
||||
function TACSMixer.GetChannelName(vChannel : Integer) : string;
|
||||
begin
|
||||
if (vChannel > -1) and (vChannel < ChannelCount) then
|
||||
Result := ChannelToStr(FChannels[vChannel]);
|
||||
end;
|
||||
|
||||
initialization
|
||||
MixersCount := CountMixers;
|
||||
end.
|
299
acs/Src/classes/acs_multimix.pas
Normal file
299
acs/Src/classes/acs_multimix.pas
Normal file
@@ -0,0 +1,299 @@
|
||||
(*
|
||||
this file is a part of audio components suite,
|
||||
copyright (c) 2005 ross levis. all rights reserved.
|
||||
see the license file for more details.
|
||||
|
||||
TMultiMixer provides for an unlimited number of inputs (channels)
|
||||
to be mixed into one audio buffer. Only supports 44100/16/2
|
||||
|
||||
TMultiMixer
|
||||
- property TotalChannels: Integer; // get/set the number of channels
|
||||
- property Channel[Index: Integer]: TChannel; default
|
||||
TChannel
|
||||
- procedure Preload; // runs Input.Init to make starting faster (optional)
|
||||
- procedure Start; // Start channel
|
||||
- procedure Stop; // Stop channel
|
||||
- property Input: TACSInput
|
||||
- property Volume: Word; // 0 = silent, 32768 = 100%
|
||||
|
||||
eg.
|
||||
MultiMixer.TotalChannels := 1;
|
||||
MultiMixer[0].Input := VorbisIn1;
|
||||
AudioOut1.Run;
|
||||
MultiMixer.TotalChannels := 2; // Channels can be added or removed while playing
|
||||
MultiMixer[1].Input := WAVEIn1;
|
||||
MultiMixer[1].Volume := 16384; // 50% volume
|
||||
MultiMixer[1].Start; // while at least 1 mixer is playing, others
|
||||
MultiMixer[0].Stop; // can be started and stopped individually.
|
||||
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_multimix.pas,v $
|
||||
Revision 1.3 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.1 2005/08/25 21:02:31 z0m3ie
|
||||
TMultiMixer by Ross Levis added
|
||||
|
||||
}
|
||||
|
||||
{$hints off}
|
||||
unit acs_multimix;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Types, ACS_Classes, ACS_Strings;
|
||||
|
||||
const
|
||||
BUF_SIZE = 8820;
|
||||
|
||||
type
|
||||
TACSMultiMixer = class;
|
||||
|
||||
TACSChannel = class
|
||||
private
|
||||
FOwner: TACSMultiMixer;
|
||||
FInput: TACSCustomInput;
|
||||
FVolume: Word;
|
||||
EndOfInput: Boolean;
|
||||
Preloaded: Boolean;
|
||||
InBuf: array[1..BUF_SIZE] of Byte;
|
||||
public
|
||||
constructor Create(AOwner: TACSMultiMixer); virtual;
|
||||
destructor Destroy; override;
|
||||
procedure Preload;
|
||||
procedure Start;
|
||||
procedure Stop;
|
||||
property Input: TACSCustomInput read FInput write FInput;
|
||||
property Volume: Word read FVolume write FVolume;
|
||||
end;
|
||||
|
||||
TACSMultiMixer = class(TACSCustomInput)
|
||||
private
|
||||
FChannel: array of TACSChannel;
|
||||
FTotalChannels: Integer;
|
||||
OutBuf: array[1..BUF_SIZE] of Byte;
|
||||
Buisy : Boolean;
|
||||
FLock: Boolean;
|
||||
function GetChannel(Index: Integer): TACSChannel;
|
||||
procedure SetTotalChannels(Num: Integer);
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
property Channel[Index: Integer]: TACSChannel read GetChannel; default;
|
||||
function GetData(Buffer: Pointer; BufferSize: Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property TotalChannels: Integer read FTotalChannels write SetTotalChannels;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
// TChannel
|
||||
|
||||
constructor TACSChannel.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FOwner := AOwner;
|
||||
FVolume := 32768;
|
||||
EndOfInput := True;
|
||||
Preloaded := False;
|
||||
end;
|
||||
|
||||
destructor TACSChannel.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSChannel.Preload;
|
||||
begin
|
||||
if EndOfInput and not Preloaded and Assigned(FInput) then
|
||||
begin
|
||||
FInput.Init;
|
||||
Preloaded := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSChannel.Start;
|
||||
begin
|
||||
if FOwner.Buisy and EndOfInput and Assigned(FInput) then
|
||||
begin
|
||||
if not Preloaded then Preload;
|
||||
EndOfInput := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSChannel.Stop;
|
||||
begin
|
||||
if not EndOfInput then
|
||||
begin
|
||||
EndOfInput := True;
|
||||
Preloaded := False;
|
||||
while FOwner.Flock do;
|
||||
FOwner.FLock := True;
|
||||
FInput.Flush;
|
||||
FOwner.Flock := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
// TACSMultiMixer
|
||||
|
||||
constructor TACSMultiMixer.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FLock := False;
|
||||
end;
|
||||
|
||||
destructor TACSMultiMixer.Destroy;
|
||||
begin
|
||||
SetTotalChannels(0); // free channels
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSMultiMixer.SetTotalChannels(Num: Integer);
|
||||
var
|
||||
chan: Integer;
|
||||
begin
|
||||
if (Num >= 0) and (Num <> FTotalChannels) then
|
||||
begin
|
||||
while Flock do;
|
||||
FLock := True;
|
||||
if Num < FTotalChannels then // remove channels
|
||||
begin
|
||||
for chan := FTotalChannels-1 downto Num do
|
||||
with FChannel[chan] do
|
||||
begin
|
||||
if not EndOfInput then FInput.Flush;
|
||||
Free;
|
||||
end;
|
||||
SetLength(FChannel,Num);
|
||||
end
|
||||
else begin // add channels
|
||||
SetLength(FChannel,Num);
|
||||
for chan := FTotalChannels to Num-1 do
|
||||
FChannel[chan] := TACSChannel.Create(Self);
|
||||
end;
|
||||
FTotalChannels := Num;
|
||||
FLock := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSMultiMixer.GetBPS;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TACSMultiMixer.GetCh;
|
||||
begin
|
||||
Result:= 2;
|
||||
end;
|
||||
|
||||
function TACSMultiMixer.GetSR;
|
||||
begin
|
||||
Result := 44100;
|
||||
end;
|
||||
|
||||
procedure TACSMultiMixer.Init;
|
||||
var
|
||||
chan: Integer;
|
||||
begin
|
||||
Buisy := True;
|
||||
FPosition := 0;
|
||||
for chan := 0 to FTotalChannels-1 do
|
||||
FChannel[chan].Start;
|
||||
FSize := 0;
|
||||
FLock := False;
|
||||
end;
|
||||
|
||||
procedure TACSMultiMixer.Flush;
|
||||
var
|
||||
chan: Integer;
|
||||
begin
|
||||
for chan := 0 to FTotalChannels-1 do
|
||||
with FChannel[chan] do
|
||||
begin
|
||||
if Assigned(FInput) then FInput.Flush;
|
||||
EndOfInput := True;
|
||||
Preloaded := False;
|
||||
end;
|
||||
Buisy := False;
|
||||
end;
|
||||
|
||||
function TACSMultiMixer.GetData;
|
||||
var
|
||||
i, chan, ReadSize, BufSize: Integer;
|
||||
InBuf16, OutBuf16: PACSBuffer16;
|
||||
begin
|
||||
if not Buisy then raise EACSException.Create(strStreamnotopen);
|
||||
begin
|
||||
while Flock do sleep(0);
|
||||
Flock := True;
|
||||
BufSize := 0;
|
||||
if BufferSize > BUF_SIZE then BufferSize := BUF_SIZE;
|
||||
for chan := 0 to FTotalChannels-1 do
|
||||
with FChannel[chan] do
|
||||
if not EndOfInput then
|
||||
begin
|
||||
ReadSize := FInput.GetData(@InBuf[1], BufferSize);
|
||||
while (ReadSize < BufferSize) and (ReadSize <> 0) do
|
||||
begin
|
||||
Result := FInput.GetData(@InBuf[ReadSize+1], BufferSize-ReadSize);
|
||||
Inc(ReadSize, Result);
|
||||
end;
|
||||
FillChar(InBuf[ReadSize+1], BufferSize-ReadSize, 0); // zero rest of buffer
|
||||
if ReadSize = 0 then EndOfInput := True
|
||||
else if ReadSize > BufSize then BufSize := ReadSize;
|
||||
end;
|
||||
if BufSize = 0 then
|
||||
begin
|
||||
Flock := False;
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
// mix
|
||||
FillChar(OutBuf[1], BufferSize, 0);
|
||||
OutBuf16 := @OutBuf;
|
||||
for chan := 0 to FTotalChannels-1 do
|
||||
with FChannel[chan] do
|
||||
if not EndOfInput then
|
||||
begin
|
||||
InBuf16 := @InBuf;
|
||||
for i := 0 to (BufSize shr 1) - 1 do
|
||||
OutBuf16[i] := OutBuf16[i] + (InBuf16[i] * FVolume div 32768);
|
||||
end;
|
||||
Flock := False;
|
||||
end;
|
||||
Result := BufSize;
|
||||
Move(OutBuf[1], Buffer^, Result);
|
||||
Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
function TACSMultiMixer.GetChannel(Index: Integer): TACSChannel;
|
||||
begin
|
||||
Result := FChannel[Index];
|
||||
end;
|
||||
|
||||
end.
|
343
acs/Src/classes/acs_procs.pas
Normal file
343
acs/Src/classes/acs_procs.pas
Normal file
@@ -0,0 +1,343 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_procs.pas,v $
|
||||
Revision 1.4 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
unit acs_procs;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, ACS_Types, Math;
|
||||
|
||||
type
|
||||
|
||||
TACSFilterWindowType = (fwHamming, fwHann, fwBlackman);
|
||||
|
||||
{$IFDEF LINUX}
|
||||
function FindLibs(const Pattern : String) : String;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
// Direction = 1 - forward FFT, Direction = -1 - inverse FFT.
|
||||
procedure ComplexFFT(Data : PACSComplexArray; DataSize, Direction : Integer);
|
||||
|
||||
procedure HannWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
|
||||
procedure HammingWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
|
||||
procedure BlackmanWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
|
||||
procedure CalculateSincKernel(OutData : PACSDoubleArray; CutOff : Double; Width : Integer; WType : TACSFilterWindowType);
|
||||
|
||||
procedure SmallIntArrayToDouble(InData : PSmallInt; OutData : PDouble; DataSize : Integer);
|
||||
|
||||
procedure SmallIntArrayToComplex(InData : PSmallInt; OutData : PACSComplex; DataSize : Integer);
|
||||
|
||||
|
||||
// Computes Op2[i] = Op1[i]*Op2[i], i = [0..DataSize-1]
|
||||
|
||||
procedure MultDoubleArrays(Op1, Op2 : PDouble; DataSize : Integer);
|
||||
|
||||
(*
|
||||
Performs calculation of
|
||||
/
|
||||
| Lg(Abs(InData[i])) + Shift, if Lg(Abs(InData[i])) + Shift >= 0
|
||||
OutData[i] = < 0, if Lg(Abs(InData[i])) + Shift < 0
|
||||
| 0, if Abs(InData[i]) = 0.
|
||||
\
|
||||
i = [0..DataSize-1]
|
||||
*)
|
||||
procedure LgMagnitude(InData : PACSComplex; OutData : PDouble; DataSize, Shift : Integer);
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF LINUX}
|
||||
function FindLibs(const Pattern : String) : String;
|
||||
var
|
||||
Path : String;
|
||||
SR : TSearchRec;
|
||||
begin
|
||||
Path := '/usr/lib/';
|
||||
if FindFirst(Path + Pattern, faAnyFile, SR) = 0 then
|
||||
begin
|
||||
Result := SR.Name;
|
||||
FindClose(SR);
|
||||
Exit;
|
||||
end;
|
||||
Path := '/usr/local/lib/';
|
||||
if FindFirst(Path + Pattern, faAnyFile, SR) = 0 then
|
||||
begin
|
||||
Result := SR.Name;
|
||||
FindClose(SR);
|
||||
Exit;
|
||||
end;
|
||||
Result := '';
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
(* This routine is converted from the original C code by P. Burke
|
||||
Direction = 1 - forward FFT, Direction = -1 - inverse FFT. *)
|
||||
procedure ComplexFFT(Data : PACSComplexArray; DataSize, Direction : Integer);
|
||||
var
|
||||
i, i1, j, k, i2, l, l1, l2, Log2n : Integer;
|
||||
c1, c2, tx, ty, t1, t2, u1, u2, z : Double;
|
||||
begin
|
||||
Log2n := Trunc(Log2(DataSize));
|
||||
// Do the bit reversal
|
||||
i2 := DataSize shr 1;
|
||||
j := 0;
|
||||
for i := 0 to DataSize-2 do
|
||||
begin
|
||||
if i < j then
|
||||
begin
|
||||
tx := Data[i].Re;
|
||||
ty := Data[i].Im;
|
||||
Data[i].Re := Data[j].Re;
|
||||
Data[i].Im := Data[j].Im;
|
||||
Data[j].Re := tx;
|
||||
Data[j].Im := ty;
|
||||
end;
|
||||
k := i2;
|
||||
while k <= j do
|
||||
begin
|
||||
Dec(j, k);
|
||||
k := k shr 1;
|
||||
end;
|
||||
Inc(j, k);
|
||||
end;
|
||||
// Compute the FFT
|
||||
c1 := -1.0;
|
||||
c2 := 0.0;
|
||||
l2 := 1;
|
||||
for l := 0 to Log2n-1 do
|
||||
begin
|
||||
l1 := l2;
|
||||
l2 := l2 shl 1;
|
||||
u1 := 1.0;
|
||||
u2 := 0.0;
|
||||
for j := 0 to l1-1 do
|
||||
begin
|
||||
i := j;
|
||||
while i < DataSize do
|
||||
begin
|
||||
i1 := i + l1;
|
||||
t1 := u1 * Data[i1].Re - u2 * Data[i1].Im;
|
||||
t2 := u1 * Data[i1].Im + u2 * Data[i1].Re;
|
||||
Data[i1].Re := Data[i].Re - t1;
|
||||
Data[i1].Im := Data[i].Im - t2;
|
||||
Data[i].Re := Data[i].Re + t1;
|
||||
Data[i].Im := Data[i].Im + t2;
|
||||
Inc(i, l2);
|
||||
end;
|
||||
z := u1*c1 - u2*c2;
|
||||
u2 := u1*c2 + u2*c1;
|
||||
u1 := z;
|
||||
end;
|
||||
c2 := Sqrt((1.0 - c1)/2.0);
|
||||
if Direction = 1 then c2 := -c2;
|
||||
c1 := Sqrt((1.0 + c1)/2.0);
|
||||
end;
|
||||
|
||||
// Scaling for forward transform
|
||||
if Direction = 1 then
|
||||
for i := 0 to DataSize-1 do
|
||||
begin
|
||||
Data[i].Re := Data[i].Re/DataSize;
|
||||
Data[i].Im := Data[i].Im/DataSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HannWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
var
|
||||
i, n : Integer;
|
||||
begin
|
||||
if Symmetric then n := Width-1
|
||||
else n := Width;
|
||||
for i := 0 to Width-1 do OutData[i] := (1-Cos(TwoPi*i/n))/2;
|
||||
end;
|
||||
|
||||
procedure HammingWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
var
|
||||
i, n : Integer;
|
||||
begin
|
||||
if Symmetric then n := Width-1
|
||||
else n := Width;
|
||||
for i := 0 to Width-1 do OutData[i] := 0.54-0.46*Cos(TwoPi*i/n);
|
||||
end;
|
||||
|
||||
procedure BlackmanWindow(OutData : PACSDoubleArray; Width : Integer; Symmetric : Boolean);
|
||||
var
|
||||
i, n : Integer;
|
||||
begin
|
||||
if Symmetric then n := Width-1
|
||||
else n := Width;
|
||||
for i := 0 to Width-1 do OutData[i] := 0.42-0.5*Cos(TwoPi*i/n) + 0.08*Cos(2*TwoPi*i/n);
|
||||
end;
|
||||
|
||||
procedure CalculateSincKernel(OutData : PACSDoubleArray; CutOff : Double; Width : Integer; WType : TACSFilterWindowType);
|
||||
var
|
||||
i : Integer;
|
||||
S : Double;
|
||||
Window : array of Double;
|
||||
begin
|
||||
// SetLength(OutData, Width);
|
||||
SetLength(Window, Width);
|
||||
case WType of
|
||||
fwHamming : HammingWindow(@Window[0], Width, False);
|
||||
fwHann : HannWindow(@Window[0], Width, False);
|
||||
fwBlackman : BlackmanWindow(@Window[0], Width, False);
|
||||
end;
|
||||
S := 0;
|
||||
for i := 0 to Width-1 do
|
||||
begin
|
||||
if i-(Width shr 1) <> 0 then
|
||||
OutData[i] := Sin(TwoPi*CutOff*(i-(Width shr 1)))/(i-(Width shr 1))*Window[i]
|
||||
else OutData[i] := TwoPi*CutOff*Window[i];
|
||||
S := S + OutData[i];
|
||||
end;
|
||||
for i := 0 to Width-1 do OutData[i] := OutData[i]/S;
|
||||
end;
|
||||
|
||||
procedure SmallIntArrayToDouble(InData : PSmallInt; OutData : PDouble; DataSize : Integer);
|
||||
begin
|
||||
{$IFDEF CPU32}
|
||||
asm
|
||||
MOV EDX, DataSize;
|
||||
SHL EDX, 3;
|
||||
MOV ECX, OutData;
|
||||
ADD EDX, ECX;
|
||||
MOV EAX, InData;
|
||||
@test: CMP EDX, ECX;
|
||||
JE @out;
|
||||
FILD WORD[EAX];
|
||||
ADD EAX, 2;
|
||||
FSTP QWORD[ECX];
|
||||
ADD ECX, 8;
|
||||
JMP @test;
|
||||
@out: ;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure SmallIntArrayToComplex(InData : PSmallInt; OutData : PACSComplex; DataSize : Integer);
|
||||
begin
|
||||
{$IFDEF CPU32}
|
||||
asm
|
||||
MOV EDX, DataSize;
|
||||
SHR EDX, 4;
|
||||
MOV ECX, OutData;
|
||||
ADD EDX, ECX;
|
||||
MOV EAX, InData;
|
||||
@test: CMP EDX, ECX;
|
||||
JE @out;
|
||||
FILD WORD[EAX];
|
||||
ADD EAX, 2;
|
||||
FSTP QWORD[EAX];
|
||||
ADD ECX, 16;
|
||||
JMP @test;
|
||||
@out: ;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure MultDoubleArrays(Op1, Op2 : PDouble; DataSize : Integer);
|
||||
begin
|
||||
{$IFDEF CPU32}
|
||||
asm
|
||||
MOV EDX, DataSize;
|
||||
SHL EDX, 3;
|
||||
MOV ECX, Op1;
|
||||
ADD EDX, ECX;
|
||||
MOV EAX, Op2;
|
||||
@test: CMP EDX, ECX;
|
||||
JE @out;
|
||||
FLD QWORD[ECX];
|
||||
FLD QWORD[EAX];
|
||||
FMUL;
|
||||
FSTP QWORD[EAX];
|
||||
ADD ECX, 8;
|
||||
ADD EAX, 8;
|
||||
JMP @test;
|
||||
@out: ;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure LgMagnitude(InData : PACSComplex; OutData : PDouble; DataSize, Shift : Integer);
|
||||
var
|
||||
LogBase : Double;
|
||||
begin
|
||||
{$IFDEF CPU32}
|
||||
asm
|
||||
FLD1;
|
||||
FLDL2T;
|
||||
FDIVP;
|
||||
FSTP LogBase;
|
||||
MOV EDX, DataSize;
|
||||
SHL EDX, 3;
|
||||
MOV ECX, OutData;
|
||||
ADD EDX, ECX;
|
||||
MOV EAX, InData;
|
||||
@test: CMP EDX, ECX;
|
||||
JE @out;
|
||||
FLD QWORD[EAX];
|
||||
FMUL ST(0), ST(0);
|
||||
ADD EAX, 8;
|
||||
FLD QWORD[EAX];
|
||||
FMUL ST(0), ST(0);
|
||||
FADDP;
|
||||
FSQRT;
|
||||
FTST;
|
||||
PUSH EAX;
|
||||
FSTSW AX;
|
||||
SAHF;
|
||||
JE @skip;
|
||||
FLD LogBase;
|
||||
FXCH;
|
||||
FYL2X;
|
||||
FIADD Shift;
|
||||
FTST;
|
||||
FSTSW AX;
|
||||
SAHF;
|
||||
JAE @skip;
|
||||
FSTP QWORD[ECX];
|
||||
FLDZ;
|
||||
@skip: POP EAX;
|
||||
ADD EAX, 8;
|
||||
FSTP QWORD[ECX];
|
||||
ADD ECX, 8;
|
||||
JMP @test;
|
||||
@out: ;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
end.
|
223
acs/Src/classes/acs_streams.pas
Normal file
223
acs/Src/classes/acs_streams.pas
Normal file
@@ -0,0 +1,223 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_streams.pas,v $
|
||||
Revision 1.5 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/11/27 16:50:33 z0m3ie
|
||||
add ACS VolumeQuerry
|
||||
make ACS_VolumeQuerry localizeable
|
||||
some little errorfixes (buffersize for linuxdrivers was initially 0)
|
||||
make TAudioIn workable
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
|
||||
unit acs_streams;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, ACS_Classes, ACS_Strings;
|
||||
|
||||
const
|
||||
|
||||
OUTBUF_SIZE = $4000;
|
||||
|
||||
|
||||
type
|
||||
|
||||
TACSStreamOut = class(TACSStreamedOutput)
|
||||
private
|
||||
function GetSR : Integer;
|
||||
function GetBPS : Integer;
|
||||
function GetCh : Integer;
|
||||
protected
|
||||
procedure Done; override;
|
||||
function DoOutput(Abort : Boolean):Boolean; override;
|
||||
procedure Prepare; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
property OutSampleRate : Integer read GetSR;
|
||||
property OutBitsPerSample : Integer read GetBPS;
|
||||
property OutChannles : Integer read GetCh;
|
||||
end;
|
||||
|
||||
TACSStreamIn = class(TACSStreamedInput)
|
||||
private
|
||||
FBPS, FChan, FFreq : Integer;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property InBitsPerSample : Integer read FBPS write FBPS;
|
||||
property InChannels : Integer read FChan write FChan;
|
||||
property InSampleRate : Integer read FFreq write FFreq;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
procedure TACSStreamOut.Prepare;
|
||||
begin
|
||||
if not FStreamAssigned then
|
||||
raise EACSException.Create(strStreamObjectnotassigned);
|
||||
FInput.Init;
|
||||
end;
|
||||
|
||||
procedure TACSStreamOut.Done;
|
||||
begin
|
||||
FInput.Flush;
|
||||
end;
|
||||
|
||||
function TACSStreamOut.DoOutput(Abort : Boolean):Boolean;
|
||||
var
|
||||
Len : Integer;
|
||||
P : Pointer;
|
||||
begin
|
||||
// No exceptions Here
|
||||
Result := True;
|
||||
if not Busy then Exit;
|
||||
if Abort or (not CanOutput) then
|
||||
begin
|
||||
Result := False;
|
||||
Exit;
|
||||
end;
|
||||
GetMem(P, OUTBUF_SIZE);
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
Len := Finput.GetData(P, OUTBUF_SIZE);
|
||||
InputLock := False;
|
||||
if Len > 0 then
|
||||
begin
|
||||
Result := True;
|
||||
FStream.WriteBuffer(P^, Len);
|
||||
end
|
||||
else Result := False;
|
||||
FreeMem(P);
|
||||
end;
|
||||
|
||||
constructor TACSStreamOut.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSStreamOut.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
constructor TACSStreamIn.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FBPS := 8;
|
||||
FChan := 1;
|
||||
FFreq := 8000;
|
||||
FSize := -1;
|
||||
end;
|
||||
|
||||
destructor TACSStreamIn.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TACSStreamIn.Init;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
if not Assigned(FStream) then raise EACSException.Create(strStreamObjectnotassigned);
|
||||
FPosition := FStream.Position;
|
||||
FBusy := True;
|
||||
FSize := FStream.Size;
|
||||
end;
|
||||
|
||||
procedure TACSStreamIn.Flush;
|
||||
begin
|
||||
// FStream.Position := 0;
|
||||
FBusy := False;
|
||||
end;
|
||||
|
||||
function TACSStreamIn.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
begin
|
||||
Result := FStream.Read(Buffer^, BufferSize);
|
||||
FPosition := FStream.Position;
|
||||
// Inc(FPosition, Result);
|
||||
if FPosition >= FSize then
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TACSStreamOut.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
function TACSStreamOut.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSStreamOut.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(Input) then
|
||||
raise EACSException.Create(strInputnotassigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSStreamIn.GetBPS : Integer;
|
||||
begin
|
||||
Result := FBPS
|
||||
end;
|
||||
|
||||
function TACSStreamIn.GetCh : Integer;
|
||||
begin
|
||||
Result := FChan;
|
||||
end;
|
||||
|
||||
function TACSStreamIn.GetSR : Integer;
|
||||
begin
|
||||
Result := Self.FFreq;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
61
acs/Src/classes/acs_strings.pas
Normal file
61
acs/Src/classes/acs_strings.pas
Normal file
@@ -0,0 +1,61 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.4.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
unit acs_strings;
|
||||
|
||||
interface
|
||||
|
||||
resourcestring
|
||||
strCoudntloadLib = 'Library %s could not be loaded.';
|
||||
strcoudntopendevice = 'Could not open device "%s" for input';
|
||||
strCoudntopendeviceOut = 'Could not open device "%s" for output';
|
||||
strBusy = 'The component is busy';
|
||||
strInputstartfailed = 'Failed to start input';
|
||||
strFailedtostartOutput = 'Failed to start output';
|
||||
strStreamnotopen = 'The Stream is not opened';
|
||||
strBufferoverrun = 'Buffer overrun.';
|
||||
strUnknownExtension = 'Unknown file extension %s';
|
||||
strAllFormats = 'All formats';
|
||||
strInputnotAssigned = 'Input not Assigned';
|
||||
strFilenamenotassigned = 'Filename not Assigned';
|
||||
strSeeknotImplemented = 'Seek: method not implemented';
|
||||
strNotinFBMode = 'The component is not in amFB mode.';
|
||||
strIllegalFrequency = 'Illegal frequency';
|
||||
strCutofftolow = 'Cut-off frequencies are greater than the half of the sample rate.';
|
||||
strListIndexOOB = 'List Index Out of Bounds %d';
|
||||
strNoInputItems = 'No input items in the list.';
|
||||
strNoInputAssigned = 'No input assigned to current item';
|
||||
strStreamObjectnotassigned = 'Stream object not assigned';
|
||||
strBufferunderrun = 'Buffer underrun';
|
||||
strDevnotplayable = 'Cannot play on the device "%s"';
|
||||
strTrackOutofRange = 'Track out of range';
|
||||
strNoAudioCD = 'Not an audio disc';
|
||||
strChannelNotRecordable = 'Channel %d is not recordable';
|
||||
strDrivenotready = 'The drive is not ready';
|
||||
strnoAudioTreck = 'This is no audio track';
|
||||
strChannelNotAvailable = 'Channel %d is not available';
|
||||
strFailedtoCreateDSdev = 'Failed to create DirectSound device';
|
||||
strFailedtoCreateDSbuf = 'Failed to create DirectSound buffer';
|
||||
strnoDriverselected = 'No driver is selected, please select an driver first !';
|
||||
strnoFileOpened = 'No file opened !';
|
||||
|
||||
strMixerVolume = 'Master output';
|
||||
strMixerTreble = 'Treble output';
|
||||
strMixerBass = 'Bass output';
|
||||
strMixerSynth = 'Synthesizer input';
|
||||
strMixerPCM = 'Audio output';
|
||||
strMixerSpeaker = 'Speaker output';
|
||||
strMixerLine = 'Line input';
|
||||
strMixerMic = 'Michrophone input';
|
||||
strMixerCD = 'CD input';
|
||||
strMixerIMix = 'Record monitor';
|
||||
strMixerAlt = 'Alternate output';
|
||||
strMixerRec = 'Record level';
|
||||
strMixerUnknown = 'Unknown channel';
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
84
acs/Src/classes/acs_types.pas
Normal file
84
acs/Src/classes/acs_types.pas
Normal file
@@ -0,0 +1,84 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.3.
|
||||
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||||
see the license file for more details.
|
||||
you can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: acs_types.pas,v $
|
||||
Revision 1.6 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
unit acs_types;
|
||||
|
||||
interface
|
||||
|
||||
type
|
||||
|
||||
TACSBuffer16 = array[0..0] of SmallInt;
|
||||
PACSBuffer16 = ^TACSBuffer16;
|
||||
|
||||
TACSBuffer8 = array[0..0] of Byte;
|
||||
PACSBuffer8 = ^TACSBuffer8;
|
||||
|
||||
TACSStereoSample16 = packed record
|
||||
Left, Right : SmallInt;
|
||||
end;
|
||||
|
||||
TACSStereoBuffer16 = array[0..0] of TACSStereoSample16;
|
||||
PACSStereoBuffer16 = ^TACSStereoBuffer16;
|
||||
|
||||
TACSStereoSample8 = packed record
|
||||
Left, Right : Byte;
|
||||
end;
|
||||
|
||||
TACSStereoBuffer8 = array[0..0] of TACSStereoSample8;
|
||||
PACSStereoBuffer8 = ^TACSStereoBuffer8;
|
||||
|
||||
|
||||
TACSComplex = packed record
|
||||
Re, Im : Double;
|
||||
end;
|
||||
|
||||
PACSComplex = ^TACSComplex;
|
||||
|
||||
TACSComplexArray = array[0..0] of TACSComplex;
|
||||
PACSComplexArray = ^TACSComplexArray;
|
||||
|
||||
TACSDoubleArray = array[0..0] of Double;
|
||||
PACSDoubleArray = ^TACSDoubleArray;
|
||||
|
||||
TACSStereoSampleD = record
|
||||
Left : Double;
|
||||
Right : Double;
|
||||
end;
|
||||
|
||||
TACSStereoBufferD = array[0..0] of TACSStereoSampleD;
|
||||
PACSStereoBufferD = ^TACSStereoBufferD;
|
||||
|
||||
const
|
||||
|
||||
Pi = 3.14159265359;
|
||||
TwoPi = 6.28318530718;
|
||||
HalfPi = 1.57079632679;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
227
acs/Src/classes/acs_volumequery.pas
Normal file
227
acs/Src/classes/acs_volumequery.pas
Normal file
@@ -0,0 +1,227 @@
|
||||
(*
|
||||
this file is a part of audio components suite v 2.4,
|
||||
copyright (c) 2005 ross levis. all rights reserved.
|
||||
|
||||
Provides linear volume in volLeft and volRight in the range 0 (min) to 32767 (max).
|
||||
Supports 8 and 16 bit samples, mono and stereo.
|
||||
dbLeft and dbRight returns the volume in decibels.
|
||||
Delay is in blocks of 50ms and is required due to unknown output buffer size.
|
||||
Increase Delay to bring VU levels in line with output audio.
|
||||
Suggest using a 50ms Timer to read values.
|
||||
|
||||
$Log: acs_volumequery.pas,v $
|
||||
Revision 1.2 2006/08/31 20:10:54 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.1 2005/12/19 18:34:35 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.1 2005/11/27 16:50:33 z0m3ie
|
||||
add ACS VolumeQuerry
|
||||
make ACS_VolumeQuerry localizeable
|
||||
some little errorfixes (buffersize for linuxdrivers was initially 0)
|
||||
make TAudioIn workable
|
||||
|
||||
*)
|
||||
|
||||
unit acs_volumequery;
|
||||
|
||||
{$ifdef fpc}
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, Math, ACS_Types, ACS_Classes,ACS_Strings;
|
||||
|
||||
type
|
||||
|
||||
TACSVolumeQuery = class(TACSCustomConverter)
|
||||
private
|
||||
Lock : Boolean;
|
||||
FLeft, FRight: Array of Word;
|
||||
FDelay, F50ms: Word;
|
||||
FSR,FBPS,FCh: Integer;
|
||||
protected
|
||||
function GetBPS : Integer; override;
|
||||
function GetCh : Integer; override;
|
||||
function GetSR : Integer; override;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function volLeft: Word;
|
||||
function volRight: Word;
|
||||
function dbLeft: Single;
|
||||
function dbRight: Single;
|
||||
function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override;
|
||||
procedure Init; override;
|
||||
procedure Flush; override;
|
||||
published
|
||||
property Delay: Word read FDelay write FDelay;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
constructor TACSVolumeQuery.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
end;
|
||||
|
||||
destructor TACSVolumeQuery.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.GetBPS : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.BitsPerSample;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.GetCh : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.Channels;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.GetSR : Integer;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
Result := FInput.SampleRate;
|
||||
end;
|
||||
|
||||
procedure TACSVolumeQuery.Init;
|
||||
begin
|
||||
if not Assigned(FInput) then
|
||||
raise EACSException.Create(strInputnotAssigned);
|
||||
SetLength(FLeft,FDelay+1);
|
||||
SetLength(FRight,FDelay+1);
|
||||
FillChar(FLeft[0], SizeOf(Word)*(FDelay+1), 0);
|
||||
FillChar(FRight[0], SizeOf(Word)*(FDelay+1), 0);
|
||||
//
|
||||
FBusy := True;
|
||||
FInput.Init;
|
||||
// calc 50ms worth of data
|
||||
FSR := GetSR;
|
||||
FBPS := GetBPS;
|
||||
FCH := GetCh;
|
||||
FPosition := 0;
|
||||
FSize := FInput.Size;
|
||||
F50ms := FSR * FBPS * FCh div 160;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
procedure TACSVolumeQuery.Flush;
|
||||
begin
|
||||
FInput.Flush;
|
||||
FBusy := False;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.GetData(Buffer: Pointer; BufferSize: Integer): Integer;
|
||||
var
|
||||
LVol, RVol, LMax, RMax: Word;
|
||||
i, NumSamples: Integer;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
//if FOrigBufferSize = -1 then FOrigBufferSize := BufferSize
|
||||
if BufferSize > F50ms then BufferSize := F50ms;
|
||||
while InputLock do;
|
||||
InputLock := True;
|
||||
Result := FInput.GetData(Buffer, BufferSize);
|
||||
InputLock := False;
|
||||
FPosition := FInput.Position;
|
||||
if Result = 0 then Exit;
|
||||
if Lock then Exit;
|
||||
Lock := True;
|
||||
//
|
||||
if FBPS = 8 then
|
||||
begin
|
||||
if FCh = 1 then NumSamples := Result
|
||||
else NumSamples := Result shr 1;
|
||||
end
|
||||
else begin
|
||||
if FCh = 1 then NumSamples := Result shr 1
|
||||
else NumSamples := Result shr 2;
|
||||
end;
|
||||
//
|
||||
LMax := 0;
|
||||
RMax := 0;
|
||||
for i := 0 to NumSamples-1 do
|
||||
begin
|
||||
if FBPS = 8 then
|
||||
begin
|
||||
if FCh = 1 then
|
||||
begin
|
||||
LVol := ABS(PACSBuffer8(Buffer)[i]-127)*256;
|
||||
RVol := LVol;
|
||||
end
|
||||
else begin
|
||||
LVol := ABS(PACSStereoBuffer8(Buffer)[i].Left-127)*256;
|
||||
RVol := ABS(PACSStereoBuffer8(Buffer)[i].Right-127)*256;
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
if FCh = 1 then
|
||||
begin
|
||||
LVol := ABS(PACSBuffer16(Buffer)[i]);
|
||||
RVol := LVol;
|
||||
end
|
||||
else begin
|
||||
LVol := ABS(PACSStereoBuffer16(Buffer)[i].Left);
|
||||
RVol := ABS(PACSStereoBuffer16(Buffer)[i].Right);
|
||||
end;
|
||||
end;
|
||||
if LVol > LMax then LMax := LVol;
|
||||
if RVol > RMax then RMax := RVol;
|
||||
end;
|
||||
if FDelay > 0 then
|
||||
begin
|
||||
Move(FLeft[1],FLeft[0],FDelay*Sizeof(Word));
|
||||
Move(FRight[1],FRight[0],FDelay*Sizeof(Word));
|
||||
end;
|
||||
FLeft[FDelay] := LMax;
|
||||
FRight[FDelay] := RMax;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.volLeft: Word;
|
||||
begin
|
||||
Lock := True;
|
||||
if Busy then Result := FLeft[0]
|
||||
else Result := 0;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.volRight: Word;
|
||||
begin
|
||||
Lock := True;
|
||||
if Busy then Result := FRight[0]
|
||||
else Result := 0;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.dbLeft: Single;
|
||||
begin
|
||||
Lock := True;
|
||||
if Busy then Result := 10 * Log10((FLeft[0]+1)/32768)
|
||||
else Result := -96;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
function TACSVolumeQuery.dbRight: Single;
|
||||
begin
|
||||
Lock := True;
|
||||
if Busy then Result := 10 * Log10((FRight[0]+1)/32768)
|
||||
else Result := -96;
|
||||
Lock := False;
|
||||
end;
|
||||
|
||||
end.
|
384
acs/Src/classes/linux/acs_cdrom.inc
Normal file
384
acs/Src/classes/linux/acs_cdrom.inc
Normal file
@@ -0,0 +1,384 @@
|
||||
{
|
||||
$Log: acs_cdrom.inc,v $
|
||||
Revision 1.7 2006/08/31 20:10:56 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.6 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.2 2005/12/26 17:31:39 z0m3ie
|
||||
fixed some problems in acs_dsfiles
|
||||
fixed some problems in acs_vorbis
|
||||
reworked all buffers
|
||||
|
||||
}
|
||||
|
||||
function GetTocEntry(cd_fd, Track : Integer): TACSCDTrackInfo;
|
||||
var
|
||||
Entry : cdrom_tocentry;
|
||||
toc : cdrom_tochdr;
|
||||
frames1, frames2 : Integer;
|
||||
begin
|
||||
fpioctl(cd_fd, CDROMREADTOCHDR, @toc);
|
||||
Entry.cdte_format := CDROM_MSF;
|
||||
Entry.cdte_track := Track+toc.cdth_trk0-1;
|
||||
fpioctl(cd_fd, CDROMREADTOCENTRY, @Entry);
|
||||
frames1 := MSF2Frames(TACSCDMSF(Entry.cdte_addr.msf));
|
||||
if (Entry.cdte_adr_ctrl and CDROM_DATA_TRACK) <> 0 then
|
||||
Result.TrackType := ttData
|
||||
else Result.TrackType := ttAudio;
|
||||
if Entry.cdte_track < toc.cdth_trk1 then Inc(Entry.cdte_track)
|
||||
else Entry.cdte_track := CDROM_LEADOUT;
|
||||
fpioctl(cd_fd, CDROMREADTOCENTRY, @Entry);
|
||||
frames2 := MSF2Frames(TACSCDMSF(Entry.cdte_addr.msf));
|
||||
Frames2MSF(frames2-frames1, Result.TrackLength);
|
||||
end;
|
||||
|
||||
function GetCDStatus(cd_fd : Integer) : TACSCDStatus;
|
||||
(* not all drivers support the CDROM_DRIVE_STATUS ioctl
|
||||
we use this ioctl first and then some other tecnique
|
||||
if it is not supported. *)
|
||||
var
|
||||
sci : cdrom_subchnl;
|
||||
res :Integer;
|
||||
Data: Integer;
|
||||
begin
|
||||
Data := CDSL_CURRENT;
|
||||
res := fpioctl(cd_fd, CDROM_DRIVE_STATUS, @Data);
|
||||
case res of
|
||||
CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READY:
|
||||
begin
|
||||
Result := cdsNotReady;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
(* Either the disc is ok or no information
|
||||
from the driver. Trying CDROMSUBCHNL.*)
|
||||
sci.cdsc_format := CDROM_MSF;
|
||||
if fpioctl(cd_fd, CDROMSUBCHNL, @sci) < 0 then
|
||||
begin
|
||||
Result := cdsNotReady;
|
||||
Exit;
|
||||
end;
|
||||
case sci.cdsc_audiostatus of
|
||||
CDROM_AUDIO_PLAY : Result := cdsPlaying;
|
||||
CDROM_AUDIO_PAUSED : Result := cdsPaused;
|
||||
CDROM_AUDIO_ERROR : Result := cdsNotReady;
|
||||
else Result := cdsReady;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetCDInfo(cd_fd : Integer) : TACSCDInfo;
|
||||
var
|
||||
res : Integer;
|
||||
Data: Integer;
|
||||
begin
|
||||
Result := cdiUnknown;
|
||||
Data := CDSL_CURRENT;
|
||||
res := fpioctl(cd_fd, CDROM_DRIVE_STATUS, @Data);
|
||||
case res of
|
||||
CDS_TRAY_OPEN, CDS_NO_DISC: Result := cdiNoDisc;
|
||||
CDS_DISC_OK :
|
||||
begin
|
||||
res := fpioctl(cd_fd, CDROM_DISC_STATUS, @Data);
|
||||
case res of
|
||||
CDS_AUDIO : Result := cdiDiscAudio;
|
||||
CDS_MIXED : Result := cdiDiscMixed;
|
||||
else Result := cdiDiscData;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.OpenCD;
|
||||
begin
|
||||
if FCurrentDrive >= length(DrivesPaths) then
|
||||
exit;
|
||||
if FOpened = 0 then
|
||||
begin
|
||||
_cd_fd := fpopen(PChar(DrivesPaths[FCurrentDrive]), O_RDONLY or O_NONBLOCK);
|
||||
if _cd_fd < 0 then
|
||||
raise EACSException.Create(IntToStr(errno));
|
||||
end;
|
||||
Inc(FOpened);
|
||||
end;
|
||||
|
||||
|
||||
procedure TACSCDIn.CloseCD;
|
||||
begin
|
||||
if FOpened = 1 then fpclose(_cd_fd);
|
||||
if FOpened > 0 then Dec(FOpened);
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetInfo;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
OpenCD;
|
||||
Result := GetCDInfo(_cd_fd);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetStatus;
|
||||
begin
|
||||
if FCurrentDrive >= length(DrivesPaths) then
|
||||
exit;
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
if Fopened = 0 then
|
||||
_cd_fd := fpopen(PChar(DrivesPaths[FCurrentDrive]), O_RDONLY or O_NONBLOCK);
|
||||
if _cd_fd < 0 then
|
||||
begin
|
||||
Result := cdsNotReady;
|
||||
Exit;
|
||||
end;
|
||||
Inc(FOpened);
|
||||
Result := GetCDStatus(_cd_fd);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetNumTracks;
|
||||
var
|
||||
toc : cdrom_tochdr;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
OpenCD;
|
||||
if GetStatus <> cdsNotReady then
|
||||
begin
|
||||
fpioctl(_cd_fd, CDROMREADTOCHDR, @toc);
|
||||
Result := toc.cdth_trk1 - toc.cdth_trk0 + 1;
|
||||
end else Result := 0;
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetTrackInfo;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
OpenCD;
|
||||
if (vIndex in [1..GetNumTracks]) = False then
|
||||
begin
|
||||
fpclose(_cd_fd);
|
||||
FOpened := 0;
|
||||
raise EACSException.Create(strTrackOutofRange);
|
||||
end;
|
||||
Result := GetTocEntry(_cd_fd, vIndex);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function GetTrackMSF(cd_fd, Track : Integer) : TACSCDMSF;
|
||||
var
|
||||
entry : cdrom_tocentry;
|
||||
hdr : cdrom_tochdr;
|
||||
begin
|
||||
fpioctl(cd_fd, CDROMREADTOCHDR, @hdr);
|
||||
entry.cdte_format := CDROM_MSF;
|
||||
entry.cdte_track := Track + hdr.cdth_trk0 - 1;
|
||||
if entry.cdte_track > hdr.cdth_trk1 then
|
||||
entry.cdte_track := CDROM_LEADOUT;
|
||||
fpioctl(cd_fd, CDROMREADTOCENTRY, @entry);
|
||||
Result := TACSCDMSF(entry.cdte_addr.msf);
|
||||
end;
|
||||
|
||||
function GetPosMSF(cd_fd : Integer; Pos : TACSCDPosition) : TACSCDMSF;
|
||||
var
|
||||
msf1 : TACSCDMSF;
|
||||
frames : Integer;
|
||||
begin
|
||||
msf1 := TACSCDMSF(GetTrackMSF(cd_fd, Pos.Track));
|
||||
frames := MSF2Frames(msf1);
|
||||
frames := frames + MSF2Frames(Pos.MSF);
|
||||
Frames2MSF(frames, msf1);
|
||||
Result := msf1;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetST;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FStartTrack := Track;
|
||||
FStartPos.Track := FStartTrack;
|
||||
FillChar(FStartPos.MSF, SizeOf(FStartPos.MSF), 0);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetET;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FEndTrack := Track;
|
||||
OpenCD;
|
||||
FEndPos.Track := FEndTrack + 1;
|
||||
FillChar(FEndPos.MSF, SizeOf(FEndPos.MSF), 0);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetSP;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
Self.FStartPos := Pos;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetEP;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
Self.FEndPos := Pos;
|
||||
end;
|
||||
|
||||
constructor TACSCDIn.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FCurrentDrive := 0;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetSize;
|
||||
var
|
||||
msf1, msf2 : TACSCDMSF;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
OpenCD;
|
||||
msf1 := GetPosMSF(_cd_fd, FStartPos);
|
||||
msf2 := GetPosMSF(_cd_fd, FEndPos);
|
||||
CloseCD;
|
||||
Result := ((msf2.minute*60 + msf2.second)*75 + msf2.frame -
|
||||
((msf1.minute*60 + msf1.second)*75 + msf1.frame))*CD_FRAMESIZE_RAW;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Init;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
if not (DiscInfo in [cdiDiscAudio, cdiDiscMixed]) then
|
||||
raise EACSException.Create(strNoAudioCD);
|
||||
FSize := GetSize;
|
||||
FBusy := True;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
FPosition := 0;
|
||||
OpenCD;
|
||||
FCurPos := GetPosMSF(_cd_fd, FStartPos);
|
||||
FEndMSF := GetPosMSF(_cd_fd, FEndPos);
|
||||
// GetMem(FBuffer,BUF_SIZE * CD_FRAMESIZE_RAW);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Flush;
|
||||
begin
|
||||
CloseCD;
|
||||
FBusy := False;
|
||||
// FreeMem(FBuffer);
|
||||
FSize := 0;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetData;
|
||||
var
|
||||
StartFrame, EndFrame : Integer;
|
||||
cdaudio : cdrom_read_audio;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotopen);
|
||||
StartFrame := MSF2Frames(FCurPos);
|
||||
EndFrame := MSF2Frames(FEndMSF);
|
||||
if BufStart > BufEnd then
|
||||
begin
|
||||
if EndFrame = StartFrame then
|
||||
begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
end;
|
||||
BufStart := 1;
|
||||
if (EndFrame - StartFrame) > (BUF_SIZE) then
|
||||
cdaudio.nframes := BUF_SIZE
|
||||
else
|
||||
cdaudio.nframes := EndFrame - StartFrame;
|
||||
cdaudio.addr_format := CDROM_MSF;
|
||||
cdaudio.addr.msf := cdrom_msf0(FCurPos);
|
||||
cdaudio.buf := Pointer(FBuffer);
|
||||
fpioctl(_cd_fd, CDROMREADAUDIO, @cdaudio);
|
||||
BufEnd := cdaudio.nframes * CD_FRAMESIZE_RAW;
|
||||
StartFrame := MSF2Frames(FCurPos) + cdaudio.nframes;
|
||||
Frames2MSF(StartFrame, FCurPos);
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1)
|
||||
then Result := BufferSize
|
||||
else Result := BufEnd - BufStart + 1;
|
||||
Move(FBuffer[BufStart], Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Eject;
|
||||
var
|
||||
Data: Integer;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
OpenCD;
|
||||
Data := 0;
|
||||
fpioctl(_cd_fd, CDROMEJECT,@Data);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.CloseTray;
|
||||
var
|
||||
Data: Integer;
|
||||
begin
|
||||
OpenCD;
|
||||
Data := 0;
|
||||
fpioctl(_cd_fd, CDROMCLOSETRAY,@Data);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
procedure CountDrives;
|
||||
var
|
||||
_cd_fd, i : Integer;
|
||||
fname : String;
|
||||
sci : cdrom_subchnl;
|
||||
res :Integer;
|
||||
Data: Integer;
|
||||
begin
|
||||
DrivesCount := 0;
|
||||
Data := CDSL_CURRENT;
|
||||
for i := 0 to 3 do
|
||||
begin
|
||||
fname := '/dev/hd'+chr(ord('a')+i);
|
||||
_cd_fd := fpopen(PChar(fname), O_RDONLY or O_NONBLOCK);
|
||||
if _cd_fd >= 0 then
|
||||
begin
|
||||
res := fpioctl(_cd_fd, CDROM_DRIVE_STATUS, @Data);
|
||||
case res of
|
||||
CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READY:
|
||||
begin
|
||||
inc(DrivesCount);
|
||||
setlength(DrivesPaths,DrivesCount);
|
||||
DrivesPaths[DrivesCount-1] := fname;
|
||||
fpclose(_cd_fd);
|
||||
continue;
|
||||
end;
|
||||
end;
|
||||
(* Either the disc is ok or no information
|
||||
from the driver. Trying CDROMSUBCHNL.*)
|
||||
sci.cdsc_format := CDROM_MSF;
|
||||
if fpioctl(_cd_fd, CDROMSUBCHNL, @sci) >= 0 then
|
||||
begin
|
||||
inc(DrivesCount);
|
||||
setlength(DrivesPaths,DrivesCount);
|
||||
DrivesPaths[DrivesCount-1] := fname;
|
||||
end;
|
||||
fpclose(_cd_fd);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetDrivesCount : Integer;
|
||||
begin
|
||||
Result := DrivesCount;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetCurrentDrive(Value : Integer);
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
FCurrentDrive := Value;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetDriveName : String;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
destructor TACSCDIn.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
293
acs/Src/classes/linux/acs_mixer.inc
Normal file
293
acs/Src/classes/linux/acs_mixer.inc
Normal file
@@ -0,0 +1,293 @@
|
||||
{
|
||||
$Log: acs_mixer.inc,v $
|
||||
Revision 1.2 2005/12/30 12:54:42 z0m3ie
|
||||
some error checks
|
||||
|
||||
Revision 1.1 2005/12/19 18:35:03 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.4 2005/09/09 21:33:43 z0m3ie
|
||||
linux corrections
|
||||
|
||||
Revision 1.3 2005/08/31 20:30:40 z0m3ie
|
||||
Mixer Channelname work now
|
||||
minior corrections for Converters
|
||||
|
||||
Revision 1.2 2005/08/28 20:31:18 z0m3ie
|
||||
linux restructuring for 2.4
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
}
|
||||
|
||||
|
||||
type
|
||||
TMixerInfo = record
|
||||
Path : String;
|
||||
Name : String;
|
||||
end;
|
||||
|
||||
const
|
||||
MAX_MIXERS = 5; (* There shouldn't be more than
|
||||
5 valid mixers in the system.
|
||||
Right? *)
|
||||
|
||||
var
|
||||
Mixers : array[0..MAX_MIXERS] of TMixerInfo; // one extra slot for /dev/mixer device
|
||||
|
||||
function GetChannelMask(Ch : TACSMixerChannel; Request : Integer): LongWord;
|
||||
begin
|
||||
Result := 0;
|
||||
case Request of
|
||||
0:
|
||||
case Ch of
|
||||
mcVolume: Result := SOUND_MIXER_VOLUME;
|
||||
mcTreble: Result := SOUND_MIXER_TREBLE;
|
||||
mcBass: Result := SOUND_MIXER_BASS;
|
||||
mcSynth: Result := SOUND_MIXER_SYNTH;
|
||||
mcPCM: Result := SOUND_MIXER_PCM;
|
||||
mcSpeaker: Result := SOUND_MIXER_SPEAKER;
|
||||
mcLine: Result := SOUND_MIXER_LINE;
|
||||
mcMic: Result := SOUND_MIXER_MIC;
|
||||
mcCD: Result := SOUND_MIXER_CD;
|
||||
mcIMix: Result := SOUND_MIXER_IMIX;
|
||||
mcAltPCM: Result := SOUND_MIXER_ALTPCM;
|
||||
mcRecLev: Result := SOUND_MIXER_RECLEV;
|
||||
mcUnknown: Result := 0;
|
||||
end;
|
||||
1:
|
||||
case Ch of
|
||||
mcVolume: Result := SOUND_MIXER_WRITE_VOLUME;
|
||||
mcTreble: Result := SOUND_MIXER_WRITE_TREBLE;
|
||||
mcBass: Result := SOUND_MIXER_WRITE_BASS;
|
||||
mcSynth: Result := SOUND_MIXER_WRITE_SYNTH;
|
||||
mcPCM: Result := SOUND_MIXER_WRITE_PCM;
|
||||
mcSpeaker: Result := SOUND_MIXER_WRITE_SPEAKER;
|
||||
mcLine: Result := SOUND_MIXER_WRITE_LINE;
|
||||
mcMic: Result := SOUND_MIXER_WRITE_MIC;
|
||||
mcCD: Result := SOUND_MIXER_WRITE_CD;
|
||||
mcIMix: Result := SOUND_MIXER_WRITE_IMIX;
|
||||
mcAltPCM: Result := SOUND_MIXER_WRITE_ALTPCM;
|
||||
mcRecLev: Result := SOUND_MIXER_WRITE_RECLEV;
|
||||
mcUnknown: Result := 0;
|
||||
end;
|
||||
2:
|
||||
case Ch of
|
||||
mcVolume: Result := SOUND_MIXER_READ_VOLUME;
|
||||
mcTreble: Result := SOUND_MIXER_READ_TREBLE;
|
||||
mcBass: Result := SOUND_MIXER_READ_BASS;
|
||||
mcSynth: Result := SOUND_MIXER_READ_SYNTH;
|
||||
mcPCM: Result := SOUND_MIXER_READ_PCM;
|
||||
mcSpeaker: Result := SOUND_MIXER_READ_SPEAKER;
|
||||
mcLine: Result := SOUND_MIXER_READ_LINE;
|
||||
mcMic: Result := SOUND_MIXER_READ_MIC;
|
||||
mcCD: Result := SOUND_MIXER_READ_CD;
|
||||
mcIMix: Result := SOUND_MIXER_READ_IMIX;
|
||||
mcAltPCM: Result := SOUND_MIXER_READ_ALTPCM;
|
||||
mcRecLev: Result := SOUND_MIXER_READ_RECLEV;
|
||||
mcUnknown: Result := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetChannelType(Mask : Integer) : TACSMixerChannel;
|
||||
begin
|
||||
case Mask of
|
||||
SOUND_MIXER_VOLUME: Result := mcVolume;
|
||||
SOUND_MIXER_TREBLE: Result := mcTreble;
|
||||
SOUND_MIXER_BASS: Result := mcBass;
|
||||
SOUND_MIXER_SYNTH: Result := mcSynth;
|
||||
SOUND_MIXER_PCM: Result := mcPCM;
|
||||
SOUND_MIXER_SPEAKER: Result := mcSpeaker;
|
||||
SOUND_MIXER_LINE: Result := mcLine;
|
||||
SOUND_MIXER_MIC: Result := mcMic;
|
||||
SOUND_MIXER_CD: Result := mcCD;
|
||||
SOUND_MIXER_IMIX: Result := mcIMix;
|
||||
SOUND_MIXER_ALTPCM: Result := mcAltPCM;
|
||||
SOUND_MIXER_RECLEV: Result := mcRecLev;
|
||||
else Result := mcUnknown;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetDevNum(Num : Integer);
|
||||
var
|
||||
DevMask, i : Integer;
|
||||
Channel : TACSMixerChannel;
|
||||
begin
|
||||
if Num in [0..MixersCount - 1] then // check [0..0] [0..-1]
|
||||
begin
|
||||
FFileName := Mixers[Num].Path;
|
||||
FMixerName := Mixers[Num].Name;
|
||||
setlength(FChannels,0);
|
||||
_mix_fd := fpopen(PChar(FFileName), O_RDONLY);
|
||||
fpioctl(_mix_fd, SOUND_MIXER_READ_DEVMASK, @DevMask);
|
||||
fpclose(_mix_fd);
|
||||
for i:=0 to 31 do
|
||||
begin
|
||||
if (DevMask and (1 shl i)) <> 0 then
|
||||
begin
|
||||
Channel := GetChannelType(i);
|
||||
if Channel <> mcUnknown then
|
||||
begin
|
||||
setlength(FChannels,length(FChannels)+1);
|
||||
FChannels[length(FChannels)-1] := Channel;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSMixer.GetRecSource;
|
||||
var
|
||||
rs, pow,i : Integer;
|
||||
begin
|
||||
Result := -1;
|
||||
_mix_fd := fpopen(PChar(FFileName), O_RDONLY);
|
||||
fpioctl(_mix_fd, SOUND_MIXER_READ_RECSRC, @rs);
|
||||
fpclose(_mix_fd);
|
||||
pow := 0;
|
||||
while rs <> 1 do
|
||||
begin
|
||||
rs := rs shr 1;
|
||||
Inc(pow);
|
||||
end;
|
||||
for i := 0 to length(FChannels)-1 do
|
||||
if FChannels[i] = GetChannel(pow) then
|
||||
Result := i;
|
||||
end;
|
||||
|
||||
function TACSMixer.GetVolume;
|
||||
var
|
||||
vol, chan : Integer;
|
||||
begin
|
||||
_mix_fd := fpopen(PChar(FFileName), O_RDONLY);
|
||||
chan := GetChannelMask(FChannels[vChannel], 2);
|
||||
fpioctl(_mix_fd, chan, @vol);
|
||||
fpclose(_mix_fd);
|
||||
if vol > 255 then
|
||||
begin
|
||||
Result.Left := Lo(vol);
|
||||
Result.Right := Lo(vol shr 8);
|
||||
end else Result.Main := vol;
|
||||
end;
|
||||
|
||||
function TACSMixer.IsStereo;
|
||||
var
|
||||
mask, chan : Integer;
|
||||
begin
|
||||
_mix_fd := fpopen(PChar(FFileName), O_RDONLY);
|
||||
fpioctl(_mix_fd, SOUND_MIXER_READ_STEREODEVS, @mask);
|
||||
chan := GetChannelMask(FChannels[vChannel], 0);
|
||||
fpclose(_mix_fd);
|
||||
Result := (mask and (1 shl chan))<>0;
|
||||
end;
|
||||
|
||||
function TACSMixer.IsRecordable;
|
||||
var
|
||||
mask, chan : Integer;
|
||||
begin
|
||||
_mix_fd := fpopen(PChar(FFileName), O_RDONLY);
|
||||
fpioctl(_mix_fd, SOUND_MIXER_READ_RECMASK, @mask);
|
||||
chan := GetChannelMask(FChannels[vChannel], 0);
|
||||
fpclose(_mix_fd);
|
||||
Result := (mask and (1 shl chan))<>0;
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetRecSource;
|
||||
var
|
||||
chan : Integer;
|
||||
begin
|
||||
chan := 1 shl GetChannelMask(FChannels[vChannel], 0);
|
||||
_mix_fd := fpopen(PChar(FFileName), O_WRONLY);
|
||||
fpioctl(_mix_fd, SOUND_MIXER_WRITE_RECSRC, @chan);
|
||||
fpclose(_mix_fd);
|
||||
if chan <> (1 shl GetChannelMask(FChannels[vChannel], 0)) then
|
||||
raise EACSException.Create(Format(strChannelnotRecordable,[vChannel]));
|
||||
end;
|
||||
|
||||
function TACSMixer.GetMute(vChannel : integer) : Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetMute(vChannel : integer; Mute : Boolean);
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetVolume;
|
||||
var
|
||||
vol, chan : Integer;
|
||||
begin
|
||||
chan := GetChannelMask(FChannels[vChannel], 1);
|
||||
if IsStereo(vChannel) then
|
||||
vol := vLevel.Left + (vLevel.Right shl 8)
|
||||
else vol := vLevel.Main;
|
||||
_mix_fd := fpopen(PChar(FFileName), O_WRONLY);
|
||||
fpioctl(_mix_fd, chan, @vol);
|
||||
fpclose(_mix_fd);
|
||||
end;
|
||||
|
||||
destructor TACSMixer.Destroy;
|
||||
begin
|
||||
Setlength(FChannels,0);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function CountMixers : Byte;
|
||||
var
|
||||
fd, i, DevMask : Integer;
|
||||
fname : String;
|
||||
mi : mixer_info;
|
||||
begin
|
||||
Result := 0;
|
||||
for i := 0 to MAX_MIXERS-1 do
|
||||
begin
|
||||
fname := '/dev/mixer'+IntToStr(i-1);
|
||||
try
|
||||
fd := fpopen(PChar(fname), O_RDONLY);
|
||||
except
|
||||
Break;
|
||||
end;
|
||||
if fd = -1 then Break;
|
||||
DevMask := 0;
|
||||
fpioctl(fd, SOUND_MIXER_READ_DEVMASK, @DevMask);
|
||||
if DevMask <> 0 then
|
||||
begin
|
||||
Mixers[Result].Path := fname;
|
||||
fpioctl(fd, SOUND_MIXER_INFO, @mi);
|
||||
Mixers[Result].Name := String(mi.name);
|
||||
Inc(Result);
|
||||
end;
|
||||
fpclose(fd);
|
||||
end;
|
||||
fname := '/dev/mixer';
|
||||
try
|
||||
fd := fpopen(PChar(fname), O_RDONLY);
|
||||
except
|
||||
Exit;
|
||||
end;
|
||||
if fd = -1 then Exit;
|
||||
fpioctl(fd, SOUND_MIXER_READ_DEVMASK, @DevMask);
|
||||
if DevMask <> 0 then
|
||||
begin
|
||||
Mixers[Result].Path := fname;
|
||||
fpioctl(fd, SOUND_MIXER_INFO, @mi);
|
||||
Mixers[Result].Name := String(mi.name);
|
||||
end;
|
||||
fpclose(fd);
|
||||
Inc(Result);
|
||||
end;
|
||||
|
392
acs/Src/classes/linux/cd_rom.pas
Normal file
392
acs/Src/classes/linux/cd_rom.pas
Normal file
@@ -0,0 +1,392 @@
|
||||
(* cd_rom kylix unit
|
||||
translated from cdrom.h by andrei borovsky.
|
||||
|
||||
this unit contains declarations translated
|
||||
from the huge cdrom.h header file. In fact
|
||||
cdrom.h covers a lot of stuff concerning
|
||||
CDs, DVDs, writable CDs, etc. Of all these
|
||||
there are only the declarations needed for
|
||||
reading/playing CDs in this unit. *)
|
||||
(*
|
||||
This file is a part of Audio Components Suite v 2.3.
|
||||
Copyright (c) 2002-2005 Andrei Borovsky. All rights reserved.
|
||||
See the LICENSE file for more details.
|
||||
You can contact me at mail@z0m3ie.de
|
||||
*)
|
||||
|
||||
{
|
||||
$Log: cd_rom.pas,v $
|
||||
Revision 1.3 2005/12/19 18:35:03 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
Revision 1.2 2005/08/22 20:17:01 z0m3ie
|
||||
changed Headers to log
|
||||
changed mail adress
|
||||
|
||||
}
|
||||
|
||||
|
||||
unit cd_rom;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
baseunix,unix;
|
||||
|
||||
type
|
||||
__U8 = Byte;
|
||||
request_sense = Byte;
|
||||
(* request_sense is a bitmask : veeeeeee
|
||||
v - valid
|
||||
eeeeeee - error code
|
||||
*)
|
||||
PRequest_sense = ^request_sense;
|
||||
|
||||
//const
|
||||
// EDRIVE_CANT_DO_THIS = EOPNOTSUPP;
|
||||
|
||||
(*
|
||||
The CD-ROM IOCTL commands -- these should be supported by }
|
||||
all the various cdrom drivers. For the CD-ROM ioctls, we }
|
||||
will commandeer byte 0x53, or 'S'. *)
|
||||
|
||||
const
|
||||
|
||||
CDROMPAUSE = $5301; // Pause Audio Operation
|
||||
CDROMRESUME = $5302; // Resume paused Audio Operation
|
||||
CDROMPLAYMSF = $5303; // Play Audio MSF (struct cdrom_msf)
|
||||
CDROMPLAYTRKIND = $5304; // Play Audio Track/index
|
||||
CDROMREADTOCHDR = $5305; // Read TOC header
|
||||
CDROMREADTOCENTRY = $5306; // Read TOC entry
|
||||
CDROMSTOP = $5307; // Stop the cdrom drive
|
||||
CDROMSTART = $5308; // Start the cdrom drive
|
||||
CDROMEJECT = $5309; // Ejects the cdrom media
|
||||
CDROMVOLCTRL = $530a; // Control output volume
|
||||
CDROMSUBCHNL = $530b; // Read subchannel data
|
||||
CDROMREADMODE2 = $530c; // Read CDROM mode 2 data (2336 Bytes)
|
||||
CDROMREADMODE1 = $530d; // Read CDROM mode 1 data (2048 Bytes)
|
||||
CDROMREADAUDIO = $530e; // (struct cdrom_read_audio)
|
||||
CDROMEJECT_SW = $530; // enable(1)/disable(0) auto-ejecting
|
||||
CDROMMULTISESSION = $5310; // Obtain the start-of-last-session
|
||||
CDROM_GET_MCN = $5311; // Obtain the "Universal Product Code"
|
||||
CDROM_GET_UPC = CDROM_GET_MCN; // depricated
|
||||
CDROMRESET = $5312; // hard-reset the drive
|
||||
CDROMVOLREAD = $5313; // Get the drive's volume setting
|
||||
CDROMREADRAW = $5314; // read data in raw mode (2352 Bytes)
|
||||
|
||||
{ These ioctls are used only used in aztcd.c and optcd.c }
|
||||
|
||||
CDROMREADCOOKED = $5315; // read data in cooked mode
|
||||
CDROMSEEK = $5316; // seek msf address
|
||||
|
||||
{ This ioctl is only used by the scsi-cd driver. }
|
||||
{ It is for playing audio in logical block addressing mode. }
|
||||
|
||||
CDROMPLAYBLK = $5317; // (struct cdrom_blk)
|
||||
|
||||
{ These ioctls are only used in optcd.c }
|
||||
|
||||
CDROMREADALL = $5318; // read all 2646 bytes
|
||||
|
||||
(* These ioctls are (now) only in ide-cd.c for controlling
|
||||
drive spindown time. They should be implemented in the
|
||||
Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10,
|
||||
GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE...
|
||||
-Erik *)
|
||||
|
||||
const
|
||||
|
||||
CDROMGETSPINDOWN = $531d;
|
||||
CDROMSETSPINDOWN = $531e;
|
||||
|
||||
(* These ioctls are implemented through the uniform CD-ROM driver
|
||||
They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM
|
||||
drivers are eventually ported to the uniform CD-ROM driver interface. *)
|
||||
|
||||
const
|
||||
|
||||
CDROMCLOSETRAY = $5319; // pendant of CDROMEJECT
|
||||
CDROM_SET_OPTIONS = $5320; // Set behavior options
|
||||
CDROM_CLEAR_OPTIONS = $5321; // Clear behavior options
|
||||
CDROM_SELECT_SPEED = $5322; // Set the CD-ROM speed
|
||||
CDROM_SELECT_DISC = $5323; // Select disc (for juke-boxes)
|
||||
CDROM_MEDIA_CHANGED = $5325; // Check is media changed
|
||||
CDROM_DRIVE_STATUS = $5326; // Get tray position, etc.
|
||||
CDROM_DISC_STATUS = $5327; // Get disc type, etc.
|
||||
CDROM_CHANGER_NSLOTS = $5328; // Get number of slots
|
||||
CDROM_LOCKDOOR = $5329; // lock or unlock door
|
||||
CDROM_DEBUG = $5330; // Turn debug messages on/off
|
||||
CDROM_GET_CAPABILITY = $5331; // get capabilities
|
||||
|
||||
// This ioctl is only used by sbpcd at the moment
|
||||
|
||||
CDROMAUDIOBUFSIZ = $5382; // set the audio buffer size
|
||||
CDROM_SEND_PACKET = $5393; // send a packet to the drive
|
||||
CDROM_NEXT_WRITABLE = $5394; // get next writable block
|
||||
CDROM_LAST_WRITTEN = $5395; // get last block written on disc
|
||||
|
||||
//******************************************************}
|
||||
// CDROM IOCTL structures
|
||||
//******************************************************}
|
||||
|
||||
type
|
||||
|
||||
// Address in MSF format
|
||||
cdrom_msf0 = record
|
||||
minute: __U8;
|
||||
second: __U8;
|
||||
frame: __U8;
|
||||
end;
|
||||
|
||||
// Address in either MSF or logical format
|
||||
cdrom_addr = record
|
||||
case Word of
|
||||
1: (msf: cdrom_msf0;);
|
||||
2: (lba: Integer;);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
(* cdrom_msf renamed to cdrom_msf_t since there is
|
||||
also a cdrom_msf constant in this unit *)
|
||||
|
||||
// This struct is used by the CDROMPLAYMSF ioctl
|
||||
cdrom_msf_t = record
|
||||
cdmsf_min0: __U8; // start minute
|
||||
cdmsf_sec0: __U8; // start second
|
||||
cdmsf_frame0: __U8; // start frame
|
||||
cdmsf_min1: __U8; // end minute
|
||||
cdmsf_sec1: __U8; // end second
|
||||
cdmsf_frame1: __U8; // end frame
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMPLAYTRKIND ioctl
|
||||
cdrom_ti = record
|
||||
cdti_trk0: __U8; // start track
|
||||
cdti_ind0: __U8; // start index
|
||||
cdti_trk1: __U8; // end track
|
||||
cdti_ind1: __U8; // end index
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMREADTOCHDR ioctl
|
||||
cdrom_tochdr = record
|
||||
cdth_trk0: __U8; // start track
|
||||
cdth_trk1: __U8; // end track
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls
|
||||
cdrom_volctrl = record
|
||||
channel0: __U8;
|
||||
channel1: __U8;
|
||||
channel2: __U8;
|
||||
channel3: __U8;
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMSUBCHNL ioctl
|
||||
cdrom_subchnl = record
|
||||
cdsc_format: __U8;
|
||||
cdsc_audiostatus: __U8;
|
||||
CDSC_ADR_CTRL : __U8; // 4 bits - ADR, 4 bits - CTRL
|
||||
cdsc_trk: __U8;
|
||||
cdsc_ind: __U8;
|
||||
cdsc_absaddr: cdrom_addr;
|
||||
cdsc_reladdr: cdrom_addr;
|
||||
end;
|
||||
|
||||
|
||||
// This struct is used by the CDROMREADTOCENTRY ioctl
|
||||
cdrom_tocentry = record
|
||||
cdte_track: __U8;
|
||||
cdte_adr_ctrl: __U8;
|
||||
cdte_format: __U8;
|
||||
cdte_addr: cdrom_addr;
|
||||
cdte_datamode: __U8;
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMREADMODE1, and CDROMREADMODE2 ioctls
|
||||
cdrom_read = record
|
||||
cdread_lba: Integer;
|
||||
cdread_bufaddr: PChar;
|
||||
cdread_buflen: Integer;
|
||||
end;
|
||||
|
||||
// This struct is used by the CDROMREADAUDIO ioctl
|
||||
cdrom_read_audio = record
|
||||
addr: cdrom_addr; // frame address
|
||||
addr_format: __U8; // CDROM_LBA or CDROM_MSF
|
||||
nframes: Integer; // number of 2352-byte-frames to read at once
|
||||
buf: PChar; // frame buffer (size: nframes*2352 bytes)
|
||||
end;
|
||||
|
||||
// This struct is used with the CDROMMULTISESSION ioctl
|
||||
cdrom_multisession = record
|
||||
addr: cdrom_addr;
|
||||
(* frame address: start-of-last-session
|
||||
(not the new "frame 16"!). Only valid
|
||||
if the "xa_flag" is true. *)
|
||||
xa_flag: __U8; // 1: "is XA disk"
|
||||
addr_format: __U8; // CDROM_LBA or CDROM_MSF }
|
||||
end;
|
||||
|
||||
(* This struct is used with the CDROM_GET_MCN ioctl.
|
||||
Very few audio discs actually have Universal Product Code information,
|
||||
which should just be the Medium Catalog Number on the box. Also note
|
||||
that the way the codeis written on CD is _not_ uniform across all discs! *)
|
||||
|
||||
cdrom_mcn = record
|
||||
medium_catalog_number: array[0..13] of __U8;
|
||||
{ 13 ASCII digits, null-terminated }
|
||||
end;
|
||||
|
||||
// This is used by the CDROMPLAYBLK ioctl
|
||||
type
|
||||
cdrom_blk = record
|
||||
from: Word;
|
||||
len: Word;
|
||||
end;
|
||||
|
||||
const
|
||||
CDROM_PACKET_SIZE = 12;
|
||||
CGC_DATA_UNKNOWN = 0;
|
||||
CGC_DATA_WRITE = 1;
|
||||
CGC_DATA_READ = 2;
|
||||
CGC_DATA_NONE = 3;
|
||||
|
||||
// for CDROM_PACKET_COMMAND ioctl
|
||||
type
|
||||
cdrom_generic_command = record
|
||||
cmd: array[0..CDROM_PACKET_SIZE-1] of Byte;
|
||||
buffer: PByte;
|
||||
buflen: Word;
|
||||
stat: Integer;
|
||||
sense: PREQUEST_SENSE;
|
||||
data_direction: Byte;
|
||||
quiet: Integer;
|
||||
timeout: Integer;
|
||||
reserved: array[0..0] of Pointer;
|
||||
end;
|
||||
|
||||
// Some generally useful CD-ROM information -- mostly based on the above
|
||||
const
|
||||
|
||||
CD_MINS = 74; // max. minutes per CD, not really a limit
|
||||
CD_SECS = 60; // seconds per minute
|
||||
CD_FRAMES = 75; // frames per second
|
||||
CD_SYNC_SIZE = 12; // 12 sync bytes per raw data frame
|
||||
CD_MSF_OFFSET = 150; // MSF numbering offset of first frame
|
||||
CD_CHUNK_SIZE = 24; // lowest-level 'data bytes piece'
|
||||
CD_NUM_OF_CHUNKS = 98; // chunks per frame
|
||||
CD_FRAMESIZE_SUB = 96; // subchannel data 'frame' size
|
||||
CD_HEAD_SIZE = 4; // header (address) bytes per raw data frame
|
||||
CD_SUBHEAD_SIZE = 8; // subheader bytes per raw XA data frame
|
||||
CD_EDC_SIZE = 4; // bytes EDC per most raw data frame types
|
||||
CD_ZERO_SIZE = 8; // bytes zero per yellow book mode 1 frame
|
||||
CD_ECC_SIZE = 276; // bytes ECC per most raw data frame types
|
||||
CD_FRAMESIZE = 2048; // bytes per frame, 'cooked' mode
|
||||
CD_FRAMESIZE_RAW = 2352; // bytes per frame, 'raw' mode
|
||||
CD_FRAMESIZE_RAWER = 2646; // The maximum possible returned bytes
|
||||
|
||||
// most drives don't deliver everything:
|
||||
|
||||
CD_FRAMESIZE_RAW1 = (CD_FRAMESIZE_RAW-CD_SYNC_SIZE); //2340
|
||||
CD_FRAMESIZE_RAW0 = (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE); //2336
|
||||
CD_XA_HEAD = (CD_HEAD_SIZE+CD_SUBHEAD_SIZE); // 'before data' part of raw XA frame
|
||||
CD_XA_TAIL = (CD_EDC_SIZE+CD_ECC_SIZE); // 'after data' part of raw XA frame
|
||||
CD_XA_SYNC_HEAD = (CD_SYNC_SIZE+CD_XA_HEAD); // sync bytes + header of XA frame
|
||||
|
||||
// CD-ROM address types (cdrom_tocentry.cdte_format)
|
||||
|
||||
CDROM_LBA = $01; // 'logical block': first frame is #0
|
||||
CDROM_MSF = $02; // 'minute-second-frame': binary, not bcd here!
|
||||
|
||||
// bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl)
|
||||
|
||||
CDROM_DATA_TRACK = $40;
|
||||
|
||||
// The leadout track is always 0xAA, regardless of # of tracks on disc
|
||||
|
||||
CDROM_LEADOUT = $AA;
|
||||
|
||||
// audio states (from SCSI-2, but seen with other drives, too)
|
||||
|
||||
CDROM_AUDIO_INVALID = $00; // audio status not supported
|
||||
CDROM_AUDIO_PLAY = $11; // audio play operation in progress
|
||||
CDROM_AUDIO_PAUSED = $12; // audio play operation paused
|
||||
CDROM_AUDIO_COMPLETED = $13; // audio play successfully completed
|
||||
CDROM_AUDIO_ERROR = $14; // audio play stopped due to error
|
||||
CDROM_AUDIO_NO_STATUS = $15; // no current audio status to return
|
||||
|
||||
// capability flags used with the uniform CD-ROM driver
|
||||
|
||||
CDC_CLOSE_TRAY = $1; // caddy systems _can't_ close
|
||||
CDC_OPEN_TRAY = $2; // but _can_ eject.
|
||||
CDC_LOCK = $4; // disable manual eject
|
||||
CDC_SELECT_SPEED = $8; // programmable speed
|
||||
CDC_SELECT_DISC = $10; // select disc from juke-box
|
||||
CDC_MULTI_SESSION = $20; // read sessions>1
|
||||
CDC_MCN = $40; // Medium Catalog Number
|
||||
CDC_MEDIA_CHANGED = $80; // media changed
|
||||
CDC_PLAY_AUDIO = $100; // audio functions
|
||||
CDC_RESET = $200; // hard reset device
|
||||
CDC_IOCTLS = $400; // driver has non-standard ioctls
|
||||
CDC_DRIVE_STATUS = $800; // driver implements drive status
|
||||
CDC_GENERIC_PACKET = $1000; // driver implements generic packets
|
||||
CDC_CD_R = $2000; // drive is a CD-R
|
||||
CDC_CD_RW = $4000; // drive is a CD-RW
|
||||
CDC_DVD = $8000; // drive is a DVD
|
||||
CDC_DVD_R = $10000; // drive can write DVD-R
|
||||
CDC_DVD_RAM = $20000; // drive can write DVD-RAM
|
||||
|
||||
// drive status possibilities returned by CDROM_DRIVE_STATUS ioctl
|
||||
|
||||
CDS_NO_INFO = 0; // if not implemented
|
||||
CDS_NO_DISC = 1;
|
||||
CDS_TRAY_OPEN = 2;
|
||||
CDS_DRIVE_NOT_READY = 3;
|
||||
CDS_DISC_OK = 4;
|
||||
|
||||
(* return values for the CDROM_DISC_STATUS ioctl
|
||||
can also return CDS_NO_[INFO|DISC], from above *)
|
||||
|
||||
CDS_AUDIO = 100;
|
||||
CDS_DATA_1 = 101;
|
||||
CDS_DATA_2 = 102;
|
||||
CDS_XA_2_1 = 103;
|
||||
CDS_XA_2_2 = 104;
|
||||
CDS_MIXED = 105;
|
||||
|
||||
// User-configurable behavior options for the uniform CD-ROM driver
|
||||
|
||||
CDO_AUTO_CLOSE = $1; // close tray on first open()
|
||||
CDO_AUTO_EJECT = $2; // open tray on last release()
|
||||
CDO_USE_FFLAGS = $4; // use O_NONBLOCK information on open
|
||||
CDO_LOCK = $8; // lock tray on open files
|
||||
CDO_CHECK_TYPE = $10; // check type on open for data
|
||||
|
||||
// Special codes used when specifying changer slots.
|
||||
|
||||
CDSL_NONE = $7FFFFFFE;
|
||||
CDSL_CURRENT = $7FFFFFFF;
|
||||
|
||||
(* For partition based multisession access. IDE can handle 64 partitions
|
||||
per drive - SCSI CD-ROM's use minors to differentiate between the
|
||||
various drives, so we can't do multisessions the same way there.
|
||||
Use the -o session=x option to mount on them. *)
|
||||
|
||||
CD_PART_MAX = 64;
|
||||
CD_PART_MASK = (CD_PART_MAX - 1);
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
336
acs/Src/classes/windows/acs_cdrom.inc
Normal file
336
acs/Src/classes/windows/acs_cdrom.inc
Normal file
@@ -0,0 +1,336 @@
|
||||
{
|
||||
$Log: acs_cdrom.inc,v $
|
||||
Revision 1.12 2006/08/31 20:10:56 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.11 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.3 2006/01/03 15:37:51 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/12/26 17:31:39 z0m3ie
|
||||
fixed some problems in acs_dsfiles
|
||||
fixed some problems in acs_vorbis
|
||||
reworked all buffers
|
||||
|
||||
Revision 1.1 2005/12/19 18:35:16 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.3 2005/10/02 16:51:46 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.5 2005/09/09 21:33:43 z0m3ie
|
||||
linux corrections
|
||||
|
||||
Revision 1.4 2005/09/08 22:19:00 z0m3ie
|
||||
completed akrip based CDIn
|
||||
|
||||
Revision 1.3 2005/09/07 20:53:22 z0m3ie
|
||||
begon to add MPEG and WMA support using DirectX
|
||||
|
||||
Revision 1.2 2005/09/04 17:59:38 z0m3ie
|
||||
moving CDIn support to AKRip mostly
|
||||
begon to add mpegin support for Win with mpg123
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
}
|
||||
|
||||
type
|
||||
MSFAddr = array[0..3] of Byte;
|
||||
|
||||
function Toc2MSF(t : MSFAddr) : TACSCDMSF;
|
||||
begin
|
||||
Result.Minute := t[1];
|
||||
Result.Second := t[2];
|
||||
Result.Frame := t[3];
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.OpenCD;
|
||||
var
|
||||
GetCD: GETCDHAND;
|
||||
begin
|
||||
with GetCD do
|
||||
begin
|
||||
Size := SizeOf(GETCDHAND);
|
||||
Ver := 1;
|
||||
ha := 0;
|
||||
tgt := FCurrentDrive;
|
||||
lun := 0;
|
||||
readType := CDR_ANY;
|
||||
jitterCorr := false;
|
||||
numJitter := 0;
|
||||
numOverlap := 0;
|
||||
end;
|
||||
FCDHandle := GetCDHandle(GetCD);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.CloseCD;
|
||||
begin
|
||||
if FCDHandle <> 0 then
|
||||
CloseCDHandle(FCDHandle);
|
||||
FCDHandle := 0;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetInfo : TACSCDInfo;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
OpenCD;
|
||||
Result := cdiUnknown;
|
||||
ModifyCDParms(FCDHandle, CDP_MSF, DWORD(true));
|
||||
FillChar(FToc, SizeOf(FToc),0);
|
||||
if ReadTOC(FCDHandle, FTOC) <> 1 then
|
||||
begin
|
||||
Result := cdiNoDisc;
|
||||
Exit;
|
||||
end;
|
||||
for i := 0 to FToc.lastTrack-1 do
|
||||
begin
|
||||
if (FToc.Tracks[i].adr and $04) = 0 then
|
||||
begin
|
||||
case Result of
|
||||
cdiUnknown : Result := cdiDiscAudio;
|
||||
cdiDiscData : Result := cdiDiscMixed;
|
||||
end;
|
||||
end else
|
||||
begin
|
||||
case Result of
|
||||
cdiUnknown : Result := cdiDiscData;
|
||||
cdiDiscAudio : Result := cdiDiscMixed;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetStatus : TACSCDStatus;
|
||||
var
|
||||
ms : Integer;
|
||||
AP : LongBool;
|
||||
begin
|
||||
if FPlaying then
|
||||
Result := cdsPlaying
|
||||
else if (GetInfo <> cdiNoDisc) and (GetInfo <> cdiUnknown) then
|
||||
Result := cdsReady
|
||||
else
|
||||
Result := cdsNotReady;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetNumTracks : Integer;
|
||||
begin
|
||||
OpenCD;
|
||||
if FToc.lastTrack = 0 then
|
||||
begin
|
||||
ModifyCDParms(FCDHandle, CDP_MSF, DWORD(true));
|
||||
if ReadTOC(FCDHandle, FTOC) <> 1 then
|
||||
begin
|
||||
Result := -1;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result := FToc.lastTrack;
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
FUNCTION TACSCDIn.GetTrackInfo(const vIndex : Integer) : TACSCDTrackInfo;
|
||||
VAR
|
||||
Frames: Integer;
|
||||
tmpmsf : TACSCDMSF;
|
||||
BEGIN
|
||||
IF Busy THEN
|
||||
RAISE EACSException.Create(strBusy);
|
||||
IF (vIndex IN [0..GetNumTracks-1]) = False THEN
|
||||
RAISE EACSException.Create(strTrackoutofrange);
|
||||
IF (FToc.Tracks[vIndex].adr and $04) = 0 THEN
|
||||
Result.TrackType := ttAudio
|
||||
ELSE
|
||||
Result.TrackType := ttData;
|
||||
Result.TrackStart.Minute := FToc.Tracks[vIndex].addr[1];
|
||||
Result.TrackStart.Second := FToc.Tracks[vIndex].addr[2];
|
||||
Result.TrackStart.Frame := FToc.Tracks[vIndex].addr[3];
|
||||
Frames := MSF2Frames(Toc2MSF(MSFAddr(FToc.Tracks[vIndex+1].addr)))-MSF2Frames(Toc2MSF(MSFAddr(FToc.Tracks[vIndex].addr)));
|
||||
Frames2MSF(Frames, Result.TrackLength);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetST;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FStartTrack := Track;
|
||||
FStartPos.Track := FStartTrack;
|
||||
FillChar(FStartPos.MSF, SizeOf(FStartPos.MSF), 0);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetET;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FEndTrack := Track;
|
||||
FEndPos.Track := FEndTrack+1;
|
||||
FillChar(FEndPos.MSF, SizeOf(FEndPos.MSF), 0);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetSP;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FStartPos := Pos;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetEP;
|
||||
begin
|
||||
if Self.Busy then raise EACSException.Create(strBusy);
|
||||
FEndPos := Pos;
|
||||
if Pos.Track = EndOfDisc.Track then FEndPos.Track := TracksCount + 1;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetSize : Integer;
|
||||
var
|
||||
Sect1, Sect2 : Integer;
|
||||
begin
|
||||
if Busy then
|
||||
begin
|
||||
Result := FRipEnd-FRipStart*CD_FRAMESIZE_RAW;
|
||||
Exit;
|
||||
end;
|
||||
Sect1 := MSF2Frames(Toc2MSF(MSFAddr(FToc.tracks[FStartPos.Track].addr)));
|
||||
Sect1 := Sect1 + MSF2Frames(FStartPos.MSF);
|
||||
Sect2 := MSF2Frames(Toc2MSF(MSFAddr(FToc.tracks[FEndPos.Track].addr)));
|
||||
Sect2 := Sect2 + MSF2Frames(FEndPos.MSF);
|
||||
Result := (Sect2 - Sect1)*CD_FRAMESIZE_RAW;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Init;
|
||||
var
|
||||
Sect1, Sect2 : Integer;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
if Status = cdsNotReady then
|
||||
raise EACSException.Create(strDrivenotready);
|
||||
if (FStartPos.Track in [0..GetNumTracks-1]) = False then
|
||||
raise EACSException.Create(strTrackoutofRange);
|
||||
if Tracks[FStartPos.Track].TrackType = ttData then
|
||||
raise EACSException.Create(strnoAudioTreck);
|
||||
OpenCD;
|
||||
FSize := GetSize;
|
||||
FBusy := True;
|
||||
BufStart := 1;
|
||||
BufEnd := 0;
|
||||
FPosition := 0;
|
||||
Sect1 := MSF2Frames(Toc2MSF(MSFAddr(FToc.tracks[FStartPos.Track].addr)));
|
||||
Sect1 := Sect1 + MSF2Frames(FStartPos.MSF);
|
||||
Sect2 := MSF2Frames(Toc2MSF(MSFAddr(FToc.tracks[FEndPos.Track].addr)));
|
||||
Sect2 := Sect2 + MSF2Frames(FEndPos.MSF);
|
||||
FRipEnd := Sect2;
|
||||
FRipStart := Sect1;
|
||||
SetLength(FBuffer,(BUF_SIZE * CD_FRAMESIZE_RAW)+TRACKBUFEXTRA);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Flush;
|
||||
begin
|
||||
CloseCD;
|
||||
FBusy := False;
|
||||
Setlength(FBuffer,0);
|
||||
FBuffer := nil;
|
||||
FSize := 0;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetData(Buffer : Pointer; BufferSize : Integer): Integer;
|
||||
var
|
||||
Abort : LongBool;
|
||||
fnum : Integer;
|
||||
begin
|
||||
if not Busy then raise EACSException.Create(strStreamnotOpen);
|
||||
if BufStart > BufEnd then //Buffer clear try to fill it
|
||||
begin
|
||||
BufStart := 1;
|
||||
Abort := False;
|
||||
if FRipEnd-FRipStart > BUF_SIZE then
|
||||
fNum := BUF_SIZE
|
||||
else
|
||||
fNum := FRipEnd-FRipStart;
|
||||
FiBuffer^.startFrame := FRipStart;
|
||||
FiBuffer^.numFrames := fNum;
|
||||
FiBuffer^.maxLen := FiBuffer^.numFrames * CD_FRAMESIZE_RAW;
|
||||
FiBuffer^.len := 0;
|
||||
FiBuffer^.status := 0;
|
||||
FiBuffer^.startOffset := 0;
|
||||
if ReadCDAudioLBA(FCDHandle,FiBuffer) = 1 then
|
||||
begin
|
||||
Inc(FRipStart,FiBuffer^.numFrames);
|
||||
BufEnd := FiBuffer^.len;
|
||||
end;
|
||||
end;
|
||||
if BufferSize < (BufEnd - BufStart + 1) then
|
||||
Result := BufferSize
|
||||
else
|
||||
Result := BufEnd - BufStart + 1;
|
||||
Move(FiBuffer^.buf[BufStart-1],Buffer^, Result);
|
||||
Inc(BufStart, Result);
|
||||
Inc(FPosition, Result);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.SetCurrentDrive;
|
||||
begin
|
||||
if Value in [0..FCDList.num-1] then
|
||||
FCurrentDrive := Value;
|
||||
OpenCD;
|
||||
FillChar(FToc, SizeOf(FToc),0);
|
||||
ModifyCDParms(FCDHandle, CDP_MSF, DWORD(true));
|
||||
ReadTOC(FCDHandle, FTOC);
|
||||
CloseCD;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetDrivesCount : Integer;
|
||||
begin
|
||||
Result := FCDList.num;
|
||||
end;
|
||||
|
||||
function TACSCDIn.GetDriveName : string;
|
||||
begin
|
||||
Result := FCDList.Cd[FCurrentDrive].id;
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.Eject;
|
||||
begin
|
||||
if Busy then raise EACSException.Create(strBusy);
|
||||
end;
|
||||
|
||||
procedure TACSCDIn.CloseTray;
|
||||
begin
|
||||
end;
|
||||
|
||||
constructor TACSCDIn.Create;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
AppPath := ExtractFilePath(ParamStr(0));
|
||||
if AppPath[length(AppPath)] <> '\' then AppPath := AppPath + '\';
|
||||
CDRIPInit(AppPath);
|
||||
if not (csDesigning in ComponentState) then
|
||||
if not CDRipLoaded then
|
||||
raise EACSException.Create(akriplib + ' could not be loaded.');
|
||||
FillChar(FCDList, SizeOf(FCDList),0);
|
||||
FCDList.max := MAXCDLIST;
|
||||
GetCDList(FCDList);
|
||||
end;
|
||||
|
||||
destructor TACSCDIn.Destroy;
|
||||
begin
|
||||
if Busy then
|
||||
Flush;
|
||||
CloseCD;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
407
acs/Src/classes/windows/acs_mixer.inc
Normal file
407
acs/Src/classes/windows/acs_mixer.inc
Normal file
@@ -0,0 +1,407 @@
|
||||
{
|
||||
$Log: acs_mixer.inc,v $
|
||||
Revision 1.3 2006/07/04 17:12:45 z0m3ie
|
||||
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)
|
||||
|
||||
Revision 1.1 2005/12/19 18:35:16 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.3 2005/12/04 16:54:34 z0m3ie
|
||||
All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now)
|
||||
|
||||
Revision 1.2 2005/09/13 21:54:11 z0m3ie
|
||||
acs is localizeable now (ACS_Strings)
|
||||
|
||||
Revision 1.1 2005/09/12 22:04:52 z0m3ie
|
||||
modified structure again, fileformats are now in an sperat folder.
|
||||
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||||
|
||||
Revision 1.10 2005/08/31 20:30:40 z0m3ie
|
||||
Mixer Channelname work now
|
||||
minior corrections for Converters
|
||||
|
||||
Revision 1.9 2005/08/31 14:37:59 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.8 2005/08/30 22:10:55 z0m3ie
|
||||
Mixer mostly completed
|
||||
|
||||
Revision 1.7 2005/08/29 22:50:33 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.6 2005/08/29 21:46:43 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.5 2005/08/28 20:33:10 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.4 2005/08/28 18:35:53 z0m3ie
|
||||
created Delphi package for 2.4
|
||||
more Mixer stuff
|
||||
updated some things for Delphi
|
||||
|
||||
Revision 1.3 2005/08/26 17:12:56 z0m3ie
|
||||
*** empty log message ***
|
||||
|
||||
Revision 1.2 2005/08/26 17:03:20 z0m3ie
|
||||
begon to make acs resourcestring aware
|
||||
more advanced tmixer for windows
|
||||
restructured tmixer its better handleable now
|
||||
|
||||
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||||
Version 2.4 restructure
|
||||
TCDPlayer removed (fits not in component structure)
|
||||
TMP3ToWavConverter removed (fits not in component structure)
|
||||
|
||||
}
|
||||
|
||||
function mixerSetControlDetails(x1: HMIXEROBJ; x2: PMIXERCONTROLDETAILS; x3: DWORD): MMRESULT; stdcall;
|
||||
external 'winmm.dll' name
|
||||
'mixerSetControlDetails';
|
||||
|
||||
function GetChannelfromMask(Mask : DWORD) : TACSMixerChannel;
|
||||
begin
|
||||
case Mask of
|
||||
MIXERLINE_COMPONENTTYPE_DST_UNDEFINED : Result := mcUnknown;
|
||||
MIXERLINE_COMPONENTTYPE_DST_DIGITAL : Result := mcDigital;
|
||||
MIXERLINE_COMPONENTTYPE_DST_LINE : Result := mcLine;
|
||||
MIXERLINE_COMPONENTTYPE_DST_MONITOR : Result := mcMonitor;
|
||||
MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : Result := mcVolume;
|
||||
MIXERLINE_COMPONENTTYPE_DST_HEADPHONES : Result := mcHeadphone;
|
||||
MIXERLINE_COMPONENTTYPE_DST_TELEPHONE : Result := mcTelephone;
|
||||
MIXERLINE_COMPONENTTYPE_DST_WAVEIN : Result := mcPCM;
|
||||
MIXERLINE_COMPONENTTYPE_DST_VOICEIN : Result := mcUnknown;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED : Result := mcUnknown;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_DIGITAL : Result := mcDigital;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_LINE : Result := mcLine;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE : Result := mcMic;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: Result := mcSynth;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: Result := mcCD;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE : Result := mcTelephone;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER : Result := mcVolume;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : Result := mcPCM;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY : Result := mcAltPCM;
|
||||
MIXERLINE_COMPONENTTYPE_SRC_ANALOG : Result := mcUnknown;
|
||||
else
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetDevNum(Num : Integer);
|
||||
type
|
||||
TData = array [0..3] of MIXERCONTROLDETAILS_UNSIGNED;
|
||||
PData = ^TData;
|
||||
var
|
||||
destination,
|
||||
connection : Integer;
|
||||
data : PData;
|
||||
pmxctrl : PMixerControl;
|
||||
s : String;
|
||||
aLineInfo,
|
||||
aConnLineInfo : TMixerLine;
|
||||
error : Integer;
|
||||
|
||||
procedure GetLineControls(mixLineInfo : TMixerLine);
|
||||
var
|
||||
j, k,
|
||||
datasize : Integer;
|
||||
aLineControl : TMixerLineControls;
|
||||
aControlDetails: TMixerControlDetails;
|
||||
amixControl : PMixerControl;
|
||||
aControl : PControlEntry;
|
||||
begin
|
||||
with aLineControl do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerLineControls);
|
||||
dwLineID := mixLineInfo.dwLineID;
|
||||
cControls := mixLineInfo.cControls;
|
||||
cbmxctrl := SizeOf(TMixerControl);
|
||||
GetMem(amixControl, SizeOf(TMixerControl) * mixLineInfo.cControls);
|
||||
pamxctrl := amixControl;
|
||||
end;
|
||||
error := mixerGetLineControls(Num, @aLineControl, MIXER_GETLINECONTROLSF_ALL);
|
||||
pmxctrl := amixControl;
|
||||
for j := 0 TO aLineControl.cControls -1 do
|
||||
begin
|
||||
if (pmxctrl^.dwControlType <> MIXERCONTROL_CONTROLTYPE_VOLUME)
|
||||
and (pmxctrl^.dwControlType <> MIXERCONTROL_CONTROLTYPE_MUTE) then
|
||||
continue;
|
||||
if (pmxctrl^.fdwControl and MIXERCONTROL_CONTROLF_UNIFORM) > 0 then
|
||||
aControlDetails.cChannels := 1
|
||||
else
|
||||
aControlDetails.cChannels := mixLineInfo.cChannels;
|
||||
if (pmxctrl^.fdwControl AND MIXERCONTROL_CONTROLF_MULTIPLE) > 0 then
|
||||
begin
|
||||
aControlDetails.cMultipleItems := pmxctrl^.cMultipleItems;
|
||||
Getmem(data,pmxctrl^.cMultipleItems * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := pmxctrl^.cMultipleItems;
|
||||
end
|
||||
else
|
||||
begin
|
||||
aControlDetails.cMultipleItems := 0;
|
||||
Getmem(data, aControlDetails.cChannels * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := aControlDetails.cChannels;
|
||||
end;
|
||||
with aControlDetails do
|
||||
begin
|
||||
cbStruct := sizeOf(TmixerControlDetails);
|
||||
dwControlID := pmxctrl^.dwControlID;
|
||||
cbDetails := SizeOf(MIXERCONTROLDETAILS_UNSIGNED);
|
||||
paDetails := data;
|
||||
end;
|
||||
error := mixerGetControlDetails(Num, @aControlDetails, MIXER_GETCONTROLDETAILSF_VALUE );
|
||||
if (pmxctrl^.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE) then
|
||||
begin
|
||||
setlength(FMuteControls,length(FControls)+1);
|
||||
aControl := @FMuteControls[length(FControls)-1];
|
||||
end
|
||||
else
|
||||
begin
|
||||
setlength(FControls,length(FControls)+1);
|
||||
aControl := @FControls[length(FControls)-1];
|
||||
end;
|
||||
setlength(FChannels,Max(length(FControls),length(FMuteControls)));
|
||||
with aControl^, pmxctrl^, aControlDetails do
|
||||
begin
|
||||
IsInited := True;
|
||||
CDestination := mixLineInfo.dwDestination;
|
||||
CName := String(szShortname);
|
||||
CComponentTyp := mixLineInfo.dwComponentType;
|
||||
CKanal := cChannels;
|
||||
CID := dwControlID;
|
||||
CConnect := mixLineInfo.cConnections;
|
||||
CCControls := mixLineInfo.cControls;
|
||||
CControl := fdwControl;
|
||||
CControlTyp := dwControlType;
|
||||
CMultItems := cMultipleItems;
|
||||
CMax := Bounds.lMaximum;
|
||||
CMin := Bounds.lMinimum;
|
||||
CcSteps := Metrics.cSteps;
|
||||
for k := 0 to datasize -1 do
|
||||
CDetails[k].dwValue := data^[k].dwvalue;
|
||||
end;
|
||||
FChannels[length(FControls)-1] := GetChannelfromMask(aControl.CComponentTyp);
|
||||
Freemem(data);
|
||||
inc(pmxctrl);
|
||||
end;
|
||||
Freemem(amixControl);
|
||||
end;
|
||||
|
||||
begin
|
||||
if Num in [0..MixersCount - 1] then // check [0..0] [0..-1]
|
||||
begin
|
||||
setlength(FChannels,0);
|
||||
setlength(FControls,0);
|
||||
setlength(FMuteControls,0);
|
||||
error := mixerGetDevCaps(Num, @FMixerCaps, sizeof(TMixerCaps));
|
||||
FMixer := Num;
|
||||
FMixerName := StrPas(FMixerCaps.szPName);
|
||||
error := mixerOpen(@Num, 0, 0, 0, MIXER_OBJECTF_MIXER);
|
||||
if error = MMSYSERR_NOERROR then
|
||||
begin
|
||||
for destination := 0 to FMixerCaps.cDestinations - 1 do
|
||||
begin
|
||||
aLineInfo.cbStruct := SizeOf(TMixerLine);
|
||||
aLineInfo.dwDestination := destination;
|
||||
error := mixerGetLineInfo(Num, @aLineInfo, MIXER_GETLINEINFOF_DESTINATION);
|
||||
if aLineInfo.dwComponentType <> MIXERLINE_COMPONENTTYPE_DST_SPEAKERS then
|
||||
continue;
|
||||
GetLineControls(aLineInfo);
|
||||
for connection := 0 TO aLineInfo.cConnections-1 do
|
||||
begin
|
||||
with aConnLineInfo do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerLine);
|
||||
dwDestination := destination;
|
||||
dwSource := connection;
|
||||
end;
|
||||
error := mixerGetLineInfo(Num, @aConnLineInfo, MIXER_GETLINEINFOF_SOURCE);
|
||||
GetLineControls(aConnLineInfo);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TACSMixer.GetVolume(vChannel : Integer) : TACSMixerLevel;
|
||||
type
|
||||
TData = array [0..3] of MIXERCONTROLDETAILS_UNSIGNED;
|
||||
PData = ^TData;
|
||||
var
|
||||
data : PData;
|
||||
aControldetails : TMixerControlDetails;
|
||||
datasize,k : Integer;
|
||||
begin
|
||||
if vChannel >= length(FControls) then
|
||||
exit;
|
||||
if FControls[vChannel].IsInited = False then
|
||||
exit;
|
||||
if (FControls[vChannel].CControl and MIXERCONTROL_CONTROLF_UNIFORM) > 0 then
|
||||
aControlDetails.cChannels := 1
|
||||
else
|
||||
aControlDetails.cChannels := FControls[vChannel].CKanal;
|
||||
if (FControls[vChannel].CControl AND MIXERCONTROL_CONTROLF_MULTIPLE) > 0 then
|
||||
begin
|
||||
aControlDetails.cMultipleItems := FControls[vChannel].CMultItems;
|
||||
Getmem(data, FControls[vChannel].CMultItems * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := FControls[vChannel].CMultItems;
|
||||
end
|
||||
else
|
||||
begin
|
||||
aControlDetails.cMultipleItems := 0;
|
||||
Getmem(data, aControlDetails.cChannels * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := aControlDetails.cChannels;
|
||||
end;
|
||||
with aControlDetails do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerControlDetails);
|
||||
dwControlID := FControls[vChannel].CID;
|
||||
cChannels := FControls[vChannel].CKanal;
|
||||
cMultipleItems := FControls[vChannel].CMultItems;
|
||||
cbDetails := sizeof(MIXERCONTROLDETAILS_Signed);
|
||||
padetails := data;
|
||||
end;
|
||||
mixerGetControlDetails(FMixer, @aControlDetails,MIXER_GETCONTROLDETAILSF_VALUE );
|
||||
with FControls[vChannel] do
|
||||
begin
|
||||
for k := 0 to datasize -1 do
|
||||
CDetails[k].dwValue := data^[k].dwvalue;
|
||||
end;
|
||||
Freemem(data);
|
||||
if IsStereo(vChannel) then
|
||||
begin
|
||||
Result.Left := round((FControls[vChannel].CDetails[0].dwValue*255)/FControls[vChannel].Cmax);
|
||||
Result.Right := round((FControls[vChannel].CDetails[1].dwValue*255)/FControls[vChannel].Cmax);
|
||||
end
|
||||
else
|
||||
Result.Main := round((FControls[vChannel].CDetails[0].dwValue*255)/FControls[vChannel].Cmax);
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetVolume(vChannel : Integer; vLevel : TACSMixerLevel);
|
||||
var
|
||||
aControlDetails : TMixerControlDetails;
|
||||
begin
|
||||
if vChannel >= length(FControls) then
|
||||
exit;
|
||||
if IsStereo(vChannel) then
|
||||
begin
|
||||
FControls[vChannel].CDetails[0].dwValue := round((vLevel.Left*FControls[vChannel].CMax)/255);
|
||||
FControls[vChannel].CDetails[1].dwValue := round((vLevel.Right*FControls[vChannel].CMax)/255);
|
||||
end
|
||||
else
|
||||
FControls[vChannel].CDetails[0].dwValue := round((vLevel.Main*FControls[vChannel].CMax)/255);
|
||||
with aControlDetails do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerControlDetails);
|
||||
dwControlID := FControls[vChannel].CID;
|
||||
cChannels := FControls[vChannel].CKanal;
|
||||
cMultipleItems := 0;
|
||||
cbDetails := sizeof(MIXERCONTROLDETAILS_Signed);
|
||||
padetails := @FControls[vChannel].CDetails;
|
||||
end;
|
||||
mixerSetControlDetails(FMixer, @aControlDetails,MIXER_SETCONTROLDETAILSF_Value);
|
||||
end;
|
||||
|
||||
function TACSMixer.IsStereo(vChannel : Integer) : Boolean;
|
||||
begin
|
||||
if vChannel >= length(FControls) then
|
||||
exit;
|
||||
Result := not (FControls[vChannel].CKanal = 1);
|
||||
end;
|
||||
|
||||
function TACSMixer.GetMute(vChannel : integer) : Boolean;
|
||||
type
|
||||
TData = array [0..3] of MIXERCONTROLDETAILS_UNSIGNED;
|
||||
PData = ^TData;
|
||||
var
|
||||
data : PData;
|
||||
aControldetails : TMixerControlDetails;
|
||||
datasize,k : Integer;
|
||||
begin
|
||||
if vChannel >= length(FMuteControls) then
|
||||
exit;
|
||||
if FMuteControls[vChannel].IsInited = False then
|
||||
exit;
|
||||
if (FMuteControls[vChannel].CControl and MIXERCONTROL_CONTROLF_UNIFORM) > 0 then
|
||||
aControlDetails.cChannels := 1
|
||||
else
|
||||
aControlDetails.cChannels := FMuteControls[vChannel].CKanal;
|
||||
if (FMuteControls[vChannel].CControl AND MIXERCONTROL_CONTROLF_MULTIPLE) > 0 then
|
||||
begin
|
||||
aControlDetails.cMultipleItems := FMuteControls[vChannel].CMultItems;
|
||||
Getmem(data, FMuteControls[vChannel].CMultItems * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := FMuteControls[vChannel].CMultItems;
|
||||
end
|
||||
else
|
||||
begin
|
||||
aControlDetails.cMultipleItems := 0;
|
||||
Getmem(data, aControlDetails.cChannels * SizeOf(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
datasize := aControlDetails.cChannels;
|
||||
end;
|
||||
with aControlDetails do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerControlDetails);
|
||||
dwControlID := FMuteControls[vChannel].CID;
|
||||
cChannels := FMuteControls[vChannel].CKanal;
|
||||
cMultipleItems := FMuteControls[vChannel].CMultItems;
|
||||
cbDetails := sizeof(MIXERCONTROLDETAILS_Signed);
|
||||
padetails := data;
|
||||
end;
|
||||
mixerGetControlDetails(FMixer, @aControlDetails,MIXER_GETCONTROLDETAILSF_VALUE );
|
||||
with FMuteControls[vChannel] do
|
||||
begin
|
||||
for k := 0 to datasize -1 do
|
||||
CDetails[k].dwValue := data^[k].dwvalue;
|
||||
end;
|
||||
Freemem(data);
|
||||
Result := (FMuteControls[vChannel].CDetails[0].dwValue = 1);
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetMute(vChannel : integer; Mute : Boolean);
|
||||
var
|
||||
aControlDetails : TMixerControlDetails;
|
||||
begin
|
||||
if vChannel >= length(FMuteControls) then
|
||||
exit;
|
||||
if FMuteControls[vChannel].IsInited = False then
|
||||
exit;
|
||||
if Mute then
|
||||
FMuteControls[vChannel].CDetails[0].dwValue := 1
|
||||
else
|
||||
FMuteControls[vChannel].CDetails[0].dwValue := 0;
|
||||
with aControlDetails do
|
||||
begin
|
||||
cbStruct := SizeOf(TMixerControlDetails);
|
||||
dwControlID := FMuteControls[vChannel].CID;
|
||||
cChannels := FMuteControls[vChannel].CKanal;
|
||||
cMultipleItems := 0;
|
||||
cbDetails := sizeof(MIXERCONTROLDETAILS_Signed);
|
||||
padetails := @FMuteControls[vChannel].CDetails;
|
||||
end;
|
||||
mixerSetControlDetails(FMixer, @aControlDetails,MIXER_SETCONTROLDETAILSF_Value);
|
||||
end;
|
||||
|
||||
function TACSMixer.IsRecordable(vChannel : Integer) : Boolean;
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TACSMixer.SetRecSource(vChannel : Integer);
|
||||
begin
|
||||
end;
|
||||
|
||||
function TACSMixer.GetRecSource : Integer;
|
||||
begin
|
||||
end;
|
||||
|
||||
destructor TACSMixer.Destroy;
|
||||
begin
|
||||
Setlength(FControls,0);
|
||||
Setlength(FMuteControls,0);
|
||||
Setlength(FChannels,0);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function CountMixers : Byte;
|
||||
begin
|
||||
Result := mixerGetNumDevs;
|
||||
end;
|
||||
|
332
acs/Src/classes/windows/akrip32.pas
Normal file
332
acs/Src/classes/windows/akrip32.pas
Normal file
@@ -0,0 +1,332 @@
|
||||
unit akrip32;
|
||||
{*
|
||||
* akrip32.h - copyright (c) 1999 jay a. key
|
||||
*
|
||||
* api for akrip32.dll (v0.93)
|
||||
*
|
||||
* modified for acs (dynamic loading ...) y christian ulrich (mail@z0m3ie.de)
|
||||
* translated for borland delphi by holger dors (holger@dors.de)
|
||||
*
|
||||
* history of delphi version:
|
||||
*
|
||||
* 09. january 2000: first released version
|
||||
* 05. February 2000: Updated for new function "CDDBGetServerList"
|
||||
* in V.093 of akrip32.dll
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*}
|
||||
|
||||
interface
|
||||
|
||||
uses windows;
|
||||
|
||||
const
|
||||
|
||||
TRACK_AUDIO = $00;
|
||||
TRACK_DATA = $01;
|
||||
|
||||
MAXIDLEN = 64;
|
||||
MAXCDLIST = 8;
|
||||
|
||||
{*
|
||||
* TRACKBUF
|
||||
*
|
||||
* This structure should not be allocated directly. If a buffer containing
|
||||
* 27 * 2353 bytes is desired, a buffer should be allocated containing
|
||||
* the desired amount + 24 bytes. The allocated memory can then be
|
||||
* typecast to a LPTRACKBUF. It is the program's responsibility to guard
|
||||
* against reading/writing past the end of allocated memory.
|
||||
*
|
||||
* The following must always apply:
|
||||
* (len + startOffset) <= (numFrames * 2352) <= maxLen
|
||||
*}
|
||||
|
||||
type
|
||||
PTRACKBUF = ^TRACKBUF;
|
||||
TRACKBUF = record
|
||||
startFrame: DWord; {* 00: starting frame number *}
|
||||
numFrames: DWord; {* 04: number of frames read *}
|
||||
maxLen: DWord; {* 08: length of buffer itself *}
|
||||
len: DWord; {* 0C: length of data actually in buf *}
|
||||
status: DWord; {* 10: status of last read operation *}
|
||||
startOffset: Integer; {* 14: offset of valid data in buf *}
|
||||
buf: array[0..1024 * 1024 - 1] of Byte; {* 18: the data itself *}
|
||||
end;
|
||||
|
||||
TRACKBUFDUMMY = record
|
||||
startFrame: DWord; {* 00: starting frame number *}
|
||||
numFrames: DWord; {* 04: number of frames read *}
|
||||
maxLen: DWord; {* 08: length of buffer itself *}
|
||||
len: DWord; {* 0C: length of data actually in buf *}
|
||||
status: DWord; {* 10: status of last read operation *}
|
||||
startOffset: Integer; {* 14: offset of valid data in buf *}
|
||||
end;
|
||||
|
||||
const
|
||||
TRACKBUFEXTRA = SizeOf(TRACKBUFDUMMY);
|
||||
|
||||
type
|
||||
PCDINFO = ^CDINFO;
|
||||
CDINFO = record
|
||||
vendor: array[0..8] of Char;
|
||||
prodId: array[0..16] of Char;
|
||||
rev: array[0..4] of Char;
|
||||
vendSpec: array[0..20] of Char;
|
||||
end;
|
||||
|
||||
PCDREC = ^CDREC;
|
||||
CDREC = record
|
||||
ha: Byte;
|
||||
tgt: Byte;
|
||||
lun: Byte;
|
||||
pad: Byte;
|
||||
id: array[0..MAXIDLEN] of Char;
|
||||
info: CDINFO;
|
||||
end;
|
||||
|
||||
PCDLIST = ^CDLIST;
|
||||
CDLIST = record
|
||||
max: Byte;
|
||||
num: Byte;
|
||||
cd: array[0..MAXCDLIST - 1] of CDREC;
|
||||
end;
|
||||
|
||||
{*
|
||||
* TOCTRACK and TOC must be byte-aligned. If you're not using Mingw32,
|
||||
* CygWin, or some other compiler that understands the PACKED keyword,
|
||||
* you need to ensure that these structures are byte aligned. Usually,
|
||||
* this is done using a
|
||||
* #pragma pack(1)
|
||||
* See your compiler's documentation for details
|
||||
*}
|
||||
|
||||
TOCTRACK = packed record
|
||||
rsvd: Byte;
|
||||
ADR: Byte;
|
||||
trackNumber: Byte;
|
||||
rsvd2: Byte;
|
||||
addr: array[0..3] of Byte;
|
||||
end;
|
||||
|
||||
PTOC = ^TOC;
|
||||
TOC = packed record
|
||||
tocLen: Word;
|
||||
firstTrack: Byte;
|
||||
lastTrack: Byte;
|
||||
tracks: array[0..99] of TOCTRACK;
|
||||
end;
|
||||
|
||||
PTRACK = ^TRACK;
|
||||
TRACK = packed record
|
||||
trackNo: Integer;
|
||||
startLBA: DWord;
|
||||
trackLen: DWord;
|
||||
_type: Byte;
|
||||
pad: array[0..3] of Byte;
|
||||
name: ShortString;//array[0..255] of Char;
|
||||
end;
|
||||
|
||||
PREADMSF = ^READMSF;
|
||||
READMSF = record
|
||||
sm: Byte;
|
||||
ss: Byte;
|
||||
sf: Byte;
|
||||
em: Byte;
|
||||
es: Byte;
|
||||
ef: Byte;
|
||||
end;
|
||||
|
||||
const
|
||||
{*
|
||||
* Error codes set by functions in ASPILIB.C
|
||||
*}
|
||||
|
||||
ALERR_NOERROR = 0;
|
||||
ALERR_NOWNASPI = 1;
|
||||
ALERR_NOGETASPI32SUPP = 2;
|
||||
ALERR_NOSENDASPICMD = 3;
|
||||
ALERR_ASPI = 4;
|
||||
ALERR_NOCDSELECTED = 5;
|
||||
ALERR_BUFTOOSMALL = 6;
|
||||
ALERR_INVHANDLE = 7;
|
||||
ALERR_NOMOREHAND = 8;
|
||||
ALERR_BUFPTR = 9;
|
||||
ALERR_NOTACD = 10;
|
||||
ALERR_LOCK = 11;
|
||||
ALERR_DUPHAND = 12;
|
||||
ALERR_INVPTR = 13;
|
||||
ALERR_INVPARM = 14;
|
||||
ALERR_JITTER = 15;
|
||||
|
||||
{*
|
||||
* constants used for queryCDParms()
|
||||
*}
|
||||
|
||||
CDP_READCDR = $0001; // can read CD-R
|
||||
CDP_READCDE = $0002; // can read CD-E
|
||||
CDP_METHOD2 = $0003; // can read CD-R wriiten via method 2
|
||||
CDP_WRITECDR = $0004; // can write CD-R
|
||||
CDP_WRITECDE = $0005; // can write CD-E
|
||||
CDP_AUDIOPLAY = $0006; // can play audio
|
||||
CDP_COMPOSITE = $0007; // composite audio/video stream
|
||||
CDP_DIGITAL1 = $0008; // digital output (IEC958) on port 1
|
||||
CDP_DIGITAL2 = $0009; // digital output (IEC958) on port 2
|
||||
CDP_M2FORM1 = $000A; // reads Mode 2 Form 1 (XA) format
|
||||
CDP_M2FORM2 = $000B; // reads Mode 2 Form 2 format
|
||||
CDP_MULTISES = $000C; // reads multi-session or Photo-CD
|
||||
CDP_CDDA = $000D; // supports cd-da
|
||||
CDP_STREAMACC = $000E; // supports "stream is accurate"
|
||||
CDP_RW = $000F; // can return R-W info
|
||||
CDP_RWCORR = $0010; // returns R-W de-interleaved and err.
|
||||
// corrected
|
||||
CDP_C2SUPP = $0011; // C2 error pointers
|
||||
CDP_ISRC = $0012; // can return the ISRC info
|
||||
CDP_UPC = $0013; // can return the Media Catalog Number
|
||||
CDP_CANLOCK = $0014; // prevent/allow cmd. can lock the media
|
||||
CDP_LOCKED = $0015; // current lock state (TRUE = LOCKED)
|
||||
CDP_PREVJUMP = $0016; // prevent/allow jumper state
|
||||
CDP_CANEJECT = $0017; // drive can eject disk
|
||||
CDP_MECHTYPE = $0018; // type of disk loading supported
|
||||
CDP_SEPVOL = $0019; // independent audio level for channels
|
||||
CDP_SEPMUTE = $001A; // independent mute for channels
|
||||
CDP_SDP = $001B; // supports disk present (SDP)
|
||||
CDP_SSS = $001C; // Software Slot Selection
|
||||
CDP_MAXSPEED = $001D; // maximum supported speed of drive
|
||||
CDP_NUMVOL = $001E; // number of volume levels
|
||||
CDP_BUFSIZE = $001F; // size of output buffer
|
||||
CDP_CURRSPEED = $0020; // current speed of drive
|
||||
CDP_SPM = $0021; // "S" units per "M" (MSF format)
|
||||
CDP_FPS = $0022; // "F" units per "S" (MSF format)
|
||||
CDP_INACTMULT = $0023; // inactivity multiplier ( x 125 ms)
|
||||
CDP_MSF = $0024; // use MSF format for READ TOC cmd
|
||||
CDP_OVERLAP = $0025; // number of overlap frames for jitter
|
||||
CDP_JITTER = $0026; // number of frames to check for jitter
|
||||
CDP_READMODE = $0027; // mode to attempt jitter corr.
|
||||
|
||||
{*
|
||||
* defines for GETCDHAND readType
|
||||
*
|
||||
*}
|
||||
CDR_ANY = $00; // unknown
|
||||
CDR_ATAPI1 = $01; // ATAPI per spec
|
||||
CDR_ATAPI2 = $02; // alternate ATAPI
|
||||
CDR_READ6 = $03; // using SCSI READ(6)
|
||||
CDR_READ10 = $04; // using SCSI READ(10)
|
||||
CDR_READ_D8 = $05; // using command 0xD8 (Plextor?)
|
||||
CDR_READ_D4 = $06; // using command 0xD4 (NEC?)
|
||||
CDR_READ_D4_1 = $07; // 0xD4 with a mode select
|
||||
CDR_READ10_2 = $08; // different mode select w/ READ(10)
|
||||
|
||||
{*
|
||||
* defines for the read mode (CDP_READMODE)
|
||||
*}
|
||||
CDRM_NOJITTER = $00; // never jitter correct
|
||||
CDRM_JITTER = $01; // always jitter correct
|
||||
CDRM_JITTERONERR = $02; // jitter correct only after a read error
|
||||
|
||||
type
|
||||
HCDROM = THandle;
|
||||
|
||||
PGETCDHAND = ^GETCDHAND;
|
||||
GETCDHAND = packed record
|
||||
size: Byte; {* set to sizeof(GETCDHAND) *}
|
||||
ver: Byte; {* set to AKRIPVER *}
|
||||
ha: Byte; {* host adapter *}
|
||||
tgt: Byte; {* target id *}
|
||||
lun: Byte; {* LUN *}
|
||||
readType: Byte; {* read function to use *}
|
||||
jitterCorr: Bool; {* use built-in jitter correction? *}
|
||||
numJitter: Byte; {* number of frames to try to match *}
|
||||
numOverlap: Byte; {* number of frames to overlap *}
|
||||
end;
|
||||
|
||||
const
|
||||
akriplib = 'akrip32.dll';
|
||||
|
||||
var
|
||||
LibHandle : Integer;
|
||||
CDRipLoaded : Boolean;
|
||||
|
||||
type
|
||||
GetNumAdapters_t = function : Integer; cdecl;
|
||||
GetCDList_t = function (var cd: CDLIST): Integer; cdecl;
|
||||
GetAspiLibError_t = function : Integer; cdecl;
|
||||
GetAspiLibAspiError_t = function : Byte; cdecl;
|
||||
|
||||
GetCDId_t = function (hCD: HCDROM; buf: PChar; maxBuf: Integer): DWord; cdecl;
|
||||
GetDriveInfo_t = function (ha, tgt, lun: byte; var cdrec: CDREC): DWord; cdecl;
|
||||
ReadTOC_t = function (hCD: HCDROM; var MyToc: TOC): DWord; cdecl;
|
||||
ReadCDAudioLBA_t = function (hCD: HCDROM; TrackBuf: PTRACKBUF): DWord; cdecl;
|
||||
QueryCDParms_t = function (hCD: HCDROM; which: Integer; var Num: DWord): Bool; cdecl;
|
||||
ModifyCDParms_t = function (hCD: HCDROM; which: Integer; val: DWord): Bool; cdecl;
|
||||
GetCDHandle_t = function (var cd: GETCDHAND): HCDROM; cdecl;
|
||||
CloseCDHandle_t = function (hCD: HCDROM): Bool; cdecl;
|
||||
ReadCDAudioLBAEx_t = function (hCD: HCDROM; TrackBuf, Overlap: PTRACKBUF): DWord; cdecl;
|
||||
|
||||
var
|
||||
GetNumAdapters : GetNumAdapters_t;
|
||||
GetCDList : GetCDList_t;
|
||||
GetAspiLibError : GetAspiLibError_t;
|
||||
GetAspiLibAspiError : GetAspiLibAspiError_t;
|
||||
|
||||
GetCDId : GetCDId_t;
|
||||
GetDriveInfo : GetDriveInfo_t;
|
||||
ReadTOC : ReadTOC_t;
|
||||
ReadCDAudioLBA : ReadCDAudioLBA_t;
|
||||
QueryCDParms : QueryCDParms_t;
|
||||
ModifyCDParms : ModifyCDParms_t;
|
||||
GetCDHandle : GetCDHandle_t;
|
||||
CloseCDHandle : CloseCDHandle_t;
|
||||
ReadCDAudioLBAEx : ReadCDAudioLBAEx_t;
|
||||
|
||||
procedure CDRIPInit(FilePath:String);
|
||||
|
||||
implementation
|
||||
|
||||
procedure CDRIPInit(FilePath:String);
|
||||
begin
|
||||
Libhandle := LoadLibraryEx(akriplib, 0, 0);
|
||||
if Libhandle <> 0 then
|
||||
begin
|
||||
CDRipLoaded := True;
|
||||
GetNumAdapters := GetProcAddress(Libhandle, 'GetNumAdapters');
|
||||
GetCDList := GetProcAddress(Libhandle, 'GetCDList');
|
||||
GetAspiLibError := GetProcAddress(Libhandle, 'GetAspiLibError');
|
||||
GetAspiLibAspiError := GetProcAddress(Libhandle, 'GetAspiLibAspiError');
|
||||
GetCDId := GetProcAddress(Libhandle, 'GetCDId');
|
||||
GetDriveInfo := GetProcAddress(Libhandle, 'GetCDDriveInfo');
|
||||
ReadTOC := GetProcAddress(Libhandle, 'ReadTOC');
|
||||
ReadCDAudioLBA := GetProcAddress(Libhandle, 'ReadCDAudioLBA');
|
||||
QueryCDParms := GetProcAddress(Libhandle, 'QueryCDParams');
|
||||
ModifyCDParms := GetProcAddress(Libhandle, 'ModifyCDParms');
|
||||
GetCDHandle := GetProcAddress(Libhandle, 'GetCDHandle');
|
||||
CloseCDHandle := GetProcAddress(Libhandle, 'CloseCDHandle');
|
||||
ReadCDAudioLBAEx := GetProcAddress(Libhandle, 'ReadCDAudioLBAEx');
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
finalization
|
||||
if Libhandle <> 0 then
|
||||
begin
|
||||
FreeLibrary(Libhandle);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Reference in New Issue
Block a user