GameStarter for Blender

A graphical user interface for launching blenderplayer.

USING:

Standalone Python http://arctrix.com/nas/python/standalone.html
Wxpython http://www.wxpython.org
Inno Setup http://www.jrsoftware.org/isinfo.php
SimpleOSC http://www.ixi-software.net/content/body_backyard_osc.html
Pure Data http://www.puredata.info

gamestarter.jpg
# -*- coding: utf-8 -*-

import wx
import sys, time, re
from subprocess import Popen, PIPE

class Hardware:
    sc = []
    md = []

    def __init__(self):
        self.renu = re.compile("[\d][.][ \t\n\r\f\v]")
        self.resc = re.compile("audio output devices")
        self.rescstop = re.compile("API number 3")
        self.remd= re.compile("MIDI input devices")
        self.remdstop = re.compile("MIDI output devices")

        self.scin = 0
        self.mdin = 0

        self.p = Popen(['bin/pd.exe','-stderr','-listdev', '-nogui', 'App/soundcard.pd'], stdout=PIPE, stderr=PIPE)

        while True:
            self.pdout = self.p.stderr.readline()

            if not self.pdout:
                break

            # SOUNDCARD - OUT
            if self.resc.search(str(self.pdout)) or self.scin == 1:
                self.scin = 1
                if self.rescstop.search(str(self.pdout)):
                    self.scin = 0
                else:
                    if self.renu.search(str(self.pdout)):
                        self.sc.append(self.pdout[+3:])

            # MIDI - IN
            if self.remd.search(str(self.pdout)) or self.mdin == 1:
                self.mdin = 1
                if self.remdstop.search(str(self.pdout)):
                    self.mdin = 0
                else:
                    if self.renu.search(str(self.pdout)):
                        self.md.append(self.pdout[+3:])

#------------------- GUI (WXPYTHON) --------------------
ID_HELP = 102
ID_ABOUT = 101
ID_EXIT = 110

class Splash(wx.SplashScreen):
    def __init__(self, parent=None):
        aBitmap = wx.Bitmap("./App/gamestarter.bmp", wx.BITMAP_TYPE_BMP)
        splashStyle = wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT
        splashDuration = 1000
        wx.SplashScreen.__init__(self, aBitmap, splashStyle, splashDuration, parent)
        self.Bind(wx.EVT_CLOSE, self.OnExit)
        wx.Yield()

    def OnExit(self, evt):
        self.Hide()
        MyFrame = MainWindow(None,-1,"GameStarter")
        app.SetTopWindow(MyFrame)
        MyFrame.Show(True)
        MyFrame.Center()
        evt.Skip()

