Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 Manifest describing 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

  1. Configuration - Instruments are defined declaratively via JSON data.
  2. Broadcasters - Decoupled communication through HISE’s broadcaster system. This increases the modularity and flexibility of the framework.
  3. 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:

  1. Open the asset manager (File > Open HISE Asset Manager).
  2. Click Add local folders to this list to create assets at the bottom of the package list.
  3. Select the package_install.json file 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

  • local inside an inline function or stock callback.
  • var inside a function.
  • const for fixed values, arrays, and objects declared outside any function. Favour MIDI lists over arrays for related MIDI values.
  • reg for mutable, non-function-scoped namespace-level variables.
  • global variables 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:
PrefixComponent or Variable Type
pnlPanel
btnButton
knbSlider or Knob
cmbComboBox
slpSliderPack
tblTable
vptViewport
fltFloatingTile
bcBroadcaster variables
lafLocal 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:

WidgetPaired ProcessorsConnection
ArticulationListArticulationGain.jsslpArticulationGain bound via processorId
MixerPanelMixer.jsBound via processorId/parameterId
EnvelopePanelAhdsrController.js, Flex AHDSR modulatorKnobs bound via processorId/parameterId; floating tile and drag broadcaster bound to flexEnvelopeId
EqPanelParametric EQ effectfloating tile Data references effectId directly
HarpPedalPanelNoteTransposer.jsWrites to the sliderpack directly
VelocityTableVelocityScaler.jsTable’s processorId/tableIndex properties
MicrotuningPanelMicrotuner.jsslpMicrotune 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:

PropertyEffect
BypassBypasses/unbypasses the module
GainSets gain; on a Sampler the value is treated as dB.
IntensitySets a modulator’s intensity
FileLoads an Audio Sample Processor’s file via the expansion’s wildcard reference
TableRestores a table processor from base64
BipolarSets whether a modulator is bipolar
CrossfadeTable / CrossfadeGroupsRestores explicit sampler crossfade tables, or auto-generates evenly spaced ones for the given group count
IgnoreSkips 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:

  1. Custom initialisation - Any setup logic unique to the project
  2. Override functions - Replacing or extending framework behaviour
  3. 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 ObjectAssign toOverrides
knobrotary ScriptSliderdrawKnob, drawBigKnob, drawSmallKnob
sliderlinear ScriptSliderdrawSlider, drawHorizontalSlider, drawVerticalSlider.
toggleSwitchScriptButtondrawToggleSwitch
iconButtonScriptButton (icon, non-toggling)drawIconButton
iconButtonToggleScriptButton (icon, toggling)drawIconToggleButton
textButtonScriptButton (text, non-toggling)drawTextButton, falling back to drawTextButtonToggle if that’s the only one defined
textButtonToggleScriptButton (text, toggling)drawTextButtonToggle
powerButtonScriptButton (drawn as a power indicator)drawPowerButton
comboBoxScriptComboBoxdrawComboBox for the box itself; its popup uses the shared popup overrides below
viewportScriptedViewportdrawScrollbar (shared, see below)
peakMeterScriptFloatingTile hosting the built-in Matrix Peak MeterdrawMatrixPeakMeter
tableScriptTabledrawTableBackground, drawTablePath, drawTablePoint, drawTableRuler
viewportTableScriptFloatingTile 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
emptywhen you want to draw nothingnone, 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, and viewportTable’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
    }
  }
]
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.

FontInternal Name
AtkinsonHyperlegibleMono-RegularmonoRegular
AtkinsonHyperlegibleMono-MediummonoMedium
AtkinsonHyperlegibleMono-SemiBoldmonoSemiBold
AtkinsonHyperlegibleMono-BoldmonoBold
Phosphorphosphor
Phosphor-ThinphosphorThin
Phosphor-LightphosphorLight
Phosphor-BoldphosphorBold
Phosphor-FillphosphorFill
fontaudiofontaudio

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.hxi header and the sample data are packed into the same archive.
    • Split Data From Samples: the info.hxi header 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.hxi header, 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.

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.js includes directly, in a fixed order, to build the shell and its subsystems.
  • Widgets, the generic layout primitives (Container, SwitcherPanel, SettingsPanel, ValueEdit, Card) and Keyboard, also included automatically by Core.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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
bcPatchChangedFires 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

FunctionDescriptionReturns
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

