praatio.praat_scripts

Python wrappers for various praat scripts contained in /praatScripts.

see examples/auto_segment_speech.py, examples/get_pitch_and_formants.py, klatt_resynthesis.py

  1"""
  2Python wrappers for various praat scripts contained in /praatScripts.
  3
  4see **examples/auto_segment_speech.py**, **examples/get_pitch_and_formants.py**,
  5**klatt_resynthesis.py**
  6"""
  7
  8import os
  9from os.path import join
 10import io
 11import csv
 12from typing import List, Optional, Tuple
 13
 14from praatio import audio
 15from praatio import data_points
 16from praatio.utilities import constants
 17from praatio.utilities import utils
 18
 19SILENCE_LABEL = "silent"
 20SOUND_LABEL = "sound"
 21
 22
 23def changeGender(
 24    praatEXE: str,
 25    wavFN: str,
 26    outputWavFN: str,
 27    pitchFloor: float,
 28    pitchCeiling: float,
 29    formantShiftRatio: float,
 30    pitchMedian: float = 0.0,
 31    pitchRange: float = 1.0,
 32    duration: float = 1.0,
 33    scriptFN: Optional[str] = None,
 34) -> None:
 35    """Changes the speech formants in a file using praat's change gender function
 36
 37    PitchMedian = 0.0; no change in median pitch
 38    PitchRange = 1.0; no change in pitch range
 39
 40    Uses the following praat command:
 41    https://www.fon.hum.uva.nl/praat/manual/Sound__Change_gender___.html
 42    """
 43    if scriptFN is None:
 44        scriptFN = join(utils.scriptsPath, "change_gender.praat")
 45
 46    #  Praat crashes on exit after resynthesis with a klattgrid
 47    utils.runPraatScript(
 48        praatEXE,
 49        scriptFN,
 50        [
 51            wavFN,
 52            outputWavFN,
 53            pitchFloor,
 54            pitchCeiling,
 55            formantShiftRatio,
 56            pitchMedian,
 57            pitchRange,
 58            duration,
 59        ],
 60    )
 61
 62
 63def changeIntensity(
 64    praatEXE: str,
 65    wavFN: str,
 66    outputWavFN: str,
 67    newIntensity: float,
 68    scriptFN: Optional[str] = None,
 69) -> None:
 70    """Changes the intensity of the wavFN (in db)
 71
 72    Uses the following praat command:
 73    https://www.fon.hum.uva.nl/praat/manual/Sound__Scale_intensity___.html
 74    """
 75    if scriptFN is None:
 76        scriptFN = join(utils.scriptsPath, "change_intensity.praat")
 77
 78    #  Praat crashes on exit after resynthesis with a klattgrid
 79    utils.runPraatScript(praatEXE, scriptFN, [wavFN, outputWavFN, newIntensity])
 80
 81
 82def getFormants(
 83    praatEXE: str,
 84    inputWavFN: str,
 85    outputTxtFN: str,
 86    maxFormant: float,
 87    stepSize: float = 0.01,
 88    window_length: float = 0.025,
 89    preemphasis: float = 50,
 90    scriptFN: Optional[str] = None,
 91    undefinedValue: Optional[str] = None,
 92) -> List:
 93    """Get F1, F2, and F3 for the audio file
 94
 95    maxFormant = 5500 for females, 5000 for males, <8000 for children
 96
 97    Uses the following praat command:
 98    https://www.fon.hum.uva.nl/praat/manual/Sound__To_Formant__burg____.html
 99    """
