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