0

I have been building a little musicbox. It should play the mp3 files using mpg123. The music should start when one of the buttons (push button) is depressed (like sensor) it should start playing the tracks from the directory in the random order. There is one button for increasing, one for decreasing volume. Also there is next and previous buttons.

Everything is working properly, for example the song is playing when button is depressed, the volume increase and decrease, the track change after next and previous button is pressed. When the 'box is opened' and next and previous buttons not being pressed after one songs is over next starts to play.

The problem is: when next or previous buttons been pressed, after the track ends, the script fails to play next one. I think it waits for press of another button. It should play next track. The code is:

import RPi.GPIO as GPIO
import subprocess
import random
import os
import time

# Set up GPIO pins
PLAY_BUTTON_PIN = 17
NEXT_BUTTON_PIN = 5
PREV_BUTTON_PIN = 6
BUTTON_INCREASE_PIN = 26
BUTTON_DECREASE_PIN = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(PLAY_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(NEXT_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(PREV_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUTTON_INCREASE_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUTTON_DECREASE_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Set up variables
app_running = False
button_state = GPIO.input(PLAY_BUTTON_PIN)
music_dir = "/home/pi/Downloads/"
music_files = []
music_paths = []
current_song_index = 0

MAX_VOLUME = 70
MIN_VOLUME = 0

command_set = ["amixer", "sset", "Master", "0%"]
command_get = ["amixer", "get", "Master"]

# Define function to start/stop app and play next/previous songs
def toggle_app(channel):
    global app_running
    global button_state
    global current_song_index
    global music_files
    global music_paths
    if channel == PLAY_BUTTON_PIN:
        if GPIO.input(PLAY_BUTTON_PIN) != button_state:
            button_state = GPIO.input(PLAY_BUTTON_PIN)
            if button_state == GPIO.HIGH:
                if not app_running:
                    music_files = os.listdir(music_dir)
                    if len(music_files) == 0:
                        print("No music files found in directory")
                        return
                    random.shuffle(music_files)
                    music_paths = [os.path.join(music_dir, file) for file in music_files]
                    subprocess.Popen(["mpg123", "-Z", *music_paths])
                    app_running = True
                    print(f"mpg123 started with files in directory: {music_dir}")
            else:
                if app_running:
                    subprocess.run(["killall", "mpg123"])
                    app_running = False
                    music_files = []
                    music_paths = []
                    print("mpg123 stopped")
    elif channel == NEXT_BUTTON_PIN:
        if GPIO.input(NEXT_BUTTON_PIN) == GPIO.LOW and app_running:
            subprocess.run(["killall", "mpg123"])
            current_song_index = (current_song_index + 1) % len(music_files)
            subprocess.Popen(["mpg123", music_paths[current_song_index]])
            print(f"Playing next song: {music_files[current_song_index]}")
    elif channel == PREV_BUTTON_PIN:
        if GPIO.input(PREV_BUTTON_PIN) == GPIO.LOW and app_running:
            subprocess.run(["killall", "mpg123"])
            current_song_index = (current_song_index - 1) % len(music_files)
            subprocess.Popen(["mpg123", music_paths[current_song_index]])
            print(f"Playing previous song: {music_files[current_song_index]}")

# Set up interrupts
GPIO.add_event_detect(PLAY_BUTTON_PIN, GPIO.BOTH, callback=toggle_app, bouncetime=200)
GPIO.add_event_detect(NEXT_BUTTON_PIN, GPIO.FALLING, callback=lambda x: toggle_app(NEXT_BUTTON_PIN), bouncetime=200)
GPIO.add_event_detect(PREV_BUTTON_PIN, GPIO.FALLING, callback=lambda x: toggle_app(PREV_BUTTON_PIN), bouncetime=200)

while True:
    if not GPIO.input(BUTTON_INCREASE_PIN):
        # Increase volume by 3%
        result = subprocess.run(command_get, capture_output=True, text=True)
        current_volume = int(result.stdout[result.stdout.find('[')+1:result.stdout.find('%')])
        print("Current volume:", current_volume, "%")
        new_volume = current_volume + 3
        if new_volume > MAX_VOLUME:
            new_volume = MAX_VOLUME
        command_set[3] = str(new_volume) + "%"
        subprocess.run(command_set)
        print("Volume set to:", new_volume, "%")

    if not GPIO.input(BUTTON_DECREASE_PIN):
        # Decrease volume by 3%
        result = subprocess.run(command_get, capture_output=True, text=True)
        current_volume = int(result.stdout[result.stdout.find('[')+1:result.stdout.find('%')])
        print("Current volume:", current_volume, "%")
        new_volume = current_volume - 3
        if new_volume < MIN_VOLUME:
            new_volume = MIN_VOLUME
        command_set[3] = str(new_volume) + "%"
        subprocess.run(command_set)
        print("Volume set to:", new_volume, "%")

    time.sleep(0.1)

Could anyone help me with this issue.

Many thanks

1
  • Hello and welcome. I've answered the question as I've found the fault in your code, but if you want it to work in the current method you've written for; you'll need to explain why you're using mpg123 in this way, rather than a library with true playback control.
    – Ashley
    May 3, 2023 at 13:59

1 Answer 1

0

Welcome to RPI Stack Exchange.

The subprocess.Popen() command you use in the PLAY_BUTTON_PIN and the NEXT/PREV_BUTTON_PIN are different.

I don't know these libraries/executables specifically, but you're providing "-Z" and a reference to the array *music_paths in the PLAY subprocess, but only a single song (music_paths[current_song_index]) in the NEXT/PREV subprocess.

I'd say you'd want to look into a method to instruct mpg123 to change track, rather than killing it and instantiating it with one song.

If for some reason you can't do that, you'll need to reorder the array putting the next or previous song at the top, but without knowing the current state of which song is being played from mpg123, this will be difficult.

2
  • Thank you, for your help. I have managed to solve my issue by emulating the button press in the /boot/config.txt by adding dtoverlays, removing whole parts of next and previous from the code and creating a random list in the m3u file and loading this as a playlist.
    – Sumistu
    May 29, 2023 at 20:20
  • You should post your resultant code and other elements that you used to get it to work as a new answer, so that anyone who finds this question with a similar problem might be able to be helped, too.
    – Ashley
    May 31, 2023 at 9:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.