Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
If we create a long sound using SOUND inside a loop, the loop ends quickly but the sound keeps on playing in the background.
So it seems that whenever the SOUND command is called, it just adds the current frequency/duration to a queue, which then keeps playing in the background, without holding up the code.
The problem I'm having is, how do you make it stop early?
If there is no command for this, then maybe it should be added?
The below program demonstrates the issue and the strange behavior I get when trying to stop the sound with different workarounds...
Any help appreciated!
Code: (Select All) ' Q: how do you stop a sound playing with the Sound command?
Const FALSE = 0
Const TRUE = Not FALSE
Dim iLoop As Integer
Dim in$
Dim bQuit As Integer
Do
bQuit = FALSE
Cls
Print "Start playing some sounds..."
' Quick ascending tone signals that we are starting
For iLoop = 400 To 500 Step 5: Sound iLoop, .3: Next iLoop
' Middle sound (goes on a long time, how to turn it off?)
For iLoop = 1 To 2000
Sound 25000 - (iLoop * 10), .1
Next iLoop
' Quick descending tone signals that we're done
For iLoop = 500 To 400 Step -5: Sound iLoop, .3: Next iLoop
Print "Finished generating sound."
Print
Print "Now, how do we stop it playing or clear the SOUND queue?"
Print
Print "WARNING: "
Print "Options 1-3 can cause program to freeze or act strangely!"
Print
_KeyClear: While InKey$ <> "": Wend ' Clear the keyboard buffer
Print "1. Try stopping the sound with SOUND 0,0"
Print "2. Try stopping the sound with SOUND 37,1"
Print "3. Try stopping the sound with BEEP"
Print "4. Play it again"
Print "5. Quit"
Print
Input "Your choice"; in$: in$ = LCase$(_Trim$(in$))
Do
If in$ = "1" Then
Sound 0, 0
ElseIf in$ = "2" Then
Sound 37, 1
ElseIf in$ = "3" Then
Beep
ElseIf in$ = "4" Then
bQuit = FALSE: Exit Do
ElseIf in$ = "5" Or in$ = "q" Then
bQuit = TRUE: Exit Do
End If
Loop
If bQuit = TRUE Then Exit Do
Loop
Posts: 2,180
Threads: 222
Joined: Apr 2022
Reputation:
104
Yeah, QB64 never did bring the SOUND(0, 0) along from QBasic. I mean if you are desperate, you could close the program and shell another instance, using a file to direct the new instance to a different part of the program. That file could also hold and put back any variables into the new instance.
If you run the code, be sure you understand the first line about the file it creates and what you have to name the file or change the SHELL name to get it to work when it gets compiled. Here's what I'm talking about...
Code: (Select All) ' Caution, this makes a file called blahblahblah.tmp. ALSO IMPORTANT: You must name and compile this file as untitled(9). or change to another name and use that name in the SHELL call.
IF _FILEEXISTS("blahblahblah.tmp") THEN KILL "blahblahblah.tmp": GOTO 101
' Q: how do you stop a sound playing with the Sound command?
CONST FALSE = 0
CONST TRUE = NOT FALSE
DIM iLoop AS INTEGER
DIM in$
DIM bQuit AS INTEGER
DO
bQuit = FALSE
CLS
PRINT "Start playing some sounds..."
' Quick ascending tone signals that we are starting
FOR iLoop = 400 TO 500 STEP 5: SOUND iLoop, .3: NEXT iLoop
' Middle sound (goes on a long time, how to turn it off?)
FOR iLoop = 1 TO 2000
SOUND 25000 - (iLoop * 10), .1
NEXT iLoop
' Quick descending tone signals that we're done
FOR iLoop = 500 TO 400 STEP -5: SOUND iLoop, .3: NEXT iLoop
PRINT "Finished generating sound."
PRINT
PRINT "Now, how do we stop it playing or clear the SOUND queue?"
PRINT
PRINT "WARNING: "
PRINT "Options 1-3 can cause program to freeze or act strangely!"
PRINT
PRINT "1. Try stopping the sound with SOUND 0,0"
PRINT "2. Try stopping the sound with SOUND 37,1"
PRINT "3. Try stopping the sound with BEEP"
PRINT "4. Play it again"
PRINT "5. Quit"
PRINT
DO
in$ = INKEY$
IF in$ = "1" THEN
OPEN "blahblahblah.tmp" FOR APPEND AS #1: CLOSE #1
SHELL _DONTWAIT "untitled(9).exe"
STOP
ELSEIF in$ = "2" THEN
SOUND 37, 1
ELSEIF in$ = "3" THEN
BEEP
END
ELSEIF in$ = "4" THEN
bQuit = FALSE: EXIT DO
ELSEIF in$ = "5" OR in$ = "q" THEN
bQuit = TRUE: EXIT DO
END IF
LOOP
IF bQuit = TRUE THEN EXIT DO
LOOP
101
PRINT "Ha! It worked!"
SLEEP
So the part that sucks is you momentarily lose your program window. I mean the whole approach sucks, but losing the window really sucks. Now if @Spriggsy swings by, he might know of a way using Windows API to kill the sound, but if you are on Linux, that won't help you.
@Dav works a lot with sound, but I don't know if he also works on Linux, or just Windows.
Hopefully someone else has a better idea than mine. It will work, but it's ugly.
Pete
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
(08-04-2022, 10:05 PM)Pete Wrote: Yeah, QB64 never did bring the SOUND(0, 0) along from QBasic. I mean if you are desperate, you could close the program and shell another instance, using a file to direct the new instance to a different part of the program. That file could also hold and put back any variables into the new instance.
If you run the code, be sure you understand the first line about the file it creates and what you have to name the file or change the SHELL name to get it to work when it gets compiled. Here's what I'm talking about...
Code: (Select All) ' Caution, this makes a file called blahblahblah.tmp. ALSO IMPORTANT: You must name and compile this file as untitled(9). or change to another name and use that name in the SHELL call.
IF _FILEEXISTS("blahblahblah.tmp") THEN KILL "blahblahblah.tmp": GOTO 101
' Q: how do you stop a sound playing with the Sound command?
CONST FALSE = 0
CONST TRUE = NOT FALSE
DIM iLoop AS INTEGER
DIM in$
DIM bQuit AS INTEGER
DO
bQuit = FALSE
CLS
PRINT "Start playing some sounds..."
' Quick ascending tone signals that we are starting
FOR iLoop = 400 TO 500 STEP 5: SOUND iLoop, .3: NEXT iLoop
' Middle sound (goes on a long time, how to turn it off?)
FOR iLoop = 1 TO 2000
SOUND 25000 - (iLoop * 10), .1
NEXT iLoop
' Quick descending tone signals that we're done
FOR iLoop = 500 TO 400 STEP -5: SOUND iLoop, .3: NEXT iLoop
PRINT "Finished generating sound."
PRINT
PRINT "Now, how do we stop it playing or clear the SOUND queue?"
PRINT
PRINT "WARNING: "
PRINT "Options 1-3 can cause program to freeze or act strangely!"
PRINT
PRINT "1. Try stopping the sound with SOUND 0,0"
PRINT "2. Try stopping the sound with SOUND 37,1"
PRINT "3. Try stopping the sound with BEEP"
PRINT "4. Play it again"
PRINT "5. Quit"
PRINT
DO
in$ = INKEY$
IF in$ = "1" THEN
OPEN "blahblahblah.tmp" FOR APPEND AS #1: CLOSE #1
SHELL _DONTWAIT "untitled(9).exe"
STOP
ELSEIF in$ = "2" THEN
SOUND 37, 1
ELSEIF in$ = "3" THEN
BEEP
END
ELSEIF in$ = "4" THEN
bQuit = FALSE: EXIT DO
ELSEIF in$ = "5" OR in$ = "q" THEN
bQuit = TRUE: EXIT DO
END IF
LOOP
IF bQuit = TRUE THEN EXIT DO
LOOP
101
PRINT "Ha! It worked!"
SLEEP
So the part that sucks is you momentarily lose your program window. I mean the whole approach sucks, but losing the window really sucks. Now if @Spriggsy swings by, he might know of a way using Windows API to kill the sound, but if you are on Linux, that won't help you.
@Dav works a lot with sound, but I don't know if he also works on Linux, or just Windows.
Hopefully someone else has a better idea than mine. It will work, but it's ugly.
Pete
Thanks for your reply!
Oy vey, the workaround you mention would not work for me, because I just want to stop the sound during gameplay in a video game, so we cannot kill the window (not to mention that would be the biggest kludge ever, LoL!)
I think the solution for me will be to simply record the audio from that code as a sound file and play it back with _SNDPLAY. It's OK if it's a static WAV file, the sound parameters don't vary.
I do think finally adding SOUND(0, 0) to QB64 would make SOUND more useful in a lot of cases. I'm not sure how hard it would be - all that needs to be done is when there's a SOUND(0, 0) command, just shut down whatever audio is queued for SOUND...
Thanks again!
Posts: 734
Threads: 30
Joined: Apr 2022
Reputation:
43
I will have to read through this forum thread and see what's going on but if I'm able to be of any assistance then I'll see what I can do.
Tread on those who tread on you
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
08-05-2022, 03:01 AM
(This post was last modified: 08-05-2022, 03:01 AM by madscijr.)
(08-05-2022, 02:25 AM)Spriggsy Wrote: I will have to read through this forum thread and see what's going on but if I'm able to be of any assistance then I'll see what I can do.
Hey, long time no see!
I decided I can use a WAV file in this case, but implementing SOUND(0,0) to stop playing sound immediately & clear the buffer, would help make the SOUND command more useful.
Posts: 734
Threads: 30
Joined: Apr 2022
Reputation:
43
This appears to be quite the conundrum. However, there is a definite way to do background music in a loop that can be killed whenever you want. You'd need to either open up a WAV file and then just allow it to continue playing using SNDLOOP until a certain key is pressed OR you can do something using the PlaySound function from Win32. You'd still need to use a WAV file OR learn how to make the WAVE resource in memory and pass it to the function. The function can run asynchronously and then you can kill the sound whenever you want.
I've never messed with the SOUND function before but maybe you should look into SNDOPENRAW, SNDRAW, and SNDCLOSE instead since you are working with frequencies and such. Those would allow you to kill the sound whenever without having to do some hacky thing with the C backend, Win32, threading, or premade WAV files.
Tread on those who tread on you
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
08-05-2022, 03:46 AM
(This post was last modified: 08-05-2022, 04:14 AM by madscijr.)
(08-05-2022, 03:09 AM)Spriggsy Wrote: This appears to be quite the conundrum. However, there is a definite way to do background music in a loop that can be killed whenever you want. You'd need to either open up a WAV file and then just allow it to continue playing using SNDLOOP until a certain key is pressed OR you can do something using the PlaySound function from Win32. You'd still need to use a WAV file OR learn how to make the WAVE resource in memory and pass it to the function. The function can run asynchronously and then you can kill the sound whenever you want.
I've never messed with the SOUND function before but maybe you should look into SNDOPENRAW, SNDRAW, and SNDCLOSE instead since you are working with frequencies and such. Those would allow you to kill the sound whenever without having to do some hacky thing with the C backend, Win32, threading, or premade WAV files.
For now I'm going to just record it as a digital audio file and use playsound.
I saw an example of SNDRAW but had questions, got busy, etc. Need to finally absorb the WAV file specification.
That said, why have a SOUND command if you can't stop it? I hope they add "support for SOUND(0,0) to stop sounds from playing" onto the backlog.
UPDATE: Here's a thought... The SOUND command is easy. That is in the spirit of BASIC. So why not create a function that emulates the SOUND command using SNDRAW etc.? Then we can support SOUND(0,0) ourselves, within that function! You could even extend it with all sorts of commands / functions that do things like change the waveform, set the volume and panning, etc.
Are you comfortable enough with SNDRAW to create a PLAYSOUND procedure?
Posts: 730
Threads: 120
Joined: Apr 2022
Reputation:
106
I had a conversation about this at the old forum once, and if I remember right the answer is that once sound data is sent to the buffer with PLAY, SOUND, _SNDRAW then it has to play out, can’t stop it. I was asking at the time if there’s a way to detect when a PLAY statement was finished playing, and there wasn’t a way, in pure QB64 that is.
- Dav
Posts: 2,700
Threads: 327
Joined: Apr 2022
Reputation:
217
We see the same thing in other places as well. Netflix can start playing a movie preview with the sound on, you can close the tab Netflix is in -- or even close your browser! -- and you'll still hear sound until the buffer plays out and finishes. Once it's in the buffer, I don't know of any way to get it out once it starts playing. It tends to have to just run its course.
Posts: 3,981
Threads: 177
Joined: Apr 2022
Reputation:
220
But I think you CAN control how long Sounds are made, so don't make next sound until ready for it, be a clock watcher.
b = b + ...
|