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

MIDI-CI profiles extension #363

Open
wants to merge 42 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
863ba70
Add draft midici-profiles.h
Bremmers Jul 20, 2023
fbe3d0c
Merge branch 'free-audio:main' into Bremmers-midici-profiles
Bremmers Nov 18, 2023
6738f8b
added profile specific data
Bremmers Nov 18, 2023
d6d577f
added TODO about 'active'
Bremmers Nov 20, 2023
463a972
Merge branch 'free-audio:main' into Bremmers-midici-profiles
Bremmers May 2, 2024
479ad2f
Add files via upload
Bremmers May 2, 2024
c935d34
Delete include/clap/ext/draft/midici_profiles.h
Bremmers May 2, 2024
0753bb0
Add files via upload
Bremmers May 2, 2024
f07273e
typos
Bremmers May 2, 2024
415de4d
more typos
Bremmers May 2, 2024
012f310
get_data_size() / get_data() don't need channel parameter
Bremmers May 2, 2024
ff0779f
use clap_ostream_t for get_data()
Bremmers May 2, 2024
d9e1433
Added support for output ports
Bremmers May 2, 2024
297a8ad
comments
Bremmers May 2, 2024
03bf236
comments
Bremmers May 2, 2024
a69c9fc
comments
Bremmers May 2, 2024
11ab8bd
comments
Bremmers May 2, 2024
d8c514f
comments
Bremmers May 2, 2024
3861f24
comments
Bremmers May 2, 2024
59f8376
avoid plugins having to implement stream
Bremmers May 3, 2024
b6764f6
Update all.h
Bremmers May 3, 2024
6901df6
Update all.h
Bremmers May 3, 2024
dbec060
better profile_id_t
Bremmers May 3, 2024
9039f3a
better alignment
Bremmers May 3, 2024
88e38c1
improvements
Bremmers May 3, 2024
88c74af
more comments, removed output port version for now, renamed get_data(…
Bremmers May 3, 2024
b6e4a0b
comments
Bremmers May 4, 2024
7006b80
supports Profile Specific Data Messages for (MPE Channel Response etc.)
Bremmers May 4, 2024
6343856
added const
Bremmers May 4, 2024
d94bdc6
disable now works per-instance
Bremmers May 5, 2024
1fa02a3
C fixes
Bremmers May 5, 2024
1987528
more
Bremmers May 5, 2024
0c6e28c
more
Bremmers May 5, 2024
16a3470
Update midici-profiles.h
Bremmers May 5, 2024
e209ae8
Update midici-profiles.h
Bremmers May 5, 2024
a5bbca6
cleanup
Bremmers May 5, 2024
6162dca
more cleanup
Bremmers May 5, 2024
44aa332
feedback from Timo
Bremmers May 5, 2024
0ad74a7
enabled() can point at conflicts
Bremmers May 5, 2024
6597c68
changed enumeration rules
Bremmers May 5, 2024
9798481
added inquiry_target paramater to set_data()
Bremmers May 13, 2024
ca2c6d6
clap_host_midici_profiles.datachanged is now called for profile detai…
Bremmers May 16, 2024
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
1 change: 1 addition & 0 deletions include/clap/all.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
#include "ext/draft/transport-control.h"
#include "ext/draft/triggers.h"
#include "ext/draft/tuning.h"
#include "ext/draft/midici-profiles.h"
169 changes: 169 additions & 0 deletions include/clap/ext/draft/midici-profiles.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#pragma once

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

// usage examples:
// - the host can tell a MIDI keyboard the plugin conforms to the drawbar organ profile, so the keyboard can set up its faders for that.
// - the host can send per-note articulations in MIDI 2.0 protocol note-on attributes if there's an enabled profile for this.

// destination addressing:
// There are 4 types of profiles: single channel, multi channel, group and function block (called "port" here).
// The profile specifications define the type for a specific profile.
// A channel/num_channels pair allows for targeting profiles (used in profile_t, get_details() and enable()):
// single-channel profiles: channel is 0..255, num_channels is 1
// multi-channel profiles: channel is 0..255, num_channels is 1..256
// group profiles: channel is 16 * group, num_channels is 0
// port profiles: channel is 255, num_channels is 0

// enumerating profiles
// clap_plugin_midici_profiles.count()/get() return a list of clap_profile_t structs. Both enabled and disabled profiles are listed.
// All profiles which can potentially be enabled for a destination must be in the list, even if they're mutually exclusive.
// If a conflict occurs clap_plugin_midici_profiles.enable() will return the conflicting profile_index,
// and the host can disable this profile and try again.
// The list doesn't change when profiles are enabled or disabled. The plugin can change the list (if it switches to a different instrument,
// for example). In this case the plugin calls clap_host_midici_profiles.changed().

// Plugin implementations can be quite simple. For example: in case of a single-channel profile and 16 channels, clap_plugin_midici_profiles.count() can always return 16.
// get() uses the current enabled state for each channel.

// A host will typically proceed in this order:
// 1. get list using clap_plugin_midici_profiles.count()/get().
// 2. enable/disable profiles as needed.
// 3. get profile details using clap_plugin_midici_profiles.get_details().

// Plugins can use CLAP_MIDICI_PROFILES_ALWAYSON for profiles which can't be enabled/disabled by the host.
// Note that a plugin can remove a CLAP_MIDICI_PROFILES_ALWAYSON profile and call clap_host_midici_profiles.changed().

// Some features of this extension can only be used with note ports using the CLAP_NOTE_DIALECT_MIDI2 dialect (groups in particular).

static CLAP_CONSTEXPR const char CLAP_EXT_MIDICI_PROFILES[] = "clap.midici-profiles/draft/1";

#ifdef __cplusplus
extern "C" {
#endif

enum {
CLAP_MIDICI_PROFILES_DISABLED = 0,
CLAP_MIDICI_PROFILES_ENABLED = 1,
CLAP_MIDICI_PROFILES_ALWAYSON = 2
};

enum {
CLAP_MIDICI_PROFILES_INQUIRY_TARGET_DATA = 255
};

enum {
CLAP_MIDICI_PROFILES_ENABLE_SUCCES = -1,
CLAP_MIDICI_PROFILES_ENABLE_FAILED = -2
};

typedef struct clap_profile_id {
uint8_t id;
uint8_t bank;
uint8_t number;
uint8_t version;
uint8_t level;
} clap_profile_id_t;

typedef struct clap_profile {
clap_profile_id_t profile_id;
uint8_t channel; // see "destination addressing" paragraph at top of file.
uint16_t num_channels; // see "destination addressing" paragraph at top of file.
uint8_t enabled; // CLAP_MIDICI_PROFILES_*
} clap_profile_t;

typedef struct clap_plugin_midici_profiles {
// Returns the number of clap_profile_t entries available.
// The "enumerating profiles" paragraph above describes what's supposed to be in the list.
// [main-thread]
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin,
uint32_t port_index);

// Get a clap_profile_t by index.
// [main-thread]
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
uint32_t port_index,
uint32_t profile_index,
clap_profile_t *profile);

// inquiry_target is 0..127: get profile details from profile at channel/num_channels for the specified inquiry_target.
// inquiry_target is CLAP_MIDICI_PROFILES_INQUIRY_TARGET_DATA: get Profile Specific Data from profile at channel/num_channels.
// Returns true if data is written to stream correctly.
// Returns false if there's no data available for this inquiry_target.
// channel and num-channels: see "destination addressing" paragraph at top of file.
// The profile targeted by channel/num_channels should generally be enabled before calling this function.
// In some cases profile details may be needed before enabling a profile. Plugins should make sure this is handled correctly.
// CLAP_MIDICI_PROFILES_INQUIRY_TARGET_DATA: Multiple Profile Specific Data Messages can be written to stream. Each one starts with 0xF0,
// followed by the actual Profile Specific Data, and ends with 0xF7. Example: MPE Channel Response Type Notification would be F0 01 F7.
// [main-thread]
bool(CLAP_ABI *get_data)(const clap_plugin_t *plugin,
uint32_t port_index,
const clap_profile_id_t *profile_id,
uint8_t channel,
uint16_t num_channels,
uint8_t inquiry_target,
const clap_ostream_t *stream);

// inquiry_target is 0..127: Send profile details to profile at channel/num_channels for the specified inquiry_target.
// inquiry_target is CLAP_MIDICI_PROFILES_INQUIRY_TARGET_DATA: Send Profile Specific Data to profile at channel/num_channels.
// Returns true if data was accepted
// CLAP_MIDICI_PROFILES_INQUIRY_TARGET_DATA: Multiple Profile Specific Data Messages can be passed in buffer. Each one starts with 0xF0,
// followed by the actual Profile Specific Data, and ends with 0xF7. Example: MPE Channel Response Type Notification would be F0 01 F7.
// A profile may specify multiple data messages. It's recommended to send the complete 'state' in a single set_data() call.
// [main-thread]
bool(CLAP_ABI *set_data)(const clap_plugin_t *plugin,
uint32_t port_index,
const clap_profile_id_t *profile_id,
uint8_t channel,
uint16_t num_channels,
uint8_t inquiry_target,
const uint8_t *buffer,
uint32_t buffer_size);

// Enables a profile at channel/num_channels.
// Returns CLAP_MIDICI_PROFILES_ENABLE_SUCCES if the profile is enabled at channel/num_channels when the function returns.
// Result >= 0 indicates a conflict with an existing enabled profile.
// The host can call get(.., .., Result, ..), disable this profile and try again.
// Returns CLAP_MIDICI_PROFILES_ENABLE_FAILED if an error other than a conflict occured.
// Can be called multiple times to enabled a profile for multiple channels or groups.
// channel and num-channels: see "destination addressing" paragraph at top of file.
// Note for hosts: after calling this function count()/get() may have changed !!
// Note for plugins: do not call clap_host_midici_profiles.changed. Do not disable profiles.
// [main-thread]
int32_t(CLAP_ABI *enable)(const clap_plugin_t *plugin,
uint32_t port_index,
const clap_profile_id_t *profile_id,
uint8_t channel,
uint16_t num_channels);

// Disables a profile at channel/num_channels.
// Returns true if the profile isn't enabled at channel/num_channels when the function returns.
// Note for hosts: after calling this function count()/get() may have changed !!
// Note for plugins: do not call clap_host_midici_profiles.changed.
// [main-thread]
bool(CLAP_ABI *disable)(const clap_plugin_t *plugin,
uint32_t port_index,
const clap_profile_id_t *profile_id,
uint8_t channel,
uint16_t num_channels);
} clap_plugin_midici_profiles_t;

typedef struct clap_host_midici_profiles {
// Informs the host that the available or enabled profiles changed.
// [main-thread]
void(CLAP_ABI *changed)(const clap_host_t *host);

// Plugins calls this if host needs to read profile details or Profile Specific Data Messages again.
// Host calls get_data(.., port_index, profile, channel, num_channels, .., ..) for the inquiry targets it's interested in.
// [main-thread]
void(CLAP_ABI *datachanged)(const clap_host_t *host,
uint32_t port_index,
const clap_profile_id_t *profile_id,
uint8_t channel,
uint16_t num_channels);
} clap_host_midici_profiles_t;

#ifdef __cplusplus
}
#endif