From 8d289a1d29d461b512fd8d5f046793c2e242642a Mon Sep 17 00:00:00 2001 From: Rob van Son Date: Tue, 6 Dec 2016 15:11:58 +0100 Subject: [PATCH] Rebuild creaky voice detector for third tones --- ToneProt/SGC_ToneProt.praat | 168 ++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 85 deletions(-) diff --git a/ToneProt/SGC_ToneProt.praat b/ToneProt/SGC_ToneProt.praat index baa02e6..db4e34d 100644 --- a/ToneProt/SGC_ToneProt.praat +++ b/ToneProt/SGC_ToneProt.praat @@ -137,121 +137,119 @@ procedure sgc_ToneProt sgc_ToneProt.currentSound$ sgc_ToneProt.pinyin$ sgc_ToneP # If there is a third tone, replace creaky voice by low pitch # ################################################################ + toneProt.creackyThree = 0 if index(sgc_ToneProt.pinyin$, "3") + # Lowest point for tone 3 is 1 octave and 3st below the top line + # The cut-off is 0,05 quantile of model + 1/2 semitones + .creakCO = 0.030 - .delta = 0.0000001 - # Reassign creacky voice parts # Calculate Shimmer&Jitter select Sound Source .sound = selected("Sound") call createJitterShimmerContour .sound .jitterShimmer = selected("Sound") - .numSamples = Get number of samples - .voiceTier = To TextGrid: "voice", "" # Determine the low F0 part of the 3rd tone - # Generate word + # Generate word with voiceless low 3rd tone .newPinyin$ = replace_regex$(sgc_ToneProt.pinyin$, "3(?=[^0-9]+3)", "2", 0) .newPinyin$ = replace$(.newPinyin$, "3", "9", 0) call generateWord Pitch '.newPinyin$' 'sgc_ToneProt.register' select Pitch '.newPinyin$' - .generatedWord = selected("Pitch"); -pause + .generatedWord9 = selected("Pitch") - # Create a tier with creaky voice intervals - select .jitterShimmer - .prevV = Get value at sample number: 0, 1 + select Pitch 'sgc_ToneProt.pinyin$' + .generatedWord3 = selected("Pitch") + # Lower cutoff is 1/2 semitone above the 0.05 quantile + .lowerCutOff = Get quantile: 0, 0, 0.05, "Hertz" + .lowerCutOff /= sqrt(toneScript.oneSemit) + + # Create a tier with low part of the third tone as intervals + select .generatedWord3 + .modelDuration = Get total duration + .numFrames = Get number of frames + .prevV = Get value in frame: 1, "Hertz" + if .prevV = undefined or .prevV <= 0 + .prevV = sgc_ToneProt.register + endif .prevT = 0 .numIntervals = 1 - select .voiceTier - if .prevV > .creakCO - Set interval text: 1, .numIntervals, "creaky" - elsif .prevV <= .creakCO - Set interval text: 1, .numIntervals, "normal" + .pitchTier = Create TextGrid: 0, .modelDuration, "pitch", "" + select .pitchTier + if .prevV > .lowerCutOff + Set interval text: 1, .numIntervals, "NotLow" + elsif .prevV <= .lowerCutOff + Set interval text: 1, .numIntervals, "3Low" endif - for .s to .numSamples - select .jitterShimmer - .frameT = Get time from sample number: .s - .value = Get value at sample number: 0, .s - if .value > .creakCO and .prevV <= .creakCO - select .voiceTier + .lowPresent = 0 + for .s to .numFrames + select .generatedWord3 + .frameT = Get time from frame number: .s + .value = Get value in frame: .s, "Hertz" + if .value = undefined or .value <= 0 + .value = sgc_ToneProt.register + endif + if .value > .lowerCutOff and .prevV <= .lowerCutOff + select .pitchTier Insert boundary: 1, (.frameT+.prevT)/2 .numIntervals += 1 - Set interval text: 1, .numIntervals, "creaky" - elsif .value <= .creakCO and .prevV > .creakCO - select .voiceTier + Set interval text: 1, .numIntervals, "NotLow" + elsif .value <= .lowerCutOff and .prevV > .lowerCutOff + select .pitchTier Insert boundary: 1, (.frameT+.prevT)/2 .numIntervals += 1 - Set interval text: 1, .numIntervals, "normal" + Set interval text: 1, .numIntervals, "3Low" + .lowPresent += 1 endif .prevV = .value .prevT = .frameT endfor - # Create PitchTier and Voicing intervals - select te.recordedPitch - .origPointProcess = To PointProcess - .vuvTier = To TextGrid (vuv): 0.02, 0.01 - - select te.recordedPitch - .recordedPitchTier = Down to PitchTier - - # Devoice creaky voice parts - select .voiceTier - .numIntervals = Get number of intervals: 1 -.numIntervals = 0 - for .v to .numIntervals - select .voiceTier - .label$ = Get label of interval: 1, .v - if .label$ = "creaky" - .start = Get starting point: 1, .v - .end = Get end point: 1, .v - if .end > .start - select .recordedPitchTier - # Store begin and endvalues of pitch - .startValue = Get value at time: .start - .endValue = Get value at time: .end - - # Remove all pitch points between start and end - Remove points between: .start, .end - - # Add begin and en values at start and end times - Add point: .start, .startValue - Add point: .end, .endValue - - # Interpolate or add low pitch values in between start and end times if the interval is long - if .end - .start > 0.040 - Add point: .start + .delta, minimumModelFzero - Add point: .end - .delta, minimumModelFzero + # DTW of .generatedWord9 with sourcePitch + if .lowPresent > 0 + select te.recordedPitch + plus .generatedWord3 + .dtw3 = noprogress To DTW... 24 10 yes yes no restriction + Rename... DTW'.generatedWord9' + .distance3 = Get distance (weighted) + select te.recordedPitch + plus .generatedWord9 + .dtw9 = noprogress To DTW... 24 10 yes yes no restriction + Rename... DTW'.generatedWord9' + .distance9 = Get distance (weighted) + + .dtw = .dtw3 + if .dtw3 > .dtw9 + .dtw = .dtw9 + endif + select .pitchTier + .numPitchIntervals = Get number of intervals: 1 + for .i to .numPitchIntervals + select .pitchTier + .label$ = Get label of interval: 1, .i + if .label$ = "3Low" + .modelStart = Get starting point: 1, .i + .modelEnd = Get end point: 1, .i + select .dtw + .origStart = Get x time from y time: .modelStart + .origEnd = Get x time from y time: .modelEnd + select .jitterShimmer + .mean = Get mean: 0, .origStart, .origEnd + if .mean > .creakCO + toneProt.creackyThree += 1; endif endif - - endif - endfor - - # Convert new Pitchtier to Pitch object (based on old Pitch object) - select te.recordedPitch - plus .recordedPitchTier - .newPitch = To Pitch + endfor + select .dtw3 + plus .dtw9 + Remove + + toneProt.creackyThree /= .lowPresent + endif -# REMOVE -#pause - # Move new Pitch object to old Pitch object ID - select te.recordedPitch - .pitchName$ = selected$("Pitch") - Remove - te.recordedPitch = .newPitch - select .newPitch - Rename: .pitchName$ - .newPitch = 0 - # Clean up - select .origPointProcess - #plus .jitterShimmer - plus .vuvTier - plus .voiceTier - plus .recordedPitchTier - plus .generatedWord + select .jitterShimmer + plus .pitchTier + plus .generatedWord9 Remove endif -- 2.11.4.GIT