Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webview extension (draft) #430

Open
wants to merge 15 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# Changes in 1.2.3

## New draft extensions

* [scratch-memory](include/clap/ext/draft/scratch-memory.h): host provided scratch memory within the process call
* [location](include/clap/ext/draft/location.h): better info about the plugin location within the project

## Documention

* [events.h](include/clap/events.h): clarify sysex lifetime
* [host.h](include/clap/host.h): clarify `request_callback()`
* [ambisonic.h](include/clap/ext/ambisonic.h): remove bad comment

## Fixes

* [plugin-template.c](src/plugin-template.c): fix bad assertion

# Changes in 1.2.2

* [thread-check.h](include/clap/ext/thread-check.h): expand the thread-doc to clarify and expand realtime
Expand Down
3 changes: 3 additions & 0 deletions include/clap/all.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
#include "ext/draft/resource-directory.h"
#include "ext/draft/transport-control.h"
#include "ext/draft/triggers.h"
#include "ext/draft/location.h"
#include "ext/draft/tuning.h"
#include "ext/draft/undo.h"
#include "ext/draft/scratch-memory.h"
#include "ext/draft/webview.h"
2 changes: 2 additions & 0 deletions include/clap/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ typedef struct clap_color {
uint8_t blue;
} clap_color_t;

static const CLAP_CONSTEXPR clap_color_t CLAP_COLOR_TRANSPARENT = { 0, 0, 0, 0 };

