delphi audio multimedia

¿Cuál es la forma más sencilla de reproducir sonido a partir de datos de matriz en Delphi?



audio multimedia (4)

¿Hay alguna función simple? Estoy buscando algo así

Reproducir (@data, 44000, 100 {time});


He trabajado bastante con la manipulación de audio PCM. Siempre utilizo esta función cuando reproduzco secuencias cortas de datos de audio de forma de onda personalizados:

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;

dónde

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;

Una forma quizás mejor, es usar un hilo para tocar. Entonces lo hago

var OwnerForm: HWND; // = 0; SndSource: PASSound; // = nil; ThreadPlaying: boolean; // = false; type TSoundPlayerThread = class(TThread) private { Private declarations } protected procedure Execute; override; end;

implementado como

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;


La función Win32 API PlaySound puede reproducir audio estándar con codificación RIFF (como audio WAV) desde un bloque de memoria mediante el uso de su indicador SND_MEMORY . Alternativamente, si el audio está en los recursos de la aplicación, puede usar el indicador SND_RESOURCE lugar.


Microsoft tiene un artículo de Knowledge Base que le dice cómo puede reproducir el sonido de la memoria usando MCI. Probablemente necesites tener el encabezado del archivo Wave en tu matriz, o copiar los datos correctos durante la primera lectura, pero aparte de eso, debería ser bastante fácil de sobrepasar.


Wave Audio Package tiene el componente TLiveAudioPlayer. Reproduce audio desde el búfer.