Проигрывание PCM данных (Windows,Linux)
Примеры , позволяющие проиграть PCM данные. Можно задать для проигрывания указатель на данные , с возможностью задать кол-во каналов (моно. стерео), частоту дискретизации, кол-во бит на семпл (8 , 16). Для Windows подобных примеров предостаточно , но вот для Linux замучаешься искать. И хотя здесь два примера (для Windows и Linux), но интерфейс у них идинтичный.
Платформы: Windows, Linux
Автор: angros47
1) для Windows:
#INCLUDE "Windows.bi" #INCLUDE Once "crt/string.bi" #INCLUDE "win/mmsystem.bi" '#define WAVE_MAPPER -1 Dim Shared _hWaveOut As HWAVEOUT Dim Shared cs As CRITICAL_SECTION Type QueueWAVEHDR _wavehdr As WAVEHDR _next As QueueWAVEHDR Ptr End Type Dim Shared doneWaveHdrs As QueueWAVEHDR Ptr Dim Shared waitingBytes As Integer Sub dsp_callback Stdcall (_hWaveOut As HWAVEOUT, msg As UINT, instance As DWORD, p1 As DWORD, p2 As DWORD) If msg = WOM_DONE Then Dim p As QueueWAVEHDR Ptr p = Cast(QueueWAVEHDR Ptr, p1) EnterCriticalSection(@cs) p->_next = doneWaveHdrs doneWaveHdrs = p LeaveCriticalSection(@cs) End If End Sub Sub clean_unprepares() EnterCriticalSection(@cs) Do While (doneWaveHdrs) Dim p As QueueWAVEHDR Ptr p = doneWaveHdrs doneWaveHdrs = p->_next waitingBytes -= p->_wavehdr.dwBufferLength waveOutUnprepareHeader(_hWaveOut, @p->_wavehdr, Sizeof(WAVEHDR)) Deallocate(p->_wavehdr.lpData) Deallocate(p) Loop LeaveCriticalSection(@cs) End Sub Sub dsp_finalize() If _hWaveOut Then waveOutPause(_hWaveOut) waveOutReset(_hWaveOut) clean_unprepares() waveOutClose(_hWaveOut) _hWaveOut = NULL DeleteCriticalSection(@cs) End If End Sub Sub SoundSet(frequency As Integer, channels As Integer, bits As Integer) Dim As WAVEFORMATEX wfx dsp_finalize() memset(@wfx, 0, Sizeof(wfx)) wfx.wFormatTag = WAVE_FORMAT_PCM wfx.nChannels = channels wfx.nSamplesPerSec = frequency wfx.wBitsPerSample = bits wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec wfx.cbSize = 0 If waveOutOpen(@_hWaveOut, WAVE_MAPPER, @wfx, Cast(DWORD, @dsp_callback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR Then _hWaveOut = NULL Else waveOutRestart(_hWaveOut) InitializeCriticalSection(@cs) End If End Sub Sub playbuffer (soundBuffer As Any Ptr, buffersize As Integer) If _hWaveOut Then Dim p As WAVEHDR Ptr = Allocate(Sizeof(QueueWAVEHDR)) memset(p, 0, Sizeof(WAVEHDR)) p->lpData = Allocate(buffersize) If p->lpData=0 Then Deallocate(p) Else memcpy(p->lpData, SoundBuffer, buffersize) p->dwBufferLength = buffersize: p->dwBytesRecorded = buffersize waveOutPrepareHeader(_hWaveOut, p, Sizeof(WAVEHDR)) If waveOutWrite(_hWaveOut, p, Sizeof(WAVEHDR)) = MMSYSERR_NOERROR Then waitingBytes += p->dwBufferLength Else waveOutUnprepareHeader(_hWaveOut, p, Sizeof(WAVEHDR)) Deallocate(p->lpData) Deallocate(p) End If End If clean_unprepares() End If End Sub Dim MyBuffer(200000) As Short SoundSet 44100,2,16 Dim i2 As Integer For a As integer=0 To 80 For i As integer=1 To 512*4 Step 2 i2=i2+1 MyBuffer(i)= (i2 Mod 20)*i2/10 MyBuffer(i+1)= (i2 Mod 20)*i2/10 Next playbuffer @MyBuffer(0),1024*4 Next Sleep
2) для Linux:
Dim Shared As Any Ptr alsa Dim Shared As Integer OSS 'ALSA declarations alsa = Dylibload("asound") Const EAGAIN = -11 ' Try again Const EPIPE = -32 ' Broken pipe Const ESTRPIPE = -86 ' Streams pipe error Const BLOCK = 0 Const NONBLOCK = 1 Const ASYNC = 2 Const SND_PCM_STREAM_PLAYBACK = 0 Const SND_PCM_STREAM_CAPTURE = 1 Const SND_PCM_FORMAT_S16_LE = 2 Const SND_PCM_ACCESS_RW_INTERLEAVED= 3 #IFNDEF NULL #DEFINE NULL 0 #ENDIF Type snd_pcm_t As Any Ptr Type snd_pcm_hw_params_t As Any Ptr Type snd_output_t As Any Ptr ' PCM Dim Shared snd_strerror As Function ( _ Byval ecode As Integer) As Zstring Ptr snd_strerror= Dylibsymbol(alsa, "snd_strerror") Dim Shared snd_pcm_open As Function ( _ Byval pcm As snd_pcm_t Ptr, _ Byval device As Zstring Ptr, _ Byval direction As Integer, _ Byval mode As Integer) As Integer snd_pcm_open= Dylibsymbol(alsa, "snd_pcm_open") Dim Shared snd_pcm_close As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_close= Dylibsymbol(alsa, "snd_pcm_close") Dim Shared snd_pcm_start As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_start= Dylibsymbol(alsa, "snd_pcm_start") Dim Shared snd_pcm_drain As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_drain= Dylibsymbol(alsa, "snd_pcm_drain") Dim Shared snd_pcm_hw_free As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_hw_free= Dylibsymbol(alsa, "snd_pcm_hw_free") Dim Shared snd_pcm_nonblock As Function ( _ Byval pcm As snd_pcm_t, _ Byval nonblock As Integer) As Integer snd_pcm_nonblock= Dylibsymbol(alsa, "snd_pcm_nonblock") Dim Shared snd_pcm_prepare As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_prepare= Dylibsymbol(alsa, "snd_pcm_prepare") Dim Shared snd_pcm_writei As Function ( _ Byval pcm As snd_pcm_t, _ Byval buffer As Any Ptr, _ Byval size As Integer) As Integer snd_pcm_writei= Dylibsymbol(alsa, "snd_pcm_writei") Dim Shared snd_pcm_recover As Function ( _ Byval pcm As snd_pcm_t, _ Byval Err As Integer, _ Byval silent As Integer) As Integer snd_pcm_recover= Dylibsymbol(alsa, "snd_pcm_recover") Dim Shared snd_pcm_avail_update As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_avail_update= Dylibsymbol(alsa, "snd_pcm_avail_update") Dim Shared snd_pcm_delay As Function ( _ Byval pcm As snd_pcm_t, _ Byval delayp As snd_pcm_t) As Integer snd_pcm_delay= Dylibsymbol(alsa, "snd_pcm_delay") Dim Shared snd_pcm_wait As Function ( _ Byval pcm As snd_pcm_t, _ Byval msec As Integer) As Integer snd_pcm_wait= Dylibsymbol(alsa, "snd_pcm_wait") Dim Shared snd_pcm_resume As Function ( _ Byval pcm As snd_pcm_t) As Integer snd_pcm_resume= Dylibsymbol(alsa, "snd_pcm_resume") 'hardware Dim Shared snd_pcm_hw_params_malloc As Function ( _ Byval hw As snd_pcm_hw_params_t Ptr) As Integer snd_pcm_hw_params_malloc= Dylibsymbol(alsa, "snd_pcm_hw_params_malloc") Dim Shared snd_pcm_hw_params_any As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t) As Integer snd_pcm_hw_params_any= Dylibsymbol(alsa, "snd_pcm_hw_params_any") Dim Shared snd_pcm_hw_params_set_access As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval mode As Integer) As Integer snd_pcm_hw_params_set_access= Dylibsymbol(alsa, "snd_pcm_hw_params_set_access") Dim Shared snd_pcm_hw_params_set_format As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval fmt As Integer) As Integer snd_pcm_hw_params_set_format= Dylibsymbol(alsa, "snd_pcm_hw_params_set_format") Dim Shared snd_pcm_hw_params_set_channels As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval Channels As Integer) As Integer snd_pcm_hw_params_set_channels= Dylibsymbol(alsa, "snd_pcm_hw_params_set_channels") Dim Shared snd_pcm_hw_params_get_channels As Function ( _ Byval hw As snd_pcm_hw_params_t, _ Byval lpChannels As Integer Ptr) As Integer snd_pcm_hw_params_get_channels= Dylibsymbol(alsa, "snd_pcm_hw_params_get_channels") Dim Shared snd_pcm_hw_params_set_rate_near As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval lpRate As Integer Ptr, _ Byval lpDir As Integer Ptr) As Integer snd_pcm_hw_params_set_rate_near= Dylibsymbol(alsa, "snd_pcm_hw_params_set_rate_near") Dim Shared snd_pcm_hw_params_get_periods As Function ( _ Byval hw As snd_pcm_hw_params_t, _ Byval lpValue As Integer Ptr, _ Byval lpDir As Integer Ptr) As Integer snd_pcm_hw_params_get_periods= Dylibsymbol(alsa, "snd_pcm_hw_params_get_periods") Dim Shared snd_pcm_hw_params_set_periods_near As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval lpValue As Integer Ptr, _ Byval lpDir As Integer Ptr) As Integer snd_pcm_hw_params_set_periods_near= Dylibsymbol(alsa, "snd_pcm_hw_params_set_periods_near") Dim Shared snd_pcm_hw_params_get_period_size As Function ( _ Byval params As snd_pcm_hw_params_t, _ Byval lpFrames As Integer Ptr, _ Byval lpDir As Integer Ptr) As Integer snd_pcm_hw_params_get_period_size= Dylibsymbol(alsa, "snd_pcm_hw_params_get_period_size") Dim Shared snd_pcm_hw_params_set_period_size_near As Function ( _ Byval pcm As snd_pcm_t Ptr, _ Byval hw As snd_pcm_hw_params_t, _ Byval lpValue As Integer Ptr, _ Byval lpDir As Integer Ptr) As Integer snd_pcm_hw_params_set_period_size_near= Dylibsymbol(alsa, "snd_pcm_hw_params_set_period_size_near") Dim Shared snd_pcm_hw_params_set_buffer_size_near As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t, _ Byval lpFrames As Integer Ptr) As Integer snd_pcm_hw_params_set_buffer_size_near= Dylibsymbol(alsa, "snd_pcm_hw_params_set_buffer_size_near") Dim Shared snd_pcm_hw_params_get_buffer_size As Function ( _ Byval hw As snd_pcm_hw_params_t, _ Byval lpFrames As Integer Ptr) As Integer snd_pcm_hw_params_get_buffer_size= Dylibsymbol(alsa, "snd_pcm_hw_params_get_buffer_size") Dim Shared snd_pcm_hw_params As Function ( _ Byval pcm As snd_pcm_t, _ Byval hw As snd_pcm_hw_params_t) As Integer snd_pcm_hw_params= Dylibsymbol(alsa, "snd_pcm_hw_params") Dim Shared snd_pcm_hw_params_free As Sub ( _ Byval hw As snd_pcm_hw_params_t) snd_pcm_hw_params_free= Dylibsymbol(alsa, "snd_pcm_hw_params_free") Dim Shared As snd_pcm_t Ptr hDevice Dim Shared As snd_pcm_hw_params_t Ptr hw Dim Shared As Integer ret,value,direction,buffersize,nFrames,Periodsize Dim Shared As Zstring Ptr strRet 'OSS declarations #INCLUDE "file.bi" OSS=FileExists("/dev/dsp") Declare Function fileno Cdecl Alias "fileno" (Byval As Any Ptr) As Integer Declare Function ioctl Cdecl Alias "ioctl" (Byval hDevice As Integer,Byval io_cmd As Integer,Byval lpArg As Integer Ptr) As Integer #DEFINE _IOC_NRBITS 8 #DEFINE _IOC_TYPEBITS 8 #DEFINE _IOC_SIZEBITS 14 #DEFINE _IOC_DIRBITS 2 #DEFINE _IOC_NRMASK ((1 Shl _IOC_NRBITS )-1) #DEFINE _IOC_TYPEMASK ((1 Shl _IOC_TYPEBITS)-1) #DEFINE _IOC_SIZEMASK ((1 Shl _IOC_SIZEBITS)-1) #DEFINE _IOC_DIRMASK ((1 Shl _IOC_DIRBITS )-1) #DEFINE _IOC_NRSHIFT 0 #DEFINE _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) #DEFINE _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) #DEFINE _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) ' Direction bits. #DEFINE _IOC_NONE 0U #DEFINE _IOC_WRITE 1U #DEFINE _IOC_READ 2U #DEFINE _IOC(Dir,t,nr,size) (((Dir) Shl _IOC_DIRSHIFT) Or ((t) Shl _IOC_TYPESHIFT) Or ((nr) Shl _IOC_NRSHIFT) Or ((size) Shl _IOC_SIZESHIFT)) ' used to create numbers #DEFINE _IO(t,nr) _IOC(_IOC_NONE,(t),(nr),0) #DEFINE _IOR(t,nr,size) _IOC(_IOC_READ,(t),(nr),Sizeof(size)) #DEFINE _IOW(t,nr,size) _IOC(_IOC_WRITE,(t),(nr),Sizeof(size)) #DEFINE _IOWR(t,nr,size) _IOC(_IOC_READ Or _IOC_WRITE,(t),(nr),Sizeof(size)) ' used to decode ioctl numbers.. #DEFINE _IOC_DIR(nr) (((nr) Shr _IOC_DIRSHIFT) And _IOC_DIRMASK) #DEFINE _IOC_TYPE(nr) (((nr) Shr _IOC_TYPESHIFT) And _IOC_TYPEMASK) #DEFINE _IOC_NR(nr) (((nr) Shr _IOC_NRSHIFT) And _IOC_NRMASK) #DEFINE _IOC_SIZE(nr) (((nr) Shr _IOC_SIZESHIFT) And _IOC_SIZEMASK) ' ...and for the drivers/sound files... #DEFINE IOC_IN ( _IOC_WRITE Shl _IOC_DIRSHIFT) #DEFINE IOC_OUT ( _IOC_READ Shl _IOC_DIRSHIFT) #DEFINE IOC_INOUT ((_IOC_WRITE Or _IOC_READ) Shl _IOC_DIRSHIFT) #DEFINE IOCSIZE_MASK ( _IOC_SIZEMASK Shl _IOC_SIZESHIFT) #DEFINE IOCSIZE_SHIFT ( _IOC_SIZESHIFT) ' IOCTL commands for /dev/dsp and /dev/audio #DEFINE SNDCTL_DSP_RESET _IO (Asc("P"), 0) #DEFINE SNDCTL_DSP_SYNC _IO (Asc("P"), 1) #DEFINE SNDCTL_DSP_SPEED _IOWR(Asc("P"), 2, Integer) #DEFINE SNDCTL_DSP_STEREO _IOWR(Asc("P"), 3, Integer) #DEFINE SNDCTL_DSP_GETBLKSIZE _IOWR(Asc("P"), 4, Integer) #DEFINE SNDCTL_DSP_SETFMT _IOWR(Asc("P"), 5, Integer) ' Selects ONE fmt #DEFINE SNDCTL_DSP_CHANNELS _IOWR(Asc("P"), 6, Integer) #DEFINE SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS #DEFINE SOUND_PCM_WRITE_FILTER _IOWR(Asc("P"), 7, Integer) #DEFINE SNDCTL_DSP_POST _IO (Asc("P"), 8) #DEFINE SNDCTL_DSP_SUBDIVIDE _IOWR(Asc("P"), 9, Integer) #DEFINE SNDCTL_DSP_SETFRAGMENT _IOWR(Asc("P"),10, Integer) #DEFINE SNDCTL_DSP_GETFMTS _IOR (Asc("P"),11, Integer) ' Returns a mask #DEFINE SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT #DEFINE SNDCTL_DSP_GETODELAY _IOR (Asc("P"), 23, Integer) 'arg for SNDCTL_DSP_SETFMT cmd Const AFMT_MU_LAW = &H00000001 Const AFMT_A_LAW = &H00000002 Const AFMT_IMA_ADPCM = &H00000004 Const AFMT_U8 = &H00000008 Const AFMT_S16_LE = &H00000010 ' Little endian signed Const AFMT_S16_BE = &H00000020 ' Big endian signed 16 Const AFMT_S8 = &H00000040 Const AFMT_U16_LE = &H00000080 ' Little endian U16 Const AFMT_U16_BE = &H00000100 ' Big endian U16 Const AFMT_MPEG = &H00000200 ' MPEG (2) audio Const AFMT_AC3 = &H00000400 ' Dolby Digital AC3 Sub SoundSet(frequency As Integer, channels As Integer, bits As Integer) If alsa Then If bits=16 Then PeriodSize=2 Else Periodsize=1 Periodsize*=channels ret = snd_pcm_open(@hDevice,"default", SND_PCM_STREAM_PLAYBACK, BLOCK) snd_pcm_hw_params_malloc(@hw) ret = snd_pcm_hw_params_any(hDevice,hw) ret = snd_pcm_hw_params_set_access(hDevice, hw, SND_PCM_ACCESS_RW_INTERLEAVED) ret = snd_pcm_hw_params_set_format(hDevice,hw,Iif(bits=16,2,1)) ret = snd_pcm_hw_params_set_channels(hDevice,hw,channels) value=frequency 'set speed ret = snd_pcm_hw_params_set_rate_near(hDevice,hw,@value,@direction) ret = snd_pcm_hw_params(hDevice,hw) snd_pcm_hw_params_free (hw) snd_pcm_prepare(hDevice) Elseif OSS Then If OSS>0 Then Close OSS OSS=FreeFile Open "/dev/dsp" For Output As #1 Dim As Integer arg arg=IIF(bits=16, AFMT_S16_LE, AFMT_U8) ioctl fileno(Cast (Any Ptr,Fileattr(1,2))), SNDCTL_DSP_SETFMT, @arg arg=IIF(channels<>0, 1, 0) ioctl fileno(Cast (Any Ptr,Fileattr(1,2))), SNDCTL_DSP_STEREO, @arg arg=channels ioctl fileno(Cast (Any Ptr,Fileattr(1,2))), SNDCTL_DSP_CHANNELS, @arg arg=frequency ioctl fileno(Cast (Any Ptr,Fileattr(1,2))), SNDCTL_DSP_SPEED, @arg End If End Sub Sub playbuffer (soundBuffer As Any Ptr, buffersize As Integer) If alsa Then buffersize/=Periodsize ret=snd_pcm_writei(hDevice, soundBuffer, buffersize) If ret=EPIPE Then ret=snd_pcm_recover(hDevice, ret,1) If ret=0 Then ret=snd_pcm_writei(hDevice, soundBuffer, buffersize) End If Elseif OSS>0 Then Put #OSS, ,*cast(Ubyte Ptr, soundBuffer), buffersize End If End Sub Function SoundQueue() As Integer If alsa Then Dim value As Integer snd_pcm_delay(hDevice, @value) Return value*Periodsize Elseif OSS>0 Then Dim value As Integer ioctl fileno(Cast (Any Ptr,Fileattr(1,2))), SNDCTL_DSP_GETODELAY, @value Return value End If End Function Dim MyBuffer(200000) As Short SoundSet 44100,2,16 Dim i2 As Integer For a As integer=0 To 80 For i As integer=1 To 512*4 Step 2 i2=i2+1 MyBuffer(i)= (i2 Mod 20)*i2/10 MyBuffer(i+1)= (i2 Mod 20)*i2/10 Next playbuffer @MyBuffer(0),1024*4 Next Sleep