Skip to content

martin-stone/ctpatch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ctpatch.py

In Python, read, modify and write .syx patch files for the Novation Circuit Tracks.

Requires Python version >= 3.10

See example.py for an example of reading, modifying, and writing patches, and sending patches to the device.

The Python type annotations make editor autocomplete quite effective, but you can also see the structure of the loaded patch object with Python's "pretty print"...

import ctpatch
from pprint import pprint

patch = ctpatch.read_syx("example.syx")
pprint(patch)

This produces the following output ...

PatchSysex(header=Header(sysex=240,
                         mfr_id=b'\x00 )',
                         prod_type=1,
                         prod_num=100),
           command=ReplaceCurrentPatchCommand(command_id=0,       
                                              location=0,
                                              _reserved=0),       
           meta=Meta(_name=b'saw dst         ',
                     category=2,
                     genre=0,
                     _reserved=b'\x00\x00\x00\x00\x00\x00\x00\x00'
                               b'\x00\x00\x00\x00\x00\x00'),      
           voice=Voice(polyphony_mode=<PolyphonyMode.MONO_AG: 1>, 
                       portamento_rate=0,
                       pre_glide=64,
                       keyboard_octave=62),
           oscillators=[Osc(wave=<OscWaveform.SAWTOOTH: 2>,       
                            wave_interpolate=127,
                            pulse_width_index=0,
                            virtual_sync_depth=0,
                            density=0,
                            density_detune=0,
                            semitones=64,
                            cents=64,
                            pitch_bend=76),
                        Osc(wave=<OscWaveform.SAWTOOTH: 2>,       
                            wave_interpolate=127,
                            pulse_width_index=64,
                            virtual_sync_depth=0,
                            density=0,
                            density_detune=0,
                            semitones=64,
                            cents=64,
                            pitch_bend=76)],
           mixer=Mixer(osc1_level=127,
                       osc2_level=0,
                       ring_mod_level12=0,
                       noise_level=0,
                       pre_fx_level=64,
                       post_fx_level=64),
           filter=Filter(routing=0,
                         drive=0,
                         drive_type=<DistortionType.DIODE: 0>,
                         type=<FilterType.LOW_PASS_24DB: 1>,
                         frequency=38,
                         track=0,
                         resonance=0,
                         q_normalise=64,
                         env2_to_freq=64),
           envelopes=[Envelope(velocity_or_delay=92,
                               attack=0,
                               decay=93,
                               sustain=0,
                               release=40),
                      Envelope(velocity_or_delay=64,
                               attack=0,
                               decay=57,
                               sustain=0,
                               release=45),
                      Envelope(velocity_or_delay=0,
                               attack=10,
                               decay=70,
                               sustain=64,
                               release=40)],
           lfos=[Lfo(waveform=<LfoWaveform.TRIANGLE: 1>,
                     phase_offset=0,
                     slew_rate=0,
                     delay=0,
                     delay_sync=0,
                     rate=0,
                     rate_sync=0,
                     flags=LfoFlags(one_shot=0, key_sync=0, common_sync=0, delay_trigger=0, fade_mode=0)),
                 Lfo(waveform=<LfoWaveform.SINE: 0>,
                     phase_offset=0,
                     slew_rate=0,
                     delay=0,
                     delay_sync=0,
                     rate=68,
                     rate_sync=0,
                     flags=LfoFlags(one_shot=0, key_sync=0, common_sync=0, delay_trigger=0, fade_mode=0))],
           fx=Fx(distortion_level=0,
                 _fx_reserved1=0,
                 chorus_level=0,
                 _fx_reserved2=0,
                 _fx_reserved3=0,
                 equaliser_bass_frequency=64,
                 equaliser_bass_level=64,
                 equaliser_mid_frequency=64,
                 equaliser_mid_level=64,
                 equaliser_treble_frequency=125,
                 equaliser_treble_level=64,
                 _fx_reserved45678=b'\x00\x00\x00\x00\x00',
                 distortion_type=<DistortionType.DIODE: 0>,
                 distortion_compensation=100,
                 chorus_type=1,
                 chorus_rate=20,
                 chorus_rate_sync=0,
                 chorus_feedback=74,
                 chorus_mod_depth=64,
                 chorus_delay=64),
           mod_matrix=[ModMatrix(source1=<ModMatrixSource.LFO_1_PLUS: 6>,
                                 source2=<ModMatrixSource.DIRECT: 0>,
                                 depth=64,
                                 destination=<ModMatrixDestination.FILTER_FREQUENCY: 12>),
                       ModMatrix(source1=<ModMatrixSource.VELOCITY: 4>,
                                 source2=<ModMatrixSource.DIRECT: 0>,
                                 depth=78,
                                 destination=<ModMatrixDestination.FILTER_RESONANCE: 13>),

                        ...etc. 
                        ],
           macro_knobs=[MacroKnob(position=0,
                                  ranges=[MacroKnobRange(destination=<MacroKnobDestination.LFO1_RATE: 39>,
                                                         start_pos=0,
                                                         end_pos=127,
                                                         depth=127),
                                          MacroKnobRange(destination=<MacroKnobDestination.NO_DESTINATION: 0>,
                                                         start_pos=0,
                                                         end_pos=127,
                                                         depth=64),

                        ...etc. 
                    ],
           footer=Footer(eox=247))

About

Python module for reading, updating and writing Novation Circuit Tracks patches

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages