Closed oskude closed 4 years ago
thanks to https://stackoverflow.com/questions/25904537/how-do-i-send-data-to-a-running-python-thread i got it to not tank jack at all (well, no xruns and only ~1% jack-usage) :heart_eyes:
import jack
import numpy
import threading
import pygame
from queue import Queue
class Plotter (threading.Thread):
def __init__ (self, queue, size, args=(), kwargs=None):
threading.Thread.__init__(self, args=(), kwargs=None)
self.daemon = True
self.queue = queue
self.black = 0, 0, 0
self.white = 255, 255, 255
self.halfh = int(size[1] / 2)
self.screen = pygame.display.set_mode(size)
pygame.display.init()
def run (self):
while True:
data = self.queue.get()
if data is None:
return
self.paint(data)
def paint (self, data):
self.screen.fill(self.black)
x = 0
for d in data:
y = int(self.halfh * (d + 1))
pygame.draw.rect(self.screen, self.white, [x, y, 1, 1])
x += 1
pygame.display.flip()
client = jack.Client("foovju")
event = threading.Event()
input_1 = client.inports.register("input_1")
que = Queue()
size = client.blocksize, int(client.blocksize / 2)
plotter = Plotter(que, size)
plotter.start()
@client.set_process_callback
def process(frames):
assert frames == client.blocksize
data = input_1.get_array()
plotter.queue.put(data)
with client:
print('Press Ctrl+C to stop')
try:
event.wait()
except KeyboardInterrupt:
print('\nInterrupted by user')
i would still like to know any tips or tricks to make this use less cpu.
but please feel free to close this ticket (and maybe add this (or similar) to examples). now if you excuse me, i got some waves to ride :joy:
just for the records, thanks to https://stackoverflow.com/questions/6339057/draw-a-transparent-rectangle-in-pygame we get a fade out effect by filling the screen with slightly transparent black insted. (i guess cpu usage is higher thou).
diff --git a/main.py b/main.py
index b9456de..c411e9a 100644
--- a/main.py
+++ b/main.py
@@ -9,10 +9,11 @@ class Plotter (threading.Thread):
threading.Thread.__init__(self, args=(), kwargs=None)
self.daemon = True
self.queue = queue
- self.black = 0, 0, 0
self.white = 255, 255, 255
self.halfh = int(size[1] / 2)
self.screen = pygame.display.set_mode(size)
+ self.blend = pygame.Surface(size, pygame.SRCALPHA|pygame.HWSURFACE)
+ self.blend.fill([0, 0, 0, 64]) # TODO: make alpha user controllable. with midi fader!
pygame.display.init()
def run (self):
@@ -23,7 +24,7 @@ class Plotter (threading.Thread):
self.paint(data)
def paint (self, data):
- self.screen.fill(self.black)
+ self.screen.blit(self.blend, [0, 0])
x = 0
for d in data:
y = int(self.halfh * (d + 1))
ok, i stop spamming now :innocent:
holy transistors batman, did you know about gluOrtho2D()
?
AFAIK the data from get_array()
is an array of floats, ranging from -1.0
to 1.0
and lets say length is 1024
, then we could plot our data AS IS thanks to gluOrtho2D(0, 1024, -1.0, 1.0)
A.W.E.S.O.M.E:
import random
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
screen = pygame.display.set_mode([1024, 512], pygame.DOUBLEBUF|pygame.OPENGL)
pygame.display.init()
#glPointSize(2.0) # TODO: use if screen width not same as data points!!!
glColor3f(1.0, 1.0, 1.0)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
gluOrtho2D(0, 1024, -1.0, 1.0) # 1024 would be our number of data points
glFlush()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_POINTS)
for x in range(0, 1024):
y = random.uniform(-1.0, 1.0) # this would be our vanilla data point
glVertex2f(x,y)
glEnd()
glFlush()
pygame.display.flip()
pygame.time.wait(25)
yeah, sorry, thats just a proof-of-concept on the drawing side, cause i was not able to draw (or use any gl* commands) from any jack process function, it just segfaults :scream: :sob: :zzz:
moving on, thanks for all the fishsnakes and sorry for the noise :heart:
I typically suggest to use a queue, but you have already done that in your second comment.
It's normally a good idea to separate the audio callback from the drawing function. Depending on your JACK block size, the audio callback might run more often than the drawing function (or not).
Then, if you want to show a signal on the screen, you normally don't need the full sampling rate. Normally you can heavily downsample the signal. This way, the drawing function has to handle much less data. That's what I've done in this example: https://github.com/spatialaudio/python-sounddevice/blob/master/examples/plot_input.py
You seem to have moved on to C in the meantime, but my comments may be helpful there as well.
If you are using C, you can even use a better (because lock-free) queue: the JACK ringbuffer https://jackaudio.org/api/ringbuffer_8h.html
And you should not write to a global variable in your process callback! Just use the ringbuffer to shove audio data around ...
sorry if this is out of scope :smirk:, but i'm a python/audio-science noob and am just so happy how easy we can create a jack client with this library, so
blamethank you! :sweat_smile:so for funsies, i wanted to "plot" the data coming from
get_array()
, in real-time... my first omg-it-does-something experiment:it uses ~50% of one ~3GHz cpu, and its "tanking" jack badly...
any tips or tricks on making this use less cpu? (or affect jack less)