-2

I am redesigning a program that basically plays sound on command. I am trying to find a way to shuffle a list of songs. I have the basic idea of what should happen but i can't seem so find a way for it to work.

I have tried stuff like 'time.sleep(1)' and '.after(miliseconds, function)'.

songlist = [["SongName","SongFileName",{length of song in miliseconds}], 
           ["SongName2","SongFileName2",{length of song in miliseconds}]]

def shuffle():
    shuffle=True
    while shuffle == True:
        song=random.choice(songlist)
        song2 =random.choice(songlist)
        while song==song2:
            song2=random.choice(songlist)
        label2.config(text=song[0])
        winsound.PlaySound(song[1], winsound.SND_ASYNC)
        window.after(song[2])

What i want to happen is for it to play random songs from the song list until the "stop" button is pressed (Stop button not shown in code)

  • I dont understand your code. Why you keep shuffeling for no reason? And why you need to make delay? And where you need to make delay? – Martin Feb 07 '19 at 21:20
  • When i shuffle it, it plays the song perfectly fine.But it is in a while loop, this means that it will loop back round and play another song which will stop the current one from playing - This is why i think there is a need for the delay. Also, i shuffled twice because i was testing things out - When using the .after function it said that the parameters have to be .after(milliseconds, function), thats why i put another winsound/song into the after to see if it worked. – AlreadyDezire Feb 07 '19 at 21:30
  • Your whole architecture is wrong. its easy to solve your problem with threading, but there will be tons of another problems coming out. I strongly advice you to use for example Pygame Mixer to use for playing songs. Also I advice you before doing anything further, to study little bit on classes. Create class with kind of 'music player' which you will be controling from your GUI. Puting 2 While loops and threadings like this will only cause that you will come to Stackoverflow with new question on the same topic... because your GUI will simply not handle it. – Martin Feb 08 '19 at 11:40

2 Answers2

0

Just to give you some place to start. This would give you a random song from the list.

 songlist = ['a', 'b', 'c']

 def shuffle():
      while True:
          for s in songlist:
              song=random.choice(s)

              print(song)

 if __name__ == '__main__':
      shuffle()
Matthew
  • 411
  • 6
  • 22
  • So this would assign a random item (in this case a,b or c) to "song" 3 times? It would do it because there is 3 items in the songlist and you used a for loop. Also what does " __name__" and "__main__" mean? i have seen them be used but i do not know what they do. – AlreadyDezire Feb 07 '19 at 21:46
  • This will print a random item from a list as many times until you stop the script (note you use while True). Now it has 3 items to choose from so thats the limit. So whenever you want to iterate through a list you should use a for loop. The if name == name part (in short) is for executing your code - in this case shuffle() You should check this out for more detailed explanation - https://stackoverflow.com/questions/419163/what-does-if-name-main-do – Matthew Feb 07 '19 at 21:52
  • Oh! okay so i get that side of it now, and i will probably use this in my code, but how will it work if the "print(song)" is replaced by something that plays audio such as "winsound.PlaySound(song, winsound.SND_ASYNC)"? Do i still need to figure out a way to delay the next song from playing until the current has finished? or does this solve that? – AlreadyDezire Feb 07 '19 at 22:02
  • It should execute the song one after another. So it will wait until the first one is done and then move to the next one – Matthew Feb 07 '19 at 22:04
  • Oh awesome, that is perfect. Though i am using tkinter and want it to play on a click of a button, do i just set the "command" parameter on the button to "shuffle()" or do i need the "__main__" and "__name__"? – AlreadyDezire Feb 07 '19 at 22:12
  • Im not sure if it will work. i am storing the name of the song and the audio file name in the list, but the list is a 2d array. So when i use my 2d array with the code you provided, it selects a random from each item, meaning it won't always play the song. – AlreadyDezire Feb 07 '19 at 22:20
  • songlist = [[('a', 'song_name_a')], [('b', 'song_name_b')]] this should work – Matthew Feb 07 '19 at 22:29
  • Im assuming the stand alone a and b are to be replaced with the file name? – AlreadyDezire Feb 07 '19 at 22:31
  • It didn't work, here is what i am working with: https://pastebin.com/VKsdgc5i If you are wanting to run it, here are the .gif image files and wave audio files:http://www.mediafire.com/folder/04eyk5aamxj3f/Program_Assets – AlreadyDezire Feb 07 '19 at 22:47
