praatio.textgrid

Functions for reading/writing/manipulating textgrid files.

This file links the main data structures for representing Textgrid data: Textgrid, IntervalTier, and PointTier

A Textgrid is a container for multiple annotation tiers. Tiers can contain either interval data (IntervalTier) or point data (PointTier). Tiers in a Textgrid are ordered and must contain a unique name.

openTextgrid() can be used to open a textgrid file. Textgrid.save() can be used to save a Textgrid object to a file.

Historically, these three classes lived in this file. To make maintance easier, they were split off. You can still access them from this file as before, but please check out the respective files for more documentation on each class: IntervalTier in data_classes/interval_tier.py PointTier in data_classes/point_tier.py Textgrid in data_classes/textgrid.py

see the examples/ directory for examples using textgrid.py

  1"""
  2Functions for reading/writing/manipulating textgrid files.
  3
  4This file links the main data structures for representing Textgrid data:
  5Textgrid, IntervalTier, and PointTier
  6
  7A Textgrid is a container for multiple annotation tiers.  Tiers can contain
  8either interval data (IntervalTier) or point data (PointTier).
  9Tiers in a Textgrid are ordered and must contain a unique name.
 10
 11openTextgrid() can be used to open a textgrid file.
 12Textgrid.save() can be used to save a Textgrid object to a file.
 13
 14Historically, these three classes lived in this file. To
 15make maintance easier, they were split off.  You can still access
 16them from this file as before, but please check out the respective
 17files for more documentation on each class:
 18IntervalTier in data_classes/interval_tier.py
 19PointTier in data_classes/point_tier.py
 20Textgrid in data_classes/textgrid.py
 21
 22see the **examples/** directory for examples using textgrid.py
 23"""
 24
 25import io
 26from typing import (
 27    Union,
 28    Type,
 29)
 30
 31from typing_extensions import Literal
 32
 33
 34from praatio.utilities.constants import (
 35    INTERVAL_TIER,
 36)
 37from praatio.data_classes.interval_tier import IntervalTier
 38from praatio.data_classes.point_tier import PointTier
 39from praatio.data_classes.textgrid import Textgrid
 40from praatio.utilities import textgrid_io
 41from praatio.utilities import utils
 42from praatio.utilities import constants
 43from praatio.utilities import errors
 44
 45
 46def openTextgrid(
 47    fnFullPath: str,
 48    includeEmptyIntervals: bool,
 49    reportingMode: Literal["silence", "warning", "error"] = "warning",
 50    duplicateNamesMode: Literal["error", "rename"] = "error",
 51) -> Textgrid:
 52    """Opens a textgrid file (.TextGrid and .json are both fine)
 53
 54    https://www.fon.hum.uva.nl/praat/manual/TextGrid_file_formats.html
 55
 56    Args:
 57        fnFullPath: the path to the textgrid to open
 58        includeEmptyIntervals: if False, points and intervals with
 59             an empty label '' are not included in the returned Textgrid
 60
 61    Returns:
 62        A Textgrid
 63
 64    Raises:
 65        DuplicateTierName: The textgrid contains multiple tiers with the same name
 66    """
 67    utils.validateOption("reportingMode", reportingMode, constants.ErrorReportingMode)
 68    utils.validateOption(
 69        "duplicateNamesMode", duplicateNamesMode, constants.DuplicateNames
 70    )
 71    try:
 72        with io.open(fnFullPath, "r", encoding="utf-16") as fd:
 73            data = fd.read()
 74    except UnicodeError:
 75        with io.open(fnFullPath, "r", encoding="utf-8") as fd:
 76            data = fd.read()
 77
 78    tgAsDict = textgrid_io.parseTextgridStr(data, includeEmptyIntervals)
 79
 80    tierNames = []
 81    for tier in tgAsDict["tiers"]:
 82        name = tier["name"]
 83        if name in tierNames:
 84            if duplicateNamesMode == constants.DuplicateNames.ERROR:
 85                raise errors.DuplicateTierName(
 86                    f"Your textgrid contains tiers with the same name '{name}'. "
 87                    "This is not allowed. It is recommended that you rename them. "
 88                    "If you set openTextgrid(..., duplicateNamesMode='rename'), praatio "
 89                    "will automatically append numbers to the end of tiers to ensure they "
 90                    "are unique."
 91                )
 92            elif duplicateNamesMode == constants.DuplicateNames.RENAME:
 93                newName = name
 94                i = 2
 95                while newName in tierNames:
 96                    newName = f"{name}_{i}"
 97                    i += 1
 98                name = newName
 99                tier["name"] = name
100        tierNames.append(name)
101
102    return _dictionaryToTg(tgAsDict, reportingMode)
103
104
105def _dictionaryToTg(
106    tgAsDict: dict, reportingMode: Literal["silence", "warning", "error"]
107) -> Textgrid:
108    """Converts a dictionary representation of a textgrid to a Textgrid"""
109    utils.validateOption("reportingMode", reportingMode, constants.ErrorReportingMode)
110
111    tg = Textgrid()
112    tg.minTimestamp = tgAsDict["xmin"]
113    tg.maxTimestamp = tgAsDict["xmax"]
114
115    for tierAsDict in tgAsDict["tiers"]:
116        klass: Union[Type[PointTier], Type[IntervalTier]]
117        if tierAsDict["class"] == INTERVAL_TIER:
118            klass = IntervalTier
119        else:
120            klass = PointTier
121        tier = klass(
122            tierAsDict["name"],
123            tierAsDict["entries"],
124            tierAsDict["xmin"],
125            tierAsDict["xmax"],
126        )
127        tg.addTier(tier, reportingMode=reportingMode)
128
129    return tg
def openTextgrid( fnFullPath: str, includeEmptyIntervals: bool, reportingMode: Literal['silence', 'warning', 'error'] = 'warning', duplicateNamesMode: Literal['error', 'rename'] = 'error') -> praatio.data_classes.textgrid.Textgrid:
 47def openTextgrid(
 48    fnFullPath: str,
 49    includeEmptyIntervals: bool,
 50    reportingMode: Literal["silence", "warning", "error"] = "warning",
 51    duplicateNamesMode: Literal["error", "rename"] = "error",
 52) -> Textgrid:
 53    """Opens a textgrid file (.TextGrid and .json are both fine)
 54
 55    https://www.fon.hum.uva.nl/praat/manual/TextGrid_file_formats.html
 56
 57    Args:
 58        fnFullPath: the path to the textgrid to open
 59        includeEmptyIntervals: if False, points and intervals with
 60             an empty label '' are not included in the returned Textgrid
 61
 62    Returns:
 63        A Textgrid
 64
 65    Raises:
 66        DuplicateTierName: The textgrid contains multiple tiers with the same name
 67    """
 68    utils.validateOption("reportingMode", reportingMode, constants.ErrorReportingMode)
 69    utils.validateOption(
 70        "duplicateNamesMode", duplicateNamesMode, constants.DuplicateNames
 71    )
 72    try:
 73        with io.open(fnFullPath, "r", encoding="utf-16") as fd:
 74            data = fd.read()
 75    except UnicodeError:
 76        with io.open(fnFullPath, "r", encoding="utf-8") as fd:
 77            data = fd.read()
 78
 79    tgAsDict = textgrid_io.parseTextgridStr(data, includeEmptyIntervals)
 80
 81    tierNames = []
 82    for tier in tgAsDict["tiers"]:
 83        name = tier["name"]
 84        if name in tierNames:
 85            if duplicateNamesMode == constants.DuplicateNames.ERROR:
 86                raise errors.DuplicateTierName(
 87                    f"Your textgrid contains tiers with the same name '{name}'. "
 88                    "This is not allowed. It is recommended that you rename them. "
 89                    "If you set openTextgrid(..., duplicateNamesMode='rename'), praatio "
 90                    "will automatically append numbers to the end of tiers to ensure they "
 91                    "are unique."
 92                )
 93            elif duplicateNamesMode == constants.DuplicateNames.RENAME:
 94                newName = name
 95                i = 2
 96                while newName in tierNames:
 97                    newName = f"{name}_{i}"
 98                    i += 1
 99                name = newName
100                tier["name"] = name
101        tierNames.append(name)
102
103    return _dictionaryToTg(tgAsDict, reportingMode)

Opens a textgrid file (.TextGrid and .json are both fine)

https://www.fon.hum.uva.nl/praat/manual/TextGrid_file_formats.html

Arguments:
  • fnFullPath: the path to the textgrid to open
  • includeEmptyIntervals: if False, points and intervals with an empty label '' are not included in the returned Textgrid
Returns:

A Textgrid

Raises:
  • DuplicateTierName: The textgrid contains multiple tiers with the same name