Стартовый пул

This commit is contained in:
2024-04-02 08:46:59 +03:00
parent fd57fffd3a
commit 3bb34d000b
5591 changed files with 3291734 additions and 0 deletions

View 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.

View 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.

View 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.

File diff suppressed because it is too large Load Diff

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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;

View 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;

View 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.

View 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;

View 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;

View 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.