Sunday, December 30, 2007

Tablet Python #2 - Resource Modules

Introduction

In this second episode of Tablet Python, I'm going to tell you about an easy way to make resource modules. A resource module is a Python module which you can import for loading resources such as images, fonts, or whatever you want.

For example:

import graphics

img = gtk.Image()
img.set_from_pixbuf(graphics.icon)


Implementation

In episode #1 we talked about writing relocatable software. We are going to apply the same technique for resource modules, since they will be relocatable as well.

Our resource modules are Python packages, i.e. a subdirectory with a __init__.py file in it. The name of the directory will be the module's name. Be careful to only use valid characters (characters valid for Python variables) in the directory name and the filenames of the resource files (e.g., my_icon.png is OK, while my-icon.png would be not!).

Let's assume the following filesystem structure for our example:

graphics/
+ __init__.py
+ icon.png
+ logo.png
+ background.png

test.py

The package directory will also contain the resource files. In order to access them, we'll have to put them into the module namespace. Write the following into graphics/__init__.py:

import os
import gtk

_RESOURCE_PATH = os.path.dirname(__file__)

def _load_resources():

# Find all .png files in the resource directory. This construct is called
# "list comprehension" and will be covered in detail in episode #3.
# This returns a list of the names of all files in the resource directory
# ending with ".png".
resources = [ f for f in os.listdir(_RESOURCE_PATH)
if f.endswith(".png") ]

# load resources into module namespace
for r in resources:

# the filename without extension will be the name to access the
# resource, so we strip off the extension
name = os.path.splitext(r)[0]

# this is the full path to the resource file
path = os.path.join(_RESOURCE_PATH, r)

# Now we can load the resource into the module namespace.
# globals() gives us the dictionary of the module-global variables,
# and we can easily extend it by assigning new keys.
globals()[name] = gtk.gdk.pixbuf_new_from_file(path)

#end for

# load the resources when importing the module
_load_resources()

That's all. Let's test it with a tiny test program test.py:

import gtk
import graphics

win = gtk.Window(gtk.WINDOW_TOPLEVEL)
img = gtk.Image()
img.set_from_pixbuf(graphics.logo)
win.add(img)
win.show_all()

gtk.main()

You may put as many resource files as you want into the resource directory and simply access them by their name. The files are loaded only once when the module gets imported the first time. Subsequent import statements reuse the module without reloading the resources. I'm going to talk about the "singleton" nature of Python modules in a later episode.

A more sophisticated example of resource modules can be found in the theming engine of MediaBox (the subdirectory called theme).

Monday, December 24, 2007

MediaBox doesn't like winter?

There crawled a stupid little bug into MediaBox which made it dislike winter. A bug in the clock module made it return bogus data during winter. Since winter started recently, MediaBox failed to start up after December 22nd.

clock

The new release 0.92.1 fixes this. Now you can enjoy MediaBox again!


Merry Christmas!

Monday, December 17, 2007

MediaBox with Internet Radio

Now you can listen to internet radio stations (MP3, Ogg, AAC, etc; realaudio not supported) with the MediaBox Media Center.

The new release also features fullscreen song information.
MediaBox Song Info

The package installs on OS 2007, OS 2008, and even OS 2006. Not all features are enabled on OS 2006 at the moment, though.

Have fun and don't hesitate to report any bugs.

Tuesday, December 11, 2007

Important Bugfix for MediaBox

I have just released MediaBox 0.91.1 to fix a critical bug in 0.91. If you're using MediaBox 0.91 with FM radio you should upgrade!

MediaBox 0.91 has a bug which can break the radio stations list in the FM radio applet. After the list is broken, MediaBox will hang during startup. The new release fixes this.

Sunday, December 9, 2007

MediaBox gets FM radio

I have been busy getting FM radio in the MediaBox media center ready for release. So if you have a N800 (the only Nokia internet tablet with built-in FM tuner chip so far), you will get the radio button at the bottom.

FM radio in action

But the new release will also bring some improvements to N810 users (sorry, no FM radio on the N810...). Kinetic scrolling is now smoother without the occasional "hiccups" while playing an audio file. Some bugs have been squashed as well.

Oh, and since MediaBox uses pyFMRadio for the FM radio, I made a new release of this as well. The new version has improved signal scanning for automatic station detection.

Saturday, December 1, 2007

Tablet Python #1 - Relocatable Software

Python is becoming more and more popular for development on the Nokia internet tablets. It is indeed a very powerful and clear language and makes it easy to write applications that work on all internet tablet versions.

With this post I'm starting a new series on nice Python tricks which might be interesting to tablet software developers. So, if you're doing something in Python on your tablet, this series is for you!

In this first episode I will talk about writing relocatable software. This is software which works no matter where it's installed. There are no hardwired absolute paths to resources in relocatable software.

Knowing where you are

Every Python module knows the path where it's installed. You can retrieve the module's path by reading the __file__ variable.

print "This module resides at:", __file__

This makes it easy to find the directory where your app is installed:

import os
path = os.path.dirname(__file__)


Finding your resources

So if you want to load bundled resources into your application, you know where to find them:

path = os.path.dirname(__file__)
image_file = os.path.join(path, "images", "foo.png")
img = gtk.Image()
img.set_from_file(image_file)


Starting the application

This is the way I use to make my programs executable on the tablet. All of the program files and resources are within a subdirectory (e.g. /usr/lib/myapp/) together with the executable start module, which could look like this:

#! /usr/bin/env python

from mediabox.App import App

app = App()
app.run()

Let's assume this file is /usr/lib/mediabox/MediaBox. Then I make a symbolic link to this file as /usr/bin/MediaBox, and it's all done.

If I move my software to another place, I would just have to update this link.

