Play system sound or save a wave within an ipf file?
ggermer
I would like to have a sound played after the completion of a longer procedure. For an existing sound wave in a project, this works with the following procedure. But this has the consequence that I would have to copy the sound wave into every further procedure. (The sound wave is an imported .wave file created with Logic Pro.)
function f_playsound()
if (waveexists(root:temp:sound)==1)
wave sound=root:temp:sound
playsound sound
endif
end
if (waveexists(root:temp:sound)==1)
wave sound=root:temp:sound
playsound sound
endif
end
So my question is if there is a way to include the sound wave in the ipf file. Basically I could use "make" to create the wave and then write the original sound wave for each value. But with 48510 rows and 2 columns this is very complicated.
Or are there ready-made sounds or system sounds that you could play instead?
You could just use:
Beep
and then set the appropriate system sound to whatever you like to hear here.
November 17, 2020 at 10:58 pm - Permalink
Thanks... this is at least a solution for the case that the sound wave is missing.
November 18, 2020 at 09:00 am - Permalink
Beep is a good way to go. But that's far too simple.....
ImageTransform compress inputWave
WAVE W_Compressed // a byte wave that contains the data as well as metadata from inputWave
Variable numBytesCompressed = numpnts(W_Compressed)
String outStringRaw = ""
// Transfer the contents of W_Compressed into a string. The string
// will simply contain the raw binary data from the wave.
outStringRaw = PadString(outStringRaw, numBytesCompressed, 0)
Variable n
For (n=0; n < numBytesCompressed; n++)
outStringRaw[n] = num2char(W_Compressed[n], 1)
EndFor
Display
print strlen(outStringRaw)
// Base64 encode the string to get rid of any null characters and
// other characters that might cause problems.
String outStringBase64Encoded = Base64Encode(outStringRaw)
print "b64 encoded", strlen(outStringBase64Encoded)
String dataWinName = S_name
// Store the contents of the string in the window's user data.
SetWindow $dataWinName, userdata(audioWave)=outStringBase64Encoded
End
Function RecreateWaveFromWindowUserdata(String windowName)
// Get the userdata
String audioUserDataBase64Encoded = GetUserData(windowName, "", "audioWave")
print strlen(audioUserDataBase64Encoded)
String audioUserDataRaw = Base64Decode(audioUserDataBase64Encoded)
print strlen(audioUserDataRaw)
// Put the binary data in the string into a byte wave of the same length.
Variable rawStringLength = strlen(audioUserDataRaw)
Make/B/U/O/N=(rawStringLength) audioDataByteWave
audioDataByteWave = char2num(audioUserDataRaw[p])
// Decompress the data
ImageTransform decompress audioDataByteWave // Creates W_Decompressed
WAVE W_Decompressed
PlaySound W_Decompressed
End
To use this, execute:
EncodeWaveToNewWindowUserdata(mySoundWave1)
That creates a blank graph window whose named userdata contains the mySoundWave1 wave after compressing the wave and then base64 encoding.
Then, with that window still on top, execute:
RecreateWaveFromWindowUserdata("Graph0")
That command should play the wave that is encoded in the specified window's named userdata.
To use this in real life, you would call EncodeWaveToNewWindowUserdata to create the window. Then you would save the window's recreation macro to your procedure file.
Then, when this code runs on the user's computer, you would call the window recreation macro for the window, then call RecreateWaveFromWindowUserdata to create the audio wave. You would probably then want to move that wave somewhere else and kill the empty graph.
You could use this technique for any kind of wave data, not just audio data.
If you are distributing your package as a bunch of procedure files, you could also include a .ibw (igor binary wave) or .itx (igor text) file in the package that contains the data, and then have your code load that file using LoadWave.
November 18, 2020 at 01:01 pm - Permalink
Okay, um... thanks a lot! I tried the compression and the window macro is unfortunately very long (for my test sound wave about 4000 lines of code).
I think that for a "the procedure is finished" several beeps should be enough. From the second beep on it also seems to be louder, surely has to do with the power saving mode of the headphones.
beep
sleep 00:00:01
beep
sleep 00:00:01
beep
sleep 00:00:01
beep
sleep 00:00:01
beep
end
Thanks for the helpful tips.
November 18, 2020 at 04:34 pm - Permalink
Another option would be to use ExecuteScriptText to make a system call to make a noise. That would be more difficult to make cross platform, but is likely possible. On macOS you can use the system "say" command to use text to speech. I have my C++ compiler set up to say "finished" to me when a build of Igor is done.
On Windows it's more complicated. Here's the command I have executed. I haven't tried calling this from Igor though, so it may be more complicated.
cmd.exe /C PowerShell -Command "Add-Type –AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('finished');"
November 18, 2020 at 04:40 pm - Permalink
Is it possible to return the operating system and the system language as string?
ExecuteScriptText("say \"finished\"")
November 19, 2020 at 02:29 am - Permalink
To get the OS use IgorInfo(). No idea about the system language, though.
November 19, 2020 at 02:54 am - Permalink
For the OS you can test either with IgorInfo(2) or you can use conditional compilation. Here's an example of the later:
#ifdef WINDOWS
print "windows"
#else
print "macintosh"
#endif
End
For more info on conditional compilation, execute:
DisplayHelpTopic "Conditional Compilation"
You probably don't need an example on how to use IgorInfo().
As for getting the system language, on Windows you can use this Igor function. Note that it takes a few seconds to execute, so you'll want to run this only once and store the value in a global.
String cmd = "cmd.exe /C systeminfo | findstr /B /C:\"System Locale\""
ExecuteScriptText/B/UNQ/W=5 cmd
return S_value
End
On macOS, you can use ExecuteScriptText to call the "locale" command and look at the value of the LANG variable that is returned.
Since Igor itself is has only English and Japanese translations (the LOCALE key of IgorInfo(3) output will give you "Japan" for the Japanese translation), you can probably assume that your users have at least basic familiarity with written English.
November 19, 2020 at 05:17 am - Permalink
In reply to For the OS you can test… by aclight
The user is not the problem, but the speech output of macOS. It does not recognize the language, but reads it as the text would sound in the system language.
Thanks again to everyone for the helpful information.
November 20, 2020 at 01:44 am - Permalink