class MainWindow(wx.Frame):
    def __init__(self,parent,id,title):

        self.pdhf = Hardware()
        #------------------- FRAME --------------------
        wx.Frame.__init__(self,parent,wx.ID_ANY,title,size = (535,350), style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
        self.SetBackgroundColour(wx.Colour(180, 180, 180))
        self.frameicon = wx.Icon("./App/8885.ico", wx.BITMAP_TYPE_ICO)
        self.SetIcon(self.frameicon)

        #------------------- IMAGE -------------------
        self.background = wx.Bitmap("./App/gamestarter.bmp", wx.BITMAP_TYPE_BMP)
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        #------------------- FONT --------------------
        font = wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD)

        #------------------- WIDGETS --------------------
        self.txsey = wx.StaticText(self, -1, "EYE", pos=(191,15))
        self.txsey.SetFont(font)
        self.txsre = wx.StaticText(self, -1, "Fullscreen", pos=(192,40)) 
        self.bfull = wx.CheckBox( self, -1, "", pos=(250,40))
        self.txsre = wx.StaticText(self, -1, "Resolution", pos=(192,63))  
        self.dlre = wx.ComboBox(self, -1, "", (250, 60), wx.DefaultSize, ["320x240","400x300","512x384","640x384","640x480","640x512","700x525","720x450","800x512","800x600","840x525","1024x768","1280x768","1280x800","1280x1024","1440x900","1920x1080"], wx.CB_DROPDOWN)

        self.txsea = wx.StaticText(self, -1, "EAR", pos=(191,90))
        self.txsea.SetFont(font)
        self.txsdv = wx.StaticText(self, -1, "Driver", pos=(192,112))  
        self.dldv = wx.ComboBox(self, -1, "", (190, 126), wx.DefaultSize, ["asio","mmio"], wx.CB_READONLY)
        self.dldv.Bind(wx.EVT_COMBOBOX, self.onDriver)
        self.txsbf = wx.StaticText(self, -1, "Buffer", pos=(262,112))  
        self.dlbf = wx.ComboBox(self, -1, "", (260, 126), wx.DefaultSize, ["16","32","64","128","256","512"], wx.CB_READONLY)
        self.txssc = wx.StaticText(self, -1, "Sound card", pos=(192,155))  
        self.dlsc = wx.ComboBox(self, -1, "", (190, 170), wx.DefaultSize, self.pdhf.sc, wx.CB_READONLY)
        #self.dlsc.Enable(False)

        self.txsto = wx.StaticText(self, -1, "TOUCH", pos=(191,205))
        self.txsto.SetFont(font) 
        self.txsmd = wx.StaticText(self, -1, "Midi (input)", pos=(192,227)) 
        self.dlmd = wx.ComboBox(self, -1, "", (190, 242), wx.DefaultSize, self.pdhf.md, wx.CB_READONLY)
        self.dlmd.Bind(wx.EVT_COMBOBOX, self.onMidi)

        #------------------- BUTTON --------------------
        self.bttestvideo = wx.Button(self, 100, "Test Video",  pos=(435,20))
        self.bttestvideo.Bind(wx.EVT_BUTTON, self.OnTestVideo)
        self.bttestaudio = wx.Button(self, 100, "Test Audio",  pos=(435,50))
        self.bttestaudio.Bind(wx.EVT_BUTTON, self.OnTestAudio)
        self.bttestmidi = wx.Button(self, 100, "Test Midi",  pos=(435,80))
        self.bttestmidi.Enable(False)
        self.bttestmidi.Bind(wx.EVT_BUTTON, self.OnTestMidi)
        self.btlaunch = wx.Button(self, 100, "Launch",  pos=(435,240))
        self.Bind(wx.EVT_BUTTON, self.OnLaunch, self.btlaunch)    

            #-------------------- DEBUG ---------------------
            #self.control = wx.TextCtrl(self, 1, style = wx.TE_MULTILINE, size=(360,350))
        #self.control.AppendText(str(ptout))        

        #------------------- OPTION --------------------
        self.CreateStatusBar()

        #------------------- MENU -----------------------
        filemenu = wx.Menu()
        filemenu.Append(ID_HELP, "&Help", "Help")
        filemenu.Append(ID_ABOUT, "&About", "Credits")
        filemenu.AppendSeparator()
        filemenu.Append(ID_EXIT, "E&xit", "Quit without saving")
        menubar = wx.MenuBar()
        menubar.Append(filemenu, "&File")
        self.SetMenuBar(menubar)

        #------------------- MENU - EVENT -----------------------
        wx.EVT_MENU(self, ID_HELP, self.OnHelp)
        wx.EVT_MENU(self, ID_ABOUT, self.OnAbout)
        wx.EVT_MENU(self, ID_EXIT, self.OnExit)

        self.Show(True)

    #--- START EVENT HANDLERS ---

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        dc.Clear()
        dc.DrawBitmap(self.background, 0, 0, False)

    def onDriver(self, event):
        if self.dldv.GetValue() == "mmio":
                self.dlsc.Enable(False)
            else:
                self.dlsc.Enable(True)

    def onMidi(self, event):
        if not self.dlmd.GetValue() == "":
                self.bttestmidi.Enable(True)
            else:
                self.bttestmidi.Enable(False)                

    def OnTestVideo(self, event):

        #DEFAULT FEEDBACK
        if self.dlre.GetValue() == "":
            self.dlre.SetValue("640x480")

        tv = []
        tv.append('App/blenderplayer.exe')

        if self.dlre.GetValue() == "":
            tv.append('-p')
            tv.append('0')
            tv.append('0')
            tv.append('640')
            tv.append('480')
        else:
            tv.append('-p')
            tv.append('0')
            tv.append('0')
            tv.append(str(self.dlre.GetValue().split('x')[0]))
            tv.append(str(self.dlre.GetValue().split('x')[1]))

        if self.bfull.GetValue():
            tv.append('-f')

        tv.append('-g')
        tv.append('show_framerate')
        tv.append('=')
        tv.append('1')
        tv.append('App/test_video.blend')

        p = Popen(tv, stdout=PIPE, stderr=PIPE)

    def OnTestAudio(self, event):

        #DEFAULT FEEDBACK
        if self.dlbf.GetValue() == "":
            self.dlbf.SetValue("128")

        if self.dldv.GetValue() == "":
            self.dldv.SetValue("asio")

        if self.dlsc.GetValue() == "":
            self.dlsc.SetValue(sc[0])

        test = []
        test.append('bin/pd.exe')

        if self.dldv.GetValue() == "":
            test.append('-asio')
        else:
            test.append('-'+str(self.dldv.GetValue()))

        if self.dlsc.GetValue() == "":
            if not self.dldv.GetValue() == "mmio":
                test.append('-audiodev')
                test.append('1')
        else:
            if not self.dldv.GetValue() == "mmio":
                test.append('-audiodev')
                test.append(str(self.dlsc.GetCurrentSelection()+1))

        if self.dlbf.GetValue() == "":
            test.append('-audiobuf')
            test.append('128')
        else:
            test.append('-audiobuf')
            test.append(str(self.dlbf.GetValue()))        

        if self.dlmd.GetValue() == "":
            test.append('-midiindev')
            test.append('1')
        else:
            test.append('-midiindev')
            test.append(str(self.dlmd.GetCurrentSelection()+1))

        test.append('-r')
        test.append('44100')

        test.append('-nogui')

        test.append('-open')
        test.append('App/tone.pd')

        pt = Popen(test, stdout=PIPE, stderr=PIPE)

        #AVOID A BUG WITH MMIO    
        while True:
            ptout = pt.stderr.readline()
            if not ptout:
                break

    def OnTestMidi(self, event):

        tv = []
        tv.append('App/blenderplayer.exe')

        if self.dlre.GetValue() == "":
            tv.append('-p')
            tv.append('0')
            tv.append('0')
            tv.append('640')
            tv.append('480')
        else:
            tv.append('-p')
            tv.append('0')
            tv.append('0')
            tv.append(str(self.dlre.GetValue().split('x')[0]))
            tv.append(str(self.dlre.GetValue().split('x')[1]))

        if self.bfull.GetValue():
            tv.append('-f')

        tv.append('App/test_midi.blend')

        p = Popen(tv, stdout=PIPE, stderr=PIPE)

        test = []
        test.append('bin/pd.exe')

        if self.dldv.GetValue() == "":
            test.append('-asio')
        else:
            test.append('-'+str(self.dldv.GetValue()))

        if self.dlsc.GetValue() == "":
            if not self.dldv.GetValue() == "mmio":
                test.append('-audiodev')
                test.append('1')
        else:
            if not self.dldv.GetValue() == "mmio":
                test.append('-audiodev')
                test.append(str(self.dlsc.GetCurrentSelection()+1))

        if self.dlbf.GetValue() == "":
            test.append('-audiobuf')
            test.append('128')
        else:
            test.append('-audiobuf')
            test.append(str(self.dlbf.GetValue()))        

        if self.dlmd.GetValue() == "":
            test.append('-midiindev')
            test.append('1')
        else:
            test.append('-midiindev')
            test.append(str(self.dlmd.GetCurrentSelection()+1))

        test.append('-r')
        test.append('44100')

        test.append('-nogui')

        test.append('-open')
        test.append('App/oscmidi.pd')

        pt = Popen(test, stdout=PIPE, stderr=PIPE)

        #AVOID A BUG WITH MMIO    
        while True:
            ptout = pt.stderr.readline()
            if not ptout:
                break

    def OnLaunch(self, event):

        #TODO LAUNCH PD
        #SAVE XML

        launch = []
        launch.append('App/blenderplayer.exe')

        if self.dlre.GetValue() == "":
            launch.append('-p')
            launch.append('0')
            launch.append('0')
            launch.append('640')
            launch.append('480')
        else:
            launch.append('-p')
            launch.append('0')
            launch.append('0')
            launch.append(str(self.dlre.GetValue().split('x')[0]))
            launch.append(str(self.dlre.GetValue().split('x')[1]))

        if self.bfull.GetValue():
            launch.append('-f')

        launch.append('App/bounce.blend')

        p = Popen(launch, stdout=PIPE, stderr=PIPE)

    def OnHelp(self, event):
        d = wx.MessageDialog(self, "human can ear sense a latency of 12 ms and above", "Help", wx.OK)
        d.ShowModal()
        d.Destroy()

        #human can ear/sense a latency of 12 ms and above
        #sound takes about 1ms to traval 1 foot
        #Latency is another way of saying delay.
        #If your computer is busy and it doesn't process the audio in time then you will get glitches-pops-clicks in your recordings.

    def OnAbout(self, event):
        d = wx.MessageDialog(self, "GUI for configuring Edubeat\nProgramming by Patrick S├ębastien Coulombe", "About", wx.OK)
        d.ShowModal()
        d.Destroy()

    def OnExit(self, event):
        self.Close(True)

