# Play an mp3 file? Yes. Yes, you can

**URL:** <https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219>\
**Category:** Ignition\
**Created:** [August 31, 2017, 3:11pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219 "2017-08-31T15:11:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [August 31, 2017, 3:11pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/1 "2017-08-31T15:11:25Z")

</div>

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… 😒

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

```auto
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)

```

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [August 31, 2017, 4:14pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/2 "2017-08-31T16:14:37Z")

</div>

For the Raspi, I ended up using [subprocess.Popen](http://www.jython.org/docs/library/subprocess.html). It’s not as friendly as JavaFX would have been, but as the saying goes, any port in a storm…

```auto
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)

```

---

<div class="post-metadata">

**Author:** ![MMaynard](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mmaynard/32/3366_2.png) [@MMaynard](https://forum.inductiveautomation.com/u/MMaynard)\
**Post date:** [September 1, 2017, 2:34pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/3 "2017-09-01T14:34:04Z")

</div>

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

```auto

> # 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)

```

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [September 1, 2017, 3:23pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/4 "2017-09-01T15:23:17Z")

</div>

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

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.

```auto
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'])

```

---

<div class="post-metadata">

**Author:** ![dmdrendall](https://avatars.discourse-cdn.com/v4/letter/d/f9ae1b/32.png) [@dmdrendall](https://forum.inductiveautomation.com/u/dmdrendall)\
**Post date:** [September 2, 2017, 12:37am UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/5 "2017-09-02T00:37:56Z")

</div>

Home automation doorbell, or computer-based training application?😌

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [September 2, 2017, 12:54am UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/6 "2017-09-02T00:54:15Z")

</div>

Andon system. So a bit of both! 😆

---

<div class="post-metadata">

**Author:** ![MMaynard](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mmaynard/32/3366_2.png) [@MMaynard](https://forum.inductiveautomation.com/u/MMaynard)\
**Post date:** [September 7, 2017, 11:43pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/7 "2017-09-07T23:43:32Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [May 17, 2018, 1:16pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/8 "2018-05-17T13:16:35Z")

</div>

> [@MMaynard](#):
>
> Once I get the code cleaned up and human readable I will share.

Any progress on this?

---

<div class="post-metadata">

**Author:** ![MMaynard](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mmaynard/32/3366_2.png) [@MMaynard](https://forum.inductiveautomation.com/u/MMaynard)\
**Post date:** [May 17, 2018, 4:24pm UTC](https://forum.inductiveautomation.com/t/play-an-mp3-file-yes-yes-you-can/15219/9 "2018-05-17T16:24:54Z")

</div>

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
