如何取得音频文件的振幅?(100分)

  • 主题发起人 主题发起人 flyingwater007
  • 开始时间 开始时间
F

flyingwater007

Unregistered / Unconfirmed
GUEST, unregistred user!
我找你找了很久~~-_-b,可以表现振幅的控件倒是有几个,但都满足不了要求,我想取得模拟振幅变化的一个数列,谁有有这方面的资料发扬下共享精神,先行谢过。下面是一段江先生的代码,里面有个取振幅的函数getpeak,小生愚笨,死活调试不出振幅,在那个判断处总是跳出,伤了~大虾们给提点建议
http://delphi.sharpplus.com/Recommend/rcAudioMixer.htm


unit Unit2;


//Written by David Jiang(江天送)

//july 25th. 1999

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs,StdCtrls, ComCtrls, mmsystem, Buttons, ExtCtrls;


type Tvolume=record

left,right:word;


end;



type

TForm2 = class(TForm)

Lines: TComboBox;


Controls: TComboBox;


Label1: TLabel;


lmute: TLabel;


lmeter: TLabel;


LVolume: TTrackBar;


Rvolume: TTrackBar;


cmute: TCheckBox;


CheckBox1: TCheckBox;


About: TSpeedButton;


BExit: TSpeedButton;


RProgressBar: TProgressBar;


Timer1: TTimer;


procedure FormCreate(Sender: TObject);


procedure getlinecontrol;


procedure LinesChange(Sender: TObject);


procedure ControlsChange(Sender: TObject);


procedure LVolumeChange(Sender: TObject);


procedure cmuteClick(Sender: TObject);


procedure RvolumeChange(Sender: TObject);


procedure AboutClick(Sender: TObject);


procedure BExitClick(Sender: TObject);


procedure Timer1Timer(Sender: TObject);


procedure FormClose(Sender: TObject;
var

Action: TCloseAction);



private

{ Private declarations }

procedure mmixer(var msg:Tmessage);


public

{ Public declarations }

end;



function getvolume(control:Pmixercontrol;var

volume:Tvolume):boolean;


function setvolume(control:Pmixercontrol;


volume:Tvolume):boolean;


function setmute(control:Pmixercontrol;


mute:integer):boolean;


function getmute(control:Pmixercontrol;var

mute:integer):boolean;


function getpeak(control:Pmixercontrol;var

peak:integer):boolean;


procedure Fillstruct(control:Pmixercontrol;var

Cdetails:Tmixercontroldetails);


var

Form2: TForm2;


fmixerhandle:hmixer;
//混音器的句柄

mcontrols:array of array of array of PMixerControl;


line:array of Tstringlist;


peaknum:integer;
//meter mcontrols的位置

implementation


{$R *.DFM}


procedure Tform2.mmixer(var msg:Tmessage);


var

volume:Tvolume;


mute:integer;


begin


if msg.Msg=MM_MIXM_CONTROL_CHANGE then


begin


if mcontrolS[lines.itemindex][controls.itemindex]

[0].dwcontrolID=msg.LParam then


if getvolume(mcontrolS[lines.itemindex]

[controls.itemindex][0],volume) then


begin


Rvolume.Position :=-volume.right;


Lvolume.Position :=-volume.left;


end;



if mcontrolS[lines.itemindex][controls.itemindex]

[1].dwcontrolid=msg.LParam then


if getmute(mcontrolS[lines.itemindex]

[controls.itemindex][1],mute) then


cmute.Checked:=mute=1;


end;



end;



procedure TForm2.FormCreate(Sender: TObject);


begin


getlinecontrol;


lines.ItemIndex :=0;


controls.Items:=line[lines.ItemIndex];


controls.ItemIndex :=0;


controls.OnChange (sender);


end;




procedure Tform2.getlinecontrol;


var

mixerID:integer;
//混音器的ID

FMixerCaps:TMixerCaps;


n,j,k,i:integer;


ml,ml2:TMIXERLINE;


MLC:TMixerLineControls;


P:PMixerControl;


begin


if mixerGetNumDevs=0 then
exit;
//如没有混合器装置,退出

fmixerhandle:=0;


mixerID:=0;


mixerOpen (@FMixerHandle,mixerID,AllocateHWnd(mmixer),

0,CALLBACK_WINDOW OR MIXER_OBJECTF_MIXER);


//打开混音器

mixerGetDevCaps (mixerID,@FMixerCaps,SizeOf (TMixerCaps));


//返回混音器的兼容性

setlength(line,fmixercaps.cDestinations);


setlength(mcontrols,fmixercaps.cDestinations );


for i:=0 to fmixercaps.cDestinations-1do


begin


ml.dwDestination:=i;


ml.cbStruct :=sizeof(tMIXERLINE);


mixerGetLineInfo(fmixerhandle,@ml,

MIXER_GETLINEINFOF_DESTINATION);


//取得混音器的Destinations

line:=tstringlist.Create ;


setlength(mcontrols,ml.cconnections);


n:=0;


if ml.cControls>1 then


begin


n:=1;


setlength(mcontrols,ml.cconnections+1);


MLC.cbStruct:=SizeOf(MLC);


MLC.dwLineID:=ml.dwLineID;


MLC.cControls:=ml.cControls;


MLC.cbmxctrl:=SizeOf(TMixerControl);


GetMem (P,SizeOf(TMixerControl)*ml.cControls);


MLC.pamxctrl:=P;


MixerGetLineControls(fMixerHandle,@MLC,

MIXER_GETLINECONTROLSF_ALL);


setlength(mcontrols[0],ml.cControls);


line.Add(p^.szname);
//Master Volume

For k:=0 to ml.cControls-1do


begin


mcontrols[0][k]:=p;


mcontrols[0][0].Metrics.dwReserved[k+1]:=1;


inc(p);


end;



end;



lines.Items.Add(ml.szName);


ML2.cbStruct:=SizeOf(TMixerLine);


ML2.dwDestination:=ml.dwDestination ;


for j:=0 to ml.cConnections -1do


begin


ML2.dwSource:=j;


MixerGetLineInfo (fmixerHandle,@ML2,

MIXER_GETLINEINFOF_SOURCE);


MLC.cbStruct:=SizeOf(MLC);


MLC.dwLineID:=ml2.dwLineID;


MLC.cControls:=ml2.cControls;


MLC.cbmxctrl:=SizeOf(TMixerControl);


GetMem (P,SizeOf(TMixerControl)*ml2.cControls);


MLC.pamxctrl:=P;


MixerGetLineControls(fMixerHandle,@MLC,

MIXER_GETLINECONTROLSF_ALL);


setlength(mcontrols[j+n],ml2.cControls);


For k:=0 to ml2.cControls-1do


begin


if p.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME

then
line.add(p^.szName);


mcontrols[j+n][k]:=p;


mcontrols[j+n][0].Metrics.dwReserved[k+1]:=1;


inc(p);


end;
//取得混音器线路的控制器

end;



end;



end;




procedure Fillstruct(control:Pmixercontrol;var

Cdetails:Tmixercontroldetails);


begin


cdetails.cbStruct:=sizeof(cdetails);


cdetails.dwControlID:=control.dwControlID ;


cdetails.cbDetails:=sizeof(integer);


cdetails.hwndOwner :=0;


end;



function getpeak(control:Pmixercontrol;var

peak:integer):boolean;


var

details:TMIXERCONTROLDETAILSSIGNED;


cdetails:TMIXERCONTROLDETAILS;


begin


result:=false;


if control.dwControlType <>

MIXERCONTROL_CONTROLTYPE_PEAKMETER then
exit;


cdetails.cChannels :=1;


cdetails.paDetails:=@details;


fillstruct(control,cdetails);


result:=MIXERGETCONTROLDETAILS(fmixerhandle,

@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;


peak:=abs(details.LValue) div 180;


end;




function setvolume(control:Pmixercontrol;


volume:Tvolume):boolean;


var

details:array [0..30] of Integer;


cdetails:TMIXERCONTROLDETAILS;


begin


fillstruct(control,cdetails);


cdetails.cChannels :=2;


cdetails.paDetails:=@details;


details[0]:=volume.left;


details[1]:=volume.right;


result:=MIXERSETCONTROLDETAILS(fmixerhandle,

@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;


end;




function getvolume(control:Pmixercontrol;var

volume:Tvolume):boolean;


var

details:array [0..30] of Integer;


cdetails:TMIXERCONTROLDETAILS;


begin


fillstruct(control,cdetails);


cdetails.cChannels :=2;


cdetails.paDetails:=@details;


result:=MIXERGETCONTROLDETAILS(fmixerhandle,

@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;


volume.left:=details[0];


volume.right:=details[1];


end;



function setmute(control:Pmixercontrol;


mute:integer):boolean;


var

cdetails:Tmixercontroldetails;


details:array [0..30] of Integer;


begin


fillstruct(control,cdetails);


cdetails.cChannels :=1;


cdetails.paDetails:=@details;


details[0]:=mute;


result:=MIXERSETCONTROLDETAILS(fmixerhandle,

@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;


end;



function getmute(control:Pmixercontrol;var

mute:integer):boolean;


var

cdetails:Tmixercontroldetails;


details:array [0..30] of Integer;


begin


fillstruct(control,cdetails);


cdetails.cChannels :=1;


cdetails.cMultipleItems:=0;


cdetails.paDetails:=@details;


result:=MIXERGETCONTROLDETAILS(fmixerhandle,

@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;


mute:=details[0];


end;




procedure TForm2.LinesChange(Sender: TObject);


begin


controls.Items:=line[lines.ItemIndex];


if controls.ItemIndex =-1 then


controls.ItemIndex :=0;


end;




procedure TForm2.ControlsChange(Sender: TObject);


var

mute,k,j:integer;


volume:Tvolume;


begin


lmute.Visible :=false;


lmeter.Visible :=false;


k:=lines.ItemIndex;j:=controls.ItemIndex;


IF mcontrols[k][j][0].Metrics.dwReserved[2]=1 then


begin


lmute.Visible:=mcontrols[k][j][1].dwcontroltype

=MIXERCONTROL_CONTROLTYPE_MUTE;


lmeter.Visible:=mcontrols[k][j][1].dwcontroltype

=MIXERCONTROL_CONTROLTYPE_PEAKMETER;


if lmeter.Visible then
peaknum:=1;


end;



cmute.Enabled :=lmute.Visible ;


IF mcontrols[k][j][0].Metrics.dwReserved[3]=1 then


begin


lmeter.Visible:=mcontrols[k][j][2].dwcontroltype

=MIXERCONTROL_CONTROLTYPE_PEAKMETER;


if lmeter.Visible then
peaknum:=2;


end;



if getvolume(mcontrols[k][j][0],volume) then


begin


Rvolume.Position :=-volume.right;


Lvolume.Position :=-volume.left;


end;



if getmute(mcontrols[k][j][1],mute) then


cmute.Checked :=mute=1;


RProgressbar.Visible :=lmeter.Visible;;


timer1.Enabled:=lmeter.Visible;


end;




procedure TForm2.LVolumeChange(Sender: TObject);


var volume:tvolume;


begin


if checkbox1.Checked then
Rvolume.Position :=Lvolume.Position ;


volume.right :=-Rvolume.Position;


volume.left:=-Lvolume.Position ;


setvolume(mcontrolS[lines.itemindex][controls.itemindex][0],

volume);


end;




procedure TForm2.cmuteClick(Sender: TObject);


var mute:integer;


begin


if cmute.checked then
mute:=1 else
mute:=0;


setmute(mcontrolS[lines.itemindex][controls.itemindex][1],mute);


end;




procedure TForm2.RvolumeChange(Sender: TObject);


begin


if checkbox1.Checked then
Lvolume.Position :=Rvolume.Position ;


Lvolume.OnChange (sender);


end;




procedure TForm2.AboutClick(Sender: TObject);


begin


showmessage('Mixer Demo version 1.0 '+chr(13)

+'Written by David Jiang');


end;




procedure TForm2.BExitClick(Sender: TObject);


begin


close;


end;




procedure TForm2.Timer1Timer(Sender: TObject);


var peak:integer;


begin


IF mcontrols[lines.itemindex][controls.itemindex]

[0].Metrics.dwReserved[peaknum+1]=1 then


if getpeak(mcontrols[lines.itemindex][controls.itemindex]

[peaknum],peak) then


Rprogressbar.Position :=peak;


end;




procedure TForm2.FormClose(Sender: TObject;
var Action: TCloseAction);


begin


mixerclose(fmixerhandle);


end;



end.
 
用 FFT 变换
 
记得看过一代码。好象在回调函数中可以
 
用directsound。播放后lock住buffer直接取数据。
 
一个WAV文件本身记录的就是振幅——取样点的电压值,与频率无关。
你需要的是winamp那样的频谱显示,还是cooledit编辑音频文件时那样的波形显示?

波形显示就是WAV文件的取样显示,直接显示数据量太大,每隔N点取出一点来显示就是cooledit那样的波形显示。

频谱显示需要FFT变换,例如,一个WAV文件,取样频率44100Hz,双声道,取其中一个声道连续的一组WAV数据库8192点,就是一个buffer[0..8191];经FFT变换,得到一个buffer2[0..8191],
df:=44100/8192=5.3833;
buffer2[0]的大小就是0-5.3833Hz的振幅大小
buffer2[1]的大小就是5.3833-5.3833*2Hz的振幅大小
.........
 
都非我所需,谁还有更好的建议?
to skadon:
我需要能获取mp3文件的...哎,玩音频的高手帮帮忙拉
 
那你需要先把 mp3 解码成 原始的 wav 才行。

如果上面说的都不是你想要的,那我们都没有明白你想要什么
 
首先你应该设置你接受的声音一些基本信息

with RecordFormatdo

begin

wFormatTag := 1;
{ format type }
nChannels := 2;
{ number of channels (i.e. mono, stereo, etc.) }
nSamplesPerSec := 44100;
{ sample rate }

nAvgBytesPerSec := 176400;
{ for buffer estimation }
nBlockAlign := 4;
{ block size of data }
wBitsPerSample := 16;
{ number of bits per sample of mono data }
cbSize := 25449;
end;


其次
用TACMWaveIn空间获取输入的声音,就得到声音振幅了,但是该振幅是 时域,如果你要显示频域 就应该调用fft (快速傅立叶)把时域变成频域函数

如果是wav文件,你先了解一下wav文件结构,去掉wav的文件头,剩下的就是它的时域振幅了
 
谢谢各位。找到份别人写的例子,研究中...
 
多人接受答案了。
 
后退
顶部