2010-08-11 30 views

Trả lời

2

Microsoft có số Knowledge Base article cho bạn biết cách phát âm thanh từ bộ nhớ bằng MCI. Bạn có thể cần phải có tiêu đề tập tin sóng trong mảng của bạn, hoặc bằng cách khác sao chép vào đúng dữ liệu trong lần đọc đầu tiên, nhưng khác hơn là nó nên được khá dễ dàng để chuyển qua.

4

Wave Audio Package có thành phần TLiveAudioPlayer. Nó phát âm thanh từ bộ đệm.

+0

Có nó làm việc cho tôi là tốt. và điều tốt của nó, không có thành phần bên ngoài như bass.dll lame.exe vv. – XBasic3000

+0

Tôi nghĩ rằng câu trả lời này nên đã được đánh dấu là tốt nhất. – Javid

2

Chức năng Win32 API PlaySound có thể phát âm thanh được mã hóa RIFF tiêu chuẩn (chẳng hạn như âm thanh WAV) từ khối bộ nhớ bằng cách sử dụng cờ SND_MEMORY. Ngoài ra, nếu âm thanh có trong tài nguyên của ứng dụng, bạn có thể sử dụng cờ SND_RESOURCE để thay thế.

7

Tôi đã làm việc khá nhiều với thao tác âm thanh PCM. Tôi luôn luôn sử dụng chức năng này khi chơi chuỗi ngắn của dạng sóng tùy chỉnh dữ liệu âm thanh:

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; 

nơi

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; 

Một cách có lẽ tốt hơn, là sử dụng một sợi cho chơi. Sau đó, tôi làm

var 
    OwnerForm: HWND; // = 0; 
    SndSource: PASSound; // = nil; 
    ThreadPlaying: boolean; // = false; 

type 
    TSoundPlayerThread = class(TThread) 
    private 
    { Private declarations } 
    protected 
    procedure Execute; override; 
    end; 

thực hiện như

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

tôi muốn hỏi thêm về PCM. đây là E-Add [email protected] của tôi, tôi cần sự giúp đỡ của bạn. – XBasic3000

Các vấn đề liên quan