Page 1 of 2
PlaySound with a 20KHz file produces sound ?!
Posted: Fri Jan 09, 2026 7:59 am
by escape75
I'm playing around with a 20000Hz wave file that should not be heard (and it's not heard when using Windows Media Player)
but when I play back from PureBasic it produces a sound that I believe is around 8KHz more or less ...
InitSound()
CatchSound(#Sound, ?Sound)
PlaySound(#Sound)
What am I doing wrong ...
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Fri Jan 09, 2026 9:39 am
by Skipper
Are these three lines all the code you're using?
Can you upload the WAV-file here?
What platform are you on and which version of PureBasic are you using?
cheers
Skipper
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 1:00 am
by escape75
Here's the complete code:
Code: Select all
EnableExplicit
Enumeration 100
#Window
#Timer
#Sound
EndEnumeration
OpenWindow(#Window, 0, 0, 300, 200, "20000Hz Sound", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
If InitSound()
CatchSound(#Sound, ?Sound)
PlaySound(#Sound)
AddWindowTimer(#Window, #Timer, 5000)
EndIf
Repeat
Define Event = WaitWindowEvent(250)
If Event = #PB_Event_Timer And EventTimer() = #Timer
PlaySound(#Sound)
EndIf
Until Event = #PB_Event_CloseWindow
DataSection
Sound:
IncludeBinary "20000.wav"
EndDataSection
It's Windows 11 64bit with PureBasic 6.21
I'm including the link to the wave file below:
https://gofile.io/d/Koc4zZ
Thanks!
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 1:47 am
by idle
without wav, I can still hear lower frequencies though?
Code: Select all
EnableExplicit
InitSound()
Structure RIFFStructure
Riff.a[4]
Length.l
Wave.a[4]
EndStructure
Structure fmtStructure
fmt.a[4]
Length.l
Format.u
Channels.u
SampleRate.l
BytesPerSecond.l
BlockAlign.u
BitsPerSample.u
EndStructure
Structure dataStructure
Signature.a[4]
Length.l
EndStructure
Procedure.i CreateSound(Sound.i, Duration.i, Bits.i=16, Channels.i=2, SamplingRate.i=44100,frequency=500)
Protected.i Result, HeaderSize, DataSize, samples,sample,time.f,tone.u
Protected *WAVBuffer, *RiffPtr.RIFFStructure, *fmtPtr.fmtStructure, *dataPtr.dataStructure, *audioPtr.Unicode
HeaderSize = SizeOf(RIFFStructure)
HeaderSize + SizeOf(fmtStructure)
HeaderSize + SizeOf(dataStructure)
DataSize = (Bits / 8) * SamplingRate * Duration * Channels / 1000
samples = (DataSize / 2 / 2) - 1
*WAVBuffer = AllocateMemory(HeaderSize + DataSize, #PB_Memory_NoClear)
If *WAVBuffer
*RiffPtr = *WAVBuffer
PokeS(@*RiffPtr\Riff, "RIFF", 4, #PB_Ascii|#PB_String_NoZero)
*RiffPtr\Length = HeaderSize + DataSize - 8
PokeS(@*RiffPtr\Wave, "WAVE", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr = *WAVBuffer + SizeOf(RIFFStructure)
PokeS(@*fmtPtr\fmt, "fmt ", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr\Length = SizeOf(fmtStructure) - 8
*fmtPtr\Format = 1
*fmtPtr\Channels = Channels
*fmtPtr\SampleRate = SamplingRate
*fmtPtr\BitsPerSample = Bits
*fmtPtr\BlockAlign = *fmtPtr\Channels * ((*fmtPtr\BitsPerSample + 7) / 8)
*fmtPtr\BytesPerSecond = *fmtPtr\SampleRate * *fmtPtr\BlockAlign
*dataPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure)
PokeS(@*dataPtr\Signature, "data", 4, #PB_Ascii|#PB_String_NoZero)
*dataPtr\Length = DataSize
*audioPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure)
For sample = 0 To samples
time = sample / SamplingRate * 8
tone = Sin(time * frequency) * 32767
*audioPtr\u= tone
*audioPtr+2
*audioPtr\u = tone
*audioPtr+2
Next
Result = CatchSound(Sound, *WAVBuffer)
FreeMemory(*WAVBuffer)
EndIf
ProcedureReturn Result
EndProcedure
CreateSound(0,1000,16,2,44100,20000)
PlaySound(0)
Delay(1000)
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 1:52 am
by escape75
Interesting, thanks!!
Does the above also produce an audible sound for you? ... It does for me ...
At 20KHz it should be silent

Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 2:01 am
by idle
Yes it does sound like it's aliasing. You need twice the sampling rate to play back a sound so it should work.
try with 96k
Code: Select all
CreateSound(0,1000,16,2,96000,20000)
PlaySound(0)
Delay(1000)
edit
testing it in my morse decoder at 20k it works and that uses a Goertzel function which is centered around 20k I can't hear it but it decodes the message.
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 6:04 am
by escape75
When I do:
CreateSound(0,1000,16,2,96000,20000)
I can still hear it a little, so it's not 20KHz for sure, hmm!
--------------
It's interesting that this also keeps changing the playback every few seconds, like it keeps adding in more frequencies:
CreateSound(0,10000,16,2,96000,20000)
PlaySound(0)
Delay(10000)
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 10:56 am
by infratec
You need an oszilloscope to check it.
If it is not 100% sine wave, you can hear the generated subfrequencies.
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 9:36 pm
by Skipper
infratec wrote: Sat Jan 10, 2026 10:56 am
You need an oszilloscope to check it.
If it is not 100% sine wave, you can hear the generated subfrequencies.
Yes, I agree. I also agree with Idle about sampling rate requirements. Search for "Nyquist frequency".
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 10:04 pm
by idle
It was aliasing, the problem was the calculation for the tone, changing time to a double fixed it.
Code: Select all
EnableExplicit
InitSound()
Structure RIFFStructure
Riff.a[4]
Length.l
Wave.a[4]
EndStructure
Structure fmtStructure
fmt.a[4]
Length.l
Format.u
Channels.u
SampleRate.l
BytesPerSecond.l
BlockAlign.u
BitsPerSample.u
EndStructure
Structure dataStructure
Signature.a[4]
Length.l
EndStructure
Procedure.i CreateSound(Sound.i, Duration.i, Bits.i=16, Channels.i=2, SamplingRate.i=44100,frequency=500)
Protected.i Result, HeaderSize, DataSize, samples,sample,time.d,tone.u
Protected *WAVBuffer, *RiffPtr.RIFFStructure, *fmtPtr.fmtStructure, *dataPtr.dataStructure, *audioPtr.Unicode
HeaderSize = SizeOf(RIFFStructure)
HeaderSize + SizeOf(fmtStructure)
HeaderSize + SizeOf(dataStructure)
DataSize = (Bits / 8) * SamplingRate * Duration * Channels / 1000
samples = (DataSize / 2 / 2) - 1
*WAVBuffer = AllocateMemory(HeaderSize + DataSize, #PB_Memory_NoClear)
If *WAVBuffer
*RiffPtr = *WAVBuffer
PokeS(@*RiffPtr\Riff, "RIFF", 4, #PB_Ascii|#PB_String_NoZero)
*RiffPtr\Length = HeaderSize + DataSize - 8
PokeS(@*RiffPtr\Wave, "WAVE", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr = *WAVBuffer + SizeOf(RIFFStructure)
PokeS(@*fmtPtr\fmt, "fmt ", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr\Length = SizeOf(fmtStructure) - 8
*fmtPtr\Format = 1
*fmtPtr\Channels = Channels
*fmtPtr\SampleRate = SamplingRate
*fmtPtr\BitsPerSample = Bits
*fmtPtr\BlockAlign = *fmtPtr\Channels * ((*fmtPtr\BitsPerSample + 7) / 8)
*fmtPtr\BytesPerSecond = *fmtPtr\SampleRate * *fmtPtr\BlockAlign
*dataPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure)
PokeS(@*dataPtr\Signature, "data", 4, #PB_Ascii|#PB_String_NoZero)
*dataPtr\Length = DataSize
*audioPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure)
For sample = 0 To samples
time = sample / SamplingRate * 8
tone = Sin(time * frequency) * 32767
*audioPtr\u= tone
*audioPtr+2
*audioPtr\u = tone
*audioPtr+2
Next
Result = CatchSound(Sound, *WAVBuffer)
FreeMemory(*WAVBuffer)
EndIf
ProcedureReturn Result
EndProcedure
CreateSound(0,10000,16,2,96000,20000)
PlaySound(0)
Delay(10000)
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 10:08 pm
by escape75
I'm less so concerned with how accurate the sound playback is, although clearly there's some re-samplig going on here ...
But what I'm trying to do is send a 20KHz sound to speakers to wake them up, I found and modified the following code, but I feel like there's a better way of doing this and compressing the code further:
Code: Select all
EnableExplicit
Define T,i, *P, *OutBufMem
Global Volume.d = 0.00002
Global Up = #True
Enumeration 100
#Window
EndEnumeration
Declare WinCallback(hwnd, uMsg, wParam, lParam)
Declare MAKE_WAVE(*SBuf)
Global SampleClock = 44100
Global BlockSize = 8192
Global BytesPerSample = 2
Global Channels = 2
Global nBuf = 8
Global Frequency = 2000
Global hWaveOut
Global NumOutDevs
Global PlayFormat.WAVEFORMATEX
Global Dim outHdr.WAVEHDR(nBuf)
Procedure WinCallback(hwnd, uMsg, wParam, lParam)
Static *hWaveO.WAVEHDR
Select uMsg
Case #MM_WOM_DONE
If Volume > 0
*hWaveO.WAVEHDR = lParam
MAKE_WAVE(*hWaveO\lpData)
*hWaveO\dwBytesRecorded = BlockSize
waveOutWrite_(hWaveOut,lParam, SizeOf(WAVEHDR))
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure MAKE_WAVE(*SBuf)
Static.d Angle, K, La, Ra
Static.i sample
Static.l Vl, Vr
K = (2*#PI) * Frequency / SampleClock
sample = 1
Repeat
If Volume < 0.9 And Up = #True
Volume = Volume + 0.00002
Else
Up = #False
EndIf
If Volume > 0 And Up = #False
Volume = Volume - 0.00002
EndIf
Vl = Sin(La) * 32767 * Volume
La + K
If La > (2*#PI) : La - (2*#PI) : EndIf
PokeW(*SBuf,Vl)
*SBuf + BytesPerSample
Vr = Sin(Ra) * 32767 * Volume
Ra + K
If Ra > (2*#PI) : Ra - (2*#PI) : EndIf
PokeW(*SBuf,Vr)
*SBuf + BytesPerSample
sample + PlayFormat\nBlockAlign
Until sample > BlockSize
EndProcedure
OpenWindow(#Window,0,0,300,200,"Generator", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
SetWindowCallback(@WinCallback(), #Window)
With PlayFormat
\wFormatTag = #WAVE_FORMAT_PCM
\nChannels = Channels
\wBitsPerSample = BytesPerSample * 8
\nSamplesPerSec = SampleClock
\nBlockAlign = Channels * BytesPerSample
\nAvgBytesPerSec = \nSamplesPerSec * \nBlockAlign
EndWith
If *OutBufMem : FreeMemory(*OutBufMem) : EndIf
*OutBufMem = AllocateMemory(BlockSize * nBuf)
waveOutOpen_(@hWaveOut, #WAVE_MAPPER, @PlayFormat, WindowID(#Window), #True, #CALLBACK_WINDOW | #WAVE_FORMAT_DIRECT)
*P = *OutBufMem
For i = 0 To nBuf-1
outHdr(i)\lpData = *P
outHdr(i)\dwBufferLength = BlockSize
outHdr(i)\dwFlags = 0
outHdr(i)\dwLoops = 0
waveOutPrepareHeader_(hWaveOut, outHdr(i), SizeOf(WAVEHDR))
*P + BlockSize
Next
For i = 0 To nBuf-1
PostMessage_(WindowID(#Window),#MM_WOM_DONE,0,outHdr(i))
Next
Repeat
Define Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow Or Volume <= 0
waveOutReset_(hWaveOut)
For i = 0 To nBuf-1
waveOutUnprepareHeader_(hWaveOut, outHdr(i), SizeOf(WAVEHDR))
Next
waveOutClose_(hWaveOut)
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sat Jan 10, 2026 10:21 pm
by idle
Can you explain that a bit more, I'm not sure what you mean by wake up your speakers?
I was thinking more along the lines of air gapping like advertisers used to do or maybe still do by using in audible frequencies to tag what your watching on TV, so a listening device would id and tag and trace the user.
The code I posted above is working now though it DB level is very low not sure if that's just my recording settings though.
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sun Jan 11, 2026 4:43 am
by escape75
I have a friend who has a speaker that goes to sleep when there's no audio activity for a bit, and that setting cannot be disabled.
It actually takes a fairly long time to wake up as well which is annnoying, so I figured sending a short inaudible tone once a minute would fix that

Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sun Jan 11, 2026 5:01 am
by idle
I'm guessing the speakers are wireles, I haven't encountered speakers going to sleep before but if it works great.
Re: PlaySound with a 20KHz file produces sound ?!
Posted: Sun Jan 11, 2026 6:10 am
by escape75
I think they are actually plugged in via analog input
I have a question about this line:
I've seen it also done this way, just wondering which way is correct:
I have added smooth volume increase in the code to make it not pop, as well as added so it plays for a duration of 1 second every 60 seconds, and then every 5 seconds when the computer wakes up from sleep 6 times in a row ... the reason for this is I haven't been able to figure out when the sound system gets ready after wake up ... as the program starts playing back on the lock screen and no sound is actually played!
Also an interesting issue I found is that when you do a mono sound, you can actually hear a faint sound:
CreateSound(#Sound,1000,16,1,96000,20000)
*Edit* I modifed the code to fix the mono issue (I think)
Here's my updated code:
Code: Select all
EnableExplicit
Enumeration 100
#Window
#Timer
#Sound
EndEnumeration
Global Counter = -1
Structure RIFFStructure
ChunkID.a[4]
ChunkSize.l
Format.a[4]
EndStructure
Structure fmtStructure
Subchunk1ID.a[4]
Subchunk1Size.l
AudioFormat.u
NumChannels.u
SampleRate.l
ByteRate.l
BlockAlign.u
BitsPerSample.u
EndStructure
Structure dataStructure
Subchunk2ID.a[4]
Subchunk2Size.l
EndStructure
Procedure ErrorHandler()
Define ErrorMessage$ = ErrorMessage() + "(" + ErrorLine() + ")"
MessageRequester("Program Error", ErrorMessage$)
End
EndProcedure
OnErrorCall(@ErrorHandler())
Procedure FixSysTrayIcon(hWnd, uMsg, wParam, lParam)
If uMsg = #WM_POWERBROADCAST And wParam = #PBT_APMRESUMESUSPEND
RemoveWindowTimer(#Window, #Timer)
AddWindowTimer(#Window, #Timer, 5000)
Counter = 5
EndIf
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure.i CreateSound(Sound, Duration, BitsPerSample, NumChannels, SamplingRate, Frequency)
Protected.i Result, HeaderSize, DataSize, Samples, Sample, Time.d, Tone.u, NumChannel
Protected *WAVBuffer, *RiffPtr.RIFFStructure, *fmtPtr.fmtStructure, *dataPtr.dataStructure, *audioPtr
HeaderSize = SizeOf(RIFFStructure)
HeaderSize + SizeOf(fmtStructure)
HeaderSize + SizeOf(dataStructure)
DataSize = (BitsPerSample/8) * SamplingRate * Duration * NumChannels / 1000
Samples = (DataSize / 2 / NumChannels) - 1
*WAVBuffer = AllocateMemory(HeaderSize + DataSize, #PB_Memory_NoClear)
If *WAVBuffer
*RiffPtr = *WAVBuffer
PokeS(@*RiffPtr\ChunkID, "RIFF", 4, #PB_Ascii|#PB_String_NoZero)
*RiffPtr\ChunkSize = HeaderSize + DataSize - 8
PokeS(@*RiffPtr\Format, "WAVE", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr = *WAVBuffer + SizeOf(RIFFStructure)
PokeS(@*fmtPtr\Subchunk1ID, "fmt ", 4, #PB_Ascii|#PB_String_NoZero)
*fmtPtr\Subchunk1Size = SizeOf(fmtStructure) - 8
*fmtPtr\AudioFormat = 1
*fmtPtr\NumChannels = NumChannels
*fmtPtr\SampleRate = SamplingRate
*fmtPtr\BlockAlign = *fmtPtr\NumChannels * (*fmtPtr\BitsPerSample/8)
*fmtPtr\ByteRate = *fmtPtr\SampleRate * *fmtPtr\BlockAlign
*fmtPtr\BitsPerSample = BitsPerSample
*dataPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure)
PokeS(@*dataPtr\Subchunk2ID, "data", 4, #PB_Ascii|#PB_String_NoZero)
*dataPtr\Subchunk2Size = DataSize
*audioPtr = *WAVBuffer + SizeOf(RIFFStructure) + SizeOf(fmtStructure) + SizeOf(dataStructure)
Define Steps.d = 0.9 / (Samples*0.25)
Define Volume.d = 0.0
For Sample = 0 To Samples
If Sample < (Samples*0.25)
Volume + Steps
EndIf
If Sample > (Samples*0.75)
Volume - Steps
EndIf
Time = Sample / SamplingRate * 8
Tone = Sin(Time * Frequency) * 32767 * Volume
For NumChannel = 1 To NumChannels
PokeU(*audioPtr, Tone)
*audioPtr + 2
Next
Next
Result = CatchSound(Sound, *WAVBuffer)
FreeMemory(*WAVBuffer)
EndIf
ProcedureReturn Result
EndProcedure
OpenWindow(#Window, 0, 0, 300, 200, "20000Hz Sound", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
If InitSound()
CreateSound(#Sound, 1000, 16, 2, 96000, 20000)
PlaySound(#Sound)
AddWindowTimer(#Window, #Timer, 60000)
SetWindowCallback(@FixSysTrayIcon(), #Window)
EndIf
Repeat
Define Event = WaitWindowEvent(250)
If Event = #PB_Event_Timer And EventTimer() = #Timer
PlaySound(#Sound)
If Counter = 0
RemoveWindowTimer(#Window, #Timer)
AddWindowTimer(#Window, #Timer, 60000)
EndIf
If Counter > -1
Counter = Counter - 1
EndIf
EndIf
Until Event = #PB_Event_CloseWindow