class GMA(wx.App):
    def OnInit(self):
        CSplash = Splash()
        CSplash.Show()
        return True

app = GMA(redirect=True, filename = "demo.log")
app.MainLoop()

Inno Setup code

[Setup]
AppName=Edubeat
AppVerName=Edubeat 0.1
DefaultDirName={pf}\Edubeat
DefaultGroupName=Edubeat
UninstallDisplayIcon={app}\Edubeat.exe
Compression=lzma
SolidCompression=yes
OutputDir=userdocs:edubeatsetup

[Files]
Source: "Edubeat.exe"; DestDir: "{app}"
Source: "msvcr71.dll"; DestDir: "{app}"
Source: "python25.dll"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
Source: C:\gamestarter\bin\*.*; DestDir: {app}\bin; Flags: ignoreversion recursesubdirs
Source: C:\gamestarter\App\*.*; DestDir: {app}\App; Flags: ignoreversion recursesubdirs
Source: C:\gamestarter\DLLs\*.*; DestDir: {app}\DLLs; Flags: ignoreversion recursesubdirs
Source: C:\gamestarter\extra\*.*; DestDir: {app}\extra; Flags: ignoreversion recursesubdirs
Source: C:\gamestarter\Lib\*.*; DestDir: {app}\Lib; Flags: ignoreversion recursesubdirs

[Tasks]
Name: "quicklaunchicon"; Description: "Create a &Quick Launch icon"; GroupDescription: "Additional icons:"; Flags: unchecked
Name: "quickdesktopicon"; Description: "Create a &Desktop icon"; GroupDescription: "Additional icons:"; Flags: unchecked

[Icons]
Name: "{group}\Edubeat"; Filename: "{app}\Edubeat.exe"
Name: "{commondesktop}\Edubeat"; Filename: "{app}\Edubeat.exe"; WorkingDir: "{app}"; Tasks: quickdesktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Edubeat"; Filename: "{app}\Edubeat.exe"; WorkingDir: "{app}"; Tasks: quicklaunchicon
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License