如何自动控制音量,让每首歌在听的时候音量都一样 ( 积分: 200 )

  • 主题发起人 主题发起人 dali2000
  • 开始时间 开始时间
大家可以看下这个软件:MP3Gain,在百度中找一下就找到了,挺不错的一个软件,我用它把部分歌音量调成相同了
 
1.可以提前通过一些软件预处理
2.对每个歌曲记录一个音量值
3.实时抓取声音数据,在一段时间内取平均,根据此值调解音量.其实方法一中就是此种手段,只不过因为可以不用实时,因此可以在整首歌曲取平均,这样比较合理
 
谁做过类似的系统,没人能解决了?!
 
可以通过
Dspack 及 TBalancer in DSPack 声道均衡控件 、
DC-DSP Filter
 
//下面是我通过DC-DSP Filter里面的动态放大音量改的
//TBalancer for DSPACK(声道均衡控件,加入了动态放大音量)

//下面是源代码

unit Balancer;

interface

uses Classes, BaseClass, ActiveX, DirectShow9, MMSystem, Windows, DSUTil,
DSPack, BalConst, Math, SysUtils, Trace, Forms;

const
Name_Balancer = 'Audio Balancer by Style.Chen';
CLSID_Balancer: TGUID = '{BD8A846D-95A3-4916-AFEC-951C6A469363}';
IID_BalancerChannel: TGUID = '{01F2EFF9-722A-4D84-A93D-53CF6CD47384}';

type
TAudioChannel = (acStereo, acLeft, acRight);

type

TBalancerFilterGraph = class(TFilterGraph)
public
procedure InsertFilter(AFilter: IFilter);
procedure RemoveFilter(AFilter: IFilter);
end;


IBalancerChannel = interface(IunKnown)
['{BF88E3D0-573E-4D9B-9794-FC18B93E346B}']
function put_MediaType(mt: PAMMediaType): HRESULT;
stdcall;
function get_MediaType(out mt: TAMMediaType): HRESULT;
stdcall;
function get_IPin(out Pin: IPin): HRESULT;
stdcall;
function get_State(out State: TFilterState): HRESULT;
stdcall;
function SetAudioChannel(AudioChannel: TAudioChannel): HRESULT;
stdcall;
end;


const
MEDIATYPE_Audio: TGUID = (D1: $73647561;
D2: $0000;
D3: $0010;
D4: ($80, $00,
$00, $AA, $00, $38, $9B, $71));
MEDIASUBTYPE_PCM: TGUID = (D1: $00000001;
D2: $0000;
D3: $0010;
D4: ($80, $00,
$00, $AA, $00, $38, $9B, $71));

var
InstanceCount: integer = 0;

type
TBalancer = class;

TBalancerFilter = class(TBCTransInPlaceFilter, IBalancerChannel, IPersist)
//动态放大
fMaxAmplification : Cardinal;
fAmpWait : integer;
fReleaseTime : Cardinal;
fLastAmp : Single;
fAmpWaitPos : integer;
fAttackTime : Cardinal;
fSampleSize : Cardinal;
fSamplerate :integer;

FThisInstance: integer;
FPreferred: TAMMediaType;
FBalancerLock: TBCCritSec;
FCurrentChannel: TAudioChannel;
FParent: TBalancer;
private
function AudioChannelMix(PBuffer: Pointer;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer;
Channels: WORD;
Float: boolean): HRESULT;
public
property Samplerate : integer read fSamplerate write fSamplerate;

{ Sets the SampleSize so that the Buffer will be splitted to Process an amount
of Data only on every Process. Set SampleSize to 0 to disable it. Prevent
using small size Values. Use at least 1024 or more. }
property SampleSize : Cardinal read fSampleSize write fSampleSize;
{ Specifys the Amplification Value than will be used when Amplifying. }
property AttackTime : Cardinal read fAttackTime write fAttackTime;
{ Specifys the Time in MilliSeconds that the DSP will wait to continue
Amplification, after the Maximum has been reached. }
property ReleaseTime : Cardinal read fReleaseTime write fReleaseTime;
{ Sets the Amplification for a Channel. Default Value is 10000, which means
that no Amplification occours. A Value of 20000 raises the Amplification
by 2. }
property MaxAmplification : Cardinal read fMaxAmplification write fMaxAmplification;
{ Retrieves the Current Amplification Factor. }
property CurrentAmplification : Single read fLastAmp;


function StartStreaming: HRESULT;
override;
function CheckInputType(mtIn: PAMMediaType): HRESULT;
override;
function put_MediaType(mt: PAMMediaType): HRESULT;
stdcall;
function get_MediaType(out mt: TAMMediaType): HRESULT;
stdcall;
function get_IPin(out Pin: IPin): HRESULT;
stdcall;
function get_State(out State: TFilterState): HRESULT;
stdcall;

function GetPages(out pages: TCAGUID): HResult;
stdcall;

constructor Create(ObjName: string;
unk: IUnKnown;
out hr: HRESULT);
constructor CreateFromFactory(Factory: TBCClassFactory;
const Controller:
IUnknown);
override;
destructor Destroy;
override;

function Transform(Sample: IMediaSample): HRESULT;
override;
function SetAudioChannel(AudioChannel: TAudioChannel): HRESULT;
stdcall;
property Parent: TBalancer read FParent write FParent;
end;


TBalancer = class(TComponent, IFilter)
private

FFilter: TBalancerFilter;
FFilterGraph: TFilterGraph;
FBaseFilter: IBaseFilter;
FAudioChannel: TAudioChannel;
function GetFilter: IBaseFilter;
function GetName: string;
procedure NotifyFilter(operation: TFilterOperation;
Param: integer = 0);
procedure SetFilterGraph(AFilterGraph: TFilterGraph);
procedure SetAudioChannel(AAudioChannel: TAudioChannel);
function CreateFilter: HResult;

function GetCurrentAmplification: Single;

function GetAttackTime: Cardinal;
function GetReleaseTime: Cardinal;
function GetMaxAmplification: Cardinal;

procedure SetAttackTime(Value: Cardinal);
procedure SetReleaseTime(Value: Cardinal);
procedure SetMaxAmplification(Value: Cardinal);

protected
procedure Notification(AComponent: TComponent;
Operation: TOperation);
override;
public
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
function QueryInterface(const IID: TGUID;
out Obj): HResult;
override;
stdcall;
published
property FilterGraph: TFilterGraph read FFilterGraph write SetFilterGraph;
property AudioChannel: TAudioChannel read FAudioChannel write
SetAudioChannel;
{ Specifys the Amplification Value than will be used when Amplifying. }
property AttackTime : Cardinal read GetAttackTime write SetAttackTime;
{ Specifys the Time in MilliSeconds that the DSP will wait to continue
Amplification, after the Maximum has been reached. }
property ReleaseTime : Cardinal read GetReleaseTime write SetReleaseTime;
{ Sets the Amplification for a Channel. Default Value is 10000, which means
that no Amplification occours. A Value of 20000 raises the Amplification
by 2. }
property MaxAmplification : Cardinal read GetMaxAmplification write SetMaxAmplification;
public
//这里是即时放大的值
property CurrentAmplification : Single read GetCurrentAmplification;

end;


procedure Register;

implementation

procedure TBalancerFilterGraph.InsertFilter(AFilter: IFilter);
begin

inherited InsertFilter(AFilter);
end;


procedure TBalancerFilterGraph.RemoveFilter(AFilter: IFilter);
begin

inherited RemoveFilter(AFilter);
end;



{
这个是以前的东西

function TBalancerFilter.AudioChannelMix(PBuffer: PByte;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer): HRESULT;
var
i: Integer;
begin

Result := S_OK;
try
if AudioBits = 8 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 2) = 0 then

begin

PByte(Integer(PBuffer) + i + 1)^ :=
PByte(Integer(PBuffer) +
i)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 2) = 0 then

begin

PByte(Integer(PBuffer) + i)^ :=
PByte(Integer(PBuffer) + i +
1)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 16 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i + 2)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 3)^ :=
PByte(Integer(PBuffer) + i +
1)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i)^ := PByte(Integer(PBuffer) + i +
2)^;
PByte(Integer(PBuffer) + i + 1)^ := PByte(Integer(PBuffer) + i +
3)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 24 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 6) = 0 then

begin

PByte(Integer(PBuffer) + i + 3)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 4)^ :=
PByte(Integer(PBuffer) + i +
1)^;
PByte(Integer(PBuffer) + i + 5)^ :=
PByte(Integer(PBuffer) + i +
2)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 6) = 0 then

begin

PByte(Integer(PBuffer) + i)^ :=
PByte(Integer(PBuffer) +
i + 3)^;
PByte(Integer(PBuffer) + i + 1)^ :=
PByte(Integer(PBuffer) + i +
4)^;
PByte(Integer(PBuffer) + i + 2)^ :=
PByte(Integer(PBuffer) + i +
5)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 32 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 8) = 0 then

begin

PByte(Integer(PBuffer) + i + 4)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 5)^ :=
PByte(Integer(PBuffer) + i +
1)^;
PByte(Integer(PBuffer) + i + 6)^ :=
PByte(Integer(PBuffer) +
2)^;
PByte(Integer(PBuffer) + i + 7)^ :=
PByte(Integer(PBuffer) + i +
3)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i)^ := PByte(Integer(PBuffer) + i +
4)^;
PByte(Integer(PBuffer) + i + 1)^ := PByte(Integer(PBuffer) + i +
5)^;
PByte(Integer(PBuffer) + i + 2)^ := PByte(Integer(PBuffer) + i +
6)^;
PByte(Integer(PBuffer) + i + 3)^ := PByte(Integer(PBuffer) + i +
7)^;
end;

end;

end;

end;

Exit;
end;

Result := S_OK;
except
Result := S_FALSE;
end;

end;


}

//这个是加入了动态放大的声音
function TBalancerFilter.AudioChannelMix(PBuffer: Pointer;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer;
Channels: WORD;
Float: boolean): HRESULT;
var
Buf8 : PByteArray;
Buf16 : PSmallIntArray;
Buf24 : PInteger24Array;
Buf32 : PFloatArray;
Buf32i : PIntegerArray;
NumSamples : integer;
i,c : integer;
LoudestSample : integer;
LoudestSample64 : Int64;
AmpFactor,
AmpFactorS : Single;
tmp : integer;
sLastAmp : Single;
SmoothAmp : Single;
begin


LoudestSample := 0;
LoudestSample64 := 0;
NumSamples := Size div (AudioBits div 8);
AmpFactorS := fMaxAmplification / 1000;
AmpFactor := 1.0;
fAmpWait := Round((Samplerate * Channels * (AudioBits div 8) * Int64(fReleaseTime)) / 1000);

Buf32 := nil;
Buf16 := nil;
Buf24 := nil;
Buf32i := nil;
Buf8 := nil;

case AudioBits of
8:
begin

Buf8 := PByteArray(PBuffer);
for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf8^ - 128) > LoudestSample then
LoudestSample := abs(Buf8^ - 128);
AmpFactor := 128 / LoudestSample;
end;

16:
begin

Buf16 := PSmallIntArray(PBuffer);
for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf16^) > LoudestSample then
LoudestSample := abs(Buf16^);
AmpFactor := 32768 / LoudestSample;
end;

24:
begin

Buf24 := PInteger24Array(PBuffer);
for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Cvt24BitTo32(Buf24^)) > LoudestSample then
LoudestSample := abs(Cvt24BitTo32(Buf24^));
AmpFactor := 8388608 / LoudestSample;
end;

32:
begin

if Float then

begin

Buf32 := PFloatArray(PBuffer);
for i := 0 to (NumSamples) -1do

begin

// Check for the Loudest Sample in this Chunk
tmp := Round(abs(Buf32^) * 32767);
if tmp > LoudestSample then
LoudestSample := tmp;
end;

AmpFactor := 32768 / LoudestSample;
end else

begin

Buf32i := PIntegerArray(PBuffer);
for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf32i^) > LoudestSample64 then
LoudestSample64 := abs(Buf32i^);
AmpFactor := 2147483648 / LoudestSample64;
end;

end;

end;


sLastAmp := fLastAmp;
if AmpFactor > AmpFactorS then
AmpFactor := AmpFactorS;

if AmpFactor < fLastAmp then

begin

fAmpWaitPos := 0;
fLastAmp := AmpFactor;
end else

begin

if fAmpWaitPos <= fAmpWait then

begin

inc(fAmpWaitPos,Size);
AmpFactor := fLastAmp;
end else

begin

fLastAmp := fLastAmp + ((Size * (fAttackTime / 1000) / Samplerate / Channels / (AudioBits div 8)));
AmpFactor := fLastAmp;
if AmpFactor > AmpFactorS then

begin

AmpFactor := AmpFactorS;
fLastAmp := AmpFactor;
end;

end;

end;


NumSamples := NumSamples div Channels;
case AudioBits of
8:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + (1-c)] := Clip_8(Trunc((Buf8^[i * Channels + c] - 128) * (sLastAmp - (SmoothAmp * i)))) + 128;
end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + c] := Clip_8(Trunc((Buf8^[i * Channels + (1 - c)] - 128) * (sLastAmp - (SmoothAmp * i)))) + 128;
end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + c] := Clip_8(Trunc((Buf8^[i * Channels + c] - 128) * (sLastAmp - (SmoothAmp * i)))) + 128;
end;

end;

end;

16:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + (1-c)] := Clip_16(Trunc(Buf16^[i * Channels + c] * (sLastAmp - (SmoothAmp * i))));
end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + c] := Clip_16(Trunc(Buf16^[i * Channels + (1-c)] * (sLastAmp - (SmoothAmp * i))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + c] := Clip_16(Trunc(Buf16^[i * Channels + c] * (sLastAmp - (SmoothAmp * i))));
end;

end;

end;

24:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + (1-c)] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32(Buf24^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i)))));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + c] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32(Buf24^[i * Channels + (1-c)]) * (sLastAmp - (SmoothAmp * i)))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + c] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32(Buf24^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i)))));
end;

end;

end;

32:
begin

if Float then

begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + (1-c)] := Buf32^[i * Channels + c] * (sLastAmp - (SmoothAmp * i));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + c] := Buf32^[i * Channels + (1-c)] * (sLastAmp - (SmoothAmp * i));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + c] := Buf32^[i * Channels + c] * (sLastAmp - (SmoothAmp * i));
end;

end;

end else

begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + (1-c)] := Clip_32(Trunc(Int64(Buf32i^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i))));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + c] := Clip_32(Trunc(Int64(Buf32i^[i * Channels + (1-c)]) * (sLastAmp - (SmoothAmp * i))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + c] := Clip_32(Trunc(Int64(Buf32i^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i))));
end;

end;

end;

end;

end;

end;



function TBalancerFilter.StartStreaming: HRESULT;
var
MpegAudioDecoder: IMpegAudioDecoder;
IntDecode: LongWord;
ppEnum: IEnumFilters;
ppFilter: IBaseFilter;
begin

if FParent.FFilterGraph <> nil then

begin

(FParent.FFilterGraph as IFilterGraph).EnumFilters(ppEnum);
while ppEnum.Next(1, ppFilter, nil) = S_OKdo

begin

ppFilter.QueryInterface(IMpegAudioDecoder, MpegAudioDecoder);
if MpegAudioDecoder <> nil then

begin

MpegAudioDecoder.get_DualMode(IntDecode);
MpegAudioDecoder.put_DualMode(0);
end;

end;

end;


MpegAudioDecoder := nil;
ppEnum := nil;
ppFilter := nil;
Result := S_OK;
end;


function TBalancerFilter.CheckInputType(mtIn: PAMMediaType):
HRESULT;
begin

if not IsEqualGUID(mtIn^.majortype, MEDIATYPE_Audio) then

begin

Result := VFW_E_INVALIDMEDIATYPE;
Exit;
end;


if (not IsEqualGUID(mtIn^.subtype, MEDIASUBTYPE_PCM)) and
(not IsEqualGUID(mtIn^.subtype, MEDIASUBTYPE_IEEE_FLOAT)) then

begin

Result := VFW_E_INVALIDSUBTYPE;
Exit;
end;


if not IsEqualGUID(mtIn^.formattype, FORMAT_WaveFormatEx) then

begin

Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;


Result := S_OK;
end;


constructor TBalancerFilter.Create(ObjName: string;
unk:
IInterface;
out hr: HRESULT);
var
pmt: PAMMediaType;
begin

inherited Create(ObjName, unk, CLSID_Balancer, hr);
FThisInstance := InterlockedIncrement(InstanceCount);
pmt := @FPreferred;
TBCMediaType(pmt).InitMediaType;
FBalancerLock := TBCCritSec.Create;
FCurrentChannel := acStereo;

fLastAmp := 1.0;
fAttackTime := 1000;
fReleaseTime := 3000;
fMaxAmplification := 10000;

fSamplerate := 44100;

fSampleSize := DefaultSampleSize;

end;


constructor TBalancerFilter.CreateFromFactory(Factory:
TBCClassFactory;
const Controller: IInterface);
var
hr: HRESULT;
begin

Create(Factory.Name, Controller, hr);
end;


destructor TBalancerFilter.Destroy;
begin

FBalancerLock.Free;
inherited;
end;


function TBalancerFilter.get_IPin(out Pin: IPin): HRESULT;
begin

Result := S_OK;
FBalancerLock.Lock;
try
if (Input = nil) then

begin

Pin := nil;
Exit;
end;

if not Input.IsConnected then

Pin := nil
else

Pin := Input.GetConnected;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.get_MediaType(out mt: TAMMediaType):
HRESULT;
begin

FBalancerLock.Lock;
try
mt := FPreferred;
Result := NOERROR;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.get_State(out State: TFilterState):
HRESULT;
begin

FBalancerLock.Lock;
try
State := self.State;
Result := NOERROR;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.GetPages(out pages: TCAGUID): HResult;
begin

Pages.cElems := 1;
Result := NOERROR;
end;


function TBalancerFilter.put_MediaType(mt: PAMMediaType):
HRESULT;
var
Pin: IPin;
pmt: PAMMediaType;
begin

FBalancerLock.Lock;
try
if (State = State_Running) then

begin

Result := E_UNEXPECTED;
Exit;
end;


pmt := @FPreferred;
if (mt = nil) then

TBCMediaType(pmt).InitMediaType
else

begin

Pin := Input.GetConnected;
if (Pin <> nil) then

begin

if (Pin.QueryAccept(mt^) <> NOERROR) then

begin

MessageBox(0,
PChar('Upstream filter cannot provide this type'),
PChar('Format Selection'),
MB_OK or MB_ICONEXCLAMATION);
Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;

end;


Pin := Output.GetConnected;
if (Pin <> nil) then

begin

if (Pin.QueryAccept(mt^) <> NOERROR) then

begin

MessageBox(0,
PChar('Downstream filter cannot accept this type'),
PChar('Format Selection'),
MB_OK or MB_ICONEXCLAMATION);
Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;

end;

FPreferred := mt^;
end;


if (Input.IsConnected) then

begin

pmt := Input.CurrentMediaType.MediaType;
if not TBCMediaType(pmt).Equal(@FPreferred) then

Graph.Reconnect(Input);
end;

Result := NOERROR;
finally
FBalancerLock.Unlock;
end;

end;


function TBalancerFilter.Transform(Sample: IMediaSample):
HRESULT;
var
PWaveFormat: PWaveFormatEx;
AudioChannel: TAudioChannel;
Size: Integer;
PBuffer: PByte;

SplitBuffer : PChar;
SizeLeft : integer;
SplitSize : integer;
CurrentSize : integer;

Msg: TMsg;

begin

try
PWaveFormat := FInput.CurrentMediaType.MediaType.pbFormat;

// 输出通道数
// TraceString(IntToStr(pWaveFormat.nChannels));

AudioChannel := FCurrentChannel;

Sample.GetPointer(PBuffer);
Size := Sample.GetActualDataLength;

// AudioChannelMix2(Pbuffer, Size, AudioChannel, PWaveFormat.wBitsPerSample, pWaveFormat.nChannels, true);
if fSampleSize = 0 then

AudioChannelMix(Pbuffer, Size, AudioChannel, PWaveFormat.wBitsPerSample, pWaveFormat.nChannels, true)
else

begin

SplitBuffer := Pointer(PBuffer);
SplitSize := fSampleSize * (PWaveFormat.wBitsPerSample div 8) * pWaveFormat.nChannels;
SizeLeft := Size;
while SizeLeft > 0do

begin

if SizeLeft > SplitSize then
CurrentSize := SplitSize
else
CurrentSize := SizeLeft;

AudioChannelMix(@SplitBuffer[Size - SizeLeft], CurrentSize, AudioChannel, PWaveFormat.wBitsPerSample, pWaveFormat.nChannels, true);
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then

begin

TranslateMessage(Msg);
DispatchMessage(Msg);

end;

dec(SizeLeft,SplitSize);
end;

end;


finally
Result := S_OK;
end;

end;


{

var
SplitBuffer : PChar;
SizeLeft : integer;
SplitSize : integer;
CurrentSize : integer;


if not fEnabled then
Exit;
if fSampleSize = 0 then

begin

do
DSP(Buffer,Size,Samplerate,Bits,Channels,Float);
end else

begin

SplitBuffer := Buffer;
SplitSize := fSampleSize * (Bits div 8) * Channels;
SizeLeft := Size;
while SizeLeft > 0do

begin

if SizeLeft > SplitSize then
CurrentSize := SplitSize
else
CurrentSize := SizeLeft;
do
DSP(@SplitBuffer[Size - SizeLeft],CurrentSize,Samplerate,Bits,Channels,Float);
if fProcessMessages then
Application.ProcessMessages;
dec(SizeLeft,SplitSize);
end;

end;

}


function TBalancerFilter.SetAudioChannel(AudioChannel:
TAudioChannel): HRESULT;
stdcall;
begin

try
FCurrentChannel := AudioChannel;
finally
Result := S_OK;
end;

end;


function TBalancer.GetFilter: IBaseFilter;
begin

Result := FBaseFilter;
end;


function TBalancer.GetName: string;
begin

Result := Name_Balancer;
end;


procedure TBalancer.NotifyFilter(operation: TFilterOperation;
Param: integer =
0);
begin

case operation of
foAdding:
begin

CreateFilter;
end;

foRemoving: if FFilter <> nil then

FFilter.Stop;
foRemoved:
begin

FFilter := nil;
FBaseFilter := nil;
end;

foRefresh: if Assigned(FFilterGraph) then

begin

TBalancerFilterGraph(FFilterGraph).RemoveFilter(self);
TBalancerFilterGraph(FFilterGraph).InsertFilter(self);
end;

end;

end;


procedure TBalancer.SetFilterGraph(AFilterGraph: TFilterGraph);
begin

if AFilterGraph = FFilterGraph then

exit;
if FFilterGraph <> nil then

TBalancerFilterGraph(FFilterGraph).RemoveFilter(self);
if AFilterGraph <> nil then

TBalancerFilterGraph(AFilterGraph).InsertFilter(self);
FFilterGraph := AFilterGraph;
end;


procedure TBalancer.Notification(AComponent: TComponent;
Operation:
TOperation);
begin

