Grand validation:

Ajouté interface pour plusiers APIs de tablette.
Essayé d'ajouter .NET interop
Changé storage des champs
Nouveau functions pour afficher du texte
This commit is contained in:
yaw-man 2022-08-16 10:47:12 -03:00
parent 422ec60f3b
commit b2eeb12fc3
8 changed files with 211 additions and 229 deletions

View File

@ -1,4 +1,20 @@
cmake_minimum_required(VERSION 3.10) 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) project(yaw-audio)
add_subdirectory("lib") add_subdirectory("lib")
add_subdirectory("src") add_subdirectory("src")

View File

@ -12,5 +12,11 @@ target_include_directories(yaw-tab PUBLIC
"." "."
"../../lib/wintab" "../../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)

View File

@ -19,11 +19,11 @@
#endif #endif
enum Parameters { enum Parameters {
kParameterTabletX = 0, ktpax = 0,
kParameterTabletY, ktpay,
kParameterTabletZ, ktpaz,
kParameterTabletPressure, ktpap,
kParameterTabletButtons, ktpab,
kParameterTime, kParameterTime,
kParameterCount kParameterCount
}; };

View File

@ -33,23 +33,23 @@ protected:
switch (index) switch (index)
{ {
case kParameterTabletX: case ktpax:
parameter.name = "x"; parameter.name = "x";
parameter.symbol = "x"; parameter.symbol = "x";
break; break;
case kParameterTabletY: case ktpay:
parameter.name = "y"; parameter.name = "y";
parameter.symbol = "y"; parameter.symbol = "y";
break; break;
case kParameterTabletZ: case ktpaz:
parameter.name = "z"; parameter.name = "z";
parameter.symbol = "z"; parameter.symbol = "z";
break; break;
case kParameterTabletPressure: case ktpap:
parameter.name = "p"; parameter.name = "p";
parameter.symbol = "p"; parameter.symbol = "p";
break; break;
case kParameterTabletButtons: case ktpab:
parameter.name = "Buttons"; parameter.name = "Buttons";
parameter.symbol = "b"; parameter.symbol = "b";
parameter.hints = kParameterIsAutomable | kParameterIsInteger; parameter.hints = kParameterIsAutomable | kParameterIsInteger;
@ -78,17 +78,17 @@ protected:
{ {
fParameters[idx] = val; fParameters[idx] = val;
switch (idx) { switch (idx) {
case kParameterTabletX: case ktpax:
period = 0.02f * val * static_cast<float>(sampleRate); period = 0.02f * val * static_cast<float>(sampleRate);
break; break;
case kParameterTabletY: case ktpay:
break; break;
case kParameterTabletZ: case ktpaz:
break; break;
case kParameterTabletPressure: case ktpap:
volume = val; volume = val;
break; break;
case kParameterTabletButtons: case ktpab:
break; break;
} }
} }

View File

@ -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

45
src/yaw-tab/tablet.h Normal file
View File

@ -0,0 +1,45 @@
//Interface to supported tablet APIs.
#include <array>
#include <string>
#ifdef YAW_USE_WINTAB
#include <Windows.h>
#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
};

View File

@ -1,10 +1,6 @@
#include "DistrhoUI.hpp" #include "DistrhoUI.hpp"
#ifdef YAW_USE_WINTAB #include "tablet.h"
#include "wintab.cpp" #include <format>
#endif
#ifdef YAW_USE_RTSTYLUS
#include "rtstylus.cpp"
#endif
START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO
@ -18,12 +14,8 @@ public:
: UI(kInitialWidth, kInitialHeight), : UI(kInitialWidth, kInitialHeight),
fSampleRate(getSampleRate()), fSampleRate(getSampleRate()),
fResizable(isResizable()), fResizable(isResizable()),
fScale(1.0f), tab(getWindow().getNativeWindowHandle())
fScaleFactor(getScaleFactor()),
tab(reinterpret_cast<HWND>(getWindow().getNativeWindowHandle()))
{ {
std::memset(fParameters, 0, sizeof(float) * kParameterCount);
std::memset(fStrBuf, 0, sizeof(char) * (0xff + 1));
#ifdef DGL_NO_SHARED_RESOURCES #ifdef DGL_NO_SHARED_RESOURCES
createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"); createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
@ -38,42 +30,32 @@ protected:
void getTabletData() void getTabletData()
{ {
//Lire donnés de la tablet if (!tab.initialized || !tab.GetPacket(pkt)) return;
tab.NewPacket(); if (pkt == lastPkt) return;
if (pkt.x != lastPkt.x) setParameterValue(ktpax, pkt.x);
float x = static_cast<float>(tab.pkt.pkX) / tab.extX; if (pkt.y != lastPkt.y) setParameterValue(ktpay, pkt.y);
float y = static_cast<float>(tab.pkt.pkY) / tab.extY; if (pkt.z != lastPkt.z) setParameterValue(ktpaz, pkt.z);
float z = static_cast<float>(tab.pkt.pkZ) / tab.extZ; if (pkt.p != lastPkt.p) setParameterValue(ktpap, pkt.p);
float p = static_cast<float>(tab.pkt.pkNormalPressure) / tab.extP; if (pkt.buttons != lastPkt.buttons) setParameterValue(ktpab, pkt.buttons);
lastPkt = pkt;
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;
}
} }
void parameterChanged(uint32_t index, float value) override void parameterChanged(uint32_t index, float value) override
{ {
if (index != kParameterTime) { if (index != kParameterTime && index < kParameterCount) {
fParameters[index] = value; 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<unsigned long>(value);
}
return; return;
} }
getTabletData(); getTabletData();
repaint(); repaint();
} }
@ -100,44 +82,30 @@ protected:
void onNanoDisplay() override void onNanoDisplay() override
{ {
drawCircle( fontSize(15.0f);
fParameters[kParameterTabletX], textLineHeight(1.f);
fParameters[kParameterTabletY],
fParameters[kParameterTabletZ],
fParameters[kParameterTabletPressure]
);
const float lineHeight = 20 * fScale; //Report tablet errors.
if (!tab.initialized) {
fontSize(15.0f * fScale); const std::string err = std::vformat("Tablet not supported:\n{}",
textLineHeight(lineHeight); std::make_format_args(tab.errormsg));
beginPath();
fillColor(200, 200, 200);
// textBox(0.f, 15.f, 250.f, err.c_str(), nullptr);
float x = 0.0f * fScale; closePath();
float y = 15.0f * fScale;
if (!tab.wintabAvailable) {
drawLeft(x, y, "Failed to connect to tablet.");
return; return;
} }
drawLeft(x, y, "x:"); //Numerical feedback.
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletX])); beginPath();
y += lineHeight; fillColor(200, 200, 200);
textBox(0.f, 15.f, 250.f,
drawLeft(x, y, "y:"); std::format("x: {:.3f}\ny: {:.3f}\nz: {:.3f}\np: {:.3f}\nb: {}",
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletY])); pkt.x, pkt.y, pkt.z, pkt.p, pkt.buttons).c_str(), nullptr);
y += lineHeight; closePath();
drawLeft(x, y, "z:");
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletZ]));
y += lineHeight;
drawLeft(x, y, "p:");
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletPressure]));
y += lineHeight;
//Pen position and pressure.
drawCircle(pkt.x, pkt.y, pkt.z, pkt.p);
} }
void drawCircle(float x, float y, float z, float p) { void drawCircle(float x, float y, float z, float p) {
@ -156,8 +124,8 @@ protected:
beginPath(); beginPath();
strokeColor(1.f, 1.f, 1.f, 0.5f); strokeColor(1.f, 1.f, 1.f, 0.5f);
moveTo(x , y - z * circleRadius); moveTo(x, y - z * circleRadius);
lineTo(x , y + z * circleRadius); lineTo(x, y + z * circleRadius);
stroke(); stroke();
closePath(); closePath();
@ -192,7 +160,6 @@ protected:
private: private:
// Parameters // Parameters
float fParameters[kParameterCount];
double fSampleRate; double fSampleRate;
// UI stuff // UI stuff
@ -202,61 +169,9 @@ private:
// Tablet context handler // Tablet context handler
Tablet tab; 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. Set our UI class as non-copyable and add a leak detector just in case.

View File

@ -1,104 +1,81 @@
#include <string> #ifdef YAW_USE_WINTAB
#include <Windows.h> #include "tablet.h"
#include "MSGPACK.H"
#include "wintab.h"
#define PACKETDATA (PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE) #define PACKETDATA (PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE)
#define PACKETMODE PK_BUTTONS //#define PACKETMODE
#include "pktdef.h" #include "pktdef.h"
#include "wtutil.h" #include "wtutil.h"
class Tablet { Tablet::Tablet(uintptr_t handle)
public: {
HWND hwnd = reinterpret_cast<HWND>(handle);
if (!hwnd) { return; }
Tablet(HWND hwnd) { if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) {
if (!hwnd) { return; } errormsg = "Wintab not installed.";
return;
if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) {
return;
}
NewContext(hwnd);
} }
~Tablet() { NewContext(hwnd);
if (hctx) { gpWTClose(hctx); } }
UnloadWintab();
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() { //Store newest packet in pkt, flush older packets.
//Serial number of newest packet. PACKET pkt;
UINT oldest, newest; bool newData = gpWTPacket(hctx, newest, &pkt);
//This function returns false when it fails if (!newData) return false;
//which may happen with a full or empty queue. packet.x = static_cast<float>(pkt.pkX) / ext.x;
if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) { packet.y = static_cast<float>(pkt.pkY) / ext.y;
//Queue may be full, flush it all just in case. packet.z = static_cast<float>(pkt.pkZ) / ext.z;
gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr); packet.p = static_cast<float>(pkt.pkNormalPressure) / ext.p;
return false; packet.buttons = pkt.pkButtons;
} return true;
}
//Store newest packet in pkt, flush older packets. void Tablet::NewContext(HWND hwnd) {
return gpWTPacket(hctx, newest, &pkt); if (hctx) { gpWTClose(hctx); }
} LOGCONTEXT ctx = {};
bool wintabAvailable = false;
PACKET pkt = { 0 };
UINT maxPressure = 1;
float extX;
float extY;
float extZ;
float extP;
private:
HCTX hctx = NULL;
UINT wDevice = 0;
AXIS TabletX = { 0 }; AXIS TabletX = { 0 };
AXIS TabletY = { 0 }; AXIS TabletY = { 0 };
AXIS TabletZ = { 0 }; AXIS TabletZ = { 0 };
AXIS TabletPressure = { 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) { //Tablet extents.
if (hctx) { gpWTClose(hctx); } gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX);
gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx); gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);
ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);
ctx.lcPktData = PACKETDATA; gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure);
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);
ctx.lcInOrgX = TabletX.axMin; ext.x = static_cast<float>(TabletX.axMax);
ctx.lcInExtX = TabletX.axMax; ext.y = static_cast<float>(TabletY.axMax);
ctx.lcOutOrgX = TabletX.axMin; ext.z = static_cast<float>(TabletZ.axMax);
ctx.lcOutExtX = TabletX.axMax; ext.p = static_cast<float>(TabletPressure.axMax);
extX = static_cast<float>(TabletX.axMax);
ctx.lcInOrgY = TabletY.axMin; hctx = gpWTOpenA(hwnd, &ctx, TRUE);
ctx.lcInExtY = TabletY.axMax;
ctx.lcOutOrgY = TabletY.axMin;
ctx.lcOutExtY = TabletY.axMax;
extY = static_cast<float>(TabletY.axMax);
ctx.lcInOrgZ = TabletZ.axMin; if (!hctx)
ctx.lcInExtZ = TabletZ.axMax; {
ctx.lcOutOrgZ = TabletZ.axMin; errormsg = "Could not open Wintab context.";
ctx.lcOutExtZ = TabletZ.axMax; return;
extZ = static_cast<float>(TabletZ.axMax);
extP = static_cast<float>(TabletPressure.axMax);
hctx = gpWTOpenA(hwnd, &ctx, FALSE);
if (!hctx) { return; }
gpWTEnable(hctx, TRUE);
wintabAvailable = true;
} }
initialized = true;
};
}; #endif