Page 1 of 5

Capturing Audio [COMPLETE SOURCE]

Posted: Fri Jul 25, 2003 9:56 am
by Flype
Here is my program that shows how to capture audio under windows without using MCI functions. Raw sound is saved in a file... which can be loaded and listened thanx a software like SoundForge.

Raw format sound generated : 16bit, Mono, 44100Hz

You have to configure the Volume Control (use the volume systray icon) in order to select Stereo Mixer (Menu->Properties->Record...). You should also set the volume not too high...

Have fun :wink:

Code: Select all

i removed it, see the correct source below

Posted: Fri Jul 25, 2003 10:26 am
by Tranquil
WOW! Very, very nice work!! Thanks for sharing this source!!!!

Respect!

Mike

Posted: Fri Jul 25, 2003 10:45 am
by gnozal
Je dirais même plus : excellent :D

Posted: Fri Jul 25, 2003 11:04 am
by Flype
merci merci 8)

thanx, i'll hope somebody will increase the functionnality of this little proggy ! and especially shared it :wink:

there's much of things to do like, in a first part, listing the available devices in order to let the user choose...
It would be, also, nice to let the user select Mono/Stereo - 8/16bits - Frequency...

I'm interesting to know if it doesn't work on your configuration, especially win98/Me :roll: ...

I've tested it on win2000 / winXP and there's no problem.

I know that sometimes when resizing the window, it freezes, Silly...

Posted: Fri Jul 25, 2003 11:59 am
by Denis
:wink:


Denis

Posted: Fri Jul 25, 2003 2:57 pm
by Tranquil
Works fine on Windows 2000 Prof and Server.

Posted: Sat Jul 26, 2003 3:41 am
by kns
This is my personal bias....

The code presented appears beautifully structured and readable. It's been my experience (C in this case) that it's easier to follow the logic when long stretches are broken into discrete functions. On a personal level I would have an easier time learning from more such examples. [I know that there an any number of retorts that can be hurled my way, hence couching the observation as a personal preference.]

Thanks for the example!

KNS

Posted: Sun Jul 27, 2003 3:56 am
by Flype
kns, thanx for your observation : Structuring source code is VERY important i think even if it's at a cost of more lines ! This way, we can read it easier and as a consequence make the project grows faster...
I know that sometimes when resizing the window, it freezes, Silly...
So, i would like to post a correction of my recorder. It now use a SetTimer_() for displaying wave and there's no more freezes. Also, i improved some things, try and you'll see :wink:

Code: Select all

;***********************************************************************************
;- DECLARATIONS                                ; SOUND CAPTURE, Flype (26-juil-2002)
;***********************************************************************************


Declare CAPTURE_Read( hWaveIn.l, lpWaveHdr.l )
Declare CAPTURE_Error( err.l )
Declare CAPTURE_Start()
Declare CAPTURE_Stop()
Declare CAPTURE_Draw()
Declare CAPTURE_Now()

Declare GUI_CallBack( hWnd.l, Message.l, wParam.l, lParam.l )
Declare GUI_Button( id.l, ico.l, tip.s )
Declare GUI_Init()
Declare GUI_Main()
Declare GUI_Resize()

Declare FILE_Recording( state.b )
Declare FILE_Create()
Declare FILE_Append()
Declare FILE_Close()


;***********************************************************************************
;- INIT CONFIGURABLE CONSTANTES
;***********************************************************************************


#SOUND_NCHANNELS   = 1      ; This example only support Mono
#SOUND_NBITS       = 16     ; This example only support 16bits
#SOUND_NHERTZ      = 44100  ; Try 8000, 11050, 22100, 44100...

#BUFFER_NUM        = 8      ; Number of buffer for capture
#BUFFER_SIZE       = 512    ; Size of each buffer, should be x2 in Stereo
#BUFFER_TICK       = 10     ; Wave redraw delay : SetTimer_ in CAPTURE_Start()


;***********************************************************************************
;- INIT CONSTANTES
;***********************************************************************************


#BYTE = 1
#WORD = 2

#gadRecord   =  0
#gadStop     =  1
#gadMode     =  2

#StatusBar   =  0
#StatusTime  =  0
#StatusInfo  =  1
#StatusFile  =  2

#COLOR_RECBACK  = $000050
#COLOR_RECLINE  = $000035
#COLOR_RECWAVE  = $1010E0
#COLOR_CAPBACK  = $004900
#COLOR_CAPLINE  = $004000
#COLOR_CAPWAVE  = $20E020
#COLOR_VOLUME   = $00FFFF

#STR_ERROR      = "Error"
#STR_STOP       = "Stop"
#STR_RECORD     = "Record"
#STR_CLOSED     = "File saved"
#STR_SAVEREQ    = "Choose a file..."
#STR_MODE       = "Display mode"
#STR_RECORDED   = " bytes recorded"
#STR_PBFILE     = "Problem while creating file"
#STR_NODEVICE   = "Audio device not found"


;***********************************************************************************
;- INIT STRUCTURES
;***********************************************************************************


Structure RECORD_INFO
  x.l          ; Left
  y.l          ; Top
  w.l          ; Width
  h.l          ; Height
  m.l          ; YMiddle
  cback.l      ; Back color
  cline.l      ; Line color
  cwave.l      ; Wave color
  size.l       ; Wave buffer size
  buffer.l     ; Wave buffer pointer
  output.l     ; WindowOutput()
  mode.b       ; Wave mode (line or plain)
  wave.l       ; Address of waveform-audio input device
  frame.b      ; Counter for back clearing
  update.b     ; If true Wave have to be redrawn
  recorded.l   ; Number of bytes recorded
  recording.b  ; Record is running...
  time.s       ; Store the time string
EndStructure

Structure WAVEFORMATEX
  wFormatTag.w
  nChannels.w
  nSamplesPerSec.l
  nAvgBytesPerSec.l
  nBlockAlign.w
  wBitsPerSample.w
  cbSize.w
EndStructure

