There are two design requirements:
1. The random numbers must be confined to the range 1 to 80;
2. There must be no numbers that duplicate a previously-picked number.
When reading audio samples I have trouble satisfying condition #1, so I instead use CryptRandomData(). I then examine the picked number and filter out numbers < 1 or > 80. This satisfies requirement #1.
Where I'm having trouble is in filtering out duplicate picks, requirement #2. Line 323 of the code is supposed to do this but I'm still getting duplicate picks and skipped numbers. Any idea why this is so?
There is still a lot of code which can probably be deleted.
Thank you.
Code: Select all
;/ Object Audio Recorder 1.0 (a)
;/
;/ Date August 2004
;/ Author Philippe Carpentier
;/ Contact flype@altern.org
;/ Info MS Windows only - winmm.lib - mmsystem.h
;/
; Bug fixes by chris319 on September 2, 2007
; 04/02/2010 : DrGolf for PB 4.50
; 01/20/2011 : Vitor_Boss® -- Fixed clamping
; 6/8/2012 -- revised again by chris319 on PB 4.61
Global QuitRec.l
;
;- REC CONSTANTES
;
#MinWidth = 320
#MinHeight = 240
#MONO = 1
Global *Key = AllocateMemory(256)
If OpenCryptRandom() And *Key
CryptRandomData(*Key, 256)
EndIf
Global Dim randomPicks(256)
Global Dim pickedNumbers.a(257)
Global pickCount = 0
For cnt = 0 To 80
pickedNumbers(cnt) = 0
Next
;- REC INITIALISATION
Enumeration 0 ; #CHANNEL
#CHANNEL_LEFT
; #CHANNEL_RIGHT
EndEnumeration
Enumeration 0 ; #GADGET
#gadFrame1
#gadFrame2
#gadStart
#gadStop
#gadSndVol
#gadFile
#gadChannel
#gadResolution
#gadFrequence
#gadDevice
#gadText1
#gadText2
EndEnumeration
Enumeration 0 ; #WINDOW
#Window
EndEnumeration
Enumeration 0 ; #TOOLBAR
#ToolBar
EndEnumeration
Enumeration 0 ; #STATUSBAR
#StatusBar
EndEnumeration
;Structure WAVEFORMATEX -- NOT NEEDED IN PB 4.10 -- chris319
; wFormatTag.w
; nChannels.w
; nSamplesPerSec.l
; nAvgBytesPerSec.l
; nBlockAlign.w
; wBitsPerSample.w
; cbSize.w
;EndStructure
Structure SCOPE
channel.b
left.l
top.l
width.l
height.l
middleY.l
quarterY.l
EndStructure
Structure CONFIG
hWindow.l ; Window handle
hToolBar.l ; ToolBar handle
hfont.l ; Font handle
Date.l ; Start date
size.l ; Wave buffer size
buffer.l ; Wave buffer pointer
output.l ; WindowOutput()
wave.l ; Address of waveform-audio input device
recorded.l ; Number of bytes recorded
recording.b ; Record is running...
File.s ; Recording FileName (c:\unnamed.snd) ;chris319 6/7/12
FileId.l ; Recording FileId (#PB_Any)
SndVol.s ; Microsoft Volume Control (sndvol32.exe)
format.WAVEFORMATEX ; Capturing WaveFormatEx
lBuf.l ; Capturing Buffer size
nBuf.l ; Capturing Buffer number
nDev.l ; Capturing Device identifier
; nBit.l ; Capturing Resolution (8/16) ;chris319 6/7/12
; nHertz.l ; Capturing Frequency (Hertz) ;chris319 6/7/12
; nChannel.l ; Capturing Channels number (Mono/Stereo) ;chris319 6/7/12
LScope.SCOPE ; Wave form display
RScope.SCOPE ; Wave form display
ScopeTimer.l ; Scope Timer (redraw every n times)
cback.l ; Back color
cline.l ; Line color
cwave.l ; Wave color
ColRecWave.l ; Scope Record Wave Color
ColRecBack.l ; Scope Record Back Color
ColRecLine.l ; Scope Record Line Color
ColCapWave.l ; Scope Capture Wave Color
ColCapBack.l ; Scope Capture Back Color
ColCapLine.l ; Scope Capture Line Color
EndStructure
Global Config.CONFIG
Global Dim inHdr.WAVEHDR(16)
Config\hfont = LoadFont(0,"Arial",7)
Config\format\cbSize = 0
Config\format\wFormatTag = #WAVE_FORMAT_PCM
Config\LScope\channel = #CHANNEL_LEFT
;- REC DECLARATIONS
Declare CONFIG_Load()
Declare CAPTURE_Stop()
Declare CAPTURE_Start()
Declare CAPTURE_Error(err.l)
Declare CAPTURE_GetDevices(gadId.l)
Declare CAPTURE_Read(hWaveIn.l,lpWaveHdr.l)
Declare DRAW_Wave8M(*scope.SCOPE)
Declare DRAW_Wave16M(*scope.SCOPE)
;Declare DRAW_Background(*scope.SCOPE)
Declare DrawNumber()
Declare GUI_Init()
Declare GUI_Resize()
Declare GUI_TBCombo(Id,x,y,w,h)
Declare GUI_CallBack(hWnd.l,Msg.l,wParam.l,lParam.l)
;- REC PROCEDURES
Procedure CONFIG_Load()
Config\nDev = #Null
Config\format\nChannels = #MONO
Config\format\nSamplesPerSec = 48000
Config\format\wBitsPerSample = 8
Config\nBuf = 8
Config\lBuf = 2048
pos.WINDOWPLACEMENT
pos\length=SizeOf(WINDOWPLACEMENT)
pos\ptMinPosition\x = 0
pos\ptMinPosition\y = 0
pos\ptMaxPosition\x = -1
pos\ptMaxPosition\y = -1
pos\rcNormalPosition\left = 100
pos\rcNormalPosition\top = 100
pos\rcNormalPosition\right = #MinWidth
pos\rcNormalPosition\bottom = #MinHeight
Config\cback = Config\ColCapBack
Config\cline = Config\ColCapLine
Config\cwave = Config\ColCapWave
StatusBarText(0,2,Config\File)
SetGadgetState(#gadDevice,Config\nDev)
SetGadgetState(#gadChannel,Config\format\nChannels - 1)
Select Config\format\wBitsPerSample
Case 8: SetGadgetState(#gadResolution, 0)
Case 16: SetGadgetState(#gadResolution, 1)
EndSelect
SetWindowPlacement_(Config\hWindow,@pos)
ShowWindow_(Config\hWindow,#True)
EndProcedure
Procedure CAPTURE_Start()
CAPTURE_Stop()
;GET USER SETTINGS
Config\format\nChannels = #MONO
gui_Resize()
Config\format\wBitsPerSample = 8
Config\format\nBlockAlign = (Config\format\nChannels * Config\format\wBitsPerSample) / 8
Config\format\nAvgBytesPerSec = Config\format\nSamplesPerSec * Config\format\nBlockAlign
Config\format\cbSize = 0
If #MMSYSERR_NOERROR = waveInOpen_(@Config\wave,#WAVE_MAPPER+Config\nDev,@Config\format,Config\hWindow,#Null,#CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT)
For i = 0 To 7 ;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)
;SetTimer_(Config\hWindow,0,Config\ScopeTimer,0)
EndIf
EndIf
EndProcedure
;
Procedure CAPTURE_Stop()
If Config\wave
waveInReset_(Config\wave)
waveInStop_(Config\wave)
For i = 0 To Config\nBuf - 1
If inHdr(i)
waveInUnprepareHeader_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
EndIf
Next
waveInClose_(Config\wave)
EndIf
KillTimer_(Config\hWindow,0)
EndProcedure
Procedure CAPTURE_Read(hWaveIn.l,lpWaveHdr.l)
; waveInAddBuffer_(hWaveIn,lpWaveHdr,SizeOf(WAVEHDR))
*hWave.WAVEHDR=lpWaveHdr
Config\buffer=*hWave\lpData
Config\size=*hWave\dwBytesRecorded
; dwBytesRecorded MUST BE SAVED BEFORE CALLING waveInAddBuffer -- chris319
waveInAddBuffer_(hWaveIn,lpWaveHdr,SizeOf(WAVEHDR))
DrawNumber()
EndProcedure
;
Procedure CAPTURE_GetDevices(gadId.l)
MMNumDevice.l = waveInGetNumDevs_()
If MMNumDevice
For MMDeviceId=#WAVE_MAPPER To MMNumDevice-1
MMResult.l = waveInGetDevCaps_(MMDeviceId,@Caps.WAVEINCAPS,SizeOf(WAVEINCAPS))
If MMResult = #MMSYSERR_NOERROR
AddGadgetItem(gadId,-1,PeekS(@Caps\szPname,#MAXPNAMELEN))
EndIf
Next
EndIf
EndProcedure
Procedure DRAW_Wave8M(*scope.SCOPE)
Protected Max_Y = (Config\RScope\height)/2
oldx.l = *scope\left
For i = 0 To Config\size - 1 ;chris319
value.b=PeekB(Config\buffer+i)+$7F
;xx=Clamp(*scope\left+(i * *scope\width)/(Config\size+1),*scope\left,*scope\width)
yy=(value**scope\height)/$FF
If yy > Max_Y : yy = Max_Y : EndIf
If yy < -Max_Y : yy = -Max_Y : EndIf
LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy, Config\cwave)
oldx=xx:oldy=yy
Next
EndProcedure
Procedure DRAW_Wave16M(*scope.SCOPE) ;16 BITS MONO
Config\cwave = $00ffff
Protected Max_Y = (Config\RScope\height)/2
oldx.l = *scope\left
For i = 0 To (Config\size - 2) Step 2
value.w = PeekW(Config\buffer + i)
;xx = Clamp(*scope\left+(i**scope\width)/(Config\size+1),*scope\left,*scope\width)
yy = (value * *scope\height)/$FFFF
;yy = (value * *scope\height) / $FFF
ayy = Abs(yy)
If ayy > vmax: vmax = ayy: EndIf
If yy > Max_Y : yy = Max_Y : EndIf
If yy < -Max_Y : yy = -Max_Y : EndIf
LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy,Config\cwave)
oldx = xx: oldy = yy
Next
LineXY(oldx, *scope\middleY + oldy, xx, *scope\middleY + yy, Config\cwave)
oldx = xx: oldy = yy
EndProcedure
Procedure DrawNumber()
Config\recorded + Config\size
CryptRandomData(*Key, 256)
;index.a = PeekA(@Config\buffer)
;pick.a = PeekA(@Config\buffer)
;pick.a = PeekA(*Key+index)
pick.a = PeekA(*Key)
isUnique = #True
For cnt = 0 To 81
If pick = pickedNumbers(cnt)
isUnique = #False
Else
pickedNumbers(cnt) = pick
EndIf
Next
If isUnique = #True And pick >= 1 And pick <= 80 And pickCount < 80
pickCount + 1: Debug pick
EndIf
If pickCount > 80
For cnt = 0 To 255
pickedNumbers(cnt) = 255
Next
EndIf
EndProcedure
Procedure GUI_Init()
QuitRec = 0
WndId.l = OpenWindow(0,0,0,500,400,"Recorder",#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_Invisible)
If WndId=#Null
MessageRequester("Error", "Unable to open window.") ;chris319 -- 6/8/12
End
EndIf
LoadFont(0, "Arial", 24)
Config\hWindow=WindowID(0)
Config\output=WindowOutput(0)
Config\hToolBar=CreateToolBar(#ToolBar,Config\hWindow)
If Config\hToolBar=#Null : ProcedureReturn #False : EndIf
If CreateStatusBar(#StatusBar,Config\hWindow)=#Null
ProcedureReturn #False
EndIf
ToolBarStandardButton(#gadStart,#PB_ToolBarIcon_Open) ;START RECORDING
ToolBarStandardButton(#gadStop,#PB_ToolBarIcon_Delete) ;STOP RECORDING
ToolBarStandardButton(#gadFile,#PB_ToolBarIcon_Save) ;SAVE FILE
ToolBarSeparator()
; ToolBarStandardButton(#gadSndVol,#PB_ToolBarIcon_Properties) ;VOLUME CONTROL -- NOT IMPLEMENTED
ToolBarSeparator()
ToolBarToolTip(#ToolBar, #gadStart,"Record")
ToolBarToolTip(#ToolBar, #gadStop,"Stop")
ToolBarToolTip(#ToolBar, #gadFile,"Create a file")
; ToolBarToolTip(#ToolBar, #gadSndVol,"Volume")
GUI_TBCombo(#gadChannel,0,1,58,20) ; 04/02/2010 DrGolf
AddGadgetItem(#gadChannel,-1,"Mono")
AddGadgetItem(#gadChannel,-1,"Stereo")
SetGadgetState(#gadChannel,0)
GUI_TBCombo(#gadResolution,1,1,55,20) ; 04/02/2010 DrGolf
AddGadgetItem(#gadResolution,-1,"8 bits")
AddGadgetItem(#gadResolution,-1,"16 bits")
SetGadgetState(#gadResolution, 1)
GUI_TBCombo(#gadFrequence,2,1,80,20) ; 04/02/2010 DrGolf
AddGadgetItem(#gadFrequence,-1,"8.0 kHz")
AddGadgetItem(#gadFrequence,-1,"11.025 kHz")
AddGadgetItem(#gadFrequence,-1,"12.0 kHz")
AddGadgetItem(#gadFrequence,-1,"16.0 kHz")
AddGadgetItem(#gadFrequence,-1,"22.05 kHz")
AddGadgetItem(#gadFrequence,-1,"24.0 kHz")
AddGadgetItem(#gadFrequence,-1,"32.0 kHz")
AddGadgetItem(#gadFrequence,-1,"44.1 kHz")
AddGadgetItem(#gadFrequence,-1,"48.0 kHz")
SetGadgetState(#gadFrequence, 7) ;chris319 6/7/12
GUI_TBCombo(#gadDevice,2,1,160,20) ; 04/02/2010 DrGolf
CAPTURE_GetDevices(#gadDevice)
SetGadgetState(#gadDevice,0)
;Frame3DGadget(#gadFrame1,0,0,0,0,"",#PB_Frame3D_Double)
;Frame3DGadget(#gadFrame2,0,0,0,0,"",#PB_Frame3D_Double)
AddStatusBarField( 100)
AddStatusBarField( 80)
AddStatusBarField(1000)
StatusBarText(0,0,"0 "+"bytes",#PB_StatusBar_Center)
StatusBarText(0,1,"0.0 "+"secs",#PB_StatusBar_Center)
SetWindowCallback(@GUI_CallBack())
GUI_Resize()
ProcedureReturn #True
EndProcedure
;
Procedure GUI_Resize()
WndW.l = ( WindowWidth(0) - 4 )
WndH.l = ( WindowHeight(0) - 60 ) >> 1
Config\LScope\left = 28
Config\LScope\top = 30
Config\LScope\width = WndW
Config\LScope\height = WndH
Config\LScope\quarterY = Config\LScope\height >> 2
Config\LScope\middleY = Config\LScope\top + Config\LScope\height >> 1
; ResizeGadget(#gadFrame1,Config\LScope\left-2,Config\LScope\top-2,Config\LScope\width+4,Config\LScope\height+4)
Config\RScope\left = 28
Config\RScope\top = Config\LScope\top + Config\LScope\height + 6
Config\RScope\width = WndW
Config\RScope\height = WndH
Config\RScope\quarterY = Config\RScope\height >> 2
Config\RScope\middleY = Config\RScope\top + Config\RScope\height >> 1
; ResizeGadget(#gadFrame2,Config\RScope\left-2,Config\RScope\top-2,Config\RScope\width+4,Config\RScope\height+4)
EndProcedure
Procedure GUI_TBCombo(Id,x,y,w,h)
pos=SendMessage_(Config\hToolBar,#TB_BUTTONCOUNT,0,0)
ToolBarSeparator()
SendMessage_(Config\hToolBar,#TB_GETBUTTON,pos,@separator.TBBUTTON)
separator\iBitmap=x+w
SendMessage_(Config\hToolBar,#TB_DELETEBUTTON,pos,0)
SendMessage_(Config\hToolBar,#TB_INSERTBUTTON,pos,separator)
SendMessage_(Config\hToolBar,#TB_GETITEMRECT,pos,@rc.RECT)
UseGadgetList(Config\hToolBar)
ComboBoxGadget(Id,x+rc\left,y,w,h)
UseGadgetList(Config\hWindow)
EndProcedure
Procedure GUI_CallBack(hWnd.l,Msg.l,wParam.l,lParam.l)
Result.l = #PB_ProcessPureBasicEvents
Select Msg
Case #WM_KEYDOWN
If GetAsyncKeyState_(#VK_ESCAPE)
QuitRec = 1
EndIf
Case #WM_SIZE: GUI_Resize()
Case #MM_WIM_DATA: CAPTURE_Read(wParam,lParam): ;DRAW_Scope()
Case #WM_GETMINMAXINFO
*mmi.MINMAXINFO=lParam
*mmi\ptMinTrackSize\x=#MinWidth
*mmi\ptMinTrackSize\y=#MinHeight
EndSelect
ProcedureReturn Result
EndProcedure
;START RECORDER
If GUI_Init()
CONFIG_Load()
CAPTURE_Start()
Repeat
Until WaitWindowEvent() = #WM_CLOSE Or QuitRec
CAPTURE_Stop()
Else
MessageRequester("Error", "Unable to initialize GUI.") ;chris319 6/7/12
End
EndIf