From b2eeb12fc336474ac6cfc9780995ba46949d563f Mon Sep 17 00:00:00 2001 From: yaw-man Date: Tue, 16 Aug 2022 10:47:12 -0300 Subject: [PATCH] =?UTF-8?q?Grand=20validation:=20Ajout=C3=A9=20interface?= =?UTF-8?q?=20pour=20plusiers=20APIs=20de=20tablette.=20Essay=C3=A9=20d'aj?= =?UTF-8?q?outer=20.NET=20interop=20Chang=C3=A9=20storage=20des=20champs?= =?UTF-8?q?=20Nouveau=20functions=20pour=20afficher=20du=20texte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 16 +++ src/yaw-tab/CMakeLists.txt | 8 +- src/yaw-tab/DistrhoPluginInfo.h | 10 +- src/yaw-tab/dsp.cpp | 20 ++-- src/yaw-tab/rtstylus.cpp | 23 +++++ src/yaw-tab/tablet.h | 45 +++++++++ src/yaw-tab/ui.cpp | 171 ++++++++------------------------ src/yaw-tab/wintab.cpp | 147 ++++++++++++--------------- 8 files changed, 211 insertions(+), 229 deletions(-) create mode 100644 src/yaw-tab/tablet.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c74bb48..5d4579f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,20 @@ cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_STANDARD 20) + +#include(CMakePrintHelpers) + + +# Runtime checks are not compatiable +#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") +#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") +#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") +#cmake_print_variables(CMAKE_C_FLAGS) +#cmake_print_variables(CMAKE_C_FLAGS_DEBUG) + +# Exception handling should use C++ standard stack unwinding +#string(REGEX REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +#string(REGEX REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") project(yaw-audio) add_subdirectory("lib") add_subdirectory("src") \ No newline at end of file diff --git a/src/yaw-tab/CMakeLists.txt b/src/yaw-tab/CMakeLists.txt index 88e4891..ae967e6 100644 --- a/src/yaw-tab/CMakeLists.txt +++ b/src/yaw-tab/CMakeLists.txt @@ -12,5 +12,11 @@ target_include_directories(yaw-tab PUBLIC "." "../../lib/wintab" ) +target_compile_definitions(yaw-tab PUBLIC YAW_USE_WINTAB) + +set_target_properties(yaw-tab PROPERTIES VS_DOTNET_REFERENCES "System") +set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/clr") +set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/Zc:twoPhase-") + +# default compiler flags from CMAKE conflict with managed code compliation, probably a better way of doing this. -target_compile_definitions(yaw-tab PUBLIC YAW_USE_WINTAB=1 YAW_USE_RTSTYLUS=1) \ No newline at end of file diff --git a/src/yaw-tab/DistrhoPluginInfo.h b/src/yaw-tab/DistrhoPluginInfo.h index 38114bc..29286c6 100644 --- a/src/yaw-tab/DistrhoPluginInfo.h +++ b/src/yaw-tab/DistrhoPluginInfo.h @@ -19,11 +19,11 @@ #endif enum Parameters { - kParameterTabletX = 0, - kParameterTabletY, - kParameterTabletZ, - kParameterTabletPressure, - kParameterTabletButtons, + ktpax = 0, + ktpay, + ktpaz, + ktpap, + ktpab, kParameterTime, kParameterCount }; diff --git a/src/yaw-tab/dsp.cpp b/src/yaw-tab/dsp.cpp index bc7fac1..69642b5 100644 --- a/src/yaw-tab/dsp.cpp +++ b/src/yaw-tab/dsp.cpp @@ -33,23 +33,23 @@ protected: switch (index) { - case kParameterTabletX: + case ktpax: parameter.name = "x"; parameter.symbol = "x"; break; - case kParameterTabletY: + case ktpay: parameter.name = "y"; parameter.symbol = "y"; break; - case kParameterTabletZ: + case ktpaz: parameter.name = "z"; parameter.symbol = "z"; break; - case kParameterTabletPressure: + case ktpap: parameter.name = "p"; parameter.symbol = "p"; break; - case kParameterTabletButtons: + case ktpab: parameter.name = "Buttons"; parameter.symbol = "b"; parameter.hints = kParameterIsAutomable | kParameterIsInteger; @@ -78,17 +78,17 @@ protected: { fParameters[idx] = val; switch (idx) { - case kParameterTabletX: + case ktpax: period = 0.02f * val * static_cast(sampleRate); break; - case kParameterTabletY: + case ktpay: break; - case kParameterTabletZ: + case ktpaz: break; - case kParameterTabletPressure: + case ktpap: volume = val; break; - case kParameterTabletButtons: + case ktpab: break; } } diff --git a/src/yaw-tab/rtstylus.cpp b/src/yaw-tab/rtstylus.cpp index e69de29..b093fbd 100644 --- a/src/yaw-tab/rtstylus.cpp +++ b/src/yaw-tab/rtstylus.cpp @@ -0,0 +1,23 @@ +#ifdef YAW_USE_OTD +// text_write.cpp +// compile with: /clr +using namespace System; +using namespace System::IO; + +int func() +{ + String^ fileName = "textfile.txt"; + + StreamWriter^ sw = gcnew StreamWriter(fileName); + sw->WriteLine("A text file is born!"); + sw->Write("You can use WriteLine"); + sw->WriteLine("...or just Write"); + sw->WriteLine("and do {0} output too.", "formatted"); + sw->WriteLine("You can also send non-text objects:"); + sw->WriteLine(DateTime::Now); + sw->Close(); + Console::WriteLine("a new file ('{0}') has been written", fileName); + + return 0; +} +#endif \ No newline at end of file diff --git a/src/yaw-tab/tablet.h b/src/yaw-tab/tablet.h new file mode 100644 index 0000000..be3167d --- /dev/null +++ b/src/yaw-tab/tablet.h @@ -0,0 +1,45 @@ +//Interface to supported tablet APIs. +#include +#include + +#ifdef YAW_USE_WINTAB +#include +#include "MSGPACK.H" +#include "wintab.h" +#endif + + +struct Packet { + float x; + float y; + float z; + float p; + unsigned long buttons; + bool operator==(const Packet& p) + { return + this->x == p.x && + this->y == p.y && + this->z == p.z && + this->p == p.p && + this->buttons == p.buttons; + }; + bool operator!=(const Packet& p) { return !(*this == p); } +}; + +class Tablet { +public: + Tablet(uintptr_t handle); + ~Tablet(); + bool GetPacket( Packet &pkt ); + bool initialized; + std::string errormsg = ""; + +private: + + Packet ext = { 0 }; + +#ifdef YAW_USE_WINTAB + void NewContext(HWND hwnd); + HCTX hctx = NULL; +#endif +}; \ No newline at end of file diff --git a/src/yaw-tab/ui.cpp b/src/yaw-tab/ui.cpp index b2a84bd..eeac73d 100644 --- a/src/yaw-tab/ui.cpp +++ b/src/yaw-tab/ui.cpp @@ -1,10 +1,6 @@ #include "DistrhoUI.hpp" -#ifdef YAW_USE_WINTAB -#include "wintab.cpp" -#endif -#ifdef YAW_USE_RTSTYLUS -#include "rtstylus.cpp" -#endif +#include "tablet.h" +#include START_NAMESPACE_DISTRHO @@ -18,12 +14,8 @@ public: : UI(kInitialWidth, kInitialHeight), fSampleRate(getSampleRate()), fResizable(isResizable()), - fScale(1.0f), - fScaleFactor(getScaleFactor()), - tab(reinterpret_cast(getWindow().getNativeWindowHandle())) + tab(getWindow().getNativeWindowHandle()) { - std::memset(fParameters, 0, sizeof(float) * kParameterCount); - std::memset(fStrBuf, 0, sizeof(char) * (0xff + 1)); #ifdef DGL_NO_SHARED_RESOURCES createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"); @@ -38,42 +30,32 @@ protected: void getTabletData() { - //Lire donnés de la tablet - tab.NewPacket(); - - float x = static_cast(tab.pkt.pkX) / tab.extX; - float y = static_cast(tab.pkt.pkY) / tab.extY; - float z = static_cast(tab.pkt.pkZ) / tab.extZ; - float p = static_cast(tab.pkt.pkNormalPressure) / tab.extP; - - if (x != fParameters[kParameterTabletX]) { - setParameterValue(kParameterTabletX, x); - fParameters[kParameterTabletX] = x; - } - if (y != fParameters[kParameterTabletY]) { - setParameterValue(kParameterTabletY, y); - fParameters[kParameterTabletY] = y; - } - if (z != fParameters[kParameterTabletZ]) { - setParameterValue(kParameterTabletZ, z); - fParameters[kParameterTabletZ] = z; - } - if (p != fParameters[kParameterTabletPressure]) { - setParameterValue(kParameterTabletPressure, p); - fParameters[kParameterTabletPressure] = p; - } + if (!tab.initialized || !tab.GetPacket(pkt)) return; + if (pkt == lastPkt) return; + if (pkt.x != lastPkt.x) setParameterValue(ktpax, pkt.x); + if (pkt.y != lastPkt.y) setParameterValue(ktpay, pkt.y); + if (pkt.z != lastPkt.z) setParameterValue(ktpaz, pkt.z); + if (pkt.p != lastPkt.p) setParameterValue(ktpap, pkt.p); + if (pkt.buttons != lastPkt.buttons) setParameterValue(ktpab, pkt.buttons); + lastPkt = pkt; } void parameterChanged(uint32_t index, float value) override { - if (index != kParameterTime) { - fParameters[index] = value; + if (index != kParameterTime && index < kParameterCount) { + switch (index) + { + case(ktpax): pkt.x = value; + case(ktpay): pkt.y = value; + case(ktpaz): pkt.z = value; + case(ktpap): pkt.p = value; + case(ktpab): pkt.buttons = static_cast(value); + } return; } getTabletData(); - repaint(); } @@ -100,44 +82,30 @@ protected: void onNanoDisplay() override { - drawCircle( - fParameters[kParameterTabletX], - fParameters[kParameterTabletY], - fParameters[kParameterTabletZ], - fParameters[kParameterTabletPressure] - ); + fontSize(15.0f); + textLineHeight(1.f); - const float lineHeight = 20 * fScale; - - fontSize(15.0f * fScale); - textLineHeight(lineHeight); - - - - float x = 0.0f * fScale; - float y = 15.0f * fScale; - - if (!tab.wintabAvailable) { - drawLeft(x, y, "Failed to connect to tablet."); + //Report tablet errors. + if (!tab.initialized) { + const std::string err = std::vformat("Tablet not supported:\n{}", + std::make_format_args(tab.errormsg)); + beginPath(); + fillColor(200, 200, 200); + // textBox(0.f, 15.f, 250.f, err.c_str(), nullptr); + closePath(); return; } - drawLeft(x, y, "x:"); - drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletX])); - y += lineHeight; - - drawLeft(x, y, "y:"); - drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletY])); - y += lineHeight; - - drawLeft(x, y, "z:"); - drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletZ])); - y += lineHeight; - - drawLeft(x, y, "p:"); - drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletPressure])); - y += lineHeight; + //Numerical feedback. + beginPath(); + fillColor(200, 200, 200); + textBox(0.f, 15.f, 250.f, + std::format("x: {:.3f}\ny: {:.3f}\nz: {:.3f}\np: {:.3f}\nb: {}", + pkt.x, pkt.y, pkt.z, pkt.p, pkt.buttons).c_str(), nullptr); + closePath(); + //Pen position and pressure. + drawCircle(pkt.x, pkt.y, pkt.z, pkt.p); } void drawCircle(float x, float y, float z, float p) { @@ -156,8 +124,8 @@ protected: beginPath(); strokeColor(1.f, 1.f, 1.f, 0.5f); - moveTo(x , y - z * circleRadius); - lineTo(x , y + z * circleRadius); + moveTo(x, y - z * circleRadius); + lineTo(x, y + z * circleRadius); stroke(); closePath(); @@ -192,7 +160,6 @@ protected: private: // Parameters - float fParameters[kParameterCount]; double fSampleRate; // UI stuff @@ -202,61 +169,9 @@ private: // Tablet context handler Tablet tab; + Packet pkt = { 0 }; + Packet lastPkt = { 0 }; - // temp buf for text - char fStrBuf[0xff + 1]; - - // helpers for putting text into fStrBuf and returning it - const char* getTextBufInt(const int value) - { - std::snprintf(fStrBuf, 0xff, "%i", value); - return fStrBuf; - } - - const char* getTextBufFloat(const float value) - { - std::snprintf(fStrBuf, 0xff, "%.1f", value); - return fStrBuf; - } - - const char* getTextBufFloatExtra(const float value) - { - std::snprintf(fStrBuf, 0xff, "%.2f", value + 0.001f); - return fStrBuf; - } - - const char* getTextBufTime(const uint64_t frame) - { - const uint32_t time = frame / uint64_t(fSampleRate); - const uint32_t secs = time % 60; - const uint32_t mins = (time / 60) % 60; - const uint32_t hrs = (time / 3600) % 60; - std::snprintf(fStrBuf, 0xff, "%02i:%02i:%02i", hrs, mins, secs); - return fStrBuf; - } - - // helpers for drawing text - void drawLeft(float x, const float y, const char* const text, const int offset = 0) - { - const float width = (100.0f + offset) * fScale; - x += offset * fScale; - beginPath(); - fillColor(200, 200, 200); - textAlign(ALIGN_RIGHT | ALIGN_TOP); - textBox(x, y, width, text); - closePath(); - } - - void drawRight(float x, const float y, const char* const text, const int offset = 0) - { - const float width = (100.0f + offset) * fScale; - x += offset * fScale; - beginPath(); - fillColor(255, 255, 255); - textAlign(ALIGN_LEFT | ALIGN_TOP); - textBox(x + (105 * fScale), y, width, text); - closePath(); - } /** Set our UI class as non-copyable and add a leak detector just in case. diff --git a/src/yaw-tab/wintab.cpp b/src/yaw-tab/wintab.cpp index 25d51c2..d1ff0b2 100644 --- a/src/yaw-tab/wintab.cpp +++ b/src/yaw-tab/wintab.cpp @@ -1,104 +1,81 @@ -#include -#include -#include "MSGPACK.H" -#include "wintab.h" - +#ifdef YAW_USE_WINTAB +#include "tablet.h" #define PACKETDATA (PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE) -#define PACKETMODE PK_BUTTONS +//#define PACKETMODE #include "pktdef.h" #include "wtutil.h" -class Tablet { -public: +Tablet::Tablet(uintptr_t handle) +{ + HWND hwnd = reinterpret_cast(handle); + if (!hwnd) { return; } - Tablet(HWND hwnd) { - if (!hwnd) { return; } - - if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) { - return; - } - - NewContext(hwnd); + if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) { + errormsg = "Wintab not installed."; + return; } - ~Tablet() { - if (hctx) { gpWTClose(hctx); } - UnloadWintab(); + NewContext(hwnd); +} + +Tablet::~Tablet() { + if (hctx) { gpWTClose(hctx); } + UnloadWintab(); +} + +bool Tablet::GetPacket( Packet& packet ) { + //Serial number of newest packet. + UINT oldest, newest; + //This function returns false when it fails + //which may happen with a full or empty queue. + if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) { + //Queue may be full, flush it all just in case. + gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr); + return false; } - bool NewPacket() { - //Serial number of newest packet. - UINT oldest, newest; - //This function returns false when it fails - //which may happen with a full or empty queue. - if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) { - //Queue may be full, flush it all just in case. - gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr); - return false; - } + //Store newest packet in pkt, flush older packets. + PACKET pkt; + bool newData = gpWTPacket(hctx, newest, &pkt); + if (!newData) return false; + packet.x = static_cast(pkt.pkX) / ext.x; + packet.y = static_cast(pkt.pkY) / ext.y; + packet.z = static_cast(pkt.pkZ) / ext.z; + packet.p = static_cast(pkt.pkNormalPressure) / ext.p; + packet.buttons = pkt.pkButtons; + return true; +} - //Store newest packet in pkt, flush older packets. - return gpWTPacket(hctx, newest, &pkt); - } - - bool wintabAvailable = false; - PACKET pkt = { 0 }; - UINT maxPressure = 1; - float extX; - float extY; - float extZ; - float extP; - -private: - - HCTX hctx = NULL; - UINT wDevice = 0; +void Tablet::NewContext(HWND hwnd) { + if (hctx) { gpWTClose(hctx); } + LOGCONTEXT ctx = {}; AXIS TabletX = { 0 }; AXIS TabletY = { 0 }; AXIS TabletZ = { 0 }; AXIS TabletPressure = { 0 }; - LOGCONTEXT ctx = {}; + gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx); + ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela + ctx.lcPktData = PACKETDATA; + ctx.lcPktMode = 0; - void NewContext(HWND hwnd) { - if (hctx) { gpWTClose(hctx); } - gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx); - ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela - ctx.lcPktData = PACKETDATA; - ctx.lcPktMode = PACKETMODE; - - //Tablet extents. - gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX); - gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY); - gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ); - gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure); + //Tablet extents. + gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX); + gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY); + gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ); + gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure); - ctx.lcInOrgX = TabletX.axMin; - ctx.lcInExtX = TabletX.axMax; - ctx.lcOutOrgX = TabletX.axMin; - ctx.lcOutExtX = TabletX.axMax; - extX = static_cast(TabletX.axMax); + ext.x = static_cast(TabletX.axMax); + ext.y = static_cast(TabletY.axMax); + ext.z = static_cast(TabletZ.axMax); + ext.p = static_cast(TabletPressure.axMax); - ctx.lcInOrgY = TabletY.axMin; - ctx.lcInExtY = TabletY.axMax; - ctx.lcOutOrgY = TabletY.axMin; - ctx.lcOutExtY = TabletY.axMax; - extY = static_cast(TabletY.axMax); + hctx = gpWTOpenA(hwnd, &ctx, TRUE); - ctx.lcInOrgZ = TabletZ.axMin; - ctx.lcInExtZ = TabletZ.axMax; - ctx.lcOutOrgZ = TabletZ.axMin; - ctx.lcOutExtZ = TabletZ.axMax; - extZ = static_cast(TabletZ.axMax); - - extP = static_cast(TabletPressure.axMax); - - hctx = gpWTOpenA(hwnd, &ctx, FALSE); - - if (!hctx) { return; } - - gpWTEnable(hctx, TRUE); - wintabAvailable = true; + if (!hctx) + { + errormsg = "Could not open Wintab context."; + return; } - - -}; \ No newline at end of file + initialized = true; +}; +#endif \ No newline at end of file