100    if scriptFN is None:
101        scriptFN = join(utils.scriptsPath, "get_formants.praat")
102
103    argList = [
104        inputWavFN,
105        outputTxtFN,
106        stepSize,
107        maxFormant,
108        window_length,
109        preemphasis,
110        -1,
111        -1,
112    ]
113    utils.runPraatScript(praatEXE, scriptFN, argList)
114
115    # Load the output
116    path, fn = os.path.split(outputTxtFN)
117    with open(os.path.join(path, fn), "r", encoding="utf-8") as fd:
118        csvFile = csv.reader(fd)
119        dataList = [row for row in csvFile]
120
121    # The new praat script includes a header
122    if dataList[0][0] == "time":
123        dataList = dataList[1:]
124
125    # Handle undefined values, convert values to float
126    returnList = []
127    for row in dataList:
128        keep = True
129        for i in range(1, 4):
130            if "--" in row[i]:
131                if undefinedValue is not None:
132                    row[i] = undefinedValue
133                else:
134                    keep = False
135                    break
136
137        if keep is True:
138            returnList.append([float(val) for val in row])
139
140    return returnList
141
142
143def getPulses(
144    praatEXE: str,
145    inputWavFN: str,
146    outputPointTierFN: str,
147    minPitch: float,
148    maxPitch: float,
149    scriptFN: Optional[str] = None,
150) -> data_points.PointObject1D:
151    """Gets the pitch/glottal pulses for an audio file.
152
153    Uses the following praat command:
154    http://www.fon.hum.uva.nl/praat/manual/Sound___Pitch__To_PointProcess__peaks____.html
155    """
156    if scriptFN is None:
157        scriptFN = join(utils.scriptsPath, "get_pulses.praat")
158
159    argList = [inputWavFN, outputPointTierFN, minPitch, maxPitch]
160    utils.runPraatScript(praatEXE, scriptFN, argList)
161
162    # Load the output
163    pointObj = data_points.open1DPointObject(outputPointTierFN)
164
165    return pointObj
166
167
168def getSpectralInfo(
169    praatEXE: str,
170    inputWavFN: str,
171    inputTGFN: str,
172    outputCSVFN: str,
173    tierName: str,
174    spectralPower: int = 2,
175    spectralMoment: int = 3,
176    scriptFN: Optional[str] = None,
177) -> Tuple[List, List]:
178    """Extracts various spectral measures from an audio file
179
180    Measures include: center_of_gravity, standard_deviation
181    skewness, kertosis, central_movement
182
183    Uses the following praat command:
184    http://www.fon.hum.uva.nl/praat/manual/Spectrum.html
185    """
186    if scriptFN is None:
187        scriptFN = join(utils.scriptsPath, "get_spectral_info.praat")
188
189    argList = [
190        inputWavFN,
191        inputTGFN,
192        outputCSVFN,
193        tierName,
194        spectralPower,
195        spectralMoment,
196    ]
197    utils.runPraatScript(praatEXE, scriptFN, argList)
198
199    # Load the output
200    with io.open(outputCSVFN, "r", encoding="utf-8") as fd:
201        data = fd.read()
202
203    dataList = data.rstrip().split("\n")
204    dataListOfLists = [row.split(",") for row in dataList]
205    titleRow, mainDataListOfLists = dataListOfLists[0], dataListOfLists[1:]
206
207    return titleRow, mainDataListOfLists
208
209
210def resynthesizePitch(
211    praatEXE: str,
212    inputWavFN: str,
213    pitchFN: str,
214    outputWavFN: str,
215    minPitch: float,
216    maxPitch: float,
217    scriptFN: Optional[str] = None,
218    pointList: Optional[List] = None,
219) -> None:
220    """Resynthesizes the pitch in a wav file with the given pitch contour file
221
222    The pitch track to use can optionally be passed in as pointList.  If
223    so, it will be saved as pitchFN for praat to be able to use.
224
225    Uses the following praat command:
226    https://www.fon.hum.uva.nl/praat/manual/Manipulation.html
227    """
228    if scriptFN is None:
229        scriptFN = join(utils.scriptsPath, "resynthesize_pitch.praat")
230
231    if pointList is not None:
232        dur = audio.QueryWav(inputWavFN).duration
233        pointObj = data_points.PointObject2D(
234            pointList, constants.DataPointTypes.PITCH, 0, dur
235        )
236        pointObj.save(pitchFN)
237
238    utils.runPraatScript(
239        praatEXE, scriptFN, [inputWavFN, pitchFN, outputWavFN, minPitch, maxPitch]
240    )
241
242
243def resynthesizeDuration(
244    praatEXE: str,
245    inputWavFN: str,
246    durationTierFN: str,
247    outputWavFN: str,
248    minPitch: float,
249    maxPitch: float,
250    scriptFN: Optional[str] = None,
251) -> None:
252    """Resynthesizes the duration in a wav file with the given duration tier
253
254    Uses the following praat command:
255    https://www.fon.hum.uva.nl/praat/manual/Manipulation.html
256    """
257    if scriptFN is None:
258        scriptFN = join(utils.scriptsPath, "resynthesize_duration.praat")
259
260    utils.runPraatScript(
261        praatEXE,
262        scriptFN,
263        [inputWavFN, durationTierFN, outputWavFN, minPitch, maxPitch],
264    )
265
266
267def annotateSilences(
268    praatEXE: str,
269    inputWavPath: str,
270    outputTGPath: str,
271    minPitch: float = 100,
272    timeStep: float = 0.0,
273    silenceThreshold: float = -25.0,
274    minSilDur: float = 0.1,
275    minSoundDur: float = 0.1,
276    silentLabel: str = SILENCE_LABEL,
277    soundLabel: str = SOUND_LABEL,
278    scriptFN: Optional[str] = None,
279) -> None:
280    """Marks the silences and non-silences of an audio file
281
282    Uses the praat command:
283    https://www.fon.hum.uva.nl/praat/manual/Sound__To_TextGrid__silences____.html
284    """
285    if scriptFN is None:
286        scriptFN = join(utils.scriptsPath, "annotate_silences.praat")
287
288    utils.runPraatScript(
289        praatEXE,
290        scriptFN,
291        [
292            inputWavPath,
293            outputTGPath,
294            minPitch,
295            timeStep,
296            silenceThreshold,
297            minSilDur,
298            minSoundDur,
299            silentLabel,
300            soundLabel,
301        ],
302    )
SILENCE_LABEL = 'silent'
SOUND_LABEL = 'sound'
def changeGender( praatEXE: str, wavFN: str, outputWavFN: str, pitchFloor: float, pitchCeiling: float, formantShiftRatio: float, pitchMedian: float = 0.0, pitchRange: float = 1.0, duration: float = 1.0, scriptFN: Optional[str] = None) -> None:
24def changeGender(
25    praatEXE: str,
26    wavFN: str,
27    outputWavFN: str,
28    pitchFloor: float,
29    pitchCeiling: float,
30    formantShiftRatio: float,
31    pitchMedian: float = 0.0,
32    pitchRange: float = 1.0,
33    duration: float = 1.0,
34    scriptFN: Optional[str] = None,
35) -> None:
36    """Changes the speech formants in a file using praat's change gender function
37
38    PitchMedian = 0.0; no change in median pitch
39    PitchRange = 1.0; no change in pitch range
40
41    Uses the following praat command:
42    https://www.fon.hum.uva.nl/praat/manual/Sound__Change_gender___.html
43    """
44    if scriptFN is None:
45        scriptFN = join(utils.scriptsPath, "change_gender.praat")
46
47    #  Praat crashes on exit after resynthesis with a klattgrid
48    utils.runPraatScript(
49        praatEXE,
50        scriptFN,
51        [
52            wavFN,
53            outputWavFN,
54            pitchFloor,
55            pitchCeiling,
56            formantShiftRatio,
57            pitchMedian,
58            pitchRange,
59            duration,
60        ],
61    )

Changes the speech formants in a file using praat's change gender function

PitchMedian = 0.0; no change in median pitch PitchRange = 1.0; no change in pitch range

Uses the following praat command: https://www.fon.hum.uva.nl/praat/manual/Sound__Change_gender___.html

def changeIntensity( praatEXE: str, wavFN: str, outputWavFN: str, newIntensity: float, scriptFN: Optional[str] = None) -> None:
64def changeIntensity(
65    praatEXE: str,
66    wavFN: str,
67    outputWavFN: str,
68    newIntensity: float,
69    scriptFN: Optional[str] = None,
70) -> None:
71    """Changes the intensity of the wavFN (in db)
72
73    Uses the following praat command:
74    https://www.fon.hum.uva.nl/praat/manual/Sound__Scale_intensity___.html
75    """
76    if scriptFN is None:
77        scriptFN = join(utils.scriptsPath, "change_intensity.praat")
78
79    #  Praat crashes on exit after resynthesis with a klattgrid
80    utils.runPraatScript(praatEXE, scriptFN, [wavFN, outputWavFN, newIntensity])

Changes the intensity of the wavFN (in db)

Uses the following praat command: https://www.fon.hum.uva.nl/praat/manual/Sound__Scale_intensity___.html

def getFormants( praatEXE: str, inputWavFN: str, outputTxtFN: str, maxFormant: float, stepSize: float = 0.01, window_length: float = 0.025, preemphasis: float = 50, scriptFN: Optional[str] = None, undefinedValue: Optional[str] = None) -> List:
 83def getFormants(
 84    praatEXE: str,
 85    inputWavFN: str,
 86    outputTxtFN: str,
 87    maxFormant: float,
 88    stepSize: float = 0.01,
 89    window_length: float = 0.025,
 90    preemphasis: float = 50,
 91    scriptFN: Optional[str] = None,
 92    undefinedValue: Optional[str] = None,
 93) -> List:
 94    """Get F1, F2, and F3 for the audio file
 95
 96    maxFormant = 5500 for females, 5000 for males, <8000 for children
 97
 98    Uses the following praat command:
 99    https://www.fon.hum.uva.nl/praat/manual/Sound__To_Formant__burg____.html
100    """
101    if scriptFN is None:
102        scriptFN = join(utils.scriptsPath, "get_formants.praat")
103
104    argList = [
105        inputWavFN,
106        outputTxtFN,
107        stepSize,
108        maxFormant,
109        window_length,
110        preemphasis,
111        -1,
112        -1,
113    ]
114    utils.runPraatScript(praatEXE, scriptFN, argList)
115
116    # Load the output
117    path, fn = os.path.split(outputTxtFN)
118    with open(os.path.join(path, fn), "r", encoding="utf-8") as fd:
119        csvFile = csv.reader(fd)
120        dataList = [row for row in csvFile]
121
122    # The new praat script includes a header
123    if dataList[0][0] == "time":
124        dataList = dataList[1:]
125
126    # Handle undefined values, convert values to float
127    returnList = []
128    for row in dataList:
129        keep = True
130        for i in range(1, 4):
131            if "--" in row[i]:
132                if undefinedValue is not None:
133                    row[i] = undefinedValue
134                else:
135                    keep = False
136                    break
137
138        if keep is True:
139            returnList.append([float(val) for val in row])
140
141    return returnList

