diff --git a/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.cpp b/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.cpp index 829062fd..416a95d1 100644 --- a/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.cpp +++ b/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.cpp @@ -1,10 +1,20 @@ +#include "aap/core/aap_midi2_helper.h" #include "AAPMidiEventTranslator.h" aap::AAPMidiEventTranslator::AAPMidiEventTranslator(RemotePluginInstance* instance, int32_t midiBufferSize, int32_t initialMidiProtocol) : instance(instance), midi_buffer_size(midiBufferSize), + conversion_helper_buffer_size(AAP_MAX_EXTENSION_URI_SIZE + AAP_MAX_EXTENSION_DATA_SIZE + 16), receiver_midi_protocol(initialMidiProtocol) { translation_buffer = (uint8_t*) calloc(1, midi_buffer_size); + conversion_helper_buffer = (uint8_t*) calloc(1, conversion_helper_buffer_size); +} + +aap::AAPMidiEventTranslator::~AAPMidiEventTranslator() { + if (translation_buffer) + free(translation_buffer); + if (conversion_helper_buffer) + free(conversion_helper_buffer); } int32_t aap::AAPMidiEventTranslator::translateMidiEvent(uint8_t * bytes, int32_t length) { @@ -63,10 +73,23 @@ size_t aap::AAPMidiEventTranslator::runThroughMidi2UmpForMidiMapping(uint8_t* by break; } if (presetIndex >= 0) { - // FIXME: this should not trigger non-RT extension event, but rather, generate an - // extension SysEx8 (TBD as per issue #73) and send it so that it can be processed - // in RT-safe manner as well as in sample accurate manner. - instance->getStandardExtensions().setCurrentPresetIndex(presetIndex); + if (instance->getInstanceState() == aap::PluginInstantiationState::PLUGIN_INSTANTIATION_STATE_ACTIVE) { + auto aapxsInstance = instance->getAAPXSManager()->getInstanceFor( + AAP_PRESETS_EXTENSION_URI); + auto size = aap_midi2_generate_aapxs_sysex8( + (uint32_t *) (translation_buffer + translatedIndex), + (midi_buffer_size - translatedIndex) / 4, + conversion_helper_buffer, + conversion_helper_buffer_size, + 0, + AAP_PRESETS_EXTENSION_URI, + (const uint8_t *) aapxsInstance->data, + aapxsInstance->data_size); + translatedIndex += size; + } + else + // Trigger non-RT extension event at inactive state. + instance->getStandardExtensions().setCurrentPresetIndex(presetIndex); } // If a translated AAP parameter change message is detected, then output sysex8. if (parameterIndex < 0) { diff --git a/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.h b/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.h index 41e49843..6ca21525 100644 --- a/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.h +++ b/androidaudioplugin-manager/src/main/cpp/AAPMidiEventTranslator.h @@ -12,6 +12,10 @@ namespace aap { // used when we need MIDI1<->UMP translation. uint8_t* translation_buffer{nullptr}; int32_t midi_buffer_size; + + uint8_t* conversion_helper_buffer{nullptr}; + int32_t conversion_helper_buffer_size; + // MIDI protocol type of the messages it receives via JNI int32_t receiver_midi_protocol; int32_t current_mapping_policy{AAP_PARAMETERS_MAPPING_POLICY_NONE}; @@ -20,6 +24,7 @@ namespace aap { public: AAPMidiEventTranslator(RemotePluginInstance* instance, int32_t midiBufferSize = AAP_MANAGER_MIDI_BUFFER_SIZE, int32_t initialMidiProtocol = CMIDI2_PROTOCOL_TYPE_MIDI2); + ~AAPMidiEventTranslator(); int32_t translateMidiEvent(uint8_t *data, int32_t length); diff --git a/androidaudioplugin-manager/src/main/cpp/LocalDefinitions.h b/androidaudioplugin-manager/src/main/cpp/LocalDefinitions.h index 512edc0b..d652fe63 100644 --- a/androidaudioplugin-manager/src/main/cpp/LocalDefinitions.h +++ b/androidaudioplugin-manager/src/main/cpp/LocalDefinitions.h @@ -1,7 +1,6 @@ #ifndef AAP_CORE_LOCALDEFINITIONS_H #define AAP_CORE_LOCALDEFINITIONS_H -#define AAP_PUBLIC_API __attribute__((__visibility__("default"))) #define AAP_OPEN_CLASS #define AAP_MANAGER_MIDI_BUFFER_SIZE 65536 diff --git a/androidaudioplugin/src/main/cpp/core/hosting/aap_midi2_helper.cpp b/androidaudioplugin/src/main/cpp/core/hosting/aap_midi2_helper.cpp index 0fd966db..4029a0f7 100644 --- a/androidaudioplugin/src/main/cpp/core/hosting/aap_midi2_helper.cpp +++ b/androidaudioplugin/src/main/cpp/core/hosting/aap_midi2_helper.cpp @@ -1,6 +1,10 @@ #include "aap/core/aap_midi2_helper.h" #include "aap/core/host/plugin-instance.h" +#ifdef __cplusplus +extern "C" { +#endif + static uint32_t aapMidi2ExtensionHelperGetUInt32(uint8_t* dst) { if (cmidi2_util_is_platform_little_endian()) return dst[0] + (dst[1] << 8) + (dst[2] << 16) + (dst[1] << 24); @@ -27,17 +31,17 @@ static void* aapMidi2ExtensionInvokeHelperSysEx8Forge(uint64_t data1, uint64_t d return (void*) true; } -bool aapMidi2GenerateAAPXSSysEx8(uint32_t* dst, - size_t dstSizeInInt, - uint8_t* conversionHelperBuffer, - size_t conversionHelperBufferSize, - uint8_t group, - const char* uri, - const uint8_t* data, - size_t dataSize) { +size_t aap_midi2_generate_aapxs_sysex8(uint32_t* dst, + size_t dstSizeInInt, + uint8_t* conversionHelperBuffer, + size_t conversionHelperBufferSize, + uint8_t group, + const char* uri, + const uint8_t* data, + size_t dataSize) { size_t required = 16 + strlen(uri) + 4 + dataSize * sizeof(uint32_t); if (dstSizeInInt < required || conversionHelperBufferSize < required) - return false; + return 0; uint8_t* sysex = conversionHelperBuffer; uint8_t* ptr = sysex; @@ -69,7 +73,7 @@ bool aapMidi2GenerateAAPXSSysEx8(uint32_t* dst, cmidi2_ump_sysex8_process(group, sysex, ptr - sysex, 0, aapMidi2ExtensionInvokeHelperSysEx8Forge, &forge); - return true; + return forge.offset; } cmidi2_ump_binary_read_state* sysex8_binary_reader_helper_select_stream(uint8_t targetStreamId, void* context) { @@ -124,3 +128,6 @@ bool aap_midi2_parse_aapxs_sysex8(aap_midi2_aapxs_parse_context* context, return true; } +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/include/aap/android-audio-plugin.h b/include/aap/android-audio-plugin.h index 1a065cee..92fbd3bf 100644 --- a/include/aap/android-audio-plugin.h +++ b/include/aap/android-audio-plugin.h @@ -7,6 +7,9 @@ #include #include +/* it *may* be used on some public API. Not comprehensive. */ +#define AAP_PUBLIC_API __attribute__((__visibility__("default"))) + #ifdef __cplusplus extern "C" { #endif @@ -49,6 +52,11 @@ typedef struct aap_buffer_t { /* The length of any plugin is limited to this number. */ const int32_t AAP_MAX_PLUGIN_ID_SIZE = 1024; const int32_t AAP_MAX_EXTENSION_URI_SIZE = 1024; +/* + * Maximum transferable AAPXS data size (either as Binder Parcelable or as MIDI2 SysEx8). + * Anything that goes beyond this size in total should be passed via shared memory. + */ +const int32_t AAP_MAX_EXTENSION_DATA_SIZE = 1024; /* forward declarations */ struct AndroidAudioPluginFactory; diff --git a/include/aap/core/aap_midi2_helper.h b/include/aap/core/aap_midi2_helper.h index 820f20ef..de752e47 100644 --- a/include/aap/core/aap_midi2_helper.h +++ b/include/aap/core/aap_midi2_helper.h @@ -10,6 +10,9 @@ #include "aap/android-audio-plugin.h" // C header, not C++. No namespace. +#ifdef __cplusplus +extern "C" { +#endif #define AAP_MIDI2_AAPXS_DATA_MAX_SIZE 1024 @@ -27,31 +30,33 @@ * @param uri the extension URI (must be null terminated) * @param data the extension invocation data * @param dataSize the size of `data` - * @return `true` if success, `false` for failure (so far insufficient memory only). + * @return size of generated bytes (0 if failed) */ -[[maybe_unused]] // FIXME: test! -static bool aapMidi2GenerateAAPXSSysEx8(uint32_t* dst, - size_t dstSizeInInt, - uint8_t* conversionHelperBuffer, - size_t conversionHelperBufferSize, - uint8_t group, - const char* uri, - const uint8_t* data, - size_t dataSize); +[[maybe_unused]] // it is used in androidaudioplugin-manager +AAP_PUBLIC_API +size_t aap_midi2_generate_aapxs_sysex8(uint32_t *dst, + size_t dstSizeInInt, + uint8_t *conversionHelperBuffer, + size_t conversionHelperBufferSize, + uint8_t group, + const char *uri, + const uint8_t *data, + size_t dataSize); struct aap_midi2_aapxs_parse_context { uint8_t group; char uri[AAP_MAX_EXTENSION_URI_SIZE]; // must be null-terminated uint8_t *data; // buffer must be allocated by the parsing host uint32_t dataSize; // parsed result - uint8_t* conversionHelperBuffer; + uint8_t *conversionHelperBuffer; size_t conversionHelperBufferSize; }; +AAP_PUBLIC_API static inline void aap_midi2_aapxs_parse_context_prepare( - aap_midi2_aapxs_parse_context* context, - uint8_t* dataBuffer, - uint8_t* conversionHelperBuffer, + aap_midi2_aapxs_parse_context *context, + uint8_t *dataBuffer, + uint8_t *conversionHelperBuffer, size_t conversionHelperBufferSize) { context->data = dataBuffer; context->dataSize = 0; @@ -62,8 +67,12 @@ static inline void aap_midi2_aapxs_parse_context_prepare( // Reads AAPXS SysEx8 UMP into `aap_midi2_aapxs_parse_context`. // Returns true if it is successfully parsed and it turned out to be AAPXS SysEx8. // In any other case, return false. -bool aap_midi2_parse_aapxs_sysex8(aap_midi2_aapxs_parse_context* context, - uint8_t* umpData, - size_t umpSize); +AAP_PUBLIC_API +bool aap_midi2_parse_aapxs_sysex8(aap_midi2_aapxs_parse_context *context, + uint8_t *umpData, + size_t umpSize); +#ifdef __cplusplus +} // extern "C" +#endif #endif //AAP_CORE_AAP_MIDI2_HELPER_H