Afinador de guitarra (Python) Usar GTK+ y GStreamer para construir un sencillo afinador de guitarra para GNOME. Muestra cómo usar el diseñador de interfaces. Proyecto de documentación de GNOME gnome-doc-list@gnome.org Johannes Schmid jhs@gnome.org Marta Maria Casetti mmcasetti@gmail.com 2013 Marta Maria Casetti mmcasetti@gmail.com 2013 Daniel Mustieles daniel.mustieles@gmail.com 2011 - 2017 Nicolás Satragno nsatragno@gmail.com 2012 - 2013 Jorge González jorgegonz@svn.gnome.org 2011 Afinador de guitarra

En este tutorial se va a hacer un programa que reproduce tonos que puede usar para afinar su guitarra. Aprenderá a:

Configurar un proyecto básico en Anjuta

Crear una IGU sencilla con el diseñador IU de Anjuta

Usar GStreamer para reproducir sonidos

Necesitará lo siguiente para poder seguir este tutorial:

Una copia instalada del EID Anjuta

Conocimiento básico del lenguaje de programación Python

Crear un proyecto en Anjuta

Antes de empezar a programar, deberá configurar un proyecto nuevo en Anjuta. Esto creará todos los archivos que necesite para construir y ejecutar el código más adelante. También es útil para mantener todo ordenado.

Inicie Anjuta y pulse ArchivoNuevoProyecto para abrir el asistente de proyectos.

Seleccione PyGTK (automake) en la pestaña Python, pulse Continuar, y rellene los detalles en las siguientes páginas. Use afinador-guiterra como nombre del proyecto y de la carpeta.

Pulse Aplicar y se creará el proyecto. Abra src/afinador-guitarra.py desde las pestañas Proyecto o Archivo. Debería ver algo de código que comience con las líneas:

from gi.repository import Gtk, GdkPixbuf, Gdk import os, sys
Ejecutar el código por primera vez

La mayor parte del código del archivo se usa como plantilla. Carga una ventana (vacía) desde el archivo de descripción de interfaz de usuario y la muestra. Se ofrecen más detalles a continuación; omita esta lista si entiende los conceptos básicos:

Las líneas import en la parte superior indican a Python que cargue la interfaz de usuario y las bibliotecas del sistema necesarias.

Se declara una clase que estará en la clase principal de la aplicación. En el método __init__ se carga la ventana principal desde el archivo de GtkBuilder (src/guitar-tuner.ui) y se conectan las señales.

Conectar señales es como se define lo que pasa cuando pulsa un botón, o cuando ocurre algún otro evento. Aquí, se llama al método destroy (y se sale de la aplicación) cuando cierra la ventana.

La función main se ejecuta de manera predeterminada cuando inicia una aplicación Python. Simplemente crea una instancia de la clase principal e inicia el bucle principal para mostrar la ventana.

Este código está listo para usarse, por lo que puede ejecutarlo pulsando EjecutarEjecutar.

Crear la interfaz de usuario

El archivo de GtkBuilder contiene una descripción de la interfaz de usuario (IU). Para editar la interfaz de usuario, abra src/guitar_tuner.ui. Esto cambiará al diseñador de interfaces. La ventana de diseño está en el centro; los widgets y sus propiedades están a la derecha, y la paleta de los widgets disponibles está a la izquierda.

La distribución de cualquier IU en GTK+ se organiza usando cajas y tablas. Aquí se usará una GtkButtonBox vertical para asignar seis GtkButtons, uno para cada una de las cuerdas de la guitarra.

Seleccione una GtkButtonBox de la sección Contenedor de la Paleta de la derecha y póngalo en la ventana. En el panel de Propiedades, establezca el número de elementos a «6» (para las seis cuerdas) y la orientación a «vertical».

Ahora, elija un GtkButton de la paleta y póngalo en la primera parte de la caja.

Mientras el botón esté seleccionado, cambie la propiedad Etiqueta en la pestaña Widgets a E. Esta será la cuerda Mi grave.

