Handling multiple plays of PlaySound across different indicators

 

Hi,

I've created a number of indicators and EAs that use PlaySound() function from time to time. What I've noticed is that if two or more of such applications try to play the .wav audio at the same time (e.g. right after the start of a new bar), the second call to PlaySound suppresses the first call.

Now of course that is bad, since that means I'm loosing an alert. So what I want is to create a system that will concatenate the .wav sound files of my applications whenever such situations occur.

The general idea on how to do that seems clear to me, but I still have two issues. First, is there a global variable already used as a flag by MT5 telling me "an audio file is being played"? Or will I have to create my own of such variable (using the global variable system or some other thread safe way)? And second: since I need to only start playing the second audio once the first is started and the indicators' users may have loaded a custom sound file to be played as an alert, how do I get the .wav duration ins secs or milisecs? I found some generic answers on the web (like:  How to get duration of WAV file in Python (minimal example) - TechOverflow and How to calculate duration of wave file from its size? (microsoft.com) and even tried something with ChatGPT, without success (https://youtu.be/m5U_D2S-BNs)), but nothing for MQL5. What would be the way to do this in this language?

Thanks for any help!

How to get duration of WAV file in Python (minimal example)
  • Uli Köhler
  • techoverflow.net
Use duration_seconds = mywav.getnframes() / mywav.getframerate() to get the duration of a WAV file in seconds. Full example: import wave with wave.open("myaudio.wav") as mywav: duration_seconds = mywav.getnframes() / mywav.getframerate() print(f"Length of the WAV file: {duration_seconds:.1f} s")
 
Martin Bittencourt:

Hi,

I've created a number of indicators and EAs that use PlaySound() function from time to time. What I've noticed is that if two or more of such applications try to play the .wav audio at the same time (e.g. right after the start of a new bar), the second call to PlaySound suppresses the first call.

Now of course that is bad, since that means I'm loosing an alert. So what I want is to create a system that will concatenate the .wav sound files of my applications whenever such situations occur.

The general idea on how to do that seems clear to me, but I still have two issues. First, is there a global variable already used as a flag by MT5 telling me "an audio file is being played"? Or will I have to create my own of such variable (using the global variable system or some other thread safe way)? And second: since I need to only start playing the second audio once the first is started and the indicators' users may have loaded a custom sound file to be played as an alert, how do I get the .wav duration ins secs or milisecs? I found some generic answers on the web (like:  How to get duration of WAV file in Python (minimal example) - TechOverflow and How to calculate duration of wave file from its size? (microsoft.com) and even tried something with ChatGPT, without success (https://youtu.be/m5U_D2S-BNs)), but nothing for MQL5. What would be the way to do this in this language?

Thanks for any help!

Hello , i have not tried if it plays simultaneously but try this library : 

#import "winmm.dll"
int mciSendStringW(string lpszCommand,string lpszReturnString,uint cchReturn,int hwndCallback);
#import
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
  mciSendStringW("play E:\\email.wav wait",NULL,0,0); // no open or alias used 
//---
   return(INIT_SUCCEEDED);
  }

Problem i got was the paths cannot have gaps in them (hence the e:\\email.wav)

Documentation :

https://learn.microsoft.com/en-us/previous-versions//dd757161(v=vs.85)

Edit : i played around with trying to find the "dos path" and i ended up with this . It can play from the sounds directory too 

#property strict
#import "winmm.dll"
int mciSendStringW(string lpszCommand,string lpszReturnString,uint cchReturn,int hwndCallback);
#import
#import "kernel32.dll"
int GetShortPathNameW(string longpath,ushort &result[],int cchBuffer_max_chars_in_result);
#import
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  string path_with_gaps=TerminalPath()+"\\Sounds\\email.wav";
  string dospath=NULL;
  ushort out[];
  int need=GetShortPathNameW(path_with_gaps,out,0);
  ArrayResize(out,need,0);
  int t=GetShortPathNameW(path_with_gaps,out,1024);
  if(t>0){
  dospath=ShortArrayToString(out,0,WHOLE_ARRAY);
  Print("DosPath["+dospath+"]");
  mciSendStringW("play "+dospath+" wait",NULL,0,0);
  }else{
  Print("error");
  }
  return(INIT_SUCCEEDED);
  }

It even plays mp3's  🤣 🤣 🤣

#property strict
#import "winmm.dll"
int mciSendStringW(string lpszCommand,string lpszReturnString,uint cchReturn,int hwndCallback);
#import
#import "kernel32.dll"
int GetShortPathNameW(string longpath,ushort &result[],int cchBuffer_max_chars_in_result);
#import
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  string path_with_gaps=TerminalPath()+"\\Sounds\\email.wav";
  string dospath=NULL;
  ushort out[];
  int need=GetShortPathNameW(path_with_gaps,out,0);
  ArrayResize(out,need,0);
  int t=GetShortPathNameW(path_with_gaps,out,1024);
  if(t>0){
  dospath=ShortArrayToString(out,0,WHOLE_ARRAY);
  Print("DosPath["+dospath+"]");
  mciSendStringW("play "+dospath+" wait",NULL,0,0);
  //hmm wait command stops and returns to the program after the file finishes
  }else{
  Print("error");
  }
  //mp3 test
  path_with_gaps=TerminalPath()+"\\Sounds\\AlexMoe_Prelude.mp3";
  dospath=NULL;
  ArrayFree(out);
  need=GetShortPathNameW(path_with_gaps,out,0);
  ArrayResize(out,need,0);
  t=GetShortPathNameW(path_with_gaps,out,1024);
  if(t>0){
  dospath=ShortArrayToString(out,0,WHOLE_ARRAY);
  Print("DosPath["+dospath+"]");
  mciSendStringW("open "+dospath+" alias music",NULL,0,0);
  mciSendStringW("play music",NULL,0,0);
  Sleep(10000);
  mciSendStringW("stop music",NULL,0,0);
  mciSendStringW("close music",NULL,0,0);
  }else{
  Print("error : cannot open "+path_with_gaps);
  }
  return(INIT_SUCCEEDED);
  }
 
Lorentzos Roussos #:

Hello , i have not tried if it plays simultaneously but try this library : 

Problem i got was the paths cannot have gaps in them (hence the e:\\email.wav)

Documentation :

https://learn.microsoft.com/en-us/previous-versions//dd757161(v=vs.85)

Edit : i played around with trying to find the "dos path" and i ended up with this . It can play from the sounds directory too 

It even plays mp3's  🤣 🤣 🤣

Well, that certainly seems an interesting workaround! But if I got it correctly, it calls for a sound system outside MT5's Terminal, which doesn't seem to be the ideal :T  In fact, it would be great if MetaQuotes would update the PlaySound function to handle a variable telling if it needs to stop the currently playing file or go to a stack. But anyway, I'll consider your solution in case I can't find any help in making a more inside MQL5 solution. Thanks!

 
Martin Bittencourt #:

Well, that certainly seems an interesting workaround! But if I got it correctly, it calls for a sound system outside MT5's Terminal, which doesn't seem to be the ideal :T  In fact, it would be great if MetaQuotes would update the PlaySound function to handle a variable telling if it needs to stop the currently playing file or go to a stack. But anyway, I'll consider your solution in case I can't find any help in making a more inside MQL5 solution. Thanks!

Yeah if its for a market product it cannot be used unfortuletanetely 

Reason: