praatio.data_classes.klattgrid API documentation

# praatio.data_classes.klattgrid

KlattGrid and related classes.

KlattGrids can be used for synthesizing and manipulating speech

View Source

      1"""KlattGrid and related classes.
      2
      3KlattGrids can be used for synthesizing and manipulating speech
      4"""
      5
      6import io
      7
      8from typing import List, Optional, Dict, Callable, Union
      9
     10from praatio.data_classes import textgrid
     11from praatio.data_classes import textgrid_tier
     12from praatio.utilities import errors
     13from praatio.utilities import my_math
     14
     15
     16class _KlattBaseTier:
     17    def __init__(self, name: str):
     18        self.tierNameList: List[str] = []  # Preserves the order of the tiers
     19        self.tierDict: Dict[str, "_KlattBaseTier"] = {}
     20        self.name = name
     21        self.minTimestamp = None
     22        self.maxTimestamp = None
     23
     24    def __eq__(self, other):
     25        if not isinstance(other, _KlattBaseTier):
     26            return False
     27
     28        isEqual = True
     29        isEqual &= self.name == other.name
     30        isEqual &= self.minTimestamp == other.minTimestamp
     31        isEqual &= self.maxTimestamp == other.maxTimestamp
     32
     33        isEqual &= self.tierNameList == other.tierNameList
     34        if isEqual:
     35            for tierName in self.tierNameList:
     36                isEqual &= self.tierDict[tierName] == other.tierDict[tierName]
     37
     38        return isEqual
     39
     40    def addTier(self, tier, tierIndex=None) -> None:
     41
     42        if tierIndex is None:
     43            self.tierNameList.append(tier.name)
     44        else:
     45            self.tierNameList.insert(tierIndex, tier.name)
     46
     47        if tier.name in list(self.tierDict.keys()):
     48            raise errors.TierNameExistsError(
     49                f"Cannot add tier with name {tier.name} as it already exists in the Klattgrid"
     50            )
     51        self.tierDict[tier.name] = tier
     52
     53        minV = tier.minTimestamp
     54        if self.minTimestamp is None or (minV is not None and minV < self.minTimestamp):
     55            self.minTimestamp = minV
     56
     57        maxV = tier.maxTimestamp
     58        if self.maxTimestamp is None or (maxV is not None and maxV > self.maxTimestamp):
     59            self.maxTimestamp = maxV
     60
     61
     62class KlattContainerTier(_KlattBaseTier):
     63    """Contains a set of intermediate tiers"""
     64
     65    def getAsText(self):
     66        outputTxt = ""
     67        outputTxt += "%s? <exists>\n" % self.name
     68
     69        try:
     70            self.minTimestamp = toIntOrFloat(self.minTimestamp)
     71            outputTxt += "xmin = %s\nxmax = %s\n" % (
     72                my_math.numToStr(self.minTimestamp),
     73                my_math.numToStr(self.maxTimestamp),
     74            )
     75        except TypeError:
     76            pass
     77
     78        for name in self.tierNameList:
     79            outputTxt += self.tierDict[name].getAsText()
     80
     81        return outputTxt
     82
     83    def modifySubtiers(self, tierName: str, modFunc) -> None:
     84        """
     85        Modify values in every tier contained in the named intermediate tier
     86        """
     87        kit = self.tierDict[tierName]
     88        for name in kit.tierNameList:
     89            subpointTier = kit.tierDict[name]
     90            subpointTier.modifyValues(modFunc)
     91
     92
     93class KlattIntermediateTier(_KlattBaseTier):
     94    """
     95    Has many point tiers that are semantically related (e.g. formant tiers)
     96    """
     97
     98    def getAsText(self):
     99        outputTxt = ""
    100        headerTxt = "%s: size=%d\n" % (self.name, len(self.tierNameList))
    101
    102        for name in self.tierNameList:
    103            outputTxt += self.tierDict[name].getAsText()
    104
    105        outputTxt = headerTxt + outputTxt
    106
    107        return outputTxt
    108
    109
    110class KlattPointTier(textgrid_tier.TextgridTier):
    111    """
    112    A Klatt tier not contained within another tier
    113    """
    114
    115    def __init__(
    116        self,
    117        name: str,
    118        entries: List,
    119        minT: Optional[float] = None,
    120        maxT: Optional[float] = None,
    121    ):
    122
    123        entries = [(float(time), label) for time, label in entries]
    124
    125        # Determine the min and max timestamps
    126        timeList = [time for time, label in entries]
    127        if minT is not None:
    128            timeList.append(float(minT))
    129        if maxT is not None:
    130            timeList.append(float(maxT))
    131
    132        try:
    133            setMinT = min(timeList)
    134            setMaxT = max(timeList)
    135        except ValueError:
    136            raise errors.TimelessTextgridTierException()
    137
    138        super(KlattPointTier, self).__init__(name, entries, setMinT, setMaxT)
    139
    140    def crop(self):
    141        raise NotImplementedError
    142
    143    def dejitter(self):
    144        raise NotImplementedError
    145
    146    def deleteEntry(self, entry):
    147        raise NotImplementedError
    148
    149    def editTimestamps(self):
    150        raise NotImplementedError
    151
    152    def eraseRegion(self):
    153        raise NotImplementedError
    154
    155    def insertEntry(self):
    156        raise NotImplementedError
    157
    158    def insertSpace(self):
    159        raise NotImplementedError
    160
    161    @property
    162    def timestamps(self):
    163        raise NotImplementedError
    164
    165    def validate(self):
    166        raise NotImplementedError
    167
    168    def modifyValues(self, modFunc: Callable[[float], bool]) -> None:
    169        newEntries = [
    170            (timestamp, modFunc(float(value))) for timestamp, value in self.entries
    171        ]
    172
    173        self._entries = newEntries
    174
    175    def getAsText(self) -> str:
    176        outputList = []
    177        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    178        outputList.append("%s? <exists> " % self.name)
    179        outputList.append("xmin = %s" % my_math.numToStr(self.minTimestamp))
    180        outputList.append("xmax = %s" % my_math.numToStr(self.maxTimestamp))
    181
    182        if self.name not in ["phonation", "vocalTract", "coupling", "frication"]:
    183            outputList.append("points: size= %d" % len(self.entries))
    184
    185        for i, entry in enumerate(self.entries):
    186            outputList.append("points [%d]:" % (i + 1))
    187            outputList.append("    number = %s" % my_math.numToStr(entry[0]))
    188            outputList.append("    value = %s" % my_math.numToStr(entry[1]))
    189
    190        return "\n".join(outputList) + "\n"
    191
    192
    193class KlattSubPointTier(KlattPointTier):
    194    """
    195    Tiers contained in a KlattIntermediateTier
    196    """
    197
    198    def getAsText(self) -> str:
    199        outputList = []
    200        outputList.append("%s:" % self.name)
    201        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    202        outputList.append("    xmin = %s" % my_math.numToStr(self.minTimestamp))
    203        outputList.append("    xmax = %s" % my_math.numToStr(self.maxTimestamp))
    204        outputList.append("    points: size = %d" % len(self.entries))
    205
    206        for i, entry in enumerate(self.entries):
    207            outputList.append("    points [%d]:" % (i + 1))
    208            outputList.append("        number = %s" % my_math.numToStr(entry[0]))
    209            outputList.append("        value = %s" % my_math.numToStr(entry[1]))
    210
    211        return "\n".join(outputList) + "\n"
    212
    213
    214class Klattgrid(textgrid.Textgrid):
    215    def save(self, fn: str, minimumIntervalLength: Optional[float] = None):
    216        """
    217
    218        minimumIntervalLength is used for compatibility with Textgrid.save()
    219            but it has no impact on a Klattgrid
    220        """
    221
    222        # Header
    223        outputTxt = ""
    224        outputTxt += 'File type = "ooTextFile"\n'
    225        outputTxt += 'Object class = "KlattGrid"\n\n'
    226        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    227        outputTxt += "xmin = %s\nxmax = %s\n" % (
    228            my_math.numToStr(self.minTimestamp),
    229            my_math.numToStr(self.maxTimestamp),
    230        )
    231
    232        for tierName in self.tierNames:
    233            outputTxt += self._tierDict[tierName].getAsText()
    234
    235        outputTxt = _cleanNumericValues(outputTxt)
    236
    237        with io.open(fn, "w", encoding="utf-8") as fd:
    238            fd.write(outputTxt)
    239
    240
    241def toIntOrFloat(val: Union[str, float]) -> float:
    242    if float(val) - float(int(val)) == 0.0:
    243        val = int(val)
    244    else:
    245        val = float(val)
    246    return val
    247
    248
    249def _cleanNumericValues(dataStr: str) -> str:
    250    dataList = dataStr.split("\n")
    251    newDataList = []
    252    for row in dataList:
    253        row = row.rstrip()
    254        try:
    255            if "min" in row or "max" in row:
    256                raise errors.ParsingError(
    257                    f"Found unexpected keyword 'min' or 'max' in row '{row}'"
    258                )
    259
    260            head, tail = row.split("=")
    261            head = head.rstrip()
    262            tail = tail.strip()
    263            try:
    264                row = str(int(tail))
    265            except ValueError:
    266                tail = "%s" % tail
    267                if float(tail) == 0:
    268                    tail = "0"
    269            row = "%s = %s" % (head, tail)
    270        except (ValueError, errors.ParsingError):  # TODO: Is it really ok?
    271            pass
    272        finally:
    273            newDataList.append(row.rstrip())
    274
    275    outputTxt = "\n".join(newDataList)
    276
    277    return outputTxt

class KlattContainerTier(_KlattBaseTier): View Source

    63class KlattContainerTier(_KlattBaseTier):
    64    """Contains a set of intermediate tiers"""
    65
    66    def getAsText(self):
    67        outputTxt = ""
    68        outputTxt += "%s? <exists>\n" % self.name
    69
    70        try:
    71            self.minTimestamp = toIntOrFloat(self.minTimestamp)
    72            outputTxt += "xmin = %s\nxmax = %s\n" % (
    73                my_math.numToStr(self.minTimestamp),
    74                my_math.numToStr(self.maxTimestamp),
    75            )
    76        except TypeError:
    77            pass
    78
    79        for name in self.tierNameList:
    80            outputTxt += self.tierDict[name].getAsText()
    81
    82        return outputTxt
    83
    84    def modifySubtiers(self, tierName: str, modFunc) -> None:
    85        """
    86        Modify values in every tier contained in the named intermediate tier
    87        """
    88        kit = self.tierDict[tierName]
    89        for name in kit.tierNameList:
    90            subpointTier = kit.tierDict[name]
    91            subpointTier.modifyValues(modFunc)

Contains a set of intermediate tiers

def getAsText(self): View Source

    66    def getAsText(self):
    67        outputTxt = ""
    68        outputTxt += "%s? <exists>\n" % self.name
    69
    70        try:
    71            self.minTimestamp = toIntOrFloat(self.minTimestamp)
    72            outputTxt += "xmin = %s\nxmax = %s\n" % (
    73                my_math.numToStr(self.minTimestamp),
    74                my_math.numToStr(self.maxTimestamp),
    75            )
    76        except TypeError:
    77            pass
    78
    79        for name in self.tierNameList:
    80            outputTxt += self.tierDict[name].getAsText()
    81
    82        return outputTxt

def modifySubtiers(self, tierName: str, modFunc) -> None: View Source

    84    def modifySubtiers(self, tierName: str, modFunc) -> None:
    85        """
    86        Modify values in every tier contained in the named intermediate tier
    87        """
    88        kit = self.tierDict[tierName]
    89        for name in kit.tierNameList:
    90            subpointTier = kit.tierDict[name]
    91            subpointTier.modifyValues(modFunc)

Modify values in every tier contained in the named intermediate tier

##### Inherited Members

_KlattBaseTier
  _KlattBaseTier
  tierNameList
  tierDict
  name
  minTimestamp
  maxTimestamp
  addTier

class KlattIntermediateTier(_KlattBaseTier): View Source

     94class KlattIntermediateTier(_KlattBaseTier):
     95    """
     96    Has many point tiers that are semantically related (e.g. formant tiers)
     97    """
     98
     99    def getAsText(self):
    100        outputTxt = ""
    101        headerTxt = "%s: size=%d\n" % (self.name, len(self.tierNameList))
    102
    103        for name in self.tierNameList:
    104            outputTxt += self.tierDict[name].getAsText()
    105
    106        outputTxt = headerTxt + outputTxt
    107
    108        return outputTxt

Has many point tiers that are semantically related (e.g. formant tiers)

