Streaming audio

Windows specific questions.
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Streaming audio

Postby angros47 » Dec 05, 2014 22:46

I converted it from a C source called EASYWAVE:

Code: Select all

#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


You can create a sound with SoundSet rate, no_channels, bits (so, you can have mono or stereo, 8 or 16 bit audio); then, you use the command PlayBuffer data_pointer, no_bytes to send raw sound data, that will be queued and played.

Here is an example:

Code: Select all

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
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Re: Streaming audio

Postby angros47 » Dec 14, 2014 17:38

I made also a linux version: http://freebasic.net/forum/viewtopic.php?f=5&t=23122

And here is another example:

Code: Select all

#DEFINE MusicFunction (i shr 6 or i or i shr (i shr 16))*10+((i shr 11) and 7)

Dim Mybuffer(1000) as ubyte

SoundSet 8000,1,8

dim as integer i

do until multikey(1)
   MyBuffer(i mod 1000)=MusicFunction
   i+=1
   if i mod 1000=999 then playbuffer @MyBuffer(0),1000:sleep 1
loop

sleep


CrisDEV
Posts: 37
Joined: Jun 07, 2016 18:51
Location: Brasil - Sorocaba -SP

Re: Streaming audio

Postby CrisDEV » Jun 09, 2016 18:52

This is fantastic !!!!
I like the music from the second example. Chiptunes music !!!!

Now I will study how to play *.wav and *.ogg
CrisDEV
Posts: 37
Joined: Jun 07, 2016 18:51
Location: Brasil - Sorocaba -SP

Re: Streaming audio

Postby CrisDEV » Jun 09, 2016 21:07

Finaly I have discovered the simplest way to play a WAV music.

Code: Select all

#include once "windows.bi"
#include once "win/mmsystem.bi"  'here have the function to play music.
 
   sndPlaySoundA("teste.wav", 1) '1 to play asynchronously

print "Press any key to exit ...!"
while inkey()=""
  sleep 100
wend


I spend 3 days searching in this forum and nothing. I have find in Google something in Visual Basic and search in the "mmsystem.bi" the function.
And I'am very happy!!!!
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Re: Streaming audio

Postby angros47 » Oct 06, 2016 11:27

A simple question: can anyone tell me if my code works in windows 64 bit, too?
dodicat
Posts: 5757
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Streaming audio

Postby dodicat » Oct 06, 2016 17:24

Win 10
64 bits
line 4
#define wavemapper -1 (wave_mapper seems to clash)
Line 22
Lne 71

I have written (here) above the three tweaks.

I get a terrible screeching, like a banshee, the cat is terrified.
System:
FBIde: 0.4.6
fbc: FreeBASIC Compiler - Version 1.05.0 (01-31-2016), built for win64 (64bit)
OS: Windows NT 6.2 (build 9200)

Tweaked code:

Code: Select all

#include "Windows.bi"
#Include Once "crt/string.bi"
#include "win/mmsystem.bi"
'         here
#define Wavemapper -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
      '                          here
      p = cast(QueueWAVEHDR ptr, @p1)
      '#print typeof(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
   
   '                                           here
   if waveOutOpen(@_hWaveOut, Wavemapper, @wfx, 0, 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
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Re: Streaming audio

Postby angros47 » Oct 07, 2016 22:50

Thanks, but, by doing that, you removed the callback control, so now it would not work any more.

A question: my original code would compile, if you replace all the "dword" with "unsigned integer"?
dodicat
Posts: 5757
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Streaming audio

Postby dodicat » Oct 07, 2016 23:05

Yes, uinteger does the job win 10, 64 bit.

#define WAVEMAPPER -1
instead of
WAVE_MAPPER, which is defined already somewhere.
Runs with no warnings or hiccups
DamageX
Posts: 115
Joined: Nov 21, 2009 8:42

Re: Streaming audio

Postby DamageX » Sep 16, 2017 21:24

CrisDEV wrote:Finaly I have discovered the simplest way to play a WAV music.

Yes! Playing WAV data from memory buffer is also similar. The only thing needed from includes is a single declaration. Why didn't anybody tell me it was this easy?

Code: Select all

' Windows PCM audio demo
' take care not to blow up your speaker

declare function sndPlaySound lib "winmm" alias "sndPlaySoundA" (byval as any ptr, byval as uinteger) as integer

dim as integer x
dim shared sndbuf(0 to &H40015) as short => _
{ &H4952,&H4646,&H0024,&H0008,&H4157,&H4556,&H6D66,&H2074, _
  &H0010,&H0000,&H0001,&H0001,&HAC44,&H0000,&H5888,&H0001, _
  &H0002,&H0010,&H6164,&H6174,&H0000,&H0008 }

for x=22 to &H40015
sndbuf(x)=((x and 127) shl ((x shr 12) and 15))
next x

x=sndPlaySound(@sndbuf(0),5)

print "playing..."
sleep 10000
MrSwiss
Posts: 3078
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Streaming audio

Postby MrSwiss » Sep 17, 2017 19:24

angros47 wrote:A question: my original code would compile, if you replace all the "dword" with "unsigned integer"?
No, I'd use ULong instead, because we are dealing with a "unsigned 32-bit integer", aka: C's UINT,
which in FB, is ULong (fixed data type = 32-bit) on all platforms: 32/64 bit's.

Alternative: UInteger<32> (but, to much typing for me!)
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Re: Streaming audio

Postby angros47 » Sep 18, 2017 8:18

MrSwiss wrote:No, I'd use ULong instead, because we are dealing with a "unsigned 32-bit integer", aka: C's UINT,
which in FB, is ULong (fixed data type = 32-bit) on all platforms: 32/64 bit's.


Have you tried on Windows 64 bit? Does it work? Because DWORD, too, is 32 bit... and it does not work (I have no windows 64, so I can't test it)
D.J.Peters
Posts: 7667
Joined: May 28, 2005 3:28

Re: Streaming audio

Postby D.J.Peters » Sep 18, 2017 10:01

angros47 it must be DWORD_PTR not DWORD !

Joshy

Code: Select all

#Include once "crt/string.bi"
#include once "Windows.bi"
#include once "win/mmsystem.bi"

#ifndef WAVE_MAPPER
 #define WAVE_MAPPER -1
#endif

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_PTR, _
                          p1 as DWORD_PTR, _
                          p2 as DWORD_PTR)
   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_PTR, @dsp_callback), _
                  cptr(DWORD_PTR, 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
angros47
Posts: 1444
Joined: Jun 21, 2005 19:04

Re: Streaming audio

Postby angros47 » Sep 18, 2017 10:18

Thank you!

Return to “Windows”

Who is online

Users browsing this forum: No registered users and 1 guest