Source Files

Most of the code for the application is included in a single main.py file which contains a single Application class to manage the running of the application and a main function to start it.

Much of the code is very similar to other examples and tutorials. We will focus on the parts that are specific to this example.

Relevant Modules

We use the GSound module to enable us to play sounds in a simple way. This module is imported in the same way as the Gtk module:

import os
import sys
import gi

gi.require_version('GSound', '1.0')
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, GSound, Gtk

from . import config

The config module contains a few definitions that allow us to locate the supplied sound files so that they can be played.

Setting up the User Interface

The application provides an Application class with the usual methods to set up the application and perform tasks when it is run. The window is defined in a UI file, created using Glade, but used in a different way to the UI file included with the Treasure example.

In this example, we use the Gtk.Template decorator to make a Window class that represents the window defined in the UI file. An instance of this class is created in the Application class. The Window class begins by relating the definition with objects that represent its child widgets:

@Gtk.Template(resource_path='/com/example/play_sounds/ui/window.ui')
class Window(Gtk.ApplicationWindow):

    __gtype_name__ = 'Window'

    complete_button = Gtk.Template.Child('complete_button')
    shutter_button = Gtk.Template.Child('shutter_button')
    fanfare_button = Gtk.Template.Child('fanfare_button')
    invader_button = Gtk.Template.Child('invader_button')

In the __init__ method, the state of these child widgets is determined by whether it is possible to initialize a sound context, represented by an instance of the GSound.Context class:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.sound_context = GSound.Context()
        sound_available = self.sound_context.init()

        self.complete_button.set_sensitive(sound_available)
        self.shutter_button.set_sensitive(sound_available)
        self.fanfare_button.set_sensitive(sound_available)
        self.invader_button.set_sensitive(sound_available)

If a sound context cannot be initialized, all of these buttons will be non-interactive. With an initialized context, any of the buttons can be clicked to cause a sound to play. This is handled by a collection of callback methods that are automatically connected to signals defined in the UI file.

Playing Sounds

Each of the buttons are connected to a callback where an appropriate sound is played. The first of these plays a standard sound that is usually associated with a desktop event:

    @Gtk.Template.Callback()
    def complete_button_clicked_cb(self, *args):

        self.sound_context.play_simple(
            {GSound.ATTR_EVENT_ID: 'complete'}
        )

The play_simple method of the sound context that was created earlier is used to play the standard “complete” sound. The method accepts a dictionary that describes the sound to be played, and the ATTR_EVENT_ID key is used to specify that an event sound is to be played, with the value being the name of the sound.

We also want to play custom sounds, and we do this in a very similar way, using the same play_simple method. However, we pass a dictionary containing the ATTR_MEDIA_FILENAME key to indicate that the sound is supplied in a file, and with a value that is the name of the file itself:

    @Gtk.Template.Callback()
    def fanfare_button_clicked_cb(self, *args):

        sound_file = os.path.join(config.pkgdatadir, 'sounds', 'fanfare.ogg')

        self.sound_context.play_simple(
            {GSound.ATTR_MEDIA_FILENAME: sound_file}
        )

As a result, when the user clicks the appropriate button, the fanfare.ogg file is loaded and played. To obtain the location of this file, we use the value held by the config.pkgdatadir constant. This is provided by the config Python module that is generated when the application is installed.

Summary

One of the simplest ways to play sounds is by creating a GSound.Context object, initializing it before it is used, then using its play_simple method to play sounds. Both standard event sounds and custom sound files can be played.

The dictionary passed to this method is used to specify which kind of sound will be played, where ATTR_EVENT_ID is useful for playing simple sounds provided with the system, and ATTR_MEDIA_FILENAME is used to play custom sounds provided with the application.