Tutorial: Programar un sencillo reproductor de música en Python



En este tutorial vamos a programar un reproductor de música para Windows en el lenguaje Python. Utilizaremos dos librerias base para esto: PySimpleGUI para el desarrollo de la interfaz grafica y Pygame para la reproducción de audio.

Primero importamos las librerias necesarias:

from pygame import mixer
import pygame
import PySimpleGUI as sg
from threading import Thread
import os

Si no tienes pygame, puedes instalarlo usando pip install pygame, para pysimplegui puedes hacerlo de la misma manera, aunque no sera necesario ya que en los archivos del código incluire un archivo que contiene pysimplegui.

Ahora, vamos a desarrollar el reproductor, primero necesitamos definir una clase reproductor y dentro de ella, como primer punto desarrollar la interfaz grafica.

Definiremos nuestra interaz con 2 botones superiores, uno para seleccionar una canción individual y otro para seleccionar una carpeta completa, además añadiremos una imagen central y 3 botones para pausar la canción, retroceder y continuar a la siguiente.

También añadiremos varias variables que nos permitirán controlar el funcionamiento del reproductor.

class reproductor:
    def __init__(self):
        sg.theme('DarkGreen5')
        # Definimos los elementos de la interfaz grafica
        layout = [[sg.Button(button_text="Seleccionar Carpeta", key="carpeta"), sg.Button(button_text="Seleccionar Cancion", key="cancion")],
                  [sg.Image(filename='logo.png', key='-image-')],
                  [sg.Text(text="-------Nombre de la cancion----", key='name', justification=("center"))],
                  [sg.Button('Anterior'), sg.Button(button_text='Pausar', key="pausa"), sg.Button('Siguiente')]]
        # Creamos la interfaz grafica
        self.window = sg.Window('Reproductor',
                           layout,
                           no_titlebar=False,
                           location=(0, 0))
        self.boton_pausa = self.window['pausa']
        self.nombre_cancion = self.window['name']
        self.ruta = ""
        self.canciones = []
        self.estado = False
        self.posicion = 0
        self.pausa = False
        self.proceso = ""

La función principal sera la de reproducir música, en este caso usando el módulo mixer de la librería pygame sera sencillo de implementar, de esta manera:

def reproducir(self, ruta):
    self.estado = True
    try:

        mixer.init()
        mixer.music.load(ruta)
        mixer.music.set_volume(0.7)
        mixer.music.play()
        while True:
            if self.estado == False:
                break
            elif self.proceso == "pausa":
                mixer.music.pause()
                self.proceso = ""
            elif self.proceso == "continuar":
                mixer.music.unpause()
                self.proceso = ""

    except pygame.error:
        pass

En nuestra función, recibiremos una ruta absoluta sobre la canción a reproducir, inicializando el reproductor con parámetros predefinidos y creando los controles para pausar y continuar. La variable estado nos permitirá saber que se esta ejecutando una canción actualmente.


Ahora, vamos a añadir un par de funciones a nuestra clase, que nos permitirán seleccionar una canción o una carpeta completa:

def cargar_cancion(self, ruta,cancion):
    hilo = Thread(target=self.reproducir, args=(ruta + "/" + cancion, ), daemon= True)
    hilo.start()

def cargar_cancion_unica(self, ruta):
    hilo2 = Thread(target=self.reproducir, args=(ruta,), daemon= True)
    hilo2.start()


En este caso vamos a usar hilos, lo que nos permitirá seguir reproduciendo música aunque estemos realizando otras tareas y asi evitamos que nuestro programa se bloquee. Ambas funciones son similares, la diferencia es que una de ellas solo permite reproducir una canción, y la otra una lista de varias canciones. Ambas finalizando mandando a llamar nuestra función reproducir antes creada.

Ahora vamos a definir el funcionamiento principal del reproductor, que permitirá ejecutar la interfaz grafica y controlar los procesos de selección y reproducción de canciones, el código es el siguiente:

