External App running in GE

I want to launch an external command line audio player, to play mo3 files, (a tiny compressed modules), while the game is running.

I used these scripts:

import os
var = “contest.exe” + “song.mo3”

import subprocess
p1 = subprocess.Popen([“contest.exe”, “song.mo3”], stdout=subprocess.PIPE)
print p1.stdout.read()

When the app “contest” starts inside the console, it plays “song” very well, but the GE freezes until the song stops…

How can I avoid the GE to freeze, while the background app is working?


Normally, I don’t think that the parent process waits for the child process to terminate. However, because you’re calling:

print p1.stdout.read() 

The parent process has to wait for the child process to return something. Try removing that line and see if it works. If that doesn’t work, try setting stdout to None (which should be it’s default). From what I understand of the documentation using stdout=PIPE can create dealocks, try using p1.communicate() instead if you need to get something from the child process (though if stdout=None then communicate() will return None! So you’ll probably have to have a play with various setups).

Also, please use code tags to make any code easier to read!

Hope this helps! :smiley:

EDIT: alternatively, you could try running the audio player as a daemon:

It worked!

I’m a noob with python… Now I just need to load the app from a folder (Music\contest.exe for example), and kill the process… I,ll try…


No worries, happy to help! :smiley:

It’s always good to see people using python and everyone’s gotta start somewhere! If you get stuck with anything there’s always people around willing to help.

As to your point about loading the application from a folder, you can use the bge.logic module’s expandPath() function to expand a path to the file from where the blend / standalone executable exists. An example:

path = logic.expandPath("//music/contest.exe")

to get the path to the executable file. The first two slashes in the path string above tell it to look relative to the current folder (I’ve forgotten, it might be \, not // at the beginning).

I don’t know how to use path = logic.expandPath… It keeps complaining… An easy way to play the music from /music folder, would be a windows .bat file… but I want to make it all using python :(.


Complaining about what? Try switching out the first two slashes - I might have gotten it wrong. It should work… If there’s an error, tell us what the error is.

path = logic.expandPath(\\Music/contest.exe)

Unespected character after line continuation character (it points to the last “)”

With regards to your error: In python a backslash () is line continuation character for explicit line joining, used when breaking one logical line over two or more physical lines to improve readability. As a very contrived example:

if x == 10 and y == 20 and i == 30 \
    and ob.has_key('someProp') and ob['someKey'] == True \
    and ob.getDistanceTo(enemy) < 17:
        #go do something!

This tells the interpretor to join the line after the backslash to the previous one, forming one long if statement (1 logical line spread across 3 physical lines), which would be a lot clearer than writing that all in one really long line! So in the example you gave, your first argument to expandPath() is a new line character, by following it with something after the character causes an error as python doesn’t expect there to be anything else on that line.

Back to the problem: When using .expandPath() it takes a string as it’s paramter, so be sure to enclose the path in quotation marks! Because you didn’t use quotation marks the backslash was read as a continuation character rather than as part of the file path - hence the error.

Furthermore, I think expandPath() uses forward-slashes as a directory separator. It should look something like this:

path = logic.expandPath("//Music/contest.exe")

I hope all that makes sense and help you understand the error a bit more! :smiley:

I just have to change directory at the beginning, for example in a little intro scene before the game starts.

import os

Any command line player, and the songs, can be placed inside Music folder

Once the directory has been changed, you can load the player and the songs with this code, during “gameplay”

import subprocess
p1 = subprocess.Popen(["contest.exe", "song.mo3"], stdout=subprocess.PIPE)

When the player starts (or is killed), GE freezes just for 2 or 3 frames… This is usefull in scene transitions so that you don’t see the GE freezing.

I’m making a minigolf game (I’ll post it, in Works in Progress). By using this player, I managed to reduce my game size a lot!, now, with songs in Mo3, my game is just 30 MB (containing textures in .png format, and all dll’s in windows).


Battery is exactly correct. While changing the directory of the OS’s working directory using chdir might appear to be a good idea, it may have unexpected results, particularly if you try to use scripts in the same (or a different) directory as the blend file. Just be aware of that - but, if you have it working, then go with it.

I know, I’ll have to keep any external script inside music, but the game is not using many scripts, just a mouse import one,(internal text). It works OK with blender 2.49b and python 2.6, but is not working in Blender 2.57b.

import Rasterizer as R
cont = GameLogic.getCurrentController()
own = cont.getOwner()
mPosi = cont.getSensor("MousePosi")

### Start mouse position at center of game screen 
if own.init == 1:     
   R.setMousePosition(R.getWindowWidth()/2, R.getWindowHeight()/2)
   own.init = 0

### Move cursor to mouse position
cursorPosi = mPosi.getRaySource()

Is there any other way to use ingame mouse?.

I’m with SolarLune: it’s probably not a good idea to change the current working directory without good reason. Can you not supply the full path to subprocess.Popen() instead?

There’s a lot of syntax changes in python 3.0 and the Blender 2.5x python API. I’m not familiar with the changes so can’t help you there. But for Blender 2.49b some of that script is depreciated (changes in bold):

import Rasterizer as R
cont = GameLogic.getCurrentController()
own = <b>cont.owner </b>
mPosi = cont.<b>sensors["MousePosi"]</b>

### Start mouse position at center of game screen 
if <b>own['init'] </b>== 1:     
   R.setMousePosition(R.getWindowWidth()/2, R.getWindowHeight()/2)
   <b>own['init']</b> = 0

### Move cursor to mouse position
cursorPosi = mPosi.<b>raySource</b>
own.<b>position = cursorPosi</b>

But this codes doesn’t seem to cope to well with sudden mouse movements or when the mouse moves off the cursor. If you wanted to see the mouse in the game engine you could just use:

import Rasterizer as R

Then you could just use mPosi.hitObject to get the object the mouse is over (like a button). I think 2.5x has an option to show the mouse in game without python somewhere. However, this only displays the system cursor, if you wanted to use a custom cursor then you’d have to use a cursor script of some kind.

Hope this helps! :smiley:

My game uses a custom cursor :D.

I wanted the game to use relative paths to make it more portable, and the tiny player I used can be run in windows, Linux and mac :D… The only problem now, is the custom mouse…

If I upload my game, I’ll have to write some TXT warning about using mouse.

Thanks for your help.

I forgot… one last question:

Does blender 2.57b have a “save as runtime” option?

Thanks again.

Yes, it does. You have to enable it in the ‘Add-ons’ menu of the User Preferences menu - I believe it’s under the ‘Export’ section.

Hi again.

I want to make my game to be Linux and Mac compatible.

If you run this code, it will run “app”(linux,mac) or “app.exe”(win).

import subprocess
p1 = subprocess.Popen(["app", "file"], stdout=subprocess.PIPE)

Now I want to kill the external executable for any system, win, linux or mac.

How can I do it?. Can I send a “esc key” to the executable or something?


…I still don’t know how to tell “subprocess” to look inside a subdirectory :evilgrin: