Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Play mp3 file dependant on python output

Sun Aug 13, 2017 11:35 pm

I have a python script which prints an output from A1 to K10 dependant on the gpio input (100 selections as no letter I), how can i make a specific mp3 play for each output it prints e.g. A1.mp3 to k10.mp3?

i.e. if it printed A1 it would play A1.mp3,

would be great if it was possible to queue songs to be played next also.

Please could someone write an example as i have not been able to get an answer from anyone.

I am just learning !

Thanks for your help.

here is what someone suggested but it didn't work;

Code: Select all

track = SELECTION_LETTERS[count_of_letter_pulses-1] + str((count_of_number_pulses-1))
    message = ("+++ TRACK FOUND +++ Track Selection: ", track)
    logger.info (message)
    return   track

def play_song(track) :
   print "Playing Track %s" % track
   global ACTIVE_PROCESS
   if ACTIVE_PROCESS:
     ACTIVE_PROCESS.terminate()
     ACTIVE_PROCESS = subprocess.Popen(["mpg321", "/Desktop/2/%s.mp3" % track]) 
Full code: https://pastebin.com/DxeJ7Zrj

User avatar
Paeryn
Posts: 2952
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Play mp3 file dependant on python output

Sun Aug 13, 2017 11:58 pm

Jarrettenglish1 wrote:
Sun Aug 13, 2017 11:35 pm

Code: Select all

     ACTIVE_PROCESS = subprocess.Popen(["mpg321", "/Desktop/2/%s.mp3" % track]) 
The path to your music files looks like it is probably wrong, I'd expect it to be more like