BroadcasterDescription
bcPatchChangedFires when knbPatch changes value. Applies the Manifest’s top-level components array, then the new patch’s own components array, via setComponentProperties().
bcArticulationChangedFires 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, and data for sliderpacks/tables), already decoded.
  • data.Modules, data.MPEData, module state and MPE data.
  • data.MidiAutomation.Children, saved automation assignments, each with an Attribute naming 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

FunctionDraws
drawPresetBrowserPanelThe whole pnlPresetBrowser panel, replacing its default background/border.
drawPresetBrowserBackgroundThe floating tile’s background fill.
drawPresetBrowserColumnBackgroundA whole bank/category/preset column: its background, border, and label text.
drawPresetBrowserColumnAfterFillAn extra pass after the default column background/border, before its label text; only reached when drawPresetBrowserColumnBackground isn’t overridden.
drawPresetBrowserListItemA single item row in a column.
drawPresetBrowserEditButtonThe Add/Rename/Delete/More edit icon buttons.
drawPresetBrowserSearchBarThe search bar.
drawPresetBrowserScrollbarEach column’s scrollbar.

Public API

FunctionDescriptionReturns
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

BroadcasterDescription
broadcasters.preLoadBroadcaster 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.postLoadBroadcaster that fires after every preset load/save, with the same isInternal argument. Use it to restore state snapshotted in preLoad.

Internal Reference

FunctionDescriptionReturns
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

FunctionDraws
drawHeaderThe header panel’s whole paint routine, replacing the default drawing entirely.
drawPanVolSlidersBoth 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

FunctionDraws
drawFooterThe footer panel’s whole paint routine, replacing the default drawing entirely.
drawStatusBarThe status bar panel’s whole paint routine, replacing the default drawing entirely.
drawLogoThe 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

FunctionDraws
drawSettingsPanelThe whole Settings window panel, replacing the default drawing entirely.
drawSettingsPanelBackgroundThe Settings window panel’s background fill and border, keeping the title text and inner divider line drawn by default.

Public API

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
bcEngineSettingChangedFires 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

FunctionDescriptionReturns
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

BroadcasterDescription
bcMpeBypassWatcherFires 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

FunctionDescriptionReturns
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

BroadcasterDescription
bcTooltipPanelFires 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.
bcTooltipButtonFires 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

FunctionDescriptionReturns
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

BroadcasterDescription
bcpnlHeaderMouseFires on click events in pnlHeader. Resets cmbZoom to index 3 (100%) when the header title area (x between 40 and 300) is double-clicked.
bcpnlZoomValueFires 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.
bccmbZoomValueFires 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

FunctionDescriptionReturns
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:

OptionDescriptionDefault
fillcreateStack()/createRow(). Shares the available height/width equally across children instead of using a fixed or evenly-spread spacing.false
justificationcreateStack(). Cross-axis alignment: "left", "right", or "stretch".Centred
alignmentcreateRow(). Cross-axis alignment: "top", "bottom", or "stretch"."middle"
fillX / fillYcreateGrid(). Fill behaviour along each axis, same meaning as fill above.false
layoutcreateGrid(). Optional per-item array of {colSpan, rowSpan, justification, alignment} specs, for irregular grids.—

Public API

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
panel.data.broadcasters.switcherWatcherThe 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:

OptionDescriptionDefault
useNoiseForwarded as an option to ValueEdit for any child panel setupChildren() upgrades into a ValueEdit control.—

Public API

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
create(panelId: string, options: JSON)Builds the styled background, knob, and step buttons.ScriptObject

Broadcasters

BroadcasterDescription
panel.data.bcThe 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

FunctionDescriptionReturns
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

OptionDescriptionDefault
tabWidthWidth 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

FunctionDraws
drawCardThe card’s whole paint routine, replacing the default drawing entirely.
drawCardBackgroundAn extra pass drawn on top of the card’s default background fill; it doesn’t replace that fill.
drawCardBorderJust the border.
drawCardLabelJust a tab label, on a tabbed card.

Public API

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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.

FunctionDraws
drawWhiteNoteEach white key.
drawBlackNoteEach black key.

Public API

Thin wrappers over the fltKeyboard floating tile, usable by an expansion that needs to adjust keyboard display properties at runtime:

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
bcPatchChangedknbPatch’s value changes. Applies the new patch’s keyranges, if any, and re-colours the keyboard.
bcArticulationChangedknbArticulation’s value changes. Applies the new articulation’s keyranges, if any, and re-colours the keyboard.
bcTranposeChangedknbTranspose’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

IDDescription
PatchCurrent 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.
ArticulationCurrent 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

FunctionDescriptionReturns
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

IDDescription
LazyLoadToggles global Lazy Load mode.
PurgeStateA 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

FunctionDescriptionReturns
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

IDDescription
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

FunctionDescriptionReturns
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

IDDescription
GainDecibel-mode gain, -100–12 dB.
SmoothingTime-mode smoothing, 0–1000 ms.
WidthStereo width, 0–200.
BalancePan-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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
bcTranposeChangedknbTranspose’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

FunctionDescriptionReturns
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

BroadcasterDescription
bcbtnReleaseTriggersValuebtnReleaseTriggers’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

IDDescription
AttackAttack time, in ms.
HoldHold time, in ms.
DecayDecay time, in ms.
SustainSustain level.
ReleaseRelease time, in ms.
AttackLevelAttack level.
AttackCurveAttack curve shape.
DecayCurveDecay curve shape.
ReleaseCurveRelease 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

FunctionDescriptionReturns
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

IDDescription
ArticulationCurrent articulation index, 0–100. Set from the articulation global cable rather than by the user directly.
GainDeveloper-set baseline gain applied before the per-articulation gain, -24–24 dB.
slpGain100-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

FunctionDescriptionReturns
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

IDDescription
MuteDisables the processor; no offset or fade is applied while on.
AttackOffsetMax sample start offset for a fresh attack, -1–20000 samples.
RepeatOffsetMax sample start offset for a repeated attack, -1–20000 samples.
AttackFadeMax fade-in time for a fresh attack, 0–500 ms.
RepeatFadeMax fade-in time for a repeated attack, 0–500 ms.
MinVelocity / MaxVelocityVelocity 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

FunctionDescriptionReturns
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

IDDescription
AttackTime to ease towards the snap target, 0–500 ms.
SmoothUp / SmoothDownRate 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.
Value0–127. Both the resting target and the velocity threshold that decides whether a note’s snap target sits above or below it.
ResponseTableOptional 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

FunctionDescriptionReturns
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

IDDescription
GroupActive 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

IDDescription
TriggerMIDI 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

IDDescription
MuteDisables the processor; see Mute behaviour above.
GlideSwitches between legato mode (off) and glide mode (on), each with its own timing/offset/pitch settings below.
LegatoPitchFine pitch offset applied per step in legato mode, 0–100.
GlidePitchFine pitch offset applied per step in glide mode, 0–100.
StepsMaxCaps 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.
LegatoTimeMinDuration for a one-semitone legato transition, 5–100 ms.
LegatoTimeMaxDuration for an octave-or-more legato transition, 50–1000 ms.
LegatoOffsetSample start offset, in samples, for intermediate legato steps, -1–65535.
TargetOffsetSample start offset, in samples, for the final note of a legato transition, -1–65535.
GlideTimeMinDuration for a one-semitone glide transition, 200–1000 ms.
GlideTimeMaxDuration for an octave-or-more glide transition, 500–2000 ms.
GlideOffsetSample 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

FunctionDescriptionReturns
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

IDDescription
BlockOn: 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

IDDescription
Microtune12-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

FunctionDescriptionReturns
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.

IDDescription
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

FunctionDescriptionReturns
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

IDDescription
MuteDisables the processor; no filtering is applied while on.
LowNote / HighNoteNote range, 0–127.
BlockOn: notes inside the range are blocked. Off: only notes inside the range are allowed.
ReleaseExtends filtering to note-offs as well.
IgnoreTransposeRange-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

IDDescription
Transpose12-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

IDDescription
MuteDisables 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

IDDescription
MuteDisables 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.
LegatoRelease samples only trigger when no other keys are held.
AttenuateAttenuates based on how long the note was held, shaped by tblTime against Time’s range, up to 30 dB.
IgnoreSustainWhen 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.
TimeHeld-duration range used to look up tblTime, 0–60 seconds, step 0.1. Only relevant when Attenuate is on.
tblTimeShapes 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

FunctionDescriptionReturns
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

