邵鹏飞老师制作 http://www.bubuko.com/infodetail-9283.html Praat对声音的标注,通常在研究语料不太多的情况下,完全手工进行,但是如果语料数据很多,这种方式会非常慢,以中英文为例,需要进行音段的详细标注,如果有更好的方式进行自动音段对齐,将会节省很多时间,英文有 SPPAS 这样的工具,但是对于初学者来说,并不容易掌握,在这里如果通过使用脚本的方式,将声音文件和标注文本进行一个对应,这里的对应只能以时长平均值的形式出现,并不是完全意义上的音段对齐,也将节省很多时间,而且对于初学者来说,只是掌握一个脚本的使用就可以。而且这个脚本适用于篇章,有些音段对齐的工作可能对于很长的声音文件并不是很方便,这里的方式,将会解决这个问题。 首先将长篇章的语料标注出句子序号: 只保留一层即可。 其次,制作文本句子对应的序号列表: 表头要符合上面的名称。所谓syllable一列,主要是考虑到英语需要标注音节层,而在汉语中,这一列可改为汉字的拼音,都要以空格隔开。 将上述列表制作成文本文件,格式为Unicode格式。 然后在Praat里运行以下脚本: ######################################################################################################################################################################## #####Designed by Pengfei Shao feipengshao@163.com ######################################################################################################################################################################## #### 以篇章为处理对象,能够做到将内容自动添加进标注中,但是无法强制对齐,只是根据时间平均添加。 #### 要求: #### 1.有声音文件 #### 2.声音文件有一层标注,标注内容是声音文件的分组,以1,2,3,4,分开,每一个数字代表一句话,或者一个短语 #### 3.制作和上述分组内容对应的文本文件,要求为Unicode格式,文本文件有三列,第一列是和上面对应的序号,表头为order #### ,第二列是sentence ,如果是中文就是序号代表的汉字句子,如果是英文就是英语句子,第三列是syllable,如果是中文是拼音,如果是英语还是句子 #### 4.汉语会产生至少三层,句子层是汉语句子,单词层是拼音,声韵层是产生的声韵母切分开,英语产生四层,句子层是句子,单词层是单词分开,还有音节层和音段层 ######################################################################################################################################################################## #### 2013.9.24 对于汉语拼音,能够对不同类型的音分别标注不同,如zhi标为zh iii等 #### 2013.9.25 filename一列既可以是文件名称,也可以是带扩展名 #### 2013.9.26 添加对于英语的音段的处理 #### 2014.1.12 将这个脚本修改为对于篇章的处理 ######################################################################################################################################################################## form information comment 请输入句子标注层级: positive tier_number 1 comment 请输入声音文件所在的目录: comment (产生的TextGrid将会保存在声音文件所在的目录) text openpath E:\oldwav comment 请输入产生的新Textgrid保存目录: text savepath E:\newTextGrid comment comment 请输入文本文档所在的路径和文件名称: comment (格式是TAB间隔) text textPath E:\txt\ text textFileName en.txt comment 选择语言种类: optionmenu language_of_text: 1 option English option Chinese endform if right$(openpath$,1)<>"\" openpath$=openpath$+"\" endif if right$(savepath$,1)<>"\" savepath$=savepath$+"\" endif if right$(textPath$,1)<>"\" textPath$=textPath$+"\" endif textPath$=textPath$+textFileName$ ################################################# # 读内容列表 Read Table from tab-separated file... 'textPath$' txtSimpleName$=selected$("Table",1) numOfRows=Get number of rows for iRows from 1 to numOfRows # fileNameOfTxt'iRows'$=Get value... 'iRows' filename sentence'iRows'$=Get value... 'iRows' sentence order'iRows'$=Get value... 'iRows' order syllable'iRows'$=Get value... 'iRows' syllable endfor ################################################# Create Strings as file list... fileList 'openpath$'*.wav numOfWavFiles=Get number of strings for ifile from 1 to numOfWavFiles select Strings fileList fileName$=Get string... 'ifile' Read from file... 'openpath$''fileName$' simpleName$=selected$("Sound",1) textGridName$=simpleName$+".TextGrid" wavName$=simpleName$+".wav" Read from file... 'openpath$''textGridName$' select TextGrid 'simpleName$' Set tier name... 1 sentence numberOfIntervals=Get number of intervals... 'tier_number' ### 将有句子号的一层复制到第二层,并清空 if language_of_text=1 Duplicate tier... 1 2 word else Duplicate tier... 1 2 word Duplicate tier... 1 3 PY endif for iIntervals from 1 to numberOfIntervals select TextGrid 'simpleName$' labelOfIntervalOne$=Get label of interval... 'tier_number' 'iIntervals' begin_interval=Get start point... 'tier_number' 'iIntervals' end_interval=Get end point... 'tier_number' 'iIntervals' if labelOfIntervalOne$<>"" for iRows from 1 to numOfRows orderContent$=order'iRows'$ if orderContent$=labelOfIntervalOne$ sentenceDetails$=sentence'iRows'$ syllableDetails$=syllable'iRows'$ endif endfor tempSenDetails$=sentenceDetails$ tempSylDetails$=syllableDetails$ if language_of_text=1 r1=rindex(tempSenDetails$," ") len1=length(tempSenDetails$) iSen=1 #### 将空格隔开的单词分开 repeat senStrEach'iSen'$=mid$(tempSenDetails$,r1,len1) t1$=senStrEach'iSen'$ tempSenDetails$=tempSenDetails$-t1$ r1=rindex(tempSenDetails$," ") len1=length(tempSenDetails$) iSen=iSen+1 until r1=0 senStrEach'iSen'$=tempSenDetails$ totalWordNumber=iSen #### 隔开的单词是逆序的,调整顺序,并且删除单词前后的空格 newMark=1 for j from 1 to totalWordNumber mTemp=totalWordNumber+1-j t$=senStrEach'mTemp'$ if t$<>" " temp$=t$ len=length(temp$) repeat len=length(temp$) leftTemp$=left$(temp$,1) if leftTemp$=" " temp$=right$(temp$,len-1) endif rightTemp$=right$(temp$,1) if rightTemp$=" " temp$=left$(temp$,len-1) endif until leftTemp$<>" " and rightTemp$<>" " newSenStr'newMark'$=temp$ newMark=newMark+1 endif endfor wordNumber2=newMark-1 wavDuration2=end_interval-begin_interval stepTime=wavDuration2/wordNumber2 first_boundary=begin_interval last_boundary=end_interval ####添加第二层,单词层边界 for j from 1 to wordNumber2-1 bondaryTime=first_boundary+stepTime*j Insert boundary... 2 'bondaryTime' startBoundaryTwo'j'=first_boundary+stepTime*(j-1) endBoundaryTwo'j'=first_boundary+stepTime*j endfor startBoundaryTwo'wordNumber2'=first_boundary+stepTime*(wordNumber2-1) endBoundaryTwo'wordNumber2'=first_boundary+stepTime*wordNumber2 for j from 1 to wordNumber2 bondaryTime=first_boundary+stepTime*(j-1) newIntervalTemp=Get interval at time... 2 'bondaryTime' tempStrToTwo$=newSenStr'j'$ Set interval text... 2 'newIntervalTemp' 'tempStrToTwo$' endfor tempTimeForOne=first_boundary+stepTime newIntervalTempOne=Get interval at time... 1 'tempTimeForOne' Set interval text... 1 'newIntervalTempOne' 'sentenceDetails$' ####这个else是选择语言类型为英语还是汉语 else r1=rindex(tempSylDetails$," ") len1=length(tempSylDetails$) iSyl=1 repeat sylStrEach'iSyl'$=mid$(tempSylDetails$,r1,len1) t1$=sylStrEach'iSyl'$ tempSylDetails$=tempSylDetails$-t1$ r1=rindex(tempSylDetails$," ") len1=length(tempSylDetails$) iSyl=iSyl+1 until r1=0 sylStrEach'iSyl'$=tempSylDetails$ totalSyllableNumber=iSyl newMark=1 for j from 1 to totalSyllableNumber mTemp=totalSyllableNumber+1-j t$=sylStrEach'mTemp'$ if t$<>" " temp$=t$ len=length(temp$) repeat len=length(temp$) leftTemp$=left$(temp$,1) if leftTemp$=" " temp$=right$(temp$,len-1) endif rightTemp$=right$(temp$,1) if rightTemp$=" " temp$=left$(temp$,len-1) endif until leftTemp$<>" " and rightTemp$<>" " newSylStr'newMark'$=temp$ newMark=newMark+1 endif endfor syllableNumber3=newMark-1 wavDuration2=end_interval-begin_interval stepTime=wavDuration2/syllableNumber3 first_boundary=begin_interval last_boundary=end_interval ####添加第二层 stepTime2=stepTime/2 for j from 1 to syllableNumber3-1 bondaryTime=first_boundary+stepTime*j Insert boundary... 2 'bondaryTime' Insert boundary... 3 'bondaryTime' insideBoundaryTime=bondaryTime-stepTime2 Insert boundary... 3 'insideBoundaryTime' endfor insideBoundaryTime=last_boundary-stepTime2 Insert boundary... 3 'insideBoundaryTime' for j from 1 to syllableNumber3 bondaryTime=first_boundary+stepTime*(j-1) newIntervalTemp=Get interval at time... 2 'bondaryTime' tempStrToTwo$=newSylStr'j'$ Set interval text... 2 'newIntervalTemp' 'tempStrToTwo$' endfor tempTimeForOne=first_boundary+stepTime newIntervalTempOne=Get interval at time... 1 'tempTimeForOne' Set interval text... 1 'newIntervalTempOne' 'sentenceDetails$' ### 添加第三层音段层!! markThree=1 actual_Three'markThree'$="sil" for j from 1 to syllableNumber3 bondaryTime00=first_boundary+stepTime*(j-1) tempIntervalNum22=Get interval at time... 2 bondaryTime00 t$=Get label of interval... 2 'tempIntervalNum22' lenOfThis=length(t$) if t$<>"sil" bondaryTime=first_boundary+stepTime*j beginBoundaryTime=first_boundary+stepTime*(j-1) # 以第二层为中心,以时间点为联系,求出第三层的interval序列 intervalNumThree1=Get interval at time... 3 beginBoundaryTime intervalNumThree2=Get interval at time... 3 bondaryTime intervalNumThree2=intervalNumThree2-1 # 主要是考察zh ch sh的问题,所以提取头两个字符和一个字符以此判断 ctext1$=left$(t$,1) ctext2$=left$(t$,2) # 当是zh ch sh时 mtext$=mid$(t$,2,lenOfThis-1) Set interval text... 3 'intervalNumThree1' 'ctext1$' Set interval text... 3 'intervalNumThree2' 'mtext$' if ctext2$="zh" or ctext2$="sh" or ctext2$="ch" Set interval text... 3 'intervalNumThree1' 'ctext2$' mtext$=mid$(t$,3,lenOfThis-2) mtext2$=mid$(t$,3,lenOfThis-3) tone$=right$(t$,1) if mtext2$="i" mtext$="iii"+tone$ endif if mtext2$="ui" mtext$="uei"+tone$ endif if mtext2$="un" mtext$="uen"+tone$ endif if mtext2$="iu" mtext$="iou"+tone$ endif if mtext2$="ui" mtext$="uei"+tone$ endif Set interval text... 3 'intervalNumThree2' 'mtext$' endif if (ctext1$="z" or ctext1$="s" or ctext1$="c") and ctext2$<>"zh" and ctext2$<>"sh" and ctext2$<>"ch" Set interval text... 3 'intervalNumThree1' 'ctext1$' mtext$=mid$(t$,2,lenOfThis-1) mtext2$=mid$(t$,2,lenOfThis-2) tone$=right$(t$,1) if mtext2$="i" mtext$="ii"+tone$ endif Set interval text... 3 'intervalNumThree2' 'mtext$' endif if ctext1$="j" or ctext1$="q" or ctext1$="x" Set interval text... 3 'intervalNumThree1' 'ctext1$' mtext$=mid$(t$,2,lenOfThis-1) mtext2$=mid$(t$,2,lenOfThis-2) tone$=right$(t$,1) if mtext2$="u" mtext$="v"+tone$ endif Set interval text... 3 'intervalNumThree2' 'mtext$' endif if ctext1$="y" nextStr$=mid$(t$,2,1) if nextStr$="i" mtext$=mid$(t$,2,lenOfThis-1) Remove right boundary... 3 'intervalNumThree1' Set interval text... 3 'intervalNumThree1' 'mtext$' else mtext2$=mid$(t$,2,lenOfThis-2) mtext$=mid$(t$,2,lenOfThis-1) mtext$="i"+mtext$ Remove right boundary... 3 'intervalNumThree1' Set interval text... 3 'intervalNumThree1' 'mtext$' tone$=right$(t$,1) if mtext2$="u" mtext$="v"+tone$ Set interval text... 3 'intervalNumThree1' 'mtext$' endif endif endif if ctext1$="w" nextStr$=mid$(t$,2,1) if nextStr$="u" mtext$=nextStr$ Remove right boundary... 3 'intervalNumThree1' Set interval text... 3 'intervalNumThree1' 'mtext$' else mtext$=mid$(t$,2,lenOfThis-1) mtext$="u"+mtext$ Remove right boundary... 3 'intervalNumThree1' Set interval text... 3 'intervalNumThree1' 'mtext$' endif endif endif endfor # 这个是语言选择的结束 endif endif endfor ########################################################### if language_of_text=1 Duplicate tier... 2 3 syllable Duplicate tier... 3 4 phon endif ########################################################### Write to text file... 'savepath$''textGridName$' select Sound 'simpleName$' Remove select TextGrid 'simpleName$' Remove endfor select Strings fileList Remove select Table 'txtSimpleName$' Remove exit 脚本运行结束!