#ifdef __cplusplus
}
#endif
31 changes: 29 additions & 2 deletions include/clap/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ extern "C" {
#endif

// event header
// must be the first attribute of the event
// All clap events start with an event header to determine the overall
// size of the event and its type and space (a namespacing for types).
// clap_event objects are contiguous regions of memory which can be copied
// with a memcpy of `size` bytes starting at the top of the header. As
// such, be very careful when desiginig clap events with internal pointers
// and other non-value-types to consider the lifetime of those members.
typedef struct clap_event_header {
uint32_t size; // event size including this header, eg: sizeof (clap_event_note)
uint32_t time; // sample offset within the buffer for this event
Expand Down Expand Up @@ -266,6 +271,12 @@ enum clap_transport_flags {
CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL = 1 << 7,
};

// clap_event_transport provides song position, tempo, and similar information
// from the host to the plugin. There are two ways a host communicates these values.
// In the `clap_process` structure sent to each processing block, the host must
// provide a transport structure which indicates the available information at the
// start of the block. If the host provides sample-accurate tempo or transport changes,
// it can also provide subsequent inter-block transport updates by delivering a new event.
typedef struct clap_event_transport {
clap_event_header_t header;

Expand Down Expand Up @@ -297,11 +308,27 @@ typedef struct clap_event_midi {
uint8_t data[3];
} clap_event_midi_t;

// clap_event_midi_sysex contains a pointer to a sysex contents buffer.
// The lifetime of this buffer is (from host->plugin) only the process
// call in which the event is delivered or (from plugin->host) only the
// duration of a try_push call.
//
// Since `clap_output_events.try_push` requires hosts to make a copy of
// an event, host implementers receiving sysex messages from plugins need
// to take care to both copy the event (so header, size, etc...) but
// also memcpy the contents of the sysex pointer to host-owned memory, and
// not just copy the data pointer.
//
// Similarly plugins retaining the sysex outside the lifetime of a single
// process call must copy the sysex buffer to plugin-owned memory.
//
// As a consequence, the data structure pointed to by the sysex buffer
// must be contiguous and copyable with `memcpy` of `size` bytes.
typedef struct clap_event_midi_sysex {
clap_event_header_t header;

uint16_t port_index;
const uint8_t *buffer; // midi buffer
const uint8_t *buffer; // midi buffer. See lifetime comment above.
uint32_t size;
} clap_event_midi_sysex_t;

Expand Down
3 changes: 0 additions & 3 deletions include/clap/ext/ambisonic.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ typedef struct clap_plugin_ambisonic {
const clap_ambisonic_config_t *config);

// Returns true on success
//
// config_id: the configuration id, see clap_plugin_audio_ports_config.
// If config_id is CLAP_INVALID_ID, then this function queries the current port info.
// [main-thread]
bool(CLAP_ABI *get_config)(const clap_plugin_t *plugin,
bool is_input,
Expand Down
73 changes: 73 additions & 0 deletions include/clap/ext/draft/location.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#pragma once

#include "../../color.h"
#include "../../plugin.h"
#include "../../string-sizes.h"

// This extension allows a host to tell the plugin more about its position
// within a project or session.

static CLAP_CONSTEXPR const char CLAP_EXT_LOCATION[] = "clap.location/1";

#ifdef __cplusplus
extern "C" {
#endif

enum {
// Represents a document/project/session.
CLAP_PLUGIN_LOCATION_PROJECT = 1,

// Represents a group of tracks.
// It can contain both track groups, tracks and devices (post processing).
// The first device within a track group has the index of
// the last track or track group within this group + 1.
CLAP_PLUGIN_LOCATION_TRACK_GROUP = 2,

// Represents a single tracks. It contains devices (serial).
CLAP_PLUGIN_LOCATION_TRACK = 3,

// Represents a single device.
// It contains other nested device chains.
CLAP_PLUGIN_LOCATION_DEVICE = 4,

// Represents a nested device chain (serial).
// Its parent must be a device.
// It contains other devices.
CLAP_PLUGIN_LOCATION_NESTED_DEVICE_CHAIN = 5,
};

typedef struct clap_plugin_location_element {
// Kind of the element, must be one of the CLAP_PLUGIN_LOCATION_* values.
uint32_t kind;

// Index within the parent element.
// Set to 0 if irrelevant.
uint32_t index;

// Internal ID of the element.
// This is not intended for display to the user,
// but rather to give the host a potential quick way for lookups.
char id[CLAP_PATH_SIZE];

// User friendly name of the element.
char name[CLAP_NAME_SIZE];

// Color for this element, should be CLAP_COLOR_TRANSPARENT if no color is
// used for this element.
clap_color_t color;
} clap_plugin_location_element_t;

typedef struct clap_plugin_location {
// Called by the host when the location of the plugin instance changes.
//
// The last item in this array always refers to the device itself, and as
// such is expected to be of kind CLAP_PLUGIN_LOCATION_DEVICE.
// [main-thread]
void(CLAP_ABI *set_location)(clap_plugin_t *plugin,
clap_plugin_location_element_t *path,
uint32_t num_elements);
} clap_plugin_location_t;

#ifdef __cplusplus
}
#endif
91 changes: 91 additions & 0 deletions include/clap/ext/draft/scratch-memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#pragma once

#include "../../plugin.h"

// This extension lets the plugin request "scratch" memory
// from the host. Scratch memory can be accessed during the
// `process()` callback, but its content is not persistent
// between callbacks.
//
// The motivation for this extension is to allow the plugin host
// to "share" a single scratch buffer across multiple plugin
// instances.
//
// For example, imagine the host needs to process three plugins
// in sequence, and each plugin requires 10K of scratch memory.
// If each plugin pre-allocates its own scratch memory, then 30K
// of memory is being allocated in total. However, if each plugin
// requests 10K of scratch memory from the host, then the host can
// allocate a single 10K scratch buffer, and make it available to all
// three plugins.
//
// This optimization may allow for reduced memory usage and improved
// CPU cache usage.

static CLAP_CONSTEXPR const char CLAP_EXT_SCRATCH_MEMORY[] = "clap.scratch-memory/1";

#ifdef __cplusplus
extern "C" {
#endif

typedef struct clap_host_scratch_memory {
// Asks the host for certain amount of scratch memory.
// If the host is unable to provide the memory, it should
// return "false".
//
// The plugin may call this method multiple times (for
// example, gradually decreasing the amount of scratch
// being asked for until the host returns true), however,
// the plugin should avoid calling this method un-neccesarily
// since the host implementation may be relatively expensive.
// If the plugin calls `reserve()` multiple times, then the
// final call determines the actual amount of scratch memory
// that will be available to the plugin. If the final call
// returns false then no scratch memory will be provided,
// regardless of any previous calls to `reserve()`.
//
// When the plugin is de-activated, the scratch memory
// is invalidated, and the host may free the memory if
// appropriate. The plugin will need to reserve scratch
// memory again the next time it is activated.
//
// In the context of plugins and hosts that implement
// the "thread-pool" extension, scratch memory is assumed
// to be "thread-local". The plugin should request the maximum
// amount of scratch memory that it will need on a single
// thread. Accordingly, the host must ensure that each
// thread can independently provide the requested amount
// of scratch memory.
//
// [main-thread & being-activated]
bool(CLAP_ABI *reserve)(const clap_host_t *host, uint32_t scratch_size_bytes);

// Asks the host for the previously reserved scratch memory.
// If the host returned "true" when scratch memory was requested,
// then this method must return a pointer to a memory block at least
// as large as the reserved size. If the host returned "false"
// when scratch memory was requested, then this method must not
// be called, and will return NULL.
//
// This method may only be called by the plugin from the audio thread,
// (i.e. during the process() or thread_pool.exec() callback), and
// the provided memory is only valid until the plugin returns from
// that callback. The plugin must not hold any references to data
// that lives in the scratch memory after returning from the callback,
// as that data will likely be over-written by another plugin using
// the same scratch memory.
//
// The provided memory is not initialized, and may have been used
// by other plugin instances, so the plugin must correctly initialize
// the memory when using it.
//
// The provided memory is owned by the host, so the plugin must not
// free the memory.
//
// [audio-thread]
void*(CLAP_ABI *access)(const clap_host_t *host);
} clap_host_scratch_memory_t;

#ifdef __cplusplus
}
#endif
60 changes: 60 additions & 0 deletions include/clap/ext/draft/webview.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

static CLAP_CONSTEXPR const char CLAP_EXT_WEBVIEW[] = "clap.webview/1";

// clap.gui API constant. The pointer in clap_window must be NULL, but sizing methods are useful.
// uses logical size, don't call clap_plugin_gui->set_scale()
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WEBVIEW[] = "webview";

#ifdef __cplusplus
extern "C" {
#endif

/// @page Webview
///
/// This extension enables the plugin to provide the start-page for a webview UI, and exchange
/// messages back and forth.
///
/// Messages are received in the webview using a standard MessageEvent, with the data in an
/// ArrayBuffer. They are posted back to the plugin using window.parent.postMessage(), with the
/// data in an ArrayBuffer or TypedArray.

typedef struct clap_plugin_webview {
// Returns the URL for the webview's initial navigation, as a null-terminated UTF-8 string.
// This must be called while the webview is not open, and must be called before it is opened.
// If this URL is relative, it is resolved relative to the plugin (bundle) resource directory.
// The host may assume that no resources outside of that directory are used, and may use any
// protocol to provide this content, following HTTP-like relative URL resolution. The page must
// not assume that the root path of the domain is the root of the bundle. The URL may also be
// absolute, including a `file://` URL.
// Returns true on success.
// [main-thread]
bool(CLAP_ABI *provide_starting_uri)(const clap_plugin_t *plugin,
char *out_buffer,
uint32_t out_buffer_capacity);

// Receives a single message from the webview, which must be open.
// Returns true on success.
// [main-thread]
bool(CLAP_ABI *receive)(const clap_plugin_t *plugin, const void *buffer, uint32_t size);

} clap_plugin_webview_t;

typedef struct clap_host_webview {
// Returns whether the webview is "open" (running and ready to receive messages).
// If called from the main thread, it must return the open state specified by other methods.
// If called from any other thread, it must only be used as a hint for non-essential work (such
// as to skip metering calculations) as there are no synchronisation guarantees.
// [thread-safe]
bool(CLAP_ABI *is_open)(const clap_host_t *host);

// Sends a single message to the webview.
// Returns true on success. Should fail if the webview is not open.
// [main-thread]
bool(CLAP_ABI *send)(const clap_host_t *host, const void *buffer, uint32_t size);

} clap_host_webview_t;

#ifdef __cplusplus
}
#endif
11 changes: 9 additions & 2 deletions include/clap/ext/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
/// Embedding the window gives more control to the host, and feels more integrated.
/// Floating window are sometimes the only option due to technical limitations.
///
/// The Embedding protocol is by far the most common, supported by all hosts to date,
/// and a plugin author should support at least that case.
///
/// Showing the GUI works as follow:
/// 1. clap_plugin_gui->is_api_supported(), check what can work
/// 2. clap_plugin_gui->create(), allocates gui resources
Expand Down Expand Up @@ -85,7 +88,10 @@ typedef struct clap_gui_resize_hints {
bool can_resize_horizontally;
bool can_resize_vertically;

// only if can resize horizontally and vertically
// if both horizontal and vertical resize are available, do we preserve the
// aspect ratio, and if so, what is the width x height aspect ratio to preserve.
// These flags are unused if can_resize_horizontally or vertically are false,
// and ratios are unused if preserve is false.
bool preserve_aspect_ratio;
uint32_t aspect_ratio_width;
uint32_t aspect_ratio_height;
Expand All @@ -94,7 +100,8 @@ typedef struct clap_gui_resize_hints {
// Size (width, height) is in pixels; the corresponding windowing system extension is
// responsible for defining if it is physical pixels or logical pixels.
typedef struct clap_plugin_gui {
// Returns true if the requested gui api is supported
// Returns true if the requested gui api is supported, either in floating (plugin-created)
// or non-floating (embedded) mode.
// [main-thread]
bool(CLAP_ABI *is_api_supported)(const clap_plugin_t *plugin, const char *api, bool is_floating);

Expand Down
6 changes: 3 additions & 3 deletions include/clap/ext/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ typedef struct clap_param_info {
// '/' will be used as a separator to show a tree-like structure.
char module[CLAP_PATH_SIZE];

double min_value; // Minimum plain value
double max_value; // Maximum plain value
double default_value; // Default plain value
double min_value; // Minimum plain value. Must be finite (`std::isfinite` true)
double max_value; // Maximum plain value. Must be finite
double default_value; // Default plain value. Must be in [min, max] range.
} clap_param_info_t;

typedef struct clap_plugin_params {
Expand Down
7 changes: 7 additions & 0 deletions include/clap/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ typedef struct clap_host {
void(CLAP_ABI *request_process)(const struct clap_host *host);

// Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread.
// This callback should be called as soon as practicable, usually in the host application's next
// available main thread time slice. Typically callbacks occur within 33ms / 30hz.
// Despite this guidance, plugins should not make assumptions about the exactness of timing for
// a main thread callback, but hosts should endeavour to be prompt. For example, in high load
// situations the environment may starve the gui/main thread in favor of audio processing,
// leading to substantially longer latencies for the callback than the indicative times given
// here.
// [thread-safe]
void(CLAP_ABI *request_callback)(const struct clap_host *host);
} clap_host_t;
Expand Down
1 change: 1 addition & 0 deletions include/clap/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ typedef struct clap_plugin {
// In this call the plugin may allocate memory and prepare everything needed for the process
// call. The process's sample rate will be constant and process's frame count will included in
// the [min, max] range, which is bounded by [1, INT32_MAX].
// In this call the plugin may call host-provided methods marked [being-activated].
// Once activated the latency and port configuration must remain constant, until deactivation.
// Returns true on success.
// [main-thread & !active]
Expand Down
Loading