def iniciar(self):
    while True:
        # Obtenemos informacion de la interfaz grafica y video
        event, values = self.window.read(timeout=0)

        if event == "carpeta":
            self.canciones = []
            self.ruta = ""
            self.estado = False
            self.ruta = sg.popup_get_folder(title='Seleccionar Carpeta', message="Carpeta")
            for archivo in os.listdir(self.ruta):
                if archivo.endswith(".mp3"):
                    self.canciones.append(archivo)
            print(self.canciones)
            print(self.ruta)
            if len(self.canciones) == 0:
                pass
            else:
                self.nombre_cancion.update(self.canciones[0])
                self.cargar_cancion(self.ruta, self.canciones[0])
        elif event == "cancion":
            self.canciones = []
            self.ruta = ""
            self.estado = False
            self.ruta = sg.popup_get_file(title='Seleccionar Cancion', message="Cancion", file_types=(("MP3 Files", "*.mp3"),("OGG Files", "*.ogg"),)))
            #self.nombre_cancion.update(self.ruta)
            print(self.ruta)
            self.cargar_cancion_unica(self.ruta)
        elif event == "Siguiente":
            self.posicion = self.posicion + 1
            self.estado = False
            self.nombre_cancion.update(self.canciones[self.posicion])
            self.cargar_cancion(self.ruta, self.canciones[self.posicion])
        elif event == "Anterior":
            if self.posicion >= 0:
                self.posicion = self.posicion - 1
            self.estado = False
            self.nombre_cancion.update(self.canciones[self.posicion])
            self.cargar_cancion(self.ruta, self.canciones[self.posicion])

        elif event == "pausa":
            if self.pausa == False:
                self.boton_pausa.update(text = "Continuar")
                self.proceso = "pausa"
                self.pausa = True
            elif self.pausa == True:
                self.boton_pausa.update(text = "Pausar")
                self.proceso = "continuar"
                self.pausa = False


        else:
            pass
        # Si salimos
        if event in ('Exit', None):
            break

El ciclo while se ejecutara siempre, a menos que se salga del programa, lo cual permitirá actualizar la interfaz grafica y recibir eventos de la misma.

Si se recibe el evento clic de que se seleciono la opción de cargar una canción, ya sea a través de una carpeta o individual, ejecutaremos un popup para permitirle al usuario seleccionar el archivo.

        if event == "carpeta":
            self.canciones = []
            self.ruta = ""
            self.estado = False
            self.ruta = sg.popup_get_folder(title='Seleccionar Carpeta', message="Carpeta")
            for archivo in os.listdir(self.ruta):
                if archivo.endswith(".mp3"):
                    self.canciones.append(archivo)
            print(self.canciones)
            print(self.ruta)
            if len(self.canciones) == 0:
                pass
            else:
                self.nombre_cancion.update(self.canciones[0])
                self.cargar_cancion(self.ruta, self.canciones[0])
        elif event == "cancion":
            self.canciones = []
            self.ruta = ""
            self.estado = False
            self.ruta = sg.popup_get_file(title='Seleccionar Cancion', message="Cancion", file_types=(("MP3 Files", "*.mp3"),("OGG Files", "*.ogg"),)))
            #self.nombre_cancion.update(self.ruta)
            print(self.ruta)
            self.cargar_cancion_unica(self.ruta)

Una vez seleccionada la carpeta o archivo, ejecutaremos la función para cargar canción, usando los hilos, y de este modo iniciando la reproducción de la canción.

Si se selecciona una carpeta, contaremos con una lista de canciones a reproducir, con las cuales podremos adelantarlas, regresar, pausar y reproducir. Los controles se ejecutan de esta manera:

      elif event == "Siguiente":
            self.posicion = self.posicion + 1
            self.estado = False
            self.nombre_cancion.update(self.canciones[self.posicion])
            self.cargar_cancion(self.ruta, self.canciones[self.posicion])
        elif event == "Anterior":
            if self.posicion >= 0:
                self.posicion = self.posicion - 1
            self.estado = False
            self.nombre_cancion.update(self.canciones[self.posicion])
            self.cargar_cancion(self.ruta, self.canciones[self.posicion])

        elif event == "pausa":
            if self.pausa == False:
                self.boton_pausa.update(text = "Continuar")
                self.proceso = "pausa"
                self.pausa = True
            elif self.pausa == True:
                self.boton_pausa.update(text = "Pausar")
                self.proceso = "continuar"
                self.pausa = False

De modo que podremos controlar su ejecución al completo. Si queremos salir del programa, simplemente debemos dar clic en el icono de cerrar.

El funcionamiento final, quedara de la siguiente manera:

Para finalizar, debo aclarar que si bien podemos reproducir música de manera fácil usando pygame y los archivos mp3 son soportados, bajo ciertas codificaciones es imposible reproducir algunos archivos mp3 originando errores, donde lo ideal es reproducir únicamente archivos .ogg, aunque podemos realizar ciertos trucos convirtiendo los .mp3 a .ogg en tiempo de ejecución usando tempfiles en Python y de este modo volver el reproductor compatible completamente.

Como siempre, el código fuente puedes encontrarlo a continuación:


También te podría gustar...

1 respuesta

  1. Bihotza dice:

    Hola! Estoy empezando con Python y me ha ayudado mucho tu publicacion. Me gustaria poder usar el reproductor en una aplicacion web pero no consigo que funcione. En la consola me dan muchos errores que no consigo solucionar. Sabrias decirme si este reproductor se puede usar en una web? O que tendria que cambiarle? Gracias de antemano, un saludo!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Disponible para Amazon Prime