wxPython: XRC and wx.Dialogs

This is a post that arose from a question I submitted to the wxpython user group. I was just not able to call a custom dialog that I created in an XRC file. As a side note, what I find most amazing is, that it is so easy to get in touch with the main guys of the project. In fact, Robin Dunn, the guy who started wxpython, answered my question… I wasn’t surprised when it worked out of the box 😉

Basically, I didn’t understand how to call a wxDialog from an XRC file. I was falling over myself left, right and centre trying to figure it out and at the end I was just plain confused. My answer came in the form of a 2-Stage Creation Process (<– really do read that link) that allows a "load on self" approach. This approach opens up a whole load of new options and makes using XRC really easy. Especially the part about the subclass, I like. Anyhow, I go off in tangents. Ok code. This is how it was done in the end:

class ConfigDialog(wx.Dialog):
def __init__(self, parent):
self.res = xrc.XmlResource("config_dialog.xrc")
pre = wx.PreDialog()
self.res.LoadOnDialog(pre, parent, "ConfigDlg")
self.PostCreate(pre)

As you can see, there is hardly any magic involved. You create the PreDialog (or PreFrame etc.). Load the Dialog and any other flags you may want to add to it, if the need arises. Once that is done you can use PostCreate and everything's peachy. I like it.

wxPython: Inserting an unknown control in XRC to use a custom widget

I’ve been quite busy lately with getting my application done and it has improved by leaps and bounds (I may go into the intricacies of lxml, but I think the tutorials are fairly comprehensive). Most of it was basic stuff that just needed to be pieced together, so there was no real reason to post any code. All of it is documented fairly well in the wxpython wiki and its many, many tutorials (I’m too lazy to mention them this time, just do a google search).

However, recently I came across an issue that annoyed me a little and I finally got round to addressing it. I wanted to have a bitmap button in toggle state (2-state). Unfortunately, wxpython does not allow bitmap buttons to have a toggle state 😦 The answer to this was the use of a PlateButton (Here’s a good introductory tutorial). But since this is a custom widget of the wxpython library, I am not able to use it in XRC, since it is based on wxWidgets.

So what to do? After asking many a lovely person on the interwebs, I finally found a satisfactory but not complete answer. The solution lay with the XmlResource.AttachUnknownControl function (Tutorial).

It allows you to enter a placeholder within the XRC file which can be later filled using the above function. The code I used goes as follows:

First the placeholder was inserted with the following code within the XRC file:


This was followed by the insertion of the following code into my python file:

class MyFrame(wx.Frame):
    def __init__(self, parent):
        self.res = xrc.XmlResource("my_xrc_file.xrc")
        self.frame = self.res.LoadFrame("MyFrame")

        imageFile = "/a/path/to/your/file"
        png = wx.Image(imageFile, wx.BITMAP_TYPE_ANY).ConvertToBitmap()

        self.MyBtn = wx.lib.platebtn.PlateButton(self.frame, bmp=png,
                style=platebtn.PB_STYLE_TOGGLE|platebtn.PB_STYLE_DEFAULT)
        self.PlateBtn = self.res.AttachUnknownControl("MyBtn",
                                        self.MyBtn, self.frame)
 

There really is nothing exciting about the code in this example apart from the fact that you need to know that the possibility exists. Self.PlateBtn returns a bool so you need to bind your functions to self.MyBtn. Very useful to know this.

So far, I have not been able to affect the platebutton after I initialised it, that is a bit of a downside and unfortunately it looks entirely different to the rest of the buttons. I will probably end up changing all of the buttons to platebuttons, just for consistency. As a consequence, the XRC file is a bit useless, but hey, thats life.

RPG Music’N’SFX – How to filter using tags

I’ve been pondering over the same question for the best part of a day today. It is a very simple question, but difficult to answer, because it depends on habits.

My filtering system relies on tags for each file, i.e. every file has a potentially unlimited amount of tags you can add to it. But the big question I have is: how should I filter it?

There are two possibilities that I can see; Say you are searching for the tags “safe” and… Dunno “arabic”. Does that now mean that only the files that have “both” those tags should show up or should all files that have at least one of them show up…

Talking python code, for the former option, I would imagine that I would have a dictionary of the tags as keys and lists of filepaths. These would feed into a set as a tracklist pool a bit like the following:

tag_dict = {"safe" : ["an/example/file.mp3", "another/file.wav"],
           "travel" : ["an/example/file.mp3",
                       "unrelated/other/file.ogg"]}

# this would lead to playlist with both tags present looking
# as follows:

playlist = set(["an/example/file.mp3",
                "another/file.wav",
               "unrelated/other/file.ogg"])

In the latter case, I would probably just have a dictionary of the filepath as the key and its tags as a list in the values. Then whenever another tag is added or removed, I would iterate over the dictionary and check if all tags are present in the list using set.intersection (That is something I learnt from here). If that is the case, it will be added to the playlist. A bit like so:

track_dict = {"an/example/file.mp3" : ["safe", "travel"],
              "another/file.wav" : ["safe"],
              "unrelated/other/file.ogg" : ["travel"]}
 
playlist = []

choices = set(["safe", "travel"])
# i.e. only the first should be in the playlist

for key in track_dict:
    tags = set(track_dict[key])
    intersect = list(tags.intersection(choices))
    if intersect == list(choices):
        playlist.append(key)

print playlist

My tendency, user-wise, goes towards the latter as it seems more logical to me, but I have noticed on several separate occasions that this means, in fact, nothing. My brain tends not realise the most “common” modus operandi.

I am tempted to try and implement both and give the user the choice…

Using Gstreamer with Python2.6 in Windows XP – Pt. 4 Incorporating it all into wxPython

(Original post from 01. Nov. 2011)

Hi folks, back again for the next round. This time all I will do, is just putting Gstreamer and wxPython together. Nothing fancy at all. This post is based on the GStreamer Tutorial with the difference that I will only use the playbin instead of the pipeline, simply because I could not find a suitable mp3 decoder available for Windows at the time of writing this. I am sure there are suitable ones out there, but my measly skills couldn’t make them work. I could have tried the python ctypes library to get the winLame DLLs to work, but it just didn’t seem worth the hassle with mp3play available…

Anyhow, so essentially I just inserted the code from the previous post into a simply GUI with wxPython. Anyone who knows wxPython and read the previous post, will not see anything new. So here is the code and we’ll talk about it afterwards.

NOTE: I used an XRC file to represent the GUI. This is personal preference and the files can be downloaded here.

#!usr/bin/python

import os
import urllib

import pygst
pygst.require("0.10")
import gst

import wx
from wx import xrc

class SimpleAudio(wx.App):
    """
    Class definition of the GUI front end and its functionality
    """

    def OnInit(self):
       
        # Load GUI info frm xrc file
        self.res = xrc.XmlResource('simpleAudio.xrc')
        self.init_frame()
        return True

    def init_frame(self):
       
        self.frame = self.res.LoadFrame(None, 'simple_audio')
        self.panel = xrc.XRCCTRL(self.frame, "main_panel")
       
        self.init_panel()
       
        self.frame.Show()
       
    def init_panel(self):
       
        # Gstreamer player
        self.player = gst.element_factory_make("playbin2", "player")
        fakesink = gst.element_factory_make("fakesink", "fakesink")
        self.player.set_property("video-sink", fakesink)
       
        self.path_txt = xrc.XRCCTRL(self.panel, "path_txt")
        self.play_btn = xrc.XRCCTRL(self.panel, "play_btn")
        self.open_btn = xrc.XRCCTRL(self.panel, "open_btn")
       
        self.panel.Bind(wx.EVT_BUTTON, self.on_play, id=xrc.XRCID('play_btn'))
        self.panel.Bind(wx.EVT_BUTTON, self.on_open, id=xrc.XRCID('open_btn'))
   
    def on_play(self, event):
        if self.play_btn.GetLabel() == "Play":
            filepath = self.path_txt.GetValue()
            path = urllib.pathname2url(filepath)
           
            if os.path.isfile(filepath):
                self.play_btn.SetLabel("Stop")
                self.player.set_property("uri", "file:" + path)
                self.player.set_state(gst.STATE_PLAYING)
        else:
            self.player.set_state(gst.STATE_NULL)
            self.play_btn.SetLabel("Play")
           
    def on_open(self, event):
       
        dlg = wx.FileDialog(self.frame, message="Open an ogg or wav file",
                    wildcard = "OGG, WAV Files (.ogg;.wav;)|*.ogg;*.wav;",
                    defaultDir=os.getcwd(),
                    defaultFile="", style=wx.OPEN)
       
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.path_txt.SetValue(path)
                         
        dlg.Destroy()