inherited Notification(AComponent, Operation);
if ((AComponent = FFilterGraph) and (Operation = opRemove)) then

FFilterGraph := nil;
end;


constructor TBalancer.Create(AOwner: TComponent);
begin

inherited Create(AOwner);
FAudioChannel := acStereo;
CreateFilter;
end;


destructor TBalancer.Destroy;
begin

FilterGraph := nil;
inherited Destroy;
end;


function TBalancer.QueryInterface(const IID: TGUID;
out Obj):
HResult;
begin

Result := inherited QueryInterface(IID, Obj);
if not Succeeded(Result) then

if Assigned(FFilter) then

begin

Result := FFilter.QueryInterface(IID, Obj);
end;

end;


procedure TBalancer.SetAudioChannel(AAudioChannel: TAudioChannel);
begin

FAudioChannel := AAudioChannel;
FFilter.SetAudioChannel(FAudioChannel);
end;


function TBalancer.CreateFilter: HResult;
var
hr: HRESULT;
begin

if FFilter = nil then

begin

FFilter := TBalancerFilter.Create(Name, nil, hr);
FFilter.Parent := Self;
FBaseFilter := FFilter as IBaseFilter;
end;

Result := hr;
end;


function TBalancer.GetCurrentAmplification: Single;
begin

Result := FFilter.CurrentAmplification;
end;


function TBalancer.GetAttackTime: Cardinal;
begin

Result := FFilter.AttackTime;
end;

function TBalancer.GetReleaseTime: Cardinal;
begin

Result := FFilter.ReleaseTime;
end;

function TBalancer.GetMaxAmplification: Cardinal;
begin

Result := FFilter.MaxAmplification;
end;


procedure TBalancer.SetAttackTime(Value: Cardinal);
begin

FFilter.AttackTime := Value;
end;


procedure TBalancer.SetReleaseTime(Value: Cardinal);
begin

FFilter.ReleaseTime := Value;
end;


procedure TBalancer.SetMaxAmplification(Value: Cardinal);
begin

FFilter.MaxAmplification := Value;
end;


procedure Register;
begin

RegisterComponents('DSPack', [TBalancer]);
end;


end.
 
//还有一个支持库


unit BalConst;

interface

const
{ Defines the Maximum Number of Channels that will be used for DSP Processing.<br>
default = 10 }
MaxChannels = 10;
{ The maximum number of Samples that the Visual Output Buffer contains. }
MaxVisualSamples = 8192;
DefaultSampleSize = 8192;


type
{ Indicates a 24Bit Sample. Use Cvt24BitTo32 and Cvt32BitTo24 to convert those Samples to 32Bit and back to 24Bit }
T24BitSample = record
a0 : Byte;
a1 : Byte;
a2 : ShortInt;
end;

{ Pointer to a 24Bit Sample. }
P24BitSample = ^T24BitSample;

{ Used internal by the FFT to setup Reverse Bins Variables. Pointer to 16 Bit WORD Array. }
PWORDArray = ^TWORDArray;
{ Used internal by the FFT to setup Reverse Bins Variables. 16 Bit WORD Array. }
TWORDArray = array [0..255] of WORD;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to unsigned 8 Bit Integer. }
PByteArray = ^TByteArray;
{ Used internal by the DSP Components to access the Audio Buffer. unsigned 8 Bit Integer. }
TByteArray = array [0..255] of Byte;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to 16 Bit Integer. }
PSmallIntArray = ^TSmallIntArray;
{ Used internal by the DSP Components to access the Audio Buffer. 16 Bit Integer. }
TSmallIntArray = array [0..255] of SmallInt;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to 24 Bit Integer. }
PInteger24Array = ^TInteger24Array;
{ Used internal by the DSP Components to access the Audio Buffer. 24 Bit Integer. }
TInteger24Array = array[0..255] of T24BitSample;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to 32 Bit Integer. }
PIntegerArray = ^TIntegerArray;
{ Used internal by the DSP Components to access the Audio Buffer. 32 Bit Integer. }
TIntegerArray = array[0..255] of integer;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to 32 Bit Float. }
PFloatArray = ^TFloatArray;
{ Used internal by the DSP Components to access the Audio Buffer. 32Bit Float. }
TFloatArray = array [0..255] of Single;
{ Used internal by the DSP Components to access the Audio Buffer. Pointer to 64 Bit Float. }
PDoubleArray = ^TDoubleArray;
{ Used internal by the DSP Components to access the Audio Buffer. 64Bit Float. }
TDoubleArray = array [0..255] ofdo
uble;

{ Used internal by the TDCWaveform and TDCSpectrum Class. Pointer to TVisualBuffer. }
PVisualBuffer = ^TVisualBuffer;
{ Used internal by the TDCWaveform and TDCSpectrum Class. MaxVisualSamples(8192) * (MaxChannels(10)-1) Array of integer. }
TVisualBuffer = array[0..MaxChannels -1] of array[0..MaxVisualSamples -1] of Integer;


{ Clips one integer Sample into one ShortInt. Same as using EnsureRange(), but much faster. }
function Clip_8(Value: integer): ShortInt;
{ Clips one integer Sample into one SmallInt. Same as using EnsureRange(), but much faster. }
function Clip_16(Value: Integer): SmallInt;
{ Clips one integer Sample into one 24Bit integer. Same as using EnsureRange(), but much faster. }
function Clip_24(Value: Integer): Integer;
{ Clips one 64Bit integer Sample into one 32Bit Integer. Same as using EnsureRange(), but much faster. }
function Clip_32(Value : Int64) : integer;
{ Clips one integer Sample into one WORD. Same as using EnsureRange(), but much faster. }
// function ClipWORD(Value: Integer): WORD;
{ Clips one Single Float Sample into a -1.0..1.0 Range. }
function Clip_32F(Value : Single) : Single;

{ Clips one integer Sample into one WORD. Same as using EnsureRange(), but much faster. }
function ClipWORD(Value: Integer): WORD;


{ The Result of FFTSum is the same as whendo
ing sqrt(sqr(real) + sqr(imag)). }
// function FFTSum(real, imag : Single) : Single;

{ This is needed to convert a 24 Bit Sample into a 32 Bit todo
DSP on it. }
function Cvt24BitTo32(Sample : T24BitSample) : integer;
{ This is used to convert a 32 Bit Sample back to 24 Bit. }
function Cvt32BitTo24(Sample : integer) : T24BitSample;



implementation

function Cvt24BitTo32(Sample : T24BitSample) : integer;
begin

Result := Sample.a0 + (Sample.a1 shl 8) + (Sample.a2 shl 16);
end;


function Cvt32BitTo24(Sample : integer) : T24BitSample;
begin

Result.a0 := Sample;
Result.a1 := Sample shr 8;
Result.a2 := Sample shr 16;
end;


function Clip_8(Value: integer): ShortInt;
asm
cmp eax, 127
jle @@Lower
mov al, 127
ret
@@Lower:
cmp eax, -128
jge @@Finished
mov al, -128
@@Finished:
end;


function Clip_16(Value: Integer): SmallInt;
asm
cmp eax, 32767
jle @@Lower
mov ax, 32767
ret
@@Lower:
cmp eax, -32768
jge @@Finished
mov ax, -32768
@@Finished:
end;


function Clip_24(Value : integer) : integer;
asm
cmp eax, 8388607
jle @@Lower
mov eax, 8388607
ret
@@Lower:
cmp eax, -8388608
jge @@Finished
mov eax, -8388608
@@Finished:
end;


function Clip_32(Value : Int64) : integer;
begin

if Value > 2147483647 then
Result := 2147483647
else
if Value < -2147483647 then
Result := -2147483647
else
Result := integer(Value);
end;


function Clip_32F(Value : Single) : Single;
begin

if Value > 1.0 then
Result := 1.0
else
if Value < -1.0 then
Result := -1.0
else
Result := Value;
end;


