【问题标题】:Look for multiple words in praat script在 praat 脚本中查找多个单词
【发布时间】:2018-04-03 08:09:18
【问题描述】:

我正在编写一个 praat 脚本,它将在多个文件中搜索单词列表。这是我到目前为止所拥有的。它只放大到过程中的第一个单词,而不遍历其余单词。我认为这与选择的内容有关。对于For i through n,只选择了文本网格,但在注释器中,两者都被选中。我需要脚本继续搜索每个区间,以便也可以找到过程中的其他单词。

directory$ = "directory"
listfile$ = "test.txt"

Read Strings from raw text file... 'directory$'/'listfile$'
last = Get number of strings

# loop through each file
for a from 1 to last
    listfile2$ = listfile$ - ".txt"
    select Strings 'listfile2$'
    textgrid$ = Get string... 'a'
    Read from file... 'directory$'/'textgrid$'
    object_name$ = selected$("TextGrid")

    Read from file... 'directory$'/'object_name$'.wav

    # rearrange tiers 
    select TextGrid 'object_name$'
    Duplicate tier: 3, 1, "MAU"
    Remove tier: 4
    Insert interval tier: 1, "subphone"

    # find target word
    n = Get number of intervals: 3  
    for i to n

@instance: "strikes"
@instance: "raindrops"
@instance: "and"
@instance: "rainbow"
@instance: "into"
@instance: "round"
@instance: "its"
@instance: "its"

procedure instance: .target_word$

    label$ = Get label of interval: 3, i
        if label$ == .target_word$
        index = i
        i += n

# get the start and end point of the word
startpoint = Get starting point... 3 index
endpoint = Get end point... 3 index

        select TextGrid 'object_name$'
        plus Sound 'object_name$'
        View & Edit
        editor TextGrid 'object_name$'

# annotation
Select... startpoint endpoint
Zoom to selection
pause Annotate stops then continue
Close
endeditor

        endif # if the label = target word
    endfor # for number of intervals



select TextGrid 'object_name$'
Write to text file: directory$ + "/" + object_name$ + "_editedtext.TextGrid"

select all
minus Strings 'listfile2$'
Remove

endproc

#writeInfoLine: "done!"
#select Strings 'listfile2$'
endfor # for each of the files
clearinfo
print That's it!

编辑:这是根据答案修改后的脚本。

directory$ = "/Users/directorypath"
listfile$ = "test.txt"

Read Strings from raw text file... 'directory$'/'listfile$'
last = Get number of strings
listfile2$ = listfile$ - ".txt"

# loop through each file
for a from 1 to last
    select Strings 'listfile2$'
    textgrid$ = Get string... 'a'
    Read from file... 'directory$'/'textgrid$'
    object_name$ = selected$("TextGrid")
    Read from file... 'directory$'/'object_name$'.wav

    # rearrange tiers
    select TextGrid 'object_name$'
    Duplicate tier: 3, 1, "MAU"
    Remove tier: 4
    Insert interval tier: 1, "subphone"

    n = Get number of intervals: 3

    for i to n
        @instance: "strikes"
        @instance: "raindrops"
        @instance: "and"
        @instance: "rainbow"
        @instance: "into"
        @instance: "round"
        @instance: "its"
        @instance: "its"

    endfor
endfor

procedure instance: .target_word$

label$ = Get label of interval: 3, i
if label$ == .target_word$
    index = i
    i += n

    # get the start and end point of the word
    startpoint = Get starting point... 3 index
    endpoint = Get end point... 3 index

    select TextGrid 'object_name$'
    plus Sound 'object_name$'
    View & Edit
    editor TextGrid 'object_name$'

    # annotation
    Select... startpoint endpoint
    Zoom to selection
    pause Annotate stops then continue
    Close
    endeditor

    endif

endproc

