How to play audio(in generator loop) with Pyglet? - python

Version of pyglet - 1.4.2. Python - 3.6.6Ubuntu - 18.04
Code example:
import pyglet
import time
pyglet.options['audio'] = ('openal', 'pulse', 'directsound', 'silent')
source = pyglet.media.StaticSource(pyglet.media.load('explosion.wav'))
def my_playlist():
while True:
print(time.time())
print(1)
yield source
player = pyglet.media.Player()
player.queue(my_playlist())
player.play()
pyglet.app.run()
Code was writed based on documentation:
Logs in console:
1566296930.8165386 # played once
1
1566296931.529639 # won't play
1
1566296931.5301056 # won't play and etc.
1
1566296931.5304687
1
1566296931.5309348
1
Expected result:
Audio should play in loop with sounds which is returned from generator.
Current result:
Audio is played once.
Question:
What I did wrong here and how to achive expected result?

Not sure if you're trying to accomplish something more, but if all you need from your loop is to loop sound, you shouldn't actually use a loop of any kind. Instead, use the designated EOS_LOOP flag/trigger.
import pyglet
import time
pyglet.options['audio'] = ('openal', 'pulse', 'directsound', 'silent')
source = pyglet.media.StaticSource(pyglet.media.load('explosion.wav'))
player = pyglet.media.Player()
player.queue(source)
player.EOS_LOOP = 'loop'
player.play()
pyglet.app.run()
And since it's deprecated, you should move away to using the SourceGroup with the loop flag set.

Related

Python, how to execute a line of code without it stopping the rest of the code from executing?

first of all, im a beginner.
Want i want to accomplish is that music plays while the script is executing.
What it does right now it plays the music, waits until the music is over and then executes the rest of the code. That is not what i want. Here my Code:
import os
import subprocess
import multiprocessing
import threading
from playsound import playsound
CurrentPath = os.path.dirname(os.path.normpath(__file__))
os.chdir(CurrentPath)
def music():
Music = "Music.mp4"
#subprocess.run(["ffplay", "-nodisp", "-autoexit", "-hide_banner", Music])
playsound("Music.mp4")
def other_things():
print("Hello World")
#musicp = multiprocessing.Process(target=music())
#restp = multiprocessing.Process(target=other_things())
musicp = threading.Thread(target=music())
restp = threading.Thread(target=other_things())
restp.start()
musicp.start()
LIke you can see i even tried multithreading but it still waits until the music is over before it goes to the rest of the code.
Don't call the functions in the target parameter of the Thread function - delete the brackets to reference the function, not its return value
musicp = threading.Thread(target=music) # instead of music()
restp = threading.Thread(target=other_things) # instead of other_things()

How do I make a menu screen using Ursina Python?

Usually I would make a function or an if statement, like this:
def home_screen():
# code
if condition:
game()
def game():
# code
home_screen()
or something like:
game = 1
if game == 1:
# code for home screen
if condition:
game = 2
if game == 2:
# code for game
if game == 3:
# so on
The latter needs a global variable with a class, which is fine for me. However in Ursina, none of these work, either the update function stops on the former, or the color.red, color.blue, etc. stops working out of nowhere, or the second if statement just doesn't run. Does anyone have an alternative? I'm thinking of just making a home_screen.py file entirely but that won't do much good, and I'm not sure how that can be implemented anyway.
Edit: while loops also don't seem to work
Making a functional game menu is actually not that simple.
You could make a function that loads all the game models from a level, a function that shows a menu, and a final one that shows a loading screen.
Load a level :
def loadLevel():
global loading_screen
ground = Entity(model='quad', scale=10, y=-2, collider='box') # dummy entities
player = FirstPersonController()
player_model = Entity(model='player', parent=player)
building = Entity(model='building', collider='box')
destroy(loading_screen) # delete the loading screen when finished
Show the menu :
def showMenu():
play = Button('Play', on_click=showLoadingScreen) # A play button that show the loading menu when clicked
Show the loading screen :
from direct.stdpy import thread # we need threading to load entities in the background (this is specific to ursina, standard threading wouldn't work)
def showLoadingScreen():
global screen
screen = Entity(model='quad', texture='loading_image')
thread.start_new_thread(function=loadLevel, args='') # load entities in the background
Rest of the file :
from ursina import *
if __name__ == '__main__':
app = Ursina()
screen = None # for global statement
showMenu()
app.run()
Edit : a basic example is available here.

How to change the volume of playback in MediaListPlayer with LibVLC?

I'm using a MediaListPlayer instance to execute a playlist. On a standard MediaPlayer instance you can use MediaPlayer.audio_set_volume(newVolume), but when I try to use the same method(audio_set_volume(newVolume)) on a MediaListPLayer instance, I get an error.:
AtributeError: 'MediaListPLayer' object has no attribute 'audio_set_volume'. What is the replacement of that method for the MediaListPlayer?
This is the code:
from vlc import Instance
playlist = ['/home/user/Music/01 Signs.mp3','/home/user/Music/2U.mp3']
player = Instance()
mediaListPlayer = player.media_list_player_new()
mediaList = player.media_list_new()
for element in playlist:
mediaList.add_media(player.media_new(element))
mediaListPlayer.set_media_list(mediaList)
mediaListPlayer.play()
mediaListPlayer.audio_set_volume(80)
Two years later was wondering the same thing. So here is a solution that worked for me:
import vlc
inst = vlc.Instance()
player = inst.media_list_player_new()
media_list = inst.media_list_new(["example.mp3"])
player.set_media_list(media_list)
player.play()
player.get_media_player().audio_set_volume(50)
MediaListPlayer.get_media_player() returns the MediaPlayer that can be used to control the volume of the MediaListPlayer during playback.
As I said in my comment, it does look like an oversight.
However, I have managed to set the initial volume by hacking a sub_player but once it is set and you invoke the list player, I haven't found a way of adjusting it after that.
import vlc
import time
playlist=['/home/rolf/vp1.mp3','/home/rolf/vp.mp3']
inst = vlc.Instance()
sub_player = inst.media_player_new()
player = inst.media_list_player_new()
mediaList = inst.media_list_new(playlist)
player.set_media_list(mediaList)
volume = 60
sub_player.audio_set_volume(volume)
sub_player.play()
playing = set([1,2,3,4])
player.play()
while player.get_state() in playing:
time.sleep(1)
I have posted a question on videolan ,https://forum.videolan.org/viewtopic.php?f=32&t=139505 so someone with a greater knowledge of these things might provide a better solution. If I get an answer, I'll post it here.

libvlc - How to change volume during playback

I am trying to set volume while playing an audio file but it doesn't seem to work at all. Please what am I doing wrong?
# create a vlc playable object from source
self.playable = vlc.libvlc_media_new_path(self.instance, sourceURL)
# create a new vlc player
self.player = vlc.libvlc_media_player_new_from_media(self.playable)
# play
vlc.libvlc_media_player_play(self.player)
while not self.stop:
sleep(10) # sleep for a while to allow playback
self.player.audio_set_volume(50) # suppose to reduce volume. Doesn't work
sleep(10) # sleep for a while to allow playback
self.stop = True
UPDATE try the following:
self.instance = vlc.Instance()
self.mediaplayer = self.instance.media_player_new()
self.media = self.instance.media_new(unicode(sourceURL))
self.mediaplayer.set_media(self.media)
self.media.parse()
while True :
sleep(10)
self.mediaplayer.audio_set_volume(50)
Example usage
Keep in mind that volume_level is an integer between 0 and 100, 100 will be equal to 0db.
Made a big edit because I think I originally misunderstood a bit. Does the video output work for you?

Play Different Video Files Depending On Value of a Variable At Runtime