function ClipWORD(Value: Integer): WORD;
asm
cmp eax, 65535
jle @@Lower
mov eax, 65535
ret
@@Lower:
cmp eax, 0
jge @@Finished
mov eax, 0
@@Finished:
end;


{
procedure TDCAmplify.DoDSP(Buffer : Pointer;
Size : Integer;
Bits : Byte;
Channels : Byte;
Float : Boolean);
const
NormalLevel = 10000;
var
Buf8 : PByteArray;
Buf16 : PSmallIntArray;
Buf24 : PInteger24Array;
Buf32 : PFloatArray;
Buf32i : PIntegerArray;
NumSamples : integer;
i, c : integer;
Vol : Single;
nVol: Integer;
PackedSize : Integer;
begin

NumSamples := Size div (Bits div 8) div Channels;
case Bits of
8:
begin

Buf8 := PByteArray(Buffer);
for c := 0 to Channels -1do

for i := 0 to NumSamples -1do
Buf8^[i * Channels + c] := clip_8(integer(Buf8^[i * Channels + c] - 128) * Volume[c] div 10000) + 128;
end;

16:
begin

Buf16 := PSmallIntArray(Buffer);
for c := 0 to Channels -1do

for i := 0 to NumSamples -1do
Buf16^[i * Channels + c] := clip_16(integer(Buf16^[i * Channels + c]) * Volume[c] div 10000);
end;

24:
begin

Buf24 := PInteger24Array(Buffer);
for c := 0 to Channels -1do

for i := 0 to NumSamples -1do
Buf24^[i * Channels + c] := cvt32BitTo24(clip_24(int64(cvt24BitTo32(Buf24^[i * Channels + c])) * Volume[c] div 10000));
end;

32:
begin

if Float then

begin

Buf32 := PFloatArray(Buffer);
for c := 0 to Channels -1do

begin

Vol := Volume[c] / 10000;
for i := 0 to NumSamples -1do
Buf32^[i * Channels + c] := Buf32^[i * Channels + c] * Vol;
end;

end else

begin

Buf32i := PIntegerArray(Buffer);
for c := 0 to Channels -1do

for i := 0 to NumSamples -1do
Buf32i^[i * Channels + c] := clip_32(Int64(Buf32i^[i * Channels + c]) * Volume[c] div 10000);
end;

end;

end;

end
}
end.
 
要先安装DSPACK哈
上面的源码,你替换Balancer里面的文件就可以了
也可以自已新建一个空包,加入上面两个文件就行了,
 
我觉得通过上面我的方法,点歌系统应该可以达到一个限制音量大小的水平
 
// 前面的动态放大声音的程序一点小问题,它是以双声道的值来判断音量大小,并动态放大。
// 对于有些左(右)声道的声音本身很小,就不能完全的动态放大。下面是我才修改的。


unit Balancer;

interface

uses Classes, BaseClass, ActiveX, DirectShow9, MMSystem, Windows, DSUTil,
DSPack, BalConst, Math, SysUtils, Trace, Forms;

const
Name_Balancer = 'Audio Balancer by Style.Chen';
CLSID_Balancer: TGUID = '{BD8A846D-95A3-4916-AFEC-951C6A469363}';
IID_BalancerChannel: TGUID = '{01F2EFF9-722A-4D84-A93D-53CF6CD47384}';

type
TAudioChannel = (acStereo, acLeft, acRight);

type

TBalancerFilterGraph = class(TFilterGraph)
public
procedure InsertFilter(AFilter: IFilter);
procedure RemoveFilter(AFilter: IFilter);
end;


IBalancerChannel = interface(IunKnown)
['{BF88E3D0-573E-4D9B-9794-FC18B93E346B}']
function put_MediaType(mt: PAMMediaType): HRESULT;
stdcall;
function get_MediaType(out mt: TAMMediaType): HRESULT;
stdcall;
function get_IPin(out Pin: IPin): HRESULT;
stdcall;
function get_State(out State: TFilterState): HRESULT;
stdcall;
function SetAudioChannel(AudioChannel: TAudioChannel): HRESULT;
stdcall;
end;


const
MEDIATYPE_Audio: TGUID = (D1: $73647561;
D2: $0000;
D3: $0010;
D4: ($80, $00,
$00, $AA, $00, $38, $9B, $71));
MEDIASUBTYPE_PCM: TGUID = (D1: $00000001;
D2: $0000;
D3: $0010;
D4: ($80, $00,
$00, $AA, $00, $38, $9B, $71));

var
InstanceCount: integer = 0;

type
TBalancer = class;

TBalancerFilter = class(TBCTransInPlaceFilter, IBalancerChannel, IPersist)
//动态放大
fMaxAmplification : Cardinal;
fAmpWait : integer;
fReleaseTime : Cardinal;
fLastAmp : Single;
fAmpWaitPos : integer;
fAttackTime : Cardinal;
fSampleSize : Cardinal;
fSamplerate :integer;

FThisInstance: integer;
FPreferred: TAMMediaType;
FBalancerLock: TBCCritSec;
FCurrentChannel: TAudioChannel;
FParent: TBalancer;
private
function AudioChannelMix(PBuffer: Pointer;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer;
Channels: WORD;
Float: boolean): HRESULT;
public
property Samplerate : integer read fSamplerate write fSamplerate;

{ Sets the SampleSize so that the Buffer will be splitted to Process an amount
of Data only on every Process. Set SampleSize to 0 to disable it. Prevent
using small size Values. Use at least 1024 or more. }
property SampleSize : Cardinal read fSampleSize write fSampleSize;
{ Specifys the Amplification Value than will be used when Amplifying. }
property AttackTime : Cardinal read fAttackTime write fAttackTime;
{ Specifys the Time in MilliSeconds that the DSP will wait to continue
Amplification, after the Maximum has been reached. }
property ReleaseTime : Cardinal read fReleaseTime write fReleaseTime;
{ Sets the Amplification for a Channel. Default Value is 10000, which means
that no Amplification occours. A Value of 20000 raises the Amplification
by 2. }
property MaxAmplification : Cardinal read fMaxAmplification write fMaxAmplification;
{ Retrieves the Current Amplification Factor. }
property CurrentAmplification : Single read fLastAmp;


function StartStreaming: HRESULT;
override;
function CheckInputType(mtIn: PAMMediaType): HRESULT;
override;
function put_MediaType(mt: PAMMediaType): HRESULT;
stdcall;
function get_MediaType(out mt: TAMMediaType): HRESULT;
stdcall;
function get_IPin(out Pin: IPin): HRESULT;
stdcall;
function get_State(out State: TFilterState): HRESULT;
stdcall;

function GetPages(out pages: TCAGUID): HResult;
stdcall;

constructor Create(ObjName: string;
unk: IUnKnown;
out hr: HRESULT);
constructor CreateFromFactory(Factory: TBCClassFactory;
const Controller:
IUnknown);
override;
destructor Destroy;
override;

function Transform(Sample: IMediaSample): HRESULT;
override;
function SetAudioChannel(AudioChannel: TAudioChannel): HRESULT;
stdcall;
property Parent: TBalancer read FParent write FParent;
end;


TBalancer = class(TComponent, IFilter)
private

FFilter: TBalancerFilter;
FFilterGraph: TFilterGraph;
FBaseFilter: IBaseFilter;
FAudioChannel: TAudioChannel;
function GetFilter: IBaseFilter;
function GetName: string;
procedure NotifyFilter(operation: TFilterOperation;
Param: integer = 0);
procedure SetFilterGraph(AFilterGraph: TFilterGraph);
procedure SetAudioChannel(AAudioChannel: TAudioChannel);
function CreateFilter: HResult;

function GetCurrentAmplification: Single;

function GetAttackTime: Cardinal;
function GetReleaseTime: Cardinal;
function GetMaxAmplification: Cardinal;

