/* * Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) * Copyright (c) 2012-2021 libpd team * * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. * * See https://github.com/libpd/libpd/wiki for documentation * */ #ifndef __Z_LIBPD_H__ #define __Z_LIBPD_H__ #ifdef __cplusplus extern "C" { #endif #include "m_pd.h" /* initializing pd */ /// initialize libpd; it is safe to call this more than once /// returns 0 on success or -1 if libpd was already initialized /// note: sets SIGFPE handler to keep bad pd patches from crashing due to divide /// by 0, set any custom handling after calling this function EXTERN int libpd_init(void); /// clear the libpd search path for abstractions and externals /// note: this is called by libpd_init() EXTERN void libpd_clear_search_path(void); /// add a path to the libpd search paths /// relative paths are relative to the current working directory /// unlike desktop pd, *no* search paths are set by default (ie. extra) EXTERN void libpd_add_to_search_path(const char *path); /* opening patches */ /// open a patch by filename and parent dir path /// returns an opaque patch handle pointer or NULL on failure EXTERN void *libpd_openfile(const char *name, const char *dir); /// close a patch by patch handle pointer EXTERN void libpd_closefile(void *p); /// get the $0 id of the patch handle pointer /// returns $0 value or 0 if the patch is non-existent EXTERN int libpd_getdollarzero(void *p); /* audio processing */ /// return pd's fixed block size: the number of sample frames per 1 pd tick EXTERN int libpd_blocksize(void); /// initialize audio rendering /// returns 0 on success EXTERN int libpd_init_audio(int inChannels, int outChannels, int sampleRate); /// process interleaved float samples from inBuffer -> libpd -> outBuffer /// buffer sizes are based on # of ticks and channels where: /// size = ticks * libpd_blocksize() * (in/out)channels /// returns 0 on success EXTERN int libpd_process_float(const int ticks, const float *inBuffer, float *outBuffer); /// process interleaved short samples from inBuffer -> libpd -> outBuffer /// buffer sizes are based on # of ticks and channels where: /// size = ticks * libpd_blocksize() * (in/out)channels /// float samples are converted to short by multiplying by 32767 and casting, /// so any values received from pd patches beyond -1 to 1 will result in garbage /// note: for efficiency, does *not* clip input /// returns 0 on success EXTERN int libpd_process_short(const int ticks, const short *inBuffer, short *outBuffer); /// process interleaved double samples from inBuffer -> libpd -> outBuffer /// buffer sizes are based on # of ticks and channels where: /// size = ticks * libpd_blocksize() * (in/out)channels /// note: only full-precision when compiled with PD_FLOATSIZE=64 /// returns 0 on success EXTERN int libpd_process_double(const int ticks, const double *inBuffer, double *outBuffer); /// process non-interleaved float samples from inBuffer -> libpd -> outBuffer /// copies buffer contents to/from libpd without striping /// buffer sizes are based on a single tick and # of channels where: /// size = libpd_blocksize() * (in/out)channels /// returns 0 on success EXTERN int libpd_process_raw(const float *inBuffer, float *outBuffer); /// process non-interleaved short samples from inBuffer -> libpd -> outBuffer /// copies buffer contents to/from libpd without striping /// buffer sizes are based on a single tick and # of channels where: /// size = libpd_blocksize() * (in/out)channels /// float samples are converted to short by multiplying by 32767 and casting, /// so any values received from pd patches beyond -1 to 1 will result in garbage /// note: for efficiency, does *not* clip input /// returns 0 on success EXTERN int libpd_process_raw_short(const short *inBuffer, short *outBuffer); /// process non-interleaved double samples from inBuffer -> libpd -> outBuffer /// copies buffer contents to/from libpd without striping /// buffer sizes are based on a single tick and # of channels where: /// size = libpd_blocksize() * (in/out)channels /// note: only full-precision when compiled with PD_FLOATSIZE=64 /// returns 0 on success EXTERN int libpd_process_raw_double(const double *inBuffer, double *outBuffer); /* array access */ /// get the size of an array by name /// returns size or negative error code if non-existent EXTERN int libpd_arraysize(const char *name); /// (re)size an array by name; sizes <= 0 are clipped to 1 /// returns 0 on success or negative error code if non-existent EXTERN int libpd_resize_array(const char *name, long size); /// read n values from named src array and write into dest starting at an offset /// note: performs no bounds checking on dest /// returns 0 on success or a negative error code if the array is non-existent /// or offset + n exceeds range of array EXTERN int libpd_read_array(float *dest, const char *name, int offset, int n); /// read n values from src and write into named dest array starting at an offset /// note: performs no bounds checking on src /// returns 0 on success or a negative error code if the array is non-existent /// or offset + n exceeds range of array EXTERN int libpd_write_array(const char *name, int offset, const float *src, int n); /// read n values from named src array and write into dest starting at an offset /// note: performs no bounds checking on dest /// note: only full-precision when compiled with PD_FLOATSIZE=64 /// returns 0 on success or a negative error code if the array is non-existent /// or offset + n exceeds range of array /// double-precision variant of libpd_read_array() EXTERN int libpd_read_array_double(double *dest, const char *src, int offset, int n); /// read n values from src and write into named dest array starting at an offset /// note: performs no bounds checking on src /// note: only full-precision when compiled with PD_FLOATSIZE=64 /// returns 0 on success or a negative error code if the array is non-existent /// or offset + n exceeds range of array /// double-precision variant of libpd_write_array() EXTERN int libpd_write_array_double(const char *dest, int offset, const double *src, int n); /* sending messages to pd */ /// send a bang to a destination receiver /// ex: libpd_bang("foo") will send a bang to [s foo] on the next tick /// returns 0 on success or -1 if receiver name is non-existent EXTERN int libpd_bang(const char *recv); /// send a float to a destination receiver /// ex: libpd_float("foo", 1) will send a 1.0 to [s foo] on the next tick /// returns 0 on success or -1 if receiver name is non-existent EXTERN int libpd_float(const char *recv, float x); /// send a double to a destination receiver /// ex: libpd_double("foo", 1.1) will send a 1.1 to [s foo] on the next tick /// note: only full-precision when compiled with PD_FLOATSIZE=64 /// returns 0 on success or -1 if receiver name is non-existent EXTERN int libpd_double(const char *recv, double x); /// send a symbol to a destination receiver /// ex: libpd_symbol("foo", "bar") will send "bar" to [s foo] on the next tick /// returns 0 on success or -1 if receiver name is non-existent EXTERN int libpd_symbol(const char *recv, const char *symbol); /* sending compound messages: sequenced function calls */ /// start composition of a new list or typed message of up to max element length /// messages can be of a smaller length as max length is only an upper bound /// note: no cleanup is required for unfinished messages /// returns 0 on success or nonzero if the length is too large EXTERN int libpd_start_message(int maxlen); /// add a float to the current message in progress EXTERN void libpd_add_float(float x); /// add a double to the current message in progress /// note: only full-precision when compiled with PD_FLOATSIZE=64 EXTERN void libpd_add_double(double x); /// add a symbol to the current message in progress EXTERN void libpd_add_symbol(const char *symbol); /// finish current message and send as a list to a destination receiver /// returns 0 on success or -1 if receiver name is non-existent /// ex: send [list 1 2 bar( to [s foo] on the next tick with: /// libpd_start_message(3); /// libpd_add_float(1); /// libpd_add_float(2); /// libpd_add_symbol("bar"); /// libpd_finish_list("foo"); EXTERN int libpd_finish_list(const char *recv); /// finish current message and send as a typed message to a destination receiver /// note: typed message handling currently only supports up to 4 elements /// internally, additional elements may be ignored /// returns 0 on success or -1 if receiver name is non-existent /// ex: send [; pd dsp 1( on the next tick with: /// libpd_start_message(1); /// libpd_add_float(1); /// libpd_finish_message("pd", "dsp"); EXTERN int libpd_finish_message(const char *recv, const char *msg); /* sending compound messages: atom array */ /// write a float value to the given atom EXTERN void libpd_set_float(t_atom *a, float x); /// write a double value to the given atom /// note: only full-precision when compiled with PD_FLOATSIZE=64 EXTERN void libpd_set_double(t_atom *v, double x); /// write a symbol value to the given atom EXTERN void libpd_set_symbol(t_atom *a, const char *symbol); /// send an atom array of a given length as a list to a destination receiver /// returns 0 on success or -1 if receiver name is non-existent /// ex: send [list 1 2 bar( to [r foo] on the next tick with: /// t_atom v[3]; /// libpd_set_float(v, 1); /// libpd_set_float(v + 1, 2); /// libpd_set_symbol(v + 2, "bar"); /// libpd_list("foo", 3, v); EXTERN int libpd_list(const char *recv, int argc, t_atom *argv); /// send a atom array of a given length as a typed message to a destination /// receiver, returns 0 on success or -1 if receiver name is non-existent /// ex: send [; pd dsp 1( on the next tick with: /// t_atom v[1]; /// libpd_set_float(v, 1); /// libpd_message("pd", "dsp", 1, v); EXTERN int libpd_message(const char *recv, const char *msg, int argc, t_atom *argv); /* receiving messages from pd */ /// subscribe to messages sent to a source receiver /// ex: libpd_bind("foo") adds a "virtual" [r foo] which forwards messages to /// the libpd message hooks /// returns an opaque receiver pointer or NULL on failure EXTERN void *libpd_bind(const char *recv); /// unsubscribe and free a source receiver object created by libpd_bind() EXTERN void libpd_unbind(void *p); /// check if a source receiver object exists with a given name /// returns 1 if the receiver exists, otherwise 0 EXTERN int libpd_exists(const char *recv); /// print receive hook signature, s is the string to be printed /// note: default behavior returns individual words and spaces: /// line "hello 123" is received in 4 parts -> "hello", " ", "123\n" typedef void (*t_libpd_printhook)(const char *s); /// bang receive hook signature, recv is the source receiver name typedef void (*t_libpd_banghook)(const char *recv); /// float receive hook signature, recv is the source receiver name typedef void (*t_libpd_floathook)(const char *recv, float x); /// double receive hook signature, recv is the source receiver name /// note: only full-precision when compiled with PD_FLOATSIZE=64 typedef void (*t_libpd_doublehook)(const char *recv, double x); /// symbol receive hook signature, recv is the source receiver name typedef void (*t_libpd_symbolhook)(const char *recv, const char *symbol); /// list receive hook signature, recv is the source receiver name /// argc is the list length and vector argv contains the list elements /// which can be accessed using the atom accessor functions, ex: /// int i; /// for (i = 0; i < argc; i++) { /// t_atom *a = &argv[n]; /// if (libpd_is_float(a)) { /// float x = libpd_get_float(a); /// // do something with float x /// } else if (libpd_is_symbol(a)) { /// char *s = libpd_get_symbol(a); /// // do something with c string s /// } /// } /// note: check for both float and symbol types as atom may also be a pointer typedef void (*t_libpd_listhook)(const char *recv, int argc, t_atom *argv); /// typed message hook signature, recv is the source receiver name and msg is /// the typed message name: a message like [; foo bar 1 2 a b( will trigger a /// function call like libpd_messagehook("foo", "bar", 4, argv) /// argc is the list length and vector argv contains the /// list elements which can be accessed using the atom accessor functions, ex: /// int i; /// for (i = 0; i < argc; i++) { /// t_atom *a = &argv[n]; /// if (libpd_is_float(a)) { /// float x = libpd_get_float(a); /// // do something with float x /// } else if (libpd_is_symbol(a)) { /// char *s = libpd_get_symbol(a); /// // do something with c string s /// } /// } /// note: check for both float and symbol types as atom may also be a pointer typedef void (*t_libpd_messagehook)(const char *recv, const char *msg, int argc, t_atom *argv); /// set the print receiver hook, prints to stdout by default /// note: do not call this while DSP is running EXTERN void libpd_set_printhook(const t_libpd_printhook hook); /// set the bang receiver hook, NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_banghook(const t_libpd_banghook hook); /// set the float receiver hook, NULL by default /// note: avoid calling this while DSP is running /// note: you can either have a float receiver hook, or a double receiver /// hook (see below), but not both. /// calling this, will automatically unset the double receiver hook /// note: only full-precision when compiled with PD_FLOATSIZE=64 EXTERN void libpd_set_floathook(const t_libpd_floathook hook); /// set the double receiver hook, NULL by default /// note: avoid calling this while DSP is running /// note: you can either have a double receiver hook, or a float receiver /// hook (see above), but not both. /// calling this, will automatically unset the float receiver hook /// note: only full-precision when compiled with PD_FLOATSIZE=64 EXTERN void libpd_set_doublehook(const t_libpd_doublehook hook); /// set the symbol receiver hook, NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_symbolhook(const t_libpd_symbolhook hook); /// set the list receiver hook, NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_listhook(const t_libpd_listhook hook); /// set the message receiver hook, NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_messagehook(const t_libpd_messagehook hook); /// check if an atom is a float type: 0 or 1 /// note: no NULL check is performed EXTERN int libpd_is_float(t_atom *a); /// check if an atom is a symbol type: 0 or 1 /// note: no NULL check is performed EXTERN int libpd_is_symbol(t_atom *a); /// get the float value of an atom /// note: no NULL or type checks are performed EXTERN float libpd_get_float(t_atom *a); /// returns the double value of an atom /// note: no NULL or type checks are performed /// note: only full-precision when compiled with PD_FLOATSIZE=64 EXTERN double libpd_get_double(t_atom *a); /// returns the symbol value of an atom /// note: no NULL or type checks are performed EXTERN const char *libpd_get_symbol(t_atom *a); /// increment to the next atom in an atom vector /// returns next atom or NULL, assuming the atom vector is NULL-terminated EXTERN t_atom *libpd_next_atom(t_atom *a); /* sending MIDI messages to pd */ /// send a MIDI note on message to [notein] objects /// channel is 0-indexed, pitch is 0-127, and velocity is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: there is no note off message, send a note on with velocity = 0 instead /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_noteon(int channel, int pitch, int velocity); /// send a MIDI control change message to [ctlin] objects /// channel is 0-indexed, controller is 0-127, and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_controlchange(int channel, int controller, int value); /// send a MIDI program change message to [pgmin] objects /// channel is 0-indexed and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_programchange(int channel, int value); /// send a MIDI pitch bend message to [bendin] objects /// channel is 0-indexed and value is -8192-8192 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: [bendin] outputs 0-16383 while [bendout] accepts -8192-8192 /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_pitchbend(int channel, int value); /// send a MIDI after touch message to [touchin] objects /// channel is 0-indexed and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_aftertouch(int channel, int value); /// send a MIDI poly after touch message to [polytouchin] objects /// channel is 0-indexed, pitch is 0-127, and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_polyaftertouch(int channel, int pitch, int value); /// send a raw MIDI byte to [midiin] objects /// port is 0-indexed and byte is 0-256 /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_midibyte(int port, int byte); /// send a raw MIDI byte to [sysexin] objects /// port is 0-indexed and byte is 0-256 /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_sysex(int port, int byte); /// send a raw MIDI byte to [realtimein] objects /// port is 0-indexed and byte is 0-256 /// returns 0 on success or -1 if an argument is out of range EXTERN int libpd_sysrealtime(int port, int byte); /* receiving MIDI messages from pd */ /// MIDI note on receive hook signature /// channel is 0-indexed, pitch is 0-127, and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: there is no note off message, note on w/ velocity = 0 is used instead /// note: out of range values from pd are clamped typedef void (*t_libpd_noteonhook)(int channel, int pitch, int velocity); /// MIDI control change receive hook signature /// channel is 0-indexed, controller is 0-127, and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: out of range values from pd are clamped typedef void (*t_libpd_controlchangehook)(int channel, int controller, int value); /// MIDI program change receive hook signature /// channel is 0-indexed and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: out of range values from pd are clamped typedef void (*t_libpd_programchangehook)(int channel, int value); /// MIDI pitch bend receive hook signature /// channel is 0-indexed and value is -8192-8192 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: [bendin] outputs 0-16383 while [bendout] accepts -8192-8192 /// note: out of range values from pd are clamped typedef void (*t_libpd_pitchbendhook)(int channel, int value); /// MIDI after touch receive hook signature /// channel is 0-indexed and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: out of range values from pd are clamped typedef void (*t_libpd_aftertouchhook)(int channel, int value); /// MIDI poly after touch receive hook signature /// channel is 0-indexed, pitch is 0-127, and value is 0-127 /// channels encode MIDI ports via: libpd_channel = pd_channel + 16 * pd_port /// note: out of range values from pd are clamped typedef void (*t_libpd_polyaftertouchhook)(int channel, int pitch, int value); /// raw MIDI byte receive hook signature /// port is 0-indexed and byte is 0-256 /// note: out of range values from pd are clamped typedef void (*t_libpd_midibytehook)(int port, int byte); /// set the MIDI note on hook to receive from [noteout] objects, NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_noteonhook(const t_libpd_noteonhook hook); /// set the MIDI control change hook to receive from [ctlout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_controlchangehook(const t_libpd_controlchangehook hook); /// set the MIDI program change hook to receive from [pgmout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_programchangehook(const t_libpd_programchangehook hook); /// set the MIDI pitch bend hook to receive from [bendout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_pitchbendhook(const t_libpd_pitchbendhook hook); /// set the MIDI after touch hook to receive from [touchout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_aftertouchhook(const t_libpd_aftertouchhook hook); /// set the MIDI poly after touch hook to receive from [polytouchout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); /// set the raw MIDI byte hook to receive from [midiout] objects, /// NULL by default /// note: do not call this while DSP is running EXTERN void libpd_set_midibytehook(const t_libpd_midibytehook hook); /* GUI */ /// open the current patches within a pd vanilla GUI /// requires the path to pd's main folder that contains bin/, tcl/, etc /// for a macOS .app bundle: /path/to/Pd-#.#-#.app/Contents/Resources /// returns 0 on success EXTERN int libpd_start_gui(const char *path); /// stop the pd vanilla GUI EXTERN void libpd_stop_gui(void); /// manually update and handle any GUI messages /// this is called automatically when using a libpd_process function, /// note: this also facilitates network message processing, etc so it can be /// useful to call repeatedly when idle for more throughput /// returns 1 if the poll found something, in which case it might be desirable /// to poll again, up to some reasonable limit EXTERN int libpd_poll_gui(void); /* multiple instances */ /// create a new pd instance and set as current /// note: use this in place of pdinstance_new() /// returns new instance or NULL when libpd is compiled without PDINSTANCE EXTERN t_pdinstance *libpd_new_instance(void); /// set the current pd instance /// subsequent libpd calls will affect this instance only /// note: use this in place of pd_setinstance() /// does nothing when libpd is compiled without PDINSTANCE EXTERN void libpd_set_instance(t_pdinstance *pd); /// free a pd instance and set main instance as current /// note: use this in place of pdinstance_free() /// does nothing when libpd is compiled without PDINSTANCE EXTERN void libpd_free_instance(t_pdinstance *pd); /// get the current pd instance EXTERN t_pdinstance *libpd_this_instance(void); /// get the main pd instance, always valid EXTERN t_pdinstance *libpd_main_instance(void); /// get the number of pd instances, including the main instance /// returns number or 1 when libpd is compiled without PDINSTANCE EXTERN int libpd_num_instances(void); /// per-instance data free hook signature typedef void (*t_libpd_freehook)(void *data); /// set per-instance user data and optional free hook /// note: if non-NULL, freehook is called by libpd_free_instance() EXTERN void libpd_set_instancedata(void *data, t_libpd_freehook freehook); /// get per-instance user data EXTERN void* libpd_get_instancedata(void); /* log level */ /// set verbose print state: 0 or 1 EXTERN void libpd_set_verbose(int verbose); /// get the verbose print state: 0 or 1 EXTERN int libpd_get_verbose(void); #ifdef __cplusplus } #endif #endif