def outputMorphPlot(fromTGFN, toTGFN, tierName, durationParameters, stepList, outputImageFN): if outputImageFN is not None: utils.makeDir(os.path.split(outputImageFN)[0]) # Create the plot of the morph if outputImageFN is not None: _plotResults(durationParameters, fromTGFN, toTGFN, tierName, stepList, outputImageFN, None, False)
def changeDuration(fromWavFN, durationParameters, stepList, outputName, outputMinPitch, outputMaxPitch, praatEXE): ''' Uses praat to morph duration in one file to duration in another Praat uses the PSOLA algorithm ''' rootPath = os.path.split(fromWavFN)[0] # Prep output directories outputPath = join(rootPath, "duration_resynthesized_wavs") utils.makeDir(outputPath) durationTierPath = join(rootPath, "duration_tiers") utils.makeDir(durationTierPath) fromWavDuration = audio_scripts.getSoundFileDuration(fromWavFN) durationParameters = copy.deepcopy(durationParameters) # Pad any gaps with values of 1 (no change in duration) # No need to stretch out any pauses at the beginning if durationParameters[0][0] != 0: tmpVar = (0, durationParameters[0][0] - PRAAT_TIME_DIFF, 1) durationParameters.insert(0, tmpVar) # Or the end if durationParameters[-1][1] < fromWavDuration: durationParameters.append((durationParameters[-1][1] + PRAAT_TIME_DIFF, fromWavDuration, 1)) # Create the praat script for doing duration manipulation for stepAmount in stepList: durationPointList = [] for start, end, ratio in durationParameters: percentChange = 1 + (ratio - 1) * stepAmount durationPointList.append((start, percentChange)) durationPointList.append((end, percentChange)) outputPrefix = "%s_%0.3g" % (outputName, stepAmount) durationTierFN = join(durationTierPath, "%s.DurationTier" % outputPrefix) outputWavFN = join(outputPath, "%s.wav" % outputPrefix) durationTier = dataio.PointObject2D(durationPointList, dataio.DURATION, 0, fromWavDuration) durationTier.save(durationTierFN) praat_scripts.resynthesizeDuration(praatEXE, fromWavFN, durationTierFN, outputWavFN, outputMinPitch, outputMaxPitch)
def changeDuration(fromWavFN, durationParameters, stepList, outputName, outputMinPitch, outputMaxPitch, praatEXE): ''' Uses praat to morph duration in one file to duration in another Praat uses the PSOLA algorithm ''' rootPath = os.path.split(fromWavFN)[0] # Prep output directories outputPath = join(rootPath, "duration_resynthesized_wavs") utils.makeDir(outputPath) durationTierPath = join(rootPath, "duration_tiers") utils.makeDir(durationTierPath) fromWavDuration = audio_scripts.getSoundFileDuration(fromWavFN) durationParameters = copy.deepcopy(durationParameters) # Pad any gaps with values of 1 (no change in duration) # No need to stretch out any pauses at the beginning if durationParameters[0][0] != 0: tmpVar = (0, durationParameters[0][0] - PRAAT_TIME_DIFF, 1) durationParameters.insert(0, tmpVar) # Or the end if durationParameters[-1][1] < fromWavDuration: durationParameters.append( (durationParameters[-1][1] + PRAAT_TIME_DIFF, fromWavDuration, 1)) # Create the praat script for doing duration manipulation for stepAmount in stepList: durationPointList = [] for start, end, ratio in durationParameters: percentChange = 1 + (ratio - 1) * stepAmount durationPointList.append((start, percentChange)) durationPointList.append((end, percentChange)) outputPrefix = "%s_%0.3g" % (outputName, stepAmount) durationTierFN = join(durationTierPath, "%s.DurationTier" % outputPrefix) outputWavFN = join(outputPath, "%s.wav" % outputPrefix) durationTier = dataio.PointObject2D(durationPointList, dataio.DURATION, 0, fromWavDuration) durationTier.save(durationTierFN) praat_scripts.resynthesizeDuration(praatEXE, fromWavFN, durationTierFN, outputWavFN, outputMinPitch, outputMaxPitch)
def outputMorphTextgrids(fromTGFN, durationParameters, stepList, outputTGName): if outputTGName is not None: utils.makeDir(os.path.split(outputTGName)[0]) # Create the adjusted textgrids if outputTGName is not None: for stepFactor in stepList: stepDurationParameters = [ (start, end, 1 + (ratio - 1) * stepFactor) for start, end, ratio in durationParameters ] adjustedTG = textgridManipulateDuration(fromTGFN, stepDurationParameters) outputTGFN = "%s_%0.3g.TextGrid" % (outputTGName, stepFactor) adjustedTG.save(outputTGFN)
def outputMorphTextgrids(fromTGFN, durationParameters, stepList, outputTGName): if outputTGName is not None: utils.makeDir(os.path.split(outputTGName)[0]) # Create the adjusted textgrids if outputTGName is not None: for stepFactor in stepList: stepDurationParameters = [(start, end, 1 + (ratio - 1) * stepFactor) for start, end, ratio in durationParameters] adjustedTG = textgridManipulateDuration(fromTGFN, stepDurationParameters) outputTGFN = "%s_%0.3g.TextGrid" % (outputTGName, stepFactor) adjustedTG.save(outputTGFN)
def f0Morph(fromWavFN, pitchPath, stepList, outputName, doPlotPitchSteps, fromPitchData, toPitchData, outputMinPitch, outputMaxPitch, praatEXE, keepPitchRange=False, keepAveragePitch=False): ''' Resynthesizes the pitch track from a source to a target wav file fromPitchData and toPitchData should be segmented according to the portions that you want to morph. The two lists must have the same number of sublists. Occurs over a three-step process. This function can act as a template for how to use the function morph_sequence.morphChunkedDataLists to morph pitch contours or other data. By default, everything is morphed, but it is possible to maintain elements of the original speaker's pitch (average pitch and pitch range) by setting the appropriate flag) ''' fromDuration = audio_scripts.getSoundFileDuration(fromWavFN) # Iterative pitch tier data path pitchTierPath = join(pitchPath, "pitchTiers") resynthesizedPath = join(pitchPath, "f0_resynthesized_wavs") for tmpPath in [pitchTierPath, resynthesizedPath]: utils.makeDir(tmpPath) # 1. Prepare the data for morphing - acquire the segments to merge # (Done elsewhere, with the input fed into this function) # 2. Morph the fromData to the toData try: finalOutputList = morph_sequence.morphChunkedDataLists( fromPitchData, toPitchData, stepList) except IndexError: raise MissingPitchDataException() fromPitchData = [row for subList in fromPitchData for row in subList] toPitchData = [row for subList in toPitchData for row in subList] # 3. Save the pitch data and resynthesize the pitch mergedDataList = [] for i in range(0, len(finalOutputList)): outputDataList = finalOutputList[i] if keepPitchRange is True: outputDataList = morph_sequence.morphRange(outputDataList, fromPitchData) if keepAveragePitch is True: outputDataList = morph_sequence.morphAveragePitch( outputDataList, fromPitchData) stepOutputName = "%s_%0.3g" % (outputName, stepList[i]) pitchFNFullPath = join(pitchTierPath, "%s.PitchTier" % stepOutputName) outputFN = join(resynthesizedPath, "%s.wav" % stepOutputName) pointObj = dataio.PointObject2D(outputDataList, dataio.PITCH, 0, fromDuration) pointObj.save(pitchFNFullPath) outputTime, outputVals = list(zip(*outputDataList)) mergedDataList.append((outputTime, outputVals)) praat_scripts.resynthesizePitch(praatEXE, fromWavFN, pitchFNFullPath, outputFN, outputMinPitch, outputMaxPitch) # 4. (Optional) Plot the generated contours if doPlotPitchSteps: fromTime, fromVals = list(zip(*fromPitchData)) toTime, toVals = list(zip(*toPitchData)) plot_morphed_data.plotF0((fromTime, fromVals), (toTime, toVals), mergedDataList, join(pitchTierPath, "%s.png" % outputName))
fromName = "mary1" toName = "mary2" fromWavFN = join(root, fromName + ".wav") toWavFN = join(root, toName + ".wav") fromPitchFN = fromName + ".txt" toPitchFN = toName + ".txt" tierName = "PhonAlign" fromTGFN = join(root, fromName + ".TextGrid") toTGFN = join(root, toName + ".TextGrid") outputPath = join(root, "duration_morph") utils.makeDir(outputPath) outputName = "%s_%s_dur_morph" % (fromName, toName) outputTG = join(outputPath, "%s.TextGrid" % outputName) outputImageFN = join(outputPath, "%s.png" % outputName) filterFunc = None includeUnlabeledRegions = False # Morph the duration from one file to another durationParams = duration_morph.getMorphParameters(fromTGFN, toTGFN, tierName, filterFunc, includeUnlabeledRegions) morphedTG = duration_morph.textgridMorphDuration(fromTGFN, toTGFN) morphedTG.save(outputTG) duration_morph.changeDuration(fromWavFN, durationParams, stepList,
def f0Morph(fromWavFN, pitchPath, stepList, outputName, doPlotPitchSteps, fromPitchData, toPitchData, outputMinPitch, outputMaxPitch, praatEXE, keepPitchRange=False, keepAveragePitch=False, sourcePitchDataList=None, minIntervalLength=0.3): ''' Resynthesizes the pitch track from a source to a target wav file fromPitchData and toPitchData should be segmented according to the portions that you want to morph. The two lists must have the same number of sublists. Occurs over a three-step process. This function can act as a template for how to use the function morph_sequence.morphChunkedDataLists to morph pitch contours or other data. By default, everything is morphed, but it is possible to maintain elements of the original speaker's pitch (average pitch and pitch range) by setting the appropriate flag) sourcePitchDataList: if passed in, any regions unspecified by fromPitchData will be sampled from this list. In essence, this allows one to leave segments of the original pitch contour untouched by the morph process. ''' fromDuration = audio_scripts.getSoundFileDuration(fromWavFN) # Find source pitch samples that will be mixed in with the target # pitch samples later nonMorphPitchData = [] if sourcePitchDataList is not None: timeList = sorted(fromPitchData) timeList = [(row[0][0], row[-1][0]) for row in timeList] endTime = sourcePitchDataList[-1][0] invertedTimeList = praatio_utils.invertIntervalList(timeList, endTime) invertedTimeList = [(start, stop) for start, stop in invertedTimeList if stop - start > minIntervalLength] for start, stop in invertedTimeList: pitchList = praatio_utils.getValuesInInterval( sourcePitchDataList, start, stop) nonMorphPitchData.extend(pitchList) # Iterative pitch tier data path pitchTierPath = join(pitchPath, "pitchTiers") resynthesizedPath = join(pitchPath, "f0_resynthesized_wavs") for tmpPath in [pitchTierPath, resynthesizedPath]: utils.makeDir(tmpPath) # 1. Prepare the data for morphing - acquire the segments to merge # (Done elsewhere, with the input fed into this function) # 2. Morph the fromData to the toData try: finalOutputList = morph_sequence.morphChunkedDataLists( fromPitchData, toPitchData, stepList) except IndexError: raise MissingPitchDataException() fromPitchData = [row for subList in fromPitchData for row in subList] toPitchData = [row for subList in toPitchData for row in subList] # 3. Save the pitch data and resynthesize the pitch mergedDataList = [] for i in range(0, len(finalOutputList)): outputDataList = finalOutputList[i] if keepPitchRange is True: outputDataList = morph_sequence.morphRange(outputDataList, fromPitchData) if keepAveragePitch is True: outputDataList = morph_sequence.morphAveragePitch( outputDataList, fromPitchData) if sourcePitchDataList is not None: outputDataList.extend(nonMorphPitchData) outputDataList.sort() stepOutputName = "%s_%0.3g" % (outputName, stepList[i]) pitchFNFullPath = join(pitchTierPath, "%s.PitchTier" % stepOutputName) outputFN = join(resynthesizedPath, "%s.wav" % stepOutputName) pointObj = dataio.PointObject2D(outputDataList, dataio.PITCH, 0, fromDuration) pointObj.save(pitchFNFullPath) outputTime, outputVals = zip(*outputDataList) mergedDataList.append((outputTime, outputVals)) praat_scripts.resynthesizePitch(praatEXE, fromWavFN, pitchFNFullPath, outputFN, outputMinPitch, outputMaxPitch) # 4. (Optional) Plot the generated contours if doPlotPitchSteps: fromTime, fromVals = zip(*fromPitchData) toTime, toVals = zip(*toPitchData) plot_morphed_data.plotF0((fromTime, fromVals), (toTime, toVals), mergedDataList, join(pitchTierPath, "%s.png" % outputName))
def f0Morph(fromWavFN, pitchPath, stepList, outputName, doPlotPitchSteps, fromPitchData, toPitchData, outputMinPitch, outputMaxPitch, praatEXE, keepPitchRange=False, keepAveragePitch=False): ''' Resynthesizes the pitch track from a source to a target wav file fromPitchData and toPitchData should be segmented according to the portions that you want to morph. The two lists must have the same number of sublists. Occurs over a three-step process. This function can act as a template for how to use the function morph_sequence.morphChunkedDataLists to morph pitch contours or other data. By default, everything is morphed, but it is possible to maintain elements of the original speaker's pitch (average pitch and pitch range) by setting the appropriate flag) ''' fromDuration = audio_scripts.getSoundFileDuration(fromWavFN) # Iterative pitch tier data path pitchTierPath = join(pitchPath, "pitchTiers") resynthesizedPath = join(pitchPath, "f0_resynthesized_wavs") for tmpPath in [pitchTierPath, resynthesizedPath]: utils.makeDir(tmpPath) # 1. Prepare the data for morphing - acquire the segments to merge # (Done elsewhere, with the input fed into this function) # 2. Morph the fromData to the toData try: finalOutputList = morph_sequence.morphChunkedDataLists(fromPitchData, toPitchData, stepList) except IndexError: raise MissingPitchDataException() fromPitchData = [row for subList in fromPitchData for row in subList] toPitchData = [row for subList in toPitchData for row in subList] # 3. Save the pitch data and resynthesize the pitch mergedDataList = [] for i in range(0, len(finalOutputList)): outputDataList = finalOutputList[i] if keepPitchRange is True: outputDataList = morph_sequence.morphRange(outputDataList, fromPitchData) if keepAveragePitch is True: outputDataList = morph_sequence.morphAveragePitch(outputDataList, fromPitchData) stepOutputName = "%s_%0.3g" % (outputName, stepList[i]) pitchFNFullPath = join(pitchTierPath, "%s.PitchTier" % stepOutputName) outputFN = join(resynthesizedPath, "%s.wav" % stepOutputName) pointObj = dataio.PointObject2D(outputDataList, dataio.PITCH, 0, fromDuration) pointObj.save(pitchFNFullPath) outputTime, outputVals = zip(*outputDataList) mergedDataList.append((outputTime, outputVals)) praat_scripts.resynthesizePitch(praatEXE, fromWavFN, pitchFNFullPath, outputFN, outputMinPitch, outputMaxPitch) # 4. (Optional) Plot the generated contours if doPlotPitchSteps: fromTime, fromVals = zip(*fromPitchData) toTime, toVals = zip(*toPitchData) plot_morphed_data.plotF0((fromTime, fromVals), (toTime, toVals), mergedDataList, join(pitchTierPath, "%s.png" % outputName))