I have 4 video files (different scenes of a movie).
There's a starting scene that will be played when I run the player.
And before that scene ends, let's say the video player reads an int value (0-100) from external file (all happens at runtime), and depending on that int value, it has to determine which scene to play next.
pseudo example:
if (x > 0 && x < 30)
videoSource = scene2
else if (x >= 30 && x < 60)
videoSource = scene3
else if (x >= 60 && x <= 100)
videoSource = scene 4
How can I make it change video sources at runtime, depending on that variable?
I don't care about the format of the video file, (Avi, mp4...) whatever works will be fine.
I don't know how to approach this problem. I've searched for something that has the potential to accomplish this, like pyglet or GStreamer, but I didn't find a clear solution.
EDIT: I have the basic player and video player with pyglet, and I was able to play the video without depending on a variable using this code:
import pyglet
vidPath="sample.mpg"
window = pyglet.window.Window()
player = pyglet.media.Player()
source = pyglet.media.StreamingSource()
MediaLoad = pyglet.media.load(vidPath)
player.queue(MediaLoad)
player.play()
#window.event
def on_draw():
window.clear()
if player.source and player.source.video_format:
player.get_texture().blit(0,0)
pyglet.app.run()
How would I go about this? Guidance in the right direction and/or some sample code would be highly appreciated.
Thanks in advance.
Answer revised based on comments
If your goal is to constantly read a file that is receiving writes from the output of another process, you have a couple aspects that need to be solved...
You either need to read a file periodically that is constantly being overwritten, or you need to tail the output of a file that is being appended to with new values.
Your script currently blocks when you start the pyglet event loop, so this file check will have to be in a different thread, and then you would have to communicate the update event.
I can't fully comment on step 2 because I have never used pyglet and I am not familiar with how it uses events or signals. But I can at least suggest half of it with a thread.
Here is a super basic example of using a thread to read a file and report when a line is found:
import time
from threading import Thread
class Monitor(object):
def __init__(self):
self._stop = False
def run(self, inputFile, secs=3):
self._stop = False
with open(inputFile) as monitor:
while True:
line = monitor.readline().strip()
if line.isdigit():
# this is where you would notify somehow
print int(line)
time.sleep(secs)
if self._stop:
return
def stop(self):
self._stop = True
if __name__ == "__main__":
inputFile = "write.txt"
monitor = Monitor()
monitorThread = Thread(target=monitor.run, args=(inputFile, 1))
monitorThread.start()
try:
while True:
time.sleep(.25)
except:
monitor.stop()
The sleep loop at the end of the code is just a way to emulate your event loop and block.
Here is a test to show how it would work. First I open a python shell and open a new file:
>>> f = open("write.txt", 'w+', 10)
Then you can start this script. And back in the shell you can start writing lines:
>>> f.write('50\n'); f.flush()
In your script terminal you will see it read and print the lines.
The other way would be if your process that is writing to this file is constantly overwriting it, you would instead just reread the file by setting monitor.seek(0) and calling readline().
Again this is a really simple example to get you started. There are more advanced ways of solving this I am sure. The next step would be to figure out how you can signal the pyglet event loop to call a method that will change your video source.
Update
You should review this section of the pyglet docs on how to create your own event dispatcher: http://pyglet.org/doc/programming_guide/creating_your_own_event_dispatcher.html
Again, without much knowledge of pyglet, here is what it might look like:
class VideoNotifier(pyglet.event.EventDispatcher):
def updateIndex(self, value):
self.dispatch_events('on_update_index', value)
VideoNotifier.register_event('on_update_index')
videoNotifier = VideoNotifier()
#videoNotifier.event
def on_update_index(newIndex):
# thread has notified of an update
# Change the video here
pass
And for your thread class, you would pass in the dispatcher instance, and use the updateIndex() event to notify:
class Monitor(object):
def __init__(self, dispatcher):
self._stop = False
self._dispatcher = dispatcher
def run(self, inputFile, secs=3):
...
...
# should notify video of new value
line = int(line_from_file)
self._dispatcher.updateIndex(line)
...
...
Hope that gets you started!

Categories

Resources