Are you an experienced oscilloscope user?
I am especially interested in what other features you might think it needs.
Here is a link to a compiled .exe if you do not wish to make your own.
This is for windows and compiled as a 32 bit application.
Oscilloscope_0.83.exe
11/22/2013 edit: bug fix in 'GET_CAPTURE_DEVICES()' procedure.
Here is the code if you are interested.
There is an include file that you will find at this topic.
http://www.purebasic.fr/english/viewtop ... 12&t=51078
Code: Select all
; Name : Oscilloscope.pb
; Author : BasicallyPure
; Platform : Windows only
; Compiler : PureBasic 5.20 LTS
; Date : 11.22.2013
; License : Free
;
; Forum topic : http://www.purebasic.fr/english/viewtopic.php?f=27&t=57462
EnableExplicit
; version
#ver = "0.83"
; Get the include file here.
; Forum Topic: http://www.purebasic.fr/english/viewtopic.php?f=12&t=51078
IncludeFile "ToggleButtonGadget.pbi"
#PopUp = 0 ; popup menu
; menu items
#MenuItem_Always_On_Top = 0
#MenuItem_Minimize = 1
#MenuItem_Exit = 2
;{ gadgets
Enumeration
#SampleRate ; combo gadget
#InputDevice ; combo gadget, list input devices
#Aquire ; container for input choices
#Graph ; container for sweep buttons
#Trace ; container gadget for trace controls
#Trigger ; container gadget for trigger controls
#Pos_L ; Track Bar to position trace L
#Pos_R ; Track Bar to position trace R
#Pos_M ; Track Bar to position math trace
#Gain_L ; Track Bar to set chan. L gain
#Gain_R ; Track Bar to set chan. R gain
#Trig_Lvl_L ; Track Bar to set chan. L trig. level
#Trig_Lvl_R ; Track Bar to set chan. R trig. level
#Scope_Stats ; editor gadget to display settings
#Pause ; Button for pause
#Trace_L ; Button to toggle trace L
#Trace_R ; Button to toggle trace R
#Invert_L ; Button to invert trace L
#Invert_R ; Button to invert trace R
#Math ; Button to activate L + R math trace
#Graph_XY ; Button to set XY mode
#Graph_Polar ; Button to set Polar mode
#Graph_Time ; Button to set normal sweep
#LineType ; Button to toggle line type
#Trig_Slope ; Button to select trigger slope
;
#Trig_Auto ; not a gadget, trigger from 'L' or 'R'
#Trig_Free ; not a gadget, used for free run mode
#Source_None ; not a gadget, used when no trig source selected
;
; trigger buttons, order must be preserved
#Source_L ; Button to select trigger source 'L'
#Source_R ; Button to select trigger source 'R'
#Trig_Single ; Button for Trigger menu
#Trig_Arm ; Button to arm single sweep
EndEnumeration : ;}
; images
#Grat_Norm = 0 ; graticule for normal sweep mode
#Grat_Polar = 1 ; graticule for XY sweep mode
; sprites
#Screen_bkgnd = 0 ; background graticule for scope screen
#Time_Per_Div = 1 ; display horizontal time/div readout
#TrigLine_L = 2 ; line to show trigger level for trace 'L'
#TrigLine_R = 3 ; line to show trigger level for trace 'R'
;{ misc. constants
#WAVE_FORMAT_48S16 = $00008000 ; missing windows constant
#WAVE_FORMAT_96S16 = $00080000 ; missing windows constant
#TrigViewTime = 25 ; time duration to display trig lines
#WinColor = $6D6C48 ; window background
#Scope_Color = $004720 ; scope background
#Readout_Color = $00C080 ; text color on scope screen
#CB_Color = $81A280 ; background color for containers
#Trace_L_Color = $27E4D3 ; color for trace 'L'
#Trace_R_Color = $ECDF45 ; color for trace 'R'
#Math_Color = $6500F3 ; color for trace 'L + R'
#Trace_XY_Color = $AEFF0D ; color for cartesian and polar plots
#Positive = 0 ; used for trigger slope
#Negative = 1 ; used for trigger slope
#MainWin = 0
#MONO = 1
#STEREO = 2
#ScopeW = 441 ; this gives 1mS/div. for 44100 samples per sec.
#ScopeH = 353 ; this is #ScopeW * 0.8
#Dots = 0
#Lines = 1 : ;}
Structure CONFIG :;{
wave.i ; handle of wave device from WaveInOpen_
BufLen.i ; Buffer length in number of samples
lBuf.i ; Capturing Buffer length in bytes
nBuf.i ; Number of capturing Buffers
nDev.i ; Capturing Device identifier
frameRate.i ; Scope refresh rate
tr_L_offset.i ; offset for trace L position
tr_R_offset.i ; offset For trace R position
tr_M_offset.i ; offset for math trace position
gain_L.f ; gain for trace L
gain_R.f ; gain for trace R
lineType.i ; draw dots or lines for scope trace
trace_L.i ; trace A active, 1 = True
trace_R.i ; trace B active, 1 = True
invert_L.i ; flag to invert trace L
invert_R.i ; flag to invert trace R
math.i ; flag to enable L + R trace
Display_Mode.i ; sets scope graph mode
Trig_Lvl_L.i ; channel 'L' trigger level
Trig_Lvl_R.i ; channel 'R' trigger level
Trig_Mode.i ; sets sweep trigger mode
Trig_Source.i ; signal source for trigger
Trig_Armed.i ; flag to ready single sweep trigger
Trig_Slope.i ; indicates trigger slope
EndStructure : ;}
Global Config.CONFIG
Config\nBuf = 4
Config\tr_L_offset = -#ScopeH/8 * 1.5 ; offset 1.5 divisions
Config\tr_R_offset = #ScopeH/8 * 1.5
Config\gain_L = 1
Config\gain_R = 1
Config\frameRate = 15
Config\lineType = #Lines
Config\Display_Mode = #Graph_Time
Config\trace_L = #True
Config\trace_R = #True
Config\Trig_Mode = #Trig_Free
Config\Trig_Source = #Source_None
Config\Trig_Slope = #Positive
Global Format.WAVEFORMATEX ; Capturing format
Format\wFormatTag = #WAVE_FORMAT_PCM
Format\nChannels = #STEREO
Format\wBitsPerSample = 16
Format\cbSize = 0
Global Dim inHdr.WAVEHDR(Config\nBuf - 1)
Global captureActive ; flag
Global wpa, lpa, hWindow, trigView
Procedure SCOPE()
Static *hWave.WAVEHDR, *idx, *lim
Static x, y, n, my, lyl, lyr, lmy, lx, ly
Static rds, ang, scale_L, scale_R
Static xLim = #ScopeW - 1, yLim = #ScopeH - 1
Static mid_Y = #ScopeH / 2, mid_X = #scopeW / 2
Static scale = $FFFF / -#ScopeH
; use to prevent plotting beyond screen limits
Macro HardLimit(v, lim)
If v > lim : v = lim : EndIf
If v < 0 : v = 0 : EndIf
EndMacro
Macro ScanForTrigger(level)
If Config\Trig_Slope = #Positive
While PeekW(*idx) > level And *idx < *lim : *idx + 4 : Wend
While PeekW(*idx) < level And *idx < *lim : *idx + 4 : Wend
Else ; negative slope
While PeekW(*idx) < level And *idx < *lim : *idx + 4 : Wend
While PeekW(*idx) > level And *idx < *lim : *idx + 4 : Wend
EndIf
EndMacro
*hWave = lpa ; fill structure using lParam from Callback proc.
waveInAddBuffer_(wpa, *hWave, SizeOf(WAVEHDR)) ; wpa = wParam from Callback proc.
*idx = *hWave\lpData ; set index to first audio sample
If *idx <> 0
If Config\invert_L : scale_L = -scale : Else : scale_L = scale : EndIf
If Config\invert_R : scale_R = -scale : Else : scale_R = scale : EndIf
scale_L * Config\gain_L
scale_R * Config\gain_R
DisplaySprite(#Screen_bkgnd, 0, 0) ; draw this first on every frame
If Config\Display_Mode = #Graph_Time ; normal plot
; if required display trigger level lines
If trigView : trigView - 1
If GetActiveGadget() = #Trig_Lvl_L
y = #ScopeH + Config\tr_L_offset - GetGadgetState(#Trig_Lvl_L)
HardLimit(y, yLim)
DisplayTransparentSprite(#TrigLine_L,0,y)
ElseIf GetActiveGadget() = #Trig_Lvl_R
y = #ScopeH + Config\tr_R_offset - GetGadgetState(#Trig_Lvl_R)
HardLimit(y, yLim)
DisplayTransparentSprite(#TrigLine_R,0,y)
ElseIf Config\Trig_Mode <> #Trig_Free
If GetButtonState(#Source_L) = #True
y = mid_Y + Config\tr_L_offset - GetGadgetState(#Trig_Lvl_L) + #ScopeH/2
HardLimit(y, yLim)
DisplayTransparentSprite(#TrigLine_L,0,y)
EndIf
If GetButtonState(#Source_R) = #True
y = mid_y + Config\tr_R_offset - GetGadgetState(#Trig_Lvl_R) + #ScopeH/2
HardLimit(y, yLim)
DisplayTransparentSprite(#TrigLine_R,0,y)
EndIf
EndIf
EndIf
;- begin trigger code
*lim = *idx + *hWave\dwBufferLength - xLim << 2
Select Config\Trig_Mode
Case #Trig_Free
;
Case #Trig_Auto
If Config\Trig_Source = #Source_L
ScanForTrigger(Config\Trig_Lvl_L)
ElseIf Config\Trig_Source = #Source_R
*idx + 2 : ScanForTrigger(Config\Trig_Lvl_R) : *idx - 2
EndIf
Case #Trig_Single
If trigView
; take no action
ElseIf Config\Trig_Armed = #False
ProcedureReturn
EndIf
Select Config\Trig_Source
Case #Source_L
ScanForTrigger(Config\Trig_Lvl_L)
Case #Source_R
*idx + 2
ScanForTrigger(Config\Trig_Lvl_R)
*idx - 2
Case #Source_None
ProcedureReturn
EndSelect
If trigView
; take no action
ElseIf *idx >= *lim
ProcedureReturn
Else
Config\Trig_Armed = #False
SetButtonState(#Trig_Arm, #False)
EndIf
EndSelect
If *idx >= *lim ; no trigger point found
If Config\Trig_Mode = #Trig_Free Or trigView <> 0
*idx = *hWave\lpData
Else
ProcedureReturn
EndIf
EndIf
; end trigger code
DisplayTransparentSprite(#Time_Per_Div,10, #ScopeH - 20)
StartDrawing(ScreenOutput())
If Config\lineType = #Lines ; needed to draw the first line
lyl = PeekW(*idx) /scale_L + mid_Y + Config\tr_L_offset
lyr = PeekW(*idx+2)/scale_R + mid_Y + Config\tr_R_offset
lmy = lyl + lyr - mid_Y ; for first line of 'L+R' trace
EndIf
For x = 0 To xLim
y = PeekW(*idx)/scale_L + mid_Y
my = y ; for 'L+R' trace
If Config\trace_L ; check if trace L is active
y + Config\tr_L_offset
If Config\lineType = #Dots
HardLimit(y, yLim)
Plot(x, y, #Trace_L_Color)
Else
LineXY(x-1, lyl, x, y, #Trace_L_Color) : lyl = y
EndIf
EndIf
*idx + 2
y = PeekW(*idx)/scale_R
my + y ; for 'L+R' trace
If Config\trace_R ; if trace R is active draw it
y + mid_Y + Config\tr_R_offset
If Config\lineType = #Dots
HardLimit(y, yLim)
Plot(x, y, #Trace_R_Color)
Else
LineXY(x-1, lyr, x, y, #Trace_R_Color) : lyr = y
EndIf
EndIf
*idx + 2
If Config\math ; if 'L+R' trace is active draw it
my + Config\tr_M_offset
If Config\lineType = #Dots
HardLimit(my, yLim)
Plot(x, my, #Math_Color)
Else
LineXY(x-1, lmy, x, my, #Math_Color) : lmy = my
EndIf
EndIf
Next x
ElseIf Config\Display_Mode = #Graph_XY ; do XY plot
StartDrawing(ScreenOutput())
If Config\lineType = #Lines
lx = PeekW(*idx) /scale_L + mid_X
ly = PeekW(*idx+2)/scale_R + mid_Y
EndIf
For n = 1 To Config\BufLen
x = (PeekW(*idx)/ scale_L) + mid_X ; x is left channel
*idx + 2
y = (PeekW(*idx)/ scale_R) + mid_Y ; y is right channel
*idx + 2
If Config\lineType = #Dots
HardLimit(x, xLim) : HardLimit(y, yLim)
Plot(x, y, #Trace_XY_Color)
Else
LineXY(lx, ly, x, y, #Trace_XY_Color)
lx = x : ly = y
EndIf
Next n
Else ; polar plot, left channel = radius, right channel = angle
StartDrawing(ScreenOutput())
If Config\lineType = #Lines ; needed to draw the first line
rds = PeekW(*idx) / scale_L ; left channel
ang = PeekW(*idx+2)/ scale_R ; right channel
lx = Cos(Radian(ang)) * rds + mid_X
ly = Sin(Radian(ang)) * rds + mid_Y
EndIf
For n = 1 To Config\BufLen
rds = (PeekW(*idx)/ scale_L) : *idx + 2
ang = (PeekW(*idx)/ scale_R) : *idx + 2
x = Cos(Radian(ang)) * rds + mid_X
y = Sin(Radian(ang)) * rds + mid_Y
If Config\lineType = #Dots
HardLimit(x, xLim) : HardLimit(y, yLim)
Plot(x, y, #Trace_XY_Color)
Else
LineXY(lx, ly, x, y, #Trace_XY_Color)
lx = x : ly = y
EndIf
Next n
EndIf
StopDrawing()
FlipBuffers()
EndIf
EndProcedure
Procedure WIN_CALLBACK(hWnd.l, Msg.l, wParam.l, lParam.l)
If Msg = #MM_WIM_DATA
wpa = wParam
lpa = lParam
SCOPE()
EndIf
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure CREATE_GRATICULES()
Protected n
CreateImage(#Grat_Norm, #ScopeW, #ScopeH)
CreateImage(#Grat_Polar, #ScopeW, #ScopeH)
CreateSprite(#Screen_bkgnd, #ScopeW, #ScopeH)
CreateSprite(#Time_Per_Div, 175, 15) ; sprite for time/div readout
CreateSprite(#TrigLine_L, #ScopeW, 1) ; sprite for trigger line 'L'
CreateSprite(#TrigLine_R, #ScopeW, 1) ; sprite for trigger line 'R'
; trig level lines
StartDrawing(SpriteOutput(#TrigLine_L))
LineXY(0,0,#ScopeW-1,0,#Trace_L_Color)
StopDrawing()
StartDrawing(SpriteOutput(#TrigLine_R))
LineXY(0,0,#ScopeW-1,0,#Trace_R_Color)
StopDrawing()
; normal graticule
StartDrawing(ImageOutput(#Grat_Norm))
Box(0, 0, #ScopeW, #ScopeH, #Scope_Color)
For n = 0 To #ScopeH-1 Step #ScopeH/08 : LineXY(0, n, #ScopeW-1, n, 0) : Next n
For n = 0 To #ScopeW-1 Step #ScopeW/10 : LineXY(n, 0, n, #ScopeH-1, 0) : Next n
StopDrawing()
; Polar graticule
StartDrawing(ImageOutput(#Grat_Polar))
Box(0, 0, #ScopeW, #ScopeH, #Scope_Color)
DrawingMode(#PB_2DDrawing_Outlined )
For n = 0 To #ScopeW-1 Step #ScopeW/5
Circle(#ScopeW/2, #ScopeH/2, n/2, 0)
Next n
For n = 0 To 330 Step 30
LineXY(#ScopeW/2, #ScopeH/2, #ScopeW/2 + Sin(Radian(n)) * #ScopeW/2,
#ScopeH/2 + Cos(Radian(n)) * #ScopeW/2,0)
Next n
StopDrawing()
EndProcedure
Procedure GET_CAPTURE_DEVICES()
Protected DeviceID.i, n.i, items.i, waveFormats.i = $FFFFF
Protected Caps.WAVEINCAPS
Protected NumDevices.i = waveInGetNumDevs_()
If NumDevices
For DeviceID = #WAVE_MAPPER To NumDevices - 1
If waveInGetDevCaps_(DeviceID,@Caps, SizeOf(WAVEINCAPS)) = #MMSYSERR_NOERROR
AddGadgetItem(#InputDevice, -1, PeekS(@Caps\szPname, #MAXPNAMELEN))
waveFormats & Caps\dwFormats
EndIf
Next
; assume 8000 sample rate is supported
AddGadgetItem(#SampleRate, -1, "8000") : SetGadgetState(#SampleRate, 0)
; identify all available 16 bit stereo options
If waveFormats & #WAVE_FORMAT_1S16 : AddGadgetItem(#SampleRate, -1, "11025"): EndIf
If waveFormats & #WAVE_FORMAT_2S16 : AddGadgetItem(#SampleRate, -1, "22050"): EndIf
If waveFormats & #WAVE_FORMAT_4S16 : AddGadgetItem(#SampleRate, -1, "44100"): EndIf
If waveFormats & #WAVE_FORMAT_48S16 : AddGadgetItem(#SampleRate, -1, "48000"): EndIf
If waveFormats & #WAVE_FORMAT_96S16 : AddGadgetItem(#SampleRate, -1, "96000"): EndIf
items = CountGadgetItems(#SampleRate)
If items > 1
For n = 1 To items - 1
SetGadgetState(#SampleRate, n)
If GetGadgetText(#SampleRate) = "22050" ; choose this if available
n = items ; exit for/next loop
Else
SetGadgetState(#SampleRate, 0) ; use 8000 if 22050 is not available
EndIf
Next n
Else
MessageRequester("", "No suitable wave capture devices found!")
ProcedureReturn 0
EndIf
Else
MessageRequester("", "No audio devices found!")
EndIf
ProcedureReturn NumDevices
EndProcedure
Procedure INIT_GUI()
; returns window handle or 0 if fail
Protected n, flags = #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget
Protected hWin = OpenWindow(#MainWin, 0, 0, 770, 485, "Oscilloscope v." + #ver, flags)
If hWin And InitSprite() And OpenWindowedScreen(hWin, 10, 10, #ScopeW, #ScopeH)
SetWindowColor(#MainWin, #WinColor)
CreatePopupMenu(#PopUp)
MenuItem(#MenuItem_Always_On_Top, "Always On Top")
MenuItem(#MenuItem_Minimize, "Minimize")
MenuItem(#MenuItem_Exit, "Exit")
; trace controls
ContainerGadget(#Trace, #ScopeW + 20, 10, 160, 180, #PB_Container_Raised)
SetGadgetColor(#Trace, #PB_Gadget_BackColor, #CB_Color)
SetGadgetColor(TextGadget(#PB_Any, 5, 5, 110, 15, "Trace Control"), #PB_Gadget_BackColor, #CB_Color)
ToggleButtonGadget(#Trace_L , 05, 25, 55, 25, "LEFT" , "", 1)
ToggleButtonGadget(#Trace_R , 05, 55, 55, 25, "RIGHT" , "", 1)
ToggleButtonGadget(#Math , 05, 85, 55, 25, " L + R", "")
SetButtonColor(#Math, #PB_Ignore, #PB_Ignore, #Math_Color, $655DF3)
ToggleButtonGadget(#Invert_L, 05, 115, 55, 25, "Inv. L", "")
ToggleButtonGadget(#Invert_R, 05, 145, 55, 25, "Inv. R", "")
TrackBarGadget(#Pos_L, 65, 25, 25, 145, 0, #ScopeH, #PB_TrackBar_Vertical)
SetGadgetState(#Pos_L, #ScopeH/2 - Config\tr_L_offset)
GadgetToolTip(#Pos_L, "LEFT position")
TrackBarGadget(#Pos_R, 95, 25, 25, 145, 0, #ScopeH, #PB_TrackBar_Vertical)
SetGadgetState(#Pos_R, #ScopeH/2 - Config\tr_R_offset)
GadgetToolTip(#Pos_R, "RIGHT position")
TrackBarGadget(#Pos_M, 125, 25, 25, 145, 0, #ScopeH, #PB_TrackBar_Vertical)
SetGadgetState(#Pos_M, #ScopeH/2 - Config\tr_M_offset)
GadgetToolTip(#Pos_M, "'L+R' position")
DisableGadget(#Pos_M, #True)
CloseGadgetList()
; trigger controls
ContainerGadget(#Trigger, #ScopeW + 185, 10, 135, 180, #PB_Container_Raised)
SetGadgetColor(#Trigger, #PB_Gadget_BackColor, #CB_Color)
SetGadgetColor(TextGadget(#PB_Any, 10, 5, 800, 15, "Trigger Control"), #PB_Gadget_BackColor, #CB_Color)
ToggleButtonGadget(#Source_L, 05, 025, 60, 25, "LEFT")
GadgetToolTip(#Source_L, "Trigger on LEFT")
ToggleButtonGadget(#Source_R, 05, 055, 60, 25, "RIGHT")
GadgetToolTip(#Source_R, "Trigger on RIGHT")
ToggleButtonGadget(#Trig_Slope, 05, 085, 60, 25, "Slope +", "Slope -")
SetButtonColor(#Trig_Slope, $AEFF0D, $AEC00D)
ToggleButtonGadget(#Trig_Single, 05, 115, 60, 25, "Single")
ToggleButtonGadget(#Trig_Arm, 05, 145, 60, 25, "Arm", "Armed")
DisableButton(#Trig_Arm, #True)
SetButtonColor(#Trig_Arm, $1E64F0, $3A1FB4, $17D671, $17A21B)
TrackBarGadget(#Trig_Lvl_L, 70, 25, 25, 145, 0, #ScopeH, #PB_TrackBar_Vertical)
SetGadgetState(#Trig_Lvl_L, #ScopeH/2)
GadgetToolTip(#Trig_Lvl_L, "LEFT Trig. Level")
TrackBarGadget(#Trig_Lvl_R, 100, 25, 25, 145, 0, #ScopeH, #PB_TrackBar_Vertical)
SetGadgetState(#Trig_Lvl_R, #ScopeH/2)
GadgetToolTip(#Trig_Lvl_R, "RIGHT Trig. Level")
CloseGadgetList()
; graph controls
ContainerGadget(#Graph, #ScopeW + 185, 200, 135, 155, #PB_Container_Raised)
SetGadgetColor(#Graph, #PB_Gadget_BackColor, #CB_Color)
SetGadgetColor(TextGadget(#PB_Any, 10, 5, 85, 15, "Graph Control"), #PB_Gadget_BackColor, #CB_Color)
ToggleButtonGadget(#Graph_Time , 05, 025, 60, 25, "Time")
GadgetToolTip(#Graph_Time, "Plot amplitude vs time")
ToggleButtonGadget(#Graph_XY , 05, 055, 60, 25, "X Y")
GadgetToolTip(#Graph_XY, "XY plot, left vs right")
ToggleButtonGadget(#Graph_Polar , 05, 085, 60, 25, "Polar")
GadgetToolTip(#Graph_Polar, "radius (left) vs angle (right)")
ToggleButtonGadget(#LineType , 05, 120, 60, 25, "Dots", "Lines", 1)
SetButtonColor(#LineType, $AEFF0D, $AEC00D)
GadgetToolTip(#LineType, "show trace as lines or dots")
TrackBarGadget(#Gain_L, 70, 25, 25, 120, 0, 8, #PB_TrackBar_Vertical | #PB_TrackBar_Ticks)
SetGadgetState(#Gain_L, 4) ; gain is Pow(2, n-4)
GadgetToolTip(#Gain_L, "LEFT gain")
TrackBarGadget(#Gain_R, 100, 25, 25, 120, 0, 8, #PB_TrackBar_Vertical | #PB_TrackBar_Ticks)
SetGadgetState(#Gain_R, 4) ; state 4 gives default gain of x1
GadgetToolTip(#Gain_R, "RIGHT gain")
CloseGadgetList()
; signal aquisition
ContainerGadget(#Aquire, #ScopeW + 20, 200, 160, 155, #PB_Container_Raised)
SetGadgetColor(#Aquire, #PB_Gadget_BackColor, #CB_Color)
SetGadgetColor(TextGadget(#PB_Any, 5, 5, 155, 15, "Signal Aquisition"),
#PB_Gadget_BackColor, #CB_Color)
ComboBoxGadget(#InputDevice, 5, 25,145,20)
ComboBoxGadget(#SampleRate, 5, 75, 70, 20)
SetGadgetColor(TextGadget(#PB_Any, 80, 75, 80, 15,
"sample rate"), #PB_Gadget_BackColor, #CB_Color)
ToggleButtonGadget(#Pause,05, 120, 135, 25, "Pause", "Paused")
SetButtonColor(#Pause, $17D671, $17A21B, $1E64F0, $3A1FB4)
CloseGadgetList()
EditorGadget(#Scope_Stats, #ScopeW + 20, 365, 300, 110, #PB_Editor_ReadOnly)
If LoadFont(0,"Courier New", 10, #PB_Font_Bold)
SetGadgetFont(#Scope_Stats, FontID(0))
EndIf
SetGadgetColor(#Scope_Stats, #PB_Gadget_FrontColor, $DBEC45)
SetGadgetColor(#Scope_Stats, #PB_Gadget_BackColor , $51121E)
For n = 0 To 5 : AddGadgetItem(#Scope_Stats,-1,RSet("",25,".")) : Next n
SetGadgetItemText(#Scope_Stats, 0, "Left chan. gain : x 1")
SetGadgetItemText(#Scope_Stats, 1, "Right chan. gain : x 1")
SetGadgetItemText(#Scope_Stats, 2, "Left Trig level : " + Str(Config\Trig_Lvl_L))
SetGadgetItemText(#Scope_Stats, 3, "Right Trig level : " + Str(Config\Trig_Lvl_R))
If GET_CAPTURE_DEVICES() = 0
ProcedureReturn 0
Else
SetGadgetState(#InputDevice,0)
EndIf
CREATE_GRATICULES()
SetWindowCallback(@WIN_CALLBACK())
ProcedureReturn hWin
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure CAPTURE_STOP()
Protected i
If Config\wave
waveInReset_(Config\wave)
waveInStop_(Config\wave)
For i = 0 To Config\nBuf - 1
If inHdr(i)\lpData
waveInUnprepareHeader_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
FreeMemory(inHdr(i)\lpData)
inHdr(i)\lpData = 0
EndIf
Next
waveInClose_(Config\wave)
EndIf
captureActive = #False
EndProcedure
Procedure TOGGLE_LINE_TYPE()
FlipButton(#LineType)
If GetButtonState(#LineType)
Config\lineType = #Lines
Else
Config\lineType = #Dots
EndIf
EndProcedure
Procedure TOGGLE_TRACE(T$)
If T$ = "L"
FlipButton(#Trace_L)
Config\trace_L = GetButtonState(#Trace_L)
Else
FlipButton(#Trace_R)
Config\trace_R = GetButtonState(#Trace_R)
EndIf
EndProcedure
Procedure PAUSE_CAPTURE()
FlipButton(#Pause)
If GetButtonState(#Pause) = #True
waveInStop_(Config\wave)
Else
waveInStart_(Config\wave)
EndIf
EndProcedure
Procedure INIT_CAPTURE()
Protected state, i
If captureActive : CAPTURE_STOP() : EndIf
Config\nDev = GetGadgetState(#InputDevice) ; select signal source
With Format
Config\BufLen = \nSamplesPerSec / Config\frameRate ; \BufLen determines refresh rate
\nBlockAlign = (#STEREO * \wBitsPerSample) / 8 ; bytes per sample * num channels
Config\lBuf = Config\BufLen * \nBlockAlign ; multiply bufferLength by blockAlign
\nAvgBytesPerSec = \nSamplesPerSec * \nBlockAlign ; blockAlign is bytes per sample
\cbSize = 0
EndWith
If #MMSYSERR_NOERROR = waveInOpen_(@Config\wave,#WAVE_MAPPER+Config\nDev,@format,
hWindow,#Null,#CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT)
For i = 0 To Config\nBuf - 1
inHdr(i)\lpData = AllocateMemory(Config\lBuf)
inHdr(i)\dwBufferLength = Config\lBuf
waveInPrepareHeader_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
waveInAddBuffer_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
Next
If #MMSYSERR_NOERROR = waveInStart_(Config\wave)
Else
MessageRequester("Error!","waveInStart_ fail"+#CRLF$+"INIT_CAPTURE() procedure")
EndIf
Else
MessageRequester("Error!","waveInOpen_ fail"+#CRLF$+"INIT_CAPTURE() procedure")
EndIf
captureActive = #True
EndProcedure
Procedure SET_SAMPLE_RATE()
Protected n, text.s
format\nSamplesPerSec = Val(GetGadgetText(#SampleRate))
text = "Time Per Div. = " +
StrF(#ScopeW / format\nSamplesPerSec * 100, 3) + " mS."
StartDrawing(SpriteOutput(#Time_Per_Div))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0,0,OutputWidth(),OutputHeight(),0)
DrawText(0, 0,text, #Readout_Color)
StopDrawing()
INIT_CAPTURE()
EndProcedure
Procedure SET_DISPLAY_MODE(Button)
If GetButtonState(Button)
ProcedureReturn
Else
FlipButton(Button)
Config\Display_Mode = Button
Select Button
Case #Graph_Time
SetButtonState(#Graph_XY , #False)
SetButtonState(#Graph_Polar , #False)
StartDrawing(SpriteOutput(#Screen_bkgnd))
DrawImage(ImageID(#Grat_Norm), 0, 0)
StopDrawing()
DisableButton(#Trace_L , #False)
DisableButton(#Trace_R , #False)
DisableButton(#Math , #False)
If Config\lineType = #Dots : TOGGLE_LINE_TYPE() : EndIf
Case #Graph_Polar
SetButtonState(#Graph_Time, #False)
SetButtonState(#Graph_XY , #False)
StartDrawing(SpriteOutput(#Screen_bkgnd))
DrawImage(ImageID(#Grat_Polar), 0, 0)
StopDrawing()
DisableButton(#Trace_L , #True)
DisableButton(#Trace_R , #True)
DisableButton(#Math , #True)
If Config\lineType = #Lines
TOGGLE_LINE_TYPE()
EndIf
Case #Graph_XY
StartDrawing(SpriteOutput(#Screen_bkgnd))
DrawImage(ImageID(#Grat_Norm), 0, 0)
StopDrawing()
SetButtonState(#Graph_Time , #False)
SetButtonState(#Graph_Polar , #False)
DisableButton(#Trace_L , #True)
DisableButton(#Trace_R , #True)
DisableButton(#Math , #True)
If Config\lineType = #Lines : TOGGLE_LINE_TYPE() : EndIf
EndSelect
EndIf
EndProcedure
Procedure SET_STICKY_WINDOW()
Protected state = GetMenuItemState(#PopUp, #MenuItem_Always_On_Top) ! 1
SetMenuItemState(#PopUp, #MenuItem_Always_On_Top, state)
StickyWindow(#MainWin, state)
EndProcedure
Procedure TOGGLE_MATH()
FlipButton(#Math)
Config\math ! 1
DisableGadget(#Pos_M, GetButtonState(#Math) ! 1)
EndProcedure
Procedure SET_TRIG_LEVEL(chan)
Static mlt = $FFFF / #ScopeH
Protected level = (GetGadgetState(chan) - #ScopeH >> 1) * mlt
If Abs(level) < 228 : level = 0 : EndIf
If chan = #Trig_Lvl_L
Config\Trig_Lvl_L = level * Config\gain_L
SetGadgetItemText(#Scope_Stats, 2, "Left Trig level : " + Str(level/327.68))
ElseIf chan = #Trig_Lvl_R
Config\Trig_Lvl_R = level * Config\gain_R
SetGadgetItemText(#Scope_Stats, 3, "Right Trig level : " + Str(level/327.68))
EndIf
trigView = #TrigViewTime ; display trig level lines for specified duration
EndProcedure
Procedure SET_GAIN(gadNum)
Protected text.s
If gadNum = #Gain_L ; set left channel gain
Config\gain_L = Pow(2, 4 - GetGadgetState(gadNum))
SET_TRIG_LEVEL(#Trig_Lvl_L)
text = "Left chan. gain : x " + StrF(1/Config\gain_L)
SetGadgetItemText(#Scope_Stats, 0, text)
ElseIf gadNum = #Gain_R ; set right channel gain
Config\gain_R = Pow(2, 4 - GetGadgetState(gadNum))
SET_TRIG_LEVEL(#Trig_Lvl_R)
text = "Right chan. gain : x " + StrF(1/Config\gain_R)
SetGadgetItemText(#Scope_Stats, 1, text)
EndIf
EndProcedure
Procedure SET_TRIG_MODE(gadNum)
Static text.s = " Trig. source? "
Protected n
FlipButton(gadNum)
Select gadNum
Case #Source_L, #Source_R
If GetButtonState(gadNum) = #True
Config\Trig_Source = gadNum
If Config\Trig_Mode = #Trig_Free : Config\Trig_Mode = #Trig_Auto : EndIf
SetButtonState(#Source_L + #Source_R - gadNum, #False)
Else
Config\Trig_Source = #Source_None
If Config\Trig_Mode = #Trig_Auto : Config\Trig_Mode = #Trig_Free : EndIf
EndIf
Case #Trig_Single
If GetButtonState(#Trig_Single) = #True
DisableButton(#Trig_Arm, #False)
SetButtonState(#Trig_Arm, #True)
Config\Trig_Armed = #True
Config\Trig_Mode = #Trig_Single
Else
SetButtonState(#Trig_Arm, #False)
DisableButton(#Trig_Arm, #True)
Config\Trig_Armed = #False
If Config\Trig_Source = #Source_None
Config\Trig_Mode = #Trig_Free
Else
Config\Trig_Mode = #Trig_Auto
EndIf
EndIf
Case #Trig_Arm
Config\Trig_Armed = GetButtonState(#Trig_Arm)
ProcedureReturn
EndSelect
If Config\Trig_Mode = #Trig_Single
If Config\Trig_Source = #Source_None
StartDrawing(ScreenOutput())
DrawText(#ScopeW/2 - TextWidth (text)/2,
#ScopeH/2 - TextHeight(text)/2,
text, #White, #Scope_Color)
StopDrawing() : FlipBuffers()
EndIf
EndIf
trigView = #TrigViewTime ; display trig level lines for specified duration
EndProcedure
Procedure EVENT_LOOP()
Protected Quit = #False
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow : Quit = #True
Case #PB_Event_MinimizeWindow : PAUSE_CAPTURE()
Case #PB_Event_RightClick
DisplayPopupMenu(#PopUp, hWindow)
Case #PB_Event_Menu
Select EventMenu()
Case #MenuItem_Exit : Quit = #True
Case #MenuItem_Always_On_Top : SET_STICKY_WINDOW()
Case #MenuItem_Minimize : PAUSE_CAPTURE()
SetWindowState(#MainWin, #PB_Window_Minimize)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #Pause : PAUSE_CAPTURE()
Case #Graph_Time : SET_DISPLAY_MODE(#Graph_Time)
Case #Graph_XY : SET_DISPLAY_MODE(#Graph_XY)
Case #Graph_Polar : SET_DISPLAY_MODE(#Graph_Polar)
Case #InputDevice : INIT_CAPTURE()
Case #SampleRate : SET_SAMPLE_RATE()
Case #LineType : TOGGLE_LINE_TYPE()
Case #Pos_L : Config\tr_L_offset = #ScopeH/2 - GetGadgetState(#Pos_L)
Case #Pos_R : Config\tr_R_offset = #ScopeH/2 - GetGadgetState(#Pos_R)
Case #Pos_M : Config\tr_M_offset = #ScopeH/2 - GetGadgetState(#Pos_M)
Case #Trace_L : TOGGLE_TRACE("L")
Case #Trace_R : TOGGLE_TRACE("R")
Case #Invert_L : FlipButton(#Invert_L) : Config\invert_L ! 1
Case #Invert_R : FlipButton(#Invert_R) : Config\invert_R ! 1
Case #Trig_Slope : FlipButton(#Trig_Slope) : Config\Trig_Slope ! 1
Case #Math : TOGGLE_MATH()
Case #Gain_L : SET_GAIN(#Gain_L)
Case #Gain_R : SET_GAIN(#Gain_R)
Case #Trig_Lvl_L : SET_TRIG_LEVEL(#Trig_Lvl_L)
Case #Trig_Lvl_R : SET_TRIG_LEVEL(#Trig_Lvl_R)
Case #Source_L To #Trig_Arm : SET_TRIG_MODE(EventGadget())
EndSelect
EndSelect
Until Quit = #True
CAPTURE_STOP()
End
EndProcedure
hWindow = INIT_GUI()
If hWindow <> 0
SET_SAMPLE_RATE()
SET_DISPLAY_MODE(#Graph_Time)
EVENT_LOOP()
EndIf