You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It would be nice with an example program that demonstrates in the simplest way possible to record and play audio. Like the thru_client.py, but with record/playback implemented.
This is how far I got with my limited understanding of both numpy and the python JACK client.
EDIT: This updated example actually seems to work. Is this in your opinion how this should be done? If so, it could be very helpful for newcomers to have it on the project page along with the other examples.
#!/usr/bin/env python3"""Create a JACK client that records input audio and plays it back through the outputs."""importsysimportosimportjackimportnumpyimportthreadingargv=iter(sys.argv)
# By default, use script name without extension as client name:defaultclientname=os.path.splitext(os.path.basename(next(argv)))[0]
clientname=next(argv, defaultclientname)
servername=next(argv, None)
client=jack.Client(clientname, servername=servername)
ifclient.status.server_started:
print('JACK server started')
ifclient.status.name_not_unique:
print(f'unique name {client.name!r} assigned')
input_data=numpy.empty(client.blocksize, dtype='float32') # For storing the recorded audiorecording_duration=5.0# Record audio for 5 secondsplayback_position=0# For tracking the current playback position in framesevent=threading.Event()
@client.set_process_callbackdefprocess(frames):
globalinput_dataglobalplayback_positionassertlen(client.inports) ==len(client.outports)
assertframes==client.blocksize# If the recorded audio data is less that 5 seconds,# keep adding the input buffer data to itiflen(input_data) <recording_duration*client.samplerate:
mono_sample=numpy.zeros(frames, dtype='float32')
foriinclient.inports:
mono_sample=numpy.add(mono_sample, i.get_array())
input_data=numpy.append(input_data, mono_sample)
# If the recording is complete and the playback position isn't yet at the end,# keep adding the recorded data to the output bufferelifplayback_position+frames<len(input_data):
foroinclient.outports:
o.get_buffer()[:] =input_data[playback_position:playback_position+frames]
playback_position+=frames@client.set_shutdown_callbackdefshutdown(status, reason):
print('JACK shutdown!')
print('status:', status)
print('reason:', reason)
event.set()
# create two port pairsfornumberin1, 2:
client.inports.register(f'input_{number}')
client.outports.register(f'output_{number}')
withclient:
# When entering this with-statement, client.activate() is called.# This tells the JACK server that we are ready to roll.# Our process() callback will start running now.# Connect the ports. You can't do this before the client is activated,# because we can't make connections to clients that aren't running.# Note the confusing (but necessary) orientation of the driver backend# ports: playback ports are "input" to the backend, and capture ports# are "output" from it.capture=client.get_ports(is_physical=True, is_output=True)
ifnotcapture:
raiseRuntimeError('No physical capture ports')
forsrc, destinzip(capture, client.inports):
client.connect(src, dest)
playback=client.get_ports(is_physical=True, is_input=True)
ifnotplayback:
raiseRuntimeError('No physical playback ports')
forsrc, destinzip(client.outports, playback):
client.connect(src, dest)
print('Press Ctrl+C to stop')
try:
event.wait()
exceptKeyboardInterrupt:
print('\nInterrupted by user')
# When the above with-statement is left (either because the end of the# code block is reached, or because an exception was raised inside),# client.deactivate() and client.close() are called automatically.
The text was updated successfully, but these errors were encountered:
There is only one thing really wrong with your code: you should always write to the output buffer(s). If you don't have anything to write to them, write zeros. I just tried your code (on Linux) and it worked as expected until playback was finished, but then the last block was repeated indefinitely (because I guess the buffer was simply re-used and still contained the signal of the last block).
The annoying thing is that on other systems (and maybe on your system) it might just work, because the last block might not be re-used for some reason.
Other than that, it really depends on your assumptions for this example and what use case you want to illustrate with it.
If the duration of the recording is actually known in advance, it might make more sense to create a buffer of the full length and then write to it (instead of repeatedly using append()).
However, we might want to pretend that the recording duration is not yet known when starting the recording?
In this case there is still the question whether we only want to use entire blocks of audio.
Because if yes, it might make more sense to store the blocks in a list (or maybe a collections.deque) of NumPy arrays?
I think the whole playback_position thing would only make sense if we would allow the signal to start/stop mid-block.
If you want to add this as an "official" example, feel free to create a PR with it, then we can discuss further details about it.
It would be nice with an example program that demonstrates in the simplest way possible to record and play audio. Like the
thru_client.py
, but with record/playback implemented.This is how far I got with my limited understanding of both numpy and the python JACK client.
EDIT: This updated example actually seems to work. Is this in your opinion how this should be done? If so, it could be very helpful for newcomers to have it on the project page along with the other examples.
The text was updated successfully, but these errors were encountered: