Estoy escribiendo un script praat que buscará en una lista de palabras a través de múltiples archivos. Esto es lo que tengo hasta ahora. Solo se acerca a la primera palabra del procedimiento y no se repite en el resto. Creo que esto tiene algo que ver con lo que se selecciona. Para For i through n, solo se selecciona la cuadrícula de texto, pero luego en el anotador, ambos están seleccionados. Necesito que el script continúe buscando a través de cada intervalo para que también se puedan encontrar las otras palabras en el procedimiento.

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!

Editar: Aquí está el guión revisado, basado en la respuesta.

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
0
Lisa 22 oct. 2017 a las 22:14

3 respuestas

La mejor respuesta

El guión que escribió no estaba sangrado con mucho cuidado, así que traté de formatearlo para que fuera más fácil de entender lo que estaba sucediendo. Y en cierto sentido, lo hizo. Pero lo que salió a la superficie tomó un esfuerzo para comprender, no obstante.

Aquí hay un seguimiento paso a paso de lo que está sucediendo, como lo ve Praat:

  1. En la línea 8, comienza un bucle for: for a from 1 to last

  2. Dentro de ese bucle, en la línea 25, comienza un segundo: for i to n

  3. Dentro de ese segundo bucle, en la línea 27, se llama a un procedimiento llamado instance.

    En este punto, Praat salta a la línea última que define ese procedimiento (así que si lo define varias veces, solo obtendrá el último). Como solo hay uno, Praat salta a la línea 36: procedure instance: .target_word$

  4. Dentro de ese procedimiento (que, por cierto, se define dentro de un bucle for, que es ... inusual) tiene un bloque if: if label$ == .target_word$

  5. Al final de ese bloque, endfor incrementa la variable de control (en este caso, i) y cierra el bucle for. ¿Pero cuál ?

    Puede esperar que cierre el último ciclo for que ingresamos (eso es lo que hice). Pero en realidad, Praat parece realizar un seguimiento de las declaraciones de apertura for y cierre endfor, y las asigna verticalmente.

    No he mirado al intérprete con suficiente detalle para averiguar exactamente lo que sucede, pero en un caso como este, los resultados son los mismos que mapear el endfor más bajo (= el más cercano al final de su secuencia de comandos) al más alto for, y así sucesivamente.

    (Esto probablemente no es lo que realmente sucede (de lo contrario, múltiples bucles no superpuestos no funcionarían), pero esto no es realmente importante: lo importante es que solo endfor cierra un solo for, independientemente de en qué parte del script se encuentre o cuando Praat lo vea . Por otro lado, esto es no lo que sucede con endproc.)

    Independientemente de las reglas precisas, este endfor se asigna al segundo for, que ingresamos en el punto 2 (que era la línea 25). Entonces volvemos a la primera línea del bucle that (línea 26).

  6. Ahora llegamos a la línea 27 por segunda vez (esta vez para el segundo intervalo) y nuevamente llamamos a @instance: "strikes". ¡Todavía no tenemos que @instance: "raindrops"!

  7. Esto se repite para todos los intervalos, cada vez que incrementa i en uno (cada vez que tocamos el endfor), hasta que i se convierte en n. Esta vez, cuando llamamos a @instance, atravesamos el bloque if y una vez más llegamos al endfor desde el punto 5.

    Praat incrementa obedientemente la variable de control (así que ahora i = n + 1), y verifica la condición final establecida al comienzo del ciclo for. En este caso, Praat sabe que el ciclo for termina cuando i == n, y desde i = n + 1, en lugar de saltar de nuevo a la cima, continúa.

    Solo ahora , después de haber pasado por todos los intervalos del primer archivo, ¡realmente llegamos al final del procedimiento !

  8. El procedimiento finalmente termina. Praat recuerda que ingresamos a este procedimiento en el punto 3, y en ese entonces estábamos leyendo la línea 27. Entonces, obedientemente, va y lee la línea 28, que es otra llamada al mismo procedimiento: @instance: "raindrops".

  9. Y aquí es donde (¡finalmente!) Muere.

    Muere porque la variable de control i ahora es n + 1 (se convirtió en eso en el punto 7). Esto normalmente no sucedería, ya que normalmente no alcanzaría una instrucción endfor para un ciclo que ya ha finalizado. Pero en este caso lo hacemos. Entonces, cuando Praat intenta leer la etiqueta del intervalo i en un TextGrid con intervalos i-1 ... se queja diciendo que el número del intervalo es demasiado grande. Porque es.

    Su problema inicial (está haciendo solo una parte del trabajo y no está muriendo) No puedo reproducirlo porque en el bloque if realmente cambia manualmente el valor de i (que es riesgoso ), y ese bloque if solo se ejecuta si la etiqueta coincide lo suficientemente temprano en su TextGrid (lo suficientemente temprano para que ocurra antes de que el script explote).

Puedes ver todo este desastre en acción con esta versión simplificada de la estructura de tu script:

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

Para solucionar esto, probablemente debería reestructurar su código para que siga más o menos este patrón:

for a to last
  for i to n
    @instance: "word"
  endfor
endfor

procedure instance: .word$
  # do things
endproc

Esto ha sido altamente educativo. :)

3
jja 30 oct. 2017 a las 11:31

¡Yo tengo que trabajar! La página del manual en bucles fue útil. Aquí está el código si alguien lo encuentra útil.

#############################################################
#
# 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!"
0
Lisa 27 oct. 2017 a las 21:53

Intente y agregue select TextGrid 'object_name$' justo después del procedimiento init.

procedure instance: .target_word$

    select TextGrid 'object_name$'

    label$ = Get label of interval: 3, i
    if label$ == .target_word$
         index = i
         i += n
1
Stefano 23 oct. 2017 a las 06:32