0

One thing you could try, is to use threads. so first import thread module:

Python2.7: from thread import start_new_thread

Python3.x: import threading

then you just call your method that you want run "parallel" to your wait function, in your case a "playSong"-method:

Python2.7: start_new_thread(playSong, ())

Python3.x:

t = threading.Thread(target=playSong)
t.start()
Frazer
  • 56
  • 5
  • I do not completely understand the concept of threads. Could you explain? Also what i pick up from this is that i could assign each song to a thread and put the threads in the list? This is what i mean: https://pastebin.com/Vxc1S5e7 – AlreadyDezire Feb 07 '19 at 21:50
  • no dont store them in a list, so you should treat threads like a methodcaller, that lets you run a method "parallel", so that you can wait in the main thread and play the song in the other thread. so you choose a song, create a thread run the playsong method on the new thread, and wait on the main thread some time, and then play the next song by creating a new thread, the old thread will delete it self by end of the playSong-method of the first song – Frazer Feb 07 '19 at 22:00
  • So how would i implement it into something simular to this? https://pastebin.com/fvX90C1w I want to use the PlaySong function that is defined in that link. – AlreadyDezire Feb 07 '19 at 22:09
  • Sorry if i caused confusion, but i will send you the whole program that i am rewriting so you can see how it works. https://pastebin.com/vhaKjjsF Before you run the program, note that it is very messy as it was my first program and the whole "urls" was never finished but was supposed to be song references. – AlreadyDezire Feb 07 '19 at 22:28
  • so I assumed the problem was that the winsound.PlaySound method is blocking, so you cant do gui stuff, right? – Frazer Feb 07 '19 at 22:32
  • No, when using the SND_ASYNC it allows it to play along side other code running, but i want a function(shuffle) to play the 15 songs that are in the program randomly. Thats the problem - If i was to write one winsound.PlaySound and then another right away then the second one would stop the first and play. So this is why i wanted to add a delay, the delay would be the duration of the song stored in 2d array along side the songname and filename. Then i could write one winsound.PlaySound and then the delay and the 2nd winsound.PlaySound so that the 2nd would only play once the delay/ song is over – AlreadyDezire Feb 07 '19 at 22:38
  • so what happens when you wait for that time? – Frazer Feb 07 '19 at 22:43
  • It does not allow you to click any buttons during it. If you want to test it, here are the audio files and the program to test it. https://pastebin.com/VKsdgc5i http://www.mediafire.com/folder/04eyk5aamxj3f/Program_Assets – AlreadyDezire Feb 07 '19 at 22:50
  • Ok, so in that case you may have to use the mainloop and update function to check how much time has passed http://effbot.org/tkinterbook/widget.htm – Frazer Feb 07 '19 at 23:00
  • So where would i use it? before the delay? – AlreadyDezire Feb 07 '19 at 23:04
  • so you call the mainloop in your code some where at the end, then this method will call the update method continously (every frame, automatically) in that method you check the time, if its time to play a new song, you choose one and play it. Check the time with `currentTime = int(round(time.time() * 1000))` | `nextPlayTime = int(round(time.time() * 1000) + song.millis)` | set `nextPlayTime` when you play the song and check then in the update if `currentTime` (needs to be assined ever update) and `nextPlayTime` equal – Frazer Feb 07 '19 at 23:16
  • Could you show me in an example? So i can see how it works. – AlreadyDezire Feb 07 '19 at 23:21