Chuma has asked for the wisdom of the Perl Monks concerning the following question:
Hello!
I'm making a little game using Tk, and now I'm trying to add music to it. It's surprisingly difficult.
I would like to be able to start, stop, and change tracks at any point in the program. Ideally also play two sounds at the same time (music and sound effects), but let's take it one step at a time.
I've tried using a somewhat complicated set of forks, which exec() a system tool for playing sounds (afplay, on the Mac). But that's quite clumsy, system-dependent, and doesn't stop playing when the main program quits, which would be pretty annoying.
I've also tried using Audio::Play::MPG123, which sounded promising, but the very first line
$player = Audio::Play::MPG123->new;
gives an error I don't understand:
open3: exec of mpg123 -R --aggressive failed
Now I'm starting to consider calling an external Applescript, which is basically the highest level of desperation. Any other ideas?
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Playing sounds -- Tk
by Discipulus (Canon) on Nov 09, 2017 at 17:43 UTC | |
I'll link to some of his posts: one using SDL Tk Game Sound demo and another using Audio::DSP (that seems a bit aged module) Re^5: sound and gamepad support in Perl? PS I modified the title of my answer to metion Tk, and please share your improvements! PPS succesfully tested the first demo ( updated version ) with Perl 5.24 and SDL 2.546 incredible mixing capacities!! L*
There are no rules, there are no thumbs.. Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS. | [reply] [d/l] |
by zentara (Archbishop) on Nov 10, 2017 at 12:35 UTC | |
I'm not really a human, but I play one on earth. ..... an animated JAPH | [reply] |
Re: Playing sounds
by 1nickt (Canon) on Nov 09, 2017 at 17:07 UTC | |
Hi, gives an error I don't understand: That shows that the perl wrapper Audio::Play::MPG123 is attempting to launch the system binary mpg123 and failing. Dollars gets you donuts it's because you don't have it installed. On my Linux the command is: ... you'll have to find the equivalent for MacPorts or whatever package manger you are using. When you read the docs for a module and it says something like: "This is a frontend to the mpg123 player. It works by starting an external mpg123 process with the -R option and feeding commands to it."... it's pretty likely that you'll need a system application. Hope this helps!
The way forward always starts with a minimal test.
| [reply] [d/l] [select] |
Re: Playing sounds (updated)
by haukex (Archbishop) on Nov 09, 2017 at 16:45 UTC | |
which exec() a system tool for playing sounds (afplay, on the Mac). But that's quite clumsy, system-dependent,
Perhaps this will help in being a small piece in your puzzle: I showed some working code how to run a program that plays a sound while your script keeps running, and how to interrupt playback, using IPC::Run at Re^5: Killing a child process (the rest of the thread may be an interesting read too). The script uses the play tool from SoX, which according to its website is available for *NIX including Mac OS X, as well as Windows. | [reply] [d/l] |
Re: Playing sounds
by Tux (Canon) on Nov 09, 2017 at 23:17 UTC | |
I use Gstreamer. I have two versions of my internet radio player, for Gstreamer 1 and for Gstreamer 2. Of course written in Perl/Tk. Feel free to steal code Enjoy, Have FUN! H.Merijn | [reply] |
Re: Playing sounds
by karlgoethebier (Abbot) on Nov 09, 2017 at 19:04 UTC | |
[reply] [d/l] | |
Re: Playing sounds
by Chuma (Scribe) on Nov 09, 2017 at 18:48 UTC | |
Thanks! That makes sense, I'd have to install mpg123 to get that to work. But to have any hope of running my program on other machines, never mind other systems, I'd rather avoid that. If it's running an external process anyway, I might as well do it with afplay, right? I'll show you what I have so far. It's a pretty primitive idea – the music script reads a line from a file, telling it which audio file to play, then waits for that to finish, and does it again.
What I would need is: First, a way to call this from my main Perl program, and have it exit when that one does. Second, a way to get this script to kill the child process when it detects it's time to stop, in this example because the file is empty, as you see in the code. Some of the links you posted also look interesting, although I don't understand much of them. I'll continue looking there too. | [reply] [d/l] |
by haukex (Archbishop) on Nov 09, 2017 at 22:09 UTC | |
I'm not sure which node you are replying to (there are per-node "reply" links next to each post), but I'll reply anyway. But to have any hope of running my program on other machines, never mind other systems, I'd rather avoid that. AFAIK sound is always going to be an OS-dependent thing, so any Perl code would at some level have to access an external OS-dependent library or tool. Yes, running an external program just to play a sound is a bit wasteful, but you said this was for a game, and unless you're playing hundreds of sounds a second, or you need high precision in playback (precise timing down to the millisecond of when the sounds are played), or this is going to be run on very low-end machines, then IMHO using an external program is probably fine, especially for background music. (Update: On the other hand, see Discipulus's and zentara's comments about SDL here.) If it's running an external process anyway, I might as well do it with afplay, right? Personally I'd look at it differently: If I'm going to be running an external process anyway, I'd like to use the same one no matter which OS, then I will only have to handle one interface (command line arguments etc.). Then, the "only" issues I'd have to worry about are possibly pathname issues, which can be handled with a cross-platform tool like Path::Class or at least the core File::Spec, and making it as easy as possible for a user of my program to install that external tool. Perhaps you can try installing the previously mentioned mpg123 or SoX on different machines to see how easily their installers handle, how easy it is for your Perl script to call those external programs after their installation (potential PATH issues etc.), and so on. You might just simply document for your users, "if you want sound support, install package X and set configuration option Y to the installation path", and have your program gracefully handle the case of the sound playback tool not being installed (if having no sound is an option for you). Or, if your program has an installer, and you wanted to go this far, the installers of the audio software may support a "quiet" installation, which you can run during your program's installation, and depending on the license terms you might even distribute the audio package contained within yours. As for your code, I don't quite understand why you want to go through an external file - is that for interprocess communication, or will your user be editing that file? Note that both aforementioned players can play multiple files one after the other if given on the command line, and play a single file multiple times (e.g. play sound.mp3 repeat 2 and mpg123 --loop 3 sound.mp3 both play the same file three times). If you want to monitor the playback and re-start after it is finished, then yes, one way to do that would be to fork a child and have it block until the sound stops playing, but on the other hand, since I assume your code is probably based on an event loop, then regularly polling the state of the playback of the music and re-starting if necessary is also an option (that's what I do in my code below). Anyway, as a fun little project I whipped up an OO package based on the code I linked to earlier (only tested on Linux so far):
(BTW, yet another option for commandline playback is from the powerful FFmpeg or libav packages, the command line tools ffplay/avplay can be used like so: avplay -vn -nodisp -autoexit -nostats -loglevel quiet sound.mp3, I believe the options are identical for ffplay.) | [reply] [d/l] [select] |