|
Post by honkytonk on Aug 18, 2022 16:21:35 GMT
Yes, I understand that we have to create a clock to have a time base. I think I'll just count the ticks in "Audacity". Saving sound to a file is too difficult for me.
|
|
|
Post by Rod on Aug 18, 2022 17:30:08 GMT
It would be nice to better understand the project. Over what time scale do you plan to monitor the blips.
|
|
|
Post by honkytonk on Aug 19, 2022 7:39:18 GMT
It would be nice to better understand the project. Over what time scale do you plan to monitor the blips. The duration is not important because it is a ratio (Number of ticks / Time), which can be managed by a "rule of three", or "cross product". By convention, we test for one minute. I study ".wav", which is only simple for those who have studied it for a long time.
|
|
|
Post by Rod on Aug 19, 2022 12:09:41 GMT
Playing a bit more. I recorded the .wav to my phone and played it back to the software. This code samples at 16ms and averages 4 samples then charts it.
The challenge is that the blip seems to last 24ms, not long. So live sampling really needs to run at 12ms to be sure it "sees" the blip. Experiment and see how it works on the real kit. Does it detect all blips or miss a few?
I suspect what we need to do is capture a .wav every minute, then analyse the .wav. This will avoid the sample timing issue though we still have to reliably find the blips in the .wav
If anyone is interested the .wav I posted and the code I posted to break it apart is all you need to find an algorythm to find the blips.
I think the whole lot can be done cyclically and so give minute reading all day. So that's my plan now , capture an 8bit .wav, analyse and repeat.
'experimental Radiometer by rodbird@hotmail.com 'uses MMI to stream audio from Mic '8bit audio is set for faster parsing 'blips from giger counter are heard but 'need parsed, recorded and displayed 'currently samples at 16ms and averages 4 samples '480000 samples in 60000ms so 8 samples per ms 'a blip seems to last 24ms so really we should sample at 12ms
nomainwin WindowWidth = 1000 WindowHeight = 400 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2) graphicbox #1.bar, 23, 50, 950, 256 open "Radiometer" for window_nf as #1 #1.bar "down; fill white; flush" #1.bar "backcolor green" #1 "trapclose [quit]"
[startRecording] 'set the .wav recording format bitspersample = 4 channels = 1 samplespersec = 8000 alignment = bitspersample * channels / 8 bytespersec = alignment * samplespersec
params$ = " bitspersample " + STR$(bitspersample)+_ " channels " + STR$(channels) +_ " alignment " + STR$(alignment) + _ " samplespersec " + STR$(samplespersec) + _ " bytespersec " + STR$(bytespersec)
'open wav audio to listen to the wavaudio r$=mciSendString$("open new type waveaudio alias wav") r$=mciSendString$("set wav "+params$)
#1.bar "down ; fill white" average=8 count=average timer 16, [readVolume] wait
[readVolume] r$=mciSendString$("status wav level") level = val(r$) 'print level alevel=alevel+level count=count-1 if count=0 then level=alevel/average #1.bar "place ";posx;" ";256;" ; line ";posx;" ";256;" ";posx;" ";256-level posx=posx+1 alevel=0 count=average end if wait
[quit] 'End the program timer 0 r$=mciSendString$("close wav") close #1 end
Function mciSendString$(s$) 'Buffer will contain a return string from 'the function, if there is one. buffer$=space$(1024)+chr$(0) calldll #winmm,"mciSendStringA",s$ as ptr,buffer$ as ptr,_ 1028 as long, 0 as long, r as long 'truncate returned string at null character buffer$=left$(buffer$, instr(buffer$, chr$(0)) - 1) if r>0 then mciSendString$="error" else mciSendString$=buffer$ end if End Function
|
|
|
Post by honkytonk on Aug 19, 2022 13:38:32 GMT
I modified your "Viewer" -->: libertybasiccom.proboards.com/thread/2073/listening-microphone?page=1&scrollTo=14865it works perfectly, I have a radio-source to set the threshold. 15 to 30 in function charge batterie 'experimental Radiometer by rodbird@hotmail.com 'uses MMI to stream audio from Mic '8bit audio is set for faster parsing 'blips from giger counter are heard but 'need parsed, recorded and displayed 'currently samples at 50ms nomainwin WindowWidth = 450: WindowHeight = 230 UpperLeftX=20: UpperLeftY=100 button #1.start, "Start", [start], UL, 30, 20, 70, 25 '************ statictext #1.txt, "0", 130, 20, 70, 25 '*********** button #1.stop, "Stop", [stop], UL, 230, 20, 70, 25 '************ button #1.rest, "Restart", [rest], UL, 330, 20, 70, 25 '************ statictext #1.t, "Waiting", 30, 120, 70, 25 '*********** graphicbox #1.bar, 23, 70, 400, 20 open "Radiometer" for window_nf as #1 #1.bar "down; fill white; flush" #1.bar "backcolor green" #1 "trapclose [quit]" #1, "font courrier 12 bold" '********** dim count(500) '**************** wait [stop] sto=1: wait [rest] sto=0: wait [start] '************* ta= time$("milliseconds") #1.t, "Started" [startRecording] 'set the .wav recording format bitspersample = 8 channels = 1 samplespersec = 8000 alignment = bitspersample * channels / 8 bytespersec = alignment * samplespersec params$ = " bitspersample " + STR$(bitspersample)+_ " channels " + STR$(channels) +_ " alignment " + STR$(alignment) + _ " samplespersec " + STR$(samplespersec) + _ " bytespersec " + STR$(bytespersec) 'open wav audio to listen to the wavaudio r$=mciSendString$("open new type waveaudio alias wav") r$=mciSendString$("set wav "+params$) timer 50, [readVolume] '()()()()() wait [readVolume] #1.bar "discard ; backcolor white" #1.bar "boxfilled 400 25 ; backcolor green" r$=mciSendString$("status wav level") level = val(r$) if sto=1 then timer 0: wait ' print level''''''''''''''''' if level > 18 then '*********** c=c+1: count(c)=c '************ #1.txt, str$(c) '************ end if '**************** #1.bar "boxfilled ";(level^1.25);" 20; discard" tb= time$("milliseconds") if tb-ta > 60000 then timer 0 #1.t, "END" wait end if print tb-ta'********* wait '-------------- Function mciSendString$(s$) 'Buffer will contain a return string from 'the function, if there is one. buffer$=space$(1024)+chr$(0) calldll #winmm,"mciSendStringA",s$ as ptr,buffer$ as ptr,_ 1028 as long, 0 as long, r as long 'truncate returned string at null character buffer$=left$(buffer$, instr(buffer$, chr$(0)) - 1) if r>0 then mciSendString$="error" else mciSendString$=buffer$ end if End Function [quit] 'End the program timer 0 r$=mciSendString$("close wav") close #1 end
|
|
|
Post by marshawn on Aug 23, 2022 2:12:06 GMT
I added about 10 lines to Rod's wave analysis program. ( I included saving the amplitude as a csv file- which loads into a spreadsheet, but the OpenOffice spreadsheet was very slow in displaying this long file. Bit of a dead end) You certainly need to average the bursts of sound- I used calculating absolute values and averaging each new value with the three previous ones. This show the +/- waves made unidirectional with 'abs('. .. and this show the smoothed result which is now easier to analyse. which 8 bit wav file and which JB code must I enter to see this image on screen
|
|
|
Post by Rod on Aug 23, 2022 10:24:53 GMT
gamebin.webs.com/son3.wavAbove is the link to the 8bit .wav file. Below is some basic code to open it. filedialog "Open wav file", "*.wav", fileName$ open fileName$ for input as #wav 'the wavfileheader wav$ = Input$(#wav,lof(#wav)) print "ChunkID =";mid$(wav$,1,4) 'always RIFF print "ChunkSize =";value(mid$(wav$,5,4)) print "Format =";mid$(wav$,9,4) print "Sub1ID =";mid$(wav$,13,4) print "Sub1Size =";value(mid$(wav$,17,4)) print "AudioFormat =";value(mid$(wav$,21,2)) print "NumChannels =";value(mid$(wav$,23,2)) print "SampleRate =";value(mid$(wav$,25,4)) print "ByteRate =";value(mid$(wav$,29,4)) print "BlockAlign =";value(mid$(wav$,33,2)) print "bitPerSample=";value(mid$(wav$,35,2)) print "Sub2ID =";mid$(wav$,37,4) print "Sub2Size =";value(mid$(wav$,41,4)) print print "Sound Data" for n= 0 to 20 print value(mid$(wav$,45+n,1)) next wait
function value(x$) select case len(x$) case 1 value = asc(x$) case 2 value=asc(mid$(x$,1,1)) value=value+(asc(mid$(x$,2,1))*256) case 4 value=asc(mid$(x$,1,1)) value=value+(asc(mid$(x$,2,1))*256) value=value+(asc(mid$(x$,3,1))*65536) value=value+(asc(mid$(x$,4,1))*16777216) end select end function
Now there is no charting code but there lots of examples to search out. It’s very straightforward, the file contains a header of 44 bytes long then following, 480000 bytes of audio data. 8000 samples every second, one minute of audio. They .wav uses 127 as the mid position 0 as lowest value and 255 as highest value. Essentially 127 is silence with values above or below pulling or pushing the speaker diaphragm. The pings appear to be 24ms long, have a sharp initial peak and a small following envelope. There are I think 28 pings in the sample. Away from home and my pc otherwise I would post some charting code but there are several charting demos to look at. Of course it is the ping count we really need, the chart is just eye candy.
|
|
|
Post by tenochtitlanuk on Aug 23, 2022 22:26:54 GMT
marshawn See zip file at link
|
|
|
Post by Rod on Aug 26, 2022 10:18:11 GMT
Back at my PC, this is some charting code added to my original code. Change the number to average to see more or less granularity. Packing 480000 data points into 1000 pixels inevitably loses something. 'nomainwin WindowWidth = 1040 WindowHeight = 500 graphicbox #scope.graph, 15, 20, 1000, 256 open "Analyse Audio" for window_nf as #scope rem Set up the initial graphics and make them stick with flush so that we can recall the initial screens-------------------- print #scope.graph, "down" for y= 255 to 0 step -2 print #scope.graph, "color ";y/2+100;" ";y/2+100;" ";y/2+100 print #scope.graph, "line 0 ";y;" ";"950 ";y print #scope.graph, "line 0 ";y-1;" ";"950 ";y-1 next y print #scope.graph, "color yellow" print #scope.graph, "line 0 127 950 127" print #scope.graph, "flush"
filedialog "Open wav file", "*.wav", fileName$ open fileName$ for input as #wav l=lof(#wav) wav$ = Input$(#wav,l) 'the wavfileheader
print "ChunkID =";mid$(wav$,1,4) 'always RIFF print "ChunkSize =";value(mid$(wav$,5,4)) print "Format =";mid$(wav$,9,4) print "Sub1ID =";mid$(wav$,13,4) print "Sub1Size =";value(mid$(wav$,17,4)) print "AudioFormat =";value(mid$(wav$,21,2)) print "NumChannels =";value(mid$(wav$,23,2)) print "SampleRate =";value(mid$(wav$,25,4)) print "ByteRate =";value(mid$(wav$,29,4)) print "BlockAlign =";value(mid$(wav$,33,2)) print "bitPerSample=";value(mid$(wav$,35,2)) print "Sub2ID =";mid$(wav$,37,4) print "Sub2Size =";value(mid$(wav$,41,4))
numberToAverage=506 '480000/950 samples/pixel width of chart av=numberToAverage [chart] xpos=0 print #scope.graph, "discard ; redraw ; color red" for byte = 46 to l y=asc(mid$(wav$,byte,1)) if y<127 then al=al+y else ah=ah+y end if av=av-1 if av=0 then al=al/numberToAverage ah=ah/numberToAverage print #scope.graph, "line ";xpos;" ";127;" ";xpos;" ";al+127 print #scope.graph, "line ";xpos;" ";127;" ";xpos;" ";ah xpos=xpos+1 av=numberToAverage al=0 ah=0 end if next wait
[quit] close #scope end
function value(x$) select case len(x$) case 1 value = asc(x$) case 2 value=asc(mid$(x$,1,1)) value=value+(asc(mid$(x$,2,1))*256) case 4 value=asc(mid$(x$,1,1)) value=value+(asc(mid$(x$,2,1))*256) value=value+(asc(mid$(x$,3,1))*65536) value=value+(asc(mid$(x$,4,1))*16777216) end select end function
|
|
|
Post by marshawn on Nov 9, 2022 3:12:08 GMT
nice, I see it opens the file well. is there any way to also write a WAV file using that program, for example, make a copy of son3.wav but make the first second of the file silent
|
|
|
Post by Rod on Nov 9, 2022 8:19:18 GMT
To write a .wav file we just write the header and then append the sound data. If the sound format is not changing then the only thing in the header that changes is the data size and file length. To add one second of silence you would append 8000 bytes of sound data, all set to mid point (127) .then append the original sound data.
This code might point you in the right direction.
'This program lets you create little sound samples 'It uses 8000 samples per second, 8 bits per sample 'and mono sound.
'One second of sound will use 8000 bytes, each 'byte represents the volume of the sound at any 'point in time. (0-255) The changing volume creates 'the frequency of the sound you hear.
'0 pulls the speaker 255 pushes the speaker 127 is mid 'positiuon, a series of 127s would produce silence.
'The sound can be left pure or modulated by another 'tone
'program variables true=1 false=0 dim hz$(12) dim mhz$(12) hz$(0)="55.000(A)" hz$(1)="58.270(A#)" hz$(2)="61.735(B)" hz$(3)="65.406(C)" hz$(4)="69.296(C#)" hz$(5)="73.416(D)" hz$(6)="77.782(D#)" hz$(7)="82.407(E)" hz$(8)="87.307(F)" hz$(9)="92.499(F#)" hz$(10)="97.999(G)" hz$(11)="103.826(G#)" hz$(12)="110.000(A)" mhz$(0)="130.813(C)" mhz$(1)="261.626(C)" mhz$(2)="523.251(C)" mhz$(3)="1046.502(C)" wv$(0)="Sine" wv$(1)="Square" wv$(2)="Saw Tooth" wv$(3)="Triangular" mwv$(0)="Sine" mwv$(4)="None" vo$(0)="10%" vo$(1)="20%" vo$(2)="30%" vo$(3)="40%" vo$(4)="50%" vo$(5)="60%" vo$(6)="70%" vo$(7)="80%" vo$(8)="90%" vo$(9)="100%" mvo$(0)="10%" mvo$(1)="20%" mvo$(2)="30%" mvo$(3)="40%" mvo$(4)="50%" mvo$(5)="60%" mvo$(6)="70%" mvo$(7)="80%" mvo$(8)="90%" mvo$(9)="100%" du$(0)="100ms" du$(1)="500ms" du$(2)="1000ms" du$(3)="5000ms"
'open our window nomainwin WindowWidth = 600 WindowHeight = 500 UpperLeftX = int((DisplayWidth-WindowWidth)/2) UpperLeftY = int((DisplayHeight-WindowHeight)/2) graphicbox #scope.graph, 50, 20, 500, 300 statictext #scope.hz, "Hertz" ,125, 360,80,20 combobox #scope.hz, hz$(),[hertz],125,380,80,20 combobox #scope.mhz,mhz$(),[mhertz],125,420,80,20 statictext #scope.wv, "Wave Form" ,225, 360,80,20 combobox #scope.wv, wv$(),[wave],225,380,80,20 combobox #scope.mwv,mwv$(),[mwave],225,420,80,20 statictext #scope.vo, "Volume" ,325, 360,80,20 combobox #scope.vo, vo$(),[volume],325,380,80,20 combobox #scope.mvo,mvo$(),[modvol],325,420,80,20 statictext #scope.du, "Duration" ,420, 360,80,20 combobox #scope.du, du$(),[duration],420,380,80,20 button #scope.save, "Save",[save],UL,125,325 button #scope.play, "Play",[play],UL,225,325 button #scope.loop, "Loop",[repeat],UL,325,325 button #scope.stop, "Stop",[stop],UL,425,325 open "Tone Generator" for window_nf as #scope
'draw the scope background and flush it print #scope, "trapclose [quit]" print #scope.graph, "down" for y= 300 to 0 step -2 print #scope.graph, "color ";y/2+100;" ";y/2+100;" ";y/2+100 print #scope.graph, "line 0 ";y;" ";"500 ";y print #scope.graph, "line 0 ";y-1;" ";"500 ";y-1 next y print #scope.graph, "color yellow" print #scope.graph, "line 0 150 500 150" print #scope.graph, "flush"
'set the initial combobox data print #scope.hz, "select 55.000(A)" hertz=55 print #scope.wv, "select Sine" wave$="Sine" print #scope.vo, "select 100%" volume=1 print #scope.du, "select 1000ms" duration=1 print #scope.mhz, "select 261.626(C)" mhertz=261.626 print #scope.mwv, "select Sine" mwave$="Sine" print #scope.mvo, "select 10%" modvol=.1 gosub [chart]
'now wait for user input wait
' button and combobox handlers [hertz] print #scope.hz, "contents? text$" hertz=val(text$) gosub [chart] wait
[mhertz] print #scope.mhz, "contents? text$" mhertz=val(text$) gosub [chart] wait
[wave] print #scope.wv, "contents? wave$" gosub [chart] wait
[mwave] print #scope.mwv, "contents? mwave$" gosub [chart] wait
[volume] print #scope.vo, "contents? text$" volume=val(text$)/100 gosub [chart] wait
[modvol] print #scope.mvo, "contents? text$" modvol=val(text$)/100 gosub [chart] wait
[duration] print #scope.du, "contents? text$" duration=val(text$)/1000 gosub [chart] wait
[stop] playwave "" repeat=false wait
[save] filedialog "Save As...", "*.wav", fileName$ open fileName$ for output as #t print #t, header$ print #t, tone$ close #t wait
[repeat] repeat=true ' now drop down to [play]
[play] 'create the .wav file header samplesPerSecond=8000 channels=1 'mono bitsPerSample=8 blockAlign=(bitsPerSample*channels)/8 bytesPerSecond=blockAlign*samplesPerSecond
'this is the only element that changes in the header 'normally dataSize=bytesPerSecond*duration dataSize=len(tone$)
waveSize=dataSize+36 header$="" header$=header$+"RIFF" number=waveSize byte4=int(number/16777216) number=number-(byte4*16777216) byte3=int(number/65536) number=number-(byte3*65536) byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2)+chr$(byte3)+chr$(byte4) ' lof -8 header$=header$+"WAVE" header$=header$+"fmt " header$=header$+chr$(16)+chr$(0)+chr$(0)+chr$(0) ' fmt chunk length 16 bytes header$=header$+chr$(1)+chr$(0) ' pcm header$=header$+chr$(channels)+chr$(0) ' 1 = mono number=samplesPerSecond byte4=int(number/16777216) number=number-(byte4*16777216) byte3=int(number/65536) number=number-(byte3*65536) byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2)+chr$(byte3)+chr$(byte4) ' samples per second number=bytesPerSecond byte4=int(number/16777216) number=number-(byte4*16777216) byte3=int(number/65536) number=number-(byte3*65536) byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2)+chr$(byte3)+chr$(byte4) ' bytes per second number=blockAlign byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2) ' block align number=bitsPerSample byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2) ' bits per sample header$=header$+"data" number=dataSize byte4=int(number/16777216) number=number-(byte4*16777216) byte3=int(number/65536) number=number-(byte3*65536) byte2=int(number/256) byte1=number-(byte2*256) header$=header$+chr$(byte1)+chr$(byte2)+chr$(byte3)+chr$(byte4) ' number of data bytes
open "tone.wav" for output as #tone print #tone, header$ print #tone, tone$ close #tone if repeat then playwave "tone.wav", loop else playwave "tone.wav" end if wait
[chart] samplesPerSecond=8000 channels=1 'mono bitsPerSample=8 blockAlign=(bitsPerSample*channels)/8 bytesPerSecond=blockAlign*samplesPerSecond dataSize=bytesPerSecond*duration [createwavedata] tone$="" select case wave$
case "Sine" tone$="" degree=0 increment=360/(samplesPerSecond/hertz) for byte = 1 to dataSize degree=degree+increment if degree>359 then degree=0 ypos=(sin(degree/57.29577951)*128*volume)+128 t=int(ypos) tone$=tone$+chr$(t) next
case "Square" period=samplesPerSecond/hertz/2 counter=0 high=true for byte= 1 to dataSize if high then ypos=128+(128*volume) counter=counter+1 if counter>=period then high=false counter=0 end if else ypos=128-(128*volume) counter=counter+1 if counter>=period then high=true counter=0 end if end if t=int(ypos) if t<0 then t=0 if t>255 then t=255 tone$=tone$+chr$(t) next
case "Saw Tooth" period=samplesPerSecond/hertz increment=(256*volume)/period counter=0 ypos=128+128*volume for byte= 1 to dataSize if counter>=period then ypos=128+128*volume counter=0 end if ypos=ypos-increment counter = counter +1 t=int(ypos) if t<0 then t=0 if t>255 then t=255 tone$=tone$+chr$(t) next
case "Triangular" period=samplesPerSecond/hertz/2 increment=(256*volume)/period counter=0 ypos=128+128*volume high=true for byte= 1 to dataSize if high then ypos=ypos-increment counter=counter+1 if counter>=period then high=false counter=0 end if else ypos=ypos+increment counter=counter+1 if counter>=period then high=true counter=0 end if end if t=int(ypos) if t<0 then t=0 if t>255 then t=255 tone$=tone$+chr$(t) next
end select
[modulatewavedata] temp$=tone$ tone$="" select case mwave$
case "Sine" degree=0 increment=360/(samplesPerSecond/mhertz) for byte = 1 to dataSize degree=degree+increment if degree>359 then degree=0 ypos=(sin(degree/57.29577951)*128*modvol)+128 t=int(ypos) t=t+asc(mid$(temp$,byte,1))-128 if t<0 then t=0 if t>255 then t=255 tone$=tone$+chr$(t) next
case "None" tone$=temp$ temp$=""
end select
'graph the first 500 values from the file xpos=0 ypos=150 print #scope.graph, "discard ; redraw ; place 0 150" for byte = 1 to 500 ypos=asc(mid$(tone$,byte,1))+22 print #scope.graph, "color red ;goto ";xpos;" ";ypos xpos=xpos+1 next wait
[quit] close #scope end
' frequency chart of the musical scale
'0 A 55.000 110.000 220.000 440.000 880.000 1,760.000 '1 A#/Bb 58.270 116.541 233.082 466.164 932.328 1,864.655 '2 B 61.735 123.471 246.942 493.883 987.767 1,975.533 '3 C 65.406 130.813 261.626 523.251 1,046.502 2,093.005 '4 C#/Db 69.296 138.591 277.183 554.365 1,108.731 2,217.461 '5 D 73.416 146.832 293.665 587.330 1,174.659 2,349.318 '6 D#/Eb 77.782 155.563 311.127 622.254 1,244.508 2,489.016 '7 E 82.407 164.814 329.628 659.255 1,318.510 2,637.020 '8 F 87.307 174.614 349.228 698.456 1,396.913 2,793.826 '9 F#/Gb 92.499 184.997 369.994 739.989 1,479.978 2,959.955 '10 G 97.999 195.998 391.995 783.991 1,567.982 3,135.963 '11 G#/Ab 103.826 207.652 415.305 830.609 1,661.219 3,322.438 '12 A 110.000 220.000 440.000 880.000 1,760.000 3,520.000
|
|