if __name__ == '__main__':
    app = SimpleAudio(False)
    app.MainLoop()

So, as you can see, we’ve essentially transferred parts of the GStreamer syntax into the frame initialisation, so that it is ready.

        ...
        # Gstreamer player
        self.player = gst.element_factory_make("playbin2", "player")
        fakesink = gst.element_factory_make("fakesink", "fakesink")
        self.player.set_property("video-sink", fakesink)
        ...

This is a direct copy and paste job. The only thing that is a little step further is in the function “on_play”:

    ...
    def on_play(self, event):
        if self.play_btn.GetLabel() == "Play":
            filepath = self.path_txt.GetValue()
            path = urllib.pathname2url(filepath)
           
            if os.path.isfile(filepath):
                self.play_btn.SetLabel("Stop")
                self.player.set_property("uri", "file:" + path)
                self.player.set_state(gst.STATE_PLAYING)
        else:
            self.player.set_state(gst.STATE_NULL)
            self.play_btn.SetLabel("Play")
    ... 

here you will find the second part of the code from the last post with the difference that we now also give the option of “stopping” the song. Yes it may seem outlandish to want to stop a song, but I incorporated it anyway for all those non-conventional types 😉
Summing the code up: We get the path from the text control, check if the path is valid, convert to a url format and play it. That’s it really. No big deal.
Well, if I feel like it, I will try and expand on this player and include a song progress bar and a playlist, just to show you more of it, but we’ll see. Not sure yet, to be honest.

Using Gstreamer with Python2.6 in Windows XP – Pt. 3 Playing Sound Files – Which Formats Work?

(Original post from 30. Oct. 2011)

