Skip to contents

The name is meant to evoke dplyr::bind_rows() which "stacks" one dataframe on top of another. Here we pull selected tiers from one textgrid and bind them onto another other one.

Usage

bind_tiers

Format

A Praat script

textgrid_receiver

path of the textgrid file to update (attach tiers onto)

textgrid_sender

path of the textgrid file to extract tiers from

tiers_to_pull

comma-separated names of tiers to extract

textgrid_out

path of the textgrid file to create

Example usage

library(tjm.praat)

# The two textgrids we want to bind together
tg <- system.file(
  "demo-textgrids/birdhouse.TextGrid",
  package = "tjm.praat"
)
tg_data <- readtextgrid::read_textgrid(tg)

tg2 <- system.file(
  "demo-textgrids/birdhouse2.TextGrid",
  package = "tjm.praat"
)
tg2_data <- readtextgrid::read_textgrid(tg2)


tg_out <- tempfile("test", fileext = ".TextGrid")

# We want to put "p2fa-words" and "p2fa-phones" on to the first textgrid
unique(tg_data$tier_name)
#> [1] "words"  "phones"
unique(tg2_data$tier_name)
#> [1] "p2fa-words"  "p2fa-phones"

f_bind_tiers <- wrap_praat_script(
  script_code_to_run = bind_tiers,
  returning = "last-argument"
)

tg_out <- f_bind_tiers(tg, tg2, "p2fa-words,p2fa-phones", tg_out)

tg_out_data <- readtextgrid::read_textgrid(tg_out)
unique(tg_out_data$tier_name)
#> [1] "words"       "phones"      "p2fa-words"  "p2fa-phones"

Praat source code

print(f_bind_tiers, condense = FALSE)
function (textgrid_receiver = NULL, textgrid_sender = NULL, tiers_to_pull =
NULL, textgrid_out = NULL)
# <wrapped_praat_script>
# returning: "last-argument"
form Copy tiers from one textgrid (sender) onto another (reciever)
  sentence Textgrid_receiver
  sentence Textgrid_sender
  sentence Tiers_to_pull
  sentence Textgrid_out
endform
Read from file: textgrid_receiver$
id_tg_receiver = selected("TextGrid")
Read from file: textgrid_sender$
id_tg_sender = selected("TextGrid")
Create Strings as tokens: tiers_to_pull$, ","
id_str_tiers_to_pull = selected("Strings")
@stringsIter: "tiers", id_str_tiers_to_pull, "initialize"
while stringsIter.tiers.has_next
  @stringsIter("tiers", id_str_tiers_to_pull, "next")
  selectObject: id_tg_sender
  # Pull tier
  @findNumberForTier: stringsIter.tiers.next$
  Extract one tier: findNumberForTier.result
  id_tier = selected("TextGrid")
  # Bind it
  selectObject: id_tg_receiver
  plusObject: id_tier
  Merge
  id_tg_temp = selected("TextGrid")
  # Clean up
  selectObject: id_tg_receiver
  plusObject: id_tier
  Remove
  id_tg_receiver = id_tg_temp
endwhile
selectObject: id_tg_receiver
Save as text file: textgrid_out$
# Find the number of the (last) tier with a given name
procedure findNumberForTier: .target_tier$
  .tiers = Get number of tiers
  .result = 0
  for .tier_i to .tiers
    .tier_i_name$ = Get tier name: .tier_i
      if .tier_i_name$ == .target_tier$
        .result = .tier_i
      endif
  endfor
endproc
# An iterator for a list of strings
procedure stringsIter: .iter_name$, .id, .method$
    selectObject: .id
    # create a private namespace for this strings list iterator
    .list$ = .iter_name$
    if .method$ = "initialize"
        .'.list$'.length = Get number of strings
        .'.list$'.index = 0
    endif
    if .method$ = "next"
        .'.list$'.index = .'.list$'.index + 1
        .'.list$'.next$ = Get string: .'.list$'.index
    endif
    if .method$ = "has_next"
        # .has_next is updated whenever procedure is invoked
    endif
    if .'.list$'.index < .'.list$'.length
        .'.list$'.has_next = 1
    else
        .'.list$'.has_next = 0
    endif
endproc