procedure SetAttackTime(Value: Cardinal);
procedure SetReleaseTime(Value: Cardinal);
procedure SetMaxAmplification(Value: Cardinal);

protected
procedure Notification(AComponent: TComponent;
Operation: TOperation);
override;
public
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
function QueryInterface(const IID: TGUID;
out Obj): HResult;
override;
stdcall;
published
property FilterGraph: TFilterGraph read FFilterGraph write SetFilterGraph;
property AudioChannel: TAudioChannel read FAudioChannel write
SetAudioChannel;
{ Specifys the Amplification Value than will be used when Amplifying. }
property AttackTime : Cardinal read GetAttackTime write SetAttackTime;
{ Specifys the Time in MilliSeconds that the DSP will wait to continue
Amplification, after the Maximum has been reached. }
property ReleaseTime : Cardinal read GetReleaseTime write SetReleaseTime;
{ Sets the Amplification for a Channel. Default Value is 10000, which means
that no Amplification occours. A Value of 20000 raises the Amplification
by 2. }
property MaxAmplification : Cardinal read GetMaxAmplification write SetMaxAmplification;

public

//这里是获得放大的倍数
property CurrentAmplification : Single read GetCurrentAmplification;

end;


procedure Register;

implementation

procedure TBalancerFilterGraph.InsertFilter(AFilter: IFilter);
begin

inherited InsertFilter(AFilter);
end;


procedure TBalancerFilterGraph.RemoveFilter(AFilter: IFilter);
begin

inherited RemoveFilter(AFilter);
end;



{
这个是以前的东西

function TBalancerFilter.AudioChannelMix(PBuffer: PByte;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer): HRESULT;
var
i: Integer;
begin

Result := S_OK;
try
if AudioBits = 8 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 2) = 0 then

begin

PByte(Integer(PBuffer) + i + 1)^ :=
PByte(Integer(PBuffer) +
i)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 2) = 0 then

begin

PByte(Integer(PBuffer) + i)^ :=
PByte(Integer(PBuffer) + i +
1)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 16 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i + 2)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 3)^ :=
PByte(Integer(PBuffer) + i +
1)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i)^ := PByte(Integer(PBuffer) + i +
2)^;
PByte(Integer(PBuffer) + i + 1)^ := PByte(Integer(PBuffer) + i +
3)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 24 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 6) = 0 then

begin

PByte(Integer(PBuffer) + i + 3)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 4)^ :=
PByte(Integer(PBuffer) + i +
1)^;
PByte(Integer(PBuffer) + i + 5)^ :=
PByte(Integer(PBuffer) + i +
2)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 6) = 0 then

begin

PByte(Integer(PBuffer) + i)^ :=
PByte(Integer(PBuffer) +
i + 3)^;
PByte(Integer(PBuffer) + i + 1)^ :=
PByte(Integer(PBuffer) + i +
4)^;
PByte(Integer(PBuffer) + i + 2)^ :=
PByte(Integer(PBuffer) + i +
5)^;
end;

end;

end;

end;

Exit;
end;

if AudioBits = 32 then

begin

case AudioChannel of
acRight:
begin

for i := 0 to Size - 1do

begin

if (i mod 8) = 0 then

begin

PByte(Integer(PBuffer) + i + 4)^ :=
PByte(Integer(PBuffer) +
i)^;
PByte(Integer(PBuffer) + i + 5)^ :=
PByte(Integer(PBuffer) + i +
1)^;
PByte(Integer(PBuffer) + i + 6)^ :=
PByte(Integer(PBuffer) +
2)^;
PByte(Integer(PBuffer) + i + 7)^ :=
PByte(Integer(PBuffer) + i +
3)^;
end;

end;

end;

acLeft:
begin

for i := 0 to Size - 1do

begin

if (i mod 4) = 0 then

begin

PByte(Integer(PBuffer) + i)^ := PByte(Integer(PBuffer) + i +
4)^;
PByte(Integer(PBuffer) + i + 1)^ := PByte(Integer(PBuffer) + i +
5)^;
PByte(Integer(PBuffer) + i + 2)^ := PByte(Integer(PBuffer) + i +
6)^;
PByte(Integer(PBuffer) + i + 3)^ := PByte(Integer(PBuffer) + i +
7)^;
end;

end;

end;

end;

Exit;
end;

Result := S_OK;
except
Result := S_FALSE;
end;

end;


}

//这个是加入了动态放大的声音
function TBalancerFilter.AudioChannelMix(PBuffer: Pointer;
Size: Integer;
AudioChannel:
TAudioChannel;
AudioBits: Integer;
Channels: WORD;
Float: boolean): HRESULT;
var
Buf8 : PByteArray;
Buf16 : PSmallIntArray;
Buf24 : PInteger24Array;
Buf32 : PFloatArray;
Buf32i : PIntegerArray;
NumSamples : integer;
i,c : integer;
LoudestSample : integer;
LoudestSample64 : Int64;
AmpFactor,
AmpFactorS : Single;
tmp : integer;
sLastAmp : Single;
SmoothAmp : Single;
begin


LoudestSample := 0;
LoudestSample64 := 0;
NumSamples := Size div (AudioBits div 8);

AmpFactorS := fMaxAmplification / 1000;
AmpFactor := 1.0;
fAmpWait := Round((Samplerate * Channels * (AudioBits div 8) * Int64(fReleaseTime)) / 1000);

Buf32 := nil;
Buf16 := nil;
Buf24 := nil;
Buf32i := nil;
Buf8 := nil;

// 这里是最近修改的,上一次发的,只判断了 acStereo 双声道,单声道没有判断,后面一段又是以双声道的值为基础动态放大的
// 所以有一点小问题哈。

case AudioBits of
8:
begin

Buf8 := PByteArray(PBuffer);
case AudioChannel of
acRight:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf8^[i + 1] - 128) > LoudestSample then
LoudestSample := abs(Buf8^[i + 1] - 128);
end;

acLeft:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf8^ - 128) > LoudestSample then
LoudestSample := abs(Buf8^ - 128);
end;

acStereo:
begin

for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf8^ - 128) > LoudestSample then
LoudestSample := abs(Buf8^ - 128);
end;

end;

AmpFactor := 128 / LoudestSample;
end;

16:
begin

Buf16 := PSmallIntArray(PBuffer);
case AudioChannel of
acRight:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf16^[i+1]) > LoudestSample then
LoudestSample := abs(Buf16^[i+1]);

end;

acLeft:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf16^) > LoudestSample then
LoudestSample := abs(Buf16^);

end;

acStereo:
begin

for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf16^) > LoudestSample then
LoudestSample := abs(Buf16^);

end;

end;

AmpFactor := 32768 / LoudestSample;
end;

24:
begin

Buf24 := PInteger24Array(PBuffer);
case AudioChannel of
acRight:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Cvt24BitTo32(Buf24^[i+1])) > LoudestSample then
LoudestSample := abs(Cvt24BitTo32(Buf24^[i+1]));



end;

acLeft:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Cvt24BitTo32(Buf24^)) > LoudestSample then
LoudestSample := abs(Cvt24BitTo32(Buf24^));



end;

acStereo:
begin

for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Cvt24BitTo32(Buf24^)) > LoudestSample then
LoudestSample := abs(Cvt24BitTo32(Buf24^));
end;

end;


AmpFactor := 8388608 / LoudestSample;
end;

32:
begin

if Float then

begin

Buf32 := PFloatArray(PBuffer);
case AudioChannel of
acRight:
begin

for i := 0 to (NumSamples div Channels) -1do

begin

// Check for the Loudest Sample in this Chunk
tmp := Round(abs(Buf32^[i + 1]) * 32767);
if tmp > LoudestSample then
LoudestSample := tmp;
end;


end;

acLeft:
begin

for i := 0 to (NumSamples div Channels) -1do

begin

