waveIn functions
Post by Phineas Freak on Jan 16th, 2018, 07:47am
So, i have been trying to make a waveIn demo but considering the complexity of the code i surely failed to make it work:
Code:
' ----------------------------------------------------------------------------------------------------
' Setup the global variables.
hWndDevice = _NULL
result = _NULL
' ----------------------------------------------------------------------------------------------------
' Setup the structs.
struct WAVEHDR, _
lpData as long, _
dwBufferLength as ulong, _
dwBytesRecorded as ulong, _
dwUser as ulong, _
dwFlags as ulong, _
dwLoops as ulong, _
lpNext as long, _
reserved as ulong
struct WAVEFORMATEX, _
wFormatTag as word, _
nChannels as word, _
nSamplesPerSec as ulong, _
nAvgBytesPerSec as ulong, _
nBlockAlign as word, _
wBitsPerSample as word, _
cbSize as word
' ----------------------------------------------------------------------------------------------------
' Setup the basic recording parameters.
dwBitsPerSample = 8
dwChannels = 1
dwSamplesPerSec = 22050
dwTimePeriod = 1
' ----------------------------------------------------------------------------------------------------
' Calculate the rest of the recording parameters.
dwBufferLength = 2 * dwSamplesPerSec * dwTimePeriod
dwBlockAlign = (dwChannels * dwBitsPerSample) / 8
dwAvgBytesPerSec = (dwChannels * dwBitsPerSample * dwSamplesPerSec) / 8
' ----------------------------------------------------------------------------------------------------
' Create the buffer.
hMem = GlobalAlloc(_GMEM_ZEROINIT, dwBufferLength)
' ----------------------------------------------------------------------------------------------------
' Specify the recording parameters.
WAVEFORMATEX.wFormatTag.struct = _WAVE_FORMAT_PCM
WAVEFORMATEX.nChannels.struct = dwChannels
WAVEFORMATEX.nSamplesPerSec.struct = dwSamplesPerSec
WAVEFORMATEX.nAvgBytesPerSec.struct = dwAvgBytesPerSec
WAVEFORMATEX.nBlockAlign.struct = dwBlockAlign
WAVEFORMATEX.wBitsPerSample.struct = dwBitsPerSample
WAVEFORMATEX.cbSize.struct = _NULL
' ----------------------------------------------------------------------------------------------------
' Setup and prepare the input header.
WAVEHDR.lpData.struct = GlobalLock(hMem)
WAVEHDR.dwBufferLength.struct = dwBufferLength
WAVEHDR.dwBytesRecorded.struct = _NULL
WAVEHDR.dwUser.struct = _NULL
WAVEHDR.dwFlags.struct = _NULL
WAVEHDR.dwLoops.struct = _NULL
' ----------------------------------------------------------------------------------------------------
' Get the number of sound devices installed.
result = waveInGetNumDevs()
if (result = _NULL) then
null = MessageBoxEx(_NULL, "No waveform audio input devices found!", "Error", _MB_ICONERROR or _MB_OK, _NULL)
end
end if
' ----------------------------------------------------------------------------------------------------
' Open the sound device.
result = waveInOpen(hWndDevice, _WAVE_MAPPER, _NULL, _NULL, _CALLBACK_NULL or _WAVE_FORMAT_DIRECT)
if (result <> _MMSYSERR_NOERROR) then
null = MessageBoxEx(_NULL, "Failed to open the waveform audio input device!", "Error", _MB_ICONERROR or _MB_OK, _NULL)
end
end if
' ----------------------------------------------------------------------------------------------------
' Prepare the header.
result = waveInPrepareHeader(hWndDevice, len(WAVEHDR.struct))
if (result <> _MMSYSERR_NOERROR) then
null = MessageBoxEx(_NULL, "Failed to prepare a waveform audio header!", "Error", _MB_ICONERROR or _MB_OK, _NULL)
end
end if
' ----------------------------------------------------------------------------------------------------
' Insert the wave input buffer.
result = waveInAddBuffer(hWndDevice, len(WAVEHDR.struct))
if (result <> _MMSYSERR_NOERROR) then
null = MessageBoxEx(_NULL, "Failed to insert a waveform audio buffer!", "Error", _MB_ICONERROR or _MB_OK, _NULL)
end
end if
' ----------------------------------------------------------------------------------------------------
' Commence the input sampling.
result = waveInStart(hWndDevice)
if (result <> _MMSYSERR_NOERROR) then
null = MessageBoxEx(_NULL, "Failed to start the waveform audio device!", "Error", _MB_ICONERROR or _MB_OK, _NULL)
end
end if
' ----------------------------------------------------------------------------------------------------
' Wait until the buffer is full.
while ((WAVEHDR.dwFlags.struct and _WHDR_DONE) = _NULL)
' Recording is in progress.
print "Buffer Pointer..." ; WAVEHDR.lpData.struct
print "Bytes Recorded..." ; WAVEHDR.dwBytesRecorded.struct
print "Flags............" ; WAVEHDR.dwFlags.struct
print
print "Data............." ; winstring(WAVEHDR.lpData.struct)
print
' Minimize CPU usage.
null = Sleep(100)
wend
' ----------------------------------------------------------------------------------------------------
' Release the sound device.
null = GlobalFree(hMem)
null = waveInUnprepareHeader(hWndDevice, len(WAVEHDR.struct))
null = waveInClose(hWndDevice)
' ----------------------------------------------------------------------------------------------------
print "Done!"
end
As a starting point, i believe that the problematic code is the buffer initialization "routine" (memory allocation). But, i may have failed big time in something much more mundane...
Re: waveIn functions
Post by Phineas Freak on Jan 16th, 2018, 07:51am
And the required functions:
Code:
' ====================================================================================================
' Function GlobalAlloc()
' Allocates the specified number of bytes from the heap.
' ====================================================================================================
function GlobalAlloc(uFlags, dwBytes)
calldll #kernel32, "GlobalAlloc", _
uFlags as ulong, _
dwBytes as ulong, _
GlobalAlloc as handle
end function
' ====================================================================================================
' Function GlobalFree()
' Frees the specified global memory object and invalidates its handle.
' ====================================================================================================
function GlobalFree(hMem)
calldll #kernel32, "GlobalFree", _
hMem as handle, _
GlobalFree as handle
end function
' ====================================================================================================
' Function GlobalLock()
' Locks a global memory object and returns a pointer to the first byte of the object's memory block.
' ====================================================================================================
function GlobalLock(hMem)
calldll #kernel32, "GlobalLock", _
hMem as handle, _
GlobalLock as long
end function
' ====================================================================================================
' Function MessageBoxEx()
' Creates, displays, and operates a message box. The message box contains an
' application-defined message and title, plus any combination of predefined icons
' and push buttons. The buttons are in the language of the system user interface.
' ====================================================================================================
function MessageBoxEx(hWnd, lpText$, lpCaption$, uType, wLanguage)
calldll #user32, "MessageBoxExA", _
hWnd as handle, _
lpText$ as ptr, _
lpCaption$ as ptr, _
uType as ulong, _
wLanguage as word, _
MessageBoxEx as long
end function
' ====================================================================================================
' Function Sleep()
' Suspends the execution of the current thread until the time-out interval elapses.
' ====================================================================================================
function Sleep(dwMilliseconds)
calldll #kernel32, "Sleep", _
dwMilliseconds as ulong, _
_NULL as void
end function
' ====================================================================================================
' Function waveInAddBuffer()
' Sends an input buffer to the given waveform-audio input device. When the buffer is filled, the
' application is notified.
' ====================================================================================================
function waveInAddBuffer(hwi, cbwh)
calldll #winmm, "waveInPrepareHeader", _
hwi as handle, _
WAVEHDR as struct, _
cbwh as ulong, _
waveInAddBuffer as ulong
end function
' ====================================================================================================
' Function waveInClose()
' Closes the given waveform-audio input device.
' ====================================================================================================
function waveInClose(hwi)
calldll #winmm, "waveInClose", _
hwi as handle, _
waveInClose as ulong
end function
' ====================================================================================================
' Function waveInGetNumDevs()
' Returns the number of waveform-audio input devices present in the system.
' ====================================================================================================
function waveInGetNumDevs()
calldll #winmm, "waveInGetNumDevs", _
waveInGetNumDevs as ulong
end function
' ====================================================================================================
' Function waveInGetErrorText()
' Retrieves a textual description of the error identified by the given error number.
' ====================================================================================================
function waveInGetErrorText$(mmrError)
cchText = 256
pszText$ = space$(cchText)
calldll #winmm, "waveInGetErrorText", _
mmrError as ulong, _
pszText$ as ptr, _
cchText as ulong, _
waveInGetErrorText as ulong
if (waveInGetErrorText = _MMSYSERR_NOERROR) then waveInGetErrorText$ = trim$(pszText$)
end function
' ====================================================================================================
' Function waveInOpen()
' Opens the given waveform-audio input device for recording.
' ====================================================================================================
function waveInOpen(byref phwi, uDeviceID, dwCallback, dwCallbackInstance, fdwOpen)
struct WAVEIN, _
phwi$ as ptr
WAVEIN.phwi$.struct = space$(8)
calldll #winmm, "waveInOpen", _
WAVEIN as struct, _
uDeviceID as ulong, _
WAVEFORMATEX as struct, _
dwCallback as ulong, _
dwCallbackInstance as ulong, _
fdwOpen as ulong, _
waveInOpen as ulong
if (waveInOpen = _MMSYSERR_NOERROR) then phwi = WAVEIN.phwi$.struct else phwi = _NULL
end function
' ====================================================================================================
' Function waveInPrepareHeader()
' Prepares a buffer for waveform-audio input.
' ====================================================================================================
function waveInPrepareHeader(hwi, cbwh)
calldll #winmm, "waveInPrepareHeader", _
hwi as handle, _
WAVEHDR as struct, _
cbwh as ulong, _
waveInPrepareHeader as ulong
end function
' ====================================================================================================
' Function waveInReset()
' Stops input on the given waveform-audio input device and resets the current position to zero. All
' pending buffers are marked as done and returned to the application.
' ====================================================================================================
function waveInReset(hwi)
calldll #winmm, "waveInReset", _
hwi as handle, _
waveInReset as ulong
end function
' ====================================================================================================
' Function waveInStart()
' Starts input on the given waveform-audio input device.
' ====================================================================================================
function waveInStart(hwi)
calldll #winmm, "waveInStart", _
hwi as handle, _
waveInStart as ulong
end function
' ====================================================================================================
' Function waveInStop()
' Stops waveform-audio input.
' ====================================================================================================
function waveInStop(hwi)
calldll #winmm, "waveInStop", _
hwi as handle, _
waveInStop as ulong
end function
' ====================================================================================================
' Function waveInUnprepareHeader()
' Cleans up the preparation performed by the waveInPrepareHeader function. This function must be
' called after the device driver fills a buffer and returns it to the application. You must call this
' function before freeing the buffer.
' ====================================================================================================
function waveInUnprepareHeader(hwi, cbwh)
calldll #winmm, "waveInUnprepareHeader", _
hwi as handle, _
WAVEHDR as struct, _
cbwh as ulong, _
waveInUnprepareHeader as ulong
end function
Re: waveIn functions
Post by Richard Russell on Jan 16th, 2018, 08:15am
on Jan 16th, 2018, 07:47am, Phineas Freak wrote:So, i have been trying to make a waveIn demo but considering the complexity of the code i surely failed to make it work |
|
In case it helps, here again is the listing of my Audio Recorder program. This was originally written for LB, so contains code to fake an array of structures (which of course LBB supports natively).
Richard.
Code: nomainwin
global record.flag, record.buff, wavfile$
filedialog "Save WAV file", "*.wav", wavfile$
if wavfile$ = "" then end
button #w.start, "Start Recording", startrec, UL, 100, 100
button #w.stop, "Stop Recording", stoprec, UL, 100, 200
open "Audio recorder" for window as #w
#w "trapclose quit"
#w.stop "!disable"
call record.init
timer 50, record.poll
wait
sub quit handle$
timer 0
call record.exit
close #w
end
end sub
sub startrec handle$
#w.start "!disable"
#w.stop "!enable"
call record.start wavfile$
end sub
sub stoprec handle$
call record.stop
#w.stop "!disable"
#w.start "!enable"
end sub
sub record.init
' Initialise the wave input format:
struct waveFormatEx, _
wFormatTag as word, nChannels as word, nSamplesPerSec as ulong, _
nAvgBytesPerSec as ulong, nBlockAlign as word, _
wBitsPerSample as word, cbSize as word
waveFormatEx.wFormatTag.struct = _WAVE_FORMAT_PCM
waveFormatEx.nChannels.struct = 2
waveFormatEx.nSamplesPerSec.struct = 44100
waveFormatEx.wBitsPerSample.struct = 16
waveFormatEx.nBlockAlign.struct = waveFormatEx.nChannels.struct * waveFormatEx.wBitsPerSample.struct / 8
waveFormatEx.nAvgBytesPerSec.struct = waveFormatEx.nSamplesPerSec.struct * waveFormatEx.nBlockAlign.struct
' Create wave headers:
struct WAVEHDR, lpData as ulong, dwBufferLength as ulong, _
dwBytesRecorded as ulong, dwUser as ulong, dwFlags as ulong, _
dwLoops as ulong, lpNext as ulong, Reserved as ulong
' Fill in wave headers, allocate, prepare and add buffers:
BytesPerBuffer = 16384
struct WaveIn, hndl as ulong
calldll #winmm, "waveInOpen", WaveIn as struct, _WAVE_MAPPER as long, _
waveFormatEx as struct, 0 as long, 0 as long, _
0 as long, ret as long
if ret then notice "waveInOpen failed" : end
for buff = 0 TO 7
h = WaveIn.hndl.struct
l = len(WAVEHDR.struct)
' Kludge to fake array of structures:
calldll #kernel32, "GlobalAlloc", _GMEM_FIXED as long, _
l as ulong, header as ulong
calldll #kernel32, "GlobalAlloc", _GMEM_FIXED as long, _
BytesPerBuffer as ulong, buffer as ulong
Headers(buff) = header
WAVEHDR.lpData.struct = buffer
WAVEHDR.dwBufferLength.struct = BytesPerBuffer
WAVEHDR.dwFlags.struct = 0
calldll #kernel32, "RtlMoveMemory", header as ulong, _
WAVEHDR as struct, l as ulong, ret as long
calldll #winmm, "waveInPrepareHeader", h as ulong, _
header as ulong, l as ulong, ret as long
if ret then notice "waveInPrepareHeader failed" : end
calldll #winmm, "waveInAddBuffer", h as ulong, _
header as ulong, l as ulong, ret as long
if ret then notice "waveInAddBuffer failed" : end
next
record.buff = 0
calldll #winmm, "waveInStart", h as ulong, ret as long
if ret then notice, "waveInStart failed" : end
end sub
sub record.start filename$
open filename$ for output as #recordfile
format$ = waveFormatEx.struct
print #recordfile, "RIFF";
print #recordfile, d4$(0); ' Filled in later
print #recordfile, "WAVE";
print #recordfile, "fmt ";
print #recordfile, d4$(16);
print #recordfile, left$(format$,16);
print #recordfile, "data";
print #recordfile, d4$(0); ' Filled in later
seek #recordfile, 44
record.flag = 1
end sub
sub record.stop
record.flag = 0
size = lof(#recordfile)
seek #recordfile, 4
print #recordfile, d4$(size - 8);
seek #recordfile, 40
print #recordfile, d4$(size - 44);
seek #recordfile, size
close #recordfile
end sub
sub record.exit
h = WaveIn.hndl.struct
calldll #winmm, "waveInStop", h as ulong, r as long
calldll #winmm, "waveInReset", h as ulong, r as long
for i = 0 to 7
header = Headers(i)
WAVEHDR.struct = header
h = WaveIn.hndl.struct
l = len(WAVEHDR.struct)
p = WAVEHDR.lpData.struct
calldll #winmm, "waveInUnprepareHeader", h as ulong, _
header as ulong, l as ulong, r as long
calldll #kernel32, "GlobalFree", p as ulong, r as long
calldll #kernel32, "GlobalFree", header as ulong, r as long
next i
calldll #winmm, "waveInClose", h as ulong, r as long
end sub
sub record.poll
header = Headers(record.buff)
WAVEHDR.struct = header
if WAVEHDR.dwFlags.struct and _WHDR_DONE then
WAVEHDR.dwFlags.struct = WAVEHDR.dwFlags.struct and (-_WHDR_DONE-1)
if record.flag then
h = hwnd(#recordfile)
d = WAVEHDR.lpData.struct
l = WAVEHDR.dwBytesRecorded.struct
struct written, n as ulong
calldll #kernel32, "WriteFile", h as ulong, d as ulong, _
l as ulong, written as struct, 0 as ulong, r as long
end if
h = WaveIn.hndl.struct
l = len(WAVEHDR.struct)
calldll #winmm, "waveInAddBuffer", h as ulong, header as ulong, _
l as ulong, r as long
record.buff = (record.buff + 1) mod 8
end if
end sub
function d4$(n)
a = n mod 256
n = int(n/256)
b = n mod 256
n = int(n/256)
c = n mod 256
n = int(n/256)
d = n mod 256
d4$ = chr$(a)+chr$(b)+chr$(c)+chr$(d)
end function