### Xcode Project Setup for SWELL Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/swell/sample_project/readme.txt Instructions for creating and configuring an Xcode project to compile a SWELL-based application. This involves adding source files, frameworks, and modifying project settings. ```bash New Project -> Mac OS X -> Application -> Cocoa Application ``` ```bash Add to "Other sources/SWELL": (from swell path) swell-dlg.mm swell-gdi.mm swell-ini.cpp swell-kb.mm swell-menu.mm swell-misc.mm swell-miscdlg.mm swell-wnd.mm swell.cpp swell-appstub.mm swellappmain.mm ``` ```bash Add app_main.cpp main_dialog.cpp to "Other sources" ``` ```bash Go to Frameworks -> Linked Frameworks, add existing framework, Carbon.Framework ``` ```bash go to terminal, to project dir, and run /swell_resgen.pl sample_project.rc ``` ```bash Open mainmenu.xib in Interface Builder (doubleclick it in XCode) ``` ```bash + Delete the default "Window" ``` ```bash + File->Read class files, find and select "swellappmain.h" ``` ```bash + Go to Library, Objects, scroll to "Object" , drag to "MainMenu.xib", rename to "Controller", then open its properties (Cmd+Shift+I, go to class identity tab), choose for Class "SWELLAppController". ``` ```bash + Select "Application" in MainMenu.xib, go to (Cmd+Shift+I) application identity tab, select "SWELLApplication" for the class. ``` ```bash + Customize the "NewApplication" menu. ``` ```bash + Properties on "About NewApplication": + set the tag to 40002 (matching resource.h for about) + on the connection tab, "Sent Actions", remove the default connection, then drag a new connection to controller (onSysMenuCommand). ``` ```bash + Properties on "Quit NewApplication": + set the tag to 40001 (matching resource.h for quit) + on the connection tab, "Sent Actions", remove the default connection, then drag a new connection to controller (onSysMenuCommand). ``` ```bash + Delete the file/edit/format/view/window/help menus, if you like (or keep some of them if you want) ``` ```bash + Save and quit IB ``` ```bash Go to Targets->sample_project, hit cmd+I, go to "Properties", and change Principal class to "SWELLApplication" ``` -------------------------------- ### Copy SWELL MyApp Project Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/swell/sample_project/readme.txt To start a new application, copy the SWELL MyApp project to a new location. This ensures a clean base for your custom application. ```bash cp -a ./WDL/swell/swell_myapp ./my_new_app ``` -------------------------------- ### Pin Configuration (sx_getPinInfo) Source: https://context7.com/justinfrankel/jsfx/llms.txt Get information about the effect's audio input and output pin names. ```APIDOC ## Pin Configuration (sx_getPinInfo) ### Description Get information about the effect's audio input and output pin names. ### Function - `const char **sx_getPinInfo(SX_Instance *sx, int isOutput, int *numPins)`: Retrieves an array of pin names. ### Parameters - `sx` (SX_Instance *): Pointer to the JSFX instance. - `isOutput` (int): `0` for input pins, `1` for output pins. - `numPins` (int *): Pointer to an integer that will be filled with the number of pins. ### Request Example ```c int numInputs, numOutputs; const char **inputPins = sx_getPinInfo(effect, 0, &numInputs); const char **outputPins = sx_getPinInfo(effect, 1, &numOutputs); // Iterate and print pin names for (int i = 0; i < numInputs && inputPins; i++) { printf("Input pin %d: %s\n", i, inputPins[i]); } for (int i = 0; i < numOutputs && outputPins; i++) { printf("Output pin %d: %s\n", i, outputPins[i]); } ``` ### Response Example - Returns `const char **`: An array of strings, where each string is a pin name. Returns NULL if no pins are found or an error occurs. - `numPins` (int *): Filled with the count of pins. ``` -------------------------------- ### JSFX Graphics Rendering (LICE) Source: https://context7.com/justinfrankel/jsfx/llms.txt Provides examples for drawing various shapes, text, and waveforms within the @gfx section using the LICE library. Includes basic color setting, coordinate manipulation, and image loading. ```eel // JSFX script example - Graphics rendering @gfx 640 480 // Request 640x480 window // Clear background gfx_r = gfx_g = gfx_b = 0.1; // Dark gray gfx_a = 1.0; gfx_clear = gfx_r * 255 + gfx_g * 256 * 255 + gfx_b * 65536 * 255; // Set drawing color gfx_r = 1.0; gfx_g = 0.5; gfx_b = 0.0; gfx_a = 1.0; // Orange // Draw rectangle gfx_rect(10, 10, 100, 50); // Filled rectangle gfx_rectto(110, 60); // Draw to current position // Draw line gfx_x = 10; gfx_y = 100; gfx_lineto(200, 100, 1); // Draw line, aa=1 for antialiasing // Draw circle gfx_circle(320, 240, 50, 1); // x, y, radius, filled // Draw text gfx_x = 10; gfx_y = 200; gfx_setfont(1, "Arial", 16); gfx_drawstr("Hello JSFX!"); // Draw waveform gfx_r = 0; gfx_g = 1; gfx_b = 0; gfx_x = 0; loop(gfx_w, sample_idx = (gfx_x / gfx_w) * buffer_size; y = gfx_h/2 - buffer[sample_idx] * gfx_h/2; gfx_x == 0 ? gfx_y = y : gfx_lineto(gfx_x, y, 1); gfx_x += 1; ); // Mouse interaction mouse_cap & 1 ? ( // Left button pressed gfx_circle(mouse_x, mouse_y, 5, 1); ); // Load and draw image @init img = gfx_loadimg(0, "background.png"); @gfx gfx_blit(img, 1, 0); // Draw image at scale 1, no rotation ``` -------------------------------- ### Get Latency, Tail Size, and Extended Info Source: https://context7.com/justinfrankel/jsfx/llms.txt Query effect latency in samples with sx_getCurrentLatency and tail size in seconds with sx_getTailSize. sx_extended provides access to other extended functionalities like flags and gain reduction meters. ```c int sx_getCurrentLatency(SX_Instance *sx); double sx_getTailSize(SX_Instance *sx); INT_PTR sx_extended(SX_Instance *sx, int msg, void *parm1, void *parm2); ``` ```c // Example: Get latency and tail size int latencySamples = sx_getCurrentLatency(effect); double tailSeconds = sx_getTailSize(effect); printf("Effect latency: %d samples, tail: %.3f seconds\n", latencySamples, tailSeconds); ``` ```c // Query if effect is an instrument INT_PTR flags = sx_extended(effect, 0 /* JSFX_EXT_GETFLAGS */, NULL, NULL); if (flags & 1) { printf("Effect is an instrument\n"); } ``` ```c // Get gain reduction meter value double grValue; if (sx_extended(effect, 1 /* JSFX_EXT_GET_GR */, &grValue, NULL)) { printf("Gain reduction: %.2f dB\n", grValue); } ``` -------------------------------- ### Localize Strings in a Table Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt When strings are part of a data structure, use comments to delineate the section to be localized. This example shows a struct with string members. ```cpp // !WANT_LOCALIZE_STRINGS_BEGIN:section_name struct foo bar[]={ {x,y,z,"string 1"}, {x,y,z,"string 2"}, {x,y,z,"string 3"}, }; // !WANT_LOCALIZE_STRINGS_END ``` -------------------------------- ### JSFX API - Parameter Management Source: https://context7.com/justinfrankel/jsfx/llms.txt Provides functions to get and set the values of parameters (sliders) within a JSFX effect, along with their names and ranges. ```APIDOC ## Parameter Management (sx_getParmVal, sx_setParmVal) ### Description Get and set effect parameters (sliders). Parameters are accessed by index and automatically scaled to the defined range. ### Methods - `sx_getNumParms`: Returns the total number of parameters for the effect. - `sx_getParmVal`: Retrieves the current value of a parameter, along with its minimum, maximum, and step values. - `sx_setParmVal`: Sets the value of a parameter. Can optionally specify a sample offset for automation. - `sx_getParmName`: Retrieves the name of a parameter. - `sx_getParmDisplay`: Retrieves the display text for a parameter's current value. ### Parameters - **sx** (SX_Instance *) - Required - Pointer to the JSFX instance. - **parm** (int) - Required - The index of the parameter to access (0-based). - **minval** (double *) - Output (for `sx_getParmVal`) - Pointer to store the minimum value of the parameter. - **maxval** (double *) - Output (for `sx_getParmVal`) - Pointer to store the maximum value of the parameter. - **step** (double *) - Output (for `sx_getParmVal`) - Pointer to store the step value of the parameter. - **val** (double) - Required (for `sx_setParmVal`) - The new value to set for the parameter. - **sampleoffs** (int) - Optional (for `sx_setParmVal`) - The sample offset at which to apply the parameter change. 0 means immediate. - **name** (char *) - Output (for `sx_getParmName`) - Buffer to store the parameter name. - **namelen** (int) - Required (for `sx_getParmName`) - The size of the `name` buffer. - **disptxt** (char *) - Output (for `sx_getParmDisplay`) - Buffer to store the display text for the parameter's value. - **len** (int) - Required (for `sx_getParmDisplay`) - The size of the `disptxt` buffer. - **inval** (double *) - Optional (for `sx_getParmDisplay`) - Pointer to a value to get display text for a specific input value (if NULL, uses current value). ### Return Value - `sx_getNumParms`: Returns the number of parameters. - `sx_getParmVal`: Returns the current value of the parameter. - `sx_setParmVal`, `sx_getParmName`, `sx_getParmDisplay`: void (no return value). ### Request Example ```c int numParams = sx_getNumParms(effect); printf("Effect has %d parameters\n", numParams); for (int i = 0; i < numParams; i++) { char name[256], display[256]; double minVal, maxVal, step; sx_getParmName(effect, i, name, sizeof(name)); double value = sx_getParmVal(effect, i, &minVal, &maxVal, &step); sx_getParmDisplay(effect, i, display, sizeof(display), NULL); printf("Param %d: %s = %.3f (%s) [%.3f - %.3f, step %.3f]\n", i, name, value, display, minVal, maxVal, step); } // Set parameter value (with optional sample offset for automation) sx_setParmVal(effect, 0, 0.75, 0); // Set first param to 0.75 immediately sx_setParmVal(effect, 1, -6.0, 128); // Set second param at sample offset 128 ``` ``` -------------------------------- ### Manage JSFX Parameters Source: https://context7.com/justinfrankel/jsfx/llms.txt Provides functions to get and set effect parameters (sliders) by index. Parameters are automatically scaled to their defined ranges. `sx_getParmVal` retrieves the current value along with min, max, and step. `sx_setParmVal` applies a new value, optionally with a sample offset for automation. ```c int sx_getNumParms(SX_Instance *sx); double sx_getParmVal(SX_Instance *sx, int parm, double *minval, double *maxval, double *step); void sx_setParmVal(SX_Instance *sx, int parm, double val, int sampleoffs); void sx_getParmName(SX_Instance *sx, int parm, char *name, int namelen); void sx_getParmDisplay(SX_Instance *sx, int parm, char *disptxt, int len, double *inval); // Example: Enumerate and modify parameters int numParams = sx_getNumParms(effect); printf("Effect has %d parameters\n", numParams); for (int i = 0; i < numParams; i++) { char name[256], display[256]; double minVal, maxVal, step; sx_getParmName(effect, i, name, sizeof(name)); double value = sx_getParmVal(effect, i, &minVal, &maxVal, &step); sx_getParmDisplay(effect, i, display, sizeof(display), NULL); printf("Param %d: %s = %.3f (%s) [%.3f - %.3f, step %.3f]\n", i, name, value, display, minVal, maxVal, step); } // Set parameter value (with optional sample offset for automation) sx_setParmVal(effect, 0, 0.75, 0); // Set first param to 0.75 immediately sx_setParmVal(effect, 1, -6.0, 128); // Set second param at sample offset 128 ``` -------------------------------- ### Initialize Language Pack Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Call this function at application startup to load a language pack. The second argument can be used for custom callbacks. ```cpp WDL_LoadLanguagePack("/path/to/filename.langpack",NULL); ``` -------------------------------- ### Create JSFX Instance Source: https://context7.com/justinfrankel/jsfx/llms.txt Initializes a JSFX effect by loading a script from a specified directory. Ensure the provided path is correct and the effect name matches an existing .jsfx file. The `wantWak` output parameter indicates if the effect requires all keyboard input. ```c // Create a JSFX instance SX_Instance *sx_createInstance(const char *dir_root, const char *effect_name, bool *wantWak); // Example usage: bool wantAllKeys = false; SX_Instance *effect = sx_createInstance( "/path/to/reaper/resources", // Root directory containing Effects and Data folders "effects/my_compressor.jsfx", // Effect file relative path &wantAllKeys // Output: true if effect wants all keyboard input ); if (effect) { // Effect loaded successfully printf("Loaded effect: %s\n", sx_getEffectName(effect)); } else { // Handle loading error fprintf(stderr, "Failed to load JSFX effect\n"); } ``` -------------------------------- ### MIDI Context (sx_set_midi_ctx) Source: https://context7.com/justinfrankel/jsfx/llms.txt Set up MIDI send/receive callbacks for the effect to process MIDI events. ```APIDOC ## MIDI Context (sx_set_midi_ctx) ### Description Set up MIDI send/receive callbacks for the effect to process MIDI events. ### Function - `void sx_set_midi_ctx(SX_Instance *sx, double (*midi_sendrecv)(void *ctx, int action, double *ts, double *msg1, double *msg23, double *midi_bus), void *midi_ctxdata)`: Registers a MIDI callback function and its associated context data. ### Parameters - `sx` (SX_Instance *): Pointer to the JSFX instance. - `midi_sendrecv` (double (*)(void *, int, double *, double *, double *, double *)): Pointer to the MIDI callback function. - `ctx` (void *): User-defined context data. - `action` (int): Action code (-1 for receive, 1 for send, 2 for sysex). - `ts` (double *): Timestamp of the MIDI event. - `msg1` (double *): First byte of the MIDI message (status byte for send/receive). - `msg23` (double *): Second and third bytes of the MIDI message (data bytes for send/receive). - `midi_bus` (double *): MIDI bus information. - Returns: `> 0` if an event is available for receive, `1.0` for send, `0.0` otherwise. - `midi_ctxdata` (void *): User-defined context data passed to the callback. ### Request Example ```c // Example MIDI callback implementation double my_midi_callback(void *ctx, int action, double *ts, double *msg1, double *msg23, double *midi_bus) { // action: -1 = receive, 1 = send, 2 = sysex if (action == -1) { // Provide next MIDI event to the effect *ts = 0.0; // Timestamp *msg1 = 0x90; // Note On *msg23 = 60 | (100 << 8); // Note 60, velocity 100 return 1.0; } else if (action == 1) { // Effect is sending a MIDI event printf("MIDI out: status=%d data=%d\n", (int)*msg1, (int)*msg23); return 1.0; } return 0.0; } sx_set_midi_ctx(effect, my_midi_callback, myMidiContext); ``` ### Response Example (This function does not return a value; it configures the MIDI callback.) ``` -------------------------------- ### JSFX API - Creating an Instance Source: https://context7.com/justinfrankel/jsfx/llms.txt Initializes a JSFX effect by loading its script from a file. This function is the entry point for using a JSFX plugin. ```APIDOC ## Creating an Instance (sx_createInstance) ### Description Creates a new JSFX effect instance by loading an effect script from a file. This is the entry point for initializing a JSFX plugin with the specified root directory and effect name. ### Method `sx_createInstance` ### Parameters - **dir_root** (const char *) - Required - The root directory containing the JSFX effect files (e.g., Reaper's resources directory). - **effect_name** (const char *) - Required - The relative path to the JSFX effect file (e.g., "effects/my_compressor.jsfx"). - **wantWak** (bool *) - Output - Pointer to a boolean that will be set to true if the effect requests all keyboard input. ### Return Value - **SX_Instance*** - A pointer to the newly created JSFX instance, or NULL if an error occurred. ### Request Example ```c bool wantAllKeys = false; SX_Instance *effect = sx_createInstance( "/path/to/reaper/resources", // Root directory containing Effects and Data folders "effects/my_compressor.jsfx", // Effect file relative path &wantAllKeys // Output: true if effect wants all keyboard input ); if (effect) { // Effect loaded successfully printf("Loaded effect: %s\n", sx_getEffectName(effect)); } else { // Handle loading error fprintf(stderr, "Failed to load JSFX effect\n"); } ``` ``` -------------------------------- ### Create and Manage Effect UI Source: https://context7.com/justinfrankel/jsfx/llms.txt Use sx_createUI to create the effect's graphical user interface and sx_deleteUI to destroy it. sx_getUIwnd retrieves the handle of the existing UI window. ```c HWND sx_createUI(SX_Instance *sx, HINSTANCE hDllInstance, HWND hwndParent, void *hostpostparam); HWND sx_getUIwnd(SX_Instance *sx); void sx_deleteUI(SX_Instance *sx); ``` ```c // Example: Create effect UI as child window HWND effectUI = sx_createUI(effect, hInstance, parentWindow, NULL); if (effectUI) { ShowWindow(effectUI, SW_SHOW); // Effect UI is now visible } ``` ```c // Get existing UI window HWND existingUI = sx_getUIwnd(effect); ``` ```c // Destroy UI when done sx_deleteUI(effect); ``` -------------------------------- ### Localize String (Standard) Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Use this macro to mark a string for localization. Both parameters must be literal strings. ```cpp __LOCALIZE("my string","section"); ``` -------------------------------- ### JavaScript Stream Player Initialization Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/sc_bounce/index.html This function sets the stream URL based on the window hash, fetches initial stream info, and configures the audio player to load and play the stream. ```javascript function doplay() { g_url = "stream.php?stream=" + window.location.hash.replace(/^#(.+)$/,"$1"); getinfo(); var player = document.getElementById("player"); player.src = g_url + "&t=stream.mp3"; player.load(); player.play(); } ``` -------------------------------- ### UI Management (sx_createUI, sx_deleteUI) Source: https://context7.com/justinfrankel/jsfx/llms.txt Functions to create, retrieve, and delete the effect's graphical user interface. ```APIDOC ## UI Management (sx_createUI, sx_deleteUI) ### Description Create and manage the effect's graphical user interface. ### Functions - `HWND sx_createUI(SX_Instance *sx, HINSTANCE hDllInstance, HWND hwndParent, void *hostpostparam)`: Creates the effect's UI window. - `HWND sx_getUIwnd(SX_Instance *sx)`: Retrieves the handle to the effect's UI window. - `void sx_deleteUI(SX_Instance *sx)`: Destroys the effect's UI window. ### Parameters - `sx` (SX_Instance *): Pointer to the JSFX instance. - `hDllInstance` (HINSTANCE): Handle to the DLL instance. - `hwndParent` (HWND): Handle to the parent window. - `hostpostparam` (void *): Host-specific parameter. ### Request Example ```c // Create effect UI as child window HWND effectUI = sx_createUI(effect, hInstance, parentWindow, NULL); if (effectUI) { ShowWindow(effectUI, SW_SHOW); } // Get existing UI window H তরঙ্গ existingUI = sx_getUIwnd(effect); // Destroy UI when done sx_deleteUI(effect); ``` ### Response Example - `sx_createUI` returns `HWND`: Handle to the created UI window, or NULL if creation fails. - `sx_getUIwnd` returns `HWND`: Handle to the UI window, or NULL if no UI exists. - `sx_deleteUI` returns `void`. ``` -------------------------------- ### Generate Language Pack Template Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Compile and run this command to generate a template language pack from your project's resource and source files. ```bash g++ -O -o build_sample_langpack build_sample_langpack.cpp ``` ```bash build_sample_langpack --template *.rc *.cpp > template.langpack ``` -------------------------------- ### Set MIDI Context and Callback Source: https://context7.com/justinfrankel/jsfx/llms.txt Configure MIDI send/receive callbacks for an effect using sx_set_midi_ctx. The provided callback function handles MIDI events, returning a positive value if an event is available or processed. ```c void sx_set_midi_ctx( SX_Instance *sx, double (*midi_sendrecv)(void *ctx, int action, double *ts, double *msg1, double *msg23, double *midi_bus), void *midi_ctxdata ); ``` ```c // Example MIDI callback implementation double my_midi_callback(void *ctx, int action, double *ts, double *msg1, double *msg23, double *midi_bus) { // action: -1 = receive, 1 = send, 2 = sysex if (action == -1) { // Provide next MIDI event to the effect // Return > 0 if event available, set ts/msg1/msg23 *ts = 0.0; // Timestamp *msg1 = 0x90; // Note On *msg23 = 60 | (100 << 8); // Note 60, velocity 100 return 1.0; } else if (action == 1) { // Effect is sending a MIDI event printf("MIDI out: status=%d data=%d\n", (int)*msg1, (int)*msg23); return 1.0; } return 0.0; } ``` ```c sx_set_midi_ctx(effect, my_midi_callback, myMidiContext); ``` -------------------------------- ### JSFX File I/O Operations Source: https://context7.com/justinfrankel/jsfx/llms.txt Demonstrates reading various file types (audio, text, raw) and serializing state using JSFX file functions. Ensure files are opened and closed properly. ```eel // JSFX script example - File operations @init // Open a file from slider selection fh = file_open(slider1); // slider1 is a file slider fh >= 0 ? ( // Get file info for audio files file_riff(fh, num_channels, sample_rate); // Read samples into memory samples_read = file_mem(fh, buffer_address, num_samples); // Check remaining data remaining = file_avail(fh); // Rewind to start file_rewind(fh); // Close when done file_close(fh); ); // Read text file fh = file_open(#filename); fh >= 0 ? ( file_text(fh) ? ( // Check if text mode // Read line by line while (file_avail(fh)) ( file_string(fh, #line); // Process #line string ); ); file_close(fh); ); // Read single values fh = file_open(slider1); fh >= 0 ? ( file_var(fh, value1); // Read one float file_var(fh, value2); file_close(fh); ); // Serialize state (@serialize section) @serialize file_var(0, saved_state1); file_var(0, saved_state2); file_mem(0, buffer, buffer_size); file_string(0, #saved_string); ``` -------------------------------- ### Query Pin Configuration Source: https://context7.com/justinfrankel/jsfx/llms.txt Retrieve information about the effect's audio input and output pin names using sx_getPinInfo. The function returns an array of strings and the number of pins. ```c const char **sx_getPinInfo(SX_Instance *sx, int isOutput, int *numPins); ``` ```c // Example: Query pin configuration int numInputs, numOutputs; const char **inputPins = sx_getPinInfo(effect, 0, &numInputs); const char **outputPins = sx_getPinInfo(effect, 1, &numOutputs); printf("Input pins (%d):\n", numInputs); for (int i = 0; i < numInputs && inputPins; i++) { printf(" %d: %s\n", i, inputPins[i]); } printf("Output pins (%d):\n", numOutputs); for (int i = 0; i < numOutputs && outputPins; i++) { printf(" %d: %s\n", i, outputPins[i]); } ``` -------------------------------- ### JSFX Simple Gain/Pan Effect Source: https://context7.com/justinfrankel/jsfx/llms.txt This JSFX script creates a complete audio effect with sliders for gain and pan, mute functionality, and a graphical display showing input/output levels and parameter values. It uses smoothing for parameter changes and constant power panning. ```eel desc:Simple Gain and Pan //tags: utility gain pan //author: Example slider1:0<-60,12,0.1>Gain (dB) slider2:0<-100,100,1>Pan (%) slider3:0<0,1,1{Off,On}>Mute in_pin:left input in_pin:right input out_pin:left output out_pin:right output @init // Initialize variables gain_smooth = 1.0; pan_l_smooth = 1.0; pan_r_smooth = 1.0; smooth_coef = 0.995; @slider // Convert dB to linear gain target_gain = slider3 ? 0 : 10^(slider1/20); // Calculate pan (constant power) pan_pos = (slider2 + 100) / 200; // 0 to 1 target_pan_l = cos(pan_pos * $pi/2); target_pan_r = sin(pan_pos * $pi/2); @block // Smooth parameter changes per block gain_smooth = gain_smooth * smooth_coef + target_gain * (1 - smooth_coef); pan_l_smooth = pan_l_smooth * smooth_coef + target_pan_l * (1 - smooth_coef); pan_r_smooth = pan_r_smooth * smooth_coef + target_pan_r * (1 - smooth_coef); @sample // Apply gain and pan mono = (spl0 + spl1) * 0.5 * gain_smooth; spl0 = mono * pan_l_smooth; spl1 = mono * pan_r_smooth; // Track peak levels for metering peak_l = max(peak_l * 0.9995, abs(spl0)); peak_r = max(peak_r * 0.9995, abs(spl1)); @gfx 200 100 // Background gfx_clear = 0x303030; // Draw meters meter_h = 80; meter_w = 20; // Left meter gfx_r = 0.2; gfx_g = 0.8; gfx_b = 0.2; level_l = min(1, peak_l) * meter_h; gfx_rect(20, 10 + meter_h - level_l, meter_w, level_l); // Right meter level_r = min(1, peak_r) * meter_h; gfx_rect(50, 10 + meter_h - level_r, meter_w, level_r); // Labels gfx_r = gfx_g = gfx_b = 1; gfx_x = 20; gfx_y = 92; gfx_drawstr("L R"); // Gain display gfx_x = 100; gfx_y = 30; gfx_printf("Gain: %.1f dB", slider1); // Pan display gfx_x = 100; gfx_y = 50; slider2 < 0 ? gfx_printf("Pan: %d%% L", -slider2) : slider2 > 0 ? gfx_printf("Pan: %d%% R", slider2) : gfx_drawstr("Pan: Center"); ``` -------------------------------- ### JSFX Math Functions Source: https://context7.com/justinfrankel/jsfx/llms.txt Utilize these functions for trigonometric, logarithmic, exponential, and other common mathematical operations in audio DSP. ```eel // JSFX script example - Basic math operations @init // Trigonometric functions (angles in radians) angle = $pi / 4; // 45 degrees sine_val = sin(angle); cosine_val = cos(angle); tangent_val = tan(angle); // Inverse trigonometric asin_val = asin(0.5); // Returns radians acos_val = acos(0.5); atan_val = atan(1.0); atan2_val = atan2(1.0, 1.0); // atan2(y, x) // Logarithmic and exponential log_val = log(2.718); // Natural log log10_val = log10(100); // Base-10 log exp_val = exp(1.0); // e^1 // Other math sqrt_val = sqrt(16); // 4.0 sqr_val = sqr(4); // 16.0 (square) abs_val = abs(-5.0); // 5.0 sign_val = sign(-3.0); // -1.0 min_val = min(a, b); // Minimum max_val = max(a, b); // Maximum floor_val = floor(3.7); // 3.0 ceil_val = ceil(3.1); // 4.0 invsqrt_val = invsqrt(4); // ~0.5 (fast approximation) // Random number generation random_val = rand(100); // Random 0 to 100 ``` -------------------------------- ### JSFX MIDI Receive and Send Source: https://context7.com/justinfrankel/jsfx/llms.txt Process incoming MIDI messages and send MIDI out from scripts. Supports both 2 and 4-parameter `midirecv` and buffer/string-based sending. ```eel // JSFX script example - MIDI processing @block // Receive MIDI messages while (midirecv(offset, msg1, msg23)) ( status = msg1 & 0xF0; channel = msg1 & 0x0F; data1 = msg23 & 0xFF; data2 = (msg23 >> 8) & 0xFF; status == 0x90 && data2 > 0 ? ( // Note On note_number = data1; velocity = data2; // Process note on ) : status == 0x80 || (status == 0x90 && data2 == 0) ? ( // Note Off note_number = data1; // Process note off ) : status == 0xB0 ? ( // Control Change cc_number = data1; cc_value = data2; // Process CC ); // Pass through MIDI midisend(offset, msg1, msg23); ); // Alternative 4-parameter version while (midirecv(offset, msg1, data1, data2)) ( // msg1 = status byte // data1 = first data byte // data2 = second data byte midisend(offset, msg1, data1, data2); ); // Send MIDI from script @sample trigger_note ? ( midisend(0, 0x90, 60 | (100 << 8)); // Note On, C4, velocity 100 trigger_note = 0; ); // Buffer-based MIDI (for sysex or variable length) midisend_buf(offset, buffer_address, length); midirecv_buf(offset, buffer_address, max_length); // String-based MIDI midisend_str(offset, #midi_string); midirecv_str(offset, #midi_string); ``` -------------------------------- ### JSFX API - Processing Audio Samples Source: https://context7.com/justinfrankel/jsfx/llms.txt Processes a block of audio samples through the loaded JSFX effect, applying real-time audio transformations. ```APIDOC ## Processing Audio Samples (sx_processSamples) ### Description Processes a block of audio samples through the JSFX effect. This function handles block-based processing, executes @block and @sample sections, and applies wet/dry mixing. ### Method `sx_processSamples` ### Parameters - **sx** (SX_Instance *) - Required - Pointer to the JSFX instance. - **buf** (double *) - Required - Interleaved audio buffer containing the audio samples. - **cnt** (int) - Required - The number of samples per channel to process. - **nch** (int) - Required - The number of audio channels. - **srate** (int) - Required - The sample rate in Hz. - **tempo** (double) - Required - The current tempo in Beats Per Minute (BPM). - **tsnum** (int) - Required - The numerator of the current time signature. - **tsdenom** (int) - Required - The denominator of the current time signature. - **playstate** (double) - Required - The current playback state (e.g., 0=stopped, 1=playing). - **playpos** (double) - Required - The current playback position in seconds. - **playpos_b** (double) - Required - The current playback position in beats. - **lastwet** (double) - Required - The wet mix value from the previous processing block (0.0 to 1.0). - **wet** (double) - Required - The target wet mix value for the current block (0.0 to 1.0). - **flags** (int) - Optional - Flags to modify processing behavior (e.g., 1=ignore PDC, 2=delta solo, 4=zero output). ### Return Value - **int** - Returns 0 on success, or a negative value on error. ### Request Example ```c // Example: Process stereo audio at 44100 Hz double audioBuffer[2 * 512]; // 512 samples, stereo memset(audioBuffer, 0, sizeof(audioBuffer)); // Fill buffer with test signal for (int i = 0; i < 512; i++) { audioBuffer[i * 2] = sin(2.0 * M_PI * 440.0 * i / 44100.0) * 0.5; // Left audioBuffer[i * 2 + 1] = sin(2.0 * M_PI * 440.0 * i / 44100.0) * 0.5; // Right } int result = sx_processSamples( effect, audioBuffer, 512, // samples 2, // stereo 44100, // sample rate 120.0, // tempo 4, 4, // time signature 4/4 1.0, // playing 0.0, 0.0, // position 1.0, 1.0, // full wet 0 // no special flags ); ``` ``` -------------------------------- ### JSFX Slider Management Source: https://context7.com/justinfrankel/jsfx/llms.txt Shows how to access, modify, and automate JSFX sliders, including sample-accurate changes and copying slider text. Use `sliderchange` to notify the host of parameter updates. ```eel // JSFX script example - Slider operations @slider // Access slider value directly slider1; // Direct access // Access slider by number value = slider(1); // Same as slider1 // Notify host of slider changes sliderchange(slider1); // Single slider by reference sliderchange(2^0 | 2^1); // Sliders 1 and 2 by bitmask sliderchange(-1); // All sliders // Automation support slider_automate(slider1); // Report automation slider_automate(slider1, 1); // End automation gesture // Show/hide sliders slider_show(slider1, 1); // Show slider_show(slider1, 0); // Hide slider_show(slider1, -1); // Toggle visible_mask = slider_show(2^0 | 2^1); // Query visibility // Sample-accurate parameter changes @block next_offset = slider_next_chg(slider1, next_value); next_offset >= 0 ? ( // Parameter change at sample offset next_offset // Value will be next_value ); // Copy slider text to string strcpy_fromslider(#str, slider1); ``` -------------------------------- ### JSFX Control Flow Source: https://context7.com/justinfrankel/jsfx/llms.txt Implement looping and conditional logic using `while`, `loop`, and ternary operators. Supports complex conditional blocks. ```eel // JSFX script example - Control flow @sample // While loop i = 0; while (i < 10) ( buffer[i] = sin(i * 0.1); i += 1; ); // Alternative while syntax i = 0; while ( buffer[i] = sin(i * 0.1); i += 1; i < 10 // Continue condition ); // Loop with count loop(100, // Execute 100 times sum += rand(1); ); // Conditional expressions value = condition ? true_value : false_value; // Complex conditionals input > threshold ? ( // Above threshold processing output = input * ratio; gain_reduction = input - output; ) : ( // Below threshold output = input; gain_reduction = 0; ); ``` -------------------------------- ### JSFX Memory Management Source: https://context7.com/justinfrankel/jsfx/llms.txt Functions for allocating, initializing, copying, and manipulating memory buffers. Use `freembuf` to hint at unused memory. ```eel // JSFX script example - Memory operations @init // Allocate and initialize buffers buffer_size = 4096; delay_buffer = 0; // Start address for delay buffer // Initialize buffer to zero memset(delay_buffer, 0, buffer_size); // Copy data between buffers src_buffer = 10000; dst_buffer = 20000; memcpy(dst_buffer, src_buffer, 1024); // Bulk read/write values mem_set_values(0, val1, val2, val3, val4); // Write multiple values mem_get_values(0, v1, v2, v3, v4); // Read multiple values // Compute sum of products (dot product) result = mem_multiply_sum(buffer1, buffer2, length); // Special cases: sum_of_squares = mem_multiply_sum(-1, buffer, length); sum_of_abs = mem_multiply_sum(-2, buffer, length); sum_of_vals = mem_multiply_sum(-3, buffer, length); // Insert value into buffer (shift right) oldest = mem_insert_shuffle(buffer, length, new_value); // Stack operations stack_push(value); popped = stack_pop(variable); top_val = stack_peek(0); // Peek at top nth_val = stack_peek(3); // Peek at 3rd item stack_exch(variable); // Exchange with top // Release unused memory freembuf(1000); // Hint that memory above 1000 is unused ``` -------------------------------- ### Localize String with Format Specifier Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Use this macro when the localizable string contains format specifiers. The macro expands to a format string that can be used with snprintf. ```cpp snprintf(buf,sizeof(buf),__LOCALIZE_VERFMT("This has %d items","section"),6); ``` -------------------------------- ### Process Audio Samples Source: https://context7.com/justinfrankel/jsfx/llms.txt Processes a block of audio samples through the JSFX effect. This function handles real-time audio processing, including wet/dry mixing and applying effects based on various playback states and parameters. Ensure the audio buffer is correctly interleaved and sized according to `cnt` and `nch`. ```c int sx_processSamples( SX_Instance *sx, double *buf, // Interleaved audio buffer int cnt, // Number of samples per channel int nch, // Number of channels int srate, // Sample rate in Hz double tempo, // Current tempo in BPM int tsnum, // Time signature numerator int tsdenom, // Time signature denominator double playstate, // Play state (0=stopped, 1=playing, etc.) double playpos, // Play position in seconds double playpos_b, // Play position in beats double lastwet, // Previous wet mix (0.0-1.0) double wet, // Target wet mix (0.0-1.0) int flags // Flags: 1=ignore PDC, 2=delta solo, 4=zero output ); // Example: Process stereo audio at 44100 Hz double audioBuffer[2 * 512]; // 512 samples, stereo memset(audioBuffer, 0, sizeof(audioBuffer)); // Fill buffer with test signal for (int i = 0; i < 512; i++) { audioBuffer[i * 2] = sin(2.0 * M_PI * 440.0 * i / 44100.0) * 0.5; // Left audioBuffer[i * 2 + 1] = sin(2.0 * M_PI * 440.0 * i / 44100.0) * 0.5; // Right } int result = sx_processSamples( effect, audioBuffer, 512, // samples 2, // stereo 44100, // sample rate 120.0, // tempo 4, 4, // time signature 4/4 1.0, // playing 0.0, 0.0, // position 1.0, 1.0, // full wet 0 // no special flags ); ``` -------------------------------- ### Localize String (No Cache) Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Use this macro for strings that might be accessed from threads other than the main thread or from unloadable modules. It prevents caching. ```cpp __LOCALIZE_NOCACHE("my string","section"); ``` -------------------------------- ### Localize String from Table Entry Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt Use this function to localize a string pointer, typically from a table. Flags can control caching and format verification. ```cpp __localizeFunc(bar[x].stringptr,flags) ``` -------------------------------- ### Cache Localized String Source: https://github.com/justinfrankel/jsfx/blob/main/WDL/localize/localize-info.txt For performance-sensitive code, you can cache the result of a localization lookup by assigning it to a static variable. ```cpp static const char *msg; if (!msg) msg = __LOCALIZE_NOCACHE("whatever","section"); ```