Skip to content

Example program for playing audio data from memory? #119

Description

@mrzapp

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions