2010-08-11 154 views

回答

2

微軟有一個Knowledge Base article告訴你如何使用MCI從內存播放聲音。您可能需要在數組中包含波形文件標頭,否則在第一次讀取時需要複製正確的數據,但除此之外,它應該相當容易移植。

4

Wave Audio Package有TLiveAudioPlayer組件。它從緩衝區播放音頻。

+0

是的,它爲我工作爲好。和它的好處,沒有像bass.dll lame.exe等外部組件 – XBasic3000 2010-08-13 03:56:33

+0

我認爲這個答案應該被標記爲最好的。 – Javid 2014-08-03 10:52:43

2

Win32 API PlaySound函數可以使用其SND_MEMORY標誌從存儲器塊播放標準RIFF編碼音頻(如WAV音頻)。或者,如果音頻位於應用的資源中,則可以使用SND_RESOURCE標誌。

7

我在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, 0, 0, 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, @hdr, sizeof(hdr)); 
     sleep(500); 

     while waveOutUnprepareHeader(hWave, @hdr, sizeof(hdr)) = WAVERR_STILLPLAYING do 
     if PlaySoundStopper^ then 
     begin 
      waveOutPause(hWave); 
      waveOutUnprepareHeader(hWave, @hdr, 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, 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, i]), sizeof(TASWaveformSample)); 

     if waveOutOpen(@hWave, WAVE_MAPPER, @fmt, 0, 0, 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, @hdr, sizeof(hdr)); 
     waveOutWrite(hWave, @hdr, sizeof(hdr)); 
     sleep(500); 

     while waveOutUnprepareHeader(hWave, @hdr, 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, PChar(E.ClassName + ': ' + E.Message), 'TSoundPlayerThread', MB_ICONERROR); 
    end; 

    finally 
    ThreadPlaying := false; 
    end; 
end; 
+0

我想問你更多關於PCM的信息。這是我的E - 添加[email protected]我需要你的幫助。 – XBasic3000 2010-08-13 08:25:45

相關問題