def getAsText(self): View Source

     99    def getAsText(self):
    100        outputTxt = ""
    101        headerTxt = "%s: size=%d\n" % (self.name, len(self.tierNameList))
    102
    103        for name in self.tierNameList:
    104            outputTxt += self.tierDict[name].getAsText()
    105
    106        outputTxt = headerTxt + outputTxt
    107
    108        return outputTxt

##### Inherited Members

_KlattBaseTier
  _KlattBaseTier
  tierNameList
  tierDict
  name
  minTimestamp
  maxTimestamp
  addTier

class KlattPointTier(praatio.data_classes.textgrid_tier.TextgridTier): View Source

    111class KlattPointTier(textgrid_tier.TextgridTier):
    112    """
    113    A Klatt tier not contained within another tier
    114    """
    115
    116    def __init__(
    117        self,
    118        name: str,
    119        entries: List,
    120        minT: Optional[float] = None,
    121        maxT: Optional[float] = None,
    122    ):
    123
    124        entries = [(float(time), label) for time, label in entries]
    125
    126        # Determine the min and max timestamps
    127        timeList = [time for time, label in entries]
    128        if minT is not None:
    129            timeList.append(float(minT))
    130        if maxT is not None:
    131            timeList.append(float(maxT))
    132
    133        try:
    134            setMinT = min(timeList)
    135            setMaxT = max(timeList)
    136        except ValueError:
    137            raise errors.TimelessTextgridTierException()
    138
    139        super(KlattPointTier, self).__init__(name, entries, setMinT, setMaxT)
    140
    141    def crop(self):
    142        raise NotImplementedError
    143
    144    def dejitter(self):
    145        raise NotImplementedError
    146
    147    def deleteEntry(self, entry):
    148        raise NotImplementedError
    149
    150    def editTimestamps(self):
    151        raise NotImplementedError
    152
    153    def eraseRegion(self):
    154        raise NotImplementedError
    155
    156    def insertEntry(self):
    157        raise NotImplementedError
    158
    159    def insertSpace(self):
    160        raise NotImplementedError
    161
    162    @property
    163    def timestamps(self):
    164        raise NotImplementedError
    165
    166    def validate(self):
    167        raise NotImplementedError
    168
    169    def modifyValues(self, modFunc: Callable[[float], bool]) -> None:
    170        newEntries = [
    171            (timestamp, modFunc(float(value))) for timestamp, value in self.entries
    172        ]
    173
    174        self._entries = newEntries
    175
    176    def getAsText(self) -> str:
    177        outputList = []
    178        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    179        outputList.append("%s? <exists> " % self.name)
    180        outputList.append("xmin = %s" % my_math.numToStr(self.minTimestamp))
    181        outputList.append("xmax = %s" % my_math.numToStr(self.maxTimestamp))
    182
    183        if self.name not in ["phonation", "vocalTract", "coupling", "frication"]:
    184            outputList.append("points: size= %d" % len(self.entries))
    185
    186        for i, entry in enumerate(self.entries):
    187            outputList.append("points [%d]:" % (i + 1))
    188            outputList.append("    number = %s" % my_math.numToStr(entry[0]))
    189            outputList.append("    value = %s" % my_math.numToStr(entry[1]))
    190
    191        return "\n".join(outputList) + "\n"

A Klatt tier not contained within another tier

KlattPointTier( name: str, entries: List, minT: Optional[float] = None, maxT: Optional[float] = None) View Source

    116    def __init__(
    117        self,
    118        name: str,
    119        entries: List,
    120        minT: Optional[float] = None,
    121        maxT: Optional[float] = None,
    122    ):
    123
    124        entries = [(float(time), label) for time, label in entries]
    125
    126        # Determine the min and max timestamps
    127        timeList = [time for time, label in entries]
    128        if minT is not None:
    129            timeList.append(float(minT))
    130        if maxT is not None:
    131            timeList.append(float(maxT))
    132
    133        try:
    134            setMinT = min(timeList)
    135            setMaxT = max(timeList)
    136        except ValueError:
    137            raise errors.TimelessTextgridTierException()
    138
    139        super(KlattPointTier, self).__init__(name, entries, setMinT, setMaxT)

A container that stores and operates over interval and point tiers

def crop(self): View Source

    141    def crop(self):
    142        raise NotImplementedError

def dejitter(self): View Source

    144    def dejitter(self):
    145        raise NotImplementedError

def deleteEntry(self, entry): View Source

    147    def deleteEntry(self, entry):
    148        raise NotImplementedError

def editTimestamps(self): View Source

    150    def editTimestamps(self):
    151        raise NotImplementedError

def eraseRegion(self): View Source

    153    def eraseRegion(self):
    154        raise NotImplementedError

def insertEntry(self): View Source

    156    def insertEntry(self):
    157        raise NotImplementedError

def insertSpace(self): View Source

    159    def insertSpace(self):
    160        raise NotImplementedError

timestamps
def validate(self): View Source

    166    def validate(self):
    167        raise NotImplementedError

def modifyValues(self, modFunc: Callable[[float], bool]) -> None: View Source

    169    def modifyValues(self, modFunc: Callable[[float], bool]) -> None:
    170        newEntries = [
    171            (timestamp, modFunc(float(value))) for timestamp, value in self.entries
    172        ]
    173
    174        self._entries = newEntries

def getAsText(self) -> str: View Source

    176    def getAsText(self) -> str:
    177        outputList = []
    178        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    179        outputList.append("%s? <exists> " % self.name)
    180        outputList.append("xmin = %s" % my_math.numToStr(self.minTimestamp))
    181        outputList.append("xmax = %s" % my_math.numToStr(self.maxTimestamp))
    182
    183        if self.name not in ["phonation", "vocalTract", "coupling", "frication"]:
    184            outputList.append("points: size= %d" % len(self.entries))
    185
    186        for i, entry in enumerate(self.entries):
    187            outputList.append("points [%d]:" % (i + 1))
    188            outputList.append("    number = %s" % my_math.numToStr(entry[0]))
    189            outputList.append("    value = %s" % my_math.numToStr(entry[1]))
    190
    191        return "\n".join(outputList) + "\n"

##### Inherited Members

praatio.data_classes.textgrid_tier.TextgridTier
  tierType
  entryType
  name
  minTimestamp
  maxTimestamp
  errorReporter
  entries
  appendTier
  find
  new
  sort
  union

class KlattSubPointTier(KlattPointTier): View Source

    194class KlattSubPointTier(KlattPointTier):
    195    """
    196    Tiers contained in a KlattIntermediateTier
    197    """
    198
    199    def getAsText(self) -> str:
    200        outputList = []
    201        outputList.append("%s:" % self.name)
    202        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    203        outputList.append("    xmin = %s" % my_math.numToStr(self.minTimestamp))
    204        outputList.append("    xmax = %s" % my_math.numToStr(self.maxTimestamp))
    205        outputList.append("    points: size = %d" % len(self.entries))
    206
    207        for i, entry in enumerate(self.entries):
    208            outputList.append("    points [%d]:" % (i + 1))
    209            outputList.append("        number = %s" % my_math.numToStr(entry[0]))
    210            outputList.append("        value = %s" % my_math.numToStr(entry[1]))
    211
    212        return "\n".join(outputList) + "\n"

Tiers contained in a KlattIntermediateTier

def getAsText(self) -> str: View Source

    199    def getAsText(self) -> str:
    200        outputList = []
    201        outputList.append("%s:" % self.name)
    202        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    203        outputList.append("    xmin = %s" % my_math.numToStr(self.minTimestamp))
    204        outputList.append("    xmax = %s" % my_math.numToStr(self.maxTimestamp))
    205        outputList.append("    points: size = %d" % len(self.entries))
    206
    207        for i, entry in enumerate(self.entries):
    208            outputList.append("    points [%d]:" % (i + 1))
    209            outputList.append("        number = %s" % my_math.numToStr(entry[0]))
    210            outputList.append("        value = %s" % my_math.numToStr(entry[1]))
    211
    212        return "\n".join(outputList) + "\n"

##### Inherited Members

KlattPointTier
  KlattPointTier
  crop
  dejitter
  deleteEntry
  editTimestamps
  eraseRegion
  insertEntry
  insertSpace
  timestamps
  validate
  modifyValues
praatio.data_classes.textgrid_tier.TextgridTier
  tierType
  entryType
  name
  minTimestamp
  maxTimestamp
  errorReporter
  entries
  appendTier
  find
  new
  sort
  union

class Klattgrid(praatio.data_classes.textgrid.Textgrid): View Source

    215class Klattgrid(textgrid.Textgrid):
    216    def save(self, fn: str, minimumIntervalLength: Optional[float] = None):
    217        """
    218
    219        minimumIntervalLength is used for compatibility with Textgrid.save()
    220            but it has no impact on a Klattgrid
    221        """
    222
    223        # Header
    224        outputTxt = ""
    225        outputTxt += 'File type = "ooTextFile"\n'
    226        outputTxt += 'Object class = "KlattGrid"\n\n'
    227        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    228        outputTxt += "xmin = %s\nxmax = %s\n" % (
    229            my_math.numToStr(self.minTimestamp),
    230            my_math.numToStr(self.maxTimestamp),
    231        )
    232
    233        for tierName in self.tierNames:
    234            outputTxt += self._tierDict[tierName].getAsText()
    235
    236        outputTxt = _cleanNumericValues(outputTxt)
    237
    238        with io.open(fn, "w", encoding="utf-8") as fd:
    239            fd.write(outputTxt)

A container that stores and operates over interval and point tiers

Textgrids are used by the Praat software to group tiers. Each tier contains different annotation information for an audio recording.

###### Attributes:

- tierNames(Tuple[str]): the list of tier names in the textgrid
- tiers(Tuple[TextgridTier]): the list of ordered tiers
- minTimestamp(float): the minimum allowable timestamp in the textgrid
- maxTimestamp(float): the maximum allowable timestamp in the textgrid

def save(self, fn: str, minimumIntervalLength: Optional[float] = None): View Source

    216    def save(self, fn: str, minimumIntervalLength: Optional[float] = None):
    217        """
    218
    219        minimumIntervalLength is used for compatibility with Textgrid.save()
    220            but it has no impact on a Klattgrid
    221        """
    222
    223        # Header
    224        outputTxt = ""
    225        outputTxt += 'File type = "ooTextFile"\n'
    226        outputTxt += 'Object class = "KlattGrid"\n\n'
    227        self.minTimestamp = toIntOrFloat(self.minTimestamp)
    228        outputTxt += "xmin = %s\nxmax = %s\n" % (
    229            my_math.numToStr(self.minTimestamp),
    230            my_math.numToStr(self.maxTimestamp),
    231        )
    232
    233        for tierName in self.tierNames:
    234            outputTxt += self._tierDict[tierName].getAsText()
    235
    236        outputTxt = _cleanNumericValues(outputTxt)
    237
    238        with io.open(fn, "w", encoding="utf-8") as fd:
    239            fd.write(outputTxt)

minimumIntervalLength is used for compatibility with Textgrid.save() but it has no impact on a Klattgrid

##### Inherited Members

praatio.data_classes.textgrid.Textgrid
  Textgrid
  minTimestamp
  maxTimestamp
  tierNames
  tiers
  addTier
  appendTextgrid
  crop
  eraseRegion
  editTimestamps
  getTier
  insertSpace
  mergeTiers
  new
  renameTier
  removeTier
  replaceTier
  validate

def toIntOrFloat(val: Union[str, float]) -> float: View Source

    242def toIntOrFloat(val: Union[str, float]) -> float:
    243    if float(val) - float(int(val)) == 0.0:
    244        val = int(val)
    245    else:
    246        val = float(val)
    247    return val