I'm doing a project with an embedded computer module, the EXM32 Starter Kit and I want to simulate a piano with 8 musical notes. The OS is linux and I'm programming in Python. My problem is that version of Python is the 2.4 without 'pygame' library to play two sounds simultaneously. At now I am using in python "os.system('aplay ./Do.wav')" to play, from linux console, the sound.
The simplificated question is: Can I use another library to do the same as:
snd1 = pygame.mixer.Sound('./Do.wav')
snd2 = pygame.mixer.Sound('./Re.wav')
snd1.play()
snd2.play()
to play 'Do' and 'Re' simultanously? I can use "auidoop" and "wave" library.
I tried use threading but the problem is that the program wait until the console command has been finished. Another library that can I used? or the method to do with 'wave' or 'audioop'?? (this last library I believe is only for manipulated sound files)
The complete code is:
import termios, sys, os, time
TERMIOS = termios
#I wrote this method to simulate keyevent. I haven't got better libraries to do this
def getkey():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
new[6][TERMIOS.VMIN] = 1
new[6][TERMIOS.VTIME] = 0
termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
key_pressed = None
try:
key_pressed = os.read(fd, 1)
finally:
termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
return key_pressed
def keyspress(note):
if note == DO:
os.system('aplay ./notas_musicales/Do.wav')
elif note == RE:
os.system('aplay ./notas_musicales/Re.wav')
elif note == MI:
os.system('aplay ./notas_musicales/Mi.wav')
elif note == FA:
os.system('aplay ./notas_musicales/Fa.wav')
elif note == SOL:
os.system('aplay ./notas_musicales/Sol.wav')
elif note == LA:
os.system('aplay ./notas_musicales/La.wav')
elif note == SI:
os.system('aplay ./notas_musicales/Si.wav')
DO = 'a'
RE = 's'
MI = 'd'
FA = 'f'
SOL = 'g'
LA = 'h'
SI = 'j'
key_pressed = ""
i = 1
#in each iteration the program enter into the other 'if' to doesn't interrupt
#the last sound.
while(key_pressed != 'n'):
key_pressed = getkey()
if i == 1:
keyspress(key_pressed)
i = 0
elif i == 0:
keyspress(key_pressed)
i = 1
print ord(key_pressed)
Due to the global interpreter lock ("GIL") in the default python implementation only one thread will be running at a time. So that won't help you much in this case.
Additionally, os.system waits for the command to finish, and spawns an extra shell to run the command in. You should use suprocess.Popen instead, which will return as soon as it has started the program, and by default does not spawn an extra shell. The following code should start both players as closely together as possible:
import subprocess
do = subprocess.Popen(['aplay', './notas_musicales/Do.wav'])
re = subprocess.Popen(['aplay', './notas_musicales/Re.wav'])
Your basic problem is that you want to spawn a process and not wait for its return value. You can't do that with os.system() (well you could just spawn dozens of threads).
You can do this with the subprocess module which incidentally is available since 2.4. See here for an example.
Related
First, the code (which I found here: https://github.com/defaultxr/taptempo.py/blob/master/taptempo.py)
#!/usr/bin/env python
from __future__ import print_function
import tty
import termios
from time import time
from sys import stdin
def getchar():
fd = stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(stdin.fileno())
ch = stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def addtime(times):
if type(times) != list:
raise(TypeError)
t = time()
if len(times) == 0:
tdiff = 0 # initial seed
else:
tdiff = t - times[-1][0]
return (t, tdiff)
def averagetimes(times):
averagetime = sum([row[1] for row in times])/float(len(times))
bpm = (1.0/(averagetime/60.0))
return (averagetime, bpm)
def main():
print('Tap a key on each beat. Press q to quit.', end='\r')
times = []
while True:
char = getchar()
if char in ('q', 'Q', '\x1b', '\x03'): # q, Q, ESC, Control+C
print()
quit()
times.append(addtime(times))
if len(times) > 1:
# remove first element if it's either the initial seed
# or when the list reaches max length
if times[0][1] == 0 or len(times) > 16:
del times[0]
(averagetime, bpm) = averagetimes(times)
print("\rDetected BPM: %0.3f (Avg time between each: %0.3fs)"
% (bpm, averagetime), end='')
if __name__ == '__main__':
main()
I get an error saying, "ERROR: Could not find a version that satisfies the requirement termios ERROR: No matching distribution found for termios"
After some research, it turns out, termios comes with Python, but it is not included in the windows distribution (it's only in Linux), since another utility called "Airflow" is also not in windows.
I'm a musician and it looks like a nice very lightweight little app, which would be great for "tempo tapping". Larger programs that include tempo tappers are usually too bulky and unnecessary and sometimes a little slow. So I was just wondering if there is a way I could to get that little app to work in windows?
It's an interesting question, anyway. I have never run across such a "conflict" (if it could be called that) between Windows and Linux in Python.
I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage
I've been browsing a long time searching an answer to this.
I'm using Python 2.7 in Unix.
I have a continuous while loop and I need an option where user could interrupt it, do something and after that the loop would continue.
Like:
while 2 > 1:
for items in hello:
if "world" in items:
print "hello"
else:
print "world"
time.sleep(5)
here user could interrupt the loop with pressing "u" etc. and modify elements inside he loop.
I started testing out with raw_input, but since it prompts me out every cycle, it's something that I don't need.
I tried methods mentioned here:
Keyboard input with timeout in Python
couple of times, but none of those seem to work how I wish.
>>> try:
... print 'Ctrl-C to end'
... while(True):
... pass
... except KeyboardInterrupt, e:
... print 'Stopped'
... raise
...
Ctrl-C to end
Stopped
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
>>>
Obviously you need to replace pass with whatever you are doing and print with the aftermath.
Here's how to do it by polling stdin:
import select, sys
p = select.poll()
p.register(sys.stdin, 1) #select the file descriptor,
#in this case stdin, which you want the
#poll object to pay attention to. The 1 is a bit-mask
#indicating that we only care about the POLLIN
#event, which indicates that input has occurred
while True:
for items in hello:
if "world" in items:
print "hello"
else:
print "world"
result = p.poll(5) #this handles the timeout too
if len(result) > 0: #see if anything happened
read_input = sys.stdin.read(1)
while len(read_input) > 0:
if read_input == "u":
#do stuff!
read_input = sys.stdin.read(1) #keep going
#until you've read all input
Note: This probably wouldn't work in Windows.
You could do nested while loops, something structured like this:
while true:
go = True
while go:
for items in hello:
if "u" in items:
go = False
else if "world" in items:
print "hello"
else:
print "world"
#Here you parse input to modify things in the nested loop, include a condition to set
#go back to true to reenter the loop
import sys
import os
import time
import termios
import tty
import fcntl
import errno
KEY = "u"
def read_characters(f):
fd = f.fileno()
# put descriptor in non-blocking mode
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
try:
while 1:
try:
yield f.read(1)
except IOError as e:
if e.errno == errno.EAGAIN:
# no more characters to read
# right now
break
finally:
# restore blocking mode
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
def main():
fd = sys.stdin.fileno()
# save current termios settings
old_settings = termios.tcgetattr(fd)
# tty sets raw mode using termios module
tty.setraw(fd)
try:
while True:
time.sleep(1)
for c in read_characters(sys.stdin):
if c == KEY: break
else:
c = None
if c == KEY: break
sys.stdout.write("still going\r\n")
finally:
# restore terminal settings
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
if __name__ == "__main__":
main()
I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage
I'm using raw_input in Python to interact with user in shell.
c = raw_input('Press s or n to continue:')
if c.upper() == 'S':
print 'YES'
It works as intended, but the user has to press enter in the shell after pressing 's'. Is there a way to accomplish what I need from an user input without needing to press enter in the shell? I'm using *nixes machines.
Under Windows, you need the msvcrt module, specifically, it seems from the way you describe your problem, the function msvcrt.getch:
Read a keypress and return the
resulting character. Nothing is echoed
to the console. This call will block
if a keypress is not already
available, but will not wait for Enter
to be pressed.
(etc -- see the docs I just pointed to). For Unix, see e.g. this recipe for a simple way to build a similar getch function (see also several alternatives &c in the comment thread of that recipe).
Actually in the meantime (almost 10 years from the start of this thread) a cross-platform module named pynput appeared.
Below a first cut - i.e. that works with lowercase 's' only.
I have tested it on Windows but I am almost 100% positive that it should work on Linux.
from pynput import keyboard
print('Press s or n to continue:')
with keyboard.Events() as events:
# Block for as much as possible
event = events.get(1e6)
if event.key == keyboard.KeyCode.from_char('s'):
print("YES")
Python does not provide a multiplatform solution out of the box.
If you are on Windows you could try msvcrt with:
import msvcrt
print 'Press s or n to continue:\n'
input_char = msvcrt.getch()
if input_char.upper() == 'S':
print 'YES'
curses can do that as well :
import curses, time
def input_char(message):
try:
win = curses.initscr()
win.addstr(0, 0, message)
while True:
ch = win.getch()
if ch in range(32, 127):
break
time.sleep(0.05)
finally:
curses.endwin()
return chr(ch)
c = input_char('Do you want to continue? y/[n]')
if c.lower() in ['y', 'yes']:
print('yes')
else:
print('no (got {})'.format(c))
To get a single character, I have used getch, but I don't know if it works on Windows.
Instead of the msvcrt module you could also use WConio:
>>> import WConio
>>> ans = WConio.getkey()
>>> ans
'y'
On a side note, msvcrt.kbhit() returns a boolean value determining if any key on the keyboard is currently being pressed.
So if you're making a game or something and want keypresses to do things but not halt the game entirely, you can use kbhit() inside an if statement to make sure that the key is only retrieved if the user actually wants to do something.
An example in Python 3:
# this would be in some kind of check_input function
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8").lower() # getch() returns bytes data that we need to decode in order to read properly. i also forced lowercase which is optional but recommended
if key == "w": # here 'w' is used as an example
# do stuff
elif key == "a":
# do other stuff
elif key == "j":
# you get the point
I know this is old, but the solution wasn't good enough for me.
I need the solution to support cross-platform and without installing any external Python packages.
My solution for this, in case anyone else comes across this post
Reference: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
from tkinter import Tk, Frame
def __set_key(e, root):
"""
e - event with attribute 'char', the released key
"""
global key_pressed
if e.char:
key_pressed = e.char
root.destroy()
def get_key(msg="Press any key ...", time_to_sleep=3):
"""
msg - set to empty string if you don't want to print anything
time_to_sleep - default 3 seconds
"""
global key_pressed
if msg:
print(msg)
key_pressed = None
root = Tk()
root.overrideredirect(True)
frame = Frame(root, width=0, height=0)
frame.bind("<KeyRelease>", lambda f: __set_key(f, root))
frame.pack()
root.focus_set()
frame.focus_set()
frame.focus_force() # doesn't work in a while loop without it
root.after(time_to_sleep * 1000, func=root.destroy)
root.mainloop()
root = None # just in case
return key_pressed
def __main():
c = None
while not c:
c = get_key("Choose your weapon ... ", 2)
print(c)
if __name__ == "__main__":
__main()
If you can use an external library, blessed (cross platform) can do do this quite easily:
from blessed import Terminal
term = Terminal()
with term.cbreak(): # set keys to be read immediately
print("Press any key to continue")
inp = term.inkey() # wait and read one character
Note that while inside the with block, line editing capabilities of the terminal will be disabled.
Documentation for cbreak, inkey, and an example with inkey.
Standard library solution for Unix-like operating systems (including Linux):
def getch():
import sys, termios
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~termios.ICANON
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
This works by putting the terminal into non-canonical input mode before reading from the terminal.
Alternative solution that does not echo the user's input (e.g. if the user presses z, z will not appear on screen):
def getch():
import sys, termios, tty
fd = sys.stdin.fileno()
orig = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # or tty.setraw(fd) if you prefer raw mode's behavior.
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, orig)
Usage example:
print('Press s or n to continue: ', end='', flush=True)
c = getch()
print()
if c.upper() == 'S':
print('YES')
use readchar:
import readchar
key = readchar.readkey()
if key == "a":
print("text")
https://pypi.org/project/readchar/ to webpage