pyCarla¶
A python module for synthesizing MIDI events and files from python code using any kind of audio plugin!
A python module based on carla
and jack
!
Installation¶
The backbone of this project are the multiple dependencies on which it depends. Since it’s difficult to provide a script to automatically install all of these dependencies, here is a little handbook about how to install them.
TLDR¶
Use Linux: it’s free. For Windows and Mac, you can still install Carla and Jack by yourself; however, I refuse to support non-free software.
In general, use https://pkgs.org to look for the command needed in your distro.
Install:
jackd
1.9Make sure that it is available in your
PATH
environment variable
1. Installing pycarla¶
pip install --upgrade pip pycarla
2. Installing jack¶
Ubuntu/Debian based:
sudo apt-get install jackd2
Arch based:
sudo pacman -Sy jack2
Gentoo based:
sudo emerge -a media-sound/jack2
Fedora based:
sudo dnf install jack-audio-connection-kit
For other Os, pre-built binaries are available at https://jackaudio.org/downloads/
3. Installing Carla¶
After having installed the package, run python -m pycarla.carla --download
to download the correct version of Carla.
If you’re not in Linux, pre-built binaries for major OS available at https://github.com/falkTX/Carla/releases/latest
N.B. Configure Carla in `patchbay` mode (if you cannot use GUI, set `ProcessMode=3` into `~/.config/falkTX/Carla2.conf`)
To set patchbay mode in the GUI: settings -> Engine -> Process mode -> Patchbay -> Ok
Development setup¶
The next steps are only needed for contributing to this project. Do not follow them if you only want to use `pycarla`
Install poetry:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
Enter root directory of this project
poetry update
Put all the Carla configurations that you want to use in
data/carla_proj
Note that you can use the default ones, provided you have the same plugins available, otherwise you have to delete the default project files.
- Tested plugins are:
Pianoteq
Calf Reverb
Run
poetry run python -m pycarla <a_midi_file.mid>
to do a little test
Usage¶
Carla presets¶
Configure Carla in ``patchbay`` mode (if you cannot use GUI, set ``ProcessMode=3`` into ``~/.config/falkTX/Carla2.conf``)
python -m pycarla.carla --run
to launch Carla and prepare configurations
Initialization¶
from pycarla import Carla, MIDIPlayer, AudioRecorder, get_smf_duration
carla = Carla("carla_project.carxp", ['-R', '-d', 'alsa'], min_wait=4)
carla.start()
player = MIDIPlayer()
recorder = AudioRecorder()
# or
with MIDIPlayer() as player, AudioRecorder() as recorder:
# [...]
pass
Playing and recording one note¶
print("Playing and recording one note..")
duration = 2
pitch = 64
recorder.start(duration + FINAL_DECAY)
player.synthesize_midi_note(pitch, 64, duration, 0, sync=True)
recorder.wait()
audio = recorder.recorded
if not np.any(audio):
print("Error, no sample != 0")
carla.kill() # this kills both Carla and Jack
# carla.kill_carla() # this kills Carla but not Jack
sys.exit()
Playing and recording a full MIDI file¶
print("Playing and recording full file using freewheeling mode..")
duration = get_smf_duration("filename.mid")
# in the following, `condition` ensures that both the recorder and player
# start in the same cycle
recorder.start(duration + FINAL_DECAY, condition=player.is_ready)
player.synthesize_midi_file("filename.mid",
condition=recorder.is_ready, in_fw=True, out_fw=True)
# or asynchronously:
# player.synthesize_midi_file("filename.mid", sync=False)
# in this case, use
# player.wait(in_fw=True, out_fw=True)
recorder.wait(in_fw=True, out_fw=True)
recorder.save_recorded("session.wav")
player.close()
server.close()
In future, there shold be a function that does this snippet for you
You can also use AudioRecorder
and MIDIPlayer
as context managers in a
with
block; in this case, skip the close() at the end:
with pycarla.AudioRecorder() as recorder, pycarla.MIDIPlayer() as player:
# do your stuffs
pass
Closing server¶
try:
carla.kill()
except Exception as e:
print("Processes already closed!")
Classes and functions¶
Carla¶
- class pycarla.carla.Carla(proj_path: str, server_options: List[str] = [], min_wait: float = 0, nogui: bool = True)[source]¶
- __make_carla_popen(proj_path)¶
- exists(ports=['Carla:events*', 'Carla:audio*'])[source]¶
simply checks if the Carla process is running and ports are available
- ports is a list of string name representing Jack ports; you can use
‘*’, ‘?’ etc.
- Returns
bool – running, false otherwise
- Return type
True if all ports in ports exist and the Carla process is
Jack Server¶
Playing MIDI¶
- class pycarla.midiplayer.MIDIPlayer[source]¶
- MIDI_PORT = 'Carla'¶
- activate()[source]¶
Activate the MIDI player client and set the connections.
If the Carla instance is not found, this method rase a RuntimeWarning. To avoid it, use
Carla.exists
method. Note thatCarla.start
already does that!
- synthesize_messages(messages: ~typing.List[mido.Message], sync=False, condition=<function MIDIPlayer.<lambda>>, **kwargs)[source]¶
Synthesize a list of messages
Connect the port of this jack client to Carla if not yet done
Send the list of messages to the Carla instance
If sync is True, this function waits until all messages have been processed, otherwise, it suddenly returns. You can wait by calling the wait method of this object.
This function is compatible with freewheeling mode. Freewheel prevents jack from waiting between return calls. This allows for the maximum allowed speed, but not output/input operation is done with system audio (i.e. you cannot listen/recording to anything while in freewheeling mode).
condition is a function checked in the playing callback. If condition() is False, no message is sent. The callback start playing at the cycle after the one in which condition() becomes True.
kwargs are passed to wait if sync is True.
Note: Mido numbers channels 0 to 15 instead of 1 to 16. This makes them easier to work with in Python but you may want to add and subtract 1 when communicating with the user.
- synthesize_midi_file(midifile: Any, **kwargs) Process [source]¶
Send midi messages contained in filename using self.synthesize_messages. All keywords from that method can be used here.
midifile can be a mido.MidiFile object or a string
After the playback, ports are resetted
- synthesize_midi_note(pitch: int, velocity: int, duration: float, sustain: int = 0, soft: int = 0, sostenuto: int = 0, channel: int = 0, program: int = 0, **kwargs) Process [source]¶
set up a list of messages representing one note and then calls self.synthesize_messages. All keywords from that method can be used here.
Recording Audio¶
- class pycarla.audiorecorder.AudioRecorder[source]¶
- AUDIO_PORT = 'Carla'¶
- activate()[source]¶
Activate the recording client and set the connections. Set self.channels and create one input port per each Carla output port.
If the Carla instance is not found, this method rase a RuntimeWarning. To avoid it, use
Carla.exists
method. Note thatCarla.start
already does that!
- save_recorded(filename)[source]¶
Save the recorded array to file. Extensions supported by
libsndfile
!start_frame is the frame from which recorded is saved (use it to discard initial delays due to Jack setup).
- start(duration=None, sync=False, condition=<function AudioRecorder.<lambda>>, **kwargs)[source]¶
Record audio for
duration
seconds. Note that this function blocks if sync is True, otherwise, this returns suddenly and you should wait/stop by calling the wait method of this object which constructs the recorded array in self.recordedcondition is a function checked in the recording callback. If condition() is False, blocks are discarded. The callback start recording at the cycle after the one in which condition() becomes True.
This function is compatible with Jack freewheeling mode to record offline sessions.
kwargs are passed to wait if sync is True.
- wait(timeout=None, in_fw=False, out_fw=False)[source]¶
Wait until recording is finished. If timeout is a number, it should be the maximum number of seconds until which the recording stops. A boolean is returned representing if timeout is reached. (returns False if timeout is not set)
The recording stops when timeout or the duration passed when calling start is reached. In these cases, the recording client is deactivated and the callback stopped.
waits while setting freewheeling mode to in_fw it then set freewheeling mode to out_fw before exiting
Why so many external dependencies?¶
Python has no strong real-time capabilities since it cannot run with parallel threads. This method delegates most of the realtime stuffs to external C/C++ programs, improving the performances and the accuracy against pure-Python based approaches. Namely, the synthesis and the management of plugins is delegated to Carla, while the MIDI messaging and audio recording is done in python using C Jack API.
This method is really portable and supports almost any type of plugins and virtual instruments thanks to the excellent Carla:
Linux VST2/VST3
Windows VST2/VST3
LV2
LADSPA
DSSI
AU
SF2/SF3
SFZ
Any other format supported by external plugins
Credits¶
- Federico Simonetta
federico.simonetta
at
unimi.it