From 9d3da08d488e2bf2d4bb24f0e65e17f70155da2c Mon Sep 17 00:00:00 2001 From: Christoph Wagner Date: Mon, 9 Feb 2026 13:35:55 +0100 Subject: [PATCH 1/2] extended API with missing svg to str functionality --- include/VocalTractLabApi/VocalTractLabApi.h | 18 ++++++ include/VocalTractLabBackend/VocalTract.h | 6 +- src/VocalTractLabApi/VocalTractLabApi.cpp | 67 +++++++++++++++++++++ src/VocalTractLabApi/VocalTractLabApi.def | 1 + src/VocalTractLabBackend/VocalTract.cpp | 40 ++++++++---- 5 files changed, 119 insertions(+), 13 deletions(-) diff --git a/include/VocalTractLabApi/VocalTractLabApi.h b/include/VocalTractLabApi/VocalTractLabApi.h index 0dd2e92..f1ac923 100644 --- a/include/VocalTractLabApi/VocalTractLabApi.h +++ b/include/VocalTractLabApi/VocalTractLabApi.h @@ -44,6 +44,7 @@ extern "C"{ /* start extern "C" */ #endif // WIN32 #include +#include // **************************************************************************** // The exported C-compatible functions. @@ -202,6 +203,23 @@ C_EXPORT int vtlGetTractParams(const char *shapeName, double *tractParams); C_EXPORT int vtlExportTractSvg(double *tractParams, const char *fileName); +// **************************************************************************** +// Exports the vocal tract contours for the given vector of vocal tract +// parameters as a string. +// +// Function return value: +// 0: success. +// 1: The API has not been initialized. +// 2: Writing the SVG file failed. +// **************************************************************************** + +C_EXPORT int vtlExportTractSvgToStr(double *tractParams, char **svgStr, size_t *svgStrSize); + +// **************************************************************************** +// Provide a custom free function to free the memory allocated for the SVG string. +// **************************************************************************** + +C_EXPORT void vtlFree(void* p); // **************************************************************************** // Provides the tube data (especially the area function) for the given vector diff --git a/include/VocalTractLabBackend/VocalTract.h b/include/VocalTractLabBackend/VocalTract.h index 5120caf..39dd31e 100644 --- a/include/VocalTractLabBackend/VocalTract.h +++ b/include/VocalTractLabBackend/VocalTract.h @@ -450,9 +450,11 @@ class VocalTract void getCrossSection(double *upperProfile, double *lowerProfile, CrossSection *section); bool exportCrossSections(const string &fileName); + bool exportTractContourSvg(std::ostream& os, bool addCenterLine, bool addCutVectors); bool exportTractContourSvg(const string &fileName, bool addCenterLine, bool addCutVectors); - void addRibPointsSvg(ostream &os, Surface *s, int rib, int firstRibPoint, int lastRibPoint); - void addRibsSvg(ostream &os, Surface *s, int firstRib, int lastRib, int ribPoint); + std::string exportTractContourSvgToStr(bool addCenterLine, bool addCutVectors); + void addRibPointsSvg(std::ostream &os, Surface *s, int rib, int firstRibPoint, int lastRibPoint); + void addRibsSvg(std::ostream &os, Surface *s, int firstRib, int lastRib, int ribPoint); // **************************************************************** // Calculate the piecewise constant area function. diff --git a/src/VocalTractLabApi/VocalTractLabApi.cpp b/src/VocalTractLabApi/VocalTractLabApi.cpp index 70b907b..b89efc8 100644 --- a/src/VocalTractLabApi/VocalTractLabApi.cpp +++ b/src/VocalTractLabApi/VocalTractLabApi.cpp @@ -541,6 +541,73 @@ int vtlExportTractSvg(double *tractParams, const char *fileName) } } +// **************************************************************************** +// Exports the vocal tract contours for the given vector of vocal tract +// parameters as a string. +// +// Function return value: +// 0: success. +// 1: The API has not been initialized. +// 2: Writing the SVG file failed. +// **************************************************************************** + +int vtlExportTractSvgToStr(double *tractParams, char **svgStr, size_t *svgStrSize) +{ + if (!vtlApiInitialized) + { + printf("Error: The API has not been initialized.\n"); + return 1; + } + + *svgStr = NULL; + *svgStrSize = 0; + + // Store the current control parameter values. + vocalTract->storeControlParams(); + + // Set the given vocal tract parameters. + int i; + for (i = 0; i < VocalTract::NUM_PARAMS; i++) + { + vocalTract->param[i].x = tractParams[i]; + } + vocalTract->calculateAll(); + + // Save the contour as SVG file. + std::string s = vocalTract->exportTractContourSvgToStr(false, false); + bool ok = !s.empty(); + + // Restore the previous control parameter values and + // recalculate the vocal tract shape. + + vocalTract->restoreControlParams(); + vocalTract->calculateAll(); + + if (ok) + { + size_t n = s.size(); + *svgStr = (char*)std::malloc(n+1); + if(!*svgStr) + { + printf("Error: Memory allocation failed in vtlExportTractSvgToStr().\n"); + return 2; + } + + memcpy(*svgStr, s.c_str(), n); + (*svgStr)[n] = '\0'; // keep svgStr as a valid C string (null-terminated) if maybe required later + *svgStrSize = n; // return the size of the string (without the terminating null character) + return 0; + } + else + { + return 2; + } +} + +void vtlFree(void* p) +{ + std::free(p); +} // **************************************************************************** // Provides the tube data (especially the area function) for the given vector diff --git a/src/VocalTractLabApi/VocalTractLabApi.def b/src/VocalTractLabApi/VocalTractLabApi.def index 8d4f124..1a0bbfa 100644 --- a/src/VocalTractLabApi/VocalTractLabApi.def +++ b/src/VocalTractLabApi/VocalTractLabApi.def @@ -10,6 +10,7 @@ vtlGetGlottisParamInfo vtlGetGlottisParams vtlGetTractParams vtlExportTractSvg +vtlExportTractSvgToStr vtlTractToTube vtlFastTractToTube vtlGetDefaultTransferFunctionOptions diff --git a/src/VocalTractLabBackend/VocalTract.cpp b/src/VocalTractLabBackend/VocalTract.cpp index c1e3e61..ff6c546 100644 --- a/src/VocalTractLabBackend/VocalTract.cpp +++ b/src/VocalTractLabBackend/VocalTract.cpp @@ -6813,10 +6813,10 @@ bool VocalTract::exportCrossSections(const string &fileName) // **************************************************************************** -// Save the vocal tract contour lines as SVG file. +// Write the vocal tract contour lines to a stream // **************************************************************************** -bool VocalTract::exportTractContourSvg(const string &fileName, bool addCenterLine, bool addCutVectors) +bool VocalTract::exportTractContourSvg(std::ostream& os, bool addCenterLine, bool addCutVectors) { const double SCALE = 37.8; // 1 cm in Corel Draw are 37.8 "default units" (pixels?) int indent = 0; @@ -6829,14 +6829,6 @@ bool VocalTract::exportTractContourSvg(const string &fileName, bool addCenterLin bool includeTeeth = true; bool includeRibs = false; - ofstream os(fileName); - - if (!os) - { - printf("Error: Could not open the SVG file\n"); - return false; - } - // Write the "header and open the svg- and the group element. os << "" << endl; @@ -7071,12 +7063,38 @@ bool VocalTract::exportTractContourSvg(const string &fileName, bool addCenterLin indent -= 2; os << "" << endl; - // Close the file ************************************************* + return true; +} + +// **************************************************************************** +// Save the vocal tract contour lines as SVG file. +// **************************************************************************** +bool VocalTract::exportTractContourSvg(const string &fileName, bool addCenterLine, bool addCutVectors) +{ + ofstream os(fileName); + if (!os) + { + printf("Error: Could not open file '%s' for writing.\n", fileName.c_str()); + return false; + } + + exportTractContourSvg(os, addCenterLine, addCutVectors); + os.close(); return true; } +// **************************************************************************** +// Save the vocal tract contour lines to a string. +// **************************************************************************** +std::string VocalTract::exportTractContourSvgToStr(bool addCenterLine, bool addCutVectors) +{ + std::ostringstream oss; + exportTractContourSvg(oss, addCenterLine, addCutVectors); + return oss.str(); +} + // **************************************************************************** // Adds the point coordinates of some rib points to an output stream. From db8d2f1e2b7004b5fda0658ecaa3ffe23f46277a Mon Sep 17 00:00:00 2001 From: Christoph Wagner Date: Mon, 9 Feb 2026 21:07:22 +0100 Subject: [PATCH 2/2] Sped up vtl shape computation --- include/VocalTractLabBackend/VocalTract.h | 3 ++- src/VocalTractLabApi/VocalTractLabApi.cpp | 7 +++--- src/VocalTractLabBackend/VocalTract.cpp | 28 +++++++++++++++++++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/include/VocalTractLabBackend/VocalTract.h b/include/VocalTractLabBackend/VocalTract.h index 39dd31e..3055578 100644 --- a/include/VocalTractLabBackend/VocalTract.h +++ b/include/VocalTractLabBackend/VocalTract.h @@ -415,6 +415,7 @@ class VocalTract // **************************************************************** void calcSurfaces(); + void calcLimitedSurfaces(); void calcLips(); void getImportantLipPoints(Point3D &onset, Point3D &corner, Point3D &F0, Point3D &F1, double &yClose); void calcRadiation(Point3D lipCorner); @@ -477,7 +478,7 @@ class VocalTract void clearUnsavedChanges(); void storeControlParams(); - void restoreControlParams(); + void restoreControlParams(bool recalculate = true); // ************************************************************************** /// Private data. diff --git a/src/VocalTractLabApi/VocalTractLabApi.cpp b/src/VocalTractLabApi/VocalTractLabApi.cpp index b89efc8..22cb9a6 100644 --- a/src/VocalTractLabApi/VocalTractLabApi.cpp +++ b/src/VocalTractLabApi/VocalTractLabApi.cpp @@ -571,7 +571,8 @@ int vtlExportTractSvgToStr(double *tractParams, char **svgStr, size_t *svgStrSiz { vocalTract->param[i].x = tractParams[i]; } - vocalTract->calculateAll(); + + vocalTract->calcLimitedSurfaces(); // Save the contour as SVG file. std::string s = vocalTract->exportTractContourSvgToStr(false, false); @@ -580,8 +581,8 @@ int vtlExportTractSvgToStr(double *tractParams, char **svgStr, size_t *svgStrSiz // Restore the previous control parameter values and // recalculate the vocal tract shape. - vocalTract->restoreControlParams(); - vocalTract->calculateAll(); + vocalTract->restoreControlParams(false); + vocalTract->calcLimitedSurfaces(); if (ok) { diff --git a/src/VocalTractLabBackend/VocalTract.cpp b/src/VocalTractLabBackend/VocalTract.cpp index ff6c546..e2b8751 100644 --- a/src/VocalTractLabBackend/VocalTract.cpp +++ b/src/VocalTractLabBackend/VocalTract.cpp @@ -2390,6 +2390,27 @@ void VocalTract::calculateAll() } +void VocalTract::calcLimitedSurfaces() +{ + // **************************************************************** + // Set the limited parameter values equal to the set values. + // **************************************************************** + + int i; + for (i=0; i < NUM_PARAMS; i++) + { + restrictParam(i); + param[i].limitedX = param[i].x; + } + + // **************************************************************** + // Do the calculations. + // **************************************************************** + + calcSurfaces(); +} + + // **************************************************************************** /// Calculate all surfaces of the model. // **************************************************************************** @@ -7657,7 +7678,7 @@ void VocalTract::storeControlParams() /// Restore the temporarily stored (cached) control parameter values. // **************************************************************************** -void VocalTract::restoreControlParams() +void VocalTract::restoreControlParams(bool recalculate) { if (hasStoredControlParams == false) { @@ -7671,7 +7692,10 @@ void VocalTract::restoreControlParams() } hasStoredControlParams = false; - calculateAll(); + if (recalculate) + { + calculateAll(); + } }