// Check for the Loudest Sample in this Chunk
tmp := Round(abs(Buf32^) * 32767);
if tmp > LoudestSample then
LoudestSample := tmp;
end;

end;

acStereo:
begin

for i := 0 to (NumSamples) -1do

begin

// Check for the Loudest Sample in this Chunk
tmp := Round(abs(Buf32^) * 32767);
if tmp > LoudestSample then
LoudestSample := tmp;
end;

end;

end;



AmpFactor := 32768 / LoudestSample;
end else

begin

Buf32i := PIntegerArray(PBuffer);
case AudioChannel of
acRight:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf32i^[i+1]) > LoudestSample64 then
LoudestSample64 := abs(Buf32i^[i+1]);
end;

acLeft:
begin

for i := 0 to (NumSamples div Channels) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf32i^) > LoudestSample64 then
LoudestSample64 := abs(Buf32i^);
end;

acStereo:
begin

for i := 0 to (NumSamples) -1do

// Check for the Loudest Sample in this Chunk
if abs(Buf32i^) > LoudestSample64 then
LoudestSample64 := abs(Buf32i^);
end;

end;


AmpFactor := 2147483648 / LoudestSample64;
end;

end;

end;



//这后面的没有改

sLastAmp := fLastAmp;
if AmpFactor > AmpFactorS then
AmpFactor := AmpFactorS;

if AmpFactor < fLastAmp then

begin

fAmpWaitPos := 0;
fLastAmp := AmpFactor;
end else

begin

if fAmpWaitPos <= fAmpWait then

begin

inc(fAmpWaitPos,Size);
AmpFactor := fLastAmp;
end else

begin

fLastAmp := fLastAmp + ((Size * (fAttackTime / 1000) / Samplerate / Channels / (AudioBits div 8)));
AmpFactor := fLastAmp;
if AmpFactor > AmpFactorS then

begin

AmpFactor := AmpFactorS;
fLastAmp := AmpFactor;
end;

end;

end;


NumSamples := NumSamples div Channels;
case AudioBits of
8:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + (1-c)] := Clip_8(Trunc((Buf8^[i * Channels + c] -

128) * (sLastAmp - (SmoothAmp * i)))) + 128;
end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + c] := Clip_8(Trunc((Buf8^[i * Channels + (1 - c)] -

128) * (sLastAmp - (SmoothAmp * i)))) + 128;
end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf8^[i * Channels + c] := Clip_8(Trunc((Buf8^[i * Channels + c] - 128)

* (sLastAmp - (SmoothAmp * i)))) + 128;
end;

end;

end;

16:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + (1-c)] := Clip_16(Trunc(Buf16^[i * Channels + c] *

(sLastAmp - (SmoothAmp * i))));
end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + c] := Clip_16(Trunc(Buf16^[i * Channels + (1-c)] *

(sLastAmp - (SmoothAmp * i))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf16^[i * Channels + c] := Clip_16(Trunc(Buf16^[i * Channels + c] *

(sLastAmp - (SmoothAmp * i))));
end;

end;

end;

24:
begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + (1-c)] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32

(Buf24^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i)))));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + c] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32

(Buf24^[i * Channels + (1-c)]) * (sLastAmp - (SmoothAmp * i)))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf24^[i * Channels + c] := Cvt32BitTo24(Clip_24(Trunc(Cvt24BitTo32

(Buf24^[i * Channels + c]) * (sLastAmp - (SmoothAmp * i)))));
end;

end;

end;

32:
begin

if Float then

begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + (1-c)] := Buf32^[i * Channels + c] * (sLastAmp -

(SmoothAmp * i));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + c] := Buf32^[i * Channels + (1-c)] * (sLastAmp -

(SmoothAmp * i));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32^[i * Channels + c] := Buf32^[i * Channels + c] * (sLastAmp -

(SmoothAmp * i));
end;

end;

end else

begin

case AudioChannel of
acRight:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + (1-c)] := Clip_32(Trunc(Int64(Buf32i^[i *

Channels + c]) * (sLastAmp - (SmoothAmp * i))));

end;

acLeft:
begin

c := 0;
SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + c] := Clip_32(Trunc(Int64(Buf32i^[i * Channels +

(1-c)]) * (sLastAmp - (SmoothAmp * i))));

end;

acStereo:
for c := 0 to Channels -1do

begin

SmoothAmp := (sLastAmp - AmpFactor) / NumSamples;
for i := 0 to (NumSamples -1)do
Buf32i^[i * Channels + c] := Clip_32(Trunc(Int64(Buf32i^[i * Channels +

c]) * (sLastAmp - (SmoothAmp * i))));
end;

end;

end;

end;

end;

end;



function TBalancerFilter.StartStreaming: HRESULT;
var
MpegAudioDecoder: IMpegAudioDecoder;
IntDecode: LongWord;
ppEnum: IEnumFilters;
ppFilter: IBaseFilter;
begin

if FParent.FFilterGraph <> nil then

begin

(FParent.FFilterGraph as IFilterGraph).EnumFilters(ppEnum);
while ppEnum.Next(1, ppFilter, nil) = S_OKdo

begin

ppFilter.QueryInterface(IMpegAudioDecoder, MpegAudioDecoder);
if MpegAudioDecoder <> nil then

begin

MpegAudioDecoder.get_DualMode(IntDecode);
MpegAudioDecoder.put_DualMode(0);
end;

end;

end;


MpegAudioDecoder := nil;
ppEnum := nil;
ppFilter := nil;
Result := S_OK;
end;


function TBalancerFilter.CheckInputType(mtIn: PAMMediaType):
HRESULT;
begin

if not IsEqualGUID(mtIn^.majortype, MEDIATYPE_Audio) then

begin

Result := VFW_E_INVALIDMEDIATYPE;
Exit;
end;


if (not IsEqualGUID(mtIn^.subtype, MEDIASUBTYPE_PCM)) and
(not IsEqualGUID(mtIn^.subtype, MEDIASUBTYPE_IEEE_FLOAT)) then

begin

Result := VFW_E_INVALIDSUBTYPE;
Exit;
end;


if not IsEqualGUID(mtIn^.formattype, FORMAT_WaveFormatEx) then

begin

Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;


Result := S_OK;
end;


constructor TBalancerFilter.Create(ObjName: string;
unk:
IInterface;
out hr: HRESULT);
var
pmt: PAMMediaType;
begin

inherited Create(ObjName, unk, CLSID_Balancer, hr);
FThisInstance := InterlockedIncrement(InstanceCount);
pmt := @FPreferred;
TBCMediaType(pmt).InitMediaType;
FBalancerLock := TBCCritSec.Create;
FCurrentChannel := acStereo;

fLastAmp := 1.0;
fAttackTime := 1000;
fReleaseTime := 3000;
fMaxAmplification := 10000;

fSamplerate := 48000;

fSampleSize := DefaultSampleSize;

end;


constructor TBalancerFilter.CreateFromFactory(Factory:
TBCClassFactory;
const Controller: IInterface);
var
hr: HRESULT;
begin

Create(Factory.Name, Controller, hr);
end;


destructor TBalancerFilter.Destroy;
begin

FBalancerLock.Free;
inherited;
end;


function TBalancerFilter.get_IPin(out Pin: IPin): HRESULT;
begin

Result := S_OK;
FBalancerLock.Lock;
try
if (Input = nil) then

begin

Pin := nil;
Exit;
end;

if not Input.IsConnected then

Pin := nil
else

Pin := Input.GetConnected;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.get_MediaType(out mt: TAMMediaType):
HRESULT;
begin

FBalancerLock.Lock;
try
mt := FPreferred;
Result := NOERROR;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.get_State(out State: TFilterState):
HRESULT;
begin

FBalancerLock.Lock;
try
State := self.State;
Result := NOERROR;
finally
FBalancerLock.UnLock;
end;

end;


function TBalancerFilter.GetPages(out pages: TCAGUID): HResult;
begin

