|
- // Copyright 2021 Jean Pierre Cimalando
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- // SPDX-License-Identifier: Apache-2.0
- //
-
- #pragma once
- #if !defined(YSFX_INCLUDED_YSFX_H)
- #define YSFX_INCLUDED_YSFX_H
-
- #include <stdio.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdbool.h>
- #if defined(_WIN32)
- # include <wchar.h>
- #endif
-
- //------------------------------------------------------------------------------
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #if !defined(YSFX_API)
- # if defined(_WIN32) && defined(YSFX_DLL_BUILD)
- # define YSFX_API __declspec(dllexport)
- # elif defined(__GNUC__)
- # define YSFX_API __attribute__((visibility("default")))
- # else
- # define YSFX_API
- # endif
- #endif
-
- //------------------------------------------------------------------------------
- // YSFX definitions
-
- typedef double ysfx_real;
-
- enum {
- ysfx_max_sliders = 64,
- ysfx_max_channels = 64,
- ysfx_max_midi_buses = 16,
- ysfx_max_triggers = 10,
- };
-
- typedef enum ysfx_log_level_e {
- ysfx_log_info,
- ysfx_log_warning,
- ysfx_log_error,
- } ysfx_log_level;
-
- typedef void (ysfx_log_reporter_t)(intptr_t userdata, ysfx_log_level level, const char *message);
-
- //------------------------------------------------------------------------------
- // YSFX configuration
-
- typedef struct ysfx_config_s ysfx_config_t;
- typedef struct ysfx_audio_format_s ysfx_audio_format_t;
-
- // create a new configuration
- YSFX_API ysfx_config_t *ysfx_config_new();
- // delete a configuration
- YSFX_API void ysfx_config_free(ysfx_config_t *config);
- // increase the reference counter
- YSFX_API void ysfx_config_add_ref(ysfx_config_t *config);
- // set the path of the import root, a folder usually named "Effects"
- YSFX_API void ysfx_set_import_root(ysfx_config_t *config, const char *root);
- // set the path of the data root, a folder usually named "Data"
- YSFX_API void ysfx_set_data_root(ysfx_config_t *config, const char *root);
- // get the path of the import root, a folder usually named "Effects"
- YSFX_API const char *ysfx_get_import_root(ysfx_config_t *config);
- // get the path of the data root, a folder usually named "Data"
- YSFX_API const char *ysfx_get_data_root(ysfx_config_t *config);
- // guess the undefined root folders, based on the path to the JSFX file
- YSFX_API void ysfx_guess_file_roots(ysfx_config_t *config, const char *sourcepath);
- // register an audio format into the system
- YSFX_API void ysfx_register_audio_format(ysfx_config_t *config, ysfx_audio_format_t *afmt);
- // register the builtin audio formats (at least WAV file support)
- YSFX_API void ysfx_register_builtin_audio_formats(ysfx_config_t *config);
- // set the log reporting function
- YSFX_API void ysfx_set_log_reporter(ysfx_config_t *config, ysfx_log_reporter_t *reporter);
- // set the callback user data
- YSFX_API void ysfx_set_user_data(ysfx_config_t *config, intptr_t userdata);
-
- // get a string which textually represents the log level
- YSFX_API const char *ysfx_log_level_string(ysfx_log_level level);
-
- //------------------------------------------------------------------------------
- // YSFX effect
-
- typedef struct ysfx_s ysfx_t;
-
- // create a new effect, taking a reference to config
- YSFX_API ysfx_t *ysfx_new(ysfx_config_t *config);
- // delete an effect
- YSFX_API void ysfx_free(ysfx_t *fx);
- // increase the reference counter
- YSFX_API void ysfx_add_ref(ysfx_t *fx);
-
- // get the configuration
- YSFX_API ysfx_config_t *ysfx_get_config(ysfx_t *fx);
-
- typedef enum ysfx_load_option_e {
- // skip imports; useful just for accessing header information and nothing else
- ysfx_load_ignoring_imports = 1,
- } ysfx_load_option_t;
-
- // load the source code from file without compiling
- YSFX_API bool ysfx_load_file(ysfx_t *fx, const char *filepath, uint32_t loadopts);
- // unload the source code and any compiled code
- YSFX_API void ysfx_unload(ysfx_t *fx);
- // check whether the effect is loaded
- YSFX_API bool ysfx_is_loaded(ysfx_t *fx);
-
- // get the name of the effect
- YSFX_API const char *ysfx_get_name(ysfx_t *fx);
- // get the path of the file which is loaded
- YSFX_API const char *ysfx_get_file_path(ysfx_t *fx);
- // get the author of the effect
- YSFX_API const char *ysfx_get_author(ysfx_t *fx);
- // get the number of tags of the effect
- #define ysfx_get_num_tags(fx) ysfx_get_tags((fx), NULL, 0)
- // get the list of tags of the effect
- YSFX_API uint32_t ysfx_get_tags(ysfx_t *fx, const char **dest, uint32_t destsize);
- // get a single tag of the effect
- YSFX_API const char *ysfx_get_tag(ysfx_t *fx, uint32_t index);
- // get the number of inputs
- YSFX_API uint32_t ysfx_get_num_inputs(ysfx_t *fx);
- // get the number of outputs
- YSFX_API uint32_t ysfx_get_num_outputs(ysfx_t *fx);
- // get the name of the input
- YSFX_API const char *ysfx_get_input_name(ysfx_t *fx, uint32_t index);
- // get the name of the output
- YSFX_API const char *ysfx_get_output_name(ysfx_t *fx, uint32_t index);
- // get whether this effect wants metering
- YSFX_API bool ysfx_wants_meters(ysfx_t *fx);
- // get requested dimensions of the graphics area; 0 means host should decide
- YSFX_API bool ysfx_get_gfx_dim(ysfx_t *fx, uint32_t dim[2]);
-
- typedef enum ysfx_section_type_e {
- ysfx_section_init = 1,
- ysfx_section_slider = 2,
- ysfx_section_block = 3,
- ysfx_section_sample = 4,
- ysfx_section_gfx = 5,
- ysfx_section_serialize = 6,
- } ysfx_section_type_t;
-
- // get whether the source has the given section
- YSFX_API bool ysfx_has_section(ysfx_t *fx, uint32_t type);
-
- typedef struct ysfx_slider_range_s {
- ysfx_real def;
- ysfx_real min;
- ysfx_real max;
- ysfx_real inc;
- } ysfx_slider_range_t;
-
- // determine if slider exists; call from 0 to max-1 to scan available ones
- YSFX_API bool ysfx_slider_exists(ysfx_t *fx, uint32_t index);
- // get the name of a slider
- YSFX_API const char *ysfx_slider_get_name(ysfx_t *fx, uint32_t index);
- // get the range of a slider
- YSFX_API bool ysfx_slider_get_range(ysfx_t *fx, uint32_t index, ysfx_slider_range_t *range);
- // get whether the slider is an enumeration
- YSFX_API bool ysfx_slider_is_enum(ysfx_t *fx, uint32_t index);
- // get the number of labels for the enumeration slider
- #define ysfx_slider_get_enum_size(fx, index) ysfx_slider_get_enum_names((fx), (index), NULL, 0)
- // get the list of labels for the enumeration slider
- YSFX_API uint32_t ysfx_slider_get_enum_names(ysfx_t *fx, uint32_t index, const char **dest, uint32_t destsize);
- // get a single label for the enumeration slider
- YSFX_API const char *ysfx_slider_get_enum_name(ysfx_t *fx, uint32_t slider_index, uint32_t enum_index);
- // get whether the slider is a path (implies enumeration)
- YSFX_API bool ysfx_slider_is_path(ysfx_t *fx, uint32_t index);
- // get whether the slider is initially visible
- YSFX_API bool ysfx_slider_is_initially_visible(ysfx_t *fx, uint32_t index);
-
- // get the value of the slider
- YSFX_API ysfx_real ysfx_slider_get_value(ysfx_t *fx, uint32_t index);
- // set the value of the slider, and call @slider later if value has changed
- YSFX_API void ysfx_slider_set_value(ysfx_t *fx, uint32_t index, ysfx_real value);
-
- typedef enum ysfx_compile_option_e {
- // skip compiling the @serialize section
- ysfx_compile_no_serialize = 1 << 0,
- // skip compiling the @gfx section
- ysfx_compile_no_gfx = 1 << 1,
- } ysfx_compile_option_t;
-
- // compile the previously loaded source
- YSFX_API bool ysfx_compile(ysfx_t *fx, uint32_t compileopts);
- // check whether the effect is compiled
- YSFX_API bool ysfx_is_compiled(ysfx_t *fx);
-
- // get the block size
- YSFX_API uint32_t ysfx_get_block_size(ysfx_t *fx);
- // get the sample rate
- YSFX_API ysfx_real ysfx_get_sample_rate(ysfx_t *fx);
- // update the block size; don't forget to call @init
- YSFX_API void ysfx_set_block_size(ysfx_t *fx, uint32_t blocksize);
- // update the sample rate; don't forget to call @init
- YSFX_API void ysfx_set_sample_rate(ysfx_t *fx, ysfx_real samplerate);
-
- // set the capacity of the MIDI buffer
- YSFX_API void ysfx_set_midi_capacity(ysfx_t *fx, uint32_t capacity, bool extensible);
-
- // activate and invoke @init
- YSFX_API void ysfx_init(ysfx_t *fx);
-
- // get the output latency
- YSFX_API ysfx_real ysfx_get_pdc_delay(ysfx_t *fx);
- // get the range of channels where output latency applies (end not included)
- YSFX_API void ysfx_get_pdc_channels(ysfx_t *fx, uint32_t channels[2]);
- // get whether the output latency applies to MIDI as well
- YSFX_API bool ysfx_get_pdc_midi(ysfx_t *fx);
-
- typedef enum ysfx_playback_state_e {
- ysfx_playback_error = 0,
- ysfx_playback_playing = 1,
- ysfx_playback_paused = 2,
- ysfx_playback_recording = 5,
- ysfx_playback_recording_paused = 6,
- } ysfx_playback_state_t;
-
- typedef struct ysfx_time_info_s {
- // tempo in beats/minute
- ysfx_real tempo;
- // state of the playback (ysfx_playback_state_t)
- uint32_t playback_state;
- // time position in seconds
- ysfx_real time_position;
- // time position in beats
- ysfx_real beat_position;
- // time signature in fraction form
- uint32_t time_signature[2];
- } ysfx_time_info_t;
-
- // update time information; do this before processing the cycle
- YSFX_API void ysfx_set_time_info(ysfx_t *fx, const ysfx_time_info_t *info);
-
- typedef struct ysfx_midi_event_s {
- // the bus number
- uint32_t bus;
- // the frame when it happens within the cycle
- uint32_t offset;
- // the size of the message
- uint32_t size;
- // the contents of the message
- const uint8_t *data;
- } ysfx_midi_event_t;
-
- // send MIDI, it will be processed during the cycle
- YSFX_API bool ysfx_send_midi(ysfx_t *fx, const ysfx_midi_event_t *event);
- // receive MIDI, after having processed the cycle
- YSFX_API bool ysfx_receive_midi(ysfx_t *fx, ysfx_midi_event_t *event);
- // receive MIDI from a single bus (do not mix with API above, use either)
- YSFX_API bool ysfx_receive_midi_from_bus(ysfx_t *fx, uint32_t bus, ysfx_midi_event_t *event);
-
- // send a trigger, it will be processed during the cycle
- YSFX_API bool ysfx_send_trigger(ysfx_t *fx, uint32_t index);
-
- // get a bit mask of sliders whose values must be redisplayed, and clear it to zero
- YSFX_API uint64_t ysfx_fetch_slider_changes(ysfx_t *fx);
- // get a bit mask of sliders whose values must be automated, and clear it to zero
- YSFX_API uint64_t ysfx_fetch_slider_automations(ysfx_t *fx);
- // get a bit mask of sliders currently visible
- YSFX_API uint64_t ysfx_get_slider_visibility(ysfx_t *fx);
-
- // process a cycle in 32-bit float
- YSFX_API void ysfx_process_float(ysfx_t *fx, const float *const *ins, float *const *outs, uint32_t num_ins, uint32_t num_outs, uint32_t num_frames);
- // process a cycle in 64-bit float
- YSFX_API void ysfx_process_double(ysfx_t *fx, const double *const *ins, double *const *outs, uint32_t num_ins, uint32_t num_outs, uint32_t num_frames);
-
- typedef struct ysfx_state_slider_s {
- // index of the slider
- uint32_t index;
- // value of the slider
- ysfx_real value;
- } ysfx_state_slider_t;
-
- typedef struct ysfx_state_s {
- // values of the sliders
- ysfx_state_slider_t *sliders;
- // number of sliders
- uint32_t slider_count;
- // serialized data
- uint8_t *data;
- // size of serialized data
- size_t data_size;
- } ysfx_state_t;
-
- // load state
- YSFX_API bool ysfx_load_state(ysfx_t *fx, ysfx_state_t *state);
- // save current state; release this object when done
- YSFX_API ysfx_state_t *ysfx_save_state(ysfx_t *fx);
- // release a saved state object
- YSFX_API void ysfx_state_free(ysfx_state_t *state);
- // duplicate a state object
- YSFX_API ysfx_state_t *ysfx_state_dup(ysfx_state_t *state);
-
- typedef struct ysfx_preset_s {
- // name of the preset
- char *name;
- // state of the preset
- ysfx_state_t *state;
- } ysfx_preset_t;
-
- typedef struct ysfx_bank_s {
- // name of the bank
- char *name;
- // list of presets
- ysfx_preset_t *presets;
- // number of programs
- uint32_t preset_count;
- } ysfx_bank_t;
-
- // get the path of the RPL preset bank of the loaded JSFX, if present
- YSFX_API const char *ysfx_get_bank_path(ysfx_t *fx);
- // read a preset bank from RPL file
- YSFX_API ysfx_bank_t *ysfx_load_bank(const char *path);
- // free a preset bank
- YSFX_API void ysfx_bank_free(ysfx_bank_t *bank);
-
- // type of a function which can enumerate VM variables; returning 0 ends the search
- typedef int (ysfx_enum_vars_callback_t)(const char *name, ysfx_real *var, void *userdata);
- // enumerate all variables currently in the VM
- YSFX_API void ysfx_enum_vars(ysfx_t *fx, ysfx_enum_vars_callback_t *callback, void *userdata);
- // find a single variable in the VM
- YSFX_API ysfx_real *ysfx_find_var(ysfx_t *fx, const char *name);
- // read a chunk of virtual memory from the VM
- YSFX_API void ysfx_read_vmem(ysfx_t *fx, uint32_t addr, ysfx_real *dest, uint32_t count);
-
- //------------------------------------------------------------------------------
- // YSFX graphics
-
- // NOTE: all `ysfx_gfx_*` functions must be invoked from a dedicated UI thread
-
- typedef struct ysfx_gfx_config_s {
- // opaque user data passed to callbacks
- void *user_data;
- // the width of the frame buffer (having the scale factor applied)
- uint32_t pixel_width;
- // the height of the frame buffer (having the scale factor applied)
- uint32_t pixel_height;
- // the distance in bytes between lines; if 0, it defaults to (4*width)
- // currently it is required to be a multiple of 4
- uint32_t pixel_stride;
- // the pixel data of the frame buffer, of size (stride*height) bytes
- // the byte order in little-endian is 'BGRA', big-endian is 'ARGB'
- uint8_t *pixels;
- // the scale factor of the display; 1.0 or greater, 2.0 for Retina display
- ysfx_real scale_factor;
- // show a menu and run it synchronously; returns an item ID >= 1, or 0 if none
- int32_t (*show_menu)(void *user_data, const char *menu_spec, int32_t xpos, int32_t ypos);
- // change the cursor
- void (*set_cursor)(void *user_data, int32_t cursor);
- // if index is not -1, get the dropped file at this index (otherwise null)
- // if index is -1, clear the list of dropped files, and return null
- const char *(*get_drop_file)(void *user_data, int32_t index);
- } ysfx_gfx_config_t;
-
- // set up the graphics rendering
- YSFX_API void ysfx_gfx_setup(ysfx_t *fx, ysfx_gfx_config_t *gc);
- // get whether the current effect is requesting Retina support
- YSFX_API bool ysfx_gfx_wants_retina(ysfx_t *fx);
- // push a key to the input queue
- YSFX_API void ysfx_gfx_add_key(ysfx_t *fx, uint32_t mods, uint32_t key, bool press);
- // update mouse information; position is relative to canvas; wheel should be in steps normalized to ±1.0
- YSFX_API void ysfx_gfx_update_mouse(ysfx_t *fx, uint32_t mods, int32_t xpos, int32_t ypos, uint32_t buttons, ysfx_real wheel, ysfx_real hwheel);
- // invoke @gfx to paint the graphics; returns whether the framer buffer is modified
- YSFX_API bool ysfx_gfx_run(ysfx_t *fx);
-
- //------------------------------------------------------------------------------
- // YSFX key map
-
- // these key definitions match those of pugl
-
- enum {
- ysfx_mod_shift = 1 << 0,
- ysfx_mod_ctrl = 1 << 1,
- ysfx_mod_alt = 1 << 2,
- ysfx_mod_super = 1 << 3,
- };
-
- enum {
- ysfx_key_backspace = 0x08,
- ysfx_key_escape = 0x1b,
- ysfx_key_delete = 0x7f,
-
- ysfx_key_f1 = 0xe000,
- ysfx_key_f2,
- ysfx_key_f3,
- ysfx_key_f4,
- ysfx_key_f5,
- ysfx_key_f6,
- ysfx_key_f7,
- ysfx_key_f8,
- ysfx_key_f9,
- ysfx_key_f10,
- ysfx_key_f11,
- ysfx_key_f12,
- ysfx_key_left,
- ysfx_key_up,
- ysfx_key_right,
- ysfx_key_down,
- ysfx_key_page_up,
- ysfx_key_page_down,
- ysfx_key_home,
- ysfx_key_end,
- ysfx_key_insert,
- };
-
- enum {
- ysfx_button_left = 1 << 0,
- ysfx_button_middle = 1 << 1,
- ysfx_button_right = 1 << 2,
- };
-
- //------------------------------------------------------------------------------
- // YSFX menu
-
- typedef struct ysfx_menu_insn_s ysfx_menu_insn_t;
-
- typedef struct ysfx_menu_s {
- // list of instructions to build a menu
- ysfx_menu_insn_t *insns;
- // number of menu instructions
- uint32_t insn_count;
- } ysfx_menu_t;
-
- typedef enum ysfx_menu_opcode_e {
- // appends an item
- ysfx_menu_item,
- // appends a separator
- ysfx_menu_separator,
- // appends a submenu and enters
- ysfx_menu_sub,
- // terminates a submenu and leaves
- ysfx_menu_endsub,
- } ysfx_menu_opcode_t;
-
- typedef enum ysfx_menu_item_flag_e {
- // whether the item is disabled (grayed out)
- ysfx_menu_item_disabled = 1 << 0,
- // whether the item is checked
- ysfx_menu_item_checked = 1 << 1,
- } ysfx_menu_item_flag_t;
-
- typedef struct ysfx_menu_insn_s {
- // operation code of this instruction
- ysfx_menu_opcode_t opcode;
- // unique identifier, greater than 0 (opcodes: item)
- uint32_t id;
- // name (opcodes: item, sub/endsub)
- const char *name;
- // combination of item flags (opcodes: item, sub/endsub)
- uint32_t item_flags;
- } ysfx_menu_insn_t;
-
- // parse a string which describes a popup menu (cf. `gfx_showmenu`)
- YSFX_API ysfx_menu_t *ysfx_parse_menu(const char *text);
- // free a menu
- YSFX_API void ysfx_menu_free(ysfx_menu_t *menu);
-
- //------------------------------------------------------------------------------
- // YSFX audio formats
-
- typedef struct ysfx_audio_reader_s ysfx_audio_reader_t;
-
- typedef struct ysfx_audio_file_info_s {
- uint32_t channels;
- ysfx_real sample_rate;
- } ysfx_audio_file_info_t;
-
- typedef struct ysfx_audio_format_s {
- // quickly checks if this format would be able to handle the given file
- bool (*can_handle)(const char *path);
- // open an audio file of this format for reading
- ysfx_audio_reader_t *(*open)(const char *path);
- // close the audio file
- void (*close)(ysfx_audio_reader_t *reader);
- // get the sample rate and the channel count
- ysfx_audio_file_info_t (*info)(ysfx_audio_reader_t *reader);
- // get the number of samples left to read
- uint64_t (*avail)(ysfx_audio_reader_t *reader);
- // move the read pointer back to the beginning
- void (*rewind)(ysfx_audio_reader_t *reader);
- // read the next block of samples
- uint64_t (*read)(ysfx_audio_reader_t *reader, ysfx_real *samples, uint64_t count);
- } ysfx_audio_format_t;
-
- //------------------------------------------------------------------------------
-
- #ifdef __cplusplus
- } // extern "C"
- #endif
-
- //------------------------------------------------------------------------------
- // YSFX RAII helpers
-
- #if defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSVC_LANG >= 201103L))
- #include <memory>
-
- #define YSFX_DEFINE_AUTO_PTR(aptr, styp, freefn) \
- struct aptr##_deleter { \
- void operator()(styp *x) const noexcept { freefn(x); } \
- }; \
- using aptr = std::unique_ptr<styp, aptr##_deleter>
-
- YSFX_DEFINE_AUTO_PTR(ysfx_config_u, ysfx_config_t, ysfx_config_free);
- YSFX_DEFINE_AUTO_PTR(ysfx_u, ysfx_t, ysfx_free);
- YSFX_DEFINE_AUTO_PTR(ysfx_state_u, ysfx_state_t, ysfx_state_free);
- YSFX_DEFINE_AUTO_PTR(ysfx_bank_u, ysfx_bank_t, ysfx_bank_free);
- YSFX_DEFINE_AUTO_PTR(ysfx_menu_u, ysfx_menu_t, ysfx_menu_free);
- #endif // defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSVC_LANG >= 201103L))
-
- //------------------------------------------------------------------------------
-
- #endif // !defined(YSFX_INCLUDED_YSFX_H)
|