This question already has answers here:
How can I play an mp3 with pygame?
(7 answers)
how to play wav file in python?
(5 answers)
Closed 1 year ago.
I made a midiPlayer class for an experiment I'm running. It looks like this:
class midiPlayer(object):
status = NOT_STARTED
setVolume = 1
def __init__(self, Sound):
self.Sound = Sound
def play(self):
freq = 44100
bitsize = -16
channels = 2
buffer = 1024
pygame.mixer.init(freq, bitsize, channels, buffer)
pygame.mixer.music.set_volume(self.setVolume)
pygame.mixer.music.load(self.Sound)
pygame.mixer.music.play()
self.status = STARTED
def stop(self):
pygame.mixer.music.stop()
self.status = FINISHED
def setSound(self, music_file):
self.Sound = music_file
def busy(self):
return pygame.mixer.music.get_busy()
On most people's computers, this is running absolutely fine, but on one participant's computer (using Windows 10), there is about 0.6s latency. I don't have the problem on my own machine (MacOS Sierra).
Is there anything he can do to lose the latency? He's tried reducing the buffer size, but this doesn't seem to have any effect.
Here is an example of the class being used in a minimal reproducible example.:
import pygame
from psychopy import core
class midiPlayer(object):
setVolume = 1
def __init__(self, Sound):
self.Sound = Sound
def play(self):
freq = 44100
bitsize = -16
channels = 2
buffer = 1024
pygame.mixer.init(freq, bitsize, channels, buffer)
pygame.mixer.music.set_volume(self.setVolume)
pygame.mixer.music.load(self.Sound)
pygame.mixer.music.play()
def stop(self):
pygame.mixer.music.stop()
def setSound(self, music_file):
self.Sound = music_file
def busy(self):
return pygame.mixer.music.get_busy()
# You can download the MIDI file at https://wetransfer.com/downloads/868799aa1aacf7361de9a47d3218d2ee20200818095737/c3ccee ; obviously you'll need to update the file location below to wherever the file is saved on your own computer:
MIDIFILE = midiPlayer("/Users/sam/Downloads/sounds/A4_version_2_gentlemen_normal.mid")
trialClock = core.Clock()
started_playing = 0
text_printed = 0
continueRoutine = True
trialClock.reset()
while continueRoutine:
t = trialClock.getTime()
if started_playing == 0:
MIDIFILE.play()
started_playing = 1
if t >= 4.2 and text_printed ==0:
print 'now'
text_printed = 1
# this should appear on the 8th note of the tune
if t >= 6:
MIDIFILE.stop()
continueRoutine = False
Related
I'm trying to make a python program that plays a video in sync with a light show done via Arduino. To achieve this I need to know what frame of the video is currently playing to send out data to the Arduino.
I modified the cocoavlc.py example of python-vlc to play a video, pause, resume and rewind it, go forward and backwards by 10 seconds.
To keep track of the frame number tried the method get_time of python-vlc but it only updates a few times a second. I had the idea to interpolate its data with a timer but it's not perfect.
Here's the code (without the timer):
import vlc
from pycocoa import __name__ as _pycocoa_
from pycocoa import App, Item, ItemSeparator, MediaWindow, Menu, OpenPanel
from os.path import isfile
from threading import Thread
from time import sleep
import time
_Movies = '.m4v', '.mov', '.mp4'
_Select = 'select a video file from the panel'
class AppVLC(App):
player = None
sized = None
Toggle = None
video = None
window = None
def __init__(self, video = None, title = 'AppVLC'):
super(AppVLC, self).__init__(title = title)
self.media = None
self.Toggle = Item('Play', self.menuToggle_, key='p')
self.video = video
self.player = vlc.MediaPlayer()
def appLaunched_(self, app):
super(AppVLC, self).appLaunched_(app)
self.window = MediaWindow(title=self.video or self.title)
if self.player and self.video and isfile(self.video):
# the VLC player on macOS needs an ObjC NSView
self.media = self.player.set_mrl(self.video)
self.player.set_nsobject(self.window.NSview)
menu = Menu('VLC')
menu.append(
Item('Open...', key='o'),
ItemSeparator(),
self.Toggle,
Item('Rewind', key='r'),
Item('Forward', key='f'),
ItemSeparator(),
Item('Back', key='b'))
ItemSeparator(),
self.append(menu)
self.menuPlay_(None)
self.window.front()
def menuOpen_(self, item):
self.menuPause_(item)
self.badge.label = 'O'
v = OpenPanel(_Select).pick(_Movies)
if v:
self.window.title = self.video = v
self.player.set_mrl(v)
self.sized = None
def menuPause_(self, item, pause = False):
if pause or self.player.is_playing():
self.player.pause()
self.badge.label = 'S'
self.Toggle.title = 'Play'
def menuPlay_(self, item_or_None):
self.player.play()
self._resizer()
self.badge.label = 'P'
self.Toggle.title = 'Pause'
def menuRewind_(self, item):
self.player.set_position(0.0)
self.badge.label = 'R'
self.sized = None
def menuForward_(self, item):
time = self.player.get_time()
lenght = self.player.get_length()
time = time + 10000
if time < lenght:
self.player.set_time(time)
self.sized = None
def menuBack_(self, item):
time = self.player.get_time()
lenght = self.player.get_length()
time = time - 10000
if time > 0:
self.player.set_time(time)
self.sized = None
def menuToggle_(self, item):
if self.player.is_playing():
self.menuPause_(item, pause=True)
else:
self.menuPlay_(item)
def windowClose_(self, window):
if window is self.window:
self.terminate()
super(AppVLC, self).windowClose_(window)
def windowResize_(self, window):
if window is self.window:
self._resizer()
super(AppVLC, self).windowResize_(window)
def _resizer(self):
if self.sized:
self.window.ratio = self.sized
else:
Thread(target=self._sizer).start()
def _sizer(self, secs=0.1):
while True:
w, h = self.player.video_get_size(0)
if h > 0 and w > 0:
self.window.ratio = self.sized = w, h
break
elif secs > 0.001:
sleep(secs)
else:
break
def get_frame(self):
#?
def trackframes():
frame = 0
while True:
if frame != app.get_frame():
frame = app.get_frame()
send(frame) #send data to the Arduino
if __name__ == '__main__':
_video = OpenPanel('Select a video file').pick(_Movies)
app = AppVLC(video = _video)
Thread(target = trackframes).start()
app.run(timeout = None)
The only sensible way I have discovered to approximate the frame number in python vlc, is to take the frames per second player.get_fps() or 25, if not available and calculate the frame number based on the current playing time.
sec = player.get_time() / 1000
frame_no = int(round(sec * fps))
so I had this idea of controlling a media player from a python script like VLC for example, but since I am new to Python I don't know how to achieve that,
so let me explain what I am looking for is
for example, I want to get and set a volume value of VLC from my Python script?
I am not asking for a whole code or something like that just some tips to follow and thanks in advance
Install python-vlc
pip install python-vlc
Just change the path,your good to go..
from vlc import Instance
import time
import os
class VLC:
def __init__(self):
self.Player = Instance('--loop')
def addPlaylist(self):
self.mediaList = self.Player.media_list_new()
path = r"C:\Users\dell5567\Desktop\engsong"
songs = os.listdir(path)
for s in songs:
self.mediaList.add_media(self.Player.media_new(os.path.join(path,s)))
self.listPlayer = self.Player.media_list_player_new()
self.listPlayer.set_media_list(self.mediaList)
def play(self):
self.listPlayer.play()
def next(self):
self.listPlayer.next()
def pause(self):
self.listPlayer.pause()
def previous(self):
self.listPlayer.previous()
def stop(self):
self.listPlayer.stop()
Create a object
player = VLC()
Add playlist
player.addPlaylist()
Play the song
player.play()
time.sleep(9)
Play the next song
player.next()
time.sleep(9)
Pause the song
player.pause()
time.sleep(9)
Resume the song
player.play()
time.sleep(9)
Previous song
player.previous()
time.sleep(9)
Stop the song
player.stop()
Controlling vlc from tcp socket connection is better than vlc-ctrl. I tried vlc-ctrl in my raspberry pi,i cannot reach my expectation. So i decided to control the vlc player from socket connection.
Steps:-
1) you need to run from command prompt or from shell 'vlc --intf rc --rc-host 127.0.0.1:44500'[starting vlc player] to enable vlc player for controlling it from tcp connection.... you can start vlc like this from python using subprocess.
2) for cntrolling from python here is my sample script:
class player():
def __init__(self):
self.is_initiated = False
self.SEEK_TIME = 20
self.MAX_VOL = 512
self.MIN_VOL = 0
self.DEFAULT_VOL = 256
self.VOL_STEP = 13
self.current_vol = self.DEFAULT_VOL
def toggle_play(self):
if not self.is_initiated:
self.is_initiated = True
self.thrededreq("loop on")
self.thrededreq("random on")
self.thrededreq("add /home/pi/Desktop/Music")#adding the music folder
print("Init Playing")
return
self.thrededreq("pause")
print("Toggle play")
def next(self):
if not self.is_initiated:
self.toggle_play()
return
self.thrededreq("next")
print("Next")
pass
def prev(self):
if not self.is_initiated:
self.toggle_play()
return
self.thrededreq("prev")
print("Previous")
pass
def volup(self):
self.current_vol = self.current_vol + self.VOL_STEP
self.thrededreq("volume " + str(self.current_vol))
print("Volume up")
pass
def voldown(self):
self.current_vol = self.current_vol - self.VOL_STEP
self.thrededreq("volume " + str(self.current_vol))
print("Volume Down")
pass
def seek(self, forward: bool):
length = self._timeinfo("get_length")
print(length)
cur = self._timeinfo("get_time")
print(cur)
if (forward):
seekable = cur + self.SEEK_TIME
else:
seekable = cur - self.SEEK_TIME
if seekable > length:
seekable = length - 5
if seekable < 0:
seekable = 0
self.thrededreq("seek " + str(seekable))
print("Seek: ",seekable," Cur: ",cur,"Len: ",length)
pass
def _timeinfo(self, msg):
length = self.req(msg, True).split("\r\n")
if (len(length) < 2):
return None
length = length[1].split(" ")
if (len(length) < 2):
return None
try:
num = int(length[1])
return num
except:
return None
def req(self, msg: str, full=False):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.settimeout(0.7)
sock.connect(('127.0.0.1', 44500))
response = ""
received = ""
sock.sendall(bytes(msg + '\n', "utf-8"))
# if True:
try:
while (True):
received = (sock.recv(1024)).decode()
response = response + received
if full:
b = response.count("\r\n")
if response.count("\r\n") > 1:
sock.close()
break
else:
if response.count("\r\n") > 0:
sock.close()
break
except:
response = response + received
pass
sock.close()
return response
except:
return None
pass
def thrededreq(self, msg):
Thread(target=self.req, args=(msg,)).start()
#'vlc --intf rc --rc-host 127.0.0.1:44500' you need to run the vlc player from command line to allo controlling it via TCP
Player=player()
player.toggle_play()
#player.next()
#player.prev()
if you want more command and controlling,use"SocketTest" and connect to the port of vlc and check out....
this one has more control option than vlc-ctrl.
You can use python's module vlc-ctrl for this automation. And then use subprocess module module to execute its commands.
1) Install vlc-ctrl through pip
pip install vlc-ctrl
test.py: (To volume up)
import subprocess
subprocess.Popen(['vlc-ctrl', 'volume', '+10%'])
And run code with:
python test.py
More documentation for vlc-ctrl module here.
I want to know how to change video aspect ratio of vlc media player in python to 16:10. Note that I am using vlc module. my code is as below:
import vlc
class Player():
def __init__(self):
self._instance = vlc.Instance(['--video-on-top'])
self._player = self._instance.media_player_new()
self._player.set_fullscreen(True)
def play(self, path):
media = self._instance.media_new(path)
self._player.set_media(media)
self._player.play()
def stop(self):
self._player.stop()
p=Player()
p.play('C:\\Users\\Keshavarz\\Desktop\\a.mp4')
Use the video_set_aspect_ratio("n:n") option where "n:n" is any of the usual suspects "16:9", "4:3" etc but can be anything you want such as "2:5" for example.
You will also need to keep the script alive, I've included a simple loop in your play function, to do that.
import vlc
import time
class Player():
def __init__(self):
self._instance = vlc.Instance(['--video-on-top'])
self._player = self._instance.media_player_new()
#self._player.set_fullscreen(True)
self._player.video_set_aspect_ratio("16:9")
def play(self, path):
media = self._instance.media_new(path)
self._player.set_media(media)
self._player.play()
playing = set([1,2,3,4])
time.sleep(0.1)
while True:
state = self._player.get_state()
if state not in playing:
break
time.sleep(1)
def stop(self):
self._player.stop()
p=Player()
p.play('C:\\Users\\Keshavarz\\Desktop\\a.mp4')
Hi all and thanks for the help.
I am using a PyQt GUI to read and write voltages to mass flow controls and a heat flux gage. I am using QThreads to have a thread running in the background continuously updating the measurements displayed in the GUI. I am running into trouble having the background thread actually update the GUI as it does not have access to the GUI thread's functions. From what I have read online there is something about "moving" on thread into the other but am not sure what is meant by this. Can someone clarify this/point me in the right direction?
Here is my code:
from PyQt4 import QtGui, QtCore
import sys
import design4
import piplates.DAQC2plate as DAQC2
import time
import threading
air = 0.0
propane = 0
tolerance = .1
n = 1 #number of air controllers
class App4(QtGui.QMainWindow, design4.Ui_MainWindow):
def __init__(self, parent =None):
super(self.__class__, self).__init__()
self.setupUi(self)
self.sendFlow.clicked.connect(self.inputClicked)
self.displayFlow.clicked.connect(self.outputClicked)
self.hfButton.clicked.connect(self.heatFluxRead)
self.myThread = Worker()
self.myThread.start()
def inputClicked(self):
air = float(self.AirFlowInput.text())
propane = self.PropaneFlowInput.text()
if air <= 160 and air > 0:
acv = air / 20.0 / n *2 +.05#compute air control voltage for each controller
DAQC2.setDAC(0,0,acv) #changing voltage signal for channel 0
DAQC2.setDAC(0,1,acv)
else:
DAQC2.setDAC(0,0,0)
print DAQC2.getDAC(0,1)
print DAQC2.getDAC(0,0)
def outputClicked(self):
airRead = float(DAQC2.getADC(0,0)-.01) * 40 / n #converting 0-4Volts to flow
self.airFlowMeasured.display(airRead)
#print DAQC2.getADC(0,0)
#propRead = float(DAQC2.getADC(0,2)-.01) * 20
#self.propaneFlowMeasured.display(propRead)
#print DAQC2.getADC(0,1)
#palette = self.airFlowMeasured.palette()
#role = self.airFlowMeasured.backgroundRole()
#if float(DAQC2.getADC(0,0)) < (air*(1-tolerance):
# palette.setColor(role, QColor('yellow'))
#else if
def heatFluxRead(self):
heatFlux = float(DAQC2.getADC(0,7)) * 5800.0 #converts volts to kW/m^2
self.hfNumber.display(heatFlux)
print heatFlux
print self.getADC2(0,7)
def getADC2(self,addr,channel):
DAQC2.VerifyADDR(addr)
DAQC2.VerifyAINchannel(channel)
resp= DAQC2.ppCMD(addr,0x30,channel,0,2)
value=(256*resp[0]+resp[1])
if (channel==8):
value=value*5.0*2.4/65536
else:
value=(value*24.0/65536)-12.0
value=round(value*DAQC2.calScale[addr][channel]+DAQC2.calOffset[addr][channel],5)
return value
def main():
app = QtGui.QApplication(sys.argv)
form = App4()
form.show()
app.exec_()
class Update(QtCore.QObject):
sendUpdate = QtCore.pyqtSignal()
class Worker(QtCore.QThread):
def __init__(self, parent = None):
QtCore.QThread.__init__(self, parent)
self.initSignal()
def initSignal(self):
self.u = Update()
self.u.sendUpdate.connect(self.outputClicked)
def run(self):
while True:
self.u.sendUpdate.emit()
print 1
time.sleep(.25)
if __name__ == '__main__':
main()
Thanks a ton for any help!
I think that reading through DAQC2.getADC() function does not consume much time so it is not necessary to use threads, what you want to do is a periodic task, so the most appropriate option is to use QTimer:
class App4(QtGui.QMainWindow, design4.Ui_MainWindow):
def __init__(self, parent =None):
super(self.__class__, self).__init__()
self.setupUi(self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.outputClicked)
self.timer.setInterval(250)
self.sendFlow.clicked.connect(self.inputClicked)
self.displayFlow.clicked.connect(self.timer.start)
self.hfButton.clicked.connect(self.heatFluxRead)
def inputClicked(self):
air = float(self.AirFlowInput.text())
propane = self.PropaneFlowInput.text()
if air <= 160 and air > 0:
acv = air / 20.0 / n *2 +.05#compute air control voltage for each controller
DAQC2.setDAC(0,0,acv) #changing voltage signal for channel 0
DAQC2.setDAC(0,1,acv)
else:
DAQC2.setDAC(0,0,0)
print DAQC2.getDAC(0,1)
print DAQC2.getDAC(0,0)
def outputClicked(self):
airRead = float(DAQC2.getADC(0,0)-.01) * 40 / n #converting 0-4Volts to flow
self.airFlowMeasured.display(airRead)
#print DAQC2.getADC(0,0)
#propRead = float(DAQC2.getADC(0,2)-.01) * 20
#self.propaneFlowMeasured.display(propRead)
#print DAQC2.getADC(0,1)
#palette = self.airFlowMeasured.palette()
#role = self.airFlowMeasured.backgroundRole()
#if float(DAQC2.getADC(0,0)) < (air*(1-tolerance):
# palette.setColor(role, QColor('yellow'))
#else if
def heatFluxRead(self):
heatFlux = float(DAQC2.getADC(0,7)) * 5800.0 #converts volts to kW/m^2
self.hfNumber.display(heatFlux)
print heatFlux
print self.getADC2(0,7)
def getADC2(self,addr,channel):
DAQC2.VerifyADDR(addr)
DAQC2.VerifyAINchannel(channel)
resp= DAQC2.ppCMD(addr,0x30,channel,0,2)
value=(256*resp[0]+resp[1])
if (channel==8):
value=value*5.0*2.4/65536
else:
value=(value*24.0/65536)-12.0
value=round(value*DAQC2.calScale[addr][channel]+DAQC2.calOffset[addr][channel],5)
return value
Edit: I figured it out shortly after posting, it's amazing how asking a question can help you re-examine things :-). I commented the switch in the code.
I'm working on a class to download single frames from motion jpeg streams every so many seconds. It worked fine until I added some code to disconnect from the stream once a single jpeg is loaded. Now the "recorder" seems to be storing the first frame retrieved and not replacing the "image" with new content. I can destroy and recreate the object every time to fix this but that's not a very elegant solution. Any help would be appreciated!
Here's the code for the Recorder class:
import cv2
import urllib2
import threading
from PIL import Image
import numpy as np
class MJpegCam:
def __init__(self, ip, timeout=5):
self.ip = ip
self.bytes= ''
self.image = ''
self.stream = None
self.stopcam = False
self.timeout = timeout
def start(self):
self.stream=urllib2.urlopen(self.ip, timeout=self.timeout)
def run():
while True:
if self.stopcam:
self.stopcam = False
return
try:
self.bytes+=self.stream.read(1024)
a = self.bytes.find('\xff\xd8')
b = self.bytes.find('\xff\xd9')
if a!=-1 and b!=-1:
jpg = self.bytes[a:b+2]
self.bytes= self.bytes[b+2:]
cv2img = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.CV_LOAD_IMAGE_COLOR)
try:
cv2RGB = cv2.cvtColor(cv2img,cv2.COLOR_BGR2RGB)
self.image = Image.fromarray(cv2RGB)
self.stop() #This is where the program was breaking
return #
except Exception as e:
pass
except AttributeError as e:
pass
thread = threading.Thread(target=run)
thread.start()
def stop(self):
self.stream.close()
self.stopcam = False #this needed to be switched to False
self.bytes = ''
def getImage(self):
return self.image
In the actual program I'm running multiple objects on separate processes but here's the basic idea:
cam = MJpegCam(ip)
secs = 10
while(i < end):
cam.start()
time.sleep(cam.timeout)
cam.stop()
time.sleep(secs - cam.timeout)