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...
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
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