Play an mp3 file? Yes. Yes, you can

The Sound Player component and system.util.playSoundClip are wav file only. Since wav files are simply huge, compared to mp3, I decided to try out the JavaFX libraries. Here is my first runthrough.

Verified on my Windows machine. No time to check on Linux yet, but since JavaFX is included on x86/x64, I don’t see why it wouldn’t work.

I can say it will not work on ARM (like a Raspi), since Oracle dropped JavaFX support. Which is sad, because that’s what I really wanted it for… :unamused:

This example plays the theme from Bonanza, because, well, why not? Also added a tag to monitor to stop the playback early, if needed.

from javafx.scene.media import AudioClip
from time import sleep

# Set path to audio file and tag used to stop playback.
audioFilePath = 'file:///C:/media/Bonanza.mp3'
stopFlagPath = '[default]Test/Audio/stopFlag'

# Load up the audio stream
plunk = AudioClip(audioFilePath)

# Play the audio stream
plunk.play()

# Check every so often to see if the stopFlag is active, and stop playback if true. 
# Useful for long clips. 
while plunk.isPlaying() == 1:
  stopFlag = system.tag.read(stopFlagPath).value
  if stopFlag == 1:
    plunk.stop()
  else:
    sleep(0.3)

# Reset the stop flag
system.tag.write(stopFlagPath, 0)
10 Likes

For the Raspi, I ended up using subprocess.Popen. It’s not as friendly as JavaFX would have been, but as the saying goes, any port in a storm…

from subprocess import Popen
from time import sleep

audioFilePath = 'file:///home/pi/Music/TV/Bonanza.mp3'
stopFlagPath = '[default]Test/Audio/stopFlag'

plunk = Popen(['/usr/bin/omxplayer', '-o', 'local', audioFilePath])

# Poll the process to see if it's still running
poll=plunk.poll()

# Check every so often to see if the stopFlag is active, and stop playback if true. 
# Useful for long clips.
while poll is None:
  poll = plunk.poll()
  stopFlag = system.tag.read(stopFlagPath).value
  if poll is None and stopFlag != 0:
    Popen(['pkill','-9','omxplayer'])
  else:
    sleep(0.3)
	
# Reset the stop flag
system.tag.write(stopFlagPath,0)
4 Likes

Really neat! You will want to wrap it in a system.util.invokeAsynchrous call though in order for the StopFlag to work.


> # Load up the audio stream
> def playFile():
> 	plunk = AudioClip(audioFilePath)
> 	# Play the audio stream
> 	plunk.play()
> 	# Check every so often to see if the stopFlag is active, and stop playback if true. 
> 	# Useful for long clips. 
> 	while plunk.isPlaying() == 1:
> 	  stopFlag = system.tag.read(stopFlagPath).value
> 	  if stopFlag == 1:
> 		plunk.stop()
> 	  else:
> 		sleep(0.3)
> 	system.tag.write(stopFlagPath, 0)
> # Reset the stop flag
> system.util.invokeAsynchronous(playFile)
2 Likes

Heh. Since I was heading towards a Raspi, I didn’t worry too much about it. It probably would have caught me otherwise, though! :slight_smile:

My final version to use on the Pi is triggered from a custom property. No extra flags required. Don’t even have to invoke it, since Popen is already asynchronous, and I don’t really need to monitor if it’s already playing.

if event.propertyName == "musicTrigger":
  from subprocess import Popen
  
  if event.newValue == 1:  
    audioFilePath = 'file:///home/pi/Music/TV/Bonanza.mp3' 
    plunk = Popen(['/usr/bin/omxplayer', '-o', 'local', audioFilePath])
  else:
    Popen(['pkill','-9','omxplayer'])
2 Likes

Home automation doorbell, or computer-based training application?:relaxed:

Andon system. So a bit of both! :laughing:

3 Likes

I have actually used this to create a voice alarm system.
Once I get the code cleaned up and human readable I will share.

3 Likes

Any progress on this?

Yes and No. I have it working but it is customized pretty heavily to our environment.
I created a share on the Gateway server called AlarmWAV that contains all of the sound files.
Then I have 3 custom properties on each alarm tag you want a voice alarm on.
AlarmGroup
AlarmGroup is what we use to filter our alarms to certain areas of a location.
PlayCount
How many times the Sound file should be played.
AlarmWav
The name of the sound file to send

Then I have a tag in each AlarmGroup area that counts active alarms that have the alarm group and an AlarmWav set in the properties of the alarm.

An SFC monitors that tag for > 0
When the count goes over 0 it then processes the SFC which calls the script to send the sound file to the designated Node which is stored in a memory tag for each AlarmGroup
The SFC will process the sound file to the node X times the AlarmCount setting for the Alarm tag. While writing back to the Alarm Tag incrementing down the PlayCount to 0

2 Likes