#this script cluster sound extractions of the same tone categories together #first it iterates through all intervals in all the files selected, finds all tone 1 segments, extract them, and cluster them into one sound file with silences in #between; then it does the same for the tone 2, tone3, etc. form Get Task Type comment Choice=1 if you want to concatenate sounds into a sound cluster comment and create textgrid comment Choice=2 if you already have those but want to add tiers to the comment textgrid of the cluster integer choice 1 endform nos=numberOfSelected ("Sound") echo n='nos' mos=numberOfSelected ("TextGrid") printline m='mos' if nos!=mos exit ERROR!PLEASE MAKE SURE YOU SELECTED THE SAME NUMBER OF SOUND AND TEXTGRID FILES. endif printline printline List of Sound Files for i to nos sound'i' = selected ("Sound", i); printline sound'i' endfor printline printline List of TextGrid Files for i to mos textgrid'i'=selected("TextGrid",i); printline textgrid'i' endfor printline if choice=1 select sound1 sampling_frequency = Get sampling frequency mySilenceB = Create Sound from formula... silence 2 0 0.2 sampling_frequency 0 endif #mode1=tone1, mode2=tone2,etc. for mode from 1 to 4 #SOME initializations totalNumOfTone=0; totalNumOfWords=0; #both j and q are variables declared before the main loop, thus it will keep counting the total numbers of intervals and interval durations for all the files processed, not being rest to 0 for every time;numOfTone is keeping count of the current loop j=0; q=0; pnt=0; mode$=string$ (mode) nos$=string$ (nos) if choice=2 filename$="tone_"+mode$+"_"+nos$+"_File_Concatenation.TextGrid" textCon=do ("Read from file...", filename$) endif #nos is number_of_sound for i from 1 to nos printline @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ printline @ NEXT FILE @@@@@@@ printline @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ printline i='i' select textgrid'i' #this variable is used to hold total number of tone 1 words across all the files selected #first find the tier number of Tone BJ #decide which tier is lyrics then find Tone BJ numOfTier=Get number of tiers for h to numOfTier tierName$=Get tier name... h; if (tierName$="lyrics") or (tierName$="Lyrics") tierLyrics=h; endif endfor tierToneBJ=tierLyrics+3; #noi is 'number of intervals' noiTBJ=Get number of intervals... tierToneBJ #########################TONE 1 WORDS######################## if mode=1 #count number of tone 1 intervals for the current file numOfTone=0; #this loop counts the number of tone x words in the current file for b to noiTBJ tone_label$=Get label of interval... tierToneBJ b word$=Get label of interval... tierToneBJ-2 b if tone_label$="H" interval[numOfTone]=b; numOfTone+=1; printline -----------------------word is 'word$' printline the number of tone 1 is 'b' endif endfor #-----check point for debugging printline number of tone1 word in file'i' so far is 'numOfTone' endif ###########################tone1 end############################# #########################TONE 2 WORDS######################## if mode=2 #count number of tone 1 intervals for the current file numOfTone=0; #this loop counts the number of tone x words in the current file for b to noiTBJ tone_label$=Get label of interval... tierToneBJ b word$=Get label of interval... tierToneBJ-2 b if tone_label$="MH" interval[numOfTone]=b; numOfTone+=1; printline -----------------------word is 'word$' printline the number of tone 2 is 'b' endif endfor #-----check point for debugging printline number of tone2 word in file'i' so far is 'numOfTone' endif ###########################tone2 end############################# #########################TONE 2 WORDS######################## if mode=3 #count number of tone 1 intervals for the current file numOfTone=0; #this loop counts the number of tone x words in the current file for b to noiTBJ tone_label$=Get label of interval... tierToneBJ b word$=Get label of interval... tierToneBJ-2 b if tone_label$="MLH" interval[numOfTone]=b; numOfTone+=1; printline -----------------------word is 'word$' printline the number of tone 3 is 'b' endif endfor #-----check point for debugging printline number of tone3 word in file'i' so far is 'numOfTone' endif ###########################tone3 end############################# #########################TONE 4 WORDS######################## if mode=4 #count number of tone 1 intervals for the current file numOfTone=0; #this loop counts the number of tone x words in the current file for b to noiTBJ tone_label$=Get label of interval... tierToneBJ b word$=Get label of interval... tierToneBJ-2 b if tone_label$="HL" interval[numOfTone]=b; numOfTone+=1; printline -----------------------word is 'word$' printline the number of tone 4 is 'b' endif endfor #-----check point for debugging printline number of tone4 word in file'i' so far is 'numOfTone' endif ###########################tone4 end############################# #now all the positions of all tone x word for the current file are stored in the interval[0] to interval [numOfTone1-1] array #these are ready to be extracted out of the sound files #but there is one problem if you store their positions across files #you can't know where does one file end and the other stop in these total numbers #so we probably need to extract all the instances of one file after process this file, and then move on to the next. #and these sound file names can be throughly indexed in one sequence #so before this 'endfor', we should extract sounds #which is also the reason we should handle tone 1 in this whole manner, then move on to tone 2. #if choice 1, extract all segments of tone x; ##########################Choice 1 to start extracting sound segments###################### #choice 1 is to process concatenation then generate the textgrid; #Choice 2 is to add tiers to textgrid; ############## if choice=1 ############## printline NOW PROCESSING CHOICE 'choice' (1) #first we need to get the beginning and end time of these interval targets to be extracted for k from 0 to numOfTone-1 select textgrid'i' start=Get start point... tierToneBJ interval[k] end=Get end point... tierToneBJ interval[k] #in fact, q and j are exactly the same value for each loop q+=1; labelWord$ [q]=Get label of interval... tierLyrics+1 interval[k] banshiInt=Get interval at time... tierLyrics-1 start+0.001 banshi$[q]=Get label of interval... tierLyrics-1 banshiInt artist$[q]=Get label of interval... 1 1 #now labelWord$[1] to labelWord$[totalNumOfTone] store the durations for all the targeted segment intervals across all files #'j' is a variable declared value 0 before the loop,so it does not reset to 0,but keeps counting the total number #across files, instead of starting from 0 for every file processed. #but the sound'j' is from sound'1' to sound'numOfTone' #the value of 'j' finally is also consistent with the value of totalNumOfTone select sound'i' sampling_frequency = Get sampling frequency select sound'i' #then we need to extract them and store them in an array of object variables j+=1; soundOne'j'= Extract part... start end rectangular 1 no mySilence = Create Sound from formula... silence 2 0 0.2 sampling_frequency 0 select soundOne'j' plus mySilence soundOneC'j'=Concatenate endfor printline there are 'j' extracted files printline ---------------- #this ends the choice 1 on extracting all sound segments endif ################################ends choice 1################################## ##################### CHOICE 2 EXECUTION: ADDING TIERS #################### #choice 2 is for adding tiers of info to existing concatenated sound and textgrid ############# if choice=2 ############# printline ------------------------------------ printline NOW PROCESSING CHOICE 'choice' (2) #here we add a tier of information regarding the position of words in a phrase #first we already have all the numbers of intervals with tone x words within the current file #for each tone x word, check if it is followed by ac interval #if it is, check if it is the last word in the current phrase (if its right boundary equals the right boundary of the corresponding tier 1 interval) #if it is not the last word, mark it is a unit boundary #if it is the last word, check if the phrase ends in a ',' or '.' #if it is ',' then it is phrase 1 boundary #if it is '.' then it is phrase 2 boundary #BUT FIRST WE STILL NEED TO STORE THE POSITION OF THESE IN AN ARRAY #SO THAT IT HOLDS THE POSITION ACROSS FILES FOR THE CONCATENATED FILE #BECAUSE FILE IS ALREADY CONCATENATED, YOU CANNOT PROCESS INDIVIDUAL FILES BECAUSE YOU DON'T HAVE THEM #YOU ONLY HAVE ONE BIG CONCATENATED FILES WITH WHOLE NUMBERING #TO STORE THE POSITIONS AND TEXT OF THE BOUNDARY WORDS: #FIRST STORE THE LOCATIONS IN AN ARRAY #THEN STORE THE TEXT IN AN ARRAY #JUST HOLD ON UNTIL LATER FOR LABEL SETTING #we will need two numbers, first pnc counts the number of boundaries in the current file for current tone x, it holds the numbering in the original file #the other, pnt, keep count on the total number of the boundaries in the concatenated file for tone x,not applicable to the original file of all tones #but here it seems that pnc is useless bc we are only interested in storing the total number of boundaries #pnt needs to be initialized to 0 before the file loop starts #pnc needs to be initialized to 0 at the beginning of every loop #loop through all words in current file #find tone x word that are boundaries #store the position of these words in the positionNum[0] to positionNum[pnc] for k from 0 to numOfTone-1 pnc=0; select textgrid'i' nextInterval$=Get label of interval... tierLyrics+1 interval[k]+1 if nextInterval$="ac" #relativize boundary positions to the current file bc the positionNum[] opreate on the concatenated file #stored position number of boundary intervals should be relative to the tone x #numbering in the concatenated file, not the original numbering of all tones #mixed positionNum[pnt]=totalNumOfTone+k+1; position[pnc]=interval[k]; #then check what kind of boundary this is startWord=Get start point... tierLyrics+1 interval[k] endWord=Get end point... tierLyrics+1 interval[k] #ifLastTier holds the interval number of the lyrics corresponding to the k'th interval in the word tier ifLastTier=Get interval at time... tierLyrics startWord+0.001 endTier=Get end point... tierLyrics ifLastTier #found computation error in the old algorithm for evaluating whether the current word is the last word in the phrase #due to the fact that sometimes the last interval in a phrase is 'ac', not a word #new algorithm checkLast=Get interval at time... tierLyrics+1 endTier-0.01 #checkLast is the number of the last interval of the phrase on word tier lastWord$=Get label of interval... tierLyrics+1 checkLast #in the case where the last interval is a 'ac', assign the last word the second to last interval if lastWord$="ac" checkLast=checkLast-1 endif #check if the current word is the last word if checkLast=interval[k] lastLyrics$=Get label of interval... tierLyrics ifLastTier lastPunc1=rindex (lastLyrics$, ",") lastPunc2=rindex (lastLyrics$, ".") lastPunc3=rindex (lastLyrics$, ",") lastPunc4=rindex (lastLyrics$, "。") #case1: the phrase ends in coma #P1B=PHRASE 1 BOUNDARY; P2B=PHRASE 2 BOUNDARY; UB=UNIT BOUNDARY if ((lastPunc1!=0) or (lastPunc3!=0)) positionLabel$ [pnt]="P1B" #HOLD ON TIL LATER # select textCon # Duplicate tier... 1 3 position # do("Set interval text...", 3, 2*k, "P1B") #case2: the phrase ends in stop elsif ((lastPunc2!=0) or (lastPunc4!=0)) positionLabel$ [pnt]="P2B" # select textCon # Duplicate tier... 1 3 position # do("Set interval text...", 3, 2*k, "P2B") endif else positionLabel$ [pnt]="UB" # select textCon # Duplicate tier... 1 3 position #interval[k] has the info of k'th tone x word in the original file and in the concatenated file #the order of the words are preserved in the new concatenated file #so we only need 2*k to compute the position of the k'th word in the new file # do("Set interval text...", 3, 2*k,"UB") endif #this must be here because only if in the 'ac' case pnt count +1; printline ------------------------------------- printline currently finished processing boundary 'pnt' boun=position[pnc] appendInfoLine ("boundary number in origial file is ", boun," in file ", i) appendInfoLine ("boundary number in con file is", positionNum[pnt]) appendInfoLine ("boundary text is ", positionLabel$[pnt]) boundaryWord$=Get label of interval... tierLyrics+1 boun appendInfoLine ("the boundary word is ", boundaryWord$) pnt+=1; pnc+=1; # NOW WE EXPECT positionNum[0] to [pnt-1] hold all the boundary positions #and positionLabel$[0] to [pnt-1] hold all the boundary labels endif endfor endif ################## CHOICE 2 END ################################## totalNumOfTone=totalNumOfTone+numOfTone; totalNumOfWords=totalNumOfWords+noiTBJ; printline total number of tone is 'totalNumOfTone' printline total number of words so far in 'i' textgrid(s) is 'totalNumOfWords' printline total number of boundary word in 'i' file(s) is 'pnt' so far endfor ##################### CHOICE 1 to concatenate and generate textgrid################### #now start to concatenate on choice 1 if choice=1 #by this point, all the segments across files containing tone x melodies are created #then we concatenate appendInfoLine("total number of tone ",mode, " in ", i-1, " files is ", totalNumOfTone) printline there are 'j' extracted files select mySilenceB plus soundOneC1 for r from 2 to j plus soundOneC'r' endfor toneOneSoundTotal=Concatenate printline Tone1 sounds are concatenated. select toneOneSoundTotal do("Save as WAV file...", "tone_"+mode$+"_"+nos$+"_File_Concatenation.wav") select mySilence Remove for t from 1 to j select soundOneC't' plus soundOne't' Remove endfor #now creating the textgrid for the current tone x concatenated sound select toneOneSoundTotal intensity=To Intensity... 100 0 select intensity textgridCon=do("To TextGrid (silences)...", -75.0, 0.1, 0.05, "silent", "") Duplicate tier... 1 2 banshi Duplicate tier... 1 3 artist #set the labels for the textgridCon file for g from 1 to j do("Set interval text...", 1, 2*g, labelWord$[g]) do("Set interval text...", 2, 2*g, banshi$[g]) do("Set interval text...", 3, 2*g, artist$[g]) endfor do("Save as text file...", "tone_"+mode$+"_"+nos$+"_File_Concatenation.TextGrid") #this ends choice 1 concatenation and create textgrid endif #################### ENDS CHOICE 1 EXECUTION############################### ############### CHOICE 2 EXECUTION ###################### if choice=2 select textCon numTier=Get number of tiers numItv=Get number of intervals... 1 Duplicate tier... 1 numTier+1 position empti$="" for g from 1 to numItv do("Set interval text...", numTier+1, g, empti$) endfor for k from 0 to pnt-1 do("Set interval text...", numTier+1, 2*positionNum[k], positionLabel$[k] ) endfor ############ CHOICE 2 END ########################## endif #this ends the mode loop do("Save as text file...", "tone_"+mode$+"_"+nos$+"_File_Concatenation.TextGrid") endfor