Ok, so, the last time, I managed to write a very minimalistic script that gave off a static noise and nothing more. This time, I want to use the same core script, but manage to play a music file and while doing that test the waters for format compatibility. With open source libraries, there is always an issue with mp3, so I was not too hopeful.
So, here goes. This time, I will try to use the current GStreamer documentation (http://pygstdocs.berlios.de/pygst-tutorial/playbin.html ) and extract the basic functionality from the gtk clutter. What I came up with was the following:

import os
import urllib

import pygst
pygst.require("0.10")
import gst
import gobject
gobject.threads_init()

p = os.path.join("My", "path", "to", "my", "file")
path = urllib.pathname2url(p)

player = gst.element_factory_make("playbin2", "player")
fakesink = gst.element_factory_make("fakesink", "fakesink")
player.set_property("video-sink", fakesink)

player.set_property("uri", "file:" + path)
player.set_state(gst.STATE_PLAYING)

gobject.MainLoop().run()

Two things that have to be said about the above code.

[h3]1. Why urllib?[/h3]
I had a problem, feeding gstreamer a proper uri and I always had a horrible error

0:00:00.109375000 1472 00A55488 ERROR baesrc gstbasesrc.c:2974:gst_base_src_activate_pull:(source) Failed to start in pull mode

Converting the path to a url seemed to do the trick. I am assuming this has something to do with the way Windows marks paths as opposed to Linux.

[h3]2. Playbin2 – What’s that?[/h3]
Yea, that is from the tutorial. Apparently, just throw anything in and it tries to play it. If you want to only play Audio, you need to blank out the videosink with an in-build fakesink (as above).

Now when testing it, I checked the formats .ogg, .wav, and .mp3. Unfortunately, as I suspected, while ogg and wav work very well, mp3s are not played by gstreamer. There is Fluendo (http://www.fluendo.com/shop/product/fluendo-mp3-decoder/) but that does not supply for any Windows Versions… unfortunately. If anyone, finds a way to use gstreamer for mp3s, please let me know.

As an alternative, I found mp3play ( http://code.google.com/p/mp3play/ ) , which looks very good and seems to be able to do all the things I want it to do.

The last thing I wanted to test was, whether gstreamer can play more than one file at the same time. This is essential to what I am trying to achieve in the long run. Building on the above code, I just repeated what I did and created two instances. This worked as wanted. If I have any problems later on, i am sure, I will find out in the process.

import os
import urllib

import pygst
pygst.require("0.10")
import gst
import gobject
gobject.threads_init()

# First audio
p1 = os.path.join("My", "path", "to", "my", "file")
path1 = urllib.pathname2url(p1)

player1 = gst.element_factory_make("playbin2", "player1")
fakesink1 = gst.element_factory_make("fakesink", "fakesink")
player1.set_property("video-sink", fakesink1)

player1.set_property("uri", "file:" + path1)
player1.set_state(gst.STATE_PLAYING)

# Second audio
p2 = os.path.join("My", "path", "to", "my", "other", "file")
path2 = urllib.pathname2url(p2)

player2 = gst.element_factory_make("playbin2", "player2")
fakesink2 = gst.element_factory_make("fakesink", "fakesink")
player2.set_property("video-sink", fakesink2)

player2.set_property("uri", "file:" + path2)
player2.set_state(gst.STATE_PLAYING)

gobject.MainLoop().run()

Using Gstreamer with Python2.6 in Windows XP – Pt. 2 A Minimal Example

(Original post from 30. Oct. 2011)

Right folks, so first things first. Let’s try and get something easy going. You know, nothing fancy. Just a simple output. No gui nothing. For that, as a starting point, I chose the tutorial from the following website:

http://www.jonobacon.org/2006/08/28/getting-started-with-gstreamer-with-python/

In this tutorial (feel free to browse, it’s good), the author writes a very good introduction to what GStreamer is all about and explains the mechanics (Sinks, Pipelines etc.)… Unfortunately for me, for Linux. He gives a script that plays an audible tone, just to test if everything is working fine. Of course, taking it over to Windows is an issue.
Here is the code as quoted on JonoBacon’s website (many thanks for it):

#!/usr/bin/python

import pygst
pygst.require("0.10")
import gst
import pygtk
import gtk

class Main:
    def __init__(self):
        self.pipeline = gst.Pipeline("mypipeline")

        self.audiotestsrc = gst.element_factory_make("audiotestsrc", "audio")
        self.pipeline.add(self.audiotestsrc)

        self.sink = gst.element_factory_make("alsasink", "sink")
        self.pipeline.add(self.sink)

        self.audiotestsrc.link(self.sink)

        self.pipeline.set_state(gst.STATE_PLAYING)

start=Main()
gtk.main()

If you try the same code as stated on the website, you will receive a

gst.ElementNotFoundError: alsasink

in windows. After some browsing the web and learning about the combination of cygwin and the gst-inspect and gst-launch commands (google it, if you want to know more), I finally found the answer. First though, here are the website, I had that were useful to me in this instance:

http://www.jonobacon.org/2006/08/28/getting-started-with-gstreamer-with-python/

http://gstreamer.freedesktop.org/data/doc/gstreamer/head/faq/html/chapter-using.html#using-sound

The problem lies with using “alsasink”. ALSA is Linux’ way of playing sound. The equivalent of DirectSound for Windows if you want. Therefore, you need to find the right sink, to play audio on Windows. Alsasink won’t cut it, as it quite clearly is made for Linux. After trying several sinks via trial and error (osssink, esdsink, artsdsink, etc.) and no joy, I tried cygwin and gst-inspect to figure out which one I had, but this was also not successful. Finally, after a while, I came across a totally unrelated site, that mentions “autoaudiosink” as the auto-detect for your sound. Replacing “alsasink” with “autoaudiosink” and voilá, the sound was there when the script was run. Just careful and don’t turn the volume up too high. I did after a million and two failed tries and it almost blew me off my chair :D.

One last thing that I wanted to address was the pseudo-dependency on gtk. I say, pseudo, because the grand majority of examples were given with pygtk and thus most people have used gtk with it. Again a little bit of searching around, I found that the need for a gtk.main() call, was simply because GStreamer uses the Gobject module and its threads (see among others, this forum post: http://ubuntuforums.org/showthread.php?t=1168455 ). Once I found that, I was able to remove the gtk and pygtk import and replace it with the gobject import and the code still ran.
Thus, to some things up, the minimal example that works for Windows is as follows:

#!/usr/bin/python

import pygst
pygst.require("0.10")
import gst

# replaces the call to gtk and pygtk
import gobject
gobject.threads_init()

class Main:
def __init__(self):
self.pipeline = gst.Pipeline("mypipeline")

self.audiotestsrc = gst.element_factory_make("audiotestsrc", "audio")
self.pipeline.add(self.audiotestsrc)

self.sink = gst.element_factory_make("autoaudiosink", "sink")
self.pipeline.add(self.sink)

self.audiotestsrc.link(self.sink)

self.pipeline.set_state(gst.STATE_PLAYING)

start=Main()
gobject.MainLoop().run() # instead of gtk.main()

Having this in hand, I will next look at playing a simple audio file and testing the scope, i.e. which common formats work and if I can play several at the same time. Since I was able to remove gtk and replace it with gobject, I can now use wxpython to serve as my GUI of choice.

Using Gstreamer with Python2.6 in Windows XP – Pt. 1 Introduction and Installation

(Original post from 31.10.2011)

The three reasons why I feel it useful to compile my experiences with GStreamer under Windows XP, although I am not a good programmer, are as follows.

  1. There isn’t much information on how to effectively install GStreamer bindings with Python2.6 and I ran into some wonderfully confusing problems
  2. All the examples I found, were written for Linux. This caused me some problems for example in terms of knowing which “sink” to use (we’ll get to that I am sure) as they are very different from Linux to Windows
  3. The majority of examples use “pygtk” as the library to make the GUI. While I have nothing against Pygtk, I am used to wxpython in particular, and I would like to have examples without any GUI in general. Kind of a minimal example.

I will try and link to tutorials and information as I go along and quote their code, just in case, the site gets taken down sometime or something like that. The reason, I want to use GStreamer is because I want to write an audio tool for my roleplaying group that can play several audio files at the same time (mp3, ogg or wav) while being cross platform (Windows and Linux, but mostly Windows). As mentioned, the examples in Linux were plenty, Windows less so. I wrote one of those before, so all the functionality around it is already present, but the library didn’t quite cut it for me. There were irresolvable issues with it.

Installation
Let’s start with the installation, which has been quite the charmer for me. NOTE: This for an installation of Gstreamer with bindings to Python2.6.

I tried it with cygwin, as well, because I had so many problems with the “standard” way, but that just led to even more frustration. Mostly because I do not know how to use cygwin properly, I am sure.

Anyhow, go to the following website:

http://code.google.com/p/ossbuild/

and download and install “GStreamer-WinBuilds-GPL-x86.msi” & “GStreamer-WinBuilds-SDK-GPL-x86.msi”

Good, now comes the part that took me the best part of two days to figure out. The SDK installation does not install the bindings directly into your Python installation. I had to do that manually.
I went to:

..\OSSBuild\GStreamer\v0.10.6\sdk\bindings\python\v2.6\lib\site-packages

In your Gstreamer installation and copied and pasted the contents into the following folder in my Python2.6 installation

..\Python26\Lib\site-packages

If you would start an interpreter now, you could import pygst no problem, BUT (there is always a but) not the module “gst”. This was rather vexing. I finally, after about two days of feeling like an idiot, looked at the contents I copied and pasted. There you find a folder named “gst-0.10” and inside that folder was a folder called “gst”. By moving that folder directly into site-packages, I was finally able to import gst in my python interpreter.

There you go, you can now use Gstreamer together with Python2.6.