Overview
Rhapsodist is a collection of HISE scripts for building expansions for the Rhapsody Player from Libre Wave.
One of the aims with Rhapsodist is to minimise the amount of script that needs to be written to create a HISE project. In many situations no scripting is required beyond creating a configuration file and setting up a few includes.
However for more custom behaviour Rhapsodist is flexible and provides many entry points and overrides to integrate with your own scripts.
Who This Documentation Is For
Developers who already know HISE scripting, but are new to Rhapsodist’s architecture and conventions. It explains how the system fits together and how to use it. The Rhapsodist source remains the authoritative reference for implementation detail.
How To Use This Documentation
File-level pages follow a common layout: an overview, a usage example, an options table (if the file takes one), a Public API table, and, where relevant, an Internal Reference table.
Internal Reference documents a file’s non-public functions for context. These aren’t part of the public API, may change without notice, and shouldn’t be called from custom scripts.
Terminology
- Expansion: A HISE Full Instrument Expansion for Rhapsody.
- Patch: An individual patch (usually a separate instrument) within an expansion. With its own sample maps, articulations, and configuration.
- Articulation: A rule set within a patch that dynamically alters the configuration of the expansion. Most commonly used for selecting the active sample set.
- Module: Any element that can be added in HISE’s module tree. This includes MIDI processors, effects, modulators, etc.
Important
To use Rhapsodist you need to already be familiar with working in HISE and with HISE script. A complete, and free of charge, beginners’ HISE course is available here.
What Rhapsodist provides
Rhapsodist provides a complete toolkit of reusable modules, processors, and script libraries that accelerate instrument development in HISE. It implements a layered architecture with clear separation between:
-
Core - The foundational infrastructure that every project needs.
-
Includes - Shared libraries for articulation management, mixer handling, and more.
-
A shell UI (header, footer, preset browser, settings window, on-screen keyboard, preload bar, zoom controls). So every expansion gets consistent player chrome.
-
A patch/articulation configuration system that reads a developer-supplied
Manifestdescribing an expansion, its patches, and articulations, and applies module attributes, sample maps, and component properties accordingly. -
A set of reusable MIDI processors for common sample-patch needs: round robin, legato/portamento, release triggers, velocity shaping, note filtering, microtuning, and more. Dropped into a sampler’s or container’s MIDI processor chain as needed.
-
A set of UI widgets for rapidly building interfaces: articulation lists, mixers, EQ panels, envelope controls, microtuning panels, harp pedal diagrams, and more.
-
A consistent Look and Feel system with overridable drawing functions, so an expansion can restyle the shell or widgets by redeclaring functions without touching the Rhapsodist source.
Core Design Principles
- Configuration - Instruments are defined declaratively via JSON data.
- Broadcasters - Decoupled communication through HISE’s broadcaster system. This increases the modularity and flexibility of the framework.
- Namespaces as Modules - Each file exports a single namespace encapsulating its functionality.
What Rhapsodist Is Not
Not a single monolithic framework, it’s a set of independent-but-cooperating HISE script includes and standalone processor scripts that can work together.
Understanding it means understanding how these pieces connect, not just what each file does in isolation, see Architecture.
Requirements
Rhapsodist requires David Healey’s fork of HISE (master branch), not upstream HISE. The fork carries features Rhapsodist depends on and the preprocessor definitions Rhapsody itself is built with.
Precompiled binaries for each OS are available from the fork’s nightly release, so there’s no need to compile anything.
Licensing
A Rhapsody expansion isn’t a compiled, closed HISE project, it can always be extracted back into an ordinary HISE project.
There’s no practical way to conceal an expansion’s scripts or configuration. DRM or similar access-restriction schemes won’t work in a Rhapsody expansion by design.
Code written for use with the Rhapsodist API should be released under GPLv3, matching Rhapsodist’s own license.
Sample content is separate and can be released under a less permissive license.
A Note on ScriptNode Networks
Expansions aren’t compiled projects and therefore can’t include compiled ScriptNode networks that aren’t already compiled into Rhapsody. So you can only use uncompiled networks when creating an expansion.
This is rarely an issue for small networks, but a large or complex uncompiled network could cause performance problems, since it runs without a compiled network’s optimisations.
For the same reason, Faust isn’t currently compatible with Rhapsody either.
Installation
Rhapsodist is distributed as a HISE asset, installed through HISE’s asset manager (File > Open HISE Asset Manager). The asset manager keeps a list of packages you can install into a project, tracks which version of each one is installed, and lets you update or remove them later.
A future HISE Store will let you browse and install assets like Rhapsodist directly from within HISE. Until then, you point the asset manager at a local folder containing the asset, as set up below.
Set Up The Asset Source
Clone the Rhapsodist repository to a folder on your system where you keep local HISE assets:
git clone https://github.com/LibreWaveAudio/Rhapsodist.git
Then register that folder with the asset manager:
- Open the asset manager (File > Open HISE Asset Manager).
- Click Add local folders to this list to create assets at the bottom of the package list.
- Select the
package_install.jsonfile at the root of the cloned repository.
The asset manager reads Rhapsodist’s metadata from that file and adds it to the package list, ready to install. See the asset manager guidelines for more detail on the asset manager itself.
Install Into A Project
Open the asset manager in your project and click Install next to Rhapsodist. This copies the Rhapsodist framework into your project.
Each project gets its own copy of Rhapsodist’s files, tracked in that project’s own git repository, at whatever version was installed at the time.
Rather than installing Rhapsodist into a blank HISE project, it’s easier to start from one of the Templates, then install Rhapsodist into that instead.
Updating
When a new version of Rhapsodist is available, pull the latest changes into your local clone. The asset manager marks Rhapsodist with a blue dot in your project, and the button next to it changes to Update to [version]; click it to update.
If an update doesn’t apply cleanly, click Uninstall [version] next to Rhapsodist in the asset manager, then install it again.
Templates
The RhapsodistTemplates repository provides starter Rhapsody template projects.
They serve two purposes: a starting point for your own project, and a set of working examples of how the framework is intended to be used.
Before starting your own project, it’s worth spending some time with each template, comparing how they differ, and experimenting with them to see how the pieces fit together.
Setup
A template doesn’t come with Rhapsodist installed. Open the template project in HISE, then use the asset manager to install Rhapsodist into it, same as you would for a project of your own.
Overview
Minimal
A blank canvas providing just the essentials for building a Rhapsody project: a Look and Feel file with a function for drawing the logo, a Styles file with the basic colour theme, and a Manifest with placeholders.
Basic
Built on top of the Minimal template. Adds some UI controls, and contains two samplers to demonstrate basic articulation switching.
The UI includes velocity scaling, a flex AHDSR, an articulation list, an expression knob, and vibrato knobs.
The expression knob is connected to a CC gain modulator. The vibrato knobs control a global LFO, connected to the gain and pitch of the samplers.
Content has been added to the manifest to make the articulation switching functional and demonstrate other elements.
Multimic
The same as Basic, with multi-mic routing added, making use of the Mixer module and MixerPanel interface component. It also shows how to build a tabbed Card by nesting panels for the expression and vibrato controls.
Hero
A simplified “concept” interface: a hero image and four knobs.
Conventions
Rhapsodist’s source follows a HISE Script house style which you should also follow.
The purpose of a house style is to make the codebase consistent - it should look like everything was written by a single person. This makes it easier to understand, debug, and maintain.
Below is a quick reference of the most important points. For a full and detailed style guide follow the official HISE Script Coding Standards.
Namespaces
Namespaces should use PascalCase. Each namespace should be in a separate file with the same name as the namespace.
Don’t create namespaces that conflict with HISE’s built-in classes or with Rhapsodist’s namespaces. For example a namespace called Settings would trigger issues, as HISE already includes a class of the same name. Instead use something like CustomSettings.
If you want to be extra safe you could use a custom prefix for your own namespaces.
Functions
Use inline functions whenever possible. There are some situations in HISE script where they can’t be used but if they can be they should.
Function declarations should enforce Type Safety. The rare exception is when an undefined type is expected.
Functions should accept no more than five parameters. If it needs more, pass an object or an array, or consider splitting the function into multiple smaller units.
Recursion
HISE supports recursive functions but they should be used sparingly as they are often a cause of unexpected behaviour.
Variable declarations
localinside aninline functionor stock callback.varinside afunction.constfor fixed values, arrays, and objects declared outside any function. Favour MIDI lists over arrays for related MIDI values.regfor mutable, non-function-scoped namespace-level variables.globalvariables should never be used.- Loop iterator variables need no declaration, HISE Script infers them.
Components
Components on the main interface should be added through the interface designer rather than through scripting.
When you do need references to a component in your script you should use the following format:
//! btnAction
const btnAction = Content.getComponent("btnAction");
Component references should be declared upfront in on init never within a function or callback.
Braces
Allman-style: the opening brace goes on its own line.
A single-statement if/for body is typically left unbraced on its own indented line, rather than wrapped in { }.
Naming
- PascalCase for namespaces.
- camelCase for variables, functions, and most component IDs
- Component IDs follow a type-prefix convention:
| Prefix | Component or Variable Type |
|---|---|
pnl | Panel |
btn | Button |
knb | Slider or Knob |
cmb | ComboBox |
slp | SliderPack |
tbl | Table |
vpt | Viewport |
flt | FloatingTile |
bc | Broadcaster variables |
laf | Local look-and-feel variables |
Comments
In general code should be self-documenting and the use of comments should be avoided. If a function name doesn’t adequately describe what the function does and leads you to write an explanatory comment, that’s probably a good sign that the function should be split into multiple smaller units instead.
Section dividers use a //! marker for a logical block (a component, a function group), worth following for readability in larger files, this allows for quick navigation within the HISE script editor.
When used, comments should not narrate what self-explanatory code does, instead they should be used for non-obvious why.
Source File Headers
The top of each script should include a license header. You can copy the header from one of the Rhapsodist files as a starting point.
For the purposes of documentation it can be helpful to include a short header comment near the top of each file after the license header.
The preferred format:
/*
@name: ScriptName
@purpose: Brief description of what the script provides.
@entry: create()
@usage: How the to make use of the script.
@notes: Any additional relevant information.
*/
It should be brief: enough to orient a developer or an AI system to the file’s role, without documenting the full implementation.
Architecture
Understanding how Rhapsodist is structured helps you navigate the codebase and extend it effectively. This document gives a high-level overview of the architecture of Rhapsodist.
Scripts Directory Structure
Scripts/
├── App/ # Application-level customization
│ ├── Manifest.js # Instrument configuration data
│ ├── Style.js # Visual styling
│ └── LookAndFeel.js # Custom drawing overrides
├── Rhapsodist/
│ ├── Core/ # Foundation modules (load first)
│ │ ├── Core.js # Entry point, engine setup
│ │ ├── Includes/ # Core supporting modules
│ │ ├── Widgets/ # Core UI components
│ │ ├── Processors/ # Core MIDI processors
│ │ └── ScriptFX/ # Scripted effect processors
│ ├── Widgets/ # General-purpose widgets
│ ├── Includes/ # Shared libraries
│ └── Processors/ # MIDI processing scripts
└── ScriptProcessors/ # HISE ScriptProcessor slots
└── expansion-name/
└── Interface.js # Main interface script entry
Core.js
Core/Core.js is the entry point for the Rhapsodist framework in your project.
Include it in your Interface.js script and click compile. This will trigger the setup functions in Rhapsodist that will create the basic user interface.
The first time you click compile you will see some error messages in the Console about missing components - don’t worry, that’s expected since the components don’t yet exist. Clear the Console and click compile a second time to complete the setup.
include("Rhapsodist/Core/Core.js");
Core Includes and Widgets
Core.js itself includes several other essential files from the Core/Includes and Core/Widgets folders. These provide features such as the header, footer, settings panel, preset browser, and tooltips, among much else.
You never need to manually include any files from the Core/Includes folder but you may want to interface with them from your own scripts, so it’s a good idea to look through them and read the core documentation.
Core Processors and ScriptFX
The Core folder also contains Processors and ScriptFX. These files are essential to most Rhapsodist expansions and need to be added to your project’s module tree. If you’re building off one of the templates then these files will already be present.
Includes, Processors, and Widgets
These three folders provide optional interface include scripts and MIDI processors that you can use in your projects.
For the most part they have been built as standalone modules, but some are designed to be able to work together.
UI and Processor Relationships
Following HISE best practices, the interface script processor is deferred by Core.js.
As such no MIDI or audio processing is handled directly by the interface script or its includes. The interface exists only to provide a point of feedback and interaction for the end user.
The actual processing is handled by separate modules, either stock HISE modules, modules you create yourself, or those provided by Rhapsodist.
This table lists some of the most common pairings:
| Widget | Paired Processors | Connection |
|---|---|---|
| ArticulationList | ArticulationGain.js | slpArticulationGain bound via processorId |
| MixerPanel | Mixer.js | Bound via processorId/parameterId |
| EnvelopePanel | AhdsrController.js, Flex AHDSR modulator | Knobs bound via processorId/parameterId; floating tile and drag broadcaster bound to flexEnvelopeId |
| EqPanel | Parametric EQ effect | floating tile Data references effectId directly |
| HarpPedalPanel | NoteTransposer.js | Writes to the sliderpack directly |
| VelocityTable | VelocityScaler.js | Table’s processorId/tableIndex properties |
| MicrotuningPanel | Microtuner.js | slpMicrotune sliderpack bound via processorId/SliderPackIndex |
The interface scripts and the modules can work independently or paired together, as described above. Because of this you can create custom interfaces for existing modules or use the existing interface to connect to a custom module.
Some scripts are more flexible than others in this regard and I suggest using the existing scripts as a starting point if you intend to create custom versions.
Component Hierarchy
The UI is structured as nested panels with specific roles:
pnlMain (root)
├── pnlHeader (fixed 50px)
│ ├── knbPatch (hidden, patch selection)
│ ├── knbArticulation (hidden, articulation)
│ ├── pnlPresetDisplay (preset browser controls)
│ ├── knbMasterPan / knbMasterVolume (header controls)
│ └── btnSettings (settings toggle)
├── pnlBody (flexible, instrument UI)
│ └── [Application-specific content]
├── pnlFooter (fixed 100px)
│ ├── fltPerformanceLabel (CPU/RAM/Voices)
│ ├── pnlLogo (company branding)
│ └── fltKeyboard (virtual keyboard)
├── pnlPresetBrowserContainer (overlay)
├── pnlSettingsContainer (overlay)
└── pnlTooltip (hover info)
App
Each project should have an App folder within its Scripts folder. App is not part of Rhapsodist but is a location for keeping files specific to each project.
Such files include custom look and feel, preset preprocessors, theming, and any other scripts that are unique to the project.
If you have scripts you want to share between projects you should consider using the Global Scripts Folder or HISE’s asset manager.
Manifest
The Scripts/App folder must contain a Manifest.js file. This is a critical script that is used throughout the framework. It provides the configuration for your expansion, patches, and articulations.
Patch and Articulation Changes
The interface shell UI contains two hidden knobs: knbPatch and knbArticulation. These keep track of the current patch and articulation respectively. They also save and restore with the user preset.
Both knobs are connected directly to two matching knobs in the ConfigurationHandler module. When a preset loads, the patch knob will fire, in turn this will trigger the ConfigurationHandler to load the configuration for the current patch from Manifest.js.
When an articulation is changed by clicking in the articulation list on the interface this will trigger a change of value for knbArticulation which will also cause the ConfigurationHandler's articulation knob to fire its callback and load the articulation’s configuration from the Manifest.
If you want to implement a custom articulation selector on the interface, it must update knbArticulation in order for the ConfigurationHandler to be able to respond to it.
When changing articulation by MIDI (key switches, CC, or bank/program change) the interface is not part of the process, as it is deferred. Here articulation switching is handled entirely by the ConfigurationHandler, which in turn will update its patch and articulation knobs.
The interface script should also respond to articulation change triggers for the purposes of updating the UI. ArticulationSwitcher.js provides onNoteOn and onController functions for this purpose that can be dropped into the appropriate MIDI callbacks.
Additionally all patch and articulation changes are broadcast on global cables (patch and articulation).
If you’re adding a feature that needs to react to a patch or articulation change, attach your own broadcaster to the shell’s knbPatch/knbArticulation (Interface script) or the patch/articulation global cable (separate module script).
Broadcasters
Internally, Rhapsodist uses HISE’s broadcaster system extensively for decoupled communication.
Project Files
App/ holds your project’s own script files, separate from the Rhapsodist framework itself but referred to by it: Rhapsodist reads them for configuration and looks to them for override hooks, rather than including them as part of its own source.
A project typically has:
- Manifest (
App/Manifest.js), the expansion’s patch/articulation configuration. - App.js (
App/App.js), the entry point for project-specific initialisation and customisation. App/Styles.js, an optional theme definition, see Styles & Theming.App/LookAndFeel.js, optional Look and Feel overrides, see Core Look and Feel.App/UserPresetProcessor.js, an optional user preset migration script, see Presets.
Include order matters: Manifest, then Styles, then LookAndFeel, then Core.js, with App.js included last, after all other Rhapsodist includes.
The Manifest
The App/Manifest.js file defines the internal structure of an expansion. Every field it contains is optional based on the requirements of the project. The file contains a single JSON object called Manifest.
How it’s Used
The Manifest is used in several parts of Rhapsodist. Most importantly it is used by the Configuration Handler and the Component Handler.
If you need custom configuration values for your own scripts you can extend the Manifest as needed to accommodate that.
Configuration Handler
The Configuration Handler is a script module that sits below the Interface in the module tree.
It is responsible for updating the settings of other modules when an expansion loads, the patch changes, or an articulation is activated.
Component Handler
The Component Handler is included in the Interface as part of Core.js. It is responsible for updating the state of the user interface when the patch changes, or an articulation is activated.
When one of these events occurs it reads the values from the Manifest and applies them to the UI.
Levels
The configuration is separated into three levels: Expansion, Patch, and Articulation.
Expansion level values apply to the entire expansion, including every patch and articulation.
Patch level values apply to each patch and their articulations.
The articulation level values affect only individual articulations.
Expansion Level
Typically at this level the Manifest will specify the sample maps and sampler or sound generator settings used by the expansion.
This is also a good place to define default articulation settings, if the same articulations are used by multiple patches.
A Manifest can only contain one set of expansion level settings.
Patch Level
A Manifest can contain one or more patches. A patch defines a set of values that are loaded based on the value of the hidden knbPatch knob.
Typically patches are used to define different instruments within an expansion. For example a brass library might contain separate patches for trumpet, trombone, french horn, and tuba. However, it doesn’t have to be strictly used for this purpose.
Common values for the patch level are sample maps, key ranges, and gain level.
Articulation Level
Each patch can contain one or more articulations. An articulation is another set of configuration values, this time applied based on the value of the hidden knbArticulation knob.
This is typically used with key switches to allow a user to switch articulations. For example, a trumpet patch might contain separate articulations for sustain, staccato, and trills.
At the articulation level it’s not possible to specify sample maps, because samples cannot be swapped in real-time.
Common settings for articulations are a sampler’s active group, effects values, round robin settings, and enabling or disabling UI components.
Articulations can be defined at the expansion level when they are shared by multiple patches. This reduces the repetition of defining the same articulation for each patch.
A Defaults articulation can be defined with fallback values that are used as defaults by all articulations. Individual articulations can then override these defaults. The Defaults articulation is not displayed in the articulation list.
One use case for Defaults is toggling a UI component that is used by only some articulations. For example a trumpet patch might enable a Dynamics crossfade knob for its sustain articulation but disable it for all other articulations.
Manifest Property Schema
The Manifest is a single JSON style object that contains sets of key/value pairs. In many cases the values are themselves are arrays of objects.
Common keys include scripts/modulators/effects/samplers with values that are arrays of {id, properties} objects.
Each entry unbypasses its target module and applies every key in properties as an attribute. Most property names match the target module’s own attribute names, but a few are special-cases:
| Property | Effect |
|---|---|
Bypass | Bypasses/unbypasses the module |
Gain | Sets gain; on a Sampler the value is treated as dB. |
Intensity | Sets a modulator’s intensity |
File | Loads an Audio Sample Processor’s file via the expansion’s wildcard reference |
Table | Restores a table processor from base64 |
Bipolar | Sets whether a modulator is bipolar |
CrossfadeTable / CrossfadeGroups | Restores explicit sampler crossfade tables, or auto-generates evenly spaced ones for the given group count |
Ignore | Skips this entry entirely, letting a patch/articulation opt a module out of a configuration pass without deleting it |
Example Usage
Here is an example Manifest with comments describing what each part does. This is an abridged version of the Manifest used by the Bell and Bone expansion.
It contains two patches, Trombone and Trumpet. Each of which has its own settings.
At the expansion level it defines effects settings and articulations that are used by both patches.
The trumpet patch also defines some additional articulations that are unique to it.
const Manifest = { // Manifest object
effects: [ // Expansion level effects values - can be overridden by patches and articulations
{
id: "convolutionReverb0", // ID of the effect in the module tree
properties: {Ignore: true} // Property and value to set
}
],
articulations: [ // Expansion level articulations - shared by all patches
{
id: "Defaults", // ID is "Defaults" this is the fallback that can be overridden by individual articulations
components: [ // Component values
{
id: "knbVibratoRate", // ID of the UI component
properties: {enabled: false} // Property and values to set
},
{
id: "knbVibratoDepth",
properties: {enabled: false}
},
{
id: "knbDynamics",
properties: {enabled: false}
}
]
},
{
id: "Performance", // Performance articulation
muters: [0], // Which MIDI muters to keep enabled (unmuted) - every other muter is muted. Used by the Configuration Handler.
components: [ // Component properties for this articulation. Overrides those set in "Defaults"
{
id: "knbVibratoRate",
properties: {enabled: true}
},
{
id: "knbVibratoDepth",
properties: {enabled: true}
},
{
id: "knbDynamics",
properties: {enabled: true}
}
]
},
{
id: "Staccato Fall", // Staccato articulation
gain: -3, // Set a gain offset for this articulation. This will be used by the Articulation Gain module which should be added in the master chain.
muters: [1],
scripts: [ // Script (MIDI Processor) settings
{
id: "sampler1RoundRobin", // ID of script processor
properties: {FirstGroup: 1, Count: 4, Borrowed: true} // Properties/values
}
]
},
{
id: "Shakes", // Shakes articulation
muters: [1],
scripts: [
{
id: "sampler1RoundRobin",
properties: {FirstGroup: 17, Count: 2, Borrowed: false}
}
]
}
],
patches: [ // Patch configurations
{
id: "Trombone", // Name of patch
gain: 3, // Gain applied to the patchGain effect in the master chain
keyranges: [ // Key colour ranges
{loKey: 24, hiKey: 29, colour: "keyswitch"}, // Colour names (keyswitch/playable/etc) are defined in Styles.js
{loKey: 40, hiKey: 72, colour: "playable"}
],
firstKs: 24, // Keyswitches are added sequentially for each articulation starting from firstKs
samplers: [ // Sampler settings
{
id: "sampler0", // Sampler ID
properties: { // Sampler properties for this patch
VoiceAmount: 96,
VoiceLimit: 64,
SampleMap: "trombone_sustain" // Sample map to load - no .xml required.
}
},
{
id: "sampler1",
properties: {
VoiceAmount: 64,
VoiceLimit: 32,
SampleMap: "trombone_articulations"
}
}
],
scripts: [ // Patch level script (MIDI processor) settings
{
id: "sampler0Legato",
properties: {XfadeTm: 100, BendMinUp: 50, BendMinDn: 50, BendTm: 125}
},
{
id: "noteRangeFilter",
properties: {LowNote: 40, HighNote: 72}
}
],
modulators: [ // Patch level modulator settings
{
id: "sampler0GroupXFTable", // Modulator ID
properties: {Attack: 500} // Settings to use
}
]
}, // End of Trombone Patch
{
id: "Trumpet", // Trumpet patch
keyranges: [ // Different key colour ranges to the trombone
{loKey: 24, hiKey: 30, colour: "keyswitch"},
{loKey: 52, hiKey: 84, colour: "playable"}
],
firstKs: 24,
samplers: [
{
id: "sampler0",
properties: {VoiceAmount: 96, VoiceLimit: 64, SampleMap: "trumpet_sustain"}
},
{
id: "sampler1",
properties: {VoiceAmount: 64, VoiceLimit: 32, SampleMap: "trumpet_articulations"}
}
],
articulations: [ // Articulations used only by the trumpet
{
id: "Doit",
ks: 84, // Set a specific keyswitch
program: 22, // Set a specific program change number
muters: [1],
scripts: [
{
id: "sampler1RoundRobin",
properties: {FirstGroup: 13, Count: 4, Borrowed: false}
}
]
},
{
id: "Rips",
muters: [1],
scripts: [
{
id: "sampler1RoundRobin",
properties: {FirstGroup: 19, Count: 2, Borrowed: false}
}
]
}
],
scripts: [
{
id: "sampler0Legato", // Trumpet has different legato settings
properties: {XfadeTm: 80, BendMinUp: 50, BendMinDn: 60, BendTm: 80}
},
{
id: "noteRangeFilter",
properties: {LowNote: 52, HighNote: 84}
}
],
modulators: [
{
id: "sampler0GroupXFTable",
properties: {Attack: 750}
}
]
}
]
};
App.js
App/App.js
Top-level namespace for project-specific initialisation and customisation.
App.js should be included after all Rhapsodist includes.
Overview
App is a placeholder namespace in App/App.js that serves as the entry point for project-specific code and customisation.
Purpose
This namespace provides a hook point for:
- Custom initialisation - Any setup logic unique to the project
- Override functions - Replacing or extending framework behaviour
- Custom functionality - Adding project-specific functionality
Example Usage
namespace App
{
VelocityTable.create("pnlCard0", "velocityScaler", {});
EnvelopePanel.create("pnlCard1", "ahdsrController", "globalGainFlexAhdsr", {});
ArticulationList.create("pnlCard2", {});
//! knbExpression
const knbExpression = Content.getComponent("knbExpression");
knbExpression.setLocalLookAndFeel(CoreLookAndFeel.knob);
//! knbDynamics
const knbDynamics = Content.getComponent("knbDynamics");
knbDynamics.setLocalLookAndFeel(CoreLookAndFeel.knob);
}
Overview
Rhapsody includes default colour theming, fonts, and look and feel styling. Almost all of which can be easily overridden with your own scripts.
Core look and feel objects and functions are included by Core.js and are accessible through the CoreLookAndFeel namespace.
Custom styling can be defined in an App/Styles.js file. This must be included within on init before Core.js.
An optional App/LookAndFeel.js can be created to load custom fonts, override CoreLookAndFeel functions, or add any custom look and feel scripting you require. This file should be included after Styles.js and before Core.js.
The chapters in this section cover how to use CoreLookAndFeel, Styles, and LookAndFeel in more detail.
Core Look and Feel
File: Rhapsodist/Core/Includes/CoreLookAndFeel.js · Namespace: CoreLookAndFeel
Overview
CoreLookAndFeel is included by Core.js which loads Rhapsodist’s bundled fonts and implements the default drawing for every standard component type.
Widgets included with Rhapsodist’s scripts automatically assign the correct look and feel functions from the CoreLookAndFeel namespace.
You can attach these to your custom components too. For example to add CoreLookAndFeel to a knob on your interface would look like this:
const knbFrequency = Content.getComponent("knbFrequency");
knbFrequency.setLocalLookAndFeel(CoreLookAndFeel.knob);
Overrides
Almost every drawing function checks for a matching override in App/LookAndFeel.js first, and only falls back to its own drawing if none is found:
laf.registerFunction("drawPopupMenuItem", function(g, obj)
{
if (isDefined(LookAndFeel.drawPopupMenuItem))
return LookAndFeel.drawPopupMenuItem();
drawPopupMenuItem();
});
This isDefined(LookAndFeel.xxx) pattern is Rhapsodist’s standard look and feel extension mechanism, used throughout Core and the Widgets, not just here. To restyle a component, declare a same-named function inside namespace LookAndFeel in your project’s App/LookAndFeel.js.
Objects and Overrides
Assign one of these to a component with component.setLocalLookAndFeel(CoreLookAndFeel.xxx). Each one draws a specific HISE component type, and checks the listed LookAndFeel.xxx function(s) for an override before using its own default:
| LAF Object | Assign to | Overrides |
|---|---|---|
knob | rotary ScriptSlider | drawKnob, drawBigKnob, drawSmallKnob |
slider | linear ScriptSlider | drawSlider, drawHorizontalSlider, drawVerticalSlider. |
toggleSwitch | ScriptButton | drawToggleSwitch |
iconButton | ScriptButton (icon, non-toggling) | drawIconButton |
iconButtonToggle | ScriptButton (icon, toggling) | drawIconToggleButton |
textButton | ScriptButton (text, non-toggling) | drawTextButton, falling back to drawTextButtonToggle if that’s the only one defined |
textButtonToggle | ScriptButton (text, toggling) | drawTextButtonToggle |
powerButton | ScriptButton (drawn as a power indicator) | drawPowerButton |
comboBox | ScriptComboBox | drawComboBox for the box itself; its popup uses the shared popup overrides below |
viewport | ScriptedViewport | drawScrollbar (shared, see below) |
peakMeter | ScriptFloatingTile hosting the built-in Matrix Peak Meter | drawMatrixPeakMeter |
table | ScriptTable | drawTableBackground, drawTablePath, drawTablePoint, drawTableRuler |
viewportTable | ScriptFloatingTile hosting a built-in MIDI Learn/Macro panel, or a ScriptedViewport used as a data table (e.g. the Automation MPE table) | drawViewportTableToggleButton, drawViewportTableHeaderBackground, drawTableHeaderColumn, drawTableRowBackground, drawTableCell, drawTableLinearSlider, drawTableScrollbar, drawTableComboBox; its popup uses the shared popup overrides below |
empty | when you want to draw nothing | none, useful for suppressing default painting |
Body
Core.js sets a paint routine on pnlBody and checks LookAndFeel.drawBody for an override, following the standard isDefined(LookAndFeel.xxx) pattern.
Global Look and Feel
Some of elements, such as alert windows, macro tags, and some popup menus require global look and feel instead of local. For these cases CoreLookAndFeel includes a global look and feel object called laf. Overrides are provided.
Popup menus and scrollbars share one override each across every component that shows one, there’s no per-component variant:
drawPopupMenuBackground,drawPopupMenuItem,getIdealPopupMenuItemSize: every popup menu (combo boxes,viewportTable, and HISE’s own alert/macro popups).drawScrollbar: every scrollbar (viewport, andviewportTable’s own scrollbar, which applies its colours first and then falls through to this).
A handful of overrides apply automatically without assigning anything, since they cover HISE’s own built-in popups and overlays rather than a component you place: drawNumberTag (macro tags), drawAlertWindow, getAlertWindowMarkdownStyleData, drawAlertWindowIcon, drawDialogButton (all for the native alert window), and drawPerformanceLabel.
Style dependency
Colours, fonts, and other properties are read from CoreLookAndFeel.style, populated by StyleHandler before anything else in Core paints.
Styles
Rhapsodist includes a simple UI theming system. Themes are defined in a App/Styles.js file. If this file is not included Rhapsodist will fall-back to its default hardcoded styles.
This file should contain the namespace Styles within which a single array called data that contains the style definitions. No interface is provided for changing style, by default only the first style will be used.
Styles.js should be included in on init after Manifest.js and before LookAndFeel.js and Core.js.
The application of the style data is managed by Core/Includes/StyleHandler.js.
Structure
This is the basic structure of a style. You should always include an ID and mode field. The other fields are optional. Any that aren’t included will fall-back to Rhapsodist’s defaults.
namespace Styles
{
const data = [
{
id: "Dark", // An ID for your style.
mode: "dark", // Is this a "light" or "dark" palette - This alters how the style is applied
bg: 0xff192022, // The lowest layer of your UI
surface: 0xff151b1d, // Used by cards and levels above the background
raised: 0xff253131, // Components like knobs, buttons, and sliders
text: 0xfffbecca, // UI Text
accent: 0xffd2bd96 // Accented areas like knob value arcs
}
]
}
Extensions
The idea is to keep the configuration minimal and manageable. From the colours provided in the style data Rhapsodist will create a variety of shades to use in different parts of the UI.
For cases where you want more control, it’s possible to extend the style and set the properties of individual components.
For example to set the colours of pnlHeader:
const data = [
{
...,
pnlHeader: {
bgColour: 0xff243037,
textColour: 0x88fbecda,
borderSize: 1,
borderRadius: 5
}
}
]
Global Elements
There are certain elements that are reused through the UI. Alert windows, popups, scrollbars, etc. It is usually desirable that they all share a consistent appearance.
To handle this the style data allows you to specify some properties for those elements that will be used in their Look and Feel functions.
If the configuration options provided by the styles system is not sufficient for your needs you can instead override the Look and Feel used by the elements.
Alert Windows
const data = [
{
...,
alertWindows: {
buttonRadius: 1,
borderSize: 2,
borderRadius: 1,
labelRadius: 2
}
}
]
Input Box
const data = [
{
...,
inputBox: {
bgColour: 0xff151b1d,
borderSize: 0,
borderRadius: 2
}
}
]
Popup Menus
const data = [
{
...,
popupMenu: {
font: "regular",
fontSize: 18,
borderSize: 1,
borderRadius: 2,
textOffsetY: 0,
iconFont: "phosphorFill",
iconFontSize: 22,
subMenuIcon: "e13a",
subMenuIconFont: "phosphor",
subMenuIconFontSize: 16,
itemRadius: 2
}
}
]
Scrollbars
const data = [
{
...,
scrollbar: {
radius: 1,
bgColour: 0xff151b1d,
itemColour: 0xff78d092
}
}
]
Toggle Switch
const data = [
{
...,
toggleSwitch: {
borderRadius: 10,
borderSize: 1,
activeColour: 0xff78d092
}
}
]
Text Button
const data = [
{
...,
textButton: {
borderRadius: 2,
borderSize: 2
}
}
]
Peak Meter
const data = [
{
...,
peakMeter: {
radius: 1
}
}
]
Table
const data = [
{
...,
table: {
rulerColour: 0xff253131,
pointColour: 0xffd2bd96
}
}
]
Value Popup
const data = [
{
...,
valuePopup: {
fontName: "medium",
fontSize: 20,
borderSize: 2,
borderRadius: 2,
margin: 10
}
}
]
Cards
const data = [
{
...,
card: {
bgColour: 0xff243037,
borderColour: 0x0,
textColour: Colours.white
}
}
]
Keyboard
There are several properties that can be set to alter the appearance of the on-screen keyboard.
const data = [
{
...,
keyboard: {
radius: 2,
useShadow: true,
roundEndKeys: false,
textColour: Colours.black
}
}
]
Additionally the keyboard object can be supplied with a colours object in order to define different key colours that can be referred to from the Manifest.
Each key colour object is an object itself, the key is the ID you want to use for that key colour, for example “playable”, “inactive”, “keyswitch”, etc. And the value is a two element array, the first element is the white key colour, the second is the black key colour.
const data = [
{
...,
keyboard: {
...,
colours: {
playable: [0xcce0d7c0, 0x88564d37],
inactive: [0xdddcd7bc, 0xdd282924],
harmonics: [0xdd2e2622, 0xaaf3e2c5]
}
}
}
]
You can define any number of key colours you want and assign them to key ranges in your expansion’s Manifest.
Fonts
Rhapsodist is supplied with some text and icon fonts. These are installed in Images/Fonts/Rhapsodist.
These are used throughout the look and feel functions and you can access them too through CoreLookAndFeel.style.fonts.
The stock fonts are loaded with the following names, do not use the same names when using custom fonts.
| Font | Internal Name |
|---|---|
AtkinsonHyperlegibleMono-Regular | monoRegular |
AtkinsonHyperlegibleMono-Medium | monoMedium |
AtkinsonHyperlegibleMono-SemiBold | monoSemiBold |
AtkinsonHyperlegibleMono-Bold | monoBold |
Phosphor | phosphor |
Phosphor-Thin | phosphorThin |
Phosphor-Light | phosphorLight |
Phosphor-Bold | phosphorBold |
Phosphor-Fill | phosphorFill |
fontaudio | fontaudio |
To override these with your own you can pass them into the style configuration:
const data = [
{
...,
fonts: {
regular: "myRegularFont",
medium: "myMediumFont",
semibold: "mySemiBoldFont",
bold: "myBoldFont",
title: "myMediumFont",
size: 0, // A relative offset from the defaults
titleSize: 22, // Expansion name font size
titleOffset: 0 // Expansion name vertical offset
}
}
]
Noise
A stylistic element added to some expansions is a soft noise/grain texture overlay. This is enabled by default and can be disabled through the style data.
const data = [
{
...,
useNoise: false
}
]
Custom Look and Feel
To override core look and feel functions, or add project specific look and feel functions you can use a dedicated LookAndFeel namespace.
Create this in a new file: App/LookAndFeel.js.
This file should be included in on init after Manifest.js and Style.js and before Core.js.
At the top of the file you should get a reference to the core Styles object so you have access to it throughout the script.
namespace LookAndFeel
{
const style = CoreLookAndFeel.style; // Colours and properties
const fonts = style.fonts; // Loaded fonts and text properties
}
Check the Core Look And Feel chapter for a reference of the available overrides.
Packaging Expansions
A Rhapsody expansion is distributed to end users as an .hr file, containing the expansion’s scripts, UI, configuration, user presets, and samples. Rhapsody installs it into the expansion’s own folder inside Rhapsody’s app data Expansions folder.
Sample audio data can be large, so users choose where to store it, often on a different drive. Rhapsody tracks the chosen location with a small Link file inside the expansion’s Samples folder, redirecting to wherever the user placed the actual sample data.
User presets ship embedded with the expansion. At least one preset is required, following the standard Bank > Category > Preset folder structure (for example Factory/Category/Default).
How you export all of this matters. Rhapsody reads specific project metadata and files when it loads an expansion, and how you package the sample data affects how users receive future updates.
Project Settings
Before exporting, also set these Project Settings in the project’s preferences:
Expansion Type
Set to Disabled.
Encryption Key
Set to 1234. The exporter requires this exact key.
Default User Preset
Leave empty. Rhapsody handles selecting the default preset itself; see Setting The Default Preset below.
Expansion Settings
Before exporting, complete the Expansion Settings section of the project’s preferences in the HISE.
UUID
A UUID (universally unique identifier) is a randomly generated ID, effectively guaranteed to be unique. Rhapsody currently uses it to identify an expansion when checking for updates, independent of its name.
It will likely also be used to prevent clashes when two expansions from different developers happen to share a name.
There’s a one-click button in the preferences to generate one, and it shouldn’t change once you’ve released the expansion.
Required Player Version
Sets the minimum Rhapsody Player version needed to load the expansion. Leave it blank unless the expansion relies on functionality from a specific Rhapsody Player version, since setting it will stop the expansion loading in older players.
Icon
Add a 500x500px Icon.png to the project’s Images folder. It’s embedded in the exported expansion, and is the icon Rhapsody will display.
Compressing Samples
Compress the project’s samples to monoliths via Tools > Convert all samples to Monolith + Samplemap. Normalisation is locked to Full Dynamics.
Setting The Default Preset
Load the expansion’s default user preset (for example Factory/Category/Default) and resave the project xml, so the correct preset is embedded when you export.
Factory presets are read-only in Rhapsody.
Exporting The Expansion
Export the expansion’s scripts, UI, configuration, and user presets via File > Export > Export Project as Full Expansion, choosing the HXI export mode. This produces an info.hxi file in the project’s root folder.
Creating the Package File
Package the compressed sample monoliths via File > Export > Package sample monolith files. The info.hxi exported earlier is picked up automatically and embedded as the archive’s header.
- Output format: HR Archive (custom FLAC).
- Split archive size: 2 GB. Once the archive exceeds this size, the exporter continues it across further files with an incrementing extension (
..._Samples.hr1,..._Samples.hr2,..._Samples.hr3, and so on) instead of one large file. - Archive layout:
- Combined Archive: the
info.hxiheader and the sample data are packed into the same archive. - Split Data From Samples: the
info.hxiheader is written to its own file, kept separate from the sample data that follows. Use this if you want the option to ship a data-only update later without re-exporting the samples. - Data Only Update (reuse existing samples): exports just the
info.hxiheader, with no sample data at all. Use this for an update that only changes scripts or configuration, so customers who already have the sample archives installed don’t need to re-download them.
- Combined Archive: the
Either Combined Archive or Split Data From Samples works for the initial install. For a small expansion, a Combined Archive is simplest. For a larger one, Split Data From Samples is the better choice: it keeps the door open for a later Data Only Update, so customers won’t have to re-download unchanged sample data.
Update Checking
Rhapsody checks installed expansions for updates automatically (roughly monthly), and on demand via Check for Updates in the settings menu.
For an expansion to be checked, the project’s Company URL (User Settings) must be set. Rhapsody takes the base URL and requests rhapsody.json from it, so you need to host that file at the root of the same website. A URL that repeatedly fails to serve it gets skipped in future checks.
See librewave.com/rhapsody.json for a real example.
rhapsody.json is a JSON array, with one entry per expansion you publish updates for:
[
{
"uuid": "1234-5678-...",
"version": "1.2.0",
"description": "What changed in this version."
}
]
Rhapsody matches each entry to an installed expansion by uuid. A match with a higher version than the installed one flags that expansion as having an update available.
description is optional: a changelog for the most recent update. Create new lines using \n. It isn’t used by Rhapsody yet, but may be in a future version.
Core
Rhapsodist/Core includes the core scripts, processors, and effects required to use the Rhapsodist framework.
Core.js is the main entry point. It’s responsible for bringing in the other core include scripts and UI components.
Within the Core folder are sub-folders for the additional components that Core.js brings in or that need to be added in the project’s module tree.
- Includes, the files
Core.jsincludes directly, in a fixed order, to build the shell and its subsystems. - Widgets, the generic layout primitives (
Container,SwitcherPanel,SettingsPanel,ValueEdit,Card) andKeyboard, also included automatically byCore.js. - Processors & Script FX, standalone scripts loaded into their own modules, not included by
Core.js.
Core.js
Core.js sets a few engine defaults:
Synth.deferCallbacks(true)Engine.setAllowDuplicateSamples(false)Engine.loadAudioFilesIntoPool()Content.setUseHighResolutionForPanels(true))
Additionally it collects references to every Sampler of the project into an array.
If you need access to a sampler throughout your interface script you can access the reference in Core.samplers without having to manually declare it.
They are defined as ChildSynths so if you need to call a Sampler type function use .asSampler() first to convert it.
Core Includes
Rhapsodist/Core/Includes/ contains the files Core.js includes directly to build the shell UI and its subsystems.
StyleHandler
File: Rhapsodist/Core/Includes/StyleHandler.js · Namespace: StyleHandler
Overview
StyleHandler builds the CoreLookAndFeel.style object that every paint routine in Core and the Widgets reads from, and applies it to every component in the interface. It reads theme entries from Styles.data, an array you can define in your project’s App/Styles.js.
Writing a theme
A Styles.data entry sets a base palette (mode, bg, surface, raised, text, accent) plus optional per-category overrides (fonts, card, keyboard, alert window, input box, popup menu, scrollbar, toggle switch, text button, peak meter, table, and specific panel IDs). Anything you omit falls back to Rhapsodist’s built-in palette. The macro tag colours are always derived from the palette; there’s no per-category override for them. A properties[<componentId>] block lets a theme recolour one specific component without touching the whole palette.
See Styles for the full schema.
Usage
StyleHandler applies Styles.data[0] automatically once Core.js is included, so a project gets a working theme with no extra call.
Call StyleHandler.setStyle(index) to switch themes at runtime, for example from a menu built with StyleHandler.getStyleNames().
Public API
| Function | Description | Returns |
|---|---|---|
getStyleNames() | Returns the id of every entry in Styles.data. | Array |
setStyle(index: number) | Applies Styles.data[index]. Runs automatically for index 0 as soon as StyleHandler.js loads, so the first theme is active before anything else in Core paints. There’s no built-in UI for switching themes at runtime beyond calling this directly. | — |
Internal Reference
| Function | Description | Returns |
|---|---|---|
setPalette(properties: JSON) | Builds the base palette object (mode, surface0, surface1, bg, raised, text, accent) from a Styles.data entry and stores it on CoreLookAndFeel.style.palette. | — |
setLookAndFeelStyle(properties: JSON) | Builds the rest of CoreLookAndFeel.style (fonts, alert window, input box, popup menu, scrollbar, toggle switch, text button, macro tag, peak meter, table, keyboard) from palette plus any per-category overrides (the macro tag colours are derived from palette alone, with no override), and sets the value-popup style via Content.setValuePopupData(). | — |
setComponentColours(properties: JSON) | Applies colours to every component in the interface: generic per-type colours, specific per-ID overrides, pnlCard* overrides, then any properties[componentId] block from the theme, before repainting each component. | — |
setFloatingTileColours(component: ScriptObject, contentType: string) | Sets colours on a ScriptFloatingTile based on its ContentType (e.g. MatrixPeakMeter, PresetBrowser, MidiLearnPanel). Called from setComponentColours(). | — |
ErrorManager
File: Rhapsodist/Core/Includes/ErrorManager.js · Namespace: ErrorManager
Note
This is a bit of a stub at the moment and might be removed in the future.
Overview
ErrorManager installs a HISE error callback that shows a message box for two error states: invalid buffer size, and missing samples.
Usage
ErrorManager is created as soon as Core.js is included. There’s no function to call and nothing to configure.
Expansions
File: Rhapsodist/Core/Includes/Expansions.js · Namespace: Expansions
Overview
Expansions wraps Engine.createExpansionHandler(). Other Core includes and ConfigurationHandler use it rather than calling the expansion handler directly.
It also wires up the shell’s expansion-unload button (btnRhapsody), which prompts for confirmation and calls ExpansionHandler.setCurrentExpansion(""). The unloading function is used only in Rhapsody and not from within HISE.
Usage
Expansions wires itself up once Core.js is included. Call its getters from other scripts to query expansion state.
Example
How Presets locates the external automation file:
const automationDataFile = Expansions.getAppDataFolder().getChildFile("automation.xml");
Public API
| Function | Description | Returns |
|---|---|---|
getCurrentExpansionName() | The loaded expansion’s Name, or the project’s own name if none is loaded. | string |
getCurrentExpansionVersion() | The loaded expansion’s Version, or the project’s own version if none is loaded. | string |
getCurrentExpansion() | Gets the currently loaded expansion, within Rhapsody. | Expansion object or Undefined |
getAppDataFolder() | The expansion’s root folder if one is loaded, otherwise the app’s data folder. | ScriptObject |
getAllExpansionIcons() | [name, iconPath] pairs for every loaded expansion. | Array |
getNumberOfExpansions() | The number of loaded expansions. | number |
getCurrentUserPresetsFolder() | The correct user presets folder for the current context (HISE IDE, plugin with no expansion loaded, or expansion loaded). | File Object or Undefined |
ArticulationDataManager
File: Rhapsodist/Core/Includes/ArticulationDataManager.js · Namespace: ArticulationDataManager
Overview
ArticulationDataManager builds the effective per-patch articulation list by merging Manifest.articulations with a patch’s own patch.articulations overrides (matched by id), and resolves keyswitch/Program Change values to articulation indices. It rebuilds automatically whenever knbPatch changes.
This script is also included in the ConfigurationHandler, which applies the merged data to modules.
Behaviour
A "Defaults" entry in Manifest.articulations (or a patch level articulations entry), if present, fills in properties an articulation doesn’t already define.
Each articulation gets a keyswitch note (its own ks, or patch.firstKs + index) and a program number (its own program, or its index). See The Manifest for the full schema.
Usage
ArticulationDataManager rebuilds itself automatically whenever knbPatch changes, there’s nothing to set up.
Call its getters from other scripts to look up the merged, resolved articulation data, the way ArticulationSwitcher does when translating a keyswitch note into an articulation:
local index = ArticulationDataManager.getArticulationIndexForKeyswitch(noteNumber);
local articulation = ArticulationDataManager.getArticulation(index);
Public API
| Function | Description | Returns |
|---|---|---|
getArticulation(index: number) | Returns the merged articulation object at index. | object |
getAllArticulations() | Returns the full merged articulation array. | Array |
getNumArticulations() | Returns the number of merged articulations. | number |
getArticulationIndexForKeyswitch(noteNumber: number) | Returns the articulation index whose keyswitch matches noteNumber. | number |
getArticulationIndexForProgram(programNumber: number) | Returns the articulation index whose program number matches programNumber. | number |
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateArticulationData(patch) | Rebuilds the articulations array by merging Manifest.articulations with patch.articulations, applying a "Defaults" entry if present. Runs on every knbPatch change. | — |
updateTriggers(patch: JSON) | Rebuilds the keyswitches and programs lookup arrays from the merged articulations, filling in keyswitch/program numbers that aren’t explicitly set. | — |
merge(base, source, allowOverride) | Recursively merges source into base, following the same rules updateArticulationData uses for the "Defaults" entry and patch-level overrides. | object |
mergeArray(baseArray: Array, sourceArray: Array, allowOverride: number) | Merges two arrays of objects by id, used by merge for array-valued properties. | Array |
isObject(variable) | Returns whether variable is a plain object (not an array). | number |
Broadcasters
| Broadcaster | Description |
|---|---|
bcPatchChanged | Fires when knbPatch changes value. Looks up the matching Manifest.patches entry and rebuilds the articulation and trigger data for it via updateArticulationData()/updateTriggers(). |
ComponentHandler
File: Rhapsodist/Core/Includes/ComponentHandler.js · Namespace: ComponentHandler
Overview
ComponentHandler applies declarative component property changes from the Manifest when the patch or articulation changes, hiding/showing a control, changing a label’s text, and so on.
It’s enabled by adding a components array ({id, properties} objects) to a Manifest patch or articulation entry; see the schema in The Manifest.
A value property is special-cased: it goes through the component’s normal value-change path (setValue + changed()), so it also fires that component’s own control callback and any listening broadcasters. Every other property is set directly.
Patch-level components are applied first, then articulation-level, so articulation settings win if both set the same property.
Usage
ComponentHandler wires itself up as soon as Core.js is included, there’s nothing to call directly. Add a components array to a Manifest patch or articulation entry and it applies automatically whenever that patch or articulation becomes active.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getAllComponentsIndexed() | Builds a lookup of every component on the interface, keyed by ID. Used to resolve a Manifest entry’s id to its component. | object |
setComponentProperties(data: Array) | Applies a {id, properties} array from the Manifest to the matching components, special-casing value so it goes through setValue/changed(). | — |
Broadcasters
| Broadcaster | Description |
|---|---|
bcPatchChanged | Fires when knbPatch changes value. Applies the Manifest’s top-level components array, then the new patch’s own components array, via setComponentProperties(). |
bcArticulationChanged | Fires when knbArticulation changes value. Re-applies the current patch’s components array, then the matching articulation’s own components array. |
Presets
File: Rhapsodist/Core/Includes/Presets.js · Namespace: Presets
Overview
Presets owns the preset browser UI, the save/overwrite flow, and, outside the HISE IDE, external automation-data storage.
Two things worth knowing up front: MIDI/host automation assignments are stored in an external file rather than the preset XML, and Presets exposes broadcasters so other scripts can react to preset load/save without embedding state in the preset itself.
User Preset Migration
If your project needs to migrate presets saved under an older version, create an App/UserPresetProcessor.js file with a UserPresetProcessor namespace.
Within that namespace add an inline function process(data). Include the file after Manifest.js and before Core.js.
process() will be called when the user loads a preset with a saved version that is older than the running project version, using HISE’s own semantic-version comparison.
The Data Object
The data object passed to process() uses this structure:
data.version, the preset’s saved version string.data.Content, per-component saved-state objects (id,value, anddatafor sliderpacks/tables), already decoded.data.Modules,data.MPEData, module state and MPE data.data.MidiAutomation.Children, saved automation assignments, each with anAttributenaming the target component ID.
Whatever process() returns replaces the corresponding section wholesale, HISE doesn’t merge it with the original. Mutating the existing objects in place naturally keeps everything else; building new data from scratch means including every entry you want to survive. Returning a falsy value aborts the load.
Typical uses: remapping a renamed component ID in both data.Content and data.MidiAutomation.Children, expanding one saved component into several, reshaping a sliderpack’s saved data after a layout change, or dropping automation for a removed component.
State and persistence
Outside the HISE IDE, MIDI automation, MPE data, and macro-control assignments are routed to an external automation.xml file (under the expansion’s app data folder) instead of being embedded in the preset. Inside the IDE this redirection doesn’t apply.
Usage
Presets wires itself up once Core.js is included, the preset browser, save flow, and broadcasters are all ready without further setup.
Call Presets.show()/hide() from other scripts to open or close the browser programmatically, and listen to Presets.broadcasters.preLoad/postLoad to react to preset loads.
Look and Feel
| Function | Draws |
|---|---|
drawPresetBrowserPanel | The whole pnlPresetBrowser panel, replacing its default background/border. |
drawPresetBrowserBackground | The floating tile’s background fill. |
drawPresetBrowserColumnBackground | A whole bank/category/preset column: its background, border, and label text. |
drawPresetBrowserColumnAfterFill | An extra pass after the default column background/border, before its label text; only reached when drawPresetBrowserColumnBackground isn’t overridden. |
drawPresetBrowserListItem | A single item row in a column. |
drawPresetBrowserEditButton | The Add/Rename/Delete/More edit icon buttons. |
drawPresetBrowserSearchBar | The search bar. |
drawPresetBrowserScrollbar | Each column’s scrollbar. |
Public API
| Function | Description | Returns |
|---|---|---|
show() | Opens the preset browser overlay. | — |
hide() | Closes the preset browser overlay. | — |
savePreset() | The save/overwrite flow bound to btnPresetSave. If a non-read-only preset is already loaded it offers to overwrite it, otherwise opens a save dialog. Presets must be saved into a bank/category folder directly inside the expansion’s user presets folder; read-only presets can’t be overwritten. | — |
setDataProperty(property: string, value: NotUndefined) | Patches a single property into the PresetBrowser floating tile’s Data JSON. The property must already exist in that JSON. | — |
Broadcasters
| Broadcaster | Description |
|---|---|
broadcasters.preLoad | Broadcaster that fires before every preset load/save, carrying a single isInternal argument. Use it to snapshot state that should survive a preset load, see Header for the master volume/pan example. |
broadcasters.postLoad | Broadcaster that fires after every preset load/save, with the same isInternal argument. Use it to restore state snapshotted in preLoad. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
updatePresetLabel(nameOnly: number) | Updates btnPresetBrowser’s displayed text from currentPresetFile. | — |
overwriteCurrentPreset(presetName: string) | Confirms and overwrites the currently loaded preset, called by savePreset() when one is loaded and not read-only. | — |
createNewPreset() | Opens a save dialog, validates the chosen location is a bank/category folder inside the user presets folder and that it isn’t read-only, then saves. Called by savePreset() when no preset is loaded, or the loaded one is read-only. | — |
setStyleDataProperties() | Applies LookAndFeel.style.presets.dataProperties, if defined, to the PresetBrowser floating tile via setDataProperty(). Runs once at load. | — |
Header
File: Rhapsodist/Core/Includes/Header.js · Namespace: Header
Overview
Header builds the header bar and wires up the master pan/volume knobs (knbMasterPan, knbMasterVolume) and the master peak meter (fltMasterPeak).
Usage
Header builds itself once Core.js is included, there’s nothing to call directly.
Look and Feel
| Function | Draws |
|---|---|
drawHeader | The header panel’s whole paint routine, replacing the default drawing entirely. |
drawPanVolSliders | Both knbMasterPan and knbMasterVolume, replacing their shared default drawing entirely. |
Events and communication
Master volume/pan are plugin-host-facing parameters (bound via pluginParameterName). Because of that, Header snapshots them on Presets.broadcasters.preLoad and restores them on postLoad, but only for a non-internal load, so an ordinary user preset switch doesn’t silently change the host-visible gain/pan:
reg masterVolumeValue;
reg masterPanValue;
Presets.broadcasters.preLoad.addListener({}, "Preset preload", function(isInternal)
{
if (!isInternal)
{
masterVolumeValue = knbMasterVolume.getValue();
masterPanValue = knbMasterPan.getValue();
}
});
Presets.broadcasters.postLoad.addListener({}, "Preset post load", function(isInternal)
{
if (!isInternal && isDefined(masterVolumeValue))
{
knbMasterVolume.setValue(masterVolumeValue);
knbMasterPan.setValue(masterPanValue);
knbMasterVolume.changed();
knbMasterPan.changed();
}
});
Footer
File: Rhapsodist/Core/Includes/Footer.js · Namespace: Footer
Overview
Footer builds the footer/status bar, the Libre Wave logo (or, for a non-Libre-Wave project, the company name as plain text), and the “all notes off” panic button (btnAllNotesOff).
Usage
Footer builds itself once Core.js is included, there’s nothing to call.
Look and Feel
| Function | Draws |
|---|---|
drawFooter | The footer panel’s whole paint routine, replacing the default drawing entirely. |
drawStatusBar | The status bar panel’s whole paint routine, replacing the default drawing entirely. |
drawLogo | The logo panel’s whole paint routine (the Libre Wave logo, or the company name as plain text for a non-Libre-Wave project), replacing the default drawing entirely. |
PreloadBar
File: Rhapsodist/Core/Includes/PreloadBar.js · Namespace: PreloadBar
Overview
PreloadBar drives pnlPreload, the sample-preload progress bar, from HISE’s own preload lifecycle (Engine.getPreloadProgress()/getPreloadMessage()). There’s no public API and nothing to configure.
Usage
PreloadBar builds and wires itself once Core.js is included. There’s nothing to call or configure.
UserSettings
File: Rhapsodist/Core/Includes/UserSettings.js · Namespace: UserSettings
Overview
UserSettings builds and manages the Settings window (Engine, Audio, MIDI I/O, Instrument, Automation, About), and provides a general-purpose key/value store for user preferences, independent of the preset system.
Adding a settings page
Any ScriptPanel that’s a direct child of pnlSettings (other than pnlSettingsMenu itself) automatically gets a sidebar entry, using its text property as the label.
State and persistence
Settings written via setProperty persist in AppData/UserSettings.json across every preset and project session, they are not part of any preset. Engine-settings-page values (Max Voices, Disk Mode, custom BPM, Lazy Load, and others) are persisted the same way automatically.
Usage
UserSettings wires itself up once Core.js is included. Call UserSettings.setProperty()/getProperty() from any script to store or read a preference outside the preset system, scoped by name:
// Store a global (not project-specific) preference
UserSettings.setProperty("rhapsody", "preferDarkMode", true);
// Read it back later, from anywhere Core has already loaded
local preferDark = UserSettings.getProperty("rhapsody", "preferDarkMode");
Look and Feel
| Function | Draws |
|---|---|
drawSettingsPanel | The whole Settings window panel, replacing the default drawing entirely. |
drawSettingsPanelBackground | The Settings window panel’s background fill and border, keeping the title text and inner divider line drawn by default. |
Public API
| Function | Description | Returns |
|---|---|---|
setProperty(scope: string, key: string, value: Colour) | Writes a value to AppData/UserSettings.json, namespaced by scope ("rhapsody" for global settings, or an expansion name for project-specific scope). This is Rhapsodist’s general runtime preference store. The value parameter is typed Colour in the source, but in practice it’s used to store any JSON-storable value (string, number, boolean). | — |
getProperty(scope: string, key: string) | Reads a value previously written with setProperty, or undefined. | — |
show() | Opens the Settings window. | — |
hide() | Closes the Settings window. | — |
setMenuIcon(menuItem: string, iconCodePoint: string) | Sets the Phosphor icon shown next to a Settings sidebar entry. | — |
Internal Reference
| Function | Description | Returns |
|---|---|---|
getAllSettingsPanels() | Finds every component matching .*pnl.*Settings.*, excluding menu/container panels. Its result isn’t referenced elsewhere in the source; populateMenuItems() is what actually builds the sidebar. | Array |
populateMenuItems() | Builds pnlSettingsMenu’s item list (and height) from the text property of each ScriptPanel that’s a direct child of pnlSettings (other than pnlSettingsMenu itself). | — |
getScopedPropertiesFromFile(scope: string) | Reads the scope object out of UserSettings.json, or {} if it isn’t defined. Shared by getProperty() and restoreEngineSettings(). | ComplexType |
restoreEngineSettings() | Restores each Engine-settings component’s value from UserSettings.json (falling back to built-in defaults for Max Voices, Disk Mode, BPM, and Lazy Load), then sets settingsLoaded = true. Runs once, shortly after load. | — |
toggleAllMidiChannels(state) | Enables or disables all 16 MIDI input channels at once, used when the “all channels” toggle or a double-click on a channel dot is triggered. | — |
getAboutInfo() | Returns project/expansion name, version, and other Engine.getProjectInfo() fields used to render the About page. | object |
Broadcasters
| Broadcaster | Description |
|---|---|
bcEngineSettingChanged | Fires when cmbStreamingMode, cmbMaxVoices, knbGlobalBpm, btnLazyLoad, or btnTooltips changes value, once settingsLoaded is true. Persists the new value via setProperty(), scoped to the current project name. |
Automation
File: Rhapsodist/Core/Includes/Automation.js · Namespace: Automation
Overview
Automation builds the Automation tab of the Settings window: MIDI CC and Macro assignment (via HISE’s own MidiLearnPanel/FrontendMacroPanel), plus an MPE assignment table if the module tree contains any MPEModulators.
There’s no public API; an expansion benefits from this automatically once Core.js is included.
The MPE table lists every currently MPE-connected, non-bypassed MPEModulator (Parameter, Gesture, Mode, Intensity); edits write straight back to the modulator’s attributes.
Automation also registers 32 frontend macros (“Macro 1”..“Macro 32”) unconditionally at load.
Usage
Automation runs automatically once Core.js is included, no project code needs to call anything here. Add an MPEModulator to the module tree and it appears in the MPE tab on its own.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getMpeModFromParameterId(id: string) | Returns the MPEModulator with the given ID from mpeMods. | — |
populateMpeTable() | Rebuilds mpeTableData from the MPE-connected, non-bypassed modulators in mpeMods and pushes it to vptMpe. | — |
getMpeModulators() | Scans all modulators for MPEModulators, populates mpeMods, and shows/hides the MPE tab on pnlAutomation accordingly. | — |
getMpeMode(modulator: ScriptObject) | Reads a modulator’s Monophonic/Retrigger attributes and returns the corresponding mode index (Polyphonic, Legato, Retrigger). | number |
setMpeMode(modulator: ScriptObject, mode: number) | Sets a modulator’s Monophonic/Retrigger attributes for the given mode index. | — |
registerMacros() | Calls Engine.setFrontendMacros() with the 32 fixed macro names. | — |
Broadcasters
| Broadcaster | Description |
|---|---|
bcMpeBypassWatcher | Fires when the Enabled attribute changes on an MPE-connected modulator. Rebuilds the MPE table via populateMpeTable(). getMpeModulators() attaches it to the current set of MPEModulators, or bypasses it entirely when there are none. |
Tooltips
File: Rhapsodist/Core/Includes/Tooltips.js · Namespace: Tooltips
Overview
Tooltips implements the hover-tooltip popup (pnlTooltip) for any ScriptButton, ScriptSlider, ScriptTable, ScriptComboBox, or ScriptPanel that has a non-empty tooltip property. There’s no public API.
Tooltip listeners are only active while the shell’s btnTooltips toggle is on, so tooltips can be switched off entirely from Settings (“Show Tooltips”), the same toggle UserSettings persists via setProperty.
Usage
Tooltips wires itself up once Core.js is included, watching every ScriptButton, ScriptSlider, ScriptTable, ScriptComboBox, or ScriptPanel in the interface. Give a component a non-empty tooltip property to opt it in, there’s nothing else to call.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getComponents() | Collects every enabled ScriptButton, ScriptSlider, ScriptTable, ScriptComboBox, or ScriptPanel with a non-empty tooltip property. Runs once at load to build the set bcTooltipPanel attaches to. | Array |
addRemoveListeners(state: number) | Adds or removes bcTooltipPanel’s two listeners (position/show and the delayed show). Called by bcTooltipButton whenever btnTooltips is toggled. | — |
Broadcasters
| Broadcaster | Description |
|---|---|
bcTooltipPanel | Fires on mouse events for every tooltip-enabled component. Positions pnlTooltip over the hovered component and shows it after a short delay, or hides it when the hover ends. Its listeners are only active while addRemoveListeners() has turned them on. |
bcTooltipButton | Fires when btnTooltips changes value. Calls addRemoveListeners() to turn bcTooltipPanel’s listeners on or off, this is how the Settings “Show Tooltips” toggle enables or disables tooltips entirely. |
ZoomHandler
File: Rhapsodist/Core/Includes/ZoomHandler.js · Namespace: ZoomHandler
Overview
ZoomHandler implements two synced UI-scale controls: the cmbZoom combo box in Settings, and a drag-resizable handle (pnlZoom) in the interface’s bottom-right corner.
Double-clicking the header title area resets zoom to 100%. There’s no public API beyond the UI itself.
Usage
ZoomHandler wires itself up once Core.js is included. There’s nothing to call or configure directly.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getZoomLevels() | Builds the fixed list of zoom levels shown in cmbZoom (0.5 up to the screen-limited maximum, in steps of 0.25), plus a trailing "Custom" entry for values reached by dragging pnlZoom. | Array |
Broadcasters
| Broadcaster | Description |
|---|---|
bcpnlHeaderMouse | Fires on click events in pnlHeader. Resets cmbZoom to index 3 (100%) when the header title area (x between 40 and 300) is double-clicked. |
bcpnlZoomValue | Fires when pnlZoom (the drag-resizable corner handle) changes value. Syncs cmbZoom to match, selecting the "Custom" entry if the new value isn’t one of the fixed zoom levels. |
bccmbZoomValue | Fires when cmbZoom changes value. Syncs pnlZoom’s value to the selected fixed zoom level. |
LayoutBuilder
File: Rhapsodist/Core/Includes/LayoutBuilder.js · Namespace: LayoutBuilder
Overview
LayoutBuilder builds the shell UI from a declarative layout tree. ShellLayout.js is its only caller: it declares the entire shell component tree as one nested JSON literal, hands it to LayoutBuilder.add(), then calls LayoutBuilder.process(), which creates or updates each component and applies its declared properties.
process() only runs inside the HISE IDE (Engine.isHISE()), in an exported plugin the shell components already exist from the last IDE-built state and are just fetched.
It also does nothing if a project-level freezeUi variable is truthy. Set freezeUi = true during UI development to stop the layout rebuilding, and any manual IDE tweaks being overwritten, on every reload. Remove freezeUi before packaging.
Re-running the layout over an existing component never overwrites colours (left to StyleHandler) or text/border properties you’ve already customised by hand.
Usage
LayoutBuilder has no entry point for an expansion to call, ShellLayout.js is its only caller.
Internal Reference
| Function | Description | Returns |
|---|---|---|
addComponent(id: string, properties: JSON) | Creates the component if it doesn’t already exist (based on properties.type), then applies properties to it, skipping colours and text/border properties on an existing component. | object |
clearComponentColours(component: ScriptObject) | Zeroes a newly created component’s colour properties so it picks up StyleHandler’s palette instead of HISE’s defaults. | — |
ShellLayout
File: Rhapsodist/Core/Includes/ShellLayout.js · Namespace: Shell
Overview
ShellLayout declares the entire shell component tree (header, footer, preset browser, Settings window, keyboard, and everything else built-in) and hands it to LayoutBuilder to build.
Usage
ShellLayout has no callable API for other scripts, it declares the shell component tree once, when Core.js includes it, then hands it to LayoutBuilder to build.
UI and processor relationships
Two invisible knobs declared here, knbPatch and knbArticulation, are linked via processorId/parameterId to ConfigurationHandler’s own Patch/Articulation knobs, mirroring the same value both ways.
ConfigurationHandler is what actually applies a patch/articulation change, this pair is the UI-facing surface for it, and every other subsystem that needs to react (keyboard key colours, component visibility, articulation list, envelope UI) listens to the shell’s copy independently via its own broadcaster. See Architecture: Patch and Articulation Changes.
State and persistence
Several shell/session-state components are excluded from the preset (saveInPreset: false): the preset browser buttons, btnSettings/btnSettingsClose, btnRhapsody, vptSettingsMenu, and the Settings-window controls (cmbStreamingMode, cmbMaxVoices, cmbZoom, knbGlobalBpm, btnLazyLoad, btnTooltips).
Core Widgets
Rhapsodist/Core/Widgets/ contains the generic layout primitives Core.js includes automatically to build the shell, plus Keyboard.
Container
File: Rhapsodist/Core/Widgets/Container.js · Namespace: Container.
Overview
Container lays out a panel’s existing visible children without hand-placing x/y coordinates. It’s a generic, framework-level primitive. MixerPanel is built on it.
Only children that are currently visible and whose parentComponent is the target panel are considered, so hiding a child and re-running the layout reflows around it.
Usage
// Lay out three existing knobs evenly across a row, vertically centred
const pnlChannelStrip = Container.createRow("pnlChannelStrip", [10, 10, 10, 10], -1, { fill: false, alignment: "middle" });
Options
create() copies every key in options onto the panel’s data object without reading any of them back. createStack()/createRow()/createGrid() each read specific keys from their own options argument:
| Option | Description | Default |
|---|---|---|
fill | createStack()/createRow(). Shares the available height/width equally across children instead of using a fixed or evenly-spread spacing. | false |
justification | createStack(). Cross-axis alignment: "left", "right", or "stretch". | Centred |
alignment | createRow(). Cross-axis alignment: "top", "bottom", or "stretch". | "middle" |
fillX / fillY | createGrid(). Fill behaviour along each axis, same meaning as fill above. | false |
layout | createGrid(). Optional per-item array of {colSpan, rowSpan, justification, alignment} specs, for irregular grids. | — |
Public API
| Function | Description | Returns |
|---|---|---|
create(id: string, options: JSON) | Fetches or creates the panel and copies options onto panel.data. The base entry point the other three build on. | ScriptObject |
createStack(id: string, padding: Array, spacing: number, options: JSON) | Lays children out vertically. padding is [top, right, bottom, left]. options.fill shares height equally; otherwise use a fixed spacing or spacing: -1 to spread children evenly. options.justification ("left"/"right"/"stretch", default centred) sets the cross-axis. | ScriptObject |
createRow(id: string, padding: Array, spacing: number, options: JSON) | Same as createStack but horizontal, with options.alignment ("top"/"bottom"/"stretch", default "middle") for the cross-axis. | ScriptObject |
createGrid(id: string, padding: Array, spacing: Array, columns: number, options: JSON) | Arranges children into a columns-wide grid. spacing is [spacingX, spacingY]. options.fillX/fillY control fill behaviour, and an optional per-item options.layout array ({colSpan, rowSpan, justification, alignment}) allows irregular grids. | ScriptObject |
SwitcherPanel
File: Rhapsodist/Core/Widgets/SwitcherPanel.js · Namespace: SwitcherPanel.
Overview
SwitcherPanel shows or hides a panel’s children of a given componentType based on the value of a separate “switcher” component. It’s the standard mechanism behind every tabbed area in Rhapsodist: Settings window pages, the Automation tabs, and Card’s multi-tab cards.
Usage
// pnlSettings has one child panel per settings page (pnlEngineSettings, pnlAudioSettings, ...),
// each with a non-empty `text` used as its tab label; pnlSettingsMenu (the sidebar) drives which one is visible.
const pnlSettings = SwitcherPanel.create("pnlSettings", "pnlSettingsMenu", "ScriptPanel", {});
Options
options is accepted but not currently used.
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, switcherId: string, componentType: string, options: JSON) | Collects every direct child of panelId (excluding switcherId) whose type matches componentType (or all types, if componentType == "all") and whose text property is non-empty, text is used as the tab label. The switcher’s value selects which collected child is visible, by index; -1 shows all of them. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
panel.data.broadcasters.switcherWatcher | The switcher component’s value changes. Drives the visibility of the collected child panels directly. Available for an expansion to attach its own listener to the same value change. |
SettingsPanel
File: Rhapsodist/Core/Widgets/SettingsPanel.js · Namespace: SettingsPanel.
Overview
SettingsPanel lays out a Settings page’s child components into label + control rows, one per visible child. It builds the layout of pnlEngineSettings and pnlInstrumentSettings in the Settings window (see UserSettings).
Usage
To add a new setting to a Settings page, place a labelled control (a button, combo box, or a panel wrapping a single ScriptSlider, upgraded automatically into a ValueEdit control) as a direct child of the relevant settings page panel. It’s picked up automatically on the next compile.
Options
Every key in options is copied onto the panel’s data object:
| Option | Description | Default |
|---|---|---|
useNoise | Forwarded as an option to ValueEdit for any child panel setupChildren() upgrades into a ValueEdit control. | — |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, rowHeight: number, options: JSON) | Lays out the panel’s children into rows rowHeight pixels tall, painting each label from the child’s text property. Buttons, combo boxes, and panels wrapping a single ScriptSlider (upgraded automatically into a ValueEdit control) get type-appropriate defaults. | ScriptObject |
Internal Reference
| Function | Description | Returns |
|---|---|---|
setupChildren(parent: ScriptObject) | Positions each visible child on its row, applying type-specific defaults (a toggle-switch Look and Feel for buttons, a combo-box Look and Feel for combo boxes, ValueEdit for a panel wrapping a single ScriptSlider), and resizes the parent panel to fit. | — |
isValueEdit(component: ScriptObject) | Returns whether a ScriptPanel child wraps a single ScriptSlider (as 1/0), the condition setupChildren uses to upgrade it into a ValueEdit control. | number |
ValueEdit
File: Rhapsodist/Core/Widgets/ValueEdit.js · Namespace: ValueEdit.
Overview
ValueEdit turns a plain panel into a numeric “value edit box”: a styled background, a centred knob showing text only, and two step buttons that nudge its value by stepSize.
Used for compact numeric controls like Coarse/Fine Tune and Transpose on the Instrument settings page (pnlCoarseTune, pnlFineTune, pnlTranspose in ShellLayout).
Usage
In practice you rarely call ValueEdit.create() directly: SettingsPanel detects and converts eligible child panels automatically. To add a new tuning-style setting, give it a panel containing a single ScriptSlider child, inside a panel already managed by SettingsPanel.
Called directly:
const pnlMyValueEdit = ValueEdit.create("pnlMyValueEdit", {});
Options
Every key in options is copied onto the panel’s data object.
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, options: JSON) | Builds the styled background, knob, and step buttons. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
panel.data.bc | The panel’s or its knob’s enabled property changes. Used internally to keep the step buttons’ enabled state in sync with the control they belong to. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
createButtons(panel: ScriptObject) | Builds the up/down step buttons and wires their mouse callbacks to nudge the knob’s value by its stepSize, clamped to the knob’s min/max. | Array |
Card
File: Rhapsodist/Core/Widgets/Card.js · Namespace: Card.
Overview
A Card is Rhapsodist’s main UI building block for grouping controls: a styled panel with an optional title.
Usage
Panels on the UI with names pnlCard\d are automatically discovered and converted into styled cards.
Cards are also created manually by calling create().
If a card contains two or more child panels with non-empty text, it becomes a tabbed card, using SwitcherPanel: the text values become clickable tab labels, and clicking a tab switches which child panel is visible.
const pnlMyCard = Card.create("pnlMyCard", {});
Options
| Option | Description | Default |
|---|---|---|
tabWidth | Width of each tab label, in pixels, on a tabbed card. createCardsFromPanels() passes {tabWidth: 95} for every auto-discovered card. | Panel’s width divided by the number of tabs. |
Look and Feel
| Function | Draws |
|---|---|
drawCard | The card’s whole paint routine, replacing the default drawing entirely. |
drawCardBackground | An extra pass drawn on top of the card’s default background fill; it doesn’t replace that fill. |
drawCardBorder | Just the border. |
drawCardLabel | Just a tab label, on a tabbed card. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, options: JSON) | The main entry point. | ScriptObject |
createGrid(parentPanel: ScriptObject, gutter: number, layout: Array, options: JSON) | Lays out many same-shaped cards at once from a layout array of {column, row, columnSpan, rowSpan} specs and a target numColumns/numRows grid. | — |
Internal Reference
| Function | Description | Returns |
|---|---|---|
createCardsFromPanels() | Called automatically at load. Auto-discovers every panel whose ID matches pnlCard\d and turns it into a card, this is how an expansion’s pnlCard0/pnlCard1/etc. panels become Cards without an explicit Card.create call. | — |
paintRoutine() | The default paint routine for a card, used when LookAndFeel.drawCard isn’t defined. Draws the background, border, and tab labels. | — |
mouseCallback() | Handles hover and click events on a tabbed card’s labels, tracking the hovered tab and calling setValue/changed on the panel when a tab is clicked. | — |
Keyboard
File: Rhapsodist/Core/Widgets/Keyboard.js · Namespace: Keyboard.
Overview
Keyboard drives the on-screen keyboard’s key colours from Manifest.keyranges, the current patch/articulation’s own key ranges, and the current transposition, keeping colouring aligned with the notes that will actually trigger a range.
Usage
Keyboard wires itself to fltKeyboard and starts colouring keys as soon as Core.js includes it, reacting to patch, articulation, and transpose changes on its own.
Look and Feel
fltKeyboard draws through a local Look and Feel, deferring to the project’s own LookAndFeel function first if one is defined.
| Function | Draws |
|---|---|
drawWhiteNote | Each white key. |
drawBlackNote | Each black key. |
Public API
Thin wrappers over the fltKeyboard floating tile, usable by an expansion that needs to adjust keyboard display properties at runtime:
| Function | Description | Returns |
|---|---|---|
setProperty(key: string, value: NotUndefined) | Sets a fltKeyboard property directly. | — |
setDataProperty(key: string, value: NotUndefined) | Writes a key in fltKeyboard’s Data JSON. | — |
getDataProperty(key: string) | Reads a key from fltKeyboard’s Data JSON. | NotUndefined |
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateVisibleRange() | Reads LowKey/HiKey from fltKeyboard’s Data into lowHiKey, used to round the low/high key’s outer corners. | — |
setKeyRanges() | Applies every stored key range’s colour (Manifest, patch, and articulation ranges, adjusted for the current transposition) via Engine.setKeyColour. | — |
resetKeyColours() | Resets every key to its inactive colour before setKeyRanges() re-applies the active ranges. | — |
Broadcasters
| Broadcaster | Description |
|---|---|
bcPatchChanged | knbPatch’s value changes. Applies the new patch’s keyranges, if any, and re-colours the keyboard. |
bcArticulationChanged | knbArticulation’s value changes. Applies the new articulation’s keyranges, if any, and re-colours the keyboard. |
bcTranposeChanged | knbTranspose’s value changes. Updates the stored transposition and re-colours the keyboard against it. |
Core Processors & Script FX
Rhapsodist/Core/Processors/ and Rhapsodist/Core/ScriptFX/ contain standalone scripts, not included by Core.js.
ConfigurationHandler
File: Rhapsodist/Core/Processors/ConfigurationHandler.js · Expected module ID: configurationHandler (a Script Processor / MIDI Processor).
Overview
ConfigurationHandler applies Manifest-driven patch and articulation configuration to every module in the project. It’s the processing counterpart to the UI-only ComponentHandler.
It runs as its own Script Processor and includes App/Manifest.js and ArticulationDataManager.js itself, independently of Interface.js.
Running as a separate Script Processor also means it isn’t affected by Core.js’s Synth.deferCallbacks(true) (which only defers the Interface script’s own callbacks), so it responds to patch/articulation changes in real time.
See The Manifest
Parameters
| ID | Description |
|---|---|
Patch | Current patch index. Not meant to be operated directly; link it via processorId/parameterId to the shell’s own knbPatch knob so changing the shell’s patch control drives this one automatically. |
Articulation | Current articulation index. Same as Patch: link it via processorId/parameterId to the shell’s own knbArticulation knob rather than operating it directly. |
Events and communication
ConfigurationHandler writes the current patch/articulation index to two global cables ("patch" and "articulation") on every change, so a standalone processor with no broadcaster connection to the Interface script can read the current patch/articulation from there. See Architecture: Patch and Articulation Changes.
It also resolves MIDI keyswitches, CC 32 (bank-select LSB, when Manifest.useUacc is enabled), and Program Change messages, calling changeArticulation on a match.
Usage
Add ConfigurationHandler.js as a Script Processor with the ID configurationHandler, then link the shell’s invisible knbPatch/knbArticulation knobs to its own Patch/Articulation knobs via processorId/parameterId. From then on, changing the shell’s patch or articulation control drives changePatch()/changeArticulation() automatically.
Internal Reference
| Function | Description | Returns |
|---|---|---|
changePatch(index: number) | Applies Manifest.patches[index]: the Manifest-level scripts/modulators/effects/samplers attributes as a baseline, then the patch’s own overrides, then its muters. Sample maps are loaded for the samplers referenced by Manifest.samplers + patch.samplers; any sampler not referenced is bypassed and cleared. If a patchGain effect exists, its Gain is set from patch.gain (default 0). | — |
changeArticulation(index: number) | Applies the merged articulation from ArticulationDataManager.getArticulation(index) the same way, sets articulationGain’s Gain from articulation.gain (default 0) if that processor exists, and applies the articulation’s muters if present. | — |
loadManifestConfiguration() | Applies the Manifest-level scripts/modulators/effects/samplers attributes as the baseline, before a patch’s own overrides are applied. | — |
setArticulationGain(gain: number) | Sets articulationGain’s Gain attribute, if that script exists. | — |
setAttributes(modules, moduleIds: Array, attributeIds: JSON, data) | Applies a {id, properties} array (a Manifest entry’s scripts/modulators/effects/samplers list) to the matching modules, unbypassing each one and setting its properties as attributes. | — |
setAttribute(module: ScriptObject, attribute: number, property: string, value) | Applies a single property to a module, special-casing Bypass, Gain, Intensity, File, CrossfadeTable, Table, and Bipolar. | — |
loadSampleMaps(data) | Loads sample maps for the samplers referenced in data and activates group 1; clears and bypasses every sampler not referenced. | — |
clearSamplers(samplersToSkip: Array) | Bypasses and clears the sample map of every sampler not in samplersToSkip. | — |
enableMuters(mutersToEnable: Array) | Enables the muters listed by index and mutes every other muter; does nothing if the list is empty. | — |
setDefaultCrossfadeTables(samplerIndex: number, numGroups: number) | Auto-generates evenly spaced crossfade tables for a sampler’s groups when a CrossfadeGroups count is given without an explicit CrossfadeTable. | — |
setCrossfadeTables(samplerTable: ScriptObject, data: Array) | Restores explicit crossfade tables for a sampler from base64 data. | — |
SamplerPurgeHandler
File: Rhapsodist/Core/Processors/SamplerPurgeHandler.js · Expected module ID: the shell references samplerPurgeHandler.
Overview
A standalone Script Processor providing “Lazy Load” and per-sampler purge state. Purge/lazy-load is an engine-level resource-management feature.
Parameters
| ID | Description |
|---|---|
LazyLoad | Toggles global Lazy Load mode. |
PurgeState | A 50-slot slider pack (one slot per sampler) storing each sampler’s purge state (0 = always purged, 1 = loaded/lazy-loadable), bound to LazyLoad from the Settings window. |
Usage
Add SamplerPurgeHandler.js as a Script Processor referenced as samplerPurgeHandler, and link the shell’s btnLazyLoad toggle (see the btnLazyLoad component in ShellLayout / UserSettings).
A sampler whose PurgeState slot is 0 stays fully purged regardless of the Lazy Load setting. A sampler whose slot is 1 loads normally while Lazy Load is off; with Lazy Load on, it instead loads its samples on demand as they’re played (HISE’s “play from purge” mode) rather than up front.
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateSamplerPurgeState(samplerIndex, state) | Computes and sets the sampler’s Purged attribute from its PurgeState slot value and the current LazyLoad state. | — |
TuningHandler
File: Rhapsodist/Core/Processors/TuningHandler.js · Expected module ID: tuningHandler.
Overview
A standalone Script Processor for global coarse/fine tuning and octave/semitone transposition.
Parameters
| ID | Description |
|---|---|
FineTune | “Fine Tune”, -100–100 cents. Engine-wide pitch shifting via Engine.setGlobalPitchFactor. |
CoarseTune | “Coarse Tune”, -12–12 semitones. Engine-wide pitch shifting via Engine.setGlobalPitchFactor. |
OctaveTranspose | “Octave Transpose”, -2–2. |
SemiToneTranspose | “Semi Tone Transpose”, -12–12. |
Usage
Add TuningHandler.js as a Script Processor with the ID tuningHandler, then link the Instrument Settings page’s knbCoarseTune/knbFineTune/knbTranspose controls to its own knobs via processorId/parameterId.
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateTuning() | Combines CoarseTune and FineTune into a single pitch factor and applies it via Engine.setGlobalPitchFactor. Called whenever either knob changes. | — |
MultiChannelGain
File: Rhapsodist/Core/ScriptFX/MultiChannelGain.js.
Overview
Provides a basic Gain/Smoothing/Width/Balance gain stage, applied across however many channels the host Script FX module has. This isn’t the same parameter set as HISE’s built-in Simple Gain effect (which has Gain/Delay/Width/Balance/InvertPolarity and no user-facing smoothing control); the name refers to the general kind of effect, not a drop-in replacement.
Parameters
| ID | Description |
|---|---|
Gain | Decibel-mode gain, -100–12 dB. |
Smoothing | Time-mode smoothing, 0–1000 ms. |
Width | Stereo width, 0–200. |
Balance | Pan-mode balance control. |
Usage
On a Script FX module, use “Connect to External Script” and point it at MultiChannelGain.js; its Gain/Smoothing/Width/Balance knobs then control that module’s channels directly.
Gain and balance are applied per channel pair (odd/even channels share a gain stage), using an equal-power pan law for balance. Width processing is applied uniformly across every channel.
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateGainers() | Recomputes the equal-power pan values from Balance and applies gain (from Gain, converted from dB) to each of the two gain stages. Called whenever Gain or Balance changes. | — |
Rhapsodist/Includes
Rhapsodist/Includes/ contains two files, meant to be included directly into a script’s on init tab via include(), most naturally the Interface script.
ArticulationSwitcher
File: Rhapsodist/Includes/ArticulationSwitcher.js · Namespace: ArticulationSwitcher.
Overview
ArticulationSwitcher drives articulation switching from incoming MIDI: a keyswitch note, a bank-select CC, or a Program Change.
It has no direct effect on sound; it works entirely by setting the shell’s knbArticulation knob, the same knob any other UI control would set to change articulation.
Usage
Call onNoteOn() and onController() from the Interface script’s corresponding callbacks:
function onNoteOn()
{
ArticulationSwitcher.onNoteOn();
}
function onController()
{
ArticulationSwitcher.onController();
}
Events and communication
ArticulationSwitcher only drives knbArticulation’s value; it doesn’t apply any patch/articulation configuration to modules itself.
ConfigurationHandler is what actually applies attribute changes when that knob changes. See Architecture: Patch and Articulation Changes for the full picture of how a patch/articulation change fans out.
Public API
| Function | Description | Returns |
|---|---|---|
changeArticulation(index: number) | Looks up ArticulationDataManager.getArticulation(index), and if it resolves, sets knbArticulation to index, driving the shell’s articulation knob (and every listener on it). | — |
onNoteOn() | Resolves the incoming note, adjusted for the current transpose amount, against the current keyswitch map, and calls changeArticulation if it matches. | — |
onController() | Resolves CC 32 (bank-select LSB, gated by Manifest.useUacc) or an actual MIDI Program Change, and calls changeArticulation if it matches. | — |
Internal Reference
Broadcasters
| Broadcaster | Description |
|---|---|
bcTranposeChanged | knbTranspose’s value changes. Updates the stored transposition amount used to adjust incoming notes before matching them against the keyswitch map. |
ReleaseStartOptions
File: Rhapsodist/Includes/ReleaseStartOptions.js · Namespace: ReleaseStartOptions.
Overview
ReleaseStartOptions.js is an optional companion script for projects using HISE’s single sampler release trigger feature. It exposes scripted control over the Release Start options across every sampler in Core.samplers and adds a user-facing on/off toggle button in Instrument Settings.
State and persistence
btnReleaseTriggers’s value is preserved across non-internal preset loads via Presets.broadcasters.preLoad/postLoad snapshot/restore, the same pattern documented in Header for master volume/pan.
The underlying per-sampler setAllowReleaseStart state itself is set at runtime rather than stored per-preset by this script.
Usage
Include it into the Interface script’s on init via include(). applyDefaults() and the btnReleaseTriggers toggle are set up automatically at include time.
Public API
| Function | Description | Returns |
|---|---|---|
applyDefaults() | Applies a fixed set of release-fade options to every sampler in Core.samplers (ReleaseFadeTime: "8192", FadeGamma: 0.5, descending zero crossing, GainMatchingMode: "Volume", PeakSmoothing: 0.9). Called automatically at include time. | — |
setOptions(options: JSON) | Replaces the full release-start options object on every sampler in Core.samplers. | — |
setOption(option: string, value: NotUndefined) | Updates a single option key on every sampler, leaving the rest as-is. | — |
Internal Reference
Broadcasters
| Broadcaster | Description |
|---|---|
bcbtnReleaseTriggersValue | btnReleaseTriggers’s value changes. Calls setAllowReleaseStart on every sampler in Core.samplers, applying the toggle’s new state. |
MIDI Processors
Rhapsodist/Processors/ contains standalone MIDI Processor scripts, each loaded into its own Script Processor slot in a MIDI processor chain.
Mute Control
Where a processor exposes a Mute parameter, treat it as the primary on/off control, instead of using the module’s bypass toggle.
AhdsrController
File: Rhapsodist/Processors/AhdsrController.js. Standalone MIDI Processor script.
Overview
Controls the knobs of every Flex AHDSR envelope modulator in the tree whose ID contains GainFlexAhdsr.
Nine knobs, one per AHDSR parameter (Attack, Hold, Decay, Sustain, Release, Attack Level, and Attack/Decay/Release Curve). Changing a knob applies its value to every matching modulator at once.
EnvelopePanel is the widget provided to drive this processor: its own knobs bind to it automatically via processorId/parameterId.
Parameters
| ID | Description |
|---|---|
Attack | Attack time, in ms. |
Hold | Hold time, in ms. |
Decay | Decay time, in ms. |
Sustain | Sustain level. |
Release | Release time, in ms. |
AttackLevel | Attack level. |
AttackCurve | Attack curve shape. |
DecayCurve | Decay curve shape. |
ReleaseCurve | Release curve shape. |
Usage
Load into a Script Processor slot anywhere in the tree; it resolves its target modulators by ID pattern rather than by chain position, so placement doesn’t matter.
Give every Flex AHDSR modulator that should be controlled together an ID containing GainFlexAhdsr.
Internal Reference
| Function | Description | Returns |
|---|---|---|
createKnobs() | Builds the nine AHDSR knobs from a table of knob properties and wires each one to onAhdsrControl. | Array |
onAhdsrControl(component, value) | Knob control callback; looks up which knob changed and calls setModuleProperty with its index. | — |
setModuleProperty(knobIndex: number, value: number) | Maps a knob index to the matching AHDSR attribute and applies value to every modulator in mods. | — |
ArticulationGain
File: Rhapsodist/Processors/ArticulationGain.js. Standalone MIDI Processor script.
Overview
Applies a per-articulation gain to note on/off messages: a 100-slot sliderpack (slpGain, range 0–1) holds one user-facing gain value per articulation index. This is tracked via the shared articulation global cable.
The sliderpack gain value is added on top of an optional developer-set baseline value, configured in the Manifest as gain.
slpGain is what ArticulationList’s per-row gain sliders display and edit.
Parameters
| ID | Description |
|---|---|
Articulation | Current articulation index, 0–100. Set from the articulation global cable rather than by the user directly. |
Gain | Developer-set baseline gain applied before the per-articulation gain, -24–24 dB. |
slpGain | 100-slot sliderpack, one gain value per articulation index, 0–1, step 0.01. |
Usage
Load into a Script Processor slot with the module ID articulationGain, and connect a persistent sliderpack from the Interface script to slpGain.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getArticulationGain(index) | Combines Gain’s baseline with slpGain’s value at index, rescaled from 0-1 to -24-24 dB. | number |
changeArticulation(index: number) | Registered on the articulation global cable; sets Articulation to the incoming articulation index and fires its change callback. | — |
AttackOffset
File: Rhapsodist/Processors/AttackOffset.js.
Overview
Applies a randomised sample start offset and volume fade-in. Scaled separately for a note’s initial attack versus a rapid repetition of the same note (within 0.2s), and further scaled by velocity between MinVelocity and MaxVelocity.
A repetition never scales below half its maximum offset/fade; a fresh attack can scale all the way to zero at the highest tracked velocity.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; no offset or fade is applied while on. |
AttackOffset | Max sample start offset for a fresh attack, -1–20000 samples. |
RepeatOffset | Max sample start offset for a repeated attack, -1–20000 samples. |
AttackFade | Max fade-in time for a fresh attack, 0–500 ms. |
RepeatFade | Max fade-in time for a repeated attack, 0–500 ms. |
MinVelocity / MaxVelocity | Velocity range (0–127) over which offset/fade are scaled by velocity. |
-1 on an offset knob tells HISE to use the sample’s own configured Sample Start Offset, so these knobs only matter on samples that have one set.
Usage
Load into a sampler’s MIDI Processor chain and set the knobs to taste.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getScaledValue(maxValue: number, velocity: number, minValue: number) | Scales maxValue by velocity position between MinVelocity/MaxVelocity, floored at minValue as a fraction of maxValue, then applies +/-10% random jitter. Returns maxValue unchanged if it’s -1. | number |
DynamicsModulator
File: Rhapsodist/Processors/DynamicsModulator.js.
Important
This is a Script Time Variant Modulator, not a MIDI processor.
Overview
A Midi Controller-style smoothing modulator driven by note velocity as well as CC.
Below Value’s threshold, output eases toward roughly half the note’s velocity. Above it, output eases toward a point above Value.
Both approach that “snap” target over Attack, then ease back toward Value at independent SmoothUp/SmoothDown rates, optionally reshaped by a response table.
Legato/tied notes skip the snap, so retriggering an already-held note doesn’t produce a hard step.
Parameters
| ID | Description |
|---|---|
Attack | Time to ease towards the snap target, 0–500 ms. |
SmoothUp / SmoothDown | Rate at which output eases back towards Value once the snap target is reached, 0–2000 ms. Which one applies is chosen each sample by comparing current output to Value, not by which branch triggered the snap. |
Value | 0–127. Both the resting target and the velocity threshold that decides whether a note’s snap target sits above or below it. |
ResponseTable | Optional response table that reshapes the final output value every sample (x-axis = normalised output 0-1, y-axis = shaped output 0-1), the same way the built-in Midi Controller modulator shapes its CC value. |
Usage
Add a Script Time Variant Modulator to a sound generator’s gain modulation chain or as a global modulator, load this script into it and connect a UI control to the Value parameter.
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateSmootherCoefficients() | Recomputes the one-pole smoothing coefficients for Attack, Smooth Up, and Smooth Down from their millisecond knob values. Called whenever any of those knobs changes. | — |
timeToCoefficient(timeMs) | Converts a time in milliseconds to a one-pole filter coefficient at the modulator’s control rate. | number |
GroupFilter
File: Rhapsodist/Processors/GroupFilter.js.
Overview
Disables the sampler’s own round-robin engine so the group is fully script-controlled.
Parameters
| ID | Description |
|---|---|
Group | Active sampler group, 1–100. |
Usage
Load into a sampler’s MIDI Processor chain and set Group to activate that group.
It resolves the first Sampler in the tree as its target automatically. Setting Group above the sampler’s actual configured group count is a silent no-op.
LastNoteRetrigger
File: Rhapsodist/Processors/LastNoteRetrigger.js.
Overview
A single designated MIDI note retriggers the last note played. Works by rewriting the incoming note number to the last tracked note. The trigger note itself never sounds at its own pitch.
Parameters
| ID | Description |
|---|---|
Trigger | MIDI note used to retrigger the last note played, 0–127. |
Usage
Load into a sampler’s MIDI Processor chain and set Trigger to the keyswitch note that should retrigger the last note played.
Legato
File: Rhapsodist/Processors/Legato.js.
Note
The algorithms here are subject to change as they are refined.
Overview
Models legato, portamento, and retrigger transitions with pitch/volume fades and a scripted step sequence.
A transition steps semitone-by-semitone toward the target, capped by StepsMax unless gliding. A harder attack produces a faster transition, and step timing is shaped rather than evenly spaced.
Notes played within roughly 25ms of each other are treated as a chord, not a legato transition.
Releasing back to a still-held earlier note re-triggers a transition toward it; releasing the currently playing note stops it normally.
Mute behaviour
Because Legato plays the target note itself rather than passing the incoming note through, Mute does more than block new notes: it also stops any transition already in progress and cleanly ends the currently-sounding artificial note.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; see Mute behaviour above. |
Glide | Switches between legato mode (off) and glide mode (on), each with its own timing/offset/pitch settings below. |
LegatoPitch | Fine pitch offset applied per step in legato mode, 0–100. |
GlidePitch | Fine pitch offset applied per step in glide mode, 0–100. |
StepsMax | Caps the number of semitone steps triggered during a legato transition, 2–12 (12 = no limit). Also enables/disables LegatoOffset (enabled above 2). Has no effect in glide mode, where the full interval is always stepped. |
LegatoTimeMin | Duration for a one-semitone legato transition, 5–100 ms. |
LegatoTimeMax | Duration for an octave-or-more legato transition, 50–1000 ms. |
LegatoOffset | Sample start offset, in samples, for intermediate legato steps, -1–65535. |
TargetOffset | Sample start offset, in samples, for the final note of a legato transition, -1–65535. |
GlideTimeMin | Duration for a one-semitone glide transition, 200–1000 ms. |
GlideTimeMax | Duration for an octave-or-more glide transition, 500–2000 ms. |
GlideOffset | Sample start offset, in samples, for glide notes, -1–65535. |
-1 on an offset knob tells HISE to use the sample’s own configured Sample Start Offset.
Usage
Load into a sampler’s MIDI Processor chain and tune the legato/glide timing and offset knobs to taste.
Internal Reference
| Function | Description | Returns |
|---|---|---|
playLegatoNote(velocity: number) | Plays (or crossfades into) the next step of the current transition. It works out the next note, its pitch/gain fade, and start offset. It then starts the timer for the following step, or stops it if the target note has been reached. Also fires on the timer callback. | — |
getPitchBend(direction: number) | Returns the per-step fine pitch offset for the current mode (GlidePitch or LegatoPitch), signed by direction and jittered by up to 10 cents. | number |
getStartOffset(note: number) | Returns the sample start offset to use for the given step: GlideOffset in glide mode, otherwise TargetOffset for the final note or LegatoOffset for intermediate steps. | number |
getNumSteps(interval: number) | Returns how many steps the transition will take: the full interval in glide mode, otherwise the smaller of interval and StepsMax. | number |
getStep(numSteps: number) | Returns the semitone offset from origin for the current stepIndex, spread evenly across numSteps. | number |
setBaseDurations(arr: Array, min: number, max: number) | Rebuilds a 12-entry duration table (legatoDurations or glideDurations) between min and max, shaped by a fixed easing curve, whenever the corresponding time-min/time-max knobs change. | — |
getTransitionDuration(velocity: number, interval: number) | Looks up the base duration for the note interval from legatoDurations/glideDurations and scales it down for harder-velocity attacks, down to a 4 ms floor. | number |
getStepDuration(stepIndex: number, numSteps: number, max: number) | Returns the duration of one individual step within the overall transition duration, shaped so steps aren’t evenly spaced. | number |
LegatoFilter
File: Rhapsodist/Processors/LegatoFilter.js.
Note
This script has not been used in a while and may need refinement; documented as it currently stands.
Overview
Blocks or exclusively allows legato-interval notes. Applied consistently to both onNoteOn and onNoteOff.
Parameters
| ID | Description |
|---|---|
Block | On: legato notes are blocked. Off: only legato notes are allowed. |
Usage
Load into a sampler’s MIDI Processor chain and set Block depending on whether legato notes should be blocked or exclusively allowed.
Microtuner
File: Rhapsodist/Processors/Microtuner.js.
Overview
Per-semitone (12-tone, not full microtonal/Scala) fine tuning: shifting C by 10 cents shifts every C on the keyboard by 10 cents.
MicrotuningPanel is the corresponding UI widget for this exact 12-value model.
Parameters
| ID | Description |
|---|---|
Microtune | 12-slot sliderpack, one fine-tune value per semitone class, -100–100 cents, step 5.0. Registered via Engine.createAndRegisterSliderPackData(0). |
Usage
Load into a sampler’s MIDI Processor chain, connect a persistent sliderpack from the Interface script to Microtune. MicrotuningPanel binds to it via processorId/SliderPackIndex.
Internal Reference
| Function | Description | Returns |
|---|---|---|
changeTune(currentCoarse, currentFine, index) | Adds the semitone class’s Microtune cent value to the note’s current coarse/fine detune, then re-splits the combined total back into coarse semitones and fine cents before applying it via Message.setCoarseDetune/Message.setFineDetune. No-ops when the slider value is 0. | — |
Mixer
File: Rhapsodist/Processors/Mixer.js.
Overview
An up-to-12-channel mixer (adapts to however many mixerGain\d effects actually exist): gain, pan, purge, mute, solo, and output routing per channel, meant to be driven from a MixerPanel widget or custom UI.
This script does not apply gain/pan itself, it expects one SimpleGain effect per channel in the container (mixerGain0, mixerGain1, …) and sets Gain/Balance attributes on those. Route each stereo pair to a separate output via the SimpleGains’ own routing matrix.
Mute/solo is resolved jointly across all channels: a channel is audible only if it isn’t muted (or is soloed) and, when any channel is soloed, only if it’s one of the soloed ones. Toggling any channel’s mute or solo re-evaluates every channel, silencing the rest via gain rather than bypassing them.
Purge only affects samplers with more than one mic position, purging or reloading the matching position across every such sampler at once. Changing a channel’s output routes its stereo pair to the chosen bus; if that connection fails, both channels fall back to the default stereo output (0/1).
Parameters
Each control is duplicated per channel, suffixed with the channel index (0-11), e.g. Gain0, Gain1, etc.
| ID | Description |
|---|---|
Gain<n> | Channel gain, applied to that channel’s SimpleGain, decibel mode, max 12 dB. |
Pan<n> | Channel pan/balance, applied to that channel’s SimpleGain. |
Purge<n> | Reloads (on) or purges (off) mic position n across every sampler with more than one mic position. |
Mute<n> | Mutes the channel, subject to solo state. |
Solo<n> | Solos the channel; while any channel is soloed, only soloed channels are audible. |
Output<n> | Output bus for the channel, 0–12; routes the channel’s stereo pair to the corresponding routing matrix connection. |
Usage
Build the module tree first (Mixer.js plus one SimpleGain per channel, named mixerGain0, mixerGain1, …), then connect MixerPanel’s controls, or a custom UI, to this module’s parameters via processorId/parameterId.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getAllSamplers() | Collects every Sampler in the tree, used by purgeLoadChannel to purge/reload mic positions across all of them at once. | Array |
soloMuteProcess() | Re-evaluates mute/solo state for every channel and sets each SimpleGain’s Gain to either its knob value or -100 accordingly. Runs whenever any channel’s mute or solo button changes. | — |
purgeLoadChannel(index, value) | Purges or reloads the mic position at index across every sampler that has more than one mic position. | — |
updateOutputConnections(index, value) | Routes a channel’s stereo pair to the routing matrix connection implied by value, falling back to the default stereo output (0/1) if the connection fails. | — |
NoteRangeFilter
File: Rhapsodist/Processors/NoteRangeFilter.js.
Overview
Blocks (or, inverted via Block, exclusively allows) notes outside a specified range.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; no filtering is applied while on. |
LowNote / HighNote | Note range, 0–127. |
Block | On: notes inside the range are blocked. Off: only notes inside the range are allowed. |
Release | Extends filtering to note-offs as well. |
IgnoreTranspose | Range-checks the raw note number instead of the transposed one. By default the current transpose amount is added to the range boundaries before comparing. |
Usage
Load into a container or sound generator’s MIDI Processor chain and set LowNote/HighNote to the desired range.
NoteTransposer
File: Rhapsodist/Processors/NoteTransposer.js.
Overview
Per-semitone (12-tone) transposition, structurally identical to Microtuner but affecting Message.setTransposeAmount instead of detune: setting C to +2 transposes every C on the keyboard by +2 semitones.
HarpPedalPanel drives this exact module (by module ID) to implement pedal-harp-style diatonic retuning.
Parameters
| ID | Description |
|---|---|
Transpose | 12-slot sliderpack, one transpose value per semitone class, -12–12 semitones, step 1.0. Registered via Engine.createAndRegisterSliderPackData(0). |
Usage
Load into a container or sound generator’s MIDI Processor chain, connect a persistent sliderpack from the Interface script to Transpose.
RapidNoteSmoother
File: Rhapsodist/Processors/RapidNoteSmoother.js.
Overview
Reduces velocity and adds a short fade-in when notes are played in rapid succession (within 150 ms).
Creates a harp Bisbigliando effect for fast arpeggios/glissandos. Any note played within 150 ms of the previous one has its velocity halved; the fade-in time is scaled by how close together the notes are, from 10 ms up to 100 ms as the gap approaches 0 ms. Notes within 25 ms of each other (a chord) are left untouched.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; notes pass through unmodified while on. |
Usage
Load into a sampler’s MIDI Processor chain.
ReleaseTrigger
File: Rhapsodist/Processors/ReleaseTrigger.js.
Overview
A fully scripted processor for release “tails” that live as their own separate samples.
It is not merely an alternative to HISE’s native single-sampler Release Start feature, it targets a different use-case where distinct release samples are required.
HISE ships a hardcoded script for that same pattern; ReleaseTrigger.js is a more advanced, drop-in replacement with additional functionality.
A release note triggers on note-off, unless a sustain pedal is holding it, or Legato is on and other keys are still held.
If the sustain pedal is what’s holding notes, releasing it fires the release trigger for the last note played, once no keys remain held.
The triggered note carries the original note’s detune/gain, optional held-duration attenuation, and its own delayed note-off.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; no release note is triggered while on. |
NoteOnPassThru (“Note On Pass Thru”) | When enabled, incoming note-ons are not blocked, useful when the original note-on should still sound normally. |
Legato | Release samples only trigger when no other keys are held. |
Attenuate | Attenuates based on how long the note was held, shaped by tblTime against Time’s range, up to 30 dB. |
IgnoreSustain | When off, an active sustain pedal (CC64) suppresses release triggering on both note-off and pedal release. |
OffDelay (“Off Delay”) | How long after the release note starts before its own note-off fires, min 50 ms. |
Time | Held-duration range used to look up tblTime, 0–60 seconds, step 0.1. Only relevant when Attenuate is on. |
tblTime | Shapes the held-duration attenuation curve used when Attenuate is on (x-axis = normalised held duration against Time, y-axis = attenuation amount). |
Usage
Load into a sampler or container’s MIDI Processor chain and configure as needed.
Internal Reference
| Function | Description | Returns |
|---|---|---|
playReleaseNote(noteNumber, velocity) | Plays the release note, carries over the original note’s detune and gain, applies Attenuate’s held-duration attenuation via tblTime, and schedules the note-off after OffDelay. Called from both onNoteOff and the sustain-pedal release path in onController. | — |
RoundRobin
File: Rhapsodist/Processors/RoundRobin.js.
Overview
A multi-mode round robin engine:
Group mode (advances the sampler’s active RR group)
Velocity mode (offsets/remaps outgoing velocity by RR step)
Borrowed mode (randomised, non-repeating neighbour-note borrowing via transpose + detune).
Modes can be combined, and it can also work as a plain group filter - useful when RR is needed for some articulations and a single group for others.
It resolves the first sampler in the tree automatically and disables that sampler’s own built-in round robin.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; no RR action is taken while on. |
Group / Velocity / Borrowed | Three separate mode buttons. Enables one or more RR modes at once. |
Random | Random step order instead of sequential (Group/Velocity modes). |
Count | Number of variations (Group/Velocity modes), 0–30. |
FirstGroup | Starting sampler group for this articulation (Group mode), 1–50. |
Lock | Bypasses the engine and plays only the selected repetition, 0–20 (0 = unlocked). |
ResetTm | Resets the RR counter after this much idle time, 0–5 seconds, if greater than 0. |
Release | Advances the RR counter on note-off instead of note-on. |
IgnoreLegato | Legato transitions don’t advance the RR counter. |
PerNoteRR | Each note number tracks its own RR step counter, instead of one shared counter. |
VelocityOffset | Velocity mode: enable if a velocity offset was already applied earlier in the chain. |
VelocitySpread | Velocity mode: spread round robins evenly across the velocity range instead of offsetting. |
Usage
Load into a sampler’s MIDI Processor chain (exact position depends on the RR method used and what else is in the chain), enable one or more of Group/Velocity/Borrowed, and configure the matching options.
Internal Reference
| Function | Description | Returns |
|---|---|---|
doRoundRobin(note, velocity) | The core engine: resolves the current RR step (honouring reset-on-idle and Lock), applies whichever of Group/Velocity/Borrowed modes are enabled, and advances the step counter for the next hit. Called from onNoteOn or onNoteOff depending on Release. | — |
TimestretchSyncer
File: Rhapsodist/Processors/TimestretchSyncer.js.
Overview
Keeps a sampler’s timestretch ratio matched to the host tempo, computing newTempo / bpm on every tempo change.
Recommended over the sampler’s built-in tempo sync mode, which is considered awkward by comparison.
Parameters
| ID | Description |
|---|---|
bpm | The tempo the samples were recorded at, 10–200. |
Usage
Place in a sampler’s MIDI Processor chain, set that sampler’s Timestretching mode to VoiceStart or TimeVariant, and set bpm to the tempo the samples were recorded at.
Internal Reference
| Function | Description | Returns |
|---|---|---|
updateTimeStretchRatio(newTempo) | Registered on the transport handler’s tempo-change callback; divides newTempo by bpm and applies the result as the sampler’s timestretch ratio. | — |
VelocityRangeFilter
File: Rhapsodist/Processors/VelocityRangeFilter.js.
Overview
Blocks (or, inverted via Block, exclusively allows) notes outside a specified velocity range.
Parameters
| ID | Description |
|---|---|
Mute | Disables the processor; no filtering is applied while on. |
LowVelocity / HighVelocity | Velocity range, 0–127. |
Block | On: notes within the velocity range are blocked. Off: only notes outside the range are blocked. |
Release | Extends filtering to note-offs as well. |
Usage
Load into a sound generator or container’s MIDI Processor chain and set LowVelocity/HighVelocity to the desired range.
VelocityScaler
File: Rhapsodist/Processors/VelocityScaler.js.
Overview
Remaps incoming MIDI velocity through a table (Velocity). Unlike a modulator’s velocity curve, this rewrites the actual MIDI velocity value, so downstream modules see the scaled value.
Parameters
| ID | Description |
|---|---|
Velocity | Table mapping normalised input velocity (x-axis, 0-1) to normalised output velocity (y-axis, 0-1), registered via Engine.createAndRegisterTableData(0). |
Usage
Load into a sound generator or container’s MIDI Processor chain (conventionally the master chain).
VelocityTable is the paired UI widget; its create(panelId, processorId, options) takes this module’s ID as an explicit processorId argument.
VelocitySetter
File: Rhapsodist/Processors/VelocitySetter.js.
Overview
Forces every note-on to a single fixed velocity.
Parameters
| ID | Description |
|---|---|
Velocity | Fixed velocity applied to every note-on, 0–127. |
Usage
Load into a sampler or container’s MIDI Processor chain and set Velocity to the fixed value.
VibratoController
File: Rhapsodist/Processors/VibratoController.js.
Important
The modelling here is subject to change as it is refined. Might possibly be replaced by a dedicated script modulator in the future.
Overview
Controls the intensity/frequency of LFO-based vibrato, flutter, or growl effects via CC and time variant modulators, resolved by a fixed module naming convention.
One instance is used per mode (Vibrato/Flutter/Growl), selected via cmbMode; switching modes re-resolves every modulator this instance controls.
Parameters
| ID | Description |
|---|---|
Mode | Selects which mode (Vibrato/Flutter/Growl) this instance controls; switching re-resolves every modulator by naming convention. |
Gain | Sets intensity on every matched gain Global Time Variant Modulator for the current mode. |
Pitch | Sets intensity on every matched pitch Global Time Variant Modulator for the current mode, -2–2. |
Xfade | Sets intensity on every matched sampler group crossfade Global Time Variant Modulator for the current mode. |
Rate | Sets the default value on every matched frequency CC modulator for the current mode, 0–127. |
Depth | Sets the default value on every matched intensity CC modulator for the current mode, 0–127. |
Usage
A project using this processor needs a fixed set of modulators, all named by convention.
Global LFOs: vibratoGainLfo, vibratoPitchLfo, flutterGainLfo, flutterPitchLfo, growlPitchLfo (growl only needs pitch).
CC modulators controlling each LFO’s intensity/frequency, following the same naming convention, e.g. vibratoGainLfoIntensityCc. Each one is set to CC 94, an otherwise-unused controller reserved for this purpose across every VibratoController instance in the project.
Target global modulators for gain, pitch, and sampler group crossfade, as needed for the mode.
Interface knobs connected to this script’s parameters, for user control.
Internal Reference
| Function | Description | Returns |
|---|---|---|
getModulators(type: string) | Re-resolves every modulator this instance controls for the given mode (vibrato/flutter/growl): matching LFOs, CC intensity/frequency modulators, and gain/pitch/crossfade Global Time Variant Modulators, all by ID naming convention. Called whenever Mode changes. | — |
Interface Widgets
Rhapsodist/Widgets/
Reusable UI components for building instrument interfaces. They’re optional, include the ones you need via include() and call their create() functions from App/App.js.
ArticulationList
File: Rhapsodist/Widgets/ArticulationList.js · Namespace: ArticulationList.
Overview
Builds a scrollable list of the current patch’s articulations (name + keyswitch note), with a small gain slider per row backed by an articulationGain module (see ArticulationGain). Built on ListPanel for the scrolling and selection mechanics.
Selection and gain sliders
Each row’s gain slider supports double-click to set it to default, and diagonal drag to adjust it. Selecting a row changes the current articulation via ArticulationSwitcher.
The list repopulates automatically on patch change, and keeps the selected row visible (scrolling as needed) on articulation change.
Usage
const pnlArticulationList = ArticulationList.create("pnlCard1", {});
Options
| Option | Description | Default |
|---|---|---|
rowHeight | Row height in pixels, passed through to the underlying ListPanel. | 35 |
margin | Vertical gap between rows, passed through to ListPanel. | 5 |
border | Padding around the list viewport, passed through to ListPanel. | 10 |
Look and Feel
| Function | Draws |
|---|---|
drawArticulationListContainer | The container panel’s background. |
drawArticulationList | The whole list, in place of the built-in per-row drawing below. |
drawArticulationListItem | Each row, in place of the built-in row background/keyswitch/name drawing. |
drawSelectedArticulationIndicator | The selected row’s highlight, in place of the built-in selection/hover fill. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, options: JSON) | Builds the articulation list UI inside panelId. Requires ListPanel.js and ArticulationSwitcher.js. For the per-row gain sliders, the module tree also needs an articulationGain module (ArticulationGain.js). | object |
Internal Reference
| Function | Description | Returns |
|---|---|---|
checkRequirements() | Verifies ListPanel.js and ArticulationSwitcher.js are available before create() proceeds, printing a console error if not. | number |
onpnlArticulationListControl(component, value) | Handles row selection: bypasses the articulation-changed broadcaster while calling ArticulationSwitcher.changeArticulation(), so the switch doesn’t trigger a redundant update back to the list. | — |
createGainSliders(panel: ScriptObject) | Rebuilds all per-row gain sliders. | — |
addGainSlider(parentPanel: ScriptObject, index: number) | Builds a single per-row gain slider. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
bcPatchChanged | Attached to knbPatch’s value. On patch change, repopulates the list from ArticulationDataManager.getAllArticulations() and rebuilds the gain sliders. |
bcArticulationChanged | Attached to knbArticulation’s value. On articulation change, updates the list’s selection and scrolls it into view. |
ButtonGridPanel
File: Rhapsodist/Widgets/ButtonGridPanel.js · Namespace: ButtonGridPanel.
Overview
A minimal, generic radio-button grid. Given an existing panel and a labels array, it paints a numCols × numRows grid of selectable cells and sets the panel’s value to the clicked cell’s flat index.
Usage
Note
Signature may change as it’s refined.
const pnlModeGrid = ButtonGridPanel.create("pnlModeGrid", 3, 1, ["Vibrato", "Flutter", "Growl"], {});
Options
Every key in options is copied onto the panel’s data object; the paint routine reads font and fontSize back from there.
| Option | Description | Default |
|---|---|---|
font | Font used for cell labels. | "medium" |
fontSize | Font size used for cell labels. | 16 |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, numCols: int, numRows: int, labels: Array, options: JSON) | Returns the panel, configured to paint the grid and handle clicks. Clicks past labels.length, and right-clicks, are ignored. | ScriptObject |
EnvelopePanel
File: Rhapsodist/Widgets/EnvelopePanel.js · Namespace: EnvelopePanel.
Overview
Builds a Flex AHDSR UI: a floating tile graph plus a row of knobs (Attack/Hold/Decay/Sustain/Release, plus Attack Level and the three curve knobs, hidden by default since they’re normally set by dragging on the graph).
Knobs and graph
Alt-clicking a knob or the floating tile resets every knob to its default value. Dragging on the graph updates the matching knob and vice versa; both stay in sync. Unless options.defaultLayout is false, the knobs are laid out in a row.
Usage
const pnlEnvelope = EnvelopePanel.create("pnlEnvelopeContainer", "ahdsrController", "globalFlexAhdsr", {})
Options
| Option | Description | Default |
|---|---|---|
defaultLayout | Whether the knob row is arranged automatically via Container.createRow(). | true |
index | Suffix appended to the envelope panel’s own component ID (pnlEnvelope<index>), letting multiple EnvelopePanel instances coexist. | - |
knobHeight | Knob height in pixels, only applied if smaller than the default. | 90 |
Look and Feel
| Function | Draws |
|---|---|
drawAhdsrBackground | The floating tile’s background. |
drawFlexAhdsrFullPath | The full envelope shape (the gradient-filled path behind the active segment). |
drawFlexAhdsrSegment | The currently active segment’s highlighted fill. |
drawFlexAhdsrCurvePoint | The small circle shown at a segment’s curve point on hover. |
drawFlexAhdsrDragPoint | The small square shown at a segment’s drag point on hover. |
drawFlexAhdsrPosition | The playback position marker. No default drawing is provided. |
drawFlexAhdsrBall | The playback ball indicator. |
drawFlexAhdsrText | Text drawn on the graph. No default drawing is provided. |
drawAhdsrKnob | Each knob, in place of CoreLookAndFeel.drawKnob(). |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId, processorId, flexEnvelopeId, options) | Builds the graph and knob row inside panelId. processorId is the AhdsrController.js module the knobs bind to; flexEnvelopeId is the Flex AHDSR modulator the graph connects to. Both must already exist in the module tree. Each knob is bound to processorId’s matching parameter with saveInPreset: true. | ScriptObject |
EqPanel
File: Rhapsodist/Widgets/EqPanel.js · Namespace: EqPanel.
Important
Signature likely to change to align with the other widgets.
Overview
Wraps a HISE Parametric EQ effect (effectId) in a DraggableFilterPanel floating tile, with a small auto-hiding display showing the dragged band’s Gain/Freq/Q values.
Display panel
The display panel shows Gain/Freq/Q while a band is being dragged or hovered, and hides itself automatically shortly after the last update.
Usage
create() doesn’t return the panel, it builds directly onto the existing component:
EqPanel.create("pnlEq", "eq", {});
Options
Every key in options is copied onto the panel’s data object.
| Option | Description | Default |
|---|---|---|
displayBufferProperties | Overrides the display buffer’s ring buffer properties (buffer length, window type, decibel range, and so on) set by setEqProperties(). | — |
Look and Feel
| Function | Draws |
|---|---|
drawFilterBackground | The filter panel’s background. |
drawFilterDragHandle | Each band’s draggable handle. |
drawFilterPath | The frequency response curve. |
drawEqPopupMenuBackground | The background of the EQ’s right-click popup menu. |
drawEqPopupMenuItem | Each item in that popup menu (band type icons, delete/enable options, and so on). |
drawAnalyserPath | The spectrum analyser’s waveform path. |
drawAnalyserGrid | The spectrum analyser’s grid lines. |
drawAnalyserBackground | The spectrum analyser’s background. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, effectId: string, options: JSON) | Builds the floating tile and display panel, and calls Engine.addModuleStateToUserPreset(effectId) so the EQ’s band configuration is included in saved user presets. Sets display-buffer defaults (2048-sample buffer, Blackman Harris window, -100–0 dB range, logarithmic frequency axis, 0.6 decay) via setEqProperties(). | — |
Broadcasters
| Broadcaster | Description |
|---|---|
data.bc | On the panel identified by panelId (fetch it with Content.getComponent(panelId)). Fires on the EQ’s BandMoved/QChanged/MouseOver events; drives the Gain/Freq/Q display text and its show/hide. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
addBroadcasters(displayPanel: ScriptObject, tileId: string, effect: ScriptObject) | Creates the broadcaster described above. | ScriptObject |
setEqProperties(displayBufferSource, properties) | Applies the display buffer’s ring buffer properties (buffer length, window type, decibel range, and so on). | — |
HarpPedalPanel
File: Rhapsodist/Widgets/HarpPedalPanel.js · Namespace: HarpPedalPanel.
Overview
Builds an interactive harp-pedal diagram: a 7-slider sliderpack (one per diatonic pedal position, D-C-B-E-F-G-A left to right, each snapping to flat/natural/sharp), note-name labels, and Key/Scale combo boxes that can set all seven pedals at once.
11 built-in scales are provided (Major, Natural Minor, Harmonic Minor, Major/Minor Pentatonic, Dominant 7th, Octatonic, Half/Full Diminished, Augmented, Whole Tone), across all 12 keys.
Moving pedals and choosing scales
Moving a pedal writes the corresponding semitone offset into the target transposer’s matching pitch-class slot.
Choosing a Key/Scale sets all 7 pedals and the transposer to that scale at once. After every manual pedal move, the Scale combo box is updated to show a matching scale for the current key, or cleared to no selection if the pedals no longer match any known scale.
Alt-clicking the sliderpack resets the Scale combo box to its first item.
Usage
const pnlHarpPedals = HarpPedalPanel.create("pnlHarpPedals", "noteTransposer", {});
Options
| Option | Description | Default |
|---|---|---|
width | Width of the pedal sliderpack. | parentPanel.getWidth() - 80 |
height | Height of the pedal sliderpack. | 100 |
Look and Feel
| Function | Draws |
|---|---|
drawHarpPedalSliderPackBackground | The sliderpack’s background (the diagonal lines forming the harp shape). |
drawHarpPedalSliderPackTextPopup | The value popup shown while dragging a pedal. No default drawing is provided. |
drawHarpPedalSlider | Each individual pedal slider. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, processorId: string, options: JSON) | Builds the pedal diagram, note labels, and Key/Scale combo boxes inside panelId. processorId is a NoteTransposer.js-style module (12-slot transposition sliderpack); create() resolves it via Synth.getSliderPackProcessor(processorId).getSliderPack(0). | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
data.broadcasters.bcScaleChanged | Fires when the Key or Scale combo box changes; sets all 7 pedals and the transposer to the selected key/scale. |
data.broadcasters.sliderPackMouse | Fires on clicks on the pedal sliderpack; alt-clicking resets the Scale combo box to its first item. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
onslpHarpPedalsControl(component, value) | Writes a moved pedal’s semitone offset into the target transposer via setTransposer() and broadcasts the change so the Scale combo box can react. | — |
setTransposer(index: number, value: number) | Maps a pedal index to its pitch class and writes the offset into the transposer. | — |
getScaleIndex(key: number, sliderPack: ScriptObject) | Looks up whether the sliderpack’s current values match a known scale for the given key. | number |
setScale(sliderPack: ScriptObject, key: number, scaleIndex: number) | Applies a chosen key/scale to all 7 pedals and the transposer. | — |
buildScaleTable() | Precomputes the per-key, per-scale pedal patterns used by getScaleIndex()/setScale(), runs once at load. | Array |
ListPanel
File: Rhapsodist/Widgets/ListPanel.js · Namespace: ListPanel.
Overview
Creates a scrollable, interactive list.
Built with a ScriptedViewport plus an inner panel sized to fit all items, with hover/selection highlighting, per-row icons, multi-select, keyboard navigation, and automatic scroll to keep the selection visible.
Selection and keyboard behaviour
With allowMultiSelect on: shift-click for range select, ctrl/cmd-click to toggle one row, and clicking the sole selected row again to deselect it (only if allowNoSelect is also set).
Keyboard: ctrl+A/cmd+A selects all, escape deselects, page up/page down jump to the first/last item, and the cursor keys move one item at a time (wrapping at either end). Might not work in all hosts.
The viewport’s component ID is derived from the parent panel’s ID (its "pnl" prefix becomes "vpt"), useful to know if you need to reference it directly, though create() already exposes it on data.viewport.
Usage
const pnlMyList = ListPanel.create("pnlMyListContainer", ["Item A", "Item B", "Item C"], { rowHeight: 30, allowMultiSelect: true });
Options
| Option | Description | Default |
|---|---|---|
saveInPreset | Whether the list’s selection is saved in the preset. | false |
rowHeight | Height of each row. | 35 |
margin | Space around the inner panel inside the viewport. | 5 |
icons | Per-row Phosphor icon codepoints. | [] |
allowMultiSelect | Enables shift/ctrl-click range and toggle selection. | false |
allowNoSelect | Allows deselecting the sole selected row when multi-select is on. | false |
border | Padding around the viewport. | 0 |
scrollBarThickness | Width of the viewport’s scrollbar. | 10 |
useCustomPaintRoutine | Skips the built-in paint routine, so a caller can supply its own while keeping selection/scrolling/keyboard behaviour. This is how ArticulationList uses it. | false |
Look and Feel
Override the paint routine:
pnlMyList.setPaintRoutine(function(g) {
var items = this.data.items;
// Custom rendering
});
Public API
create() returns the parent panel; the helpers below take that panel as their first argument.
| Function | Description | Returns |
|---|---|---|
create(parentPanelId: string, items: Array, options: JSON) | Returns the parent panel, with viewport and listPanel set on its data object for attaching further callbacks. Prints an error if parentPanelId doesn’t exist. | object |
setItems(panel: ScriptObject, items: Array) | Replaces the item list and resizes. | — |
resize(panel: ScriptObject) | Recomputes height from the current item count. | — |
setIcons(panel: ScriptObject, icons: Array) | Replaces the row icons array. | — |
setAllowMultiSelect(panel: ScriptObject, value: number) | Toggles allowMultiSelect. | — |
selectAll(panel: ScriptObject) / deselectAll(panel: ScriptObject) | No-ops unless allowMultiSelect is on; deselectAll leaves the current value selected unless allowNoSelect is also set. | — |
updateViewportPosition(panel: ScriptObject) | Scrolls so the selected row is visible. | — |
Internal Reference
| Function | Description | Returns |
|---|---|---|
createViewport(parent: ScriptObject, options: JSON) | Creates or reuses the underlying ScriptedViewport (ID derived from the parent panel’s ID) and applies its size/scrollbar properties. | ScriptObject |
paintRoutine() | Default paint routine: draws each row’s background, selection highlight, icon, and label. Applied automatically unless useCustomPaintRoutine is set. | — |
mouseCallback() | Handles hover/click hit-testing and single/multi-select selection logic. | — |
keyPressCallback() | Handles ctrl+A/cmd+A, escape, page up/page down, and cursor-key navigation. | — |
MicrotuningPanel
File: Rhapsodist/Widgets/MicrotuningPanel.js · Namespace: MicrotuningPanel.
Overview
Creates an interactive UI for 12-tone microtuning: a sliderpack with note-name labels, a Reset button, and Shift-left/Shift-right buttons that rotate the twelve stored values. The widget only builds the UI, it does not implement microtuning itself.
Alt-clicking the sliderpack resets every value to 0, independent of the dedicated Reset button.
Usage
const pnlMicrotune = MicrotuningPanel.create("pnlMicrotuneContainer", "microtuner", {});
Options
| Option | Description | Default |
|---|---|---|
width | Width of the microtuning sliderpack. | pnlMicrotune.getWidth() - 32 |
height | Height of the microtuning sliderpack. | pnlMicrotune.getHeight() - 85 |
Look and Feel
| Function | Draws |
|---|---|
drawMicrotuningPanel | The panel’s note-name labels below the sliderpack. |
drawMicrotuningSliderPackTextPopup | The value popup shown while dragging a slider. |
drawMicrotuningSlider | Each of the 12 sliders, including black/white key shading and its value text. |
drawMicrotuningResetButton | The Reset button. |
drawMicrotuningShiftButton | The Shift-left/Shift-right buttons. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, processorId: string, options: JSON) | Builds the sliderpack, labels, Reset button, and Shift-left/Shift-right buttons inside panelId. Binds the 12-slot slpMicrotune sliderpack directly to processorId. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
data.sliderpackMouse | Fires on clicks on the sliderpack; alt-clicking resets every value to 0. |
data.bcResetButtonValue | Fires when the Reset button is clicked; resets every value to 0. |
data.bcShiftButtonValue | Fires when a Shift button is clicked; rotates the twelve stored values one step left or right. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
shiftSliderPackValues(sliderpack: ScriptObject, direction: int) | Rotates the twelve stored values one step left or right, called by the Shift-left/Shift-right buttons. | — |
MixerPanel
File: Rhapsodist/Widgets/MixerPanel.js · Namespace: MixerPanel.
Overview
Creates a complete mixer UI with channel strips: pan, gain, gain meter, gain-value readout, mute, solo, purge, and output routing. processorId, the Mixer.js module ID, is caller-supplied.
Each control’s parameterId is index-suffixed (Pan<i>, Gain<i>, Purge<i>, Mute<i>, Solo<i>, Output<i>), matching Mixer.js’s own per-channel parameter naming. The output routing combo box lists the stereo output pairs available on the root container’s routing matrix.
Mute and solo isolation
Ctrl/Cmd-clicking a channel’s Mute or Solo button isolates it: every other channel’s mute (or solo) is cleared and only the clicked channel stays engaged. A plain click just toggles that one button.
Usage
Build the module tree first: a Mixer.js instance plus one SimpleGain effect per channel.
This widget builds the UI only, bound via processorId/parameterId to Mixer.js’s script parameters. It doesn’t talk to the SimpleGain effects directly; that’s Mixer.js’s job.
const pnlMixer = MixerPanel.create("pnlMixerContainer", 3, "mixer", {})
Options
| Option | Description | Default |
|---|---|---|
gainSliderWidth | Width of each channel’s gain slider. | 22 |
gainSliderHeight | Height of each channel’s gain slider. | 180 |
Look and Feel
| Function | Draws |
|---|---|
drawMixerChannelBackground | A custom background drawn behind the channel strip, before its label and divider line. |
drawMixerPanKnob | The pan knob. |
drawMixerGainSlider | The vertical gain fader. |
drawMixerPeakMeter | The channel’s peak meter. |
drawMixerPurgeButton | The Purge/Load button. |
drawMixerOutput | The output routing combo box. |
drawMixerMuteSoloButton | The Mute and Solo buttons. |
drawMixerGainValue | The gain-value readout below the fader. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, numChannels: int, processorId: string, options: JSON) | Builds a full mixer UI with numChannels channel strips inside panelId. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
data.bcMuteIsolate | Fires when any channel’s Mute button changes value; on Ctrl/Cmd-click, enables the clicked button and disables every other channel’s Mute button. |
data.bcSoloIsolate | Fires when any channel’s Solo button changes value; on Ctrl/Cmd-click, enables the clicked button and disables every other channel’s Solo button. |
Internal Reference
| Function | Description | Returns |
|---|---|---|
addMuteSoloIsolateBroadcasters(panel: ScriptObject, muteButtons: Array, soloButtons: Array) | Implements the Ctrl/Cmd-click isolate behaviour on the Mute and Solo buttons (see Overview). | — |
Pager
File: Rhapsodist/Widgets/Pager.js · Namespace: Pager.
Overview
A tabbed-page mechanism, similar in effect to SwitcherPanel but driven by an existing HISE radio-group button set rather than a value-bearing switcher component.
Any ScriptButton children of buttonContainerId are treated as tab buttons, and any other direct children of panelId are treated as pages, one per button index. Clicking a button shows the matching page and hides the rest.
SwitcherPanel is a more versatile alternative.
Usage
Does not add any components itself; build the buttons and pages first, then call create().
// Buttons in pnlTabButtons (radio group 1) select which child page of pnlPages is visible
const pnlPages = Pager.create("pnlPages", "pnlTabButtons", 1, {});
Options
options is accepted but not currently used.
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, buttonContainerId: string, radioGroup: number, options: JSON) | Wires up an existing button set as tab controls for an existing set of page panels. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
data.broadcasters.buttonWatcher | Fires whenever a button in the radio group changes value; drives the tab buttons’ values and the pages’ visibility directly. Available for an expansion to attach its own listener to the same value change. |
VelocityTable
File: Rhapsodist/Widgets/VelocityTable.js · Namespace: VelocityTable.
Overview
Creates and styles a table that connects to a VelocityScaler.js-style module.
The table’s tableIndex is fixed at 0, selecting which stored curve it edits/displays.
Resetting the table
Alt-clicking the table resets it (component.reset()).
Usage
const pnlVelocity = VelocityTable.create("pnlVelocityContainer", "velocityScaler", {})
Options
options is accepted but not currently used.
Look and Feel
| Function | Draws |
|---|---|
drawVelocityTableBackground | The grid lines drawn behind the curve. |
velocityTable | A whole local Look and Feel object, replacing the table’s default styling entirely instead of overriding one function at a time. |
Public API
| Function | Description | Returns |
|---|---|---|
create(panelId: string, processorId: string, options: JSON) | Builds and styles the table inside panelId, binding it to processorId. | ScriptObject |
Broadcasters
| Broadcaster | Description |
|---|---|
data.broadcasters.tblVelocityMouse | Fires on clicks on the table; alt-clicking resets the table (component.reset()). |