From 16f1a8e146b345c349c0619a7368bf1ce33a5a39 Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Wed, 25 Sep 2024 10:40:33 +0200 Subject: [PATCH 1/6] converting utf8 to utf16 correctly --- src/detail/vst3/parameter.cpp | 14 ++++-- src/detail/vst3/parameter.h | 2 + src/wrapasvst3.cpp | 89 ++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/detail/vst3/parameter.cpp b/src/detail/vst3/parameter.cpp index 40c934ff..c5073b5f 100644 --- a/src/detail/vst3/parameter.cpp +++ b/src/detail/vst3/parameter.cpp @@ -92,9 +92,11 @@ Vst3Parameter* Vst3Parameter::create( } } - str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); + // str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); + utf8_to_utf16l(fullname.c_str(), (uint16_t*)(v.title), str16BufferSize(v.title)); // TODO: string shrink algorithm shortening the string a bit - str8ToStr16(v.shortTitle, info->name, str16BufferSize(v.shortTitle)); + // str8ToStr16(v.shortTitle, info->name, str16BufferSize(v.shortTitle)); + utf8_to_utf16l(info->name, (uint16_t*)v.shortTitle, str16BufferSize(v.shortTitle)); v.units[0] = 0; // unfortunately, CLAP has no unit for parameter values v.unitId = unit; @@ -153,9 +155,13 @@ Vst3Parameter* Vst3Parameter::create(uint8_t bus, uint8_t channel, uint8_t cc, V { fullname = "controller"; } - str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); + + utf8_to_utf16l(fullname.c_str(), (uint16_t*)(v.title), str16BufferSize(v.title)); + utf8_to_utf16l(name, (uint16_t*)v.shortTitle, str16BufferSize(v.shortTitle)); + + // str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); // TODO: string shrink algorithm shortening the string a bit - str8ToStr16(v.shortTitle, name, str16BufferSize(v.shortTitle)); + // str8ToStr16(v.shortTitle, name, str16BufferSize(v.shortTitle)); v.units[0] = 0; // nothing in the "unit" field // the unit will not be set here, but outside diff --git a/src/detail/vst3/parameter.h b/src/detail/vst3/parameter.h index e2ef4c57..72dea7d2 100644 --- a/src/detail/vst3/parameter.h +++ b/src/detail/vst3/parameter.h @@ -28,6 +28,8 @@ #include #include +void utf8_to_utf16l(const char* utf8string, uint16_t* target, size_t targetsize); + class Vst3Parameter : public Steinberg::Vst::Parameter { using super = Steinberg::Vst::Parameter; diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index f26b1af1..63cfb766 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -42,6 +42,84 @@ struct ClapHostExtensions }; #endif +void utf8_to_utf16l(const char* utf8string, uint16_t* target, size_t targetsize) +{ + bool result = true; + uint32_t codepoint = 0; + int state = 1; + size_t targetpos = 0; + + auto src = reinterpret_cast(utf8string); + size_t pos = 0; + while (src[pos] && (targetpos < (targetsize - 1))) + { + auto byte = src[pos]; + + if ((byte & 0b10000000) == 0b00000000) + { + codepoint = byte; + pos += 1; + } + else + { + if (((byte & 0b11100000) == 0b11000000) && src[1]) + { + codepoint = byte & 0b00011111; + codepoint = (codepoint << 6) | ((src[pos + 1]) & 0b00111111); + pos += 2; + } + else if (((byte & 0b11110000) == 0b11100000) && src[1] && src[2]) + { + codepoint = byte & 0b00001111; + codepoint = (codepoint << 6) | ((src[pos + 1] & 0b00111111)); + codepoint = (codepoint << 6) | ((src[pos + 2] & 0b00111111)); + pos += 3; + } + else if (((byte & 0b11111000) == 0b11110000) && src[1] && src[2] && src[3]) + { + codepoint = byte & 0b00000111; + codepoint = (codepoint << 6) | ((src[pos + 1] & 0b00111111)); + codepoint = (codepoint << 6) | ((src[pos + 2] & 0b00111111)); + codepoint = (codepoint << 6) | ((src[pos + 3] & 0b00111111)); + pos += 4; + } + else + { + return; + } + } + { + if (codepoint >= 0xD800 && codepoint <= 0xDFFF) + { + target[targetpos] = 0; + return; + // throw conversion_error("illegal UTF-32 codepoint (surrogat area)"); + } + if (codepoint <= 0xFFFF) + { + target[targetpos++] = codepoint; + } + else + { + if (codepoint <= 0x10FFFF && (targetpos < (targetsize - 3))) + { + codepoint -= 0x10000; + uint16_t highsurr = static_cast((codepoint >> 10) + 0xD800); + uint16_t lowsurr = static_cast((codepoint & 0x3FF) + 0xDC00); + target[targetpos++] = highsurr; + target[targetpos++] = lowsurr; + } + else + { + target[targetpos] = 0; + return; + } + } + } + } + target[targetpos] = 0; +} + tresult PLUGIN_API ClapAsVst3::initialize(FUnknown* context) { auto result = super::initialize(context); @@ -337,6 +415,10 @@ tresult PLUGIN_API ClapAsVst3::getParamValueByString(Vst::ParamID id, Vst::TChar char inbuf[128]; m.copyTo8(inbuf, 0, 128); double out = 0.; + if (param->isMidi) + { + return Steinberg::kResultFalse; + } if (this->_plugin->_ext._params->text_to_value(_plugin->_plugin, param->id, inbuf, &out)) { valueNormalized = param->asVst3Value(out); @@ -545,7 +627,9 @@ void ClapAsVst3::addAudioBusFrom(const clap_audio_port_info_t* info, bool is_inp // bool supports64bit = (info->flags & CLAP_AUDIO_PORT_SUPPORTS_64BITS); Steinberg::char16 name16[256]; // str8tostr16 writes to position n to terminate, so don't overflow - Steinberg::str8ToStr16(&name16[0], info->name, 255); + + // Steinberg::str8ToStr16(&name16[0], info->name, 255); + utf8_to_utf16l(info->name, (uint16_t*)name16, 255); if (is_input) { addAudioInput(name16, spk, bustype, Vst::BusInfo::kDefaultActive); @@ -569,7 +653,8 @@ void ClapAsVst3::addMIDIBusFrom(const clap_note_port_info_t* info, uint32_t inde Steinberg::char16 name16[256]; // str8tostr16 writes to position n to terminate, so don't overflow - Steinberg::str8ToStr16(&name16[0], info->name, 255); + // Steinberg::str8ToStr16(&name16[0], info->name, 255); + utf8_to_utf16l(info->name, (uint16_t*)name16, 255); if (is_input) { addEventInput(name16, numchannels, Vst::BusTypes::kMain, Vst::BusInfo::kDefaultActive); From ea8046908b328d5b5db3118395e43cfa8455e31d Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Wed, 25 Sep 2024 10:44:50 +0200 Subject: [PATCH 2/6] removing unused variables --- src/wrapasvst3.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index 63cfb766..c2bbd7db 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -43,10 +43,8 @@ struct ClapHostExtensions #endif void utf8_to_utf16l(const char* utf8string, uint16_t* target, size_t targetsize) -{ - bool result = true; +{ uint32_t codepoint = 0; - int state = 1; size_t targetpos = 0; auto src = reinterpret_cast(utf8string); From 26b561800918e4e399ed9215cc566e69f21ec12b Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Wed, 25 Sep 2024 10:46:05 +0200 Subject: [PATCH 3/6] formatting --- src/wrapasvst3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index c2bbd7db..ac79e676 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -43,7 +43,7 @@ struct ClapHostExtensions #endif void utf8_to_utf16l(const char* utf8string, uint16_t* target, size_t targetsize) -{ +{ uint32_t codepoint = 0; size_t targetpos = 0; From 0a057dc6b297e041aa5d0c1f43590b82f6f909b5 Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Wed, 25 Sep 2024 17:29:23 +0200 Subject: [PATCH 4/6] prevent overflow --- src/wrapasvst3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index ac79e676..3798ae9a 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -49,7 +49,7 @@ void utf8_to_utf16l(const char* utf8string, uint16_t* target, size_t targetsize) auto src = reinterpret_cast(utf8string); size_t pos = 0; - while (src[pos] && (targetpos < (targetsize - 1))) + while (src[pos] && (targetpos < (targetsize - 2))) { auto byte = src[pos]; From 3de9651b910a69b33f12a63f0aa66333e380bf33 Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Thu, 26 Sep 2024 09:29:24 +0200 Subject: [PATCH 5/6] converting param values and bus names from utf8 instead of ASCII, too --- src/wrapasvst3.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index 3798ae9a..1a20c5ef 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -385,6 +385,8 @@ tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::Param if (param->isMidi) { auto r = std::to_string((int)val); + + // usually we try to avoid UString assignment, but here it is okay. UString wrapper(&string[0], str16BufferSize(Steinberg::Vst::String128)); wrapper.assign(r.c_str(), (Steinberg::int32)(r.size() + 1)); @@ -397,9 +399,8 @@ tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::Param if (this->_plugin->_ext._params->value_to_text(_plugin->_plugin, param->id, val, outbuf, 127)) { - UString wrapper(&string[0], str16BufferSize(Steinberg::Vst::String128)); + utf8_to_utf16l(outbuf, (uint16_t*) &string[0], str16BufferSize(Steinberg::Vst::String128)); - wrapper.assign(outbuf, sizeof(outbuf)); return kResultOk; } return super::getParamStringByValue(id, valueNormalized, string); @@ -1586,8 +1587,7 @@ tresult ClapAsVst3::getBusInfo(Vst::MediaType type, Vst::BusDirection dir, int32 bus.busType = (info.flags & CLAP_AUDIO_PORT_IS_MAIN) ? Vst::kMain : Vst::kAux; bus.flags = Vst::BusInfo::kDefaultActive; - UString wrapper(&bus.name[0], str16BufferSize(Steinberg::Vst::String128)); - wrapper.assign(info.name, (Steinberg::int32)CLAP_NAME_SIZE); + utf8_to_utf16l(info.name, (uint16_t*)&bus.name[0], str16BufferSize(Steinberg::Vst::String128)); return kResultOk; } From cea8b133a55da91d872e51d426c24375ff1ef779 Mon Sep 17 00:00:00 2001 From: Timo Kaluza Date: Thu, 26 Sep 2024 09:30:39 +0200 Subject: [PATCH 6/6] do the formatting dance --- src/wrapasvst3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index 1a20c5ef..345ff7c8 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -399,7 +399,7 @@ tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::Param if (this->_plugin->_ext._params->value_to_text(_plugin->_plugin, param->id, val, outbuf, 127)) { - utf8_to_utf16l(outbuf, (uint16_t*) &string[0], str16BufferSize(Steinberg::Vst::String128)); + utf8_to_utf16l(outbuf, (uint16_t*)&string[0], str16BufferSize(Steinberg::Vst::String128)); return kResultOk; }