Cambie a la pestaña Señales (dentro de la pestaña Widgets) y busque la señal clicked del botón. Puede usar esto para conectar un manejador de señal al que se llamará cuando el usuario pulse el botón. Para hacer esto, pulse sobre la señal, escriba on_button_clicked en la columna Manejador y pulse Intro.

Repita los pasos anteriores para el resto de botones, añadiendo las 5 cuerdas restantes con los nombres A, D, G, B, y e.

Guarde el diseño de la IU (pulsando ArchivoGuardar) y déjelo abierto.

Escribir el manejador de señales

El el diseñador de interfaces, se ha hecho que todos los botones llamen a la misma función, on_button_clicked, cuando se pulsan. Se debe añadir esta función al archivo de código fuente.

Para hacer esto, abra guitar_tuner.py mientras el archivo de la interfaz de usuario está abierto. Cambie a la pestaña Señales, que ya ha usado para establecer el nombre de la señal. Ahora vaya a la fila en la que estableció la señal clicked y arrástrela al archivo de código fuente, dentro de la clase principal. Se añadirá el siguiente código a su archivo de código fuente:

def on_button_clicked (self, button):

Este manejador de la señal tiene dos argumentos: el puntero de clase Python habitual y el Gtk.Button que llamó a la función.

Por ahora, se dejará el manejador de la señal vacío mientras se escribe el código para producir sonidos.

Tuberías de Gstreamer

GStreamer es el entorno multimedia de trabajo de GNOME: puede usarlo para reproducir, grabar y procesar vídeo, sonido, flujos de la cámara web y similares. En este caso, se usará para generar tonos de frecuencia única.

Conceptualmente. GStreamer funciona de la siguiente manera: puede crear una tubería que contenga varios elementos de procesado que van desde la fuente hasta el sumidero (salida). La fuente puede ser, por ejemplo, un archivo de imagen, un vídeo o un archivo de música, y la salida puede ser un widget o la tarjeta de sonido.

Entre la fuente y el sumidero, puede aplicar varios filtros y conversores para manejar efectos, conversiones de formato, etc. Cada elemento de la tubería tiene propiedades que se pueden usar para cambiar este comportamiento.

Un ejemplo de tubería de GStreamer.

Configurar la tubería

En este sencillo ejemplo se usará un generador de tonos llamado audiotestsrc y se enviará la salida al dispositivo de sonido predeterminado del sistema, autoaudiosink. Sólo es necesario configurar la frecuencia del generador de tonos; esto es accesible a través de la propiedad freq de audiotestsrc.

Cambie la línea de importación en afinador_guitarra.py, justo al principio, por:

from gi.repository import Gtk, Gst, GObject

El Gst incluye la biblioteca GStreamer. También debe debe inicializar GStreamer correctamente, lo que se ha hecho en el método main() con esta llamada añadida encima de la línea app = GUI():

Gst.init_check(sys.argv)

Después, copie la siguiente función en la de guitar_tuner.py, en cualquier sitio:

def play_sound(self, frequency): pipeline = Gst.Pipeline(name='note') source = Gst.ElementFactory.make('audiotestsrc', 'src') sink = Gst.ElementFactory.make('autoaudiosink', 'output') source.set_property('freq', frequency) pipeline.add(source) pipeline.add(sink) source.link(sink) pipeline.set_state(Gst.State.PLAYING) GObject.timeout_add(self.LENGTH, self.pipeline_stop, pipeline)

Las tres primeras líneas crean los elementos «fuente» y «sumidero» de GStreamer y un elemento de tubería (que se usará como contenedor de los otros dos elementos). A la tubería se le asigna el nombre «note»; la fuente se llama «source» y se asocia a la fuente audiotestsrc y el sumidero se llama «output» y se asocia con el sumidero autoaudiosink (la salida de la tarjeta de sonido predeterminada).

