Page 1 of 2
Wave Function CALLBACK HandleEvent
Posted: Wed Aug 13, 2008 6:05 pm
by oknbs
Dear Harbour User
I want to make a simple Voice Recoder by using WaveInOpen and WaveOutOpen Function.
I set CALLBACK to WINDOW (the Function is as follows) and I tried to receive MM_WIN_OPEN, MM_WIN_DATA of HandleEvent.
But I don't know what to set the Class Name of CreateWindow.
I really need your help.
Or Are there any Voice Recoder Sample File made by Harbour?
Code: Select all
#define MM_WIM_OPEN 958 /* waveform input */
#define MM_WIM_CLOSE 959
#define MM_WIM_DATA 960
CLASS TWave FROM TControl
DATA hWaveIn
METHOD New() CONSTRUCTOR
METHOD WaveInStart( oWnd )
...
METHOD HandleEvent( nMsg, nWParam, nLParam )
...
ENDCLASS
METHOE New() CLASS TWave
::Create( "????" ) => ? Class Name
//
Return Self
METHOD WaveInStart( oWnd ) CLASS TWave
LOCAL hWaveIn
if WaveInOpen( &hWaveIn, oWnd:hWnd ) >= 0
::hWaveIn := hWaveIn
//
endif
Return NIL
METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TWave
do case
case nMsg == MM_WIN_OPEN
//
case nMsg == MM_WIN_DATA
//
otherwise
//
endcase
Return NIL
HB_FUNC( WAVEINOPEN )
{
HWAVEIN hWaveIn;
WAVEFORMATEX waveformat;
int nResult;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = 1 ;
waveformat.nSamplesPerSec = 11025;
waveformat.wBitsPerSample = 8;
waveformat.nBlockAlign = waveformat.nChannels*waveformat.wBitsPerSample/8;
waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec*waveformat.nBlockAlign;
waveformat.cbSize = 0;
nResult = WaveInOpen( &hWaveIn, WAVE_MAPPER, (WAVEFORMATEX)&waveformat, (DWORD) hb_parnl(2), 0, CALLBACK_WINDOW );
hb_stornl( ( LONG ) hWaveIn, 1 );
hb_retni( nResult );
}
Posted: Wed Aug 13, 2008 8:19 pm
by Antonio Linares
There is no need to provide a classname for it when calling ::Create()
FiveWin will automatically provide "TWave"
Just call ::Create()
Posted: Thu Aug 14, 2008 1:16 am
by oknbs
Thank you for your answer.
::Create() => Cannot create window or control Error!
Code: Select all
METHOD New( oWnd ) CLASS TWave
DEFAULT oWnd := GetWndDefault()
::nId = ::GetNewId()
::oWnd = oWnd
::nStyle = nOR( WS_CHILD, WS_VISIBLE )
::Register()
if !Empty( oWnd:hWnd )
::Create()
oWnd:AddControl( Self )
else
oWnd:DefControl( Self )
endif
::aBuffer[1] := HB_WaveInitBuffer()
::aBuffer[2] := HB_WaveInitBuffer()
RETURN Self
oknbs.
Posted: Thu Aug 14, 2008 7:25 am
by Antonio Linares
Oknbs,
Maybe "TWave" is an already used class in Windows. Then please try it this way:
::Create( "TMyWave" )
Posted: Thu Aug 14, 2008 7:27 am
by Antonio Linares
BTW, you are missing this important code in your class header:
CLASSDATA lRegistered AS LOGICAL
that code is a must for user defined control classes.
Posted: Thu Aug 14, 2008 9:41 am
by oknbs
Thank you for your answer Antonio.
I added "CLASSDATA lRegistered AS LOGICAL" and the problem go away.
Tahnk you.
oknbs.
Posted: Mon Aug 18, 2008 3:02 am
by oknbs
Dear Antonio.
There wasn't any error after I add the "CLASSDATA lRegistered AS LOGICAL" Code.
But the HandleEvent did not run.
Attached is my source code.
Code: Select all
#include "Fivewin.ch"
#define MM_WOM_OPEN 955 /* waveform output */
#define MM_WOM_CLOSE 956
#define MM_WOM_DONE 957
#define MM_WIM_OPEN 958 /* waveform input */
#define MM_WIM_CLOSE 959
#define MM_WIM_DATA 960
STATIC oWave
Function Main()
LOCAL oWnd
DEFINE WINDOW oWnd FROM 3, 6 TO 20, 70 ;
TITLE "Voice Recoder Test"
SetKey( VK_F2, { || StartWave( oWnd ), RecordWave( oWnd ) } )
ACTIVATE WINDOW oWnd ;
VALID App_Exit()
Return NIL
//---------------------------------------------------------------------------//
Function StartWave( oWnd )
oWave := TSipWave():New( oWnd )
Return NIL
//---------------------------------------------------------------------------//
Function RecordWave( oWnd )
oWave:WaveInStart( oWnd )
Return NIL
//---------------------------------------------------------------------------//
Function App_Exit()
LOCAL lResult := .F.
if MsgYesNo( "Are you sure?", "Do you want to exit?" )
lResult := .T.
if oWave != NIL
oWave:WaveInStop()
oWave:WaveInClose()
oWave:End()
endif
endif
Return lResult
//---------------------------------------------------------------------------//
CLASS TSipWave FROM TControl
DATA hWaveIn
DATA hWaveOut
DATA aBuffer AS ARRAY INIT Array(2)
DATA aWaveHdr AS ARRAY INIT Array(2)
CLASSDATA lRegistered AS LOGICAL
METHOD New( oWnd ) CONSTRUCTOR
METHOD WaveInStart( oWnd )
METHOD WaveInStop() INLINE HB_WaveInStop( ::hWaveIn )
METHOD WaveInClose() INLINE HB_WaveInClose( ::hWaveIn )
METHOD End() INLINE ::Destory()
METHOD Destory()
METHOD HandleEvent( nMsg, nWParam, nLParam )
ENDCLASS
//---------------------------------------------------------------------------//
METHOD New( oWnd ) CLASS TSipWave
DEFAULT oWnd := GetWndDefault()
::nId = ::GetNewId()
::oWnd = oWnd
::nStyle = nOR( WS_CHILD, WS_VISIBLE )
::Register()
if !Empty( oWnd:hWnd )
::Create()
oWnd:AddControl( Self )
else
oWnd:DefControl( Self )
endif
::aBuffer[1] := HB_WaveInitBuffer()
::aBuffer[2] := HB_WaveInitBuffer()
RETURN Self
//---------------------------------------------------------------------------//
METHOD WaveInStart( oWnd ) CLASS TSipWave
LOCAL hWaveIn
if HB_WaveInOpen( @hWaveIn, oWnd:hWnd ) >= 0
::hWaveIn := hWaveIn
::aWaveHdr[1] := HB_InitWaveHdr( ::aBuffer[1] )
::aWaveHdr[2] := HB_InitWavehdr( ::aBuffer[2] )
if HB_WaveInPrepareHeader( ::hWaveIn, ::aWaveHdr[1] ) < 0
MsgAlert( "WaveInPrepareHeader Error" )
endif
if HB_WaveInPrepareHeader( ::hWaveIn, ::aWaveHdr[2] ) < 0
MsgAlert( "WaveInPrepareHeader Error" )
endif
if HB_WaveInAddBuffer( ::hWaveIn, ::aWaveHdr[1] ) < 0
MsgAlert( "WaveInAddBuffer Error" )
endif
if HB_WaveInAddBuffer( ::hWaveIn, ::aWaveHdr[2] ) < 0
MsgAlert( "WaveInAddBuffer Error" )
endif
if HB_WaveInStart( ::hWaveIn ) >= 0
// To do
endif
endif
Return NIL
//---------------------------------------------------------------------------//
METHOD Destory() CLASS TSipWave
HB_WaveFreeBuffer( ::aBuffer[1] )
HB_WaveFreeBuffer( ::aBuffer[2] )
Return NIL
//---------------------------------------------------------------------------//
METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TSipWave
do case
case nMsg == MM_WIM_OPEN
Msginfo( "MM_WIM_OPEN" )
case nMsg == MM_WIM_DATA
MsgInfo( "MM_WIM_DATA" )
case nMsg == MM_WIM_CLOSE
MsgInfo( "MM_WIM_CLOSE" )
endcase
Return Super:HandleEvent( nMsg, nWParam, nLParam )
//---------------------------------------------------------------------------//
#pragma BEGINDUMP
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbdefs.h"
#include <windows.h>
#include <mmsystem.h>
#define BUFFER_SIZE 5000
HB_FUNC( HB_WAVEINITBUFFER )
{
PBYTE pBuffer;
pBuffer = hb_xgrab( BUFFER_SIZE );
hb_retptr( pBuffer );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEFREEBUFFER ) // BYTE pBuffer
{
hb_xfree( hb_parptr( 1 ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_INITWAVEHDR ) // BYTE pBuffer
{
PWAVEHDR pWavehdr;
pWavehdr = hb_xgrab( sizeof( WAVEHDR ) );
pWavehdr->lpData = (LPSTR) hb_parptr(1);
pWavehdr->dwBufferLength = BUFFER_SIZE;
pWavehdr->dwUser = 0;
pWavehdr->dwFlags = 0;
hb_retptr( pWavehdr );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINOPEN ) // hWaveIn, pWavehdr, hWnd
{
HWAVEIN hWaveIn ;
WAVEFORMATEX waveformat;
int nResult;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = 1;
waveformat.nBlockAlign = 1;
waveformat.wBitsPerSample = 8;
waveformat.nSamplesPerSec = 11025;
waveformat.nAvgBytesPerSec = 11025;
waveformat.cbSize = 0;
nResult = waveInOpen( &hWaveIn, WAVE_MAPPER, (LPWAVEFORMATEX)&waveformat, (DWORD)hb_parnl(2), 0, CALLBACK_WINDOW );
hb_stornl( (LONG)hWaveIn, 1 );
hb_retni( nResult );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINPREPAREHEADER ) // hWaveIn, pWavehdr
{
hb_retni( waveInPrepareHeader( (HWAVEIN) hb_parnl(1), hb_parptr(2), sizeof( WAVEHDR ) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINUNPREPAREHEADER ) // hWaveIn, pWavehdr
{
hb_retni( waveInUnprepareHeader( (HWAVEIN) hb_parnl(1), hb_parptr(2), sizeof( WAVEHDR ) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINADDBUFFER ) // hWaveIn, pWavehdr
{
hb_retni( waveInAddBuffer( (HWAVEIN) hb_parnl(1), hb_parptr(2), sizeof( WAVEHDR ) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINSTART ) // hWaveIn
{
hb_retni( waveInStart( (HWAVEIN) hb_parnl(1) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINRESET ) // hWaveIn
{
hb_retni( waveInReset( (HWAVEIN) hb_parnl(1) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINSTOP ) // hWaveIn
{
hb_retni( waveInStop( (HWAVEIN) hb_parnl(1) ) );
}
//---------------------------------------------------------------------------//
HB_FUNC( HB_WAVEINCLOSE ) // hWaveIn
{
hb_retni( waveInClose( (HWAVEIN) hb_parnl(1) ) );
}
//---------------------------------------------------------------------------//
#pragma ENDDUMP
oknbs.
Posted: Mon Aug 18, 2008 8:24 am
by Patrick Mast
Antonio Linares wrote:BTW, you are missing this important code in your class header:
CLASSDATA lRegistered AS LOGICAL
that code is a must for user defined control classes.
[Learning mode]
What is "CLASSDATA lRegistered AS LOGICAL" doing for the class? Why exactly is it needed?
[/Learning mode]
Patrick
Posted: Mon Aug 18, 2008 9:23 am
by Carles
Patrick,
> CLASSDATA lRegistered AS LOGICAL
It is needed for new control Classes that are not Windows estandard. Windows API requires to "register" a control class name. It has to be registered only once. That DATA controls that. Estandard Window classes are already "registered" by Windows itself.
C.
Posted: Mon Aug 18, 2008 9:29 am
by Patrick Mast
Carles wrote:> CLASSDATA lRegistered AS LOGICAL
It is needed for new control Classes that are not Windows estandard. Windows API requires to "register" a control class name. It has to be registered only once. That DATA controls that. Estandard Window classes are already "registered" by Windows itself.
C.
Ok, thanks. Now, WHY does Windows API requires a class to be "registered". If we don't do it, what's going to happen?
Patrick
Posted: Mon Aug 18, 2008 10:08 am
by Antonio Linares
Patrick,
It will not be "found".
Is similar as when we do CLASS TTest() ... ENDCLASS in Harbour. If we don't do that and we call TTest() then an object TTest is not created
Posted: Mon Aug 18, 2008 10:12 am
by Antonio Linares
Oknbs,
Please place some traces using MsgBeep(), MsgInfo() and LogFile() to check in which parts of your code the execution is going trough.
You can also use OutputDebugString() to check traces on an external dbwin32 utility
Posted: Mon Aug 18, 2008 10:15 am
by Otto
Hello Antonio,
> You can also use OutputDebugString() to check traces on an external dbwin utility
Could you please explain how to use an external dbwin utility and which one.
Thanks in advance
Otto
Posted: Mon Aug 18, 2008 10:41 am
by Carles
Otto,
Code: Select all
#include 'fivewin.ch'
FUNCTION Main()
Dbg( Time() )
MsgInfo( 'Output to DBWin32.exe' )
RETU nil
FUNCTION Dbg( xVal, cTitle )
DEFAULT cTitle := 'FWH Debug'
OutputDebugString( cTitle + ' => ' + cValToChar( xVal ) )
RETURN NIL
DLL32 FUNCTION OutputDebugString( cOutStr AS LPSTR ) As VOID PASCAL ;
FROM "OutputDebugStringA" lib "kernel32.dll"
*#pragma BEGINDUMP
*
*#include <windows.h>
*#include "hbapi.h"
*
*HB_FUNC( OUTPUTDEBUGSTRINGC )
*{
* OutPutDebugStringA( hb_parc( 1 ) );
*}
*
*#pragma ENDDUMP
*
*FUNCTION OutPutDebugString( xVal )
*
* OutPutDebugStringC( cValToChar( xVal ))
*
*RETURN NIL
You need execute also DBwin32.exe
C.
Posted: Mon Aug 18, 2008 10:55 am
by Antonio Linares