911 lines
24 KiB
ObjectPascal
911 lines
24 KiB
ObjectPascal
(*
|
|
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.
|