How can I use the pyglet API for sound to play subsets of a sound file e.g. from 1 second in to 3.5seconds of a 6 second sound clip?
I can load a sound file and play it, and can seek to the start of the interval desired, but am wondering how to stop playback at the point indicated?
It doesn't appear that pyglet has support for setting a stop time. Your options are:
Poll the current time and stop playback when you've reached your desired endpoint. This may not be precise enough for you.
Or, use a sound file library to extract the portion you want into a temporary sound file, then use pyglet to play that sound file in its entirety. Python has built-in support for .wav files (the "wave" module), or you could shell out to a command-line tool like "sox".
This approach seems to work: rather than poll the current time manually to stop playback, use the pyglet clock scheduler to run a stop callback once after a given interval. This is precise enough for my use case ;-)
player = None
def stop_callback(dt):
if player != None:
player.stop()
def play_sound_interval(mp3File, start=None, end=None):
sound = pyglet.resource.media(mp3File)
global player
player = pyglet.media.ManagedSoundPlayer()
player.queue(sound)
if start != None:
player.seek(start)
if end != None and start != None:
pyglet.clock.schedule_once(stop_callback, end-start)
elif end != None and start == None:
pyglet.clock.schedule_once(stop_callback, end)
player.play()
Related
I'm looking for a simple solution for audio recording with pause, resume and no duration time.
pyaudio, sounddevice, I can do something with them, but this is a rather low level.
The difficulty is that they require duration time for recording, that is, the recording time that must be set initially. In my case, the recording should continue until the appropriate code is called to stop.
I found code to record without duration time in sounddevice, but it's still complicated and not a library to use in other parts of the code:
https://github.com/spatialaudio/python-sounddevice/blob/master/examples/rec_unlimited.py
The easiest way to record that I was able to find is using the recorder library:
https://pypi.org/project/recorder/
Here is the code for a simple voice recorder that I managed to find:
import tkinter as tk
from tkinter import *
import recorder
window = Tk()#creating window
window.geometry('700x300')#geomtry of window
window.title('TechVidvan')#title to window
Label(window,text="Click on Start To Start Recording",font=('bold',20)).pack()#label
rec = recorder.Recorder(channels=2)
running = None
def start():
global running
if running is not None:
print('already running')
else:
running = rec.open('untitled.flac', 'wb')
running.start_recording()
Label(window,text='Recording has started').pack()
def stop():
global running
if running is not None:
running.stop_recording()
running.close()
running = None
Label(window,text='Recording has stoped').pack()
else:
print('not running')
Button(window,text='Start',bg='green',command=start,font=('bold',20)).pack()#create a button
Button(window,text='Stop',bg='green',command=stop,font=('bold',20)).pack()#create a button
window.mainloop()
But the question of pause and resume is still open.
Maybe you can advise something?
Thanks in advance!
I'd recommend using either the SimpleSound package or pyaudio
import simplesound as sa
import pyaudio as pa
for recording sound pyaudio might be a better choice, but have a play around and see what works for you <3
I have already programed an experiment using the python-vlc module, which plays my videos smoothly and in fullscreen as expected. Now I'd like to log to a file the time at each frame displayed on screen. Actually the log file comes from another machine and the logging part is solved with a simple function. What I need is access to the timing of frames actually displayed on screen. Is there a function in the module that could help on this?
The short answer is No, frames are not accessible in Vlc.
In fact you'll be lucky to get more granularity than 1/4 of a second on the time itself.
However, you can calculate a frame number based on the current playing time and the number of frames per second. Your best bet to calculate this, is function like the following:
def mspf(self):
# Milliseconds per frame.
return int(1000 // (self.player.get_fps() or 25))
Then based on the current playing time in seconds you can calculate an approximate frame number.
You can get the current frame time by get_time().
Check out the API documentation (https://www.olivieraubert.net/vlc/python-ctypes/doc/)
From above,
libvlc_media_player_get_time(p_mi)
Get the current movie time (in ms).
Parameters:
p_mi - the Media Player.
Returns:
the movie time (in ms), or -1 if there is no media.
Here's a simple example.
import vlc
import time
# Get VLC instance and load a video
vlc_instance = vlc.Instance()
player = vlc_instance.media_player_new()
media = vlc.Media("YOUR VIDEO PATH")
player.set_media(media)
player.play()
time.sleep(0.1)
# Check out the current play time periodically
while player.get_state() == vlc.State.Playing:
t = player.get_time()
print(t) # Treat t as you need
time.sleep(1/120) # adjust a check out period
I usually run the above while loop part in a sub-thread and compare the previous and the current time to avoid duplicate.
I was hoping someone might have some insight on how to stop a script from continuing to repeat if a button is held (or in my case pressed longer than a second)?
Basically i've a button setup on the breadboard, and I have it coded to play an audio file when the button is pressed. This works, however if the button isn't very quickly tapped, then the audio will repeat itself until button is fully released. Also if the button is pressed and held, the audio file will just repeat indefinitely.
I've recorded a quick recording to demonstrate the issue if its helpful, here: https://streamable.com/esvoy6
I should also note that I am very new to python (coding in general actually), so its most likely something simple that I just haven't been able to find yet. I am using gpiozero for my library.
Any help or insight is greatly appreciated!
Here is what my code looks like right now:
from gpiozero import LED, Button
import vlc
import time
import sys
def sleep_minute(minutes):
sleep(minutes * 60)
# GPIO Pins of Green LED
greenLight = LED(17)
greenButton = Button(27)
# Green Button Pressed Definition
def green_btn_pressed():
print("Green Button Pressed")
greenButton.when_pressed = greenLight.on
greenButton.when_released = greenLight.on
# Executed Script
while True:
if greenButton.is_pressed:
green_btn_pressed()
time.sleep(.1)
print("Game Audio Start")
p = vlc.MediaPlayer("/home/pi/Desktop/10 Second Countdown.mp3")
p.play()
So from a brief look at it, it seems that 'time.sleep(.1)' is not doing what you are expecting. Ie. it is obviously interrupted by button presses. This is not abnormal behaviour as button presses on Ardiuno and raspPi (guessing here) would be processed as interrupts.
The script itself does not contain any prevention from double pressing or press and hold etc.
Have you put in any debug lines to see what is executing when you press the button?
I would start there and make adjustments based on what you are seeing.
I am not familiar with this gpiozero, so I can't give any insight about what it may be doing, but looking at the code and given the issue you are having, I would start with some debug lines in both functions to confirm what is happening.
Thinking about it for a minute though, could you not just change the check to 'if greenButton.is_released:'? As then you know the button has already been pressed, and the amount of time it is held in for becomes irrelevant. May also want to put in a check for if the file is already playing to stop it and start it again, or ignore and continue playing (if that is the desired behaviour).
Further suggestions:
For this section of code:
# Executed Script
while True:
if greenButton.is_pressed:
green_btn_pressed()
time.sleep(.1)
print("Game Audio Start")
p = vlc.MediaPlayer("/home/pi/Desktop/10 Second Countdown.mp3")
p.play()
You want to change this to something along these lines:
alreadyPlaying = 0
# Executed Script
while True:
if greenButton.is_pressed:
green_btn_pressed()
#Check if already playing file.
if alreadyPlaying == 1:
# Do check to see if file is still playing (google this, not sure off the top of head how to do this easiest).
# If file still playing do nothing,
#else set 'alreadyPlaying' back to '0'
break
#Check if already playing file.
if alreadyPlaying == 0:
time.sleep(.1)
print("Game Audio Start")
p = vlc.MediaPlayer("/home/pi/Desktop/10 Second Countdown.mp3")
p.play()
alreadyPlaying = 1
Hopefully you get the idea of what I am saying. Best of luck!
i think you have to write something like this in your loop:
import time, vlc
def Sound(sound):
vlc_instance = vlc.Instance()
player = vlc_instance.media_player_new()
media = vlc_instance.media_new(sound)
player.set_media(media)
player.play()
time.sleep(1.5)
duration = player.get_length() / 1000
time.sleep(duration)
To be specific, I need to play sound in a while loop which is fast to execute. And the audio needs to be played separately. I've tried various functions/libraries: playsound, winsound, vlc. But none of them meet my demand.
Either the sounds are overlapped, or I need to wait for the sound to finish to continue the next line of code, which blocks the whole process, making the program running with unbearable lags.
Matters in playsound, winsound, vlc:
playsound: has block option but will block the process (with block=True) or overlap the sound (block=False).
winsound: with SND_ASYNC option, say I have audio A and audio B (which needs to be played after audio A), if audio B is played, audio A will stop immediately.
vlc: [000001ba245794d0] mmdevice audio output error: cannot initialize COM (error 0x80010106), which is kind of weird and nothing useful was found on Google. And this method seems not a good option to me and others. I use this simply for its is_playing() function and I can place the next sound to a queue.
So any advice?
If you're just after playing a sound and having it interrupt whatever was playing before, winsound does just that:
import winsound
from time import sleep
winsound.PlaySound("sound.wav", winsound.SND_ASYNC | winsound.SND_FILENAME)
sleep(1)
winsound.PlaySound("sound.wav", winsound.SND_ASYNC | winsound.SND_FILENAME)
sleep(3)
In this example (assuming sound.wav is longer than a second), the sound will start playing, be interrupted after 1 second and start playing again. The second sleep is there to avoid the script ending before the sound stops (stopping the script stops the sound).
If you want to queue up sounds to play one after the other, while your code keeps running:
import threading
import queue
import winsound
from time import sleep
q = queue.Queue()
def thread_function():
while True:
sound = q.get()
if sound is None:
break
winsound.PlaySound(sound, winsound.SND_FILENAME)
if __name__ == "__main__":
t = threading.Thread(target=thread_function)
t.start()
q.put("sound.wav")
print('One...')
sleep(1)
q.put("sound.wav")
print('Two...')
sleep(1)
q.put("sound.wav")
print('Three...')
q.put(None)
t.join()
This simple example queues up a sound which the thread starts playing, then while it is playing, it queues up the next one and a bit later a third. You'll noticed that the sounds play one after the other and the program only stops when the sounds complete playing (and the thread stops due to the None at the end of the queue).
If you're looking to play one sound over the other and have them mix, using winsound won't work, but you can use libraries like pyglet.
For example:
import pyglet
window = pyglet.window.Window()
effect = pyglet.resource.media('sound.wav', streaming=False)
#window.event
def on_key_press(symbol, modifiers):
effect.play()
#window.event
def on_draw():
window.clear()
if __name__ == "__main__":
pyglet.app.run()
This example opens a window and every time you press a key, it'll play the sound immediately, without interrupting previous sounds. The program ends immediately when you close the window.
This can be easily done with playsound.
playsound.playsound('alert.mp3', False)
Setting the second argument to False makes the function run asynchronously.
The problem is when i play a sound it stops/cuts before finishing playing. (sound being under 1 second)
import pyglet
#from time import sleep
window = pyglet.window.Window()
# i use this for my code.
#pyglet.resource.path = ['/resources']
#pyglet.resource.reindex()
#bullet_sound = pyglet.resource.media("bullet.wav", streaming=False)
## streaming fix's an error message
bullet_sound = pyglet.media.load("/resources/bullet.wav", streaming=False)
#window.event
def on_key_press(symbol, modifiers):
# sound only plays for a millisecond
bullet_sound.play()
# this lets the sound complete
#sleep(1)
# also tried this with 'update()'
#player.queue(bullet_sound)
#def update(dt):
# player.play()
#pyglet.clock.schedule_interval(update, 1/120.0)
pyglet.app.run()
I can't seem to find anything about this when google searching. Sleeping makes the sound finish, so i suppose it has something to do with it dropping the sound prematurely. But how to i get it not to do so?
I even tried using the player, putting it in an update function and queuing it from the event, but that din't change anything.
Segmentation faults, sound cutting, too large exceptions, sound related issues on linux mint might be caused by Linux/PulseAudio, the fix is using OpanAL, installing(might be pre-installed on mint) then adding a line to use it after importing pyglet:
pyglet.options['audio'] = ('openal', 'silent')