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)
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")

View File

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

View File

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

View File

@ -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<float>(sampleRate);
break;
case kParameterTabletY:
case ktpay:
break;
case kParameterTabletZ:
case ktpaz:
break;
case kParameterTabletPressure:
case ktpap:
volume = val;
break;
case kParameterTabletButtons:
case ktpab:
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"
#ifdef YAW_USE_WINTAB
#include "wintab.cpp"
#endif
#ifdef YAW_USE_RTSTYLUS
#include "rtstylus.cpp"
#endif
#include "tablet.h"
#include <format>
START_NAMESPACE_DISTRHO
@ -18,12 +14,8 @@ public:
: UI(kInitialWidth, kInitialHeight),
fSampleRate(getSampleRate()),
fResizable(isResizable()),
fScale(1.0f),
fScaleFactor(getScaleFactor()),
tab(reinterpret_cast<HWND>(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<float>(tab.pkt.pkX) / tab.extX;
float y = static_cast<float>(tab.pkt.pkY) / tab.extY;
float z = static_cast<float>(tab.pkt.pkZ) / tab.extZ;
float p = static_cast<float>(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<unsigned long>(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.

View File

@ -1,104 +1,81 @@
#include <string>
#include <Windows.h>
#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<HWND>(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<float>(pkt.pkX) / ext.x;
packet.y = static_cast<float>(pkt.pkY) / ext.y;
packet.z = static_cast<float>(pkt.pkZ) / ext.z;
packet.p = static_cast<float>(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<float>(TabletX.axMax);
ext.x = static_cast<float>(TabletX.axMax);
ext.y = static_cast<float>(TabletY.axMax);
ext.z = static_cast<float>(TabletZ.axMax);
ext.p = static_cast<float>(TabletPressure.axMax);
ctx.lcInOrgY = TabletY.axMin;
ctx.lcInExtY = TabletY.axMax;
ctx.lcOutOrgY = TabletY.axMin;
ctx.lcOutExtY = TabletY.axMax;
extY = static_cast<float>(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<float>(TabletZ.axMax);
extP = static_cast<float>(TabletPressure.axMax);
hctx = gpWTOpenA(hwnd, &ctx, FALSE);
if (!hctx) { return; }
gpWTEnable(hctx, TRUE);
wintabAvailable = true;
if (!hctx)
{
errormsg = "Could not open Wintab context.";
return;
}
};
initialized = true;
};
#endif