I have a Raspberry Pi 3b that I'm using to play music. When a button (GPIO) is pressed, I want to play a list of songs. I'm doing this using the vlc media list player. I build a media list by grabbing N random mp3 files from a directory.
eg:
i=vlc.Instance()
l=i.media_list_new()
l.insert_media(i.media_new(...)) # this loops and grabs random mp3s
p=i.media_list_player_new()
p.set_media_list(l)
p.play()
Another GPIO signal will call p.stop(). What I want to know at that point is which songs in the media list have been played. This way I can track them and not play them again the next time the Play button is pressed, but the unplayed tracks in the list should still be eligible to play.
So far I don't see any way to get any info from the media list player on what item in the list it's on or another way to tell what has been played from the list.
I tried an alternative of manually looping through a list of songs and using a regular player (not list player), but when I do this I have to do a while True loop to make the player wait for one song to finish before playing the next one. This loop also seems to block my GPIO event handler for some reason and pressing the STOP button goes undetected (have to cancel the script to stop).
My advice would be: Don't use the MediaListPlayer.
Use a MediaList along with a MediaPlayer and listen for libvlc_MediaListEndReached https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc.html
loop to make the player wait for one song to finish before playing the next one
Use libvlc events.
Actually got this working using the MediaListPlayer and events. I added an event handler for MediaListPlayerNextItemSet that calls a function that increments a counter, so I know how many songs in the list were played now.
Related
How can I manipulate the volume of the audio loaded via pyglet.media.load?
The reason is that I have to repeat a sound repeatedly (eg bullets), but if I use the Player, the sound is queued to be able to play it and plays it only once using .play() (eg bullet = pyglet.media.load("bullet.wav", streaming=False) audioPlayer = pyglet.media.Player() audioPlayer.queue(bullet) if the audioPlayer.play() command is used several times, for example from a key, it is executed only once and that's it)
If I don't use the Player, I can use the sound constantly, but at that point I can no longer manipulate the volume of the audio. (eg bullet = pyglet.media.load("bullet.wav", streaming=False) bullet.play())
So how can I go about solving the problem? I don't have much experience using Pyglet audio, so I'm probably ignoring something I'm not aware of.
The audio player is the correct approach as you can set volume on the player.
audioPlayer.volume = 0.5
Under the hood all the media.play() command does is create a Player instance, queue and play it. If you want to replay something, simply queue the source and play the player again. If you need audio overlaps, then you would create separate Player instances every time, like media.play() would.
I'm learning OpenCV and I decided to make a snake game using it. It's almost done but there is a slight problem that seems simple but I couldn't find a solution.
while True:
move()
cv2.imshow('Snake Game', frame)
cv2.waitKey(250)
It's supposed to wait 250 miliseconds before the next frame but key presses break the waiting so game speeds up when I hold down a key. How can I make it ignore the keyboard events and only use time?
I would be very surprised if waitKey didn't stop the waiting after key presses. In fact the name itself suggest that. So basically it's like calling a function called max and then expect the minimum.
From your code and what you've described, you're using waitKey for two reasons:
waiting for some fixed time. That means you're using it to synchronize your game loop.
using it (maybe) to handle key presses for user interaction with the game.
In my opinion, first thing to do is to stop waiting and just keep showing frames continuously as soon as it is ready. And for synchronization you just need to save time for each frame printing. And using that time you update after user interaction or deciding how to process frame or ... One place to help you in that is to look at how game loops are implemented.Take a look here : https://gamedev.stackexchange.com/questions/651/how-should-i-write-a-main-game-loop
Ok so basically I'm working on this pygame game and I'm using the mixer sub module for sounds. However, in pygame if you want to stop a sound, the sound must finish its cycle until it can be stopped. For all my sounds this is ok as they can be a looped 1 second sound. However, I use a falling sound which needs to constantly play in a cycle, but cycling a falling sound that is only 1 second long doesn't sound very effective. So, ultimately I want to know if there is a way to stop a 7 second sound loop instantly without it finishing a cycle.
According to the pygame documentation for pygame.mixer
pygame.mixer.pause()
will temporarily stop playback of all sound channels. You can start them all playing again with;
pygame.mixer.unpause()
For an individual sound, whilst it will stop after a full cycle, you can immediately affect it's volume with;
pygame.mixer.Sound.set_volume(0)
So what I'd try first is stopping the sound at the same time as setting it's volume to zero and seeing if that solves your problem. Alternatively, you can split your mixer into Channels for better controlling sound playback, which will give you the ability to use
pygame.mixer.Channel.pause()
pygame.mixer.Channel.unpause()
On specific groups of sounds rather than all sound. You create a mixer channel with;
pygame.mixer.Channel(id)
You can then play specific sounds on that channel with;
pygame.mixer.Channel.play(Sound, loops=0, maxtime=0, fade_ms=0)
This would also allow you to more dynamically adjust the levels of various types of sounds in your game - for example, environment, music, weather, voices and how they overlap each other, just keep in mind a channel can only play one sound at a time. Because of this, it may by prudent to use;
free_channel = pygame.mixer.find_channel()
free_channel.play(Sound)
or more simply;
pygame.mixer.find_channel().play(Sound)
For everything except your 'falling' channel.
After my song (music.mp3) ends, it doesn't replay. I have the following code:
# import pygame and other code
pygame.mixer.music.load('music.mp3')
pygame.mixer.music.play()
pygame.mixer.music.rewind()
pygame.init()
Shouldn't it be replaying itself? And if not, how do I make it replay whenever it ends?
Your code does not do what you think it does. It starts playing the MP3 but the play() call doesn't wait until the file is played, it immediately returns, playing the music asynchronously. So starting a song and immediately rewinding in the next line of code does not make any sense. If you want the music to play more than once, have a look at the loop argument of pygame.mixer.music.play(). It allows to play the music a given number of times or indefinitely.
The play function takes an integer number of times to play the sound. -1 sets it to infinite.
pygame.mixer.music.play(-1)
EDIT:
It's proper practice to initiate pygame before setting up the mixer, as pygame.init() also calls pygame.mixer.init().
I am playing a song as specified in the docs and it all works brilliantly. But how do I stop a song and clear the queue?
Thanks
Oscar
The specs at http://www.pyglet.org/doc/programming_guide/controlling_playback.html say that there is no stop method and that to stop a song and clear the queue you have to, quoting "simply pause playback and discard the player and source objects". If you need to keep playing songs after this you would create a new player object.