IDDescription
MuteDisables the processor; no RR action is taken while on.
Group / Velocity / BorrowedThree separate mode buttons. Enables one or more RR modes at once.
RandomRandom step order instead of sequential (Group/Velocity modes).
CountNumber of variations (Group/Velocity modes), 0–30.
FirstGroupStarting sampler group for this articulation (Group mode), 1–50.
LockBypasses the engine and plays only the selected repetition, 0–20 (0 = unlocked).
ResetTmResets the RR counter after this much idle time, 0–5 seconds, if greater than 0.
ReleaseAdvances the RR counter on note-off instead of note-on.
IgnoreLegatoLegato transitions don’t advance the RR counter.
PerNoteRREach note number tracks its own RR step counter, instead of one shared counter.
VelocityOffsetVelocity mode: enable if a velocity offset was already applied earlier in the chain.
VelocitySpreadVelocity 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

FunctionDescriptionReturns
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

IDDescription
bpmThe 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

FunctionDescriptionReturns
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

IDDescription
MuteDisables the processor; no filtering is applied while on.
LowVelocity / HighVelocityVelocity range, 0–127.
BlockOn: notes within the velocity range are blocked. Off: only notes outside the range are blocked.
ReleaseExtends 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

IDDescription
VelocityTable 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

IDDescription
VelocityFixed 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

IDDescription
ModeSelects which mode (Vibrato/Flutter/Growl) this instance controls; switching re-resolves every modulator by naming convention.
GainSets intensity on every matched gain Global Time Variant Modulator for the current mode.
PitchSets intensity on every matched pitch Global Time Variant Modulator for the current mode, -2–2.
XfadeSets intensity on every matched sampler group crossfade Global Time Variant Modulator for the current mode.
RateSets the default value on every matched frequency CC modulator for the current mode, 0–127.
DepthSets 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

FunctionDescriptionReturns
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

OptionDescriptionDefault
rowHeightRow height in pixels, passed through to the underlying ListPanel.35
marginVertical gap between rows, passed through to ListPanel.5
borderPadding around the list viewport, passed through to ListPanel.10

Look and Feel

FunctionDraws
drawArticulationListContainerThe container panel’s background.
drawArticulationListThe whole list, in place of the built-in per-row drawing below.
drawArticulationListItemEach row, in place of the built-in row background/keyswitch/name drawing.
drawSelectedArticulationIndicatorThe selected row’s highlight, in place of the built-in selection/hover fill.

Public API

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
bcPatchChangedAttached to knbPatch’s value. On patch change, repopulates the list from ArticulationDataManager.getAllArticulations() and rebuilds the gain sliders.
bcArticulationChangedAttached 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.

OptionDescriptionDefault
fontFont used for cell labels."medium"
fontSizeFont size used for cell labels.16

Public API

FunctionDescriptionReturns
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

OptionDescriptionDefault
defaultLayoutWhether the knob row is arranged automatically via Container.createRow().true
indexSuffix appended to the envelope panel’s own component ID (pnlEnvelope<index>), letting multiple EnvelopePanel instances coexist.-
knobHeightKnob height in pixels, only applied if smaller than the default.90

Look and Feel

FunctionDraws
drawAhdsrBackgroundThe floating tile’s background.
drawFlexAhdsrFullPathThe full envelope shape (the gradient-filled path behind the active segment).
drawFlexAhdsrSegmentThe currently active segment’s highlighted fill.
drawFlexAhdsrCurvePointThe small circle shown at a segment’s curve point on hover.
drawFlexAhdsrDragPointThe small square shown at a segment’s drag point on hover.
drawFlexAhdsrPositionThe playback position marker. No default drawing is provided.
drawFlexAhdsrBallThe playback ball indicator.
drawFlexAhdsrTextText drawn on the graph. No default drawing is provided.
drawAhdsrKnobEach knob, in place of CoreLookAndFeel.drawKnob().

Public API

FunctionDescriptionReturns
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.

OptionDescriptionDefault
displayBufferPropertiesOverrides the display buffer’s ring buffer properties (buffer length, window type, decibel range, and so on) set by setEqProperties().—

Look and Feel

FunctionDraws
drawFilterBackgroundThe filter panel’s background.
drawFilterDragHandleEach band’s draggable handle.
drawFilterPathThe frequency response curve.
drawEqPopupMenuBackgroundThe background of the EQ’s right-click popup menu.
drawEqPopupMenuItemEach item in that popup menu (band type icons, delete/enable options, and so on).
drawAnalyserPathThe spectrum analyser’s waveform path.
drawAnalyserGridThe spectrum analyser’s grid lines.
drawAnalyserBackgroundThe spectrum analyser’s background.

