Recent

Author Topic: Looping mmsystem PlaySound with SND_LOOP specifier  (Read 2141 times)

Weiss

  • Full Member
  • ***
  • Posts: 127
Looping mmsystem PlaySound with SND_LOOP specifier
« on: July 11, 2023, 10:05:24 pm »
gents, it appears SND_LOOP argument in PlaySound() function causes issues. When sound is played all other controls on the form freeze up. Same thing in sndPlaySound.

Asynchronous execution (snd_ASYNC) does not affect controls, I can stop and play sound any moment. But SND_LOOP is no bueno.

Also, I have not tested it much, there is no looping going on.

I worked around the issue by looping the sound, which is played asynchronously, by external looping structure. Is it the issue with SND_LOOP or is it me doing something wrong? Also, peculiar fact, not every looping structure does work. When loop within repeat-until, or while-do, same thing happen with snd_Async specifier. I have to play sound through timer with onTimer event, which brings its own convolution, but at least form does not freeze up.

I am running Lazarus v2.2.6 on Windows 7. Will it work on better on Windows 10-11? Does it work better on Delphi?
« Last Edit: July 11, 2023, 10:07:37 pm by Weiss »

TRon

  • Hero Member
  • *****
  • Posts: 2523
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #1 on: July 11, 2023, 11:03:13 pm »
So you have set both SND_LOOP and SND_ASYNC flags yet your GUI freezes ?

It is difficult to tell what might be wrong without being able to see some actual code.

Weiss

  • Full Member
  • ***
  • Posts: 127
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #2 on: July 11, 2023, 11:50:46 pm »
snd_LOOP flag freeze controls. SND_ASYNC does not. But. If I wrap SND_ASYC into certain looping structure, it does freeze controls as well.

I thought about dedicating thread for playing sound with SND_LOOP. But SND_LOOP does not loop the playback. Two issues with SND_LOOP - freezing controls and no looping.
« Last Edit: July 11, 2023, 11:52:47 pm by Weiss »

TRon

  • Hero Member
  • *****
  • Posts: 2523
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #3 on: July 12, 2023, 12:15:22 am »
Ok, let me try that again  :)

If you set both flags at the same time in the playsound command , does the GUI still freezes up ? see also: https://learn.microsoft.com/en-us/windows/win32/multimedia/using-playsound-to-loop-sounds

Weiss

  • Full Member
  • ***
  • Posts: 127
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #4 on: July 12, 2023, 01:55:13 am »
both flags same time, how? Playsound has only one flag.

If I call one Playsound (file,0,snd_Loop) followed by PlaySound(file,0,snd_Async)

then sound is played once (no looping), form controls are frozen for the duration of the sound, and then whatever buttons I pressed while sound was playing, will be activated. I will get another sound, different buttons pressed - whatever I did while the form was frozen. Calling SND_ASYNC flag after the SND_LOOP causes commands not executed but stored in a buffer, and executed when sound stops playing.

TRon

  • Hero Member
  • *****
  • Posts: 2523
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #5 on: July 12, 2023, 02:00:05 am »
both flags same time, how? Playsound has only one flag.
Correction, it has one parameter that allow you to define the flags.

You simply "or' them together.

Code: Pascal  [Select][+][-]
  1. playsound('my_soundy_soundfile.wav',0, snd_Loop or snd_Async);
  2.  
To perhaps make it more clear:
Code: Pascal  [Select][+][-]
  1. const
  2.   myplaysoundflags = snd_Loop or snd_Async;
  3. begin
  4.   PlaySound('my_soundy_soundfile.wav',0, myplaysoundflags);
  5. end;
  6.  

Do note that I am assuming the flags are defines as constants (and not variables). I do not have Windows to test myself.

edit: there are even more flags, and some combinations are allowed while others are not,see also the official playsound documentation https://learn.microsoft.com/en-us/previous-versions/dd743680(v=vs.85) which explain which flags there are, and what they are used for.

If you want to know more about how flags work (in c but same principle applies for Free Pascal) then see this question and answers: https://stackoverflow.com/questions/3643681/how-do-flags-work-in-c especially the last two answers.
« Last Edit: July 12, 2023, 02:22:20 am by TRon »

Weiss

  • Full Member
  • ***
  • Posts: 127
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #6 on: July 12, 2023, 03:06:04 am »
amazing! now, thinking back, the symbol "|" actually does mean "or" in logic. There was a note in documentation, but it was spelled "SND_LOOP | SND_ASYNC)"

I tried all except "or".

TRon - thank you for being patient with me.

