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