1 // Copyright 2021 Jean Pierre Cimalando
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // SPDX-License-Identifier: Apache-2.0
19 #if !defined(YSFX_INCLUDED_YSFX_H)
20 #define YSFX_INCLUDED_YSFX_H
30 //------------------------------------------------------------------------------
36 #if !defined(YSFX_API)
37 # if defined(_WIN32) && defined(YSFX_DLL_BUILD)
38 # define YSFX_API __declspec(dllexport)
39 # elif defined(__GNUC__)
40 # define YSFX_API __attribute__((visibility("default")))
46 //------------------------------------------------------------------------------
49 typedef double ysfx_real
;
52 ysfx_max_sliders
= 64,
53 ysfx_max_channels
= 64,
54 ysfx_max_midi_buses
= 16,
55 ysfx_max_triggers
= 10,
58 typedef enum ysfx_log_level_e
{
64 typedef void (ysfx_log_reporter_t
)(intptr_t userdata
, ysfx_log_level level
, const char *message
);
66 //------------------------------------------------------------------------------
69 typedef struct ysfx_config_s ysfx_config_t
;
70 typedef struct ysfx_audio_format_s ysfx_audio_format_t
;
72 // create a new configuration
73 YSFX_API ysfx_config_t
*ysfx_config_new();
74 // delete a configuration
75 YSFX_API
void ysfx_config_free(ysfx_config_t
*config
);
76 // increase the reference counter
77 YSFX_API
void ysfx_config_add_ref(ysfx_config_t
*config
);
78 // set the path of the import root, a folder usually named "Effects"
79 YSFX_API
void ysfx_set_import_root(ysfx_config_t
*config
, const char *root
);
80 // set the path of the data root, a folder usually named "Data"
81 YSFX_API
void ysfx_set_data_root(ysfx_config_t
*config
, const char *root
);
82 // get the path of the import root, a folder usually named "Effects"
83 YSFX_API
const char *ysfx_get_import_root(ysfx_config_t
*config
);
84 // get the path of the data root, a folder usually named "Data"
85 YSFX_API
const char *ysfx_get_data_root(ysfx_config_t
*config
);
86 // guess the undefined root folders, based on the path to the JSFX file
87 YSFX_API
void ysfx_guess_file_roots(ysfx_config_t
*config
, const char *sourcepath
);
88 // register an audio format into the system
89 YSFX_API
void ysfx_register_audio_format(ysfx_config_t
*config
, ysfx_audio_format_t
*afmt
);
90 // register the builtin audio formats (at least WAV file support)
91 YSFX_API
void ysfx_register_builtin_audio_formats(ysfx_config_t
*config
);
92 // set the log reporting function
93 YSFX_API
void ysfx_set_log_reporter(ysfx_config_t
*config
, ysfx_log_reporter_t
*reporter
);
94 // set the callback user data
95 YSFX_API
void ysfx_set_user_data(ysfx_config_t
*config
, intptr_t userdata
);
97 // get a string which textually represents the log level
98 YSFX_API
const char *ysfx_log_level_string(ysfx_log_level level
);
100 //------------------------------------------------------------------------------
103 typedef struct ysfx_s ysfx_t
;
105 // create a new effect, taking a reference to config
106 YSFX_API ysfx_t
*ysfx_new(ysfx_config_t
*config
);
108 YSFX_API
void ysfx_free(ysfx_t
*fx
);
109 // increase the reference counter
110 YSFX_API
void ysfx_add_ref(ysfx_t
*fx
);
112 // get the configuration
113 YSFX_API ysfx_config_t
*ysfx_get_config(ysfx_t
*fx
);
115 typedef enum ysfx_load_option_e
{
116 // skip imports; useful just for accessing header information and nothing else
117 ysfx_load_ignoring_imports
= 1,
118 } ysfx_load_option_t
;
120 // load the source code from file without compiling
121 YSFX_API
bool ysfx_load_file(ysfx_t
*fx
, const char *filepath
, uint32_t loadopts
);
122 // unload the source code and any compiled code
123 YSFX_API
void ysfx_unload(ysfx_t
*fx
);
124 // check whether the effect is loaded
125 YSFX_API
bool ysfx_is_loaded(ysfx_t
*fx
);
127 // get the name of the effect
128 YSFX_API
const char *ysfx_get_name(ysfx_t
*fx
);
129 // get the path of the file which is loaded
130 YSFX_API
const char *ysfx_get_file_path(ysfx_t
*fx
);
131 // get the author of the effect
132 YSFX_API
const char *ysfx_get_author(ysfx_t
*fx
);
133 // get the number of tags of the effect
134 #define ysfx_get_num_tags(fx) ysfx_get_tags((fx), NULL, 0)
135 // get the list of tags of the effect
136 YSFX_API
uint32_t ysfx_get_tags(ysfx_t
*fx
, const char **dest
, uint32_t destsize
);
137 // get a single tag of the effect
138 YSFX_API
const char *ysfx_get_tag(ysfx_t
*fx
, uint32_t index
);
139 // get the number of inputs
140 YSFX_API
uint32_t ysfx_get_num_inputs(ysfx_t
*fx
);
141 // get the number of outputs
142 YSFX_API
uint32_t ysfx_get_num_outputs(ysfx_t
*fx
);
143 // get the name of the input
144 YSFX_API
const char *ysfx_get_input_name(ysfx_t
*fx
, uint32_t index
);
145 // get the name of the output
146 YSFX_API
const char *ysfx_get_output_name(ysfx_t
*fx
, uint32_t index
);
147 // get whether this effect wants metering
148 YSFX_API
bool ysfx_wants_meters(ysfx_t
*fx
);
149 // get requested dimensions of the graphics area; 0 means host should decide
150 YSFX_API
bool ysfx_get_gfx_dim(ysfx_t
*fx
, uint32_t dim
[2]);
152 typedef enum ysfx_section_type_e
{
153 ysfx_section_init
= 1,
154 ysfx_section_slider
= 2,
155 ysfx_section_block
= 3,
156 ysfx_section_sample
= 4,
157 ysfx_section_gfx
= 5,
158 ysfx_section_serialize
= 6,
159 } ysfx_section_type_t
;
161 // get whether the source has the given section
162 YSFX_API
bool ysfx_has_section(ysfx_t
*fx
, uint32_t type
);
164 typedef struct ysfx_slider_range_s
{
169 } ysfx_slider_range_t
;
171 // determine if slider exists; call from 0 to max-1 to scan available ones
172 YSFX_API
bool ysfx_slider_exists(ysfx_t
*fx
, uint32_t index
);
173 // get the name of a slider
174 YSFX_API
const char *ysfx_slider_get_name(ysfx_t
*fx
, uint32_t index
);
175 // get the range of a slider
176 YSFX_API
bool ysfx_slider_get_range(ysfx_t
*fx
, uint32_t index
, ysfx_slider_range_t
*range
);
177 // get whether the slider is an enumeration
178 YSFX_API
bool ysfx_slider_is_enum(ysfx_t
*fx
, uint32_t index
);
179 // get the number of labels for the enumeration slider
180 #define ysfx_slider_get_enum_size(fx, index) ysfx_slider_get_enum_names((fx), (index), NULL, 0)
181 // get the list of labels for the enumeration slider
182 YSFX_API
uint32_t ysfx_slider_get_enum_names(ysfx_t
*fx
, uint32_t index
, const char **dest
, uint32_t destsize
);
183 // get a single label for the enumeration slider
184 YSFX_API
const char *ysfx_slider_get_enum_name(ysfx_t
*fx
, uint32_t slider_index
, uint32_t enum_index
);
185 // get whether the slider is a path (implies enumeration)
186 YSFX_API
bool ysfx_slider_is_path(ysfx_t
*fx
, uint32_t index
);
187 // get whether the slider is initially visible
188 YSFX_API
bool ysfx_slider_is_initially_visible(ysfx_t
*fx
, uint32_t index
);
190 // get the value of the slider
191 YSFX_API ysfx_real
ysfx_slider_get_value(ysfx_t
*fx
, uint32_t index
);
192 // set the value of the slider, and call @slider later if value has changed
193 YSFX_API
void ysfx_slider_set_value(ysfx_t
*fx
, uint32_t index
, ysfx_real value
);
195 typedef enum ysfx_compile_option_e
{
196 // skip compiling the @serialize section
197 ysfx_compile_no_serialize
= 1 << 0,
198 // skip compiling the @gfx section
199 ysfx_compile_no_gfx
= 1 << 1,
200 } ysfx_compile_option_t
;
202 // compile the previously loaded source
203 YSFX_API
bool ysfx_compile(ysfx_t
*fx
, uint32_t compileopts
);
204 // check whether the effect is compiled
205 YSFX_API
bool ysfx_is_compiled(ysfx_t
*fx
);
207 // get the block size
208 YSFX_API
uint32_t ysfx_get_block_size(ysfx_t
*fx
);
209 // get the sample rate
210 YSFX_API ysfx_real
ysfx_get_sample_rate(ysfx_t
*fx
);
211 // update the block size; don't forget to call @init
212 YSFX_API
void ysfx_set_block_size(ysfx_t
*fx
, uint32_t blocksize
);
213 // update the sample rate; don't forget to call @init
214 YSFX_API
void ysfx_set_sample_rate(ysfx_t
*fx
, ysfx_real samplerate
);
216 // set the capacity of the MIDI buffer
217 YSFX_API
void ysfx_set_midi_capacity(ysfx_t
*fx
, uint32_t capacity
, bool extensible
);
219 // activate and invoke @init
220 YSFX_API
void ysfx_init(ysfx_t
*fx
);
222 // get the output latency
223 YSFX_API ysfx_real
ysfx_get_pdc_delay(ysfx_t
*fx
);
224 // get the range of channels where output latency applies (end not included)
225 YSFX_API
void ysfx_get_pdc_channels(ysfx_t
*fx
, uint32_t channels
[2]);
226 // get whether the output latency applies to MIDI as well
227 YSFX_API
bool ysfx_get_pdc_midi(ysfx_t
*fx
);
229 typedef enum ysfx_playback_state_e
{
230 ysfx_playback_error
= 0,
231 ysfx_playback_playing
= 1,
232 ysfx_playback_paused
= 2,
233 ysfx_playback_recording
= 5,
234 ysfx_playback_recording_paused
= 6,
235 } ysfx_playback_state_t
;
237 typedef struct ysfx_time_info_s
{
238 // tempo in beats/minute
240 // state of the playback (ysfx_playback_state_t)
241 uint32_t playback_state
;
242 // time position in seconds
243 ysfx_real time_position
;
244 // time position in beats
245 ysfx_real beat_position
;
246 // time signature in fraction form
247 uint32_t time_signature
[2];
250 // update time information; do this before processing the cycle
251 YSFX_API
void ysfx_set_time_info(ysfx_t
*fx
, const ysfx_time_info_t
*info
);
253 typedef struct ysfx_midi_event_s
{
256 // the frame when it happens within the cycle
258 // the size of the message
260 // the contents of the message
264 // send MIDI, it will be processed during the cycle
265 YSFX_API
bool ysfx_send_midi(ysfx_t
*fx
, const ysfx_midi_event_t
*event
);
266 // receive MIDI, after having processed the cycle
267 YSFX_API
bool ysfx_receive_midi(ysfx_t
*fx
, ysfx_midi_event_t
*event
);
268 // receive MIDI from a single bus (do not mix with API above, use either)
269 YSFX_API
bool ysfx_receive_midi_from_bus(ysfx_t
*fx
, uint32_t bus
, ysfx_midi_event_t
*event
);
271 // send a trigger, it will be processed during the cycle
272 YSFX_API
bool ysfx_send_trigger(ysfx_t
*fx
, uint32_t index
);
274 // get a bit mask of sliders whose values must be redisplayed, and clear it to zero
275 YSFX_API
uint64_t ysfx_fetch_slider_changes(ysfx_t
*fx
);
276 // get a bit mask of sliders whose values must be automated, and clear it to zero
277 YSFX_API
uint64_t ysfx_fetch_slider_automations(ysfx_t
*fx
);
278 // get a bit mask of sliders currently visible
279 YSFX_API
uint64_t ysfx_get_slider_visibility(ysfx_t
*fx
);
281 // process a cycle in 32-bit float
282 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
);
283 // process a cycle in 64-bit float
284 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
);
286 typedef struct ysfx_state_slider_s
{
287 // index of the slider
289 // value of the slider
291 } ysfx_state_slider_t
;
293 typedef struct ysfx_state_s
{
294 // values of the sliders
295 ysfx_state_slider_t
*sliders
;
297 uint32_t slider_count
;
300 // size of serialized data
305 YSFX_API
bool ysfx_load_state(ysfx_t
*fx
, ysfx_state_t
*state
);
306 // save current state; release this object when done
307 YSFX_API ysfx_state_t
*ysfx_save_state(ysfx_t
*fx
);
308 // release a saved state object
309 YSFX_API
void ysfx_state_free(ysfx_state_t
*state
);
310 // duplicate a state object
311 YSFX_API ysfx_state_t
*ysfx_state_dup(ysfx_state_t
*state
);
313 typedef struct ysfx_preset_s
{
314 // name of the preset
316 // state of the preset
320 typedef struct ysfx_bank_s
{
324 ysfx_preset_t
*presets
;
325 // number of programs
326 uint32_t preset_count
;
329 // get the path of the RPL preset bank of the loaded JSFX, if present
330 YSFX_API
const char *ysfx_get_bank_path(ysfx_t
*fx
);
331 // read a preset bank from RPL file
332 YSFX_API ysfx_bank_t
*ysfx_load_bank(const char *path
);
333 // free a preset bank
334 YSFX_API
void ysfx_bank_free(ysfx_bank_t
*bank
);
336 // type of a function which can enumerate VM variables; returning 0 ends the search
337 typedef int (ysfx_enum_vars_callback_t
)(const char *name
, ysfx_real
*var
, void *userdata
);
338 // enumerate all variables currently in the VM
339 YSFX_API
void ysfx_enum_vars(ysfx_t
*fx
, ysfx_enum_vars_callback_t
*callback
, void *userdata
);
340 // find a single variable in the VM
341 YSFX_API ysfx_real
*ysfx_find_var(ysfx_t
*fx
, const char *name
);
342 // read a chunk of virtual memory from the VM
343 YSFX_API
void ysfx_read_vmem(ysfx_t
*fx
, uint32_t addr
, ysfx_real
*dest
, uint32_t count
);
345 //------------------------------------------------------------------------------
348 // NOTE: all `ysfx_gfx_*` functions must be invoked from a dedicated UI thread
350 typedef struct ysfx_gfx_config_s
{
351 // opaque user data passed to callbacks
353 // the width of the frame buffer (having the scale factor applied)
354 uint32_t pixel_width
;
355 // the height of the frame buffer (having the scale factor applied)
356 uint32_t pixel_height
;
357 // the distance in bytes between lines; if 0, it defaults to (4*width)
358 // currently it is required to be a multiple of 4
359 uint32_t pixel_stride
;
360 // the pixel data of the frame buffer, of size (stride*height) bytes
361 // the byte order in little-endian is 'BGRA', big-endian is 'ARGB'
363 // the scale factor of the display; 1.0 or greater, 2.0 for Retina display
364 ysfx_real scale_factor
;
365 // show a menu and run it synchronously; returns an item ID >= 1, or 0 if none
366 int32_t (*show_menu
)(void *user_data
, const char *menu_spec
, int32_t xpos
, int32_t ypos
);
368 void (*set_cursor
)(void *user_data
, int32_t cursor
);
369 // if index is not -1, get the dropped file at this index (otherwise null)
370 // if index is -1, clear the list of dropped files, and return null
371 const char *(*get_drop_file
)(void *user_data
, int32_t index
);
374 // set up the graphics rendering
375 YSFX_API
void ysfx_gfx_setup(ysfx_t
*fx
, ysfx_gfx_config_t
*gc
);
376 // get whether the current effect is requesting Retina support
377 YSFX_API
bool ysfx_gfx_wants_retina(ysfx_t
*fx
);
378 // push a key to the input queue
379 YSFX_API
void ysfx_gfx_add_key(ysfx_t
*fx
, uint32_t mods
, uint32_t key
, bool press
);
380 // update mouse information; position is relative to canvas; wheel should be in steps normalized to ±1.0
381 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
);
382 // invoke @gfx to paint the graphics; returns whether the framer buffer is modified
383 YSFX_API
bool ysfx_gfx_run(ysfx_t
*fx
);
385 //------------------------------------------------------------------------------
388 // these key definitions match those of pugl
391 ysfx_mod_shift
= 1 << 0,
392 ysfx_mod_ctrl
= 1 << 1,
393 ysfx_mod_alt
= 1 << 2,
394 ysfx_mod_super
= 1 << 3,
398 ysfx_key_backspace
= 0x08,
399 ysfx_key_escape
= 0x1b,
400 ysfx_key_delete
= 0x7f,
402 ysfx_key_f1
= 0xe000,
426 ysfx_button_left
= 1 << 0,
427 ysfx_button_middle
= 1 << 1,
428 ysfx_button_right
= 1 << 2,
431 //------------------------------------------------------------------------------
434 typedef struct ysfx_menu_insn_s ysfx_menu_insn_t
;
436 typedef struct ysfx_menu_s
{
437 // list of instructions to build a menu
438 ysfx_menu_insn_t
*insns
;
439 // number of menu instructions
443 typedef enum ysfx_menu_opcode_e
{
446 // appends a separator
448 // appends a submenu and enters
450 // terminates a submenu and leaves
452 } ysfx_menu_opcode_t
;
454 typedef enum ysfx_menu_item_flag_e
{
455 // whether the item is disabled (grayed out)
456 ysfx_menu_item_disabled
= 1 << 0,
457 // whether the item is checked
458 ysfx_menu_item_checked
= 1 << 1,
459 } ysfx_menu_item_flag_t
;
461 typedef struct ysfx_menu_insn_s
{
462 // operation code of this instruction
463 ysfx_menu_opcode_t opcode
;
464 // unique identifier, greater than 0 (opcodes: item)
466 // name (opcodes: item, sub/endsub)
468 // combination of item flags (opcodes: item, sub/endsub)
472 // parse a string which describes a popup menu (cf. `gfx_showmenu`)
473 YSFX_API ysfx_menu_t
*ysfx_parse_menu(const char *text
);
475 YSFX_API
void ysfx_menu_free(ysfx_menu_t
*menu
);
477 //------------------------------------------------------------------------------
478 // YSFX audio formats
480 typedef struct ysfx_audio_reader_s ysfx_audio_reader_t
;
482 typedef struct ysfx_audio_file_info_s
{
484 ysfx_real sample_rate
;
485 } ysfx_audio_file_info_t
;
487 typedef struct ysfx_audio_format_s
{
488 // quickly checks if this format would be able to handle the given file
489 bool (*can_handle
)(const char *path
);
490 // open an audio file of this format for reading
491 ysfx_audio_reader_t
*(*open
)(const char *path
);
492 // close the audio file
493 void (*close
)(ysfx_audio_reader_t
*reader
);
494 // get the sample rate and the channel count
495 ysfx_audio_file_info_t (*info
)(ysfx_audio_reader_t
*reader
);
496 // get the number of samples left to read
497 uint64_t (*avail
)(ysfx_audio_reader_t
*reader
);
498 // move the read pointer back to the beginning
499 void (*rewind
)(ysfx_audio_reader_t
*reader
);
500 // read the next block of samples
501 uint64_t (*read
)(ysfx_audio_reader_t
*reader
, ysfx_real
*samples
, uint64_t count
);
502 } ysfx_audio_format_t
;
504 //------------------------------------------------------------------------------
510 //------------------------------------------------------------------------------
513 #if defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSVC_LANG >= 201103L))
516 #define YSFX_DEFINE_AUTO_PTR(aptr, styp, freefn) \
517 struct aptr##_deleter { \
518 void operator()(styp *x) const noexcept { freefn(x); } \
520 using aptr = std::unique_ptr<styp, aptr##_deleter>
522 YSFX_DEFINE_AUTO_PTR(ysfx_config_u
, ysfx_config_t
, ysfx_config_free
);
523 YSFX_DEFINE_AUTO_PTR(ysfx_u
, ysfx_t
, ysfx_free
);
524 YSFX_DEFINE_AUTO_PTR(ysfx_state_u
, ysfx_state_t
, ysfx_state_free
);
525 YSFX_DEFINE_AUTO_PTR(ysfx_bank_u
, ysfx_bank_t
, ysfx_bank_free
);
526 YSFX_DEFINE_AUTO_PTR(ysfx_menu_u
, ysfx_menu_t
, ysfx_menu_free
);
527 #endif // defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSVC_LANG >= 201103L))
529 //------------------------------------------------------------------------------
531 #endif // !defined(YSFX_INCLUDED_YSFX_H)