Dim inHdr.WAVEHDR( #BUFFER_NUM )
Global inHdr, rec.RECORD_INFO, now.SYSTEMTIME
rec\time = Space(9)


;***********************************************************************************
;- PROCS CAPTURE
;***********************************************************************************


Procedure CAPTURE_Error( err.l )
  If err
    text.s = Space( #MAXERRORLENGTH )
    waveInGetErrorText_( err, text, #MAXERRORLENGTH )
    MessageRequester( #STR_ERROR, text, #MB_ICONERROR )
    CAPTURE_Stop()
    End
  EndIf
EndProcedure

;==============================================================================

Procedure CAPTURE_Now()
  GetLocalTime_( @now )
  GetTimeFormat_(0, 0, @now, "HH:mm:ss:", @rec\time, 9 )
  StatusBarText( #StatusBar, #StatusTime, rec\time+Str(now\wMilliseconds) )
EndProcedure

;==============================================================================

Procedure CAPTURE_Draw()
  If rec\update = #TRUE
    CAPTURE_Now()
    StartDrawing( rec\output )
      ; Draw Background...
      If rec\frame = 2
        Box( rec\x, rec\y, rec\w, rec\h, rec\cback )
        shift = rec\h >> 2
        Line( rec\x, rec\m - shift, rec\w, 0, rec\cline )
        Line( rec\x, rec\m + shift, rec\w, 0, rec\cline )
        rec\frame = 0
      Else
        rec\frame + 1
      EndIf
      ; Draw Wave Data
      oldx = rec\x : oldy = 0
      For i=0 To rec\size Step #WORD
        value = PeekW( rec\buffer + i )
        x = rec\x + ( i * rec\w-1 ) / rec\size
        y = ( value * rec\h ) / $FFFF
        If value > max : max = value : EndIf
        If x <> oldx
          Select rec\mode
            Case #TRUE  : LineXY(oldx,rec\m+oldy,x,rec\m+y,rec\cwave)
            Case #FALSE : LineXY(oldx,rec\m+oldy,x,rec\m-y,rec\cwave)
          EndSelect
          oldx=x : oldy=y
        EndIf
      Next
      ; Draw Volume
      Box(rec\x+1,rec\h+rec\y-5,(max*(rec\w-2))/$7FFF,2,#COLOR_VOLUME)
    StopDrawing()
    rec\update = #FALSE
  EndIf
EndProcedure

;==============================================================================

Procedure.s CAPTURE_GetDevice()
  Caps.WAVEINCAPS
  For i=0 To waveInGetNumDevs_()-1
    CAPTURE_ERROR( waveInGetDevCaps_( i, @Caps, SizeOf( WAVEINCAPS ) ) )
    If Caps\dwFormats & #WAVE_FORMAT_1S08
      ProcedureReturn PeekS( @Caps\szPname, 32 )
    EndIf
  Next
  ProcedureReturn #STR_NODEVICE
EndProcedure

;==============================================================================

Procedure CAPTURE_Start()
  DeviceName.s = CAPTURE_GetDevice()
  If DeviceName
    SetWindowText_( WindowID(), DeviceName )
    format.WAVEFORMATEX
    format\wFormatTag      = 1
    format\nChannels       = #SOUND_NCHANNELS
    format\wBitsPerSample  = #SOUND_NBITS
    format\nSamplesPerSec  = #SOUND_NHERTZ
    format\nBlockAlign     = #SOUND_NCHANNELS * (#SOUND_NBITS/8)
    format\nAvgBytesPerSec = #SOUND_NHERTZ * format\nBlockAlign
    format\cbSize          = 0
    CAPTURE_Error( waveInOpen_( @rec\wave, #WAVE_MAPPER, @format, WindowID(), #NULL, #CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT ) )
    For i = 0 To #BUFFER_NUM - 1
      inHdr(i)\lpData         = AllocateMemory( i, #BUFFER_SIZE )
      inHdr(i)\dwBufferLength = #BUFFER_SIZE
      CAPTURE_Error( waveInPrepareHeader_( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
      CAPTURE_Error( waveInAddBuffer_    ( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
    Next
    CAPTURE_Error( waveInStart_( rec\wave ) )
    SetTimer_( WindowID(), 0, #BUFFER_TICK, 0 )
  EndIf
EndProcedure

;==============================================================================

Procedure CAPTURE_Stop()
  If rec\wave
    CAPTURE_Error( waveInReset_( rec\wave ) )
    CAPTURE_Error( waveInStop_ ( rec\wave ) )
    For i = 0 To #BUFFER_NUM - 1
      CAPTURE_Error( waveInUnprepareHeader_( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
    Next
    CAPTURE_Error( waveInClose_( rec\wave ) )
  EndIf
  KillTimer_( WindowID(), 0 )
EndProcedure

;==============================================================================

Procedure CAPTURE_Read( hWaveIn.l, lpWaveHdr.l )
  CAPTURE_Error( waveInAddBuffer_( hWaveIn, lpWaveHdr, SizeOf( WAVEHDR ) ) )
  rec\buffer  = PeekL( lpWaveHdr )
  rec\size    = PeekL( lpWaveHdr + 8 )
  rec\update  = #TRUE
  FILE_Append()
EndProcedure


;***********************************************************************************
;- PROCS FILE
;***********************************************************************************


Procedure FILE_Create()
  File.s = SaveFileRequester( #STR_SAVEREQ, "C:\test.raw", "Son brut|(*.raw)", 0 )
  If File
    If CreateFile( 0, File )
      FILE_Recording( #True )
      StatusBarText( #StatusBar, #StatusFile, File )
    Else
      MessageRequester( #STR_ERROR, #STR_PBFILE, #MB_ICONERROR )
    EndIf
  EndIf
EndProcedure

;==============================================================================

Procedure FILE_Append()
  If rec\recording = #True
    rec\recorded + rec\size
    WriteData( rec\buffer, rec\size )
    StatusBarText( #StatusBar, #StatusInfo, Str(rec\recorded) + #STR_RECORDED )
  EndIf
EndProcedure

;==============================================================================

Procedure FILE_Recording( state.b )
  If state = #TRUE
    rec\cback = #COLOR_RECBACK
    rec\cline = #COLOR_RECLINE
    rec\cwave = #COLOR_RECWAVE
  Else
    rec\cback = #COLOR_CAPBACK
    rec\cline = #COLOR_CAPLINE
    rec\cwave = #COLOR_CAPWAVE
  EndIf
  DisableToolBarButton( #gadRecord, state )
  DisableToolBarButton( #gadStop, #TRUE-state )
  rec\recording = state
  rec\recorded = 0
EndProcedure

;==============================================================================

Procedure FILE_Close()
  If rec\recording = #TRUE
    FILE_Recording( #FALSE )
    CloseFile(0)
    StatusBarText( #StatusBar, #StatusFile, #STR_CLOSED )
  EndIf
EndProcedure


;***********************************************************************************
;- PROCS GUI
;***********************************************************************************


Procedure GUI_Button( id.l, ico.l, tip.s )
  ToolBarStandardButton( id, ico )
  ToolBarToolTip( id, tip )
EndProcedure

;==============================================================================

Procedure GUI_Init()
  hFlags.l = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
  If OpenWindow( 0, 0,0,320,160, hFlags, "" ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  If CreateToolBar( 0, WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  If CreateGadgetList( WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  Frame3DGadget( 0, 0,0,0,0, "", #PB_Frame3D_Double )
  If CreateStatusBar( #StatusBar, WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  rec\output = WindowOutput()
  GUI_Button( #gadRecord, #PB_ToolBarIcon_Save,       #STR_RECORD )
  GUI_Button( #gadStop,   #PB_ToolBarIcon_Delete,     #STR_STOP   )
  GUI_Button( #gadMode,   #PB_ToolBarIcon_Properties, #STR_MODE   )
  AddStatusBarField(   80 )
  AddStatusBarField(  150 )
  AddStatusBarField( $FFF )
  ProcedureReturn #TRUE
EndProcedure

;==============================================================================

Procedure GUI_Resize()
  rec\x = 2
  rec\y = 30
  rec\w = WindowWidth()-4
  rec\h = WindowHeight()-52
  rec\m = rec\y + rec\h / 2
  UpdateStatusBar( #StatusBar )
  ResizeGadget( 0, rec\x-2, rec\y-2, rec\w+4, rec\h+4 )
EndProcedure

;==============================================================================

Procedure GUI_CallBack( hWnd.l, uMsg.l, wParam.l, lParam.l )
  Result.l = #PB_ProcessPureBasicEvents 
  Select uMsg
    Case #MM_WIM_DATA : CAPTURE_Read( wParam, lParam )
    Case #WM_TIMER    : CAPTURE_Draw()
    Case #WM_SIZE     : GUI_Resize()
    Case #WM_CLOSE    : Quit = #TRUE
    Case #WM_COMMAND
      Select wParam
        Case #gadRecord : FILE_Create()
        Case #gadStop   : FILE_Close()
        Case #gadMode   : rec\mode = #TRUE-rec\mode
      EndSelect
  EndSelect
  ProcedureReturn Result 
EndProcedure

;==============================================================================

Procedure GUI_Main()
  If GUI_Init()
    SetWindowCallback( @GUI_CallBack() )
    FILE_Recording( #FALSE )  
    GUI_Resize()
    CAPTURE_Start()
    While WaitWindowEvent()<>#WM_CLOSE : Wend
    CAPTURE_Stop()
  EndIf
EndProcedure


;***********************************************************************************
;- START
;***********************************************************************************


GUI_Main()
End

Posted: Sun Jul 27, 2003 9:34 am
by midebor
Code doesn't compile : MMSYSTEM010 - a non valid indicator has been transmitted to system fonction.
Debugger variable list shows only: inHdr 0 long
No other variables.
OS is win98.

Posted: Sun Jul 27, 2003 11:45 am
by Psychophanta
Hi Flype.
It is a good idea your program, but here doesn't work. When i run it windows stops all sound, and when i make windows to expose some sound, your program can't run.

Windows 2000


AL

so

Posted: Sun Jul 27, 2003 3:02 pm
by DominiqueB
It works great for me.
i'm under XP pro sp1.

Dominique.

Posted: Sun Jul 27, 2003 3:33 pm
by Flype
bad, not cool :cry: I'v not win98 to test it... I'd take care of using only win98 compliant api functions : "winmm". Perhaps an error appear when the system can't find an audiocard... try this to see : comment lines

Code: Select all

Procedure CAPTURE_Start()
;  DeviceName.s = CAPTURE_GetDevice()
;  If DeviceName
;    SetWindowText_( WindowID(), DeviceName )
.
.
.
;  EndIf

note frequency

Posted: Mon Aug 02, 2004 3:24 am
by chio
How could I didplay the Hz of the note played? I have my guitar connected and would love to see the note I am playing being recognized.

Thanks

Posted: Mon Aug 02, 2004 12:55 pm
by aaron
You would have to convert the waveform to frequency on the fly. A fast fourier transform (FFT) will do the trick. A quick search on google turns up tons of info on it.... you'll likely end up converting source from C or using a DLL.

This page looks like a good place to start:
http://www.fullspectrum.com/deeth/programming/fft.html

Posted: Wed May 18, 2005 1:51 am
by Hroudtwolf

Code: Select all

;Corrected for current version of PB (3.93) (Hroudtwolf)

;***********************************************************************************
;- DECLARATIONS                                ; SOUND CAPTURE, Flype (26-juil-2002)
;***********************************************************************************


Declare CAPTURE_Read( hWaveIn.l, lpWaveHdr.l )
Declare CAPTURE_Error( err.l )
Declare CAPTURE_Start()
Declare CAPTURE_Stop()
Declare CAPTURE_Draw()
Declare CAPTURE_Now()

Declare GUI_CallBack( hWnd.l, Message.l, wParam.l, lParam.l )
Declare GUI_Button( id.l, ico.l, tip.s )
Declare GUI_Init()
Declare GUI_Main()
Declare GUI_Resize()

Declare FILE_Recording( state.b )
Declare FILE_Create()
Declare FILE_Append()
Declare FILE_Close()


;***********************************************************************************
;- INIT CONFIGURABLE CONSTANTES
;***********************************************************************************


#SOUND_NCHANNELS   = 1      ; This example only support Mono
#SOUND_NBITS       = 16     ; This example only support 16bits
#SOUND_NHERTZ      = 44100  ; Try 8000, 11050, 22100, 44100...

#BUFFER_NUM        = 8      ; Number of buffer for capture
#BUFFER_SIZE       = 512    ; Size of each buffer, should be x2 in Stereo
#BUFFER_TICK       = 10     ; Wave redraw delay : SetTimer_ in CAPTURE_Start()


;***********************************************************************************
;- INIT CONSTANTES
;***********************************************************************************



#gadRecord   =  0
#gadStop     =  1
#gadMode     =  2

#StatusBar   =  0
#StatusTime  =  0
#StatusInfo  =  1
#StatusFile  =  2

#COLOR_RECBACK  = $000050
#COLOR_RECLINE  = $000035
#COLOR_RECWAVE  = $1010E0
#COLOR_CAPBACK  = $004900
#COLOR_CAPLINE  = $004000
#COLOR_CAPWAVE  = $20E020
#COLOR_VOLUME   = $00FFFF

#STR_ERROR      = "Error"
#STR_STOP       = "Stop"
#STR_RECORD     = "Record"
#STR_CLOSED     = "File saved"
#STR_SAVEREQ    = "Choose a file..."
#STR_MODE       = "Display mode"
#STR_RECORDED   = " bytes recorded"
#STR_PBFILE     = "Problem while creating file"
#STR_NODEVICE   = "Audio device not found"


;***********************************************************************************
;- INIT STRUCTURES
;***********************************************************************************


Structure RECORD_INFO
  x.l          ; Left
  y.l          ; Top
  w.l          ; Width
  h.l          ; Height
  m.l          ; YMiddle
  cback.l      ; Back color
  cline.l      ; Line color
  cwave.l      ; Wave color
  size.l       ; Wave buffer size
  buffer.l     ; Wave buffer pointer
  output.l     ; WindowOutput()
  mode.b       ; Wave mode (line or plain)
  wave.l       ; Address of waveform-audio input device
  frame.b      ; Counter for back clearing
  update.b     ; If true Wave have to be redrawn
  recorded.l   ; Number of bytes recorded
  recording.b  ; Record is running...
  time.s       ; Store the time string
EndStructure



Dim inHdr.WAVEHDR( #BUFFER_NUM )
Global inHdr, rec.RECORD_INFO, now.SYSTEMTIME
rec\time = Space(9)


;***********************************************************************************
;- PROCS CAPTURE
;***********************************************************************************


Procedure CAPTURE_Error( err.l )
  If err
    text.s = Space( #MAXERRORLENGTH )
    waveInGetErrorText_( err, text, #MAXERRORLENGTH )
    MessageRequester( #STR_ERROR, text, #MB_ICONERROR )
    CAPTURE_Stop()
    End
  EndIf
EndProcedure

;==============================================================================

Procedure CAPTURE_Now()
  GetLocalTime_( @now )
  GetTimeFormat_(0, 0, @now, "HH:mm:ss:", @rec\time, 9 )
  StatusBarText( #StatusBar, #StatusTime, rec\time+Str(now\wMilliseconds) )
EndProcedure

;==============================================================================

Procedure CAPTURE_Draw()
  If rec\update = #TRUE
    CAPTURE_Now()
    StartDrawing( rec\output )
      ; Draw Background...
      If rec\frame = 2
        Box( rec\x, rec\y, rec\w, rec\h, rec\cback )
        shift = rec\h >> 2
        Line( rec\x, rec\m - shift, rec\w, 0, rec\cline )
        Line( rec\x, rec\m + shift, rec\w, 0, rec\cline )
        rec\frame = 0
      Else
        rec\frame + 1
      EndIf
      ; Draw Wave Data
      oldx = rec\x : oldy = 0
      For i=0 To rec\size Step #WORD
        value = PeekW( rec\buffer + i )
        x = rec\x + ( i * rec\w-1 ) / rec\size
        y = ( value * rec\h ) / $FFFF
        If value > max : max = value : EndIf
        If x <> oldx
          Select rec\mode
            Case #TRUE  : LineXY(oldx,rec\m+oldy,x,rec\m+y,rec\cwave)
            Case #FALSE : LineXY(oldx,rec\m+oldy,x,rec\m-y,rec\cwave)
          EndSelect
          oldx=x : oldy=y
        EndIf
      Next
      ; Draw Volume
      Box(rec\x+1,rec\h+rec\y-5,(max*(rec\w-2))/$7FFF,2,#COLOR_VOLUME)
    StopDrawing()
    rec\update = #FALSE
  EndIf
EndProcedure

;==============================================================================

Procedure.s CAPTURE_GetDevice()
  Caps.WAVEINCAPS
  For i=0 To waveInGetNumDevs_()-1
    CAPTURE_ERROR( waveInGetDevCaps_( i, @Caps, SizeOf( WAVEINCAPS ) ) )
    If Caps\dwFormats & #WAVE_FORMAT_1S08
      ProcedureReturn PeekS( @Caps\szPname, 32 )
    EndIf
  Next
  ProcedureReturn #STR_NODEVICE
EndProcedure

;==============================================================================

Procedure CAPTURE_Start()
  DeviceName.s = CAPTURE_GetDevice()
  If DeviceName
    SetWindowText_( WindowID(), DeviceName )
    format.WAVEFORMATEX
    format\wFormatTag      = 1
    format\nChannels       = #SOUND_NCHANNELS
    format\wBitsPerSample  = #SOUND_NBITS
    format\nSamplesPerSec  = #SOUND_NHERTZ
    format\nBlockAlign     = #SOUND_NCHANNELS * (#SOUND_NBITS/8)
    format\nAvgBytesPerSec = #SOUND_NHERTZ * format\nBlockAlign
    format\cbSize          = 0
    CAPTURE_Error( waveInOpen_( @rec\wave, #WAVE_MAPPER, @format, WindowID(), #NULL, #CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT ) )
    For i = 0 To #BUFFER_NUM - 1
      inHdr(i)\lpData         = AllocateMemory(  #BUFFER_SIZE )
      inHdr(i)\dwBufferLength = #BUFFER_SIZE
      CAPTURE_Error( waveInPrepareHeader_( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
      CAPTURE_Error( waveInAddBuffer_    ( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
    Next
    CAPTURE_Error( waveInStart_( rec\wave ) )
    SetTimer_( WindowID(), 0, #BUFFER_TICK, 0 )
  EndIf
EndProcedure

;==============================================================================

Procedure CAPTURE_Stop()
  If rec\wave
    CAPTURE_Error( waveInReset_( rec\wave ) )
    CAPTURE_Error( waveInStop_ ( rec\wave ) )
    For i = 0 To #BUFFER_NUM - 1
      CAPTURE_Error( waveInUnprepareHeader_( rec\wave, inHdr(i), SizeOf( WAVEHDR ) ) )
    Next
    CAPTURE_Error( waveInClose_( rec\wave ) )
  EndIf
  KillTimer_( WindowID(), 0 )
EndProcedure

;==============================================================================

Procedure CAPTURE_Read( hWaveIn.l, lpWaveHdr.l )
  CAPTURE_Error( waveInAddBuffer_( hWaveIn, lpWaveHdr, SizeOf( WAVEHDR ) ) )
  rec\buffer  = PeekL( lpWaveHdr )
  rec\size    = PeekL( lpWaveHdr + 8 )
  rec\update  = #TRUE
  FILE_Append()
EndProcedure


;***********************************************************************************
;- PROCS FILE
;***********************************************************************************


Procedure FILE_Create()
  File.s = SaveFileRequester( #STR_SAVEREQ, "C:\test.raw", "Son brut|(*.raw)", 0 )
  If File
    If CreateFile( 0, File )
      FILE_Recording( #True )
      StatusBarText( #StatusBar, #StatusFile, File )
    Else
      MessageRequester( #STR_ERROR, #STR_PBFILE, #MB_ICONERROR )
    EndIf
  EndIf
EndProcedure

;==============================================================================

Procedure FILE_Append()
  If rec\recording = #True
    rec\recorded + rec\size
    WriteData( rec\buffer, rec\size )
    StatusBarText( #StatusBar, #StatusInfo, Str(rec\recorded) + #STR_RECORDED )
  EndIf
EndProcedure

;==============================================================================

Procedure FILE_Recording( state.b )
  If state = #TRUE
    rec\cback = #COLOR_RECBACK
    rec\cline = #COLOR_RECLINE
    rec\cwave = #COLOR_RECWAVE
  Else
    rec\cback = #COLOR_CAPBACK
    rec\cline = #COLOR_CAPLINE
    rec\cwave = #COLOR_CAPWAVE
  EndIf
  DisableToolBarButton( #gadRecord, state )
  DisableToolBarButton( #gadStop, #TRUE-state )
  rec\recording = state
  rec\recorded = 0
EndProcedure

;==============================================================================

Procedure FILE_Close()
  If rec\recording = #TRUE
    FILE_Recording( #FALSE )
    CloseFile(0)
    StatusBarText( #StatusBar, #StatusFile, #STR_CLOSED )
  EndIf
EndProcedure


;***********************************************************************************
;- PROCS GUI
;***********************************************************************************


Procedure GUI_Button( id.l, ico.l, tip.s )
  ToolBarStandardButton( id, ico )
  ToolBarToolTip( id, tip )
EndProcedure

;==============================================================================

Procedure GUI_Init()
  hFlags.l = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
  If OpenWindow( 0, 0,0,320,160, hFlags, "" ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  If CreateToolBar( 0, WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  If CreateGadgetList( WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  Frame3DGadget( 0, 0,0,0,0, "", #PB_Frame3D_Double )
  If CreateStatusBar( #StatusBar, WindowID() ) = #NULL
    ProcedureReturn #FALSE
  EndIf
  rec\output = WindowOutput()
  GUI_Button( #gadRecord, #PB_ToolBarIcon_Save,       #STR_RECORD )
  GUI_Button( #gadStop,   #PB_ToolBarIcon_Delete,     #STR_STOP   )
  GUI_Button( #gadMode,   #PB_ToolBarIcon_Properties, #STR_MODE   )
  AddStatusBarField(   80 )
  AddStatusBarField(  150 )
  AddStatusBarField( $FFF )
  ProcedureReturn #TRUE
EndProcedure

;==============================================================================

Procedure GUI_Resize()
  rec\x = 2
  rec\y = 30
  rec\w = WindowWidth()-4
  rec\h = WindowHeight()-52
  rec\m = rec\y + rec\h / 2
  ResizeGadget( 0, rec\x-2, rec\y-2, rec\w+4, rec\h+4 )
EndProcedure

;==============================================================================

Procedure GUI_CallBack( hWnd.l, uMsg.l, wParam.l, lParam.l )
  Result.l = #PB_ProcessPureBasicEvents
  Select uMsg
    Case #MM_WIM_DATA : CAPTURE_Read( wParam, lParam )
    Case #WM_TIMER    : CAPTURE_Draw()
    Case #WM_SIZE     : GUI_Resize()
    Case #WM_CLOSE    : Quit = #TRUE
    Case #WM_COMMAND
      Select wParam
        Case #gadRecord : FILE_Create()
        Case #gadStop   : FILE_Close()
        Case #gadMode   : rec\mode = #TRUE-rec\mode
      EndSelect
  EndSelect
  ProcedureReturn Result
EndProcedure

;==============================================================================

Procedure GUI_Main()
  If GUI_Init()
    SetWindowCallback( @GUI_CallBack() )
    FILE_Recording( #FALSE ) 
    GUI_Resize()
    CAPTURE_Start()
    While WaitWindowEvent()<>#WM_CLOSE : Wend
    CAPTURE_Stop()
  EndIf
EndProcedure


;***********************************************************************************
;- START
;***********************************************************************************


GUI_Main()
End