Tuesday, November 27, 2007

MediaBox 0.90.1 addresses the gconf issue

It seems that the gconf Python bindings are not available on every installation of pymaemo. Thus many users (mainly OS 2008) were not able to run the MediaBox media center. This release is for you!

MediaBox 0.90.1 falls back to using gconftool-2, if no gconf bindings are available. As a side-result, version 0.90.1 will now also start on the Nokia 770 with OS 2006 and sorta works (kinetic scrolling looks incredibly smooth on the 770, actually smoother than on the N800, but the 770 will choke on too many thumbnails for now).

Thanks to all those who reported problems and helped me locate the gconf bug.

Monday, November 26, 2007

MediaBox Enters the Stage


Finally, the first version of MediaBox has been released. This is an
extremely finger-friendly media center for the N800 and N810 internet tablets.
The Nokia 770 should be supported with a later release.




Let the screenshots speak:












Monday, November 19, 2007

N800's FM radio now works in Japan

My kernel patch for FM band selection on the N800 was confirmed to work in Japan. Now I'm going to clean it up a little and improve support for it in pyFMRadio. Thanks to Kenroy Harrison for testing it!

Sunday, November 18, 2007

Enabling FM band selection on the N800

The Nokia N800 has a built-in FM radio which can't currently be used in Japan since Japan uses a different FM band (76 MHz to 90 MHz) than Europe and the US (87.5 MHz to 108 MHz).
Thanks to Kenroy Harrison for pointing this out.

The TEA5761 FM chip on the N800 supports the Japanese band by setting the BLIM bit but this is not supported by Nokia's driver code (Nokia doesn't sell the N800 in Japan anyway). So I have built a patched kernel enabling setting the BLIM bit.
The new release of pyFMRadio adds support for this kernel and allows switching the FM band.


If you have a N800 and are currently in Japan, please test this Python code and report if it's actually working:


from FMRadio import FMRadio
import time

r = FMRadio()
r.set_fm_band(r.FM_BAND_JPN)
for freq in r.scan():
r.set_frequency(freq)
r.set_volume(50)
time.sleep(3)
r.close()

Monday, November 12, 2007

pyFMRadio and auto-scanning

PyFMRadio, the N800 FM radio module for Python now supports automatic scanning for radio stations in the new release 0.20. The new version now also powers down the radio chip on close(), so it won't drain battery when the radio is not used.

Here's some example code for callback-based station scanning:


# import radio stuff
from FMRadio import FMRadio, FMRadioUnavailableError


stations = []


def scan_cb(freq, is_station):
"""
Callback for scanning for stations. This callback is called for every
frequency and tells you if a radio station was found.
"""

print "scanning @ %0.2f MHz" % (freq / 1000.0),
if (is_station):
print "STATION FOUND"
stations.append(freq)
else:
print ""



# open the radio
try:
radio = FMRadio()
except FMRadioUnavailableError:
# radio not available
print "Your device doesn't seem to have a FM radio..."
import sys; sys.exit(1)

# get frequency range; currently only the US/Europe frequency band is supported
# by the driver
low, high = radio.get_frequency_range()
print "Frequency range: %0.2f - %0.2f MHz" % (low / 1000.0, high / 1000.0)

# scan for radio stations
radio.scan(scan_cb)

# if we have found some stations, start playing
if (stations):
radio.set_volume(50)

print "Now listen to the radio."
for freq in stations:
print "Tuning in %0.2f MHz." % (freq / 1000.0)
radio.set_frequency(freq)
import time; time.sleep(3)

else:
print "No radio stations found. The signal is too weak."

# don't forget to shutdown the radio; this will also power down the radio chip
print "Switching off the radio."
radio.close()

Saturday, November 10, 2007

N810 maemo submission accepted

Here I am to join the lucky posts on planet.maemo.org about getting an N810 discount. Thanks to Nokia for choosing me again! :)

My new media center will soon be ready for the first release. It's already working great, only some rough edges to fix and some performance boosts to apply. When dealing with lots of thumbnail images in an resource-restricted environment such as the N800, you'll have to take special care about clean and efficient programming. And when I say "lots of thumbnail images", I mean that every video, every music ablum, and every image gets a thumbnail preview.

Another big challenge will be to get the app running fine on the Nokia 770. No, this device isn't dead for me yet. Since the video bus of the 770 is actually faster than that of the N800, kinetic scrolling works great there as well. But I'm still struggling with memory limitations and some mplayer issues on the 770.

Wednesday, November 7, 2007

My Work on MediaBox

MediaBox Media Center

Let me introduce MediaBox, a finger-friendly media center
for Nokia internet tablets, to be released in a few days.

This basically started some months ago as an experimental frontend to
mplayer
with physically correct kinetic scrolling for browsing the collection of
video files. But soon it was clear to me that this user interface could do a
lot more, so I added music playback and integrated the image viewer from my
Obscura project.

MediaBox can play video, audio, display images, features a desk clock with
large letters, and is open for new extensions. It will soon be able to use the
FM radio in the N800 with the pyFMRadio project.



Since the media player backend of MediaBox is mplayer, it will be able to play
almost anything you throw at it, including Ogg Vorbis.




PyFMRadio

The Nokia N800 has a built-in FM tuner and I wanted to be able to use this with
MediaBox. So far, the only FM radio application for the N800 seems to be the
closed-source fmradio applet by Nokia. It's good but it's not finger-friendly.

So I started diving into the kernel code and eventually came up with
a way to control the FM tuner chip with pure Python. This might
be useful to other projects as well, so I set up the offspring project
pyFMRadio.

Thursday, October 25, 2007

Moved to blogger.com

I have moved my blog to blogger.com now. My next blog entry will be about MediaBox for maemo again. Expect some screenshots.