Get F1, F2, and F3 for the audio file

maxFormant = 5500 for females, 5000 for males, <8000 for children

Uses the following praat command: https://www.fon.hum.uva.nl/praat/manual/Sound__To_Formant__burg____.html

def getPulses( praatEXE: str, inputWavFN: str, outputPointTierFN: str, minPitch: float, maxPitch: float, scriptFN: Optional[str] = None) -> praatio.data_classes.data_point.PointObject1D:
144def getPulses(
145    praatEXE: str,
146    inputWavFN: str,
147    outputPointTierFN: str,
148    minPitch: float,
149    maxPitch: float,
150    scriptFN: Optional[str] = None,
151) -> data_points.PointObject1D:
152    """Gets the pitch/glottal pulses for an audio file.
153
154    Uses the following praat command:
155    http://www.fon.hum.uva.nl/praat/manual/Sound___Pitch__To_PointProcess__peaks____.html
156    """
157    if scriptFN is None:
158        scriptFN = join(utils.scriptsPath, "get_pulses.praat")
159
160    argList = [inputWavFN, outputPointTierFN, minPitch, maxPitch]
161    utils.runPraatScript(praatEXE, scriptFN, argList)
162
163    # Load the output
164    pointObj = data_points.open1DPointObject(outputPointTierFN)
165
166    return pointObj

Gets the pitch/glottal pulses for an audio file.

Uses the following praat command: http://www.fon.hum.uva.nl/praat/manual/Sound___Pitch__To_PointProcess__peaks____.html

def getSpectralInfo( praatEXE: str, inputWavFN: str, inputTGFN: str, outputCSVFN: str, tierName: str, spectralPower: int = 2, spectralMoment: int = 3, scriptFN: Optional[str] = None) -> Tuple[List, List]:
169def getSpectralInfo(
170    praatEXE: str,
171    inputWavFN: str,
172    inputTGFN: str,
173    outputCSVFN: str,
174    tierName: str,
175    spectralPower: int = 2,
176    spectralMoment: int = 3,
177    scriptFN: Optional[str] = None,
178) -> Tuple[List, List]:
179    """Extracts various spectral measures from an audio file
180
181    Measures include: center_of_gravity, standard_deviation
182    skewness, kertosis, central_movement
183
184    Uses the following praat command:
185    http://www.fon.hum.uva.nl/praat/manual/Spectrum.html
186    """
187    if scriptFN is None:
188        scriptFN = join(utils.scriptsPath, "get_spectral_info.praat")
189
190    argList = [
191        inputWavFN,
192        inputTGFN,
193        outputCSVFN,
194        tierName,
195        spectralPower,
196        spectralMoment,
197    ]
198    utils.runPraatScript(praatEXE, scriptFN, argList)
199
200    # Load the output
201    with io.open(outputCSVFN, "r", encoding="utf-8") as fd:
202        data = fd.read()
203
204    dataList = data.rstrip().split("\n")
205    dataListOfLists = [row.split(",") for row in dataList]
206    titleRow, mainDataListOfLists = dataListOfLists[0], dataListOfLists[1:]
207
208    return titleRow, mainDataListOfLists

Extracts various spectral measures from an audio file

Measures include: center_of_gravity, standard_deviation skewness, kertosis, central_movement

