有什么简单的功能吗?我正在寻找类似的东西
播放(@data,44000,100 {时间});
解决方法
我在PCM音频操作方面做了很多工作.在播放自定义波形音频数据的短序列时,我总是使用此功能:
var PlaySoundStopper: PBoolean; SoundPlayerActive: boolean = false; procedure PlaySound(const Sound: TASSound); var hWave: HWAVEOUT; hdr: TWaveHdr; buf: PAnsiChar; fmt: TWaveFormatEx; i: Integer; n: Integer; begin try with fmt do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := length(Sound.Channels); nSamplesPerSec := Sound.SampleRate; wBitsPerSample := 32; nAvgBytesPerSec := nChannels * nSamplesPerSec * wBitsPerSample div 8; nBlockAlign := nChannels * wBitsPerSample div 8; cbSize := 0; end; GetMem(buf,fmt.nChannels * length(Sound.Channels[0]) * sizeof(TASWaveformSample)); if length(Sound.Channels) = 1 then CopyMemory(buf,@(Sound.Channels[0,0]),length(Sound.Channels[0]) * sizeof(TASWaveformSample)) else for i := 0 to high(Sound.Channels[0]) do for n := 0 to high(Sound.Channels) do CopyMemory(buf + sizeof(TASWaveformSample) * (i * fmt.nChannels + n),@(Sound.Channels[n,i]),sizeof(TASWaveformSample)); if waveOutOpen(@hWave,WAVE_MAPPER,@fmt,CALLBACK_NULL) <> MMSYSERR_NOERROR then raise Exception.Create('SoundPlayerThread.Execute: waveOutOpen Failed: ' + SysErrorMessage(GetLastError)); ZeroMemory(@hdr,sizeof(hdr)); with hdr do begin lpData := buf; dwBufferLength := fmt.nChannels * length(Sound.Channels[0]) * sizeof(TASWaveformSample); dwFlags := 0; end; try SoundPlayerActive := true; waveOutPrepareHeader(hWave,@hdr,sizeof(hdr)); waveOutWrite(hWave,sizeof(hdr)); sleep(500); while waveOutUnprepareHeader(hWave,sizeof(hdr)) = WAVERR_STILLPLAYING do if PlaySoundStopper^ then begin waveOutPause(hWave); waveOutUnprepareHeader(hWave,sizeof(hdr)); break; end else sleep(100); finally SoundPlayerActive := false; waveOutClose(hWave); FreeMem(buf); end; except on E: Exception do MessageBox(0,PChar(E.ClassName + ': ' + E.Message),'Sound Playback Error',MB_ICONERROR); end; end;
哪里
type TASWaveformSample = integer; // signed 32-bit; -2147483648..2147483647 TASWaveformSamples = packed array of TASWaveformSample; // one channel PASSound = ^TASSound; TASSound = record Channels: packed array of TASWaveformSamples; SampleRate: cardinal; end;
也许更好的方法是使用线程进行播放.然后我做
var OwnerForm: HWND; // = 0; SndSource: PASSound; // = nil; ThreadPlaying: boolean; // = false; type TSoundPlayerThread = class(TThread) private { Private declarations } protected procedure Execute; override; end;
实施为
procedure TSoundPlayerThread.Execute; var hWave: HWAVEOUT; hdr: TWaveHdr; buf: PAnsiChar; fmt: TWaveFormatEx; i: Integer; n: Integer; begin ThreadPlaying := true; try try if not Assigned(SndSource) then Exit; with fmt do begin wFormatTag := WAVE_FORMAT_PCM; nChannels := length(SndSource^.Channels); nSamplesPerSec := SndSource^.SampleRate; wBitsPerSample := 32; nAvgBytesPerSec := nChannels * nSamplesPerSec * wBitsPerSample div 8; nBlockAlign := nChannels * wBitsPerSample div 8; cbSize := 0; end; GetMem(buf,fmt.nChannels * length(SndSource^.Channels[0]) * sizeof(TASWaveformSample)); if length(SndSource^.Channels) = 1 then CopyMemory(buf,@(SndSource^.Channels[0,length(SndSource^.Channels[0]) * sizeof(TASWaveformSample)) else for i := 0 to high(SndSource^.Channels[0]) do for n := 0 to high(SndSource^.Channels) do CopyMemory(buf + sizeof(TASWaveformSample) * (i * fmt.nChannels + n),@(SndSource^.Channels[n,sizeof(TASWaveformSample)); if waveOutOpen(@hWave,CALLBACK_NULL) <> MMSYSERR_NOERROR then raise Exception.Create('SoundPlayerThread.Execute: waveOutOpen Failed: ' + SysErrorMessage(GetLastError)); ZeroMemory(@hdr,sizeof(hdr)); with hdr do begin lpData := buf; dwBufferLength := fmt.nChannels * length(SndSource^.Channels[0]) * sizeof(TASWaveformSample); dwFlags := 0; end; waveOutPrepareHeader(hWave,sizeof(hdr)) = WAVERR_STILLPLAYING do begin sleep(100); if Terminated then waveOutReset(hWave); end; waveOutClose(hWave); FreeMem(buf); except on E: Exception do MessageBox(0,'TSoundPlayerThread',MB_ICONERROR); end; finally ThreadPlaying := false; end; end;