La llamada a source.set_property establece la propiedad freq del elemento fuente a frequency, que se pasa como argumento a la función play_sound. Esto sólo es la frecuencia de la nota en Hercios; más adelante se definirán algunas frecuencias útiles.

Las dos siguientes líneas llaman a pipeline.add, poniendo la fuente y el sumidero en la tubería. La tubería puede contener muchos otros elementos de GStreamer. En general, puede añadir tantos elementos como quiera a una tubería llamando al método add repetidamente.

El siguiente pipeline.set_state se usar para iniciar la reproducción, estableciendo el estado de la tubería a «playing» (Gst.State.PLAYING).

Detener la reproducción

No se quiere reproducir un tono molesto para siempre, por lo que lo último que play_sound hace es llamar a GObject.timeout_add. Esto establece un tiempo de expiración para detener el sonido; espera LENGTH milisegundos antes de llamar a la función pipeline_stop, y se queda llamando a pipeline_stop hasta que devuelve False.

Ahora se escribirá el código de la función pipeline_stop, llamada por GObject.timeout_add. Inserte el código siguiente encima de la función play_sound:

def pipeline_stop(self, pipeline): pipeline.set_state(Gst.State.NULL) return False

Necesita definir la constante LENGTH dentro de la clase, por lo que debe añadir este código al principio de la clase principal:

LENGTH = 500

La llamada a pipeline.set_state detiene la reproducción de la tubería.

Definir los tonos

Se quiere reproducir el sonido correcto cuando un usuario pulsa un botón. En primer lugar, se necesita conocer las frecuencias de las seis cuerdas de la guitarra, que están definidas (al principio de la clase principal) dentro de un diccionario, por lo que se pueden mapear fácilmente con los nombres de las cuerdas:

# Frequencies of the strings frequencies = { 'E': 329.63, 'A': 440, 'D': 587.33, 'G': 783.99, 'B': 987.77, 'e': 1318.5 }

Ahora se se profundiza en el manejador de la señal definido anteriormente, on_button_clicked. Se podría haber conectado cada botón a un manejador de la señal diferente, pero esto había supuesto duplicar mucho código. En su lugar, se puede usar la etiqueta del botón para saber cuál de ellos se ha pulsado:

def on_button_clicked(self, button): label = button.get_child() text = label.get_label() self.play_sound (self.frequencies[text])

El botón que se ha pulsado se pasa como argumento (button) a on_button_clicked. Se puede obtener la etiqueta de ese botón usando button.get_child, y obteniendo entonces el texto de esa etiqueta usando label.get_label.

La etiqueta de texto se usa como clave para el diccionario, y se llama a play_sound con la frecuencia correspondiente a esa nota. Esto reproduce el tono; el afinador de guitarra ya está funcionando.

Ejecutar la aplicación

Todo el código debería estar listo para ejecutarse. Pulse EjecutarEjecutar para iniciar la aplicación y disfrute.

Implementación de referencia

Si tiene problemas con este tutorial, compare su código con este código de referencia.

Siguientes pasos

Aquí hay algunas ideas sobre cómo puede extender esta sencilla demostración:

Hacer que el programa recorra las notas automáticamente.

Hacer que el programa reproduzca grabaciones de cuerdas de guitarras que se están afinando.

PAra hacer esto, debe configurar una tubería de GStreamer más complicada, que le permite cargar y reproducir archivos de música. Deberá elegir un los elementos decodificador y demultiplexor de GStreamer basándose en el formato del archivo de sus sonidos grabados; los MP3 usan elementos diferentes de los de los archivos Ogg Vorbis, por ejemplo.

Puede querer conectar los elementos de maneras más complicadas. Esto puede implicar usar conceptos de GStreamer que no se han comentado en este tutorial, tales como interfaces. Es posible que encuentre útil el comando gst-inspect.

Analizar automáticamente las notas que toca el músico.

Puede conectar un micrófono y grabar sonidos con él usando una fuente de entrada. ¿Es posible que algún tipo de análisis de espectro le permita saber qué notas se están reproduciendo?