Uses the following praat command: http://www.fon.hum.uva.nl/praat/manual/Spectrum.html

def resynthesizePitch( praatEXE: str, inputWavFN: str, pitchFN: str, outputWavFN: str, minPitch: float, maxPitch: float, scriptFN: Optional[str] = None, pointList: Optional[List] = None) -> None:
211def resynthesizePitch(
212    praatEXE: str,
213    inputWavFN: str,
214    pitchFN: str,
215    outputWavFN: str,
216    minPitch: float,
217    maxPitch: float,
218    scriptFN: Optional[str] = None,
219    pointList: Optional[List] = None,
220) -> None:
221    """Resynthesizes the pitch in a wav file with the given pitch contour file
222
223    The pitch track to use can optionally be passed in as pointList.  If
224    so, it will be saved as pitchFN for praat to be able to use.
225
226    Uses the following praat command:
227    https://www.fon.hum.uva.nl/praat/manual/Manipulation.html
228    """
229    if scriptFN is None:
230        scriptFN = join(utils.scriptsPath, "resynthesize_pitch.praat")
231
232    if pointList is not None:
233        dur = audio.QueryWav(inputWavFN).duration
234        pointObj = data_points.PointObject2D(
235            pointList, constants.DataPointTypes.PITCH, 0, dur
236        )
237        pointObj.save(pitchFN)
238
239    utils.runPraatScript(
240        praatEXE, scriptFN, [inputWavFN, pitchFN, outputWavFN, minPitch, maxPitch]
241    )

Resynthesizes the pitch in a wav file with the given pitch contour file

The pitch track to use can optionally be passed in as pointList. If so, it will be saved as pitchFN for praat to be able to use.

Uses the following praat command: https://www.fon.hum.uva.nl/praat/manual/Manipulation.html

def resynthesizeDuration( praatEXE: str, inputWavFN: str, durationTierFN: str, outputWavFN: str, minPitch: float, maxPitch: float, scriptFN: Optional[str] = None) -> None:
244def resynthesizeDuration(
245    praatEXE: str,
246    inputWavFN: str,
247    durationTierFN: str,
248    outputWavFN: str,
249    minPitch: float,
250    maxPitch: float,
251    scriptFN: Optional[str] = None,
252) -> None:
253    """Resynthesizes the duration in a wav file with the given duration tier
254
255    Uses the following praat command:
256    https://www.fon.hum.uva.nl/praat/manual/Manipulation.html
257    """
258    if scriptFN is None:
259        scriptFN = join(utils.scriptsPath, "resynthesize_duration.praat")
260
261    utils.runPraatScript(
262        praatEXE,
263        scriptFN,
264        [inputWavFN, durationTierFN, outputWavFN, minPitch, maxPitch],
265    )

Resynthesizes the duration in a wav file with the given duration tier

Uses the following praat command: https://www.fon.hum.uva.nl/praat/manual/Manipulation.html

def annotateSilences( praatEXE: str, inputWavPath: str, outputTGPath: str, minPitch: float = 100, timeStep: float = 0.0, silenceThreshold: float = -25.0, minSilDur: float = 0.1, minSoundDur: float = 0.1, silentLabel: str = 'silent', soundLabel: str = 'sound', scriptFN: Optional[str] = None) -> None:
268def annotateSilences(
269    praatEXE: str,
270    inputWavPath: str,
271    outputTGPath: str,
272    minPitch: float = 100,
273    timeStep: float = 0.0,
274    silenceThreshold: float = -25.0,
275    minSilDur: float = 0.1,
276    minSoundDur: float = 0.1,
277    silentLabel: str = SILENCE_LABEL,
278    soundLabel: str = SOUND_LABEL,
279    scriptFN: Optional[str] = None,
280) -> None:
281    """Marks the silences and non-silences of an audio file
282
283    Uses the praat command:
284    https://www.fon.hum.uva.nl/praat/manual/Sound__To_TextGrid__silences____.html
285    """
286    if scriptFN is None:
287        scriptFN = join(utils.scriptsPath, "annotate_silences.praat")
288
289    utils.runPraatScript(
290        praatEXE,
291        scriptFN,
292        [
293            inputWavPath,
294            outputTGPath,
295            minPitch,
296            timeStep,
297            silenceThreshold,
298            minSilDur,
299            minSoundDur,
300            silentLabel,
301            soundLabel,
302        ],
303    )

Marks the silences and non-silences of an audio file

Uses the praat command: https://www.fon.hum.uva.nl/praat/manual/Sound__To_TextGrid__silences____.html