spatialaudio / jackclient-python Goto Github PK
View Code? Open in Web Editor NEW🂻 JACK Audio Connection Kit (JACK) Client for Python :snake:
Home Page: https://jackclient-python.readthedocs.io/
License: MIT License
🂻 JACK Audio Connection Kit (JACK) Client for Python :snake:
Home Page: https://jackclient-python.readthedocs.io/
License: MIT License
I was trying to make a experimental computer keyboard from a Midi keyboard and was using this code:
import binascii
import os
from evdev import uinput, ecodes as e
import jack
from subprocess import Popen
Keys={
"3c":"a",
"3e":"s",
"40":"d",
"41":"f",
"43":"g",
"48":"a",
"4a":"s",
"4c":"d",
"4d":"f",
"4f":"g",
"51":"DOWN",
"52":"up",
"53":"left",
"54":"right",
"54":"enter",
"55":"backspace",
"56":"p",
}
def press(key):
pid=os.fork()
if pid==0:
with uinput.UInput() as ui:
eval("ui.write(e.EV_KEY, e.KEY_" + key.upper() +", 1)")
ui.syn()
setup = ['a2j', 'a2jmidid -e']
a2j = [Popen(cmd, shell=True) for cmd in setup]
client=jack.Client("VirtualControl")
inp=client.midi_inports.register("Input")
@client.set_process_callback
def process(frames):
for offset, data in inp.incoming_midi_events():
midihex = binascii.hexlify(data).decode()
if(midihex!='f8'):
pressed = midihex[0:2] =='90'
code=midihex[2:4]
intensity=midihex[4:6]
if pressed:
press(Keys[code])
#print(midihex)
#print('{0}: 0x{1}'.format(client.last_frame_time + offset, sbinascii.hexlify(data).decode()))
#press("b")
with client:
print('#' * 80)
print('press Return to quit')
print('#' * 80)
input()
Problem is that it crashes right after i press one or two keys. With the error:
File "/usr/local/lib/python3.6/dist-packages/jack.py", line 1787, in incoming_midi_events
assert not err, err
AssertionError: -105
This fork is there because i first thought it was something related with the small delay on the simulated keypress. If i just use print it works fine. What is causing this issue? The keys get inputed and then it crashes.
I noticed your code:
for i in range(_lib.jack_midi_get_event_count(buf)):
err = _lib.jack_midi_event_get(event, buf, i)
# TODO: proper error handling if this ever happens:
assert not err, err
yield event.time, _ffi.buffer(event.buffer, event.size)
I just noticed that if I simply comment out the assert line my script works! I don't know what it does so.... Ill keep this way for now.
Hi,
I'm trying to modify this example in order to make it compatible with multiprocessing.
Mainly I had to rename some global variables:
#!/usr/bin/env python3
import sys
import threading
import jack
from mido import MidiFile
from multiprocessing import Process
midi_file = '../Musica/Mozart/k265/Zwölf-Variationen.midi'
try:
mid = iter(MidiFile(midi_file))
except Exception as e:
sys.exit(type(e).__name__ + ' while loading MIDI: ' + str(e))
client = jack.Client('Luces')
midi_port = client.midi_outports.register('output')
midi_event = threading.Event()
midi_msg = next(mid)
midi_fs = None # sampling rate
midi_offset = 0
@client.set_process_callback
def process(frames):
global midi_offset
global midi_msg
midi_port.clear_buffer()
while True:
if midi_offset >= frames:
midi_offset -= frames
return # We'll take care of this in the next block ...
# Note: This may raise an exception:
midi_port.write_midi_event(midi_offset, midi_msg.bytes())
try:
midi_msg = next(mid)
except StopIteration:
midi_event.set()
raise jack.CallbackExit
midi_offset += round(midi_msg.time * midi_fs)
@client.set_samplerate_callback
def samplerate(samplerate):
global midi_fs
midi_fs = samplerate
@client.set_shutdown_callback
def shutdown(status, reason):
print('JACK shutdown:', reason, status)
midi_event.set()
def run_midi():
with client:
print('Playing', repr(midi_file), '... press Ctrl+C to stop')
try:
midi_event.wait()
except KeyboardInterrupt:
print('\nInterrupted by user')
if __name__ == "__main__":
processes = [Process(target=run_midi)]
for p in processes:
p.start()
for p in processes:
p.join()
Now I get this error at the end of the execution:
Playing '../Musica/Mozart/k265/Zwölf-Variationen.midi' ... press Ctrl+C to stop
Cannot read socket fd = 5 err = Success
CheckRes error
JackSocketClientChannel read fail
JACK shutdown: JACK server has been closed <jack.Status 0x21: failure, server_error>
How can I fix it?
Thank you!
Carlo
Hi,
i am working on a Yolo program that takes 3 camera inputs, process the live feed and just looking for a way to give 3 different output to 3 different speakers at a same time.
is it possible with this api? all the 3 devices speakers are wired connected via usb port!
Please help me
Thanks
Is it possible to control (make and break) the Alsa MIDI connections in the same way that the Jack MIDI connections can be made?
In QJackCtl these are on the third tab and remain persistent the app is quit - which makes me think that Jackd is handling them.
I could receive the MIDI packets (with python-mido) and relay them, but I'm after a better (less latency) method.
It would be great if someone could add an example of recording audio to the examples in the documentation. If I figure it out I will try to add it. Thanks for the great library!
This probably demonstrates my lack of understanding on the inner workings of JACK, but here it goes... Why doesn't come jackclient with any volume controls? This is my No.1 Python need for Jack ;-) Thanks for clarifying.
Is there python binding for API to start and control a JACK server?
https://jackaudio.org/api/group__ControlAPI.html
I wasn't able to find them in the documentation.
I'd love to control how it starts the server like setting inputs and outputs, sampling rate, and so on.
I'm trying to write a program to send midi events to a soft synth. I can't tell from the docs what the 'time' parameter should represent.
A real simple example which I thought would work:
client = jack.Client('MIDI-Chord-Generator')
inport = client.midi_inports.register('input')
outport = client.midi_outports.register('output')
client.activate()
outport.connect("Helm:events-in")
for x in range(0,10):
print("Note")
outport.write_midi_event(0, (0x90, 60, 100))
time.sleep(5)
outport.write_midi_event(0, (0x80, 60, 100))
Can you let me know if I'm missing something obvious!
I saw this error, and I'm not quite sure what's happening. I think jackd may have stopped in the background and restarted, it's a pretty complex environment, and there are also multiple threads.
Thought you guys might want to know about it anyway though.
Thanks for the great library!
Current thread 0x00007f6719361700 (most recent call first):
File "/usr/lib/python3/dist-packages/jack.py", line 315 in owns
File "/usr/lib/python3/dist-packages/jack.py", line 1377 in _wrap_port_ptr
File "/usr/lib/python3/dist-packages/jack.py", line 1265 in get_port_by_name
File "/usr/lib/python3/dist-packages/jack.py", line 1361 in _port_list_from_pointers
File "/usr/lib/python3/dist-packages/jack.py", line 1329 in get_ports
File "/home/daniel/Projects/KaithemAutomation/kaithem/src/jackmanager.py", line 1090 in _get_ports_fix
File "/home/daniel/Projects/KaithemAutomation/kaithem/src/jackmanager.py", line 1170 in checkJackClient
File "/home/daniel/Projects/KaithemAutomation/kaithem/src/jackmanager.py", line 1064 in work
File "/usr/lib/python3.6/threading.py", line 864 in run
File "/home/daniel/Projects/KaithemAutomation/kaithem/src/tweaks.py", line 42 in run_with_except_hook
File "/usr/lib/python3.6/threading.py", line 916 in _bootstrap_inner
File "/usr/lib/python3.6/threading.py", line 884 in _bootstrap
Hello,
I would like to get current transport position from jack server. ffi string in jack.py contain reference to jack_transport_query() function but there is no corresponding python method : client.transport_query(). Did you plan to add this function ? I can help or test if you want...
Best, Vampouille
Creating an instance of jack.Client will spawn an instance of jackd server, if it is not already running.
Is there a way to specify the options to the spawned jackd server from within this python package?
I have recently noticed some very annoying behavior with the Jack server "clogging up" on client names. The critical application is that a client is created (usually does something) and is destroyed afterwards. This is then repeated for a considerable amount of times with an identical name of the client. Although this seems like a pretty bonkers use case, we actually rely on doing it (in a current implementation at least). Nevertheless, I would expect this to be possible and handled by the server without problems. Right?
I created the a simple script which provokes the behavior.
import jack
i = 0
while True:
i += 1
# name = f'Client{i:d}' # this runs infinitely
name = f'Client' # this ALWAYS fails for the 99th instance ???
print(f'Test {i:d}: creating "{name}" ...')
client = jack.Client(name=name)
client.activate()
client.deactivate()
client.close()
del client
Executing the script results in the following trailing output and error:
...
Test 97: creating "Client" ...
Test 98: creating "Client" ...
Test 99: creating "Client" ...
Cannot open Client client
JackShmReadWritePtr1::~JackShmReadWritePtr1 - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Traceback (most recent call last):
File "jack_test.py", line 11, in <module>
client = jack.Client(name=name)
File ".../jack.py", line 213, in __init__
raise JackOpenError(name, self._status)
jack.JackOpenError: Error initializing "Client": <jack.Status 0x21: failure, server_error>
The surprising thing (to me at least) is that this fails at the 99th client. And this is always reproduced in the exact same way.
On very annoying aspect is that this client name is now blocked indefinitely. An continues to be blocked even after restarting the Jack server. I did not find a possibility to instantiate a client with the given name again. This is indeed a problem when using tools like ecasound
which do not let you determine the instantiated Jack client name (this is also how I encountered the problem). The easiest way to reset the behavior is to log out and in of the OS session (or restart), which is still very disruptive. Is there an easier option to get this reset?
This would be helpful for checking the transport state, e.g. in combination with the timebase_master.py
example (#19).
https://github.com/jackaudio/jack2/blob/master/example-clients/showtime.c
https://github.com/jackaudio/example-clients/blob/master/showtime.c
Hello I am running the chatty client demo. the Xrun call back is producing negative values
e.g. xrun; delay -274886000640.0 microseconds
This clearly makes no sense.... There is no audible artifacts in the audio stream
I am running Ubuntu 20.04.2
There is a strange behaviour for clients existing before a new jack.Client is created, once the port registration callback is set.
I made a test using python 2.7, ardour and jack_mixer.
client = jack.Client('xyz', no_start_server=True)
def port_cb(*args):
print 'port_cb: {}'.format(args)
client.set_port_registration_callback(port_cb)
client.activate()
This generates a segfault on my machine (unfortunally I'm not able to make tests on other setups). The strange thing is that this does not happen when the application is started after the jack.Client instance is created and activated.
This problem is not reproducible when using a client created with jackclient-python (I don't exactly know why, maybe they exit in a different way).
Couldn't find any clear example how to use write_midi_event so came up with the following working code (a basic virtual MIDI cable) that you might add to your examples section. Any comments ?
import jack
midiInBuffer = []
midiOutBuffer = []
client = jack.Client('jack')
midi_in = client.midi_inports.register('midi_in')
midi_out = client.midi_outports.register('midi_out')
@client.set_process_callback
def process(frames):
#MIDI sent
midi_out.clear_buffer()
if (len(midiOutBuffer)):
for msg in midiOutBuffer:
midi_out.write_midi_event(0, msg)
print('MIDI sent = ', msg)
midiOutBuffer.clear()
#MIDI received
for offset, data in midi_in.incoming_midi_events():
msg = struct.unpack('3B', data)
midiInBuffer.append(msg)
print('MIDI rcvd = ', msg)
client.activate()
print(client.midi_inports)
print(client.midi_outports)
#forward all incoming messages from midi_in to midi_out
while True:
for msg in midiInBuffer
midiOutBuffer.append(msg)
print('MIDI fwd = ', msg)
midiInBuffer.clear()
The following code snippet produces the same list of ports, the correct list for the first ('hard', hardware-connected) JACK server, all four times it does the get_ports() print. The .name print comes out correctly though. Any ideas why this is happening?
print('-----------------------------------------------------------------')
print('Create JACK clients, and use them to verify JACK servers...')
print('-----------------------------------------------------------------')
jack_client_hard = jack.Client('jack_client_hard', servername='default')
jack_client_hard.activate()
jack_client_hard.outports.register('dummy_4hard')
print('JACK ports for hard server:')
print(jack_client_hard.name)
print(jack_client_hard.get_ports())
print('')
jack_client_soft1 = jack.Client('jack_client_soft1', servername='SOFT1')
jack_client_soft1.activate()
jack_client_soft1.outports.register('dummy_4soft1')
print('JACK ports for server SOFT1:')
print(jack_client_soft1.name)
print(jack_client_soft1.get_ports())
print('')
jack_client_soft2 = jack.Client('jack_client_soft2', servername='SOFT2')
jack_client_soft2.activate()
jack_client_soft2.outports.register('dummy_4soft2')
print('JACK ports for server SOFT2:')
print(jack_client_soft2.name)
print(jack_client_soft2.get_ports())
print('')
jack_client_soft3 = jack.Client('jack_client_soft3', servername='SOFT3')
jack_client_soft3.activate()
jack_client_soft3.outports.register('dummy_4soft3')
print('JACK ports for server SOFT3:')
print(jack_client_soft3.name)
print(jack_client_soft3.get_ports())
print('')
input("Press Enter to continue...")
exit(0)
Hi, when I run the code below, it repeats the MIDI message forever. I can't seem to find the correct way to send a single midi message under my control. The first port connected below is just the GMIDImonitor with JACK support, the second is a midi port on a Echo AF12 connected to a mixer. Both show the message repeated until I hit the keyboard which satisfies the input() at the end of the code.:
#!/usr/bin/env python3
import jack
import struct
client = jack.Client("MyGreatClient")
inport = client.midi_inports.register("input")
outport = client.midi_outports.register("output")
portlist = client.get_ports(is_midi=True, is_physical=True)
for port in portlist:
print('port: {} is output: {}'.format(port.name, port.is_output))
@client.set_process_callback
def macsend(frames):
print('frames: {}'.format(frames))
outport.clear_buffer()
outport.write_midi_event(0, (0xB2, 0x01, 0x40))
client.activate()
client.connect(outport,"MIDI monitor:midi_in")
client.connect(outport, portlist[1].name)
print("#" * 80)
print("press Return to quit")
print("#" * 80)
input()
Hello everyone and thanks for this amazing project!
I'm trying to play a wave sound. I'm adding some code in an application which I didn't start from scratch, so it's quite possible I'm not understanding what I have to do!
I want to have a "metronome", so first I load the 2 metronome sounds using soundfile module:
mDataE, mSamplerateE = sf.read("/home/.../click-emphasis.wav", dtype=np.float32)
mData, mSamplerate = sf.read("/home/.../click.wav", dtype=np.float32)
then in Jack callback function, I check if beat has changed and I play the sound, routing it to the dedicated metronome jack out channels. output_buffers is an array of jack client .outports, metronome_left_channel and metronome_right_channel names of the 2 dedicated channels, and also previous_beat is defined out of callback function:
# METRONOME: when Jack transport gets into new beat, metronome sound is played
if state == 1 and 'beat' in position:
current_beat = position['beat']
if current_beat != previous_beat:
if current_beat == 1: # Emphasis
output_buffers[metronome_left_channel][:] += mDataE[:]
output_buffers[metronome_right_channel][:] += mDataE[:]
else:
output_buffers[metronome_left_channel][:] += mData[:]
output_buffers[metronome_right_channel][:] += mData[:]
previous_beat = current_beat
when I hit Play, I get this error:
output_buffers[metronome_left_channel][:] += mDataE[:]
ValueError: operands could not be broadcast together with shapes (1024,) (33412,2) (1024,)
it's first time I try to play a sound, so I'm missing something for sure, but I don't urderstand what..
thanks!
Manu
Hello,
I've been trying to make jackclient work (if possible) for a real-time audio processing application in python. You can see the code below:
import jack
import numpy as np
jclient = jack.Client("jclient")
jclient.register_port("in", jack.IsInput)
jclient.register_port("out", jack.IsOutput)
jclient.activate()
jclient.connect("system:capture_1","jclient:in")
for n_playback_port in (1, 2):
jclient.connect("jclient:out", "system:playback_{}".format(n_playback_port))
#sr = jclient.get_sample_rate()
buffer_size = jclient.get_buffer_size()
jcapture = np.zeros((1,buffer_size), 'f')
jinput = np.zeros((1,buffer_size), 'f')
joutput = np.zeros((1,buffer_size), 'f')
try:
while True:
print("Capturing audio")
try:
jclient.process(joutput, jcapture)
except jack.InputSyncError:
print("InputSyncError")
except jack.OutputSyncError:
print("OutputSyncError")
#process jcapture here
print("Playing back\n")
try:
jclient.process(jcapture, jinput)
except jack.InputSyncError:
print("InputSyncError")
except jack.OutputSyncError:
print("OutputSyncError")
except KeyboardInterrupt:
pass
The problem is that even if I don't process the signal at all (use the code above) and just playback the input I hear the input but with interrupts between the consecutive frames (buffers). Am I doing something wrong or is there a better way to do this?
I'm using 16000 kHz sample rate and 1024 samples buffer size for the jackd server.
With this code, python just crashes:
import jack
client = jack.Client('test')
print(client.get_ports('[]'))
I also tried different combinations (single bracket, adding text before, etc). The segfault happens on both Python 2.7.12 and 3.4.5.
Hi,
I need to create a JACK client that plays an audio file and a MIDI file at the same time.
I'm trying to merge this two examples:
I miss the last step (I hope), i.e. merging the process()
functions:
Do you have some suggestions? If I understand correctly, this while
loop blocks the script until the end of the MIDI file, but I have to play MIDI and audio in parallel.
Thank you!
Carlo
I am trying to send MIDI messages using jackclient-python and I am seeing the issue that JACK repeats outgoing messages. I've managed to break this down to this minimal example:
import jack
cl = jack.Client('Test')
mo = cl.midi_outports.register('p2')
sent = False
@cl.set_process_callback
def process(frames):
global sent
if not sent:
mo.write_midi_event(1, b'\x80\x2f\x32')
mo.write_midi_event(2, b'\x80\x2f\x33')
print("Sent!")
sent = True
with cl:
input()
The write_midi_event
code is indeed only called once, but when I attach a MIDI analyzer (midisnoop in my case) I see that the two messages are rapidly repeated:
Am I doing something wrong here in the usage of the library?
Hey, very recently I experience this segmentation fault whenever trying to import the package. I have no idea yet what component caused the change in behavior. The most probable candidate is building more recent versions of jack2
from source. Maybe investigating this can help to solve a bug here or upstream.
This is the most basic case where the segfault happens (empty environment, basically not more than pip install
):
$ python3
Python 3.8.5 (default, Sep 4 2020, 02:22:02)
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import jack
[1] 41999 segmentation fault python3
Using faulthandler
reveals that it happens during the decoding of "JACK_METADATA_"
during import:
$ python3 -q -X faulthandler
>>> import jack
Fatal Python error: Segmentation fault
Current thread 0x0000000114f1cdc0 (most recent call first):
File "/Users/helmholz/miniconda3/envs/test/lib/python3.8/site-packages/jack.py", line 82 in _decode
File "/Users/helmholz/miniconda3/envs/test/lib/python3.8/site-packages/jack.py", line 89 in <module>
File "<frozen importlib._bootstrap>", line 219 in _call_with_frames_removed
File "<frozen importlib._bootstrap_external>", line 783 in exec_module
File "<frozen importlib._bootstrap>", line 671 in _load_unlocked
File "<frozen importlib._bootstrap>", line 975 in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 991 in _find_and_load
File "<stdin>", line 1 in <module>
[1] 43708 segmentation fault python3 -q -X faulthandler
There seems to be a limitation on a maximum number of JACK clients I can instantiate (tested under OSX 10.14, JACK 1.9.11 from old OSX bundle, jackclient-python 0.4.5).
My limit which I get there is 61 (at least plus 1 for the application starting the JACK server before -- JackPilot or such) ... each with 2 input and 2 output ports and connections.
I'm instantiating clients for benchmarking reasons, that's why the massive number (any actual implementation will not use that many of course). Still, do you have any hint where that limitation might come from?
When I catch JACK xruns on certain clients via the API, what does it mean if the reported delay is 0ms?
Not working out of the box on Windows 10 x64, latest JACK and Python binary releases:
Free Win10 VM from Microsoft
JACK2 1.9.1 64 bit
Python 3.7.0 x86-64
Seems to be CFFI related, crash happens at jack.py line 45: _lib = _ffi.dlopen(_libname)
C:\Users\IEUser\Desktop\jackclient-python>python
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import jack
(after a couple of seconds the Python shells exits with no error messages...)
C:\Users\IEUser\Desktop\jackclient-python>
Windows application log
Faulting application name: python.exe, version: 3.7.150.1013, time stamp: 0x5b331a30
Faulting module name: ntdll.dll, version: 10.0.17134.165, time stamp: 0xf4df6dc2
Exception code: 0xc0000026
Fault offset: 0x0000000000099968
Faulting process id: 0x1624
Faulting application start time: 0x01d434ca6ba235ee
Faulting application path: C:\Users\IEUser\AppData\Local\Programs\Python\Python37\python.exe
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
Report Id: 5c6d9233-baba-4d47-aa17-64bf56997ebd
Faulting package full name:
Faulting package-relative application ID:
How can I contribute to further testing?
Hello.
Every time I try to import the jack
module, Python crashes/exits.
I have installed:
jackd.exe
.pip install JACK-Client
.Also can't find any errors/exceptions.
Am I doing something wrong or is that a bug? I have been trying to resolve this for about 2 hours, by trying different Python versions, this module versions (0.5.1, 0.5.0) etc. - could not find a solution on my own.
Hi,
is there any way to connect to a client that run on different machine in the local-network?
Or to run JACK-Client in Docker container while manipulating the jack connection on the host?
Thanks
hi,
i want to play a wav file in a loop.
I tried to modify playfile.py but without luck. My idea was to reset sndfile sf.seek(0) after all blocks put to queue.
any idea what's wrong?
I am trying to use jackclient-python to send sysex messages, and it was unclear from the documentation how to do this. Can you give me a simple example?
The sysex message I'm trying to send is F0 7F 7F 06 02 F7
(MMC play)
Thanks! I love this project!
Might we have JACK server name, as optional parameter for client object creation and references, instead of using environment variable $JACK_DEFAULT_SERVER ?
I have 4 different sound devices with total of 20 inputs and 12 outputs. However, client.get_ports() only returns two system:capture and two system:playback ports.
How can I get access to different inputs/outputs in different audio interface?
I get an error when running the metadata example, JACK-Client 0.5.0, Python 3.7.3, Ubuntu 19.04:
Traceback (most recent call last):
File "metadata.py", line 12, in <module>
client.set_property(client, jack.METADATA_PRETTY_NAME, 'Best Client Ever')
File "/home/user/.local/lib/python3.7/site-packages/jack.py", line 1520, in set_property
.format(key, subject))
ValueError: Unable to set property 'http://jackaudio.org/metadata/pretty-name' for subject 0
Related to #100: can jack.Client.set_process_callback
register more than one process callback?
Thank you!
Carlo
Now we have get_array()
for people who want to use NumPy and get_buffer()
for those who don't.
get_buffer()
provides bytes and users will have to convert the bytes to floats before they can do anything meaningful.
What about providing get_memoryview()
that does the conversion for them (but still doesn't depend on an external library)?
memoryview.cast() is only available since Python 3.3, but I think that doesn't matter, users of older versions will simply get an AttributeError
if they try to use it.
Any thoughts?
Hello, I apologize for adding this as an issue, but I don't see any other way of contact and/or my lack of understanding.
attempting to run midi_chords.py
With the code as provided:
@client.set_process_callback
def process(frames):
I get this at the console:
/usr/bin/python3.4 /home/mac/PycharmProjs/JackMIDITest/midi_chords.py
################################################################################
press Return to quit
################################################################################
From cffi callback <function Client.set_process_callback.<locals>.callback_wrapper at 0x7f28d3c04c80>:
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/jack.py", line 720, in callback_wrapper
return callback(frames, userdata)
TypeError: process() takes 1 positional argument but 2 were given
If I change the code to:
@client.set_process_callback
def process(frames, x):
It runs without error, but I see no midi output.
I made the following mod so as to see midi output:
with client:
client.connect(outport,"MIDI monitor:midi_in")
The client shows up in Jack in both cases...
Can the examples be relicensed under public domain? They are a good starting point, but the requirement of retaining the copyright notice in the work derived from them doesn't seem appropriate to me.
Or am I missing something?
Hi *,
I installed with sudo python3 -m pip install JACK-Client --user
.
If I try to import the module with import jack
, I see the following error:
~ $ python3 midi_ctl.py
Traceback (most recent call last):
File "midi_ctl.py", line 3, in <module>
import jack
ImportError: /usr/local/lib/python3.5/dist-packages/jack.cpython-35m-x86_64-linux-gnu.so: undefined symbol: Py_InitModule3
Any ideas?
BR,
Ck
sorry if this is out of scope 😏, 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! 😅
so for funsies, i wanted to "plot" the data coming from get_array()
, in real-time... my first omg-it-does-something experiment:
import jack
import numpy
import threading
import pygame
client = jack.Client("foovju")
event = threading.Event()
input_1 = client.inports.register("input_1")
black = 0, 0, 0
white = 255, 255, 255
size = width, height = client.blocksize, int(client.blocksize / 2)
screen = pygame.display.set_mode(size)
pygame.display.init()
@client.set_process_callback
def process(frames):
assert frames == client.blocksize
data = input_1.get_array()
screen.fill(black)
x = 0; h = height / 2
for d in data:
y = int(h * (d + 1))
pygame.draw.rect(screen, white, [x, y, 1, 1])
x += 1
pygame.display.flip()
with client:
print('Press Ctrl+C to stop')
try:
event.wait()
except KeyboardInterrupt:
print('\nInterrupted by user')
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)
pssst, wanna see some cool waves? try this as audio source: https://ultimae.bandcamp.com/track/security or for mind-blow, try: https://www.youtube.com/user/jerobeamfenderson1 ... dammit, now i wanna know how that oscilloscope works! :yet_another_rabbit_hole:
hello,
I'm trying to figure how to keep the client running but it just shows up for a little
# coding=utf-8
import io
import logging
import sys
import jack
import soundfile as sf
import queue
import threading
BUFFERSIZE = 1024
class AudioLib:
def __init__(self):
self.log = logging.getLogger(__name__)
self.log.info("INIT AUDIO LIB")
self.buffersize = BUFFERSIZE
self.queue = queue.Queue(maxsize=self.buffersize)
self.event = threading.Event()
self.jack_client = jack.Client('TEST', session_id='Test')
self.blocksize = self.jack_client.blocksize
self.samplerate = self.jack_client.samplerate
self.jack_client.set_xrun_callback(self.xrun)
self.jack_client.set_shutdown_callback(self.shutdown)
self.jack_client.set_process_callback(self.process)
self.voice_output_0 = self.jack_client.outports.register('voice_0')
print("ACTIVATE")
self.jack_client.activate()
# self.jack_client.connect(self.voice_output_0, 'system:playback_1')
def play(self, format, audio, fin):
audio_samplerate, bits, channels = format
with sf.SoundFile(io.BytesIO(audio),
channels=channels,
samplerate=audio_samplerate,
format='RAW',
subtype='FLOAT') as audio_stream:
block_generator = audio_stream.blocks(blocksize=self.blocksize,
always_2d=True, fill_value=0)
for _, data in zip(range(self.buffersize), block_generator):
self.queue.put_nowait(data) # Pre-fill queue
timeout = self.blocksize * self.buffersize / self.samplerate
for data in block_generator:
self.queue.put(data, timeout=timeout)
self.queue.put(None, timeout=timeout) # Signal end of file
self.event.wait() # Wait until playback is
def print_error(self, *args):
print(*args, file=sys.stderr)
def xrun(self, delay):
self.print_error("An xrun occured, increase JACK's period size?")
def shutdown(self, status, reason):
self.print_error('JACK shutdown!')
self.print_error('status:', status)
self.print_error('reason:', reason)
self.event.set()
def stop_callback(self, msg=''):
if msg:
self.print_error(msg)
for port in self.jack_client.outports:
port.get_array().fill(0)
self.event.set()
raise jack.CallbackExit
def process(self, frames):
assert frames == self.jack_client.blocksize
try:
data = self.queue.get_nowait()
for channel, port in zip(data.T, self.jack_client.outports):
port.get_array()[:] = channel
except queue.Empty:
self.stop_callback('Buffer is empty: increase buffersize?')
if data is None:
self.stop_callback() # Playback is finished
else:
for channel, port in zip(data.T, self.jack_client.outports):
port.get_array()[:] = channel
this is mostly a rip off play file example
thanks
Hello,
first of all I'd like to thank you for this nice module. It's great to see it's not a dead project.
I have a problem/question. Let's say I want to create a simple application which writes MIDI beeps on output, Morse code for example. How can I do that? In all examples there is some trigger, like MIDI input, but I want my application to send those signals whenever it wants. Can I do it without callbacks?
I tried this, but it does not work:
import jack
client = jack.Client("MYMIDI")
outport = client.midi_outports.register("output")
@client.set_process_callback
def process(frames):
outport.clear_buffer()
i = client.frame_time
outport.write_midi_event(i, (144, 36, 64))
i += 1000
outport.write_midi_event(i, (128, 36, 64))
with client:
input()
Thanks very much,
Petr
Printing to the terminal isn't allowed in the process callback.
The data should be transferred to a non-realtime thread for printing.
This could also be a nice usage example for the RingBuffer
.
If you install jackclient using pip without installing jack first, it becomes hard to fix the problem. To reproduce (i use anaconda, so my pip installs are all local by default).
pip install JACK-Client
sudo apt install multimedia-jack
pip uninstall JACK-Client
pip install JACK-Client
This install mistake brings up a very strange error where find_library returns a directory instead of a library. The ... dots aren't real, just hiding my file system for no particular reason.
>>> import jack
OSError: cannot load library '.../miniconda3/envs/py3/lib/jack'
>>> from ctypes.util import find_library
>>> find_library("jack")
'.../miniconda3/envs/py3/lib/jack'
I fixed this eventually by:
step (3)
deleting the .../miniconda3/envs/py3/lib/jack
directory
step (4)
Is it possible to delete this directory as a part of the pip uninstall process?
Recently had an issue, where:
set_port_registration_callback()
before activate()
) function was running a bunch of libjack (through this module, ofc, code link) calls.And that caused client (current git master - c5982a3) to reliably crash with:
cannot read result for request type 10 from server (Connection reset by peer)
cannot send event response to engine (Broken pipe)
cannot continue execution of the processing graph (Bad file descriptor)
jack_client_thread: graph error - exiting from JACK
And JACK1 (0.124.1, Debian Jessie) logging something like:
Oct 11 06:43:42 Paging-Test6 jackd1-paging[801]: timeout waiting for client paging.812 to handle a port registered event
Oct 11 06:43:42 Paging-Test6 jackd1-paging[801]: cannot send port registration notification to paging.812 (No such file or directory)
This seem to be 100% reproducible in these kinda-specific conditions - i.e. when it's same port name being registered for the second time during client lifetime - no other calls to that callback seem to trigger it.
Can be easily reproduced with that particular app (before it was fixed not to call stuff from callbacks) by running alsa_out, closing it, then running it again - client drops with above symptoms.
Also, all connect()
/ disconnect()
calls from within that callback seem to raise JackError, while actually creating/removing connections, for any ports.
So I wonder, is it expected (e.g. "calling stuff from callbacks is obviously bad!") or sensible behavior?
And if it is, maybe it should be documented under set_port_registration_callback?
I.e. something like "calling other libjack functions here may lead to unexpected behavior like deadlocks or client timeouts" there.
If so, I can probably create a PR, but given relative lack of JACK/client knowledge, I suspect I might not be best at describing what exactly should be avoided here.
First of all, thanks for this package! Helps a lot with neatly automating my setup :)
I was wondering if Jack's metadata API can be used through jackclient-python?
I couldn't find any references to it in the the current code, so maybe some work needs to be done to enable it? If so, what would that be? Maybe I can be of help.
When I try to run your example script thru_client.py with python2.7 (linux, ubuntu 14.10), I get:
$ python thru_client.py
Press Ctrl+C to stop
From callback <function callback_wrapper at 0xb6f0aa3c>:
Trying to convert the result back to C:
TypeError: an integer is required
Any idea what's wrong?
My versions of dependencies:
JACK-Client==0.3.0
cffi==0.8.2
Hi and thanks for the great library, been using it for years!
What's the best way to detect if the last process callback lead to an xrun? Here's my use case: I'm sending MIDI, which works 99% of the time. But when an xrun occurs, the MIDI events aren't sent to connected inputs and on the next process callback I clear the buffer and they're lost forever. Here's how I'm currently doing it:
jack_midi_event_write = jack._lib.jack_midi_event_write
jack_port_get_buffer = jack._lib.jack_port_get_buffer
class Process:
__slots__ = ('_before', '_buffer', '_client', '_port', '_xrun')
def __init__(self, client: jack.Client, port: jack.OwnMidiPort) -> None:
self._before = 0;
self._buffer = jack.RingBuffer(2 ** 8)
self._xrun = threading.Event()
self._client = client
self._port = port
def process(self, frames: int) -> None:
xrun = self._xrun
xrun_set = xrun.is_set()
port = self._port
client = port._client
last_frame_time = client.last_frame_time
blocksize = client.blocksize
if not xrun_set and last_frame_time - blocksize == self._before:
port.clear_buffer()
if xrun_set:
xrun.clear()
self._before = last_frame_time
src_buffer = self._buffer
space = src_buffer.read_space
if space != 0:
data = src_buffer.read(space)
dst_buffer = jack_port_get_buffer(port._ptr, blocksize)
i = 0
while i != space:
jack_midi_event_write(dst_buffer, 0, data[i : i + 3], 3)
i += 3
def handle_xrun(self, delay_usec: float) -> None:
self._xrun.set()
def _append(self, event: Tuple[int, int, int]) -> None:
self._buffer.write(bytes(event))
def note_on(self, note: int) -> None:
self._append((0x99, note, 100))
def note_off(self, note: int) -> None:
self._append((0x89, note, 0))
I'm doing two things:
I'm comparing last_frame_time - blocksize
to the last_frame_time
on the previous process callback.
Using the set_xrun_callback
to set a threading.Event()
I'm not sure if I'm doing any of this correctly, just experimenting to see what works. I know you're not meant to use Python for realtime, but it's working too well to justify moving to C++.
Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.