【问题讨论】:

    标签: phonetics praat


    【解决方案1】:

    您编写的脚本没有很仔细地缩进,所以我尝试对其进行格式化,以便更容易理解发生了什么。从某种意义上说,确实如此。但是浮出水面的东西仍然需要一些努力才能理解。

    下面是对正在发生的事情的分步跟进,正如 Praat 所看到的:

    1. 在第 8 行开始一个 for 循环:for a from 1 to last

    2. 在该循环中,在第 25 行,您开始第二个循环:for i to n

    3. 在第二个循环中,在第 27 行,您调用了一个名为 instance 的过程。

      此时,Praat 跳到定义该过程的 last 行(因此,如果您多次定义它,您只会得到最后一个)。由于只有一个,Praat 跳转到第 36 行:procedure instance: .target_word$

    4. 在该过程中(顺便说一下,它是在 for 循环中定义的,这很不寻常)您有一个 if 块:if label$ == .target_word$

    5. 在该块的末尾,endfor 增加 控制变量(在本例中为 i)并关闭 for 循环。但是哪一个

      您可能希望它关闭我们输入的最后一个 for 循环(这就是我所做的)。但实际上,Praat 似乎会跟踪打开 for 和关闭 endfor 语句,并将它们垂直映射。

      我没有足够详细地查看解释器来弄清楚确切会发生什么,但在这种情况下,结果与映射最低endfor(=最接近脚本底部的一个)到最高的for,依此类推。

      (这可能不是真正发生的事情(否则多个非重叠循环将不起作用),但这并不重要:重要的是 endfor仅关闭 一个 for,无论它在脚本中的什么位置或 Praat 何时看到它。顺便说一句,这 不是 endproc.)

      不管精确的规则如何,这个endfor 被映射到第二个for,我们在第 2 点(即第 25 行)中输入了它。所以我们回到 that 循环的第一行(第 26 行)。

    6. 现在我们第二次进入第 27 行(这次是第二次间隔),我们再次调用@instance: "strikes"。我们还没到@instance: "raindrops"

    7. 这对所有间隔重复,每次将 i 递增 1(每当我们点击 endfor 时),直到 i 变为 n。这一次,当我们调用@instance 时,我们通过if 块,我们再次从第5 点到达endfor

      Praat 顺从地增加控制变量(所以现在是i = n + 1),并检查在 for 循环开始时设置的结束条件。在这种情况下,Praat 知道 for 循环在 i == n 时结束,并且由于 i = n + 1,它不会跳回顶部,而是继续前进。

      只有现在,在经历了第一个文件的所有间隔之后,我们是否真的到了程序的结尾

    8. 程序最终结束。 Praat 记得我们早在第 3 点就输入了这个过程,那时我们正在读取第 27 行。所以,尽职尽责地读取第 28 行,这是对同一过程的另一个调用:@instance: "raindrops"

    9. 这就是(最终!)它死亡的地方。

      它死了,因为控制变量 i 现在是 n + 1(它变成了第 7 点)。这通常不会发生,因为您通常不会为已经完成的循环点击endfor 语句。但在这种情况下,我们这样做。因此,当Praat 尝试在具有i-1 间隔的TextGrid 中读取间隔i 的标签时......它抱怨说间隔数太大。因为它是。

      您最初的问题(它只完成了部分工作,实际上并没有死)我无法重现,因为在 if 块中您实际上手动更改了 i 的值(这是有风险的),并且 if 块只有在标签足够早地在 TextGrid 中匹配时才会执行(足够早,以便它在脚本爆炸之前发生)。

    您可以通过脚本结构的这个简化版本看到整个混乱情况:

    last = 10
    for a from 1 to last
      appendInfoLine: "First line of main loop; a = ", a
    
      n = 5 
      for i to n
        appendInfoLine: "First line of second loop; i = ", i
    
        @instance: "strikes"
        @instance: "raindrops"
        @instance: "and"
    
        procedure instance: .target_word$
          appendInfoLine: "Called @instance: " + .target_word$
          appendInfoLine: "a=", a, " i=", i
    
      endfor # for number of intervals
    
          appendInfoLine: "End of @instance"
        endproc
    
      appendInfoLine: "Script claims we are done!"
    endfor # for each of the files
    

    要解决此问题,您可能应该重新构建代码结构,使其或多或少遵循以下模式:

    for a to last
      for i to n
        @instance: "word"
      endfor
    endfor
    
    procedure instance: .word$
      # do things
    endproc
    

    这是很有教育意义的。 :)

    【讨论】:

    • 非常感谢,这很有教育意义。我已经清理了很多脚本。但是,我在 if 循环中仍然遇到同样的问题。我收到错误消息“get label of interval not available for current selection”(我猜是因为此时选择了文本网格和声音。)我不知道如何修复它,使它成为一个循环,只是选择了文本网格 - 或者这甚至不是问题。我将我的新脚本粘贴到我原来的帖子中。
    • 看来您已经找到了答案。赞!但如果我是你,我会在你的问题中保留脚本的原始版本。特别是因为我通过行号多次引用它,现在这些对于新来这个问题的人来说几乎没有意义。不过,您仍然应该能够通过查看问题的编辑历史来查看原始脚本。但这是一个额外的步骤。
    【解决方案2】:

    尝试在过程初始化之后添加select TextGrid 'object_name$'

    procedure instance: .target_word$
    
        select TextGrid 'object_name$'
    
        label$ = Get label of interval: 3, i
        if label$ == .target_word$
             index = i
             i += n
    

    【讨论】:

    • 我认为这行得通,但现在我收到一条错误消息:“间隔太大:脚本第 48 行未执行或完成 >菜单命令“运行”未完成。”
    【解决方案3】:

    我让它工作了! for 循环上的 manual page 很有帮助。如果有人觉得有用的话,这里是代码。

    #############################################################
    #
    # This script requires a file listing the .Textgrid files 
    # in the directory containing the .wav files and .Textgrid files.
    # Using the command line, you can make this by navigating to the directory,
    # and typing ls *.TextGrid > contents.txt
    #
    # This script reads in files and textgrids from a directory,
    # rearranges the tiers that were output by MAUS, - http://www.bas.uni-muenchen.de/Bas/BasMAUS.html
    # provides a subphone tier, searches for words specified in the procedure
    # so that they can be annotated.
    #
    # Written using code from Bert Remijsen that was rewritten by Peggy Renwick
    #
    #############################################################
    
    # enter your directory here
    directory$ = "/Users/lisalipani/Documents/School/Graduate/Research/NSP/CorpusFiles/Test"
    
    # enter your list file here
    listfile$ = "test.txt"
    
    Read Strings from raw text file... 'directory$'/'listfile$'
    last = Get number of strings
    listfile2$ = listfile$ - ".txt"
    
    # loop through each file
    for a from 1 to last
        select Strings 'listfile2$'
        textgrid$ = Get string... 'a'
        Read from file... 'directory$'/'textgrid$'
        object_name$ = selected$("TextGrid")
        Read from file... 'directory$'/'object_name$'.wav
    
        # rearrange tiers
        select TextGrid 'object_name$'
        Duplicate tier: 3, 1, "MAU"
        Remove tier: 4
        Insert interval tier: 1, "subphone"
    
        # input target words here
        @instance: "strikes"
        @instance: "friends"
    
        # start the procedure
        procedure instance: .target_word$
    
        select TextGrid 'object_name$'
    
        numberOfIntervals = Get number of intervals: 3
    
        for intervalNumber from 1 to numberOfIntervals
            label$ = Get label of interval: 3, intervalNumber
            if label$ == .target_word$
    
                # get the start and end point of the word
                startpoint = Get starting point... 3 intervalNumber
                endpoint = Get end point... 3 intervalNumber
    
                select TextGrid 'object_name$'
                plus Sound 'object_name$'
                View & Edit
                editor TextGrid 'object_name$'
    
                # annotation
                Select... startpoint endpoint
                Zoom to selection
                pause Annotate stops then continue
                Close
                endeditor
    
                select TextGrid 'object_name$'
    
            endif
        endfor
        endproc
    
        select TextGrid 'object_name$'
        Save as text file... 'directory$'/'object_name$'_annotated.TextGrid
    
    endfor
    appendInfoLine: "all done!"
    

    【讨论】:

      猜你喜欢
      • 2019-03-01
      • 2016-07-01
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-21
      相关资源
      最近更新 更多