Reputation: 614
I'm trying to use pynput
to get realtime keyboard input, but the on_press function gets called on autorepeat.
example code:
#!/usr/bin/env python3
import sys
import numpy as np
import sounddevice as sd
from pynput import keyboard
frequency = []
def on_press(key):
global frequency
try:
print(key.vk)
if key.char == "q":
frequency.append(440)
elif key.char == "w":
frequency.append(880)
except AttributeError:
pass
def on_release(key):
global frequency
if key == keyboard.Key.esc:
# Stop listener
print("Press Enter")
return False
elif key.char == "q":
frequency.remove(440)
elif key.char == "w":
frequency.remove(880)
listener = keyboard.Listener(
on_press=on_press,
on_release=on_release,
suppress = True)
listener.start()
start_idx = 0
def callback(outdata, frames, time, status):
if status:
print(status, file=sys.stderr)
print(frames)
global start_idx
t = (start_idx + np.arange(frames)) / 48000
t = t.reshape(-1, 1)
outdata[:] = 0 * t
if len(frequency) > 0:
print("Playing")
for freq in frequency:
outdata[:] = outdata[:] + 0.2 * np.sin(2 * np.pi * freq * t)
start_idx += frames
try:
with sd.OutputStream(channels=1, callback=callback,
samplerate=48000):
input()
listener.stop()
except Exception as e:
print("Exception")
listener.stop()
exit()
If you run the code and press and hold the Q
key, the keyboard autorepeat kicks in and ruins the whole listener. Is there a python input module which handles raw keyboard input properly?
The second thing is that the code tends to crash my Xorg quite regularly. I just run the script a few times and the Xorg goes down. And I can't figure out why. Linux 5.5.2-zen1-1-zen x86_64 GNU/Linux
, X.Org 1.20.7
.
The third thing is that the sound synthesis seems to lag quite a bit. The number of frames to the callback function seems to hang around 400, which at the rate of 48000 samples per second is less then 10 milliseconds, but the actual audio feedback feels like on hundreds of milliseconds delay.
Upvotes: 1
Views: 761
Reputation: 71
pygame has a good keylistener and is easy to build a GUI window that displays output. It also works well in Linux:
import pygame
def main_loop():
#code
loopExit = False
while not loopExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
loopExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
#code
if event.type == pygame.KEYUP:
if event.key == pygame.K_q:
#code
https://www.pygame.org/docs/ref/key.html
Upvotes: 1