TRon

  • Hero Member
  • *****
  • Posts: 2523
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #7 on: July 12, 2023, 03:16:00 am »
amazing! now, thinking back, the symbol "|" actually does mean "or" in logic. There was a note in documentation, but it was spelled "SND_LOOP | SND_ASYNC)"
I also always seem to do that wrong and apparently we are not the only ones as there is a dedicated wiki page for people that are familiar with c but not so with pascal: https://wiki.freepascal.org/Pascal_for_C_users

It has always been a steady sturdy rock with helping to convert c-code to pascal or try to understand what it is that microsoft is trying to tell with their development pages  ;)

Quote
TRon - thank you for being patient with me.
You're welcome. But... uhm... did that trick actually solve your original "freezing" problem ?

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #8 on: July 12, 2023, 08:51:26 pm »
If I call one Playsound (file,0,snd_Loop) followed by PlaySound(file,0,snd_Async)

That is not valid, per the documentation:

Quote
SND_LOOP
The sound plays repeatedly until PlaySound is called again with the pszSound parameter set to NULL. If this flag is set, you must also set the SND_ASYNC flag.

So, you must call PlaySound() one time with BOTH SND_LOOP and SND_ASYNC specified together.  And then call it again when you want to stop the loop.

Quote
SND_ASYNC
The sound is played asynchronously and PlaySound returns immediately after beginning the sound. To terminate an asynchronously played waveform sound, call PlaySound with pszSound set to NULL.

then sound is played once (no looping), form controls are frozen for the duration of the sound, and then whatever buttons I pressed while sound was playing, will be activated.

When SND_ASYNC is not specified, PlaySound() blocks the calling thread until the sound is finished playing.  So, if you call it in your UI thread, your UI will be blocked while the sound is playing.  Adding SND_ASYNC should fix that.  Otherwise, like you said, you can call PlaySound() in another thread.
« Last Edit: July 12, 2023, 08:53:31 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Weiss

  • Full Member
  • ***
  • Posts: 127
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #9 on: July 14, 2023, 04:56:45 pm »
You're welcome. But... uhm... did that trick actually solve your original "freezing" problem ?

yes, it did work wonderfully. Problem solved. PlaySound(filename, 0, SND_LOOP or SND_ASINC) and everything works as it should. Now, thinking back, I spent two days researching, maybe I should learn more of C.

Weiss

  • Full Member
  • ***
  • Posts: 127
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #10 on: July 14, 2023, 07:36:29 pm »

Quote
SND_LOOP
The sound plays repeatedly until PlaySound is called again with the pszSound parameter set to NULL. If this flag is set, you must also set the SND_ASYNC flag.

So, you must call PlaySound() one time with BOTH SND_LOOP and SND_ASYNC specified together.  And then call it again when you want to stop the loop.


not obvious from description. Your TRANSLATION of the description is fine, but not what is in documentation. Not the way I read it.

The way it is written, it says, "...PlaySound() called again with ...NuLL ... If this flag is set you must also call SND_ASYNC..."

See? It says, "If you call NIL then you should call it again with SND_ASYNC". "Nil", not "LOOP". It does not say "together" or "in same call", but "also". It is like, again, sometime. And syntax, should have been proper, not this " | ".

This gibberish writing costed me two days of frustration.
« Last Edit: July 14, 2023, 07:40:09 pm by Weiss »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #11 on: July 14, 2023, 08:01:00 pm »
Not the way I read it.

Then you are not reading it correctly.

The way it is written, it says, "...PlaySound() called again with ...NuLL ... If this flag is set you must also call SND_ASYNC..."

See? It says, "If you call NIL then you should call it again with SND_ASYNC". "Nil", not "LOOP". It does not say "together" or "in same call", but "also".

That is not what it is saying.  If you read it again more carefully, it is basically saying that if you call PlaySound() with SND_LOOP specified then you MUST also specify SND_ASYNC in the same call.  In which case, it will keep playing in the background, without blocking the calling thread, until you call PlaySound() again with pszSound set to NULL to stop it.

And syntax, should have been proper, not this " | ".

That is proper syntax.  The documentation is written for C, and in C the '|' OR operator is used to combine bit flags.  In Pascal, that is done using the 'or' operator.
« Last Edit: July 14, 2023, 08:05:03 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

TRon

  • Hero Member
  • *****
  • Posts: 2523
Re: Looping mmsystem PlaySound with SND_LOOP specifier
« Reply #12 on: July 15, 2023, 02:52:50 am »
yes, it did work wonderfully. Problem solved.
Thank you for the feedback !

Quote
... maybe I should learn more of C.
If you are making a habit of calling/using native OS functionality then it definitely helps to know a little C as the majority of libraries are written in C and as a consequence also their documentation. Not to mention the amount of available examples written in/for C is definitely outnumbering examples that are written in/for Pascal.

 

TinyPortal © 2005-2018