Public API

FunctionDescriptionReturns
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

BroadcasterDescription
data.bcOn 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

FunctionDescriptionReturns
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

OptionDescriptionDefault
widthWidth of the pedal sliderpack.parentPanel.getWidth() - 80
heightHeight of the pedal sliderpack.100

Look and Feel

FunctionDraws
drawHarpPedalSliderPackBackgroundThe sliderpack’s background (the diagonal lines forming the harp shape).
drawHarpPedalSliderPackTextPopupThe value popup shown while dragging a pedal. No default drawing is provided.
drawHarpPedalSliderEach individual pedal slider.

Public API

FunctionDescriptionReturns
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

BroadcasterDescription
data.broadcasters.bcScaleChangedFires when the Key or Scale combo box changes; sets all 7 pedals and the transposer to the selected key/scale.
data.broadcasters.sliderPackMouseFires on clicks on the pedal sliderpack; alt-clicking resets the Scale combo box to its first item.

Internal Reference

FunctionDescriptionReturns
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

OptionDescriptionDefault
saveInPresetWhether the list’s selection is saved in the preset.false
rowHeightHeight of each row.35
marginSpace around the inner panel inside the viewport.5
iconsPer-row Phosphor icon codepoints.[]
allowMultiSelectEnables shift/ctrl-click range and toggle selection.false
allowNoSelectAllows deselecting the sole selected row when multi-select is on.false
borderPadding around the viewport.0
scrollBarThicknessWidth of the viewport’s scrollbar.10
useCustomPaintRoutineSkips 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.

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

OptionDescriptionDefault
widthWidth of the microtuning sliderpack.pnlMicrotune.getWidth() - 32
heightHeight of the microtuning sliderpack.pnlMicrotune.getHeight() - 85

Look and Feel

FunctionDraws
drawMicrotuningPanelThe panel’s note-name labels below the sliderpack.
drawMicrotuningSliderPackTextPopupThe value popup shown while dragging a slider.
drawMicrotuningSliderEach of the 12 sliders, including black/white key shading and its value text.
drawMicrotuningResetButtonThe Reset button.
drawMicrotuningShiftButtonThe Shift-left/Shift-right buttons.

Public API

FunctionDescriptionReturns
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

BroadcasterDescription
data.sliderpackMouseFires on clicks on the sliderpack; alt-clicking resets every value to 0.
data.bcResetButtonValueFires when the Reset button is clicked; resets every value to 0.
data.bcShiftButtonValueFires when a Shift button is clicked; rotates the twelve stored values one step left or right.

Internal Reference

FunctionDescriptionReturns
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

OptionDescriptionDefault
gainSliderWidthWidth of each channel’s gain slider.22
gainSliderHeightHeight of each channel’s gain slider.180

Look and Feel

FunctionDraws
drawMixerChannelBackgroundA custom background drawn behind the channel strip, before its label and divider line.
drawMixerPanKnobThe pan knob.
drawMixerGainSliderThe vertical gain fader.
drawMixerPeakMeterThe channel’s peak meter.
drawMixerPurgeButtonThe Purge/Load button.
drawMixerOutputThe output routing combo box.
drawMixerMuteSoloButtonThe Mute and Solo buttons.
drawMixerGainValueThe gain-value readout below the fader.

Public API

FunctionDescriptionReturns
create(panelId: string, numChannels: int, processorId: string, options: JSON)Builds a full mixer UI with numChannels channel strips inside panelId.ScriptObject

Broadcasters

BroadcasterDescription
data.bcMuteIsolateFires 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.bcSoloIsolateFires 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

FunctionDescriptionReturns
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

FunctionDescriptionReturns
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

BroadcasterDescription
data.broadcasters.buttonWatcherFires 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

FunctionDraws
drawVelocityTableBackgroundThe grid lines drawn behind the curve.
velocityTableA whole local Look and Feel object, replacing the table’s default styling entirely instead of overriding one function at a time.

Public API

FunctionDescriptionReturns
create(panelId: string, processorId: string, options: JSON)Builds and styles the table inside panelId, binding it to processorId.ScriptObject

Broadcasters

BroadcasterDescription
data.broadcasters.tblVelocityMouseFires on clicks on the table; alt-clicking resets the table (component.reset()).