From 4cd2afcab981fd9cf240a9cbb9a9781c0dc060b4 Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 13 Jul 2017 10:04:40 +0200 Subject: [PATCH 1/5] Features extension --- dwtools/Strings_extensions.cpp | 4 + fon/Feature.cpp | 458 +++++++++++++++++++++++++++++++++ fon/Feature.h | 83 ++++++ fon/TextGrid.cpp | 35 +++ fon/TextGrid.h | 58 ++--- fon/TextGridEditor.cpp | 276 +++++++++++++++++++- fon/TextGridEditor.h | 3 +- fon/praat_TextGrid_init.cpp | 383 +++++++++++++++++++++++++++ 8 files changed, 1261 insertions(+), 39 deletions(-) create mode 100644 fon/Feature.cpp create mode 100644 fon/Feature.h diff --git a/dwtools/Strings_extensions.cpp b/dwtools/Strings_extensions.cpp index 9e77a990c..3e2dea727 100644 --- a/dwtools/Strings_extensions.cpp +++ b/dwtools/Strings_extensions.cpp @@ -274,4 +274,8 @@ autoStringsIndex Table_to_StringsIndex_column (Table me, long column) { } } +bool string_isEmpty (const char32 *string) { + +} + /* End of file Strings_extensions.cpp */ diff --git a/fon/Feature.cpp b/fon/Feature.cpp new file mode 100644 index 000000000..5ab4d432b --- /dev/null +++ b/fon/Feature.cpp @@ -0,0 +1,458 @@ +/* + * Feature.cpp + * + * Copyright (C) 1992-2012,2013,2014,2015 Paul Boersma + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Created on: Feb 4, 2016 + * Author: ivan + */ + +#include "Feature.h" + +/********** char32 UTILITIES **********/ + +/** + * Allocates memory for a char32_t string of length "size", and initializes all its positions to '\0'. + * It returns a pointer to its first position. + */ +inline static char32* allocChar32(int size){ + char32* string = (char32*) malloc ((size_t) size * sizeof (char32)); + char32* currentPos = string; + for(int i=0;i 0;p++, pos--); + while (* source != U'\0') * p ++ = * source ++; + *p = U'\0'; + return target; +} + +/** + * Concatenates the contents of both source strings in a new one. + * It returns a pointer to the first position of the new string. + */ +char32* str32cat(char32 *source1, const char32 *source2){ + if(source1 == nullptr || source2 == nullptr) return nullptr; + char32 * result = allocChar32(str32len(source1) + str32len(source2) + 1); + str32cpy(result, source1); + str32append(result, source2, str32len(result)); + return result; +} + +/** + * Returns a new string with the trimmed version of the source text + */ +char32* trim(const char32 *text) { + if(str32len(text) == 0) return nullptr; + const char32 * forwardPtr = text; + int initialBlanks = 0; + while(*forwardPtr != U'\0' && *forwardPtr == U' '){ + initialBlanks++; + forwardPtr++; + } + + char32 * result = allocChar32(str32len(text) - initialBlanks + 1); + str32cpy(result, forwardPtr); + + char32 * backwardPtr = result + str32len(result)-1; + while(backwardPtr+1 != result && *backwardPtr == U' '){ + *backwardPtr-- = U'\0'; + } + + return result; +} + +/** + * Returns whether or not the string is empty or null. + */ +bool str32IsEmpty(const char32 *text){ + if(text == nullptr) return true; + bool result = false; + char32* trimmed = trim(text); + if(trimmed == nullptr || str32len(trimmed) == 0) + result = true; + delete trimmed; + return result; +} + +/*---------------------------------------------------*/ + +/** + * Given a tierFeatures it returns a pointer to the current feature. + * If there is no feature created then it creates the first and returns it. + */ +feature* getCurrentFeature(tierFeatures* data){ + if(data->currentFeature == nullptr){ + data->firstFeature = new feature(); + data->currentFeature = data->firstFeature; + } + return data->currentFeature; +} + +/** + * Given a tierFeatures it returns a pointer to the next feature after the current. + * If there is no feature after the current one, then it creates and returns it. + */ +feature* getNextFeature(tierFeatures* data){ + if(data->currentFeature == nullptr){ + data->firstFeature = new feature(); + data->currentFeature = data->firstFeature; + }else{ + if(data->currentFeature->nxtPtr == nullptr){ + data->currentFeature->nxtPtr = new feature(); + data->currentFeature = data->currentFeature->nxtPtr; + } + } + return data->currentFeature; +} + + +/** + * A states machine that reads the text and extracts its features data creating and saving it into a tierFeatures type structure. + * Structure as follows: + * State 0: Accepts any char until "@{@". Everything from the beginning is the interval or point text. + * State 1: Accepts blank spaces until "\"". + * State 2: Accepts any char until "\"". Everything from state 1 is a feature label. + * State 3: Accepts blank spaces until "=". + * State 4: Accepts blank spaces until "\"". + * State 5: Accepts any char until "\"". Everything from state 4 is a feature value. + * State 6: Accepts blank spaces until "," in which case it returns to state 2 and expects a new feature or "@}@" in which case it finishes. + * State 7: Ended correctly + * State 8: Error the whole string will be considered interval or point text. + */ +tierFeatures* extractTierFeatures(const char32* text){ + if(text == nullptr) return new tierFeatures(); + int state = 0; + int64 pos = 0; + const char32* currentPos = text; + const char32* lastCheckPoint = text; + tierFeatures* data = new tierFeatures(); + const char32* temp; + do{ + char32 currentChar = *currentPos++; + pos++; + + switch(state){ + case 0: + if(currentChar != U'@') break; + if(str32len(currentPos) < 2) break; + temp = currentPos; + if(*temp++ == U'{' && *temp++ == U'@'){ + currentPos = temp; + data->text = allocChar32(pos); + str32ncpy(data->text, lastCheckPoint, pos-1); + lastCheckPoint = currentPos; + pos = 0; + state = 1; + } + break; + case 1: + if(currentChar == U'@'){ + if(str32len(currentPos) < 2){ state = 8; break;} + temp = currentPos; + if(*temp++ == U'}' && *temp++ == U'@'){ + currentPos = temp; + pos+=2; + lastCheckPoint = currentPos; + pos = 0; + state = 7; + break; + }else{ + state = 8; + break; + } + } + if(currentChar != U'"' && currentChar != U' '){ state = 8; break;} + if(currentChar != U'"') break; + lastCheckPoint = currentPos; + pos = 0; + state = 2; + break; + case 2: + if(currentChar == U'\\'){ + if(str32len(currentPos) < 1) break; + currentPos++; + pos++; + break; + } + if(currentChar != U'"') break; + getNextFeature(data)->label = allocChar32(pos); + str32ncpy(getCurrentFeature(data)->label, lastCheckPoint, pos-1); + lastCheckPoint = currentPos; + pos = 0; + state = 3; + break; + case 3: + if(currentChar != U'=' && currentChar != U' '){ state = 8; break;} + if(currentChar != U'=') break; + lastCheckPoint = currentPos; + pos = 0; + state = 4; + break; + case 4: + if(currentChar != U'"' && currentChar != U' '){ state = 8; break;} + if(currentChar != U'"') break; + lastCheckPoint = currentPos; + pos = 0; + state = 5; + break; + case 5: + if(currentChar == U'\\'){ + if(str32len(currentPos) < 1) break; + currentPos++; + pos++; + break; + } + if(currentChar != U'"') break; + getCurrentFeature(data)->value = allocChar32(pos); + str32ncpy(getCurrentFeature(data)->value, lastCheckPoint, pos-1); + lastCheckPoint = currentPos; + pos = 0; + state = 6; + break; + case 6: + if(currentChar == U'@'){ + if(str32len(currentPos) < 2){ state = 8; break;} + temp = currentPos; + if(*temp++ == U'}' && *temp++ == U'@'){ + currentPos = temp; + pos+=2; + lastCheckPoint = currentPos; + pos = 0; + state = 7; + break; + }else{ + state = 8; + break; + } + } + if(currentChar != U',' && currentChar != U' '){ state = 8; break;} + if(currentChar != U',') break; + lastCheckPoint = currentPos; + pos = 0; + state = 1; + break; + } + }while(state != 8 && state != 7 && *currentPos != U'\0'); + + if(state != 7){ + delete data; + data = new tierFeatures(); + data->text = allocChar32(str32len(text)+1); + str32ncpy(data->text, text, str32len(text)); + } + + return data; +} + +/** + * It returns a new char32_t string with the content of text but with backslashes before \ and " + */ +char32* addBackslashes(const char32* text){ + int neededSpace = 0; + const char32* tmp = text; + for(;*tmp != U'\0';tmp++){ + neededSpace++; + if(*tmp == U'"' || *tmp == U'\\') + neededSpace++; + } + + char32* result = allocChar32(neededSpace+1); + tmp = text; + char32* aux = result; + for(;*tmp != U'\0';){ + if(*tmp == U'"' || *tmp == U'\\') + *aux++ = U'\\'; + *aux++ = *tmp++; + } + return result; +} + +/** + * It returns a new char32_t string with the content of text but without initial backslashes of special characters + */ +char32* removeBackslashes(const char32* text){ + char32* result = allocChar32(str32len(text)+1); + const char32* tmp = text; + char32* aux = result; + for(;*tmp != U'\0';){ + if(*tmp == U'\\' && str32len(tmp) > 1) + tmp++; + *aux++ = *tmp++; + } + return result; +} + +/** + * Given a tierFeatures and a label, returns the feature (feature) with the same label. Null if the feature does not exist. + */ +feature* getExistentFeature(const tierFeatures* data, const char32* label){ + if(data == nullptr) return nullptr; + + feature* current = data->firstFeature; + while(current != nullptr){ + if(str32equ(current->label, label)) + return current; + current = current->nxtPtr; + } + return nullptr; +} + +/** + * Adds a new feature with label and value to the given tierFeatures. + * If the feature already exists overwrites its value. + */ +void addFeatureToTierFeatures(tierFeatures* data, const char32* label, const char32* value){ + if(data == nullptr) return; + char32* fLabel = addBackslashes(label); + char32* fValue = addBackslashes(value); + + feature* ftr = getExistentFeature(data, fLabel); + if(ftr != nullptr){ + delete ftr->value; + ftr->value = allocChar32(str32len(fValue)+1); + str32ncpy(ftr->value, fValue, str32len(fValue)); + }else{ + getNextFeature(data)->label = allocChar32(str32len(fLabel)+1); + str32ncpy(getCurrentFeature(data)->label, fLabel, str32len(fLabel)); + getCurrentFeature(data)->value = allocChar32(str32len(fValue)+1); + str32ncpy(getCurrentFeature(data)->value, fValue, str32len(fValue)); + } + + delete fLabel; + delete fValue; +} + +/** + * Deletes the given feature from the tierFeatures. + */ +void deleteFeatureFromTierFeatures(tierFeatures* data, const char32* label){ + if(data == nullptr) return; + char32* fLabel = addBackslashes(label); + feature* ftr = getExistentFeature(data, fLabel); + delete fLabel; + if(ftr == nullptr){ + return; + } + feature* tmp = data->firstFeature; + if(tmp->nxtPtr == nullptr){ + data->firstFeature = nullptr; + data->currentFeature = nullptr; + delete ftr; + return; + }else if(tmp == ftr){ + data->firstFeature = tmp->nxtPtr; + delete ftr; + return; + }else{ + while(tmp->nxtPtr != ftr){ + tmp = tmp->nxtPtr; + } + if(data->currentFeature == ftr) data->currentFeature = tmp; + if(tmp->nxtPtr->nxtPtr != nullptr) tmp->nxtPtr = tmp->nxtPtr->nxtPtr; + else tmp->nxtPtr = nullptr; + delete ftr; + } +} + +/** + * Returns an integer representing the total length of the string representation of the whole tierFeatures. + */ +int countTierFeaturesLength(tierFeatures* data){ + if(data == nullptr) return 0; + int totalLenght = 0; + if(data->text != nullptr) + totalLenght += str32len(data->text); + totalLenght += 4; + feature* tempPtr = data->firstFeature; + while(tempPtr != nullptr){ + totalLenght += 1; + if(tempPtr->label != nullptr) + totalLenght += str32len(tempPtr->label); + totalLenght += 5; + if(tempPtr->value != nullptr) + totalLenght += str32len(tempPtr->value); + totalLenght += 1; + tempPtr = tempPtr->nxtPtr; + if(tempPtr != nullptr) + totalLenght += 2; + } + totalLenght += 5; + return totalLenght; +} + +/** + * Return a new char32_t string representing the data held in the given tierFeatures. + */ +char32* generateTextFromTierFeatures(tierFeatures* data){ + if(data == nullptr) return nullptr; + int totalLenght = countTierFeaturesLength(data); + if(totalLenght <= 0) return nullptr; + + char32* result = allocChar32(totalLenght); + if(data->text != nullptr) + str32append(result, data->text, str32len(result)); + if(data->firstFeature != nullptr){ + str32append(result, U"@{@ ", str32len(result)); + feature* tempPtr = data->firstFeature; + while(tempPtr != nullptr){ + str32append(result, U"\"", str32len(result)); + if(tempPtr->label != nullptr) + str32append(result, tempPtr->label, str32len(result)); + str32append(result, U"\" = \"", str32len(result)); + if(tempPtr->value != nullptr) + str32append(result, tempPtr->value, str32len(result)); + str32append(result, U"\"", str32len(result)); + tempPtr = tempPtr->nxtPtr; + if(tempPtr != nullptr) + str32append(result, U", ", str32len(result)); + } + str32append(result, U" @}@", str32len(result)); + } + str32append(result, U"\0", str32len(result)); + return result; +} + +/** + * Returns a new char32_t string consisting of the content within given text plus a new feature with the given label and value. + * If feature already exists it is overwritten with given value. + */ +char32* addFeatureToText(const char32* text, const char32* label, const char32* value){ + tierFeatures* res = extractTierFeatures(text); + addFeatureToTierFeatures(res, label, value); + return generateTextFromTierFeatures(res); +} + +/** + * Changes the content in the text of TierFeatures for a copy of the given one. + */ +void replaceTierFeaturesText(tierFeatures* data, const char32* text){ + if(data == nullptr) return; + delete data->text; + data->text = allocChar32(str32len(text)+1); + str32ncpy(data->text, text, str32len(text)); +} diff --git a/fon/Feature.h b/fon/Feature.h new file mode 100644 index 000000000..76bce1730 --- /dev/null +++ b/fon/Feature.h @@ -0,0 +1,83 @@ +#ifndef _Feature_h_ +#define _Feature_h_ +/* + * Feature.h + * + * Copyright (C) 1992-2012,2013,2014,2015 Paul Boersma + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Created on: Feb 4, 2016 + * Author: Ivan Latorre + */ + +#include "Preferences.h" + +struct feature{ + char32* label; + char32* value; + feature* nxtPtr; + feature() + { + label=nullptr; + value=nullptr; + nxtPtr=nullptr; + } + ~feature(){ + delete label; + delete value; + } +}; + +struct tierFeatures{ + char32* text; + feature* firstFeature; + feature* currentFeature; + tierFeatures() + { + text=nullptr; + firstFeature=nullptr; + currentFeature=nullptr; + } + ~tierFeatures(){ + delete text; + feature* tmp = firstFeature; + while(tmp != nullptr){ + feature* toDelete = tmp; + tmp = tmp->nxtPtr; + delete toDelete; + } + } +}; + +/*---char32 UTILITIES---*/ +char32* trim(const char32 *text); +bool str32IsEmpty(const char32 *text); +char32* str32cat(char32 *source1, const char32 *source2); + +/*---Features treatment---*/ +char32* addBackslashes(const char32* text); +char32* removeBackslashes(const char32* text); +tierFeatures* extractTierFeatures(const char32* text); +char32* addFeatureToText(const char32* text, const char32* label, const char32* value); +feature* getCurrentFeature(tierFeatures* data); +feature* getNextFeature(tierFeatures* data); +feature* getExistentFeature(const tierFeatures* data, const char32* label); +void deleteFeatureFromTierFeatures(tierFeatures* data, const char32* label); +char32* generateTextFromTierFeatures(tierFeatures* data); +void replaceTierFeaturesText(tierFeatures* data, const char32* text); + +/* End of file Feature.h */ +#endif diff --git a/fon/TextGrid.cpp b/fon/TextGrid.cpp index a5878986e..df89fb05c 100644 --- a/fon/TextGrid.cpp +++ b/fon/TextGrid.cpp @@ -19,6 +19,7 @@ #include "TextGrid.h" #include "longchar.h" +#include "Feature.h" #include "oo_DESTROY.h" #include "TextGrid_def.h" @@ -1217,6 +1218,23 @@ void TextGrid_setIntervalText (TextGrid me, int tierNumber, long intervalNumber, } } +void TextGrid_setIntervalHeadText (TextGrid me, int tierNumber, long intervalNumber, const char32 *text) { + try { + IntervalTier intervalTier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber); + if (intervalNumber < 1 || intervalNumber > intervalTier -> intervals.size) + Melder_throw (U"Interval ", intervalNumber, U" does not exist on tier ", tierNumber, U"."); + TextInterval interval = intervalTier -> intervals.at [intervalNumber]; + tierFeatures* result = extractTierFeatures(interval->text); + replaceTierFeaturesText(result, text); + char32* finalText = generateTextFromTierFeatures(result); + TextInterval_setText (interval, finalText); + delete result; + delete finalText; + } catch (MelderError) { + Melder_throw (me, U": interval head text not set."); + } +} + void TextGrid_insertPoint (TextGrid me, int tierNumber, double t, const char32 *mark) { try { TextTier textTier = TextGrid_checkSpecifiedTierIsPointTier (me, tierNumber); @@ -1261,6 +1279,23 @@ void TextGrid_setPointText (TextGrid me, int tierNumber, long pointNumber, const } } +void TextGrid_setPointHeadText (TextGrid me, int tierNumber, long pointNumber, const char32 *text) { + try { + TextTier textTier = TextGrid_checkSpecifiedTierIsPointTier (me, tierNumber); + if (pointNumber < 1 || pointNumber > textTier -> points.size) + Melder_throw (U"Point ", pointNumber, U" does not exist on tier ", tierNumber, U"."); + TextPoint point = textTier -> points.at [pointNumber]; + tierFeatures* result = extractTierFeatures(point->mark); + replaceTierFeaturesText(result, text); + char32* finalText = generateTextFromTierFeatures(result); + TextPoint_setText (point, finalText); + delete result; + delete finalText; + } catch (MelderError) { + Melder_throw (me, U": point head text not set."); + } +} + static void sgmlToPraat (char *text) { char *sgml = text, *praat = text; for (;;) { diff --git a/fon/TextGrid.h b/fon/TextGrid.h index 0bc251d5d..254bed336 100644 --- a/fon/TextGrid.h +++ b/fon/TextGrid.h @@ -31,23 +31,29 @@ Collection_define (FunctionList, OrderedOf, Function) { #include "TextGrid_def.h" autoTextPoint TextPoint_create (double time, const char32 *mark); - void TextPoint_setText (TextPoint me, const char32 *text); +long TextPoint_labelLength (TextPoint me); +void TextPoint_removeText (TextPoint me); autoTextInterval TextInterval_create (double tmin, double tmax, const char32 *text); - void TextInterval_setText (TextInterval me, const char32 *text); +long TextInterval_labelLength (TextInterval me); +void TextInterval_removeText (TextInterval me); autoTextTier TextTier_create (double tmin, double tmax); - void TextTier_addPoint (TextTier me, double time, const char32 *mark); autoTextTier TextTier_readFromXwaves (MelderFile file); autoPointProcess TextTier_getPoints (TextTier me, const char32 *text); +void TextTier_removePoint (TextTier me, long ipoint); +long TextTier_maximumLabelLength (TextTier me); +void TextTier_removeText (TextTier me); +void TextTier_removePoints (TextTier me, int which_Melder_STRING, const char32 *criterion); +autoTableOfReal TextTier_downto_TableOfReal (TextTier me, const char32 *label); +autoTableOfReal TextTier_downto_TableOfReal_any (TextTier me); autoIntervalTier IntervalTier_create (double tmin, double tmax); autoIntervalTier IntervalTier_readFromXwaves (MelderFile file); void IntervalTier_writeToXwaves (IntervalTier me, MelderFile file); - long IntervalTier_timeToLowIndex (IntervalTier me, double t); long IntervalTier_timeToIndex (IntervalTier me, double t); // obsolete long IntervalTier_timeToHighIndex (IntervalTier me, double t); @@ -59,12 +65,13 @@ autoPointProcess IntervalTier_getCentrePoints (IntervalTier me, const char32 *te autoPointProcess IntervalTier_PointProcess_startToCentre (IntervalTier tier, PointProcess point, double phase); autoPointProcess IntervalTier_PointProcess_endToCentre (IntervalTier tier, PointProcess point, double phase); void IntervalTier_removeLeftBoundary (IntervalTier me, long iinterval); - -void TextTier_removePoint (TextTier me, long ipoint); +long IntervalTier_maximumLabelLength (IntervalTier me); +void IntervalTier_removeText (IntervalTier me); +autoTableOfReal IntervalTier_downto_TableOfReal (IntervalTier me, const char32 *label); +autoTableOfReal IntervalTier_downto_TableOfReal_any (IntervalTier me); autoTextGrid TextGrid_createWithoutTiers (double tmin, double tmax); autoTextGrid TextGrid_create (double tmin, double tmax, const char32 *tierNames, const char32 *pointTiers); - long TextGrid_countLabels (TextGrid me, long itier, const char32 *text); long TextGrid_countIntervalsWhere (TextGrid me, long tierNumber, int which_Melder_STRING, const char32 *criterion); long TextGrid_countPointsWhere (TextGrid me, long tierNumber, int which_Melder_STRING, const char32 *criterion); @@ -78,57 +85,36 @@ autoPointProcess TextGrid_getPoints_preceded (TextGrid me, long tierNumber, autoPointProcess TextGrid_getPoints_followed (TextGrid me, long tierNumber, int which_Melder_STRING, const char32 *criterion, int which_Melder_STRING_followedBy, const char32 *criterion_followedBy); - Function TextGrid_checkSpecifiedTierNumberWithinRange (TextGrid me, long tierNumber); IntervalTier TextGrid_checkSpecifiedTierIsIntervalTier (TextGrid me, long tierNumber); TextTier TextGrid_checkSpecifiedTierIsPointTier (TextGrid me, long tierNumber); - void TextGrid_addTier_copy (TextGrid me, Function tier); autoTextGrid TextGrids_merge (OrderedOf* textGrids); autoTextGrid TextGrid_extractPart (TextGrid me, double tmin, double tmax, int preserveTimes); - -autoTextGrid Label_to_TextGrid (Label me, double duration); -autoTextGrid Label_Function_to_TextGrid (Label me, Function function); - -autoTextTier PointProcess_upto_TextTier (PointProcess me, const char32 *text); -autoTableOfReal IntervalTier_downto_TableOfReal (IntervalTier me, const char32 *label); -autoTableOfReal IntervalTier_downto_TableOfReal_any (IntervalTier me); -autoTableOfReal TextTier_downto_TableOfReal (TextTier me, const char32 *label); -autoTableOfReal TextTier_downto_TableOfReal_any (TextTier me); - -autoTextGrid PointProcess_to_TextGrid_vuv (PointProcess me, double maxT, double meanT); - -long TextInterval_labelLength (TextInterval me); -long TextPoint_labelLength (TextPoint me); -long IntervalTier_maximumLabelLength (IntervalTier me); -long TextTier_maximumLabelLength (TextTier me); long TextGrid_maximumLabelLength (TextGrid me); void TextGrid_genericize (TextGrid me); void TextGrid_nativize (TextGrid me); - -void TextInterval_removeText (TextInterval me); -void TextPoint_removeText (TextPoint me); -void IntervalTier_removeText (IntervalTier me); -void TextTier_removeText (TextTier me); - -void TextTier_removePoints (TextTier me, int which_Melder_STRING, const char32 *criterion); void TextGrid_removePoints (TextGrid me, long tierNumber, int which_Melder_STRING, const char32 *criterion); - void TextGrid_insertBoundary (TextGrid me, int itier, double t); void TextGrid_removeBoundaryAtTime (TextGrid me, int itier, double t); void TextGrid_setIntervalText (TextGrid me, int itier, long iinterval, const char32 *text); +void TextGrid_setIntervalHeadText (TextGrid me, int itier, long iinterval, const char32 *text); void TextGrid_insertPoint (TextGrid me, int itier, double t, const char32 *mark); void TextGrid_setPointText (TextGrid me, int itier, long ipoint, const char32 *text); - +void TextGrid_setPointHeadText (TextGrid me, int tierNumber, long pointNumber, const char32 *text); void TextGrid_writeToChronologicalTextFile (TextGrid me, MelderFile file); autoTextGrid TextGrid_readFromChronologicalTextFile (MelderFile file); autoTextGrid TextGrid_readFromCgnSyntaxFile (MelderFile file); - autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeDecimals, bool includeTierNames, bool includeEmptyIntervals); void TextGrid_list (TextGrid me, bool includeLineNumbers, int timeDecimals, bool includeTierNames, bool includeEmptyIntervals); - void TextGrid_correctRoundingErrors (TextGrid me); autoTextGrid TextGrids_concatenate (OrderedOf* me); +autoTextGrid Label_to_TextGrid (Label me, double duration); +autoTextGrid Label_Function_to_TextGrid (Label me, Function function); + +autoTextTier PointProcess_upto_TextTier (PointProcess me, const char32 *text); +autoTextGrid PointProcess_to_TextGrid_vuv (PointProcess me, double maxT, double meanT); + /* End of file TextGrid.h */ #endif diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp index 6bb90536d..49b234a97 100644 --- a/fon/TextGridEditor.cpp +++ b/fon/TextGridEditor.cpp @@ -274,6 +274,7 @@ static void menu_cb_Erase (TextGridEditor me, EDITOR_ARGS_DIRECT) { } #endif +//MelderCallback static void menu_cb_Genericize (TextGridEditor me, EDITOR_ARGS_DIRECT) { Editor_save (me, U"Convert to Backslash Trigraphs"); TextGrid_genericize ((TextGrid) my data); @@ -654,6 +655,244 @@ static void menu_cb_InsertIntervalOnTier6 (TextGridEditor me, EDITOR_ARGS_DIRECT static void menu_cb_InsertIntervalOnTier7 (TextGridEditor me, EDITOR_ARGS_DIRECT) { do_insertIntervalOnTier (me, 7); } static void menu_cb_InsertIntervalOnTier8 (TextGridEditor me, EDITOR_ARGS_DIRECT) { do_insertIntervalOnTier (me, 8); } +#define LABEL_INSERT_DATA U"Insert feature" +#define LABEL_SHOW_DATA U"Show features" +#define LABEL_DELETE_DATA U"Delete feature" +#define LABEL_GET_DATA U"Get feature" +static void menu_cb_InsertFeature (TextGridEditor me, EDITOR_ARGS_FORM) { + EDITOR_FORM (LABEL_INSERT_DATA, nullptr) + SENTENCE (U"Label", U"") + SENTENCE (U"Value", U"") + EDITOR_OK + SET_STRING (U"Label", U"") + SET_STRING (U"Value", U"") + EDITOR_DO + TextGrid grid = (TextGrid) my data; + checkTierSelection (me, LABEL_INSERT_DATA); + if (my selectedTier) { + IntervalTier intervalTier; + TextTier textTier; + _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); + Editor_save (me, LABEL_INSERT_DATA); + if(intervalTier != nullptr){ + long selectedInterval = getSelectedInterval (me); + if (selectedInterval) { + if(str32IsEmpty(GET_STRING (U"Label")) || str32IsEmpty(GET_STRING (U"Value"))){ + Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); + } + TextInterval interval = intervalTier -> intervals.at [selectedInterval]; + char32* tL = trim(GET_STRING (U"Label")); + char32* tV = trim(GET_STRING (U"Value")); + char32* result = addFeatureToText(interval->text, tL, tV); + delete tL; + delete tV; + TextInterval_setText (interval, result); + delete result; + FunctionEditor_updateText (me); + FunctionEditor_redraw (me); + Editor_broadcastDataChanged (me); + } + } else { + long selectedPoint = getSelectedPoint (me); + if (selectedPoint) { + TextPoint point = textTier -> points.at [selectedPoint]; + if (point -> mark) { + char32* tL = trim(GET_STRING (U"Label")); + char32* tV = trim(GET_STRING (U"Value")); + char32* result = addFeatureToText(point -> mark, tL, tV); + delete tL; + delete tV; + TextPoint_setText (point, result); + delete result; + FunctionEditor_updateText (me); + FunctionEditor_redraw (me); + Editor_broadcastDataChanged (me); + } + } + else{ + Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); + } + } + } + EDITOR_END +} + +static void menu_cb_ShowFeatures (TextGridEditor me, EDITOR_ARGS_FORM) { + TextGrid grid = (TextGrid) my data; + checkTierSelection (me, LABEL_INSERT_DATA); + if (my selectedTier) { + IntervalTier intervalTier; + TextTier textTier; + _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); + if(intervalTier != nullptr){ + //Editor_save (me, LABEL_INSERT_DATA); + long selectedInterval = getSelectedInterval (me); + if (selectedInterval) { + TextInterval interval = intervalTier -> intervals.at [selectedInterval]; + tierFeatures* result = extractTierFeatures(interval->text); + Melder_clearInfo (); + MelderInfo_open (); + feature* tmp = result->firstFeature; + while(tmp != nullptr){ + char32* nLabel = removeBackslashes(tmp->label); + char32* nValue = removeBackslashes(tmp->value); + char32 * cat = str32cat(nLabel, U": "); + MelderInfo_writeLine (cat, nValue); + delete cat; + delete nLabel; + delete nValue; + tmp = tmp->nxtPtr; + } + MelderInfo_close (); + delete result; + } + } else { + long selectedPoint = getSelectedPoint (me); + if (selectedPoint) { + TextPoint point = textTier -> points.at [selectedPoint]; + tierFeatures* result = extractTierFeatures(point->mark); + Melder_clearInfo (); + MelderInfo_open (); + feature* tmp = result->firstFeature; + while(tmp != nullptr){ + char32* nLabel = removeBackslashes(tmp->label); + char32* nValue = removeBackslashes(tmp->value); + char32 * cat = str32cat(nLabel, U": "); + MelderInfo_writeLine (cat, nValue); + delete cat; + delete nLabel; + delete nValue; + tmp = tmp->nxtPtr; + } + MelderInfo_close (); + delete result; + } + else{ + Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); + } + } + } +} + +static void menu_cb_DeleteFeature (TextGridEditor me, EDITOR_ARGS_FORM) { + EDITOR_FORM (LABEL_DELETE_DATA, nullptr) + SENTENCE (U"Label", U"") + EDITOR_OK + SET_STRING (U"Label", U"") + EDITOR_DO + TextGrid grid = (TextGrid) my data; + checkTierSelection (me, LABEL_DELETE_DATA); + if (my selectedTier) { + IntervalTier intervalTier; + TextTier textTier; + _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); + Editor_save (me, LABEL_DELETE_DATA); + if(intervalTier != nullptr){ + long selectedInterval = getSelectedInterval (me); + if (selectedInterval) { + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + TextInterval interval = intervalTier -> intervals.at [selectedInterval]; + char32* tL = trim(GET_STRING (U"Label")); + tierFeatures* tierData = extractTierFeatures(interval->text); + deleteFeatureFromTierFeatures(tierData, tL); + char32 * newText = generateTextFromTierFeatures(tierData); + TextInterval_setText (interval, newText); + FunctionEditor_updateText (me); + FunctionEditor_redraw (me); + Editor_broadcastDataChanged (me); + delete tierData; + delete newText; + delete tL; + } + }else { + long selectedPoint = getSelectedPoint (me); + if (selectedPoint) { + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + TextPoint point = textTier -> points.at [selectedPoint]; + char32* tL = trim(GET_STRING (U"Label")); + tierFeatures* tierData = extractTierFeatures(point->mark); + deleteFeatureFromTierFeatures(tierData, tL); + char32 * newText = generateTextFromTierFeatures(tierData); + TextPoint_setText (point, newText); + FunctionEditor_updateText (me); + FunctionEditor_redraw (me); + Editor_broadcastDataChanged (me); + delete tierData; + delete newText; + delete tL; + } + else{ + Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); + } + } + } + EDITOR_END +} + +static void menu_cb_GetFeature (TextGridEditor me, EDITOR_ARGS_FORM) { + EDITOR_FORM (LABEL_GET_DATA, nullptr) + SENTENCE (U"Label", U"") + EDITOR_OK + SET_STRING (U"Label", U"") + EDITOR_DO + TextGrid grid = (TextGrid) my data; + checkTierSelection (me, LABEL_GET_DATA); + if (my selectedTier) { + IntervalTier intervalTier; + TextTier textTier; + _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); + if(intervalTier != nullptr){ + long selectedInterval = getSelectedInterval (me); + if (selectedInterval) { + TextInterval interval = intervalTier -> intervals.at [selectedInterval]; + tierFeatures* result = extractTierFeatures(interval->text); + char32* tL = trim(GET_STRING (U"Label")); + char32* fLabel = addBackslashes(tL); + feature* ann = getExistentFeature(result, fLabel); + if(ann != nullptr){ + Melder_clearInfo (); + MelderInfo_open (); + char32* nValue = removeBackslashes(ann->value); + MelderInfo_writeLine (nValue); + delete nValue; + MelderInfo_close (); + } + delete tL; + delete fLabel; + delete result; + } + } else { + long selectedPoint = getSelectedPoint (me); + if (selectedPoint) { + TextPoint point = textTier -> points.at [selectedPoint]; + tierFeatures* result = extractTierFeatures(point->mark); + char32* tL = trim(GET_STRING (U"Label")); + char32* fLabel = addBackslashes(tL); + feature* ann = getExistentFeature(result, fLabel); + if(ann != nullptr){ + Melder_clearInfo (); + MelderInfo_open (); + char32* nValue = removeBackslashes(ann->value); + MelderInfo_writeLine (nValue); + delete nValue; + MelderInfo_close (); + } + delete tL; + delete fLabel; + delete result; + } + else{ + Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); + } + } + } + EDITOR_END +} + static void menu_cb_AlignInterval (TextGridEditor me, EDITOR_ARGS_DIRECT) { TextGrid grid = (TextGrid) my data; checkTierSelection (me, U"align words"); @@ -1226,6 +1465,11 @@ void structTextGridEditor :: v_createMenus () { EditorMenu_addCommand (menu, U"-- extract tier --", 0, nullptr); EditorMenu_addCommand (menu, U"Extract to list of objects:", GuiMenu_INSENSITIVE, menu_cb_PublishTier /* dummy */); EditorMenu_addCommand (menu, U"Extract entire selected tier", 0, menu_cb_PublishTier); + EditorMenu_addCommand (menu, U"-- annotations --", 0, nullptr); + EditorMenu_addCommand (menu, LABEL_INSERT_DATA, 0, menu_cb_InsertFeature); + EditorMenu_addCommand (menu, LABEL_DELETE_DATA, 0, menu_cb_DeleteFeature); + EditorMenu_addCommand (menu, LABEL_GET_DATA, 0, menu_cb_GetFeature); + EditorMenu_addCommand (menu, LABEL_SHOW_DATA, 0, menu_cb_ShowFeatures); if (spellingChecker) { menu = Editor_addMenu (this, U"Spell", 0); @@ -1268,6 +1512,14 @@ static void gui_text_cb_changed (TextGridEditor me, GuiTextEvent /* event */) { TextInterval interval = intervalTier -> intervals.at [selectedInterval]; //Melder_casual (U"gui_text_cb_change 3 in editor ", Melder_pointer (me)); TextInterval_setText (interval, text); + /*tierFeatures* tierTextData = extractTierFeatures(interval->text); + delete tierTextData->text; + tierTextData->text = allocChar32(str32len(text)+1); + str32cpy(tierTextData->text, text); + char32 * fullText = generateTextFromTierFeatures(tierTextData); + TextInterval_setText (interval, fullText); + delete fullText;*/ + //Melder_casual (U"gui_text_cb_change 4 in editor ", Melder_pointer (me)); FunctionEditor_redraw (me); //Melder_casual (U"gui_text_cb_change 5 in editor ", Melder_pointer (me)); @@ -1281,6 +1533,14 @@ static void gui_text_cb_changed (TextGridEditor me, GuiTextEvent /* event */) { Melder_free (point -> mark); if (str32spn (text, U" \n\t") != str32len (text)) // any visible characters? point -> mark = Melder_dup_f (text); + /*tierFeatures* tierTextData = extractTierFeatures(point->mark); + delete tierTextData->text; + tierTextData->text = allocChar32(str32len(text)+1); + str32cpy(tierTextData->text, text); + char32 * fullText = generateTextFromTierFeatures(tierTextData); + TextPoint_setText (point, fullText); + delete fullText;*/ + FunctionEditor_redraw (me); Editor_broadcastDataChanged (me); } @@ -1418,7 +1678,9 @@ static void do_drawIntervalTier (TextGridEditor me, IntervalTier tier, int itier double t1 = my d_startWindow > tmin ? my d_startWindow : tmin; double t2 = my d_endWindow < tmax ? my d_endWindow : tmax; Graphics_setColour (my d_graphics.get(), intervalIsSelected ? Graphics_RED : Graphics_BLACK); - Graphics_textRect (my d_graphics.get(), t1, t2, 0.0, 1.0, interval -> text); + tierFeatures* ttd = extractTierFeatures(interval -> text); + Graphics_textRect (my d_graphics.get(), t1, t2, 0.0, 1.0, ttd->text); + delete ttd; Graphics_setColour (my d_graphics.get(), Graphics_BLACK); } @@ -1489,7 +1751,11 @@ static void do_drawTextTier (TextGridEditor me, TextTier tier, int itier) { Graphics_line (my d_graphics.get(), t, 0.8, t, 1.0); } Graphics_setColour (my d_graphics.get(), pointIsSelected ? Graphics_RED : Graphics_BLUE); - if (point -> mark) Graphics_text (my d_graphics.get(), t, 0.5, point -> mark); + if (point -> mark){ + tierFeatures* ttd = extractTierFeatures(point -> mark); + Graphics_text (my d_graphics.get(), t, 0.5, ttd->text); + delete ttd; + } } } Graphics_setPercentSignIsItalic (my d_graphics.get(), true); @@ -2030,6 +2296,7 @@ void structTextGridEditor :: v_play (double tmin, double tmax) { void structTextGridEditor :: v_updateText () { TextGrid grid = (TextGrid) our data; const char32 *newText = U""; + //tierTextData* tierTextData = nullptr; trace (U"selected tier ", our selectedTier); if (our selectedTier) { IntervalTier intervalTier; @@ -2040,6 +2307,8 @@ void structTextGridEditor :: v_updateText () { if (iinterval) { TextInterval interval = intervalTier -> intervals.at [iinterval]; if (interval -> text) { + /*tierTextData = extractTierTextData(interval -> text); + newText = tierTextData -> text;*/ newText = interval -> text; } } @@ -2048,6 +2317,8 @@ void structTextGridEditor :: v_updateText () { if (ipoint) { TextPoint point = textTier -> points.at [ipoint]; if (point -> mark) { + /*tierTextData = extractTierTextData(point -> mark); + newText = tierTextData -> text;*/ newText = point -> mark; } } @@ -2062,6 +2333,7 @@ void structTextGridEditor :: v_updateText () { GuiText_setSelection (text, cursor, cursor); our suppressRedraw = false; } + //delete tierTextData; } void structTextGridEditor :: v_prefs_addFields (EditorCommand cmd) { diff --git a/fon/TextGridEditor.h b/fon/TextGridEditor.h index 51fa0b72f..96b293b8b 100644 --- a/fon/TextGridEditor.h +++ b/fon/TextGridEditor.h @@ -22,7 +22,8 @@ #include "TimeSoundAnalysisEditor.h" #include "TextGrid.h" #include "SpellingChecker.h" -#include "Preferences.h" +//#include "Preferences.h" +#include "Feature.h" #include "TextGridEditor_enums.h" diff --git a/fon/praat_TextGrid_init.cpp b/fon/praat_TextGrid_init.cpp index be98f8b8c..7e45a3e71 100644 --- a/fon/praat_TextGrid_init.cpp +++ b/fon/praat_TextGrid_init.cpp @@ -38,6 +38,7 @@ static const char32 *STRING_FROM_FREQUENCY_HZ = U"left Frequency range (Hz)"; static const char32 *STRING_TO_FREQUENCY_HZ = U"right Frequency range (Hz)"; static const char32 *STRING_TIER_NUMBER = U"Tier number"; static const char32 *STRING_INTERVAL_NUMBER = U"Interval number"; +static const char32 *STRING_FEATURE_NUMBER = U"Feature number"; static const char32 *STRING_POINT_NUMBER = U"Point number"; void praat_TimeFunction_modify_init (ClassInfo klas); // Modify buttons for time-based subclasses of Function. @@ -1161,6 +1162,368 @@ DO MelderInfo_close (); END2 } +FORM (TextGrid_insertFeatureToInterval, U"TextGrid: Insert feature to interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + SENTENCE (U"Label", U"") + SENTENCE (U"Value", U"") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + if(str32IsEmpty(GET_STRING (U"Label")) || str32IsEmpty(GET_STRING (U"Value"))){ + Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); + } + char32* tL = trim(GET_STRING (U"Label")); + char32* tV = trim(GET_STRING (U"Value")); + char32* result = addFeatureToText(interval->text, tL, tV); + delete tL; + delete tV; + TextInterval_setText(interval, result); + delete result; +END2 } + +FORM (TextGrid_deleteFeatureFromInterval, U"TextGrid: Delete feature from interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + SENTENCE (U"Label", U"") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + char32* tL = trim(GET_STRING (U"Label")); + tierFeatures* tierData = extractTierFeatures(interval->text); + deleteFeatureFromTierFeatures(tierData, tL); + char32 * newText = generateTextFromTierFeatures(tierData); + TextInterval_setText (interval, newText); + delete tierData; + delete newText; + delete tL; +END2 } + +FORM (TextGrid_getFeatureFromInterval, U"TextGrid: Get feature from interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + SENTENCE (U"Label", U"") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + tierFeatures* result = extractTierFeatures(interval->text); + char32* tL = trim(GET_STRING (U"Label")); + char32* fLabel = addBackslashes(tL); + feature* ann = getExistentFeature(result, fLabel); + if(ann != nullptr){ + Melder_clearInfo (); + MelderInfo_open (); + char32* nValue = removeBackslashes(ann->value); + MelderInfo_write (nValue); + delete nValue; + MelderInfo_close (); + } + delete tL; + delete fLabel; + delete result; +END2 } + +/*FORM (TextGrid_showFeaturesInInterval, U"TextGrid: Show feature in interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + tierFeatures* result = extractTierFeatures(interval->text); + Melder_clearInfo (); + MelderInfo_open (); + feature* tmp = result->firstFeature; + while(tmp != nullptr){ + char32* nLabel = removeBackslashes(tmp->label); + char32* nValue = removeBackslashes(tmp->value); + char32 * cat = str32cat(nLabel, U":"); + char32 * cat2 = str32cat(nValue, U";"); + MelderInfo_write (cat, cat2); + delete cat2; + delete cat; + delete nLabel; + delete nValue; + tmp = tmp->nxtPtr; + } + MelderInfo_close (); + delete result; +END2 }*/ + +FORM (TextGrid_showFeaturesInInterval, U"TextGrid: Show feature in interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + tierFeatures* result = extractTierFeatures(interval->text); + Melder_clearInfo (); + MelderInfo_open (); + feature* tmp = result->firstFeature; + while(tmp != nullptr){ + char32* nLabel = removeBackslashes(tmp->label); + char32* nValue = removeBackslashes(tmp->value); + char32 * cat = str32cat(nLabel, U": "); + MelderInfo_writeLine (cat, nValue); + delete cat; + delete nLabel; + delete nValue; + tmp = tmp->nxtPtr; + } + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_numberFeaturesInInterval, U"TextGrid: Get number of features in interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + tierFeatures* result = extractTierFeatures(interval->text); + feature* tmp = result->firstFeature; + int count = 0; + while(tmp != nullptr){ + count ++; + tmp = tmp->nxtPtr; + } + Melder_clearInfo (); + MelderInfo_open (); + MelderInfo_write (count); + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_labelFeaturesInInterval, U"TextGrid: Get label of features in interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + NATURAL (STRING_FEATURE_NUMBER, U"1") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + tierFeatures* result = extractTierFeatures(interval->text); + feature* tmp = result->firstFeature; + int count = 0; + int featureNumber = GET_INTEGER (STRING_FEATURE_NUMBER); + while(tmp != nullptr && count < featureNumber -1){ + count ++; + tmp = tmp->nxtPtr; + } + if(tmp == nullptr){ + Melder_throw (U"Feature does not exist."); + } + Melder_clearInfo (); + MelderInfo_open (); + char32* nLabel = removeBackslashes(tmp->label); + MelderInfo_write (nLabel); + delete nLabel; + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_headOfInterval, U"TextGrid: Get head of interval", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + OK2 +DO + TextInterval interval = pr_TextGrid_peekInterval (dia); + tierFeatures* result = extractTierFeatures(interval->text); + Melder_clearInfo (); + MelderInfo_open (); + MelderInfo_write (result->text); + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_setIntervalHeadText, U"TextGrid: Set interval head text", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_INTERVAL_NUMBER, U"1") + LABEL (U"", U"Text:") + TEXTFIELD (U"text", U"") + OK2 +DO + LOOP { + iam (TextGrid); + TextGrid_setIntervalHeadText (me, GET_INTEGER (STRING_TIER_NUMBER), GET_INTEGER (STRING_INTERVAL_NUMBER), GET_STRING (U"text")); + praat_dataChanged (me); + } +END2 } + +FORM (TextGrid_setPointHeadText, U"TextGrid: Set point head text", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + LABEL (U"", U"Text:") + TEXTFIELD (U"text", U"") + OK2 +DO + LOOP { + iam (TextGrid); + TextGrid_setPointHeadText (me, GET_INTEGER (STRING_TIER_NUMBER), GET_INTEGER (STRING_POINT_NUMBER), GET_STRING (U"text")); + praat_dataChanged (me); + } +END2 } + +FORM (TextGrid_headOfPoint, U"TextGrid: Get head of point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint (dia); + tierFeatures* result = extractTierFeatures(point->mark); + Melder_clearInfo (); + MelderInfo_open (); + MelderInfo_write (result->text); + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_numberFeaturesInPoint, U"TextGrid: Get number of features in point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint (dia); + tierFeatures* result = extractTierFeatures(point->mark); + feature* tmp = result->firstFeature; + int count = 0; + while(tmp != nullptr){ + count ++; + tmp = tmp->nxtPtr; + } + Melder_clearInfo (); + MelderInfo_open (); + MelderInfo_write (count); + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_labelFeaturesInPoint, U"TextGrid: Get label of features in point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + NATURAL (STRING_FEATURE_NUMBER, U"1") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint (dia); + tierFeatures* result = extractTierFeatures(point->mark); + feature* tmp = result->firstFeature; + int count = 0; + int featureNumber = GET_INTEGER (STRING_FEATURE_NUMBER); + while(tmp != nullptr && count < featureNumber -1){ + count ++; + tmp = tmp->nxtPtr; + } + if(tmp == nullptr){ + Melder_throw (U"Feature does not exist."); + } + Melder_clearInfo (); + MelderInfo_open (); + char32* nLabel = removeBackslashes(tmp->label); + MelderInfo_write (nLabel); + delete nLabel; + MelderInfo_close (); + delete result; +END2 } + +FORM (TextGrid_insertFeatureToPoint, U"TextGrid: Insert feature to point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + SENTENCE (U"Label", U"") + SENTENCE (U"Value", U"") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint(dia); + if(str32IsEmpty(GET_STRING (U"Label")) || str32IsEmpty(GET_STRING (U"Value"))){ + Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); + } + char32* tL = trim(GET_STRING (U"Label")); + char32* tV = trim(GET_STRING (U"Value")); + char32* result = addFeatureToText(point -> mark, tL, tV); + delete tL; + delete tV; + TextPoint_setText(point, result); + delete result; +END2 } + +FORM (TextGrid_deleteFeatureFromPoint, U"TextGrid: Delete feature from point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + SENTENCE (U"Label", U"") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint(dia); + + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + char32* tL = trim(GET_STRING (U"Label")); + tierFeatures* tierData = extractTierFeatures(point->mark); + deleteFeatureFromTierFeatures(tierData, tL); + char32 * newText = generateTextFromTierFeatures(tierData); + TextPoint_setText (point, newText); + delete tierData; + delete newText; + delete tL; +END2 } + +FORM (TextGrid_getFeatureFromPoint, U"TextGrid: Get feature from point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + SENTENCE (U"Label", U"") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint(dia); + + if(str32IsEmpty(GET_STRING (U"Label"))){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + tierFeatures* result = extractTierFeatures(point->mark); + char32* tL = trim(GET_STRING (U"Label")); + char32* fLabel = addBackslashes(tL); + feature* ann = getExistentFeature(result, fLabel); + if(ann != nullptr){ + Melder_clearInfo (); + MelderInfo_open (); + char32* nValue = removeBackslashes(ann->value); + MelderInfo_write (nValue); + delete nValue; + MelderInfo_close (); + } + delete tL; + delete fLabel; + delete result; +END2 } + +FORM (TextGrid_showFeaturesInPoint, U"TextGrid: Show feature in point", nullptr) { + NATURAL (STRING_TIER_NUMBER, U"1") + NATURAL (STRING_POINT_NUMBER, U"1") + OK2 +DO + TextPoint point = pr_TextGrid_peekPoint(dia); + tierFeatures* result = extractTierFeatures(point->mark); + Melder_clearInfo (); + MelderInfo_open (); + feature* tmp = result->firstFeature; + while(tmp != nullptr){ + char32* nLabel = removeBackslashes(tmp->label); + char32* nValue = removeBackslashes(tmp->value); + char32 * cat = str32cat(nLabel, U": "); + MelderInfo_writeLine (cat, nValue); + delete cat; + delete nLabel; + delete nValue; + tmp = tmp->nxtPtr; + } + MelderInfo_close (); + delete result; +END2 } + FORM (TextGrid_getNumberOfPoints, U"TextGrid: Get number of points", nullptr) { NATURAL (STRING_TIER_NUMBER, U"1") OK2 @@ -1763,6 +2126,7 @@ void praat_uvafon_TextGrid_init () { praat_addAction1 (classTextGrid, 1, U"Get start point...", nullptr, praat_HIDDEN + praat_DEPTH_2, DO_TextGrid_getStartingPoint); praat_addAction1 (classTextGrid, 1, U"Get end point...", nullptr, 2, DO_TextGrid_getEndPoint); praat_addAction1 (classTextGrid, 1, U"Get label of interval...", nullptr, 2, DO_TextGrid_getLabelOfInterval); + praat_addAction1 (classTextGrid, 1, U"Get head of interval...", nullptr, 2, DO_TextGrid_headOfInterval); praat_addAction1 (classTextGrid, 1, U"-- query interval from time --", nullptr, 2, nullptr); praat_addAction1 (classTextGrid, 1, U"Get interval at time...", nullptr, 2, DO_TextGrid_getIntervalAtTime); praat_addAction1 (classTextGrid, 1, U"Get low interval at time...", nullptr, 2, DO_TextGrid_getLowIntervalAtTime); @@ -1771,16 +2135,27 @@ void praat_uvafon_TextGrid_init () { praat_addAction1 (classTextGrid, 1, U"Get interval boundary from time...", nullptr, 2, DO_TextGrid_getIntervalBoundaryFromTime); praat_addAction1 (classTextGrid, 1, U"-- query interval labels --", nullptr, 2, nullptr); praat_addAction1 (classTextGrid, 1, U"Count intervals where...", nullptr, 2, DO_TextGrid_countIntervalsWhere); + praat_addAction1 (classTextGrid, 1, U"-- --", nullptr, 2, nullptr); + praat_addAction1 (classTextGrid, 1, U"Get number of features in interval...", nullptr, 2, DO_TextGrid_numberFeaturesInInterval); + praat_addAction1 (classTextGrid, 1, U"Get label of feature in interval...", nullptr, 2, DO_TextGrid_labelFeaturesInInterval); + praat_addAction1 (classTextGrid, 1, U"Get feature from interval...", nullptr, 2, DO_TextGrid_getFeatureFromInterval); + praat_addAction1 (classTextGrid, 1, U"Show features in interval...", nullptr, 2, DO_TextGrid_showFeaturesInInterval); praat_addAction1 (classTextGrid, 1, U"Query point tier", nullptr, 1, nullptr); praat_addAction1 (classTextGrid, 1, U"Get number of points...", nullptr, 2, DO_TextGrid_getNumberOfPoints); praat_addAction1 (classTextGrid, 1, U"Get time of point...", nullptr, 2, DO_TextGrid_getTimeOfPoint); praat_addAction1 (classTextGrid, 1, U"Get label of point...", nullptr, 2, DO_TextGrid_getLabelOfPoint); + praat_addAction1 (classTextGrid, 1, U"Get head of point...", nullptr, 2, DO_TextGrid_headOfPoint); praat_addAction1 (classTextGrid, 1, U"-- query point from time --", nullptr, 2, nullptr); praat_addAction1 (classTextGrid, 1, U"Get low index from time...", nullptr, 2, DO_TextGrid_getLowIndexFromTime); praat_addAction1 (classTextGrid, 1, U"Get high index from time...", nullptr, 2, DO_TextGrid_getHighIndexFromTime); praat_addAction1 (classTextGrid, 1, U"Get nearest index from time...", nullptr, 2, DO_TextGrid_getNearestIndexFromTime); praat_addAction1 (classTextGrid, 1, U"-- query point labels --", nullptr, 2, nullptr); praat_addAction1 (classTextGrid, 1, U"Count points where...", nullptr, 2, DO_TextGrid_countPointsWhere); + praat_addAction1 (classTextGrid, 1, U"-- --", nullptr, 2, nullptr); + praat_addAction1 (classTextGrid, 1, U"Get number of features in point...", nullptr, 2, DO_TextGrid_numberFeaturesInPoint); + praat_addAction1 (classTextGrid, 1, U"Get label of feature in point...", nullptr, 2, DO_TextGrid_labelFeaturesInPoint); + praat_addAction1 (classTextGrid, 1, U"Get feature from point...", nullptr, 2, DO_TextGrid_getFeatureFromPoint); + praat_addAction1 (classTextGrid, 1, U"Show features in point...", nullptr, 2, DO_TextGrid_showFeaturesInPoint); praat_addAction1 (classTextGrid, 1, U"-- query labels --", nullptr, praat_HIDDEN + praat_DEPTH_1, nullptr); praat_addAction1 (classTextGrid, 1, U"Count labels...", nullptr, praat_HIDDEN + praat_DEPTH_1, DO_TextGrid_countLabels); // hidden 2015 praat_addAction1 (classTextGrid, 0, U"Modify -", nullptr, 0, nullptr); @@ -1801,11 +2176,19 @@ void praat_uvafon_TextGrid_init () { praat_addAction1 (classTextGrid, 0, U"Remove right boundary...", nullptr, 2, DO_TextGrid_removeRightBoundary); praat_addAction1 (classTextGrid, 0, U"Remove boundary at time...", nullptr, 2, DO_TextGrid_removeBoundaryAtTime); praat_addAction1 (classTextGrid, 0, U"Set interval text...", nullptr, 2, DO_TextGrid_setIntervalText); + praat_addAction1 (classTextGrid, 0, U"Set interval head text...", nullptr, 2, DO_TextGrid_setIntervalHeadText); + praat_addAction1 (classTextGrid, 1, U"-- --", nullptr, 2, nullptr); + praat_addAction1 (classTextGrid, 1, U"Insert feature to interval...", nullptr, 2, DO_TextGrid_insertFeatureToInterval); + praat_addAction1 (classTextGrid, 1, U"Delete feature from interval...", nullptr, 2, DO_TextGrid_deleteFeatureFromInterval); praat_addAction1 (classTextGrid, 0, U"Modify point tier", nullptr, 1, nullptr); praat_addAction1 (classTextGrid, 0, U"Insert point...", nullptr, 2, DO_TextGrid_insertPoint); praat_addAction1 (classTextGrid, 0, U"Remove point...", nullptr, 2, DO_TextGrid_removePoint); praat_addAction1 (classTextGrid, 0, U"Remove points...", nullptr, 2, DO_TextGrid_removePoints); praat_addAction1 (classTextGrid, 0, U"Set point text...", nullptr, 2, DO_TextGrid_setPointText); + praat_addAction1 (classTextGrid, 0, U"Set point head text...", nullptr, 2, DO_TextGrid_setPointHeadText); + praat_addAction1 (classTextGrid, 1, U"-- --", nullptr, 2, nullptr); + praat_addAction1 (classTextGrid, 1, U"Insert feature to point...", nullptr, 2, DO_TextGrid_insertFeatureToPoint); + praat_addAction1 (classTextGrid, 1, U"Delete feature from point...", nullptr, 2, DO_TextGrid_deleteFeatureFromPoint); praat_addAction1 (classTextGrid, 0, U"Analyse", nullptr, 0, nullptr); praat_addAction1 (classTextGrid, 1, U"Extract one tier...", nullptr, 0, DO_TextGrid_extractOneTier); praat_addAction1 (classTextGrid, 1, U"Extract tier...", nullptr, praat_HIDDEN, DO_TextGrid_extractTier); // hidden 2010 From b25ef3877c7b238b90255b4e47fb32e686ad247c Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 13 Jul 2017 13:20:35 +0200 Subject: [PATCH 2/5] Makefile with new class Feature --- fon/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fon/Makefile b/fon/Makefile index 3643c0056..9f3804e8b 100644 --- a/fon/Makefile +++ b/fon/Makefile @@ -37,7 +37,7 @@ OBJECTS = Transition.o Distributions_and_Transition.o \ manual_programming.o manual_Fon.o manual_voice.o Praat_tests.o \ manual_glossary.o manual_Sampling.o manual_exampleSound.o \ manual_sound.o manual_pitch.o manual_spectrum.o manual_formant.o manual_annotation.o \ - praat_Sound_init.o praat_TextGrid_init.o praat_Fon.o + praat_Sound_init.o praat_TextGrid_init.o praat_Fon.o Feature.o .PHONY: all clean From 0884502212ffd0c3a751313d831df2474e50993a Mon Sep 17 00:00:00 2001 From: Ivan Date: Wed, 15 Nov 2017 16:09:17 +0100 Subject: [PATCH 3/5] Changes on features extension: Char32 pointers replaced for MelderString and autoMelderString widely in structures and functions Memory management revised Duplicated functions deleted Text treatment functions like trim added as MelderString functions New processing functions created to clean up interface code Functions renamed to better fit Praat's notation and names pollution solved --- dwtools/Strings_extensions.cpp | 4 - fon/Feature.cpp | 325 ++++++++++++++------------------- fon/Feature.h | 63 +++---- fon/TextGrid.cpp | 24 +-- fon/TextGridEditor.cpp | 181 +++++++----------- fon/praat_TextGrid_init.cpp | 292 ++++++++++------------------- sys/melder.h | 3 + sys/melder_strings.cpp | 24 +++ 8 files changed, 370 insertions(+), 546 deletions(-) diff --git a/dwtools/Strings_extensions.cpp b/dwtools/Strings_extensions.cpp index 5e1ae3c11..3153f1bc4 100644 --- a/dwtools/Strings_extensions.cpp +++ b/dwtools/Strings_extensions.cpp @@ -314,8 +314,4 @@ autoStringsIndex Table_to_StringsIndex_column (Table me, long column) { } } -bool string_isEmpty (const char32 *string) { - -} - /* End of file Strings_extensions.cpp */ diff --git a/fon/Feature.cpp b/fon/Feature.cpp index 5ab4d432b..3eac449a2 100644 --- a/fon/Feature.cpp +++ b/fon/Feature.cpp @@ -23,91 +23,15 @@ #include "Feature.h" -/********** char32 UTILITIES **********/ - -/** - * Allocates memory for a char32_t string of length "size", and initializes all its positions to '\0'. - * It returns a pointer to its first position. - */ -inline static char32* allocChar32(int size){ - char32* string = (char32*) malloc ((size_t) size * sizeof (char32)); - char32* currentPos = string; - for(int i=0;i 0;p++, pos--); - while (* source != U'\0') * p ++ = * source ++; - *p = U'\0'; - return target; -} - -/** - * Concatenates the contents of both source strings in a new one. - * It returns a pointer to the first position of the new string. - */ -char32* str32cat(char32 *source1, const char32 *source2){ - if(source1 == nullptr || source2 == nullptr) return nullptr; - char32 * result = allocChar32(str32len(source1) + str32len(source2) + 1); - str32cpy(result, source1); - str32append(result, source2, str32len(result)); - return result; -} - -/** - * Returns a new string with the trimmed version of the source text - */ -char32* trim(const char32 *text) { - if(str32len(text) == 0) return nullptr; - const char32 * forwardPtr = text; - int initialBlanks = 0; - while(*forwardPtr != U'\0' && *forwardPtr == U' '){ - initialBlanks++; - forwardPtr++; - } - - char32 * result = allocChar32(str32len(text) - initialBlanks + 1); - str32cpy(result, forwardPtr); - - char32 * backwardPtr = result + str32len(result)-1; - while(backwardPtr+1 != result && *backwardPtr == U' '){ - *backwardPtr-- = U'\0'; - } - - return result; -} - -/** - * Returns whether or not the string is empty or null. - */ -bool str32IsEmpty(const char32 *text){ - if(text == nullptr) return true; - bool result = false; - char32* trimmed = trim(text); - if(trimmed == nullptr || str32len(trimmed) == 0) - result = true; - delete trimmed; - return result; -} - -/*---------------------------------------------------*/ +#define my me -> /** * Given a tierFeatures it returns a pointer to the current feature. * If there is no feature created then it creates the first and returns it. */ -feature* getCurrentFeature(tierFeatures* data){ +Feature* TierFeatures_getCurrentFeature(TierFeatures* data){ if(data->currentFeature == nullptr){ - data->firstFeature = new feature(); + data->firstFeature = new Feature(); data->currentFeature = data->firstFeature; } return data->currentFeature; @@ -117,13 +41,13 @@ feature* getCurrentFeature(tierFeatures* data){ * Given a tierFeatures it returns a pointer to the next feature after the current. * If there is no feature after the current one, then it creates and returns it. */ -feature* getNextFeature(tierFeatures* data){ +Feature* TierFeatures_getNextFeature(TierFeatures* data){ if(data->currentFeature == nullptr){ - data->firstFeature = new feature(); + data->firstFeature = new Feature(); data->currentFeature = data->firstFeature; }else{ if(data->currentFeature->nxtPtr == nullptr){ - data->currentFeature->nxtPtr = new feature(); + data->currentFeature->nxtPtr = new Feature(); data->currentFeature = data->currentFeature->nxtPtr; } } @@ -144,13 +68,13 @@ feature* getNextFeature(tierFeatures* data){ * State 7: Ended correctly * State 8: Error the whole string will be considered interval or point text. */ -tierFeatures* extractTierFeatures(const char32* text){ - if(text == nullptr) return new tierFeatures(); +TierFeatures* TierFeatures_extractFromText(const char32* text){ + if(text == nullptr) return new TierFeatures(); int state = 0; int64 pos = 0; const char32* currentPos = text; const char32* lastCheckPoint = text; - tierFeatures* data = new tierFeatures(); + TierFeatures* data = new TierFeatures(); const char32* temp; do{ char32 currentChar = *currentPos++; @@ -163,8 +87,7 @@ tierFeatures* extractTierFeatures(const char32* text){ temp = currentPos; if(*temp++ == U'{' && *temp++ == U'@'){ currentPos = temp; - data->text = allocChar32(pos); - str32ncpy(data->text, lastCheckPoint, pos-1); + MelderString_ncopy(&data->headText, lastCheckPoint, pos-1); lastCheckPoint = currentPos; pos = 0; state = 1; @@ -200,8 +123,7 @@ tierFeatures* extractTierFeatures(const char32* text){ break; } if(currentChar != U'"') break; - getNextFeature(data)->label = allocChar32(pos); - str32ncpy(getCurrentFeature(data)->label, lastCheckPoint, pos-1); + MelderString_ncopy(&TierFeatures_getNextFeature(data)->label, lastCheckPoint, pos-1); lastCheckPoint = currentPos; pos = 0; state = 3; @@ -228,8 +150,7 @@ tierFeatures* extractTierFeatures(const char32* text){ break; } if(currentChar != U'"') break; - getCurrentFeature(data)->value = allocChar32(pos); - str32ncpy(getCurrentFeature(data)->value, lastCheckPoint, pos-1); + MelderString_ncopy(&TierFeatures_getCurrentFeature(data)->value, lastCheckPoint, pos-1); lastCheckPoint = currentPos; pos = 0; state = 6; @@ -261,61 +182,59 @@ tierFeatures* extractTierFeatures(const char32* text){ if(state != 7){ delete data; - data = new tierFeatures(); - data->text = allocChar32(str32len(text)+1); - str32ncpy(data->text, text, str32len(text)); + data = new TierFeatures(); + MelderString_copy(&data->headText, text); } return data; } /** - * It returns a new char32_t string with the content of text but with backslashes before \ and " + * It encodes a Feature text by adding backslash before special characters so it can be stores inside Tierfeatures text */ -char32* addBackslashes(const char32* text){ - int neededSpace = 0; - const char32* tmp = text; - for(;*tmp != U'\0';tmp++){ - neededSpace++; - if(*tmp == U'"' || *tmp == U'\\') - neededSpace++; +void Feature_encodeText(MelderString* me){ + int sizeNeeded = my length; + for(int i = 0;i < my length; i++){ + if(my string [i] == U'"' || my string [i] == U'\\') + sizeNeeded++; } - char32* result = allocChar32(neededSpace+1); - tmp = text; - char32* aux = result; - for(;*tmp != U'\0';){ - if(*tmp == U'"' || *tmp == U'\\') - *aux++ = U'\\'; - *aux++ = *tmp++; + if (sizeNeeded > my bufferSize) MelderString_expand (me, sizeNeeded); + + for(int newSize = sizeNeeded, oldSize = my length; newSize >= 0 && oldSize >= 0; newSize--, oldSize--){ + my string [newSize] = my string [oldSize]; + if(my string [newSize] == U'"' || my string [newSize] == U'\\'){ + newSize --; + my string [newSize] = U'\\'; + } } - return result; + my length = sizeNeeded; } /** - * It returns a new char32_t string with the content of text but without initial backslashes of special characters + * It decodes a Feature text coming from TierFeatures text by deleting backslash preceding special characters */ -char32* removeBackslashes(const char32* text){ - char32* result = allocChar32(str32len(text)+1); - const char32* tmp = text; - char32* aux = result; - for(;*tmp != U'\0';){ - if(*tmp == U'\\' && str32len(tmp) > 1) - tmp++; - *aux++ = *tmp++; +void Feature_decodeText(MelderString* me){ + int newLenght = my length; + for(int newPos = 0, oldPos = 0; newPos <= my length && oldPos <= my length; newPos++, oldPos++){ + if(my string [oldPos] == U'\\'){ + oldPos ++; + newLenght --; + } + my string [newPos] = my string [oldPos]; } - return result; + my length = newLenght; } /** - * Given a tierFeatures and a label, returns the feature (feature) with the same label. Null if the feature does not exist. + * Given a tierFeatures and a label, returns the Feature with the same label. Null if the feature does not exist. */ -feature* getExistentFeature(const tierFeatures* data, const char32* label){ +Feature* TierFeatures_getExistentFeature(const TierFeatures* data, const char32* label){ if(data == nullptr) return nullptr; - feature* current = data->firstFeature; + Feature* current = data->firstFeature; while(current != nullptr){ - if(str32equ(current->label, label)) + if(str32equ(current->label.string, label)) return current; current = current->nxtPtr; } @@ -323,42 +242,35 @@ feature* getExistentFeature(const tierFeatures* data, const char32* label){ } /** - * Adds a new feature with label and value to the given tierFeatures. + * Adds a new feature with label and value to the given TierFeatures. * If the feature already exists overwrites its value. */ -void addFeatureToTierFeatures(tierFeatures* data, const char32* label, const char32* value){ +void Feature_addFeatureToTierFeatures(TierFeatures* data, MelderString* label, MelderString* value){ if(data == nullptr) return; - char32* fLabel = addBackslashes(label); - char32* fValue = addBackslashes(value); + Feature_encodeText(label); + Feature_encodeText(value); - feature* ftr = getExistentFeature(data, fLabel); + Feature* ftr = TierFeatures_getExistentFeature(data, label->string); if(ftr != nullptr){ - delete ftr->value; - ftr->value = allocChar32(str32len(fValue)+1); - str32ncpy(ftr->value, fValue, str32len(fValue)); + MelderString_copy(&ftr->value, value->string); }else{ - getNextFeature(data)->label = allocChar32(str32len(fLabel)+1); - str32ncpy(getCurrentFeature(data)->label, fLabel, str32len(fLabel)); - getCurrentFeature(data)->value = allocChar32(str32len(fValue)+1); - str32ncpy(getCurrentFeature(data)->value, fValue, str32len(fValue)); + MelderString_copy(&TierFeatures_getNextFeature(data)->label, label->string); + MelderString_copy(&TierFeatures_getCurrentFeature(data)->value, value->string); } - delete fLabel; - delete fValue; } /** - * Deletes the given feature from the tierFeatures. + * Deletes the Feature with given label from the TierFeatures. */ -void deleteFeatureFromTierFeatures(tierFeatures* data, const char32* label){ +void Feature_deleteFeatureFromTierFeatures(TierFeatures* data, MelderString* label){ if(data == nullptr) return; - char32* fLabel = addBackslashes(label); - feature* ftr = getExistentFeature(data, fLabel); - delete fLabel; + Feature_encodeText(label); + Feature* ftr = TierFeatures_getExistentFeature(data, label->string); if(ftr == nullptr){ return; } - feature* tmp = data->firstFeature; + Feature* tmp = data->firstFeature; if(tmp->nxtPtr == nullptr){ data->firstFeature = nullptr; data->currentFeature = nullptr; @@ -380,22 +292,20 @@ void deleteFeatureFromTierFeatures(tierFeatures* data, const char32* label){ } /** - * Returns an integer representing the total length of the string representation of the whole tierFeatures. + * Returns an integer representing the total length of the text of the TierFeatures. */ -int countTierFeaturesLength(tierFeatures* data){ +int countTierFeaturesLength(TierFeatures* data){ if(data == nullptr) return 0; int totalLenght = 0; - if(data->text != nullptr) - totalLenght += str32len(data->text); + //if(data->text != nullptr) + totalLenght += data->headText.length; totalLenght += 4; - feature* tempPtr = data->firstFeature; + Feature* tempPtr = data->firstFeature; while(tempPtr != nullptr){ totalLenght += 1; - if(tempPtr->label != nullptr) - totalLenght += str32len(tempPtr->label); + totalLenght += tempPtr->label.length; totalLenght += 5; - if(tempPtr->value != nullptr) - totalLenght += str32len(tempPtr->value); + totalLenght += tempPtr->value.length; totalLenght += 1; tempPtr = tempPtr->nxtPtr; if(tempPtr != nullptr) @@ -406,53 +316,102 @@ int countTierFeaturesLength(tierFeatures* data){ } /** - * Return a new char32_t string representing the data held in the given tierFeatures. + * It sets in a result MelderString the text of the TierFeatures. */ -char32* generateTextFromTierFeatures(tierFeatures* data){ - if(data == nullptr) return nullptr; +void TierFeatures_generateText(TierFeatures* data, MelderString * result){ + if(data == nullptr) return; int totalLenght = countTierFeaturesLength(data); - if(totalLenght <= 0) return nullptr; + if(totalLenght <= 0) return; - char32* result = allocChar32(totalLenght); - if(data->text != nullptr) - str32append(result, data->text, str32len(result)); + if(data->headText.bufferSize > 0) + MelderString_append(result, data->headText.string); if(data->firstFeature != nullptr){ - str32append(result, U"@{@ ", str32len(result)); - feature* tempPtr = data->firstFeature; + MelderString_append(result, U"@{@ "); + Feature* tempPtr = data->firstFeature; while(tempPtr != nullptr){ - str32append(result, U"\"", str32len(result)); - if(tempPtr->label != nullptr) - str32append(result, tempPtr->label, str32len(result)); - str32append(result, U"\" = \"", str32len(result)); - if(tempPtr->value != nullptr) - str32append(result, tempPtr->value, str32len(result)); - str32append(result, U"\"", str32len(result)); + MelderString_append(result, U"\""); + if(tempPtr->label.bufferSize > 0) + MelderString_append(result, tempPtr->label.string); + MelderString_append(result, U"\" = \""); + if(tempPtr->value.bufferSize > 0) + MelderString_append(result, tempPtr->value.string); + MelderString_append(result, U"\""); tempPtr = tempPtr->nxtPtr; if(tempPtr != nullptr) - str32append(result, U", ", str32len(result)); + MelderString_append(result, U", "); } - str32append(result, U" @}@", str32len(result)); + MelderString_append(result, U" @}@"); } - str32append(result, U"\0", str32len(result)); - return result; + MelderString_append(result, U"\0"); } /** - * Returns a new char32_t string consisting of the content within given text plus a new feature with the given label and value. + * Sets in result MelderString the given text plus a new feature with the given label and value. * If feature already exists it is overwritten with given value. */ -char32* addFeatureToText(const char32* text, const char32* label, const char32* value){ - tierFeatures* res = extractTierFeatures(text); - addFeatureToTierFeatures(res, label, value); - return generateTextFromTierFeatures(res); +void Feature_addFeatureToText(const char32* text, MelderString* label, MelderString* value, MelderString* result){ + TierFeatures* features = TierFeatures_extractFromText(text); + Feature_addFeatureToTierFeatures(features, label, value); + TierFeatures_generateText(features, result); } /** - * Changes the content in the text of TierFeatures for a copy of the given one. + * Sets in result MelderString the given text without the feature with the given label. */ -void replaceTierFeaturesText(tierFeatures* data, const char32* text){ +void Feature_deleteFeatureFromText(const char32* text, MelderString* label, MelderString* result){ + TierFeatures* features = TierFeatures_extractFromText(text); + Feature_deleteFeatureFromTierFeatures(features, label); + TierFeatures_generateText(features, result); +} + +/** + * Changes the content of headText in the TierFeatures for a copy of the given one. + */ +void TierFeatures_replaceHeadText(TierFeatures* data, const char32* text){ if(data == nullptr) return; - delete data->text; - data->text = allocChar32(str32len(text)+1); - str32ncpy(data->text, text, str32len(text)); + MelderString_ncopy(&data->headText, text, str32len(text)); +} + +/** + * Returns a pointer to the Feature in the given position. Melder error if feature does not exist. + */ +Feature* TierFeatures_getFeature(TierFeatures* data, int position){ + Feature* tmp = data->firstFeature; + int count = 0; + while(tmp != nullptr && count < position -1){ + count ++; + tmp = tmp->nxtPtr; + } + if(tmp == nullptr){ + Melder_throw (U"Feature does not exist."); + } +} + +/** + * Return the number of Features in a TierFeature. + */ +int TierFeatures_getNumberOfFeatures(TierFeatures* data){ + Feature* tmp = data->firstFeature; + int result = 0; + while(tmp != nullptr){ + result ++; + tmp = tmp->nxtPtr; + } + return result; } + +/** + * Sets in result MelderString a readable representation of the features in the TierFeatures. + */ +void TierFeatures_getFeaturesString(TierFeatures* data, MelderString* result){ + Feature* tmp = data->firstFeature; + while(tmp != nullptr){ + Feature_decodeText(&tmp->label); + Feature_decodeText(&tmp->value); + MelderString_append(result, tmp->label.string, U": ", tmp->value.string, U"\n"); + + tmp = tmp->nxtPtr; + } +} + + diff --git a/fon/Feature.h b/fon/Feature.h index 76bce1730..f0ec98d6b 100644 --- a/fon/Feature.h +++ b/fon/Feature.h @@ -25,59 +25,52 @@ #include "Preferences.h" -struct feature{ - char32* label; - char32* value; - feature* nxtPtr; - feature() +struct Feature{ + autoMelderString label; + autoMelderString value; + Feature* nxtPtr; + Feature() { - label=nullptr; - value=nullptr; nxtPtr=nullptr; } - ~feature(){ - delete label; - delete value; + ~Feature(){ } }; -struct tierFeatures{ - char32* text; - feature* firstFeature; - feature* currentFeature; - tierFeatures() +struct TierFeatures{ + autoMelderString headText; + Feature* firstFeature; + Feature* currentFeature; + TierFeatures() { - text=nullptr; firstFeature=nullptr; currentFeature=nullptr; } - ~tierFeatures(){ - delete text; - feature* tmp = firstFeature; + ~TierFeatures(){ + Feature* tmp = firstFeature; while(tmp != nullptr){ - feature* toDelete = tmp; + Feature* toDelete = tmp; tmp = tmp->nxtPtr; delete toDelete; } } }; -/*---char32 UTILITIES---*/ -char32* trim(const char32 *text); -bool str32IsEmpty(const char32 *text); -char32* str32cat(char32 *source1, const char32 *source2); -/*---Features treatment---*/ -char32* addBackslashes(const char32* text); -char32* removeBackslashes(const char32* text); -tierFeatures* extractTierFeatures(const char32* text); -char32* addFeatureToText(const char32* text, const char32* label, const char32* value); -feature* getCurrentFeature(tierFeatures* data); -feature* getNextFeature(tierFeatures* data); -feature* getExistentFeature(const tierFeatures* data, const char32* label); -void deleteFeatureFromTierFeatures(tierFeatures* data, const char32* label); -char32* generateTextFromTierFeatures(tierFeatures* data); -void replaceTierFeaturesText(tierFeatures* data, const char32* text); +void Feature_encodeText(MelderString *me); +void Feature_decodeText(MelderString *me); +void Feature_addFeatureToText(const char32* text, MelderString* label, MelderString* value, MelderString* result); +void Feature_deleteFeatureFromText(const char32* text, MelderString* label, MelderString* result); + +TierFeatures* TierFeatures_extractFromText(const char32* text); +Feature* TierFeatures_getCurrentFeature(TierFeatures* data); +Feature* TierFeatures_getNextFeature(TierFeatures* data); +Feature* TierFeatures_getExistentFeature(const TierFeatures* data, const char32* label); +void TierFeatures_generateText(TierFeatures* data, MelderString * result); +void TierFeatures_replaceHeadText(TierFeatures* data, const char32* text); +Feature* TierFeatures_getFeature(TierFeatures* data, int position); +int TierFeatures_getNumberOfFeatures(TierFeatures* data); +void TierFeatures_getFeaturesString(TierFeatures* data, MelderString* result); /* End of file Feature.h */ #endif diff --git a/fon/TextGrid.cpp b/fon/TextGrid.cpp index d49c7d474..46f18e276 100644 --- a/fon/TextGrid.cpp +++ b/fon/TextGrid.cpp @@ -1223,12 +1223,12 @@ void TextGrid_setIntervalHeadText (TextGrid me, int tierNumber, long intervalNum if (intervalNumber < 1 || intervalNumber > intervalTier -> intervals.size) Melder_throw (U"Interval ", intervalNumber, U" does not exist on tier ", tierNumber, U"."); TextInterval interval = intervalTier -> intervals.at [intervalNumber]; - tierFeatures* result = extractTierFeatures(interval->text); - replaceTierFeaturesText(result, text); - char32* finalText = generateTextFromTierFeatures(result); - TextInterval_setText (interval, finalText); - delete result; - delete finalText; + TierFeatures* features = TierFeatures_extractFromText(interval->text); + TierFeatures_replaceHeadText(features, text); + autoMelderString result; + TierFeatures_generateText(features, &result); + TextInterval_setText (interval, result.string); + delete features; } catch (MelderError) { Melder_throw (me, U": interval head text not set."); } @@ -1284,12 +1284,12 @@ void TextGrid_setPointHeadText (TextGrid me, int tierNumber, long pointNumber, c if (pointNumber < 1 || pointNumber > textTier -> points.size) Melder_throw (U"Point ", pointNumber, U" does not exist on tier ", tierNumber, U"."); TextPoint point = textTier -> points.at [pointNumber]; - tierFeatures* result = extractTierFeatures(point->mark); - replaceTierFeaturesText(result, text); - char32* finalText = generateTextFromTierFeatures(result); - TextPoint_setText (point, finalText); - delete result; - delete finalText; + TierFeatures* features = TierFeatures_extractFromText(point->mark); + TierFeatures_replaceHeadText(features, text); + autoMelderString result; + TierFeatures_generateText(features, &result); + TextPoint_setText (point, result.string); + delete features; } catch (MelderError) { Melder_throw (me, U": point head text not set."); } diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp index cae010967..c2e7a95aa 100644 --- a/fon/TextGridEditor.cpp +++ b/fon/TextGridEditor.cpp @@ -668,50 +668,54 @@ static void menu_cb_InsertFeature (TextGridEditor me, EDITOR_ARGS_FORM) { EDITOR_DO TextGrid grid = (TextGrid) my data; checkTierSelection (me, LABEL_INSERT_DATA); + if (my selectedTier) { IntervalTier intervalTier; TextTier textTier; _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); Editor_save (me, LABEL_INSERT_DATA); + + MelderString label { 0 }; + MelderString value { 0 }; + MelderString_copy(&label, GET_STRING (U"Label")); + MelderString_copy(&value, GET_STRING (U"Value")); + + if(MelderString_isEmptyAfterTrim(&label) || MelderString_isEmptyAfterTrim(&value)){ + Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); + } + if(intervalTier != nullptr){ long selectedInterval = getSelectedInterval (me); if (selectedInterval) { - if(str32IsEmpty(GET_STRING (U"Label")) || str32IsEmpty(GET_STRING (U"Value"))){ - Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); - } TextInterval interval = intervalTier -> intervals.at [selectedInterval]; - char32* tL = trim(GET_STRING (U"Label")); - char32* tV = trim(GET_STRING (U"Value")); - char32* result = addFeatureToText(interval->text, tL, tV); - delete tL; - delete tV; - TextInterval_setText (interval, result); - delete result; + + autoMelderString newText; + Feature_addFeatureToText(interval->text, &label, &value, &newText); + TextInterval_setText (interval, newText.string); FunctionEditor_updateText (me); FunctionEditor_redraw (me); Editor_broadcastDataChanged (me); + + }else{ + Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); } } else { long selectedPoint = getSelectedPoint (me); if (selectedPoint) { TextPoint point = textTier -> points.at [selectedPoint]; - if (point -> mark) { - char32* tL = trim(GET_STRING (U"Label")); - char32* tV = trim(GET_STRING (U"Value")); - char32* result = addFeatureToText(point -> mark, tL, tV); - delete tL; - delete tV; - TextPoint_setText (point, result); - delete result; - FunctionEditor_updateText (me); - FunctionEditor_redraw (me); - Editor_broadcastDataChanged (me); - } + + autoMelderString newText; + Feature_addFeatureToText(point -> mark, &label, &value, &newText); + TextPoint_setText (point, newText.string); + FunctionEditor_updateText (me); + FunctionEditor_redraw (me); + Editor_broadcastDataChanged (me); } else{ Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); } } + } EDITOR_END } @@ -728,43 +732,27 @@ static void menu_cb_ShowFeatures (TextGridEditor me, EDITOR_ARGS_FORM) { long selectedInterval = getSelectedInterval (me); if (selectedInterval) { TextInterval interval = intervalTier -> intervals.at [selectedInterval]; - tierFeatures* result = extractTierFeatures(interval->text); + TierFeatures* features = TierFeatures_extractFromText(interval->text); + autoMelderString output; + TierFeatures_getFeaturesString(features, &output); Melder_clearInfo (); MelderInfo_open (); - feature* tmp = result->firstFeature; - while(tmp != nullptr){ - char32* nLabel = removeBackslashes(tmp->label); - char32* nValue = removeBackslashes(tmp->value); - char32 * cat = str32cat(nLabel, U": "); - MelderInfo_writeLine (cat, nValue); - delete cat; - delete nLabel; - delete nValue; - tmp = tmp->nxtPtr; - } + MelderInfo_writeLine (output.string); MelderInfo_close (); - delete result; + delete features; } } else { long selectedPoint = getSelectedPoint (me); if (selectedPoint) { TextPoint point = textTier -> points.at [selectedPoint]; - tierFeatures* result = extractTierFeatures(point->mark); + TierFeatures* features = TierFeatures_extractFromText(point->mark); + autoMelderString output; + TierFeatures_getFeaturesString(features, &output); Melder_clearInfo (); MelderInfo_open (); - feature* tmp = result->firstFeature; - while(tmp != nullptr){ - char32* nLabel = removeBackslashes(tmp->label); - char32* nValue = removeBackslashes(tmp->value); - char32 * cat = str32cat(nLabel, U": "); - MelderInfo_writeLine (cat, nValue); - delete cat; - delete nLabel; - delete nValue; - tmp = tmp->nxtPtr; - } + MelderInfo_writeLine (output.string); MelderInfo_close (); - delete result; + delete features; } else{ Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); @@ -786,43 +774,34 @@ static void menu_cb_DeleteFeature (TextGridEditor me, EDITOR_ARGS_FORM) { TextTier textTier; _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); Editor_save (me, LABEL_DELETE_DATA); + + MelderString label { 0 }; + MelderString_copy(&label, GET_STRING (U"Label")); + if(MelderString_isEmptyAfterTrim(&label)){ + Melder_throw (U"Label cannot be empty. Please fill the field."); + } + if(intervalTier != nullptr){ long selectedInterval = getSelectedInterval (me); if (selectedInterval) { - if(str32IsEmpty(GET_STRING (U"Label"))){ - Melder_throw (U"Label cannot be empty. Please fill the field."); - } TextInterval interval = intervalTier -> intervals.at [selectedInterval]; - char32* tL = trim(GET_STRING (U"Label")); - tierFeatures* tierData = extractTierFeatures(interval->text); - deleteFeatureFromTierFeatures(tierData, tL); - char32 * newText = generateTextFromTierFeatures(tierData); - TextInterval_setText (interval, newText); + autoMelderString newText; + Feature_deleteFeatureFromText(interval->text, &label, &newText); + TextInterval_setText (interval, newText.string); FunctionEditor_updateText (me); FunctionEditor_redraw (me); Editor_broadcastDataChanged (me); - delete tierData; - delete newText; - delete tL; } }else { long selectedPoint = getSelectedPoint (me); if (selectedPoint) { - if(str32IsEmpty(GET_STRING (U"Label"))){ - Melder_throw (U"Label cannot be empty. Please fill the field."); - } TextPoint point = textTier -> points.at [selectedPoint]; - char32* tL = trim(GET_STRING (U"Label")); - tierFeatures* tierData = extractTierFeatures(point->mark); - deleteFeatureFromTierFeatures(tierData, tL); - char32 * newText = generateTextFromTierFeatures(tierData); - TextPoint_setText (point, newText); + autoMelderString newText; + Feature_deleteFeatureFromText(point->mark, &label, &newText); + TextPoint_setText (point, newText.string); FunctionEditor_updateText (me); FunctionEditor_redraw (me); Editor_broadcastDataChanged (me); - delete tierData; - delete newText; - delete tL; } else{ Melder_throw (U"Selected tier is not a valid tier. Please select an interval or a point in a valid tier by clicking it."); @@ -844,44 +823,40 @@ static void menu_cb_GetFeature (TextGridEditor me, EDITOR_ARGS_FORM) { IntervalTier intervalTier; TextTier textTier; _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); + + MelderString label { 0 }; + MelderString_copy(&label, GET_STRING (U"Label")); + MelderString_trim(&label); + Feature_encodeText(&label); + if(intervalTier != nullptr){ long selectedInterval = getSelectedInterval (me); if (selectedInterval) { TextInterval interval = intervalTier -> intervals.at [selectedInterval]; - tierFeatures* result = extractTierFeatures(interval->text); - char32* tL = trim(GET_STRING (U"Label")); - char32* fLabel = addBackslashes(tL); - feature* ann = getExistentFeature(result, fLabel); + TierFeatures* result = TierFeatures_extractFromText(interval->text); + Feature* ann = TierFeatures_getExistentFeature(result, label.string); if(ann != nullptr){ Melder_clearInfo (); MelderInfo_open (); - char32* nValue = removeBackslashes(ann->value); - MelderInfo_writeLine (nValue); - delete nValue; + Feature_decodeText(&ann->value); + MelderInfo_writeLine (ann->value.string); MelderInfo_close (); } - delete tL; - delete fLabel; delete result; } } else { long selectedPoint = getSelectedPoint (me); if (selectedPoint) { TextPoint point = textTier -> points.at [selectedPoint]; - tierFeatures* result = extractTierFeatures(point->mark); - char32* tL = trim(GET_STRING (U"Label")); - char32* fLabel = addBackslashes(tL); - feature* ann = getExistentFeature(result, fLabel); + TierFeatures* result = TierFeatures_extractFromText(point->mark); + Feature* ann = TierFeatures_getExistentFeature(result, label.string); if(ann != nullptr){ Melder_clearInfo (); MelderInfo_open (); - char32* nValue = removeBackslashes(ann->value); - MelderInfo_writeLine (nValue); - delete nValue; + Feature_decodeText(&ann->value); + MelderInfo_writeLine (ann->value.string); MelderInfo_close (); } - delete tL; - delete fLabel; delete result; } else{ @@ -1513,14 +1488,6 @@ static void gui_text_cb_changed (TextGridEditor me, GuiTextEvent /* event */) { TextInterval interval = intervalTier -> intervals.at [selectedInterval]; //Melder_casual (U"gui_text_cb_change 3 in editor ", Melder_pointer (me)); TextInterval_setText (interval, text); - /*tierFeatures* tierTextData = extractTierFeatures(interval->text); - delete tierTextData->text; - tierTextData->text = allocChar32(str32len(text)+1); - str32cpy(tierTextData->text, text); - char32 * fullText = generateTextFromTierFeatures(tierTextData); - TextInterval_setText (interval, fullText); - delete fullText;*/ - //Melder_casual (U"gui_text_cb_change 4 in editor ", Melder_pointer (me)); FunctionEditor_redraw (me); //Melder_casual (U"gui_text_cb_change 5 in editor ", Melder_pointer (me)); @@ -1534,14 +1501,6 @@ static void gui_text_cb_changed (TextGridEditor me, GuiTextEvent /* event */) { Melder_free (point -> mark); if (str32spn (text, U" \n\t") != str32len (text)) // any visible characters? point -> mark = Melder_dup_f (text); - /*tierFeatures* tierTextData = extractTierFeatures(point->mark); - delete tierTextData->text; - tierTextData->text = allocChar32(str32len(text)+1); - str32cpy(tierTextData->text, text); - char32 * fullText = generateTextFromTierFeatures(tierTextData); - TextPoint_setText (point, fullText); - delete fullText;*/ - FunctionEditor_redraw (me); Editor_broadcastDataChanged (me); } @@ -1679,8 +1638,8 @@ static void do_drawIntervalTier (TextGridEditor me, IntervalTier tier, int itier double t1 = my startWindow > tmin ? my startWindow : tmin; double t2 = my endWindow < tmax ? my endWindow : tmax; Graphics_setColour (my graphics.get(), intervalIsSelected ? Graphics_RED : Graphics_BLACK); - tierFeatures* ttd = extractTierFeatures(interval -> text); - Graphics_textRect (my graphics.get(), t1, t2, 0.0, 1.0, ttd->text); + TierFeatures* ttd = TierFeatures_extractFromText(interval -> text); + Graphics_textRect (my graphics.get(), t1, t2, 0.0, 1.0, ttd->headText.string); delete ttd; Graphics_setColour (my graphics.get(), Graphics_BLACK); } @@ -1754,8 +1713,8 @@ static void do_drawTextTier (TextGridEditor me, TextTier tier, int itier) { } Graphics_setColour (my graphics.get(), pointIsSelected ? Graphics_RED : Graphics_BLUE); if (point -> mark){ - tierFeatures* ttd = extractTierFeatures(point -> mark); - Graphics_text (my graphics.get(), t, 0.5, ttd->text); + TierFeatures* ttd = TierFeatures_extractFromText(point -> mark); + Graphics_text (my graphics.get(), t, 0.5, ttd->headText.string); delete ttd; } } @@ -2419,7 +2378,6 @@ void structTextGridEditor :: v_play (double tmin, double tmax) { void structTextGridEditor :: v_updateText () { TextGrid grid = (TextGrid) our data; const char32 *newText = U""; - //tierTextData* tierTextData = nullptr; trace (U"selected tier ", our selectedTier); if (our selectedTier) { IntervalTier intervalTier; @@ -2430,8 +2388,6 @@ void structTextGridEditor :: v_updateText () { if (iinterval) { TextInterval interval = intervalTier -> intervals.at [iinterval]; if (interval -> text) { - /*tierTextData = extractTierTextData(interval -> text); - newText = tierTextData -> text;*/ newText = interval -> text; } } @@ -2440,8 +2396,6 @@ void structTextGridEditor :: v_updateText () { if (ipoint) { TextPoint point = textTier -> points.at [ipoint]; if (point -> mark) { - /*tierTextData = extractTierTextData(point -> mark); - newText = tierTextData -> text;*/ newText = point -> mark; } } @@ -2456,7 +2410,6 @@ void structTextGridEditor :: v_updateText () { GuiText_setSelection (text, cursor, cursor); our suppressRedraw = false; } - //delete tierTextData; } void structTextGridEditor :: v_prefs_addFields (EditorCommand cmd) { diff --git a/fon/praat_TextGrid_init.cpp b/fon/praat_TextGrid_init.cpp index fae919daa..05e924179 100644 --- a/fon/praat_TextGrid_init.cpp +++ b/fon/praat_TextGrid_init.cpp @@ -1065,16 +1065,19 @@ FORM (MODIFY_TextGrid_insertFeatureToInterval, U"TextGrid: Insert feature to int DO MODIFY_EACH (TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - if(str32IsEmpty(labelText) || str32IsEmpty(valueText)){ + + MelderString label { 0 }; + MelderString value { 0 }; + MelderString_copy(&label, labelText); + MelderString_copy(&value, valueText); + + if(MelderString_isEmptyAfterTrim(&label) || MelderString_isEmptyAfterTrim(&value)){ Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); } - char32* tL = trim(labelText); - char32* tV = trim(valueText); - char32* result = addFeatureToText(interval->text, tL, tV); - delete tL; - delete tV; - TextInterval_setText(interval, result); - delete result; + + autoMelderString newText; + Feature_addFeatureToText(interval->text, &label, &value, &newText); + TextInterval_setText(interval, newText.string); MODIFY_EACH_END } @@ -1087,17 +1090,15 @@ DO MODIFY_EACH (TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - if(str32IsEmpty(labelText)){ + MelderString label { 0 }; + MelderString_copy(&label, labelText); + + if(MelderString_isEmptyAfterTrim(&label)){ Melder_throw (U"Label cannot be empty. Please fill the field."); } - char32* tL = trim(labelText); - tierFeatures* tierData = extractTierFeatures(interval->text); - deleteFeatureFromTierFeatures(tierData, tL); - char32 * newText = generateTextFromTierFeatures(tierData); - TextInterval_setText (interval, newText); - delete tierData; - delete newText; - delete tL; + autoMelderString newText; + Feature_deleteFeatureFromText(interval->text, &label, &newText); + TextInterval_setText (interval, newText.string); MODIFY_EACH_END } @@ -1110,31 +1111,25 @@ DO STRING_ONE (TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - if(str32IsEmpty(labelText)){ + MelderString label { 0 }; + MelderString_copy(&label, labelText); + + if(MelderString_isEmptyAfterTrim(&label)){ Melder_throw (U"Label cannot be empty. Please fill the field."); } - tierFeatures* features = extractTierFeatures(interval->text); - char32* tL = trim(labelText); - char32* fLabel = addBackslashes(tL); - feature* ann = getExistentFeature(features, fLabel); - char32* text = nullptr; - if(ann != nullptr){ - text = removeBackslashes(ann->value); - } - static char32* result; - if (result != nullptr){ - delete(result); - result = nullptr; - } - if(text != nullptr){ - result = (char32*) malloc ((size_t) (str32len(text)+1) * sizeof (char32)); - str32cpy(result, text); - delete text; + Feature_encodeText(&label); + + TierFeatures* features = TierFeatures_extractFromText(interval->text); + Feature* ann = TierFeatures_getExistentFeature(features, label.string); + + autoMelderString value; + if(ann != nullptr){ + MelderString_copy(&value, ann->value.string); + Feature_decodeText(&value); } + const char32* result = value.string; - delete tL; - delete fLabel; delete features; STRING_ONE_END } @@ -1146,39 +1141,10 @@ FORM (STRING_TextGrid_showFeaturesInInterval, U"TextGrid: Show features in inter DO STRING_ONE (TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - tierFeatures* features = extractTierFeatures(interval->text); - feature* tmp = features->firstFeature; - static char32* result; - if (result != nullptr) { - delete(result); - result = nullptr; - } - - while(tmp != nullptr){ - char32* nLabel = removeBackslashes(tmp->label); - char32* nValue = removeBackslashes(tmp->value); - char32* cat = str32cat(nLabel, U": "); - char32* semiline = str32cat(cat, nValue); - char32* line = str32cat(semiline, U"\n"); - - if(result != nullptr){ - char32* full = str32cat(result, line); - delete(result); - result = (char32*) malloc ((size_t) (str32len(full)+1) * sizeof (char32)); - str32cpy(result, full); - delete full; - }else{ - result = (char32*) malloc ((size_t) (str32len(line)+1) * sizeof (char32)); - str32cpy(result, line); - } - - delete line; - delete semiline; - delete cat; - delete nValue; - delete nLabel; - tmp = tmp->nxtPtr; - } + TierFeatures* features = TierFeatures_extractFromText(interval->text); + autoMelderString output; + TierFeatures_getFeaturesString(features, &output); + const char32* result = output.string; delete features; STRING_ONE_END } @@ -1190,13 +1156,8 @@ FORM (INTEGER_TextGrid_numberFeaturesInInterval, U"TextGrid: Get number of featu DO INTEGER_ONE(TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - tierFeatures* features = extractTierFeatures(interval->text); - feature* tmp = features->firstFeature; - int result = 0; - while(tmp != nullptr){ - result ++; - tmp = tmp->nxtPtr; - } + TierFeatures* features = TierFeatures_extractFromText(interval->text); + int result = TierFeatures_getNumberOfFeatures(features); delete features; INTEGER_ONE_END(U"") } @@ -1209,22 +1170,13 @@ FORM (STRING_TextGrid_labelFeaturesInInterval, U"TextGrid: Get label of feature DO STRING_ONE(TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - tierFeatures* features = extractTierFeatures(interval->text); - feature* tmp = features->firstFeature; - int count = 0; - while(tmp != nullptr && count < featureNumber -1){ - count ++; - tmp = tmp->nxtPtr; - } - if(tmp == nullptr){ - Melder_throw (U"Feature does not exist."); - } - char32* text = removeBackslashes(tmp->label); - static char32* result; - if (result != nullptr) delete(result); - result = (char32*) malloc ((size_t) (str32len(text)+1) * sizeof (char32)); - str32cpy(result, text); - delete text; + TierFeatures* features = TierFeatures_extractFromText(interval->text); + Feature* feature = TierFeatures_getFeature(features, featureNumber); + autoMelderString label; + MelderString_copy(&label, feature->label.string); + Feature_decodeText(&label); + const char32* result = label.string; + delete features; STRING_ONE_END } @@ -1236,11 +1188,10 @@ FORM (STRING_TextGrid_headOfInterval, U"TextGrid: Get head of interval", nullptr DO STRING_ONE(TextGrid) TextInterval interval = pr_TextGrid_peekInterval (me, tierNumber, intervalNumber); - tierFeatures* features = extractTierFeatures(interval->text); - static char32* result; - if (result != nullptr) delete(result); - result = (char32*) malloc ((size_t) (str32len(features->text)+1) * sizeof (char32)); - str32cpy(result, features->text); + TierFeatures* features = TierFeatures_extractFromText(interval->text); + autoMelderString head; + MelderString_copy(&head, features->headText.string); + const char32* result = head.string; delete features; STRING_ONE_END } @@ -1278,12 +1229,12 @@ FORM (STRING_TextGrid_headOfPoint, U"TextGrid: Get head of point", nullptr) { DO STRING_ONE(TextGrid) TextPoint point = pr_TextGrid_peekPoint (me, tierNumber, pointNumber); - tierFeatures* features = extractTierFeatures(point->mark); - static char32* result; - if (result != nullptr) delete(result); - result = (char32*) malloc ((size_t) (str32len(features->text)+1) * sizeof (char32)); - str32cpy(result, features->text); + TierFeatures* features = TierFeatures_extractFromText(point->mark); + autoMelderString head; + MelderString_copy(&head, features->headText.string); + const char32* result = head.string; delete features; + STRING_ONE_END } @@ -1294,13 +1245,8 @@ FORM (INTEGER_TextGrid_numberFeaturesInPoint, U"TextGrid: Get number of features DO INTEGER_ONE(TextGrid) TextPoint point = pr_TextGrid_peekPoint (me, tierNumber, pointNumber); - tierFeatures* features = extractTierFeatures(point->mark); - feature* tmp = features->firstFeature; - int result = 0; - while(tmp != nullptr){ - result ++; - tmp = tmp->nxtPtr; - } + TierFeatures* features = TierFeatures_extractFromText(point->mark); + int result = TierFeatures_getNumberOfFeatures(features); delete features; INTEGER_ONE_END(U"") } @@ -1313,24 +1259,12 @@ FORM (STRING_TextGrid_labelFeaturesInPoint, U"TextGrid: Get label of feature in DO STRING_ONE(TextGrid) TextPoint point = pr_TextGrid_peekPoint (me, tierNumber, pointNumber); - tierFeatures* features = extractTierFeatures(point->mark); - feature* tmp = features->firstFeature; - int count = 0; - while(tmp != nullptr && count < featureNumber -1){ - count ++; - tmp = tmp->nxtPtr; - } - if(tmp == nullptr){ - Melder_throw (U"Feature does not exist."); - } - Melder_clearInfo (); - - char32* text = removeBackslashes(tmp->label); - static char32* result; - if (result != nullptr) delete(result); - result = (char32*) malloc ((size_t) (str32len(text)+1) * sizeof (char32)); - str32cpy(result, text); - delete text; + TierFeatures* features = TierFeatures_extractFromText(point->mark); + Feature* feature = TierFeatures_getFeature(features, featureNumber); + autoMelderString label; + MelderString_copy(&label, feature->label.string); + Feature_decodeText(&label); + const char32* result = label.string; delete features; STRING_ONE_END @@ -1344,17 +1278,18 @@ FORM (MODIFY_TextGrid_insertFeatureToPoint, U"TextGrid: Insert feature to point" OK DO MODIFY_EACH (TextGrid) - TextPoint point = pr_TextGrid_peekPoint(me, tierNumber, pointNumber); - if(str32IsEmpty(labelText) || str32IsEmpty(valueText)){ + TextPoint point = pr_TextGrid_peekPoint(me, tierNumber, pointNumber); + MelderString label { 0 }; + MelderString value { 0 }; + MelderString_copy(&label, labelText); + MelderString_copy(&value, valueText); + + if(MelderString_isEmptyAfterTrim(&label) || MelderString_isEmptyAfterTrim(&value)){ Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); } - char32* tL = trim(labelText); - char32* tV = trim(valueText); - char32* result = addFeatureToText(point -> mark, tL, tV); - delete tL; - delete tV; - TextPoint_setText(point, result); - delete result; + autoMelderString newText; + Feature_addFeatureToText(point->mark, &label, &value, &newText); + TextPoint_setText(point, newText.string); MODIFY_EACH_END } @@ -1366,18 +1301,15 @@ FORM (MODIFY_TextGrid_deleteFeatureFromPoint, U"TextGrid: Remove feature from po DO MODIFY_EACH (TextGrid) TextPoint point = pr_TextGrid_peekPoint(me, tierNumber, pointNumber); + MelderString label { 0 }; + MelderString_copy(&label, labelText); - if(str32IsEmpty(labelText)){ + if(MelderString_isEmptyAfterTrim(&label)){ Melder_throw (U"Label cannot be empty. Please fill the field."); } - char32* tL = trim(labelText); - tierFeatures* tierData = extractTierFeatures(point->mark); - deleteFeatureFromTierFeatures(tierData, tL); - char32 * newText = generateTextFromTierFeatures(tierData); - TextPoint_setText (point, newText); - delete tierData; - delete newText; - delete tL; + autoMelderString newText; + Feature_deleteFeatureFromText(point->mark, &label, &newText); + TextPoint_setText (point, newText.string); MODIFY_EACH_END } @@ -1389,32 +1321,24 @@ FORM (STRING_TextGrid_getFeatureFromPoint, U"TextGrid: Get feature from point", DO STRING_ONE(TextGrid) TextPoint point = pr_TextGrid_peekPoint(me, tierNumber, pointNumber); + MelderString label { 0 }; + MelderString_copy(&label, labelText); - if(str32IsEmpty(labelText)){ + if(MelderString_isEmptyAfterTrim(&label)){ Melder_throw (U"Label cannot be empty. Please fill the field."); } - tierFeatures* features = extractTierFeatures(point->mark); - char32* tL = trim(labelText); - char32* fLabel = addBackslashes(tL); - feature* ann = getExistentFeature(features, fLabel); - char32* text = nullptr; - if(ann != nullptr){ - text = removeBackslashes(ann->value); - } + Feature_encodeText(&label); - static char32* result; - if (result != nullptr){ - delete(result); - result = nullptr; - } - if(text != nullptr){ - result = (char32*) malloc ((size_t) (str32len(text)+1) * sizeof (char32)); - str32cpy(result, text); - delete text; + TierFeatures* features = TierFeatures_extractFromText(point->mark); + Feature* ann = TierFeatures_getExistentFeature(features, label.string); + + autoMelderString value; + if(ann != nullptr){ + MelderString_copy(&value, ann->value.string); + Feature_decodeText(&value); } + const char32* result = value.string; - delete tL; - delete fLabel; delete features; STRING_ONE_END } @@ -1426,38 +1350,10 @@ FORM (STRING_TextGrid_showFeaturesInPoint, U"TextGrid: Show features in point", DO STRING_ONE(TextGrid) TextPoint point = pr_TextGrid_peekPoint(me, tierNumber, pointNumber); - tierFeatures* features = extractTierFeatures(point->mark); - feature* tmp = features->firstFeature; - static char32* result; - if (result != nullptr){ - delete(result); - result = nullptr; - } - while(tmp != nullptr){ - char32* nLabel = removeBackslashes(tmp->label); - char32* nValue = removeBackslashes(tmp->value); - char32* cat = str32cat(nLabel, U": "); - char32* semiline = str32cat(cat, nValue); - char32* line = str32cat(semiline, U"\n"); - - if(result != nullptr){ - char32* full = str32cat(result, line); - delete(result); - result = (char32*) malloc ((size_t) (str32len(full)+1) * sizeof (char32)); - str32cpy(result, full); - delete full; - }else{ - result = (char32*) malloc ((size_t) (str32len(line)+1) * sizeof (char32)); - str32cpy(result, line); - } - - delete line; - delete semiline; - delete cat; - delete nValue; - delete nLabel; - tmp = tmp->nxtPtr; - } + TierFeatures* features = TierFeatures_extractFromText(point->mark); + autoMelderString output; + TierFeatures_getFeaturesString(features, &output); + const char32* result = output.string; delete features; STRING_ONE_END } diff --git a/sys/melder.h b/sys/melder.h index d050ce4ba..47eca1b74 100644 --- a/sys/melder.h +++ b/sys/melder.h @@ -723,6 +723,9 @@ void MelderString_copy (MelderString *me, Melder_14_OR_15_ARGS); void MelderString_copy (MelderString *me, Melder_16_TO_19_ARGS); void MelderString_ncopy (MelderString *me, const char32 *source, int64 n); +void MelderString_trim(MelderString *me); +bool MelderString_isEmptyAfterTrim(MelderString *me); + inline static void MelderString_append (MelderString *me, Melder_1_ARG) { const char32 *s1 = arg1._arg ? arg1._arg : U""; int64 length1 = str32len (s1); int64 sizeNeeded = me -> length + length1 + 1; diff --git a/sys/melder_strings.cpp b/sys/melder_strings.cpp index f028aafd9..6aa945420 100644 --- a/sys/melder_strings.cpp +++ b/sys/melder_strings.cpp @@ -428,6 +428,30 @@ void MelderString_ncopy (MelderString *me, const char32 *source, int64 n) { my length = length; } +void MelderString_trim(MelderString *me){ + if(my bufferSize == 0) return; + const char32 * forwardPtr = my string; + int initialBlanks = 0; + while(*forwardPtr != U'\0' && *forwardPtr == U' '){ + initialBlanks++; + forwardPtr++; + } + + MelderString_copy(me, forwardPtr); + //Melder_free(forwardPtr); + + char32 * backwardPtr = my string + my length -1; + while(backwardPtr+1 != my string && *backwardPtr == U' '){ + *backwardPtr-- = U'\0'; + } + //Melder_free(backwardPtr); +} + +bool MelderString_isEmptyAfterTrim(MelderString *me){ + MelderString_trim(me); + return my length == 0; +} + /*void MelderString_append (MelderString *me, Melder_1_ARG) { const char32 *s1 = arg1._arg ? arg1._arg : U""; int64 length1 = _str32len (s1); int64 sizeNeeded = my length + length1 + 1; From 03be61df9a11b54f58603a5ac440778620ca94a4 Mon Sep 17 00:00:00 2001 From: Ivan Date: Wed, 15 Nov 2017 16:22:40 +0100 Subject: [PATCH 4/5] Git ignore updated --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 42fcc81ce..fa2ed592b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,11 @@ makefile.defs praat Praat Praat.exe + +\.autotools + +\.project + +\.cproject + +\.settings/ From f884ce1984cce7bafda345ac1371ca66a4d63708 Mon Sep 17 00:00:00 2001 From: Ivan Date: Wed, 15 Nov 2017 17:53:36 +0100 Subject: [PATCH 5/5] Code changed to work properly with 6.0.36 version --- fon/TextGridEditor.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp index 3efdc8240..1563102ea 100644 --- a/fon/TextGridEditor.cpp +++ b/fon/TextGridEditor.cpp @@ -675,10 +675,10 @@ static void menu_cb_InsertFeature (TextGridEditor me, EDITOR_ARGS_FORM) { _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); Editor_save (me, LABEL_INSERT_DATA); - MelderString label { 0 }; - MelderString value { 0 }; - MelderString_copy(&label, GET_STRING (U"Label")); - MelderString_copy(&value, GET_STRING (U"Value")); + autoMelderString label; + autoMelderString value; + MelderString_copy(&label, labelVar); + MelderString_copy(&value, valueVar); if(MelderString_isEmptyAfterTrim(&label) || MelderString_isEmptyAfterTrim(&value)){ Melder_throw (U"Neither label nor value can be empty. Please fill the fields."); @@ -728,7 +728,6 @@ static void menu_cb_ShowFeatures (TextGridEditor me, EDITOR_ARGS_FORM) { TextTier textTier; _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); if(intervalTier != nullptr){ - //Editor_save (me, LABEL_INSERT_DATA); long selectedInterval = getSelectedInterval (me); if (selectedInterval) { TextInterval interval = intervalTier -> intervals.at [selectedInterval]; @@ -775,8 +774,8 @@ static void menu_cb_DeleteFeature (TextGridEditor me, EDITOR_ARGS_FORM) { _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); Editor_save (me, LABEL_DELETE_DATA); - MelderString label { 0 }; - MelderString_copy(&label, GET_STRING (U"Label")); + autoMelderString label; + MelderString_copy(&label, labelVar); if(MelderString_isEmptyAfterTrim(&label)){ Melder_throw (U"Label cannot be empty. Please fill the field."); } @@ -824,8 +823,8 @@ static void menu_cb_GetFeature (TextGridEditor me, EDITOR_ARGS_FORM) { TextTier textTier; _AnyTier_identifyClass (grid -> tiers->at [my selectedTier], & intervalTier, & textTier); - MelderString label { 0 }; - MelderString_copy(&label, GET_STRING (U"Label")); + autoMelderString label; + MelderString_copy(&label, labelVar); MelderString_trim(&label); Feature_encodeText(&label);