录音时,显示即时播形图,求助 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiMultimedia/html/delphi_20061106094422173.html
我想在录音的时候,同时显示出对应的波形数据,我用的是waveinstart系列函数,但是最终生成的wave文件中,并没有声音,用千千静听播放时,全是杂音,而且千千静听显示的波形很怪。我用的是如下方法生成wave文件头的。
procedure TRecorder.WriteHead;
var
fmtSize: Integer;
fileSize: DWORD;
wf : file of TWavHeader;
wh : TWavHeader;
begin
wh.rId := $46464952;
wh.rLen := 36 + m_SumData;
wh.wId := $45564157;
wh.fId := $20746d66;
wh.fLen := 16;
wh.wFormatTag := 1;
wh.nChannels := m_WaveFormat.nChannels;
wh.nSamplesPerSec := m_WaveFormat.nSamplesPerSec;
wh.nAvgBytesPerSec := m_WaveFormat.nAvgBytesPerSec;
wh.nBlockAlign := m_WaveFormat.nBlockAlign;
wh.wBitsPerSample := m_WaveFormat.wBitsPerSample;
wh.dId := $61746164;
wh.wSampleLength := m_SumData;
FileStream.Write(wh, SizeOf(wh));
end;
其他代码即如下:
constructor TRecorder.Create(wBitsPerSample, wChannels: Word;
dwSampleRate: Cardinal; nBufferLength: Integer);
var
i: Integer;
begin
m_bRecording := FALSE;
m_bDeviceOpen := FALSE;
m_PcmFormat.wBitsPerSample := wBitsPerSample;
m_PcmFormat.wChannels := wChannels;
m_PcmFormat.dwSampleRate := dwSampleRate;
m_dwBufferSize := (nBufferLength * (m_PcmFormat.wChannels) * (m_PcmFormat.wBitsPerSample) div 8);
fnProcessBuffer := nil;
m_lpWaveHdr := nil;
m_SumData := 0;
m_hEvent := 0;
m_hThread := 0;
for i:= 0 to MAXNUMOFBUFFER - 1 do
begin
m_hWaveInHdr[i] := 0;
m_hInBuffer[i] := 0;
end;
end;
constructor TRecorder.Create(nBufferLength: Integer);
var
i: Integer;
begin
m_bRecording := False;
m_bDeviceOpen := False;
m_PcmFormat.wBitsPerSample := 16;
m_PcmFormat.wChannels := 2;
m_PcmFormat.dwSampleRate := 11025;
m_dwBufferSize := (nBufferLength * m_PcmFormat.wChannels * m_PcmFormat.wBitsPerSample div 8);
fnProcessBuffer := nil;
m_lpWaveHdr := nil;
m_hEvent := 0;
m_hThread := 0;
for i:= 0 to MAXNUMOFBUFFER - 1 do
begin
m_hWaveInHdr[i] := 0;
m_hInBuffer[i] := 0;
end;
end;
constructor TRecorder.Create(pcm: TPCMFormat; nBufferLength: Integer);
var
i: Integer;
begin
m_bRecording := FALSE;
m_bDeviceOpen := FALSE;
m_PcmFormat.wBitsPerSample := pcm.wBitsPerSample;
m_PcmFormat.wChannels := pcm.wChannels;
m_PcmFormat.dwSampleRate := pcm.dwSampleRate;
m_dwBufferSize := (nBufferLength * m_PcmFormat.wChannels * m_PcmFormat.wBitsPerSample div 8);
fnProcessBuffer := nil;
m_lpWaveHdr := nil;
m_hEvent := 0;
m_hThread := 0;
for i:= 0 to MAXNUMOFBUFFER - 1 do
begin
m_hWaveInHdr[i] := 0;
m_hInBuffer[i] := 0;
end;
end;
function TRecorder.GetPosition: Int64;
var
mmtime: TMMTime;
begin
if m_hWaveIn <> 0 then
begin
mmtime.wType := TIME_SAMPLES;
if waveInGetPosition(m_hWaveIn, @mmTime, SizeOf(mmTime)) <> MMSYSERR_NOERROR then
Result := -1
else
Result := mmTime.sample;
end;
Result := -1;
end;
function TRecorder.IsDeviceOpen: Boolean;
begin
Result := m_bDeviceOpen;
end;
function TRecorder.IsFormatSupported(wfEX: tWAVEFORMATEX;
nDev: Cardinal): Boolean;
var
mm: MMRESULT;
begin
mm := waveInOpen(nil, nDev, @wfEx, 0, 0, WAVE_FORMAT_QUERY);
if mm = MMSYSERR_NOERROR then
Result := True
else
Result := False;
end;
function TRecorder.IsRecording: Boolean;
begin
Result := m_bRecording;
end;
procedure TRecorder.Open(dwCallBack, dwCallbackType: Cardinal;
wMCIDeviceID: MCIDEVICEID);
var
i: Integer;
begin
if not m_bDeviceOpen then
begin
if dwCallBack = 0 then
dwCallBack := DWord(@waveinProc);
for i:= 0 to MAXNUMOFBUFFER - 1 do
begin
m_hWaveInHdr[i] := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TWaveHdr));
m_lpWaveInHdr[i] := pWaveHdr(GlobalLock(m_hWaveInHdr[i]));
m_hInBuffer[i] := GlobalAlloc(GHND or GMEM_SHARE , m_dwBufferSize);
m_lpInBuffer[i] := PBYTE(GlobalLock(m_hInBuffer[i]));
m_lpWaveInHdr[i]^.lpData := PChar(m_lpInBuffer[i]);
m_lpWaveInHdr[i]^.dwBufferLength := m_dwBufferSize;
m_lpWaveInHdr[i]^.dwBytesRecorded := 0;
m_lpWaveInHdr[i]^.dwUser := Cardinal(Pointer(Self));
m_lpWaveInHdr[i]^.dwFlags := 0;
m_lpWaveInHdr[i]^.dwLoops := 1;
m_lpWaveInHdr[i]^.lpNext := nil;
m_lpWaveInHdr[i]^.reserved := 0;
end;
m_WaveFormat.wFormatTag := WAVE_FORMAT_PCM;
m_WaveFormat.nChannels := m_PcmFormat.wChannels;
m_WaveFormat.wBitsPerSample := m_PcmFormat.wBitsPerSample;
m_WaveFormat.nSamplesPerSec := m_PcmFormat.dwSampleRate;
m_WaveFormat.nBlockAlign := m_WaveFormat.nChannels * m_WaveFormat.wBitsPerSample div 8;
m_WaveFormat.nAvgBytesPerSec := m_WaveFormat.nBlockAlign * m_WaveFormat.nSamplesPerSec;
m_waveClass.lpData := Self;
if not ((waveInOpen(PHWAVEIN(@m_waveClass), wMCIDeviceID, PWaveFormatEx(@m_WaveFormat),
dwCallBack, 0, dwCallbackType) <> 0) or
(m_waveClass.hWave = 0)
) then
begin
m_waveClass.lpData := Self;
m_hWaveIn := HWAVEIN(m_waveClass.hWave);
m_hEvent := CreateEvent(nil, False, False, nil);
m_bDeviceOpen := True;
end;
end;
end;
function TRecorder.Pause: Boolean;
begin
Result := False;
if m_hWaveIn <> 0 then
begin
if waveInStop(m_hWaveIn) = MMSYSERR_NOERROR then
begin
m_bRecording := False;
Result := True;
end;
end;
end;
procedure TRecorder.ProcessNextBuffer(pwh: PWaveHdr);
begin
if @fnProcessBuffer <> nil then
fnProcessBuffer(m_lpData,pwh);
m_SumData := m_SumData + 2048 -1;
waveInUnprepareHeader(m_hWaveIn, pwh, sizeof(WAVEHDR));
waveInPrepareHeader (m_hWaveIn, pwh, sizeof(WAVEHDR));
waveInAddBuffer(m_hWaveIn, pwh, sizeof(WAVEHDR));
end;
procedure TRecorder.SetBufferFunction(lpData: Pointer;
fnProcess: ProcessBuffer);
begin
m_lpData := lpData;
fnProcessBuffer := fnProcess;
end;
procedure TRecorder.SetFormat(lpPcmFormat: pPCMFormat);
begin
if m_bDeviceOpen = False then
begin
m_PcmFormat.wBitsPerSample := lpPcmFormat^.wBitsPerSample;
m_PcmFormat.wChannels := lpPcmFormat^.wChannels;
m_PcmFormat.dwSampleRate := lpPcmFormat^.dwSampleRate;
end;
end;
procedure TRecorder.SetFormat(wBitsPerSample, wChannels: Word;
dwSampleRate: Cardinal);
begin
if m_bDeviceOpen = False then
begin
m_PcmFormat.wBitsPerSample := wBitsPerSample;
m_PcmFormat.wChannels := wChannels;
m_PcmFormat.dwSampleRate := dwSampleRate;
end;
end;
procedure TRecorder.Start;
var
i: Integer;
ThreadId: DWORD;
begin
if not m_bDeviceOpen then
Exit
else
begin
for i:= 0 to MAXNUMOFBUFFER - 1 do
begin
if waveInPrepareHeader(m_hWaveIn, m_lpWaveInHdr[i], SizeOf(TWaveHdr)) <> MMSYSERR_NOERROR then
Exit;
if waveInAddBuffer(m_hWaveIn, m_lpWaveInHdr[i], SizeOf(TWaveHdr)) <> MMSYSERR_NOERROR then
Exit;
end;
FileStream := TFileStream.Create('c:\wave.wav', fmCreate or fmOpenReadWrite );
WriteHead;
//begin sampling
m_bRecording := True;
m_hThread := CreateThread(nil, 0, @RecorderThreadFunc, Self, 0, ThreadId);
waveInStart(m_hWaveIn);
if m_hThread <> 0 then
begin
SetPriorityClass(m_hThread, REALTIME_PRIORITY_CLASS);
SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST);
end;
end;
end;
procedure TRecorder.Stop;
begin
if (m_bDeviceOpen = False) or (m_bRecording = False) then
Exit;
if (waveInStop(m_hWaveIn)) <> MMSYSERR_NOERROR then
Exit
else
m_bRecording := False;
end;
求高手与熟手指点下啊。如果哪位有代码请帮下俺啊。在线等,很急。
剩下的代码:
procedure TRecorder.Close;
var
i: Integer;
begin
FileStream.Position := 0; //重定位
WriteHead;
if m_bRecording then
Stop;
if m_hThread <> 0 then
CloseHandle(m_hThread);
if m_bDeviceOpen then
waveInClose(m_hWaveIn);
for i:= 0 to MAXNUMOFBUFFER-1 do
begin
if (m_hWaveInHdr[i] <> 0 ) then
begin
if GlobalUnlock(m_hWaveInHdr[i]) then
GlobalFree(m_hWaveInHdr[i]);
if GlobalUnlock(m_hInBuffer[i]) then
GlobalFree(m_hInBuffer[i]);
m_hWaveInHdr[i] := 0;
m_hInBuffer[i] := 0;
end;
end;
m_bDeviceOpen := False;
m_bRecording := False;
m_hThread := 0;
end;
function TRecorder.Continue: Boolean;
begin
Result := False;
if m_hWaveIn <> 0 then
begin
if waveInStart(m_hWaveIn) = MMSYSERR_NOERROR then
begin
m_bRecording := False;
Result := True;
end;
end;
end;
好像没多少人有这么多工夫来检查这么多的代码。自己调试吧。哪出的问题,针对它查资料。
用Wave Audio组件的TAudioRecorder(开源的)
就都不用自己写代码,呵呵~
这个组件可以实现吗????
数据已实现出来了,请问哪位老大有显示波形图的函数啊。急啊
直接使用DirectX,对应数据话矩形,就可以搞定