錄音時,顯示即時播形圖,求助 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,對應資料話矩形,就可以搞定