Pages.cElems := 1;
Result := NOERROR;
end;


function TBalancerFilter.put_MediaType(mt: PAMMediaType):
HRESULT;
var
Pin: IPin;
pmt: PAMMediaType;
begin

FBalancerLock.Lock;
try
if (State = State_Running) then

begin

Result := E_UNEXPECTED;
Exit;
end;


pmt := @FPreferred;
if (mt = nil) then

TBCMediaType(pmt).InitMediaType
else

begin

Pin := Input.GetConnected;
if (Pin <> nil) then

begin

if (Pin.QueryAccept(mt^) <> NOERROR) then

begin

MessageBox(0,
PChar('Upstream filter cannot provide this type'),
PChar('Format Selection'),
MB_OK or MB_ICONEXCLAMATION);
Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;

end;


Pin := Output.GetConnected;
if (Pin <> nil) then

begin

if (Pin.QueryAccept(mt^) <> NOERROR) then

begin

MessageBox(0,
PChar('Downstream filter cannot accept this type'),
PChar('Format Selection'),
MB_OK or MB_ICONEXCLAMATION);
Result := VFW_E_TYPE_NOT_ACCEPTED;
Exit;
end;

end;

FPreferred := mt^;
end;


if (Input.IsConnected) then

begin

pmt := Input.CurrentMediaType.MediaType;
if not TBCMediaType(pmt).Equal(@FPreferred) then

Graph.Reconnect(Input);
end;

Result := NOERROR;
finally
FBalancerLock.Unlock;
end;

end;


function TBalancerFilter.Transform(Sample: IMediaSample):
HRESULT;
var
PWaveFormat: PWaveFormatEx;
AudioChannel: TAudioChannel;
Size: Integer;
PBuffer: PByte;

SplitBuffer : PChar;
SizeLeft : integer;
SplitSize : integer;
CurrentSize : integer;

// Msg: TMsg;

begin

try
PWaveFormat := FInput.CurrentMediaType.MediaType.pbFormat;

// 输出声音比率
// TraceString('声音' + IntToStr(pWaveFormat.nSamplesPerSec));

// 这一句也是加的
fSamplerate := pWaveFormat.nSamplesPerSec;

AudioChannel := FCurrentChannel;

Sample.GetPointer(PBuffer);
Size := Sample.GetActualDataLength;

// AudioChannelMix2(Pbuffer, Size, AudioChannel, PWaveFormat.wBitsPerSample, pWaveFormat.nChannels, true);
if fSampleSize = 0 then

AudioChannelMix(Pbuffer, Size, AudioChannel, PWaveFormat.wBitsPerSample, pWaveFormat.nChannels, true)
else

begin

SplitBuffer := Pointer(PBuffer);
SplitSize := fSampleSize * (PWaveFormat.wBitsPerSample div 8) * pWaveFormat.nChannels;
SizeLeft := Size;
while SizeLeft > 0do

begin

if SizeLeft > SplitSize then
CurrentSize := SplitSize
else
CurrentSize := SizeLeft;

AudioChannelMix(@SplitBuffer[Size - SizeLeft], CurrentSize, AudioChannel, PWaveFormat.wBitsPerSample,

pWaveFormat.nChannels, true);

// if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then

// begin

// TranslateMessage(Msg);
// DispatchMessage(Msg);
// end;

dec(SizeLeft,SplitSize);
end;

end;


finally
Result := S_OK;
end;

end;


{

var
SplitBuffer : PChar;
SizeLeft : integer;
SplitSize : integer;
CurrentSize : integer;


if not fEnabled then
Exit;
if fSampleSize = 0 then

begin

do
DSP(Buffer,Size,Samplerate,Bits,Channels,Float);
end else

begin

SplitBuffer := Buffer;
SplitSize := fSampleSize * (Bits div 8) * Channels;
SizeLeft := Size;
while SizeLeft > 0do

begin

if SizeLeft > SplitSize then
CurrentSize := SplitSize
else
CurrentSize := SizeLeft;
do
DSP(@SplitBuffer[Size - SizeLeft],CurrentSize,Samplerate,Bits,Channels,Float);
if fProcessMessages then
Application.ProcessMessages;
dec(SizeLeft,SplitSize);
end;

end;

}


function TBalancerFilter.SetAudioChannel(AudioChannel:
TAudioChannel): HRESULT;
stdcall;
begin

try
FCurrentChannel := AudioChannel;
finally
Result := S_OK;
end;

end;


function TBalancer.GetFilter: IBaseFilter;
begin

Result := FBaseFilter;
end;


function TBalancer.GetName: string;
begin

Result := Name_Balancer;
end;


procedure TBalancer.NotifyFilter(operation: TFilterOperation;
Param: integer =
0);
begin

case operation of
foAdding:
begin

CreateFilter;
end;

foRemoving: if FFilter <> nil then

FFilter.Stop;
foRemoved:
begin

FFilter := nil;
FBaseFilter := nil;
end;

foRefresh: if Assigned(FFilterGraph) then

begin

TBalancerFilterGraph(FFilterGraph).RemoveFilter(self);
TBalancerFilterGraph(FFilterGraph).InsertFilter(self);
end;

end;

end;


procedure TBalancer.SetFilterGraph(AFilterGraph: TFilterGraph);
begin

if AFilterGraph = FFilterGraph then

exit;
if FFilterGraph <> nil then

TBalancerFilterGraph(FFilterGraph).RemoveFilter(self);
if AFilterGraph <> nil then

TBalancerFilterGraph(AFilterGraph).InsertFilter(self);
FFilterGraph := AFilterGraph;
end;


procedure TBalancer.Notification(AComponent: TComponent;
Operation:
TOperation);
begin

inherited Notification(AComponent, Operation);
if ((AComponent = FFilterGraph) and (Operation = opRemove)) then

FFilterGraph := nil;
end;


constructor TBalancer.Create(AOwner: TComponent);
begin

inherited Create(AOwner);
FAudioChannel := acStereo;
CreateFilter;
end;


destructor TBalancer.Destroy;
begin

FilterGraph := nil;
inherited Destroy;
end;


function TBalancer.QueryInterface(const IID: TGUID;
out Obj):
HResult;
begin

Result := inherited QueryInterface(IID, Obj);
if not Succeeded(Result) then

if Assigned(FFilter) then

begin

Result := FFilter.QueryInterface(IID, Obj);
end;

end;


procedure TBalancer.SetAudioChannel(AAudioChannel: TAudioChannel);
begin

FAudioChannel := AAudioChannel;
FFilter.SetAudioChannel(FAudioChannel);
end;


function TBalancer.CreateFilter: HResult;
var
hr: HRESULT;
begin

if FFilter = nil then

begin

FFilter := TBalancerFilter.Create(Name, nil, hr);
FFilter.Parent := Self;
FBaseFilter := FFilter as IBaseFilter;
end;

Result := hr;
end;


function TBalancer.GetCurrentAmplification: Single;
begin

Result := FFilter.CurrentAmplification;
end;


function TBalancer.GetAttackTime: Cardinal;
begin

Result := FFilter.AttackTime;
end;

function TBalancer.GetReleaseTime: Cardinal;
begin

Result := FFilter.ReleaseTime;
end;

function TBalancer.GetMaxAmplification: Cardinal;
begin

Result := FFilter.MaxAmplification;
end;


procedure TBalancer.SetAttackTime(Value: Cardinal);
begin

FFilter.AttackTime := Value;
end;


procedure TBalancer.SetReleaseTime(Value: Cardinal);
begin

FFilter.ReleaseTime := Value;
end;


procedure TBalancer.SetMaxAmplification(Value: Cardinal);
begin

FFilter.MaxAmplification := Value;
end;


procedure Register;
begin

RegisterComponents('DSPack', [TBalancer]);
end;


end.
 
我也没有好的思路。
 

Similar threads

D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部