Code: Select all

     ACTIVE_PROCESS = subprocess.Popen(["mpg321", "/home/pi/Desktop/2/%s.mp3" % track)
unless for some strange reason you really have created a directory called Desktop in the root directory.
She who travels light — forgot something.

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 12:36 am

Thank you for your reply, unfortunately it still does not play any mp3. Maybe the player is missing? Thank you.

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 2:04 am

I have been using the pygame library to play sounds files via bluetooth speaker. see something like this https://raspberrypi.stackexchange.com/q ... ith-python

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 5:33 am

The (faulty) indentation of the subprocess line causes it that the statement isn't executed when ACTIVE_PROCESS is None (which is the case upon initial play). Correct the indentation so the subprocess statement is not part of the if-statement.

Code: Select all

def play_song(track) :
   print "Playing Track %s" % track
   global ACTIVE_PROCESS
   if ACTIVE_PROCESS:
     ACTIVE_PROCESS.terminate()
   ACTIVE_PROCESS = subprocess.Popen(["mpg321", "/home/pi/Desktop/2/%s.mp3" % track]) 

Also there is no global ACTIVE_PROCESS variable; define at the top of the program

Code: Select all

ACTIVE_PROCESS  = None
Once started a (forum) thread you better stick to it to maintain the history of your issue.

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 11:47 am

Hi,
unfortunately still not working , I have put the two codes together. Here is the full code,
someone may know whats wrong with it and why it won't play?. Thanks

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import RPi.GPIO as GPIO
import time
import sys, httplib
import logging
 
ACTIVE_PROCESS = None
logger = logging.getLogger('jukeboxcontroller')
hdlr = logging.FileHandler('/var/log/jukeboxcontroller.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
 
#contants and literals
SELECTION_LETTERS=("A","B","C","D","E","F","G","H","J","K")
WALLBOX=21
 
#>>>these constants can be changed to fit the characteristics of your wallbox
MAXMIMUM_GAP=3
MINIMUM_PULSE_GAP_WIDTH=0.01
LETTER_NUMBER_GAP=0.22
 
#set up IO port for input
GPIO.setmode(GPIO.BCM)
GPIO.setup(WALLBOX, GPIO.IN)
 
 
#this function tests if a pulse or gap is wide enough to be registered
#this is needed for two reasons. 1) Sometimes the wallbox will generate an errant pulse
#which will cause errors if interpretted as a proper contact pulse 2) because of the
#way that I have tapped the wallbox pulses, there will be short gaps inside each pulse
#that need to be ignored
 
def state_has_changed(starting_state):
    starting_time = time.time()
    elapsed_time = 0
 
    for i in range (400):
        if GPIO.input(WALLBOX) != starting_state:
            elapsed_time = time.time() - starting_time
            #print ("check time recorded: %.3f" %elapsed_time)
            return False
    return True
       
#this function is called as soon as the main loop determines that a train of pulses
#has started.  It begins by counting the number pulses, then when it encounters a larger
#gap, it starts incrementing the letters.  If your wallbox uses the opposite order
#you will need to change this.  Also the final calculation of the track may need to be changed
#as some boxes have additional pulses at either the start or the end of the train
#once it encounters a gap over a pre-determined maxmimum we know that the rotator arm
#has stopped and we calculate the track
 
def calculate_track():
 
    state = True
    count_of_number_pulses = 1 #since we are in the first pulse
    count_of_letter_pulses = 0
    length_of_last_gap = 0
    first_train = True
    time_of_last_gap = time.time()
 
    while length_of_last_gap < MAXMIMUM_GAP:
        if GPIO.input(WALLBOX) != state:
           
            if state_has_changed(not state): # state has changed but check it is not anomaly
                state = not state # I use this rather than the GPIO value just in case GPIO has changed - unlikely but possible
                if state: #indicates we're in a new pulse
                    length_of_last_gap = time.time() - time_of_last_gap
                    #print ("Pulse.  Last gap: %.3f" %length_of_last_gap)
 
                    if length_of_last_gap > LETTER_NUMBER_GAP: # indicates we're into the second train of pulses
                        first_train = False
 
                    if first_train:
                        count_of_number_pulses += 1
                    else:
                        count_of_letter_pulses +=1
                else: #indicates we're in a new gap
                    time_of_last_gap = time.time()
        else:
            length_of_last_gap = time.time() - time_of_last_gap #update gap length and continue to poll    
    print count_of_number_pulses
    print count_of_letter_pulses
    if count_of_number_pulses > 11 :
       count_of_number_pulses = count_of_number_pulses - 10
       count_of_letter_pulses = count_of_letter_pulses * 2
    else :
       count_of_letter_pulses = (count_of_letter_pulses * 2) - 1
 
    track = SELECTION_LETTERS[count_of_letter_pulses-1] + str((count_of_number_pulses-1))
    message = ("+++ TRACK FOUND +++ Track Selection: ", track)
    logger.info (message)
    return   track
 
def play_song(track) :
   print "Playing Track %s" % track
   global ACTIVE_PROCESS
   if ACTIVE_PROCESS:
     ACTIVE_PROCESS.terminate()
   ACTIVE_PROCESS = subprocess.Popen(["mpg321", "/Desktop/2/%s.mp3" % track])
 
 
 
#this is the main loop. We poll the GPIO port until there is a pulse.
#sometimes there can be random pulses, or a spike when the rotor arm starts to move
#so before trying to decode the pulse train I check that
#the pulse is long enough to indicate a contact on the selector arm
 
logger.info ("starting controller")
while True:
    if GPIO.input(WALLBOX):
        if state_has_changed(True):
            try:
              track = calculate_track()
              play_song(track)
            except:
              logger.info ("error calculating track")
        #else:
#            print ("--> Pulse ignored")nqueue&selection=%s"%track
Last edited by Jarrettenglish1 on Mon Aug 14, 2017 1:13 pm, edited 1 time in total.

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 12:31 pm

The code is, apart from some added space characters, the same as the pastebin'ed code.
The subprocess line is still part of the if statement! Remove 2 spaces at the beginning of the subprocess line.

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 1:14 pm

jehutting wrote:
Mon Aug 14, 2017 12:31 pm
The code is, apart from some added space characters, the same as the pastebin'ed code.
The subprocess line is still part of the if statement! Remove 2 spaces at the beginning of the subprocess line.
Sorry I have corrected that now, but it still does not work.

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 1:30 pm

OK... but what exactly doesn't work?
When you execute on the command line

Code: Select all

cat /var/log/jukeboxcontroller.log
what do you get? Expect to see some "+++ TRACK FOUND +++... " lines for every button you pressed on your wallbox.

Do you get the print-statement of the play_song function? Expect to see the letter and number of the selected track.

I don't know if mpg321 prints something. If you replace it with 'omxplayer' you should see some output.
Edit: forget my edits on this comment :D as you will get output without using the stdout, stderr arguments of Popen.
Last edited by jehutting on Mon Aug 14, 2017 3:26 pm, edited 3 times in total.

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 1:54 pm

This is what the script prints when it is running and a selection is made on the wallbox;
2017-08-14-133818_1776x952_scrot.png
2017-08-14-133818_1776x952_scrot.png (55.98 KiB) Viewed 3875 times
The original author put the log file in there, which looks like this;
2017-08-14-134109_1776x952_scrot.jpg
2017-08-14-134109_1776x952_scrot.jpg (108.95 KiB) Viewed 3875 times

Thanks Again.

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 3:00 pm

OK...took some time to figure out why the Popen throwed an exception :D The problem is the missing of the following line:

Code: Select all

import subprocess
Put it at the top of the file (below "import logging").

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 3:19 pm

Thank you so much!! , It works :)

is there anyway to cue songs to play next?

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 3:45 pm

Yes.. use python's basic type list. Use the list function append to add the selected track to this list.
A thread could then -in a while loop- use the list function pop(0) to get the first track from the list and play it (with the Popen function).
After the Popen function, you can with the subprocess.Popen.wait function wait for the process termination (= track played completely).
If all tracks are played (len(list) equals zero) just do a sleep(x) seconds and continue with the while loop.

Something like that :D

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 4:05 pm

Thank you.. as a beginner that all sounds very complicated :( but i cant thank you enough for solving this!

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 4:18 pm

jehutting wrote:
Mon Aug 14, 2017 3:45 pm
Yes.. use python's basic type list. Use the list function append to add the selected track to this list.
A thread could then -in a while loop- use the list function pop(0) to get the first track from the list and play it (with the Popen function).
After the Popen function, you can with the subprocess.Popen.wait function wait for the process termination (= track played completely).
If all tracks are played (len(list) equals zero) just do a sleep(x) seconds and continue with the while loop.

Something like that :D
if you could write it and tell me where to add it that would excellent :)

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 7:32 pm

Something like attached?
It is a quick and dirty proof of concept.
Attachments
2pi-queue.py.zip
(2.16 KiB) Downloaded 43 times

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 8:04 pm

Thanks for your reply, Unfortunately it does not queue the songs but plays straight away when another selection is made, like the original script. (i have changed the mp3 directory)

Here is a screenshot of the script running.
2017-08-14-200516_1776x952_scrot.png
2017-08-14-200516_1776x952_scrot.png (127.77 KiB) Viewed 3750 times

Ronicus
Posts: 54
Joined: Sat May 06, 2017 7:34 am

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 8:44 pm

Try /home/pi/Desktop/TheRestOfDirHere currently your code is looking for "Desktop" in the root directory /Desktop/BLAH!! <=== Is one Dir up from root

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 8:55 pm

Ronicus wrote:
Mon Aug 14, 2017 8:44 pm
Try /home/pi/Desktop/TheRestOfDirHere currently your code is looking for "Desktop" in the root directory /Desktop/BLAH!! <=== Is one Dir up from root
Thanks for your Reply , i have already corrected the directory path,

Jarrett

Ronicus
Posts: 54
Joined: Sat May 06, 2017 7:34 am

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 9:02 pm

Jarrettenglish1 wrote:
Mon Aug 14, 2017 8:55 pm
Ronicus wrote:
Mon Aug 14, 2017 8:44 pm
Try /home/pi/Desktop/TheRestOfDirHere currently your code is looking for "Desktop" in the root directory /Desktop/BLAH!! <=== Is one Dir up from root
Thanks for your Reply , i have already corrected the directory path,

Jarrett
Are you sure read your last screenshot

Image

Jarrettenglish1
Posts: 19
Joined: Wed Aug 09, 2017 2:41 pm

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 9:13 pm

I do apologise i didn't see the second directory. Now it is playing multiple songs at the same time when another selection is made.

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 9:33 pm

Oeps...yes, you changed the music folder to /home/pi/Desktop. Sorry, missed that when I was modifying your last posted code.

Strange that it isn't waiting for the completion (process.wait() should do the trick.)
Do you see multiple instances of mpg321 when executing 'top' or 'htop'?

I'm already in the process of changing the code as I don't like the quick and dirty one :D

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 9:52 pm

Ok I have looked at the thread a bit closer and now understand what your trying to do create a que.

This is the way that I would have done it.

que = [ ] #create a list variable to store the que
if button_pushed : que.append(button_pushed0 #everytime a button is pushed then append the list to add the pushed button to the que

I assume that you have a main loop that is reading the buttons being pushed in this loop I would also be testing if the last song was finished. If the song was finished playing then start the next song stored in que[0] and also que.remove(current_song) #start next song and remove the last song from the que list.

If you don't have a main loop and using event driven programming then you need to put the code that tests if song ended then changes song in a routine that runs as a thread and make the que variable global

User avatar
OutoftheBOTS
Posts: 711
Joined: Tue Aug 01, 2017 10:06 am

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 10:01 pm

import thread
import pygame

pygame.mixer.init()
global que
que=[ ]

def play_qued_songs() :
global que
while True:
if not pygame.mixer.music.get_busy() and len(que) > 0 : #if the song has finished and there is more songs in the que
pygame.mixer.music.load(que[0])
pygame.mixer.music.play()
que.remove(que[0])

thread.start_new_thread( play_qued_songs )

#you need to add code that updates the global que variable anytime a button is pressed
Last edited by OutoftheBOTS on Mon Aug 14, 2017 10:06 pm, edited 2 times in total.

jehutting
Posts: 143
Joined: Sun Feb 15, 2015 8:37 am
Location: The Netherlands

Re: Play mp3 file dependant on python output

Mon Aug 14, 2017 10:06 pm

Yes that's what I did.

Code: Select all


track_list = []    # the global tracklist

def player():
    while True:
        # if the track_list has a track to play...
        if len(track_list):
            # ...get it and remove it from the tracklist
            print("BEFORE track_list={0}".format(track_list))
            track = track_list.pop(0)
            print('track popped = %s' % track)
            print("AFTER track_list={0}".format(track_list))
            # play the track
            #process = subprocess.Popen(["mpg321", "/Desktop/2/%s.mp3" % track]);
            process = subprocess.Popen(["omxplayer", "./music/%s.mp3" % track]);
            # wait till the track is fully played
            process.wait()
        else:
            # track list is empty
            # we don't want the CPU to be running continuously at full load
            time.sleep(1)   
and the main

Code: Select all

thread = threading.Thread(target=player)
thread.start()   

while True:
    if GPIO.input(WALLBOX):
        if state_has_changed(True):
            try:
              track = calculate_track()
              #play_song(track)
              track_list.append(track)
              print("track_list={0}".format(track_list))
            except:
              logger.info ("error calculating track")
        else:
            # same here, we don't want the CPU to be running continuously at full load
            time.sleep(1)
Apparently the process.wait() is not doing what I think it should do.
Last edited by jehutting on Mon Aug 14, 2017 10:08 pm, edited 1 time in total.

Return to “General discussion”