7 Signal data extraction14
As mentioned in the default workflow of Chapter 2, after querying the symbolic annotation structure and dereferencing its time information, the result is a set of items with associated time stamps. It was necessary that the emuR
package contain a mechanism for extracting signal data corresponding to this set of items. As illustrated in Chapter 8, wrassp
provides the R ecosystem with signal data file handling capabilities as well as numerous signal processing routines. emuR
can use this functionality to either obtain pre-stored signal data or calculate derived signal data that correspond to the result of a query. Figure 7.1A shows a snippet of speech with overlaid annotations where the resulting SEGMENT
of an example query (e.g., "Phonetic == ai"
) is highlighted in yellow. Figure 7.1B displays a time parallel derived signal data contour as would be returned by one of wrassp
’s file handling or signal processing routines. The yellow segment in Figure 7.1B marks the corresponding samples that belong to the ai
segment of Figure 7.1A.
The R code snippet below shows how to create the demo data that will be used throughout this chapter.
# load the package
library(emuR)
# create demo data in directory provided by the tempdir() function
create_emuRdemoData(dir = tempdir())
# get the path to a emuDB called "ae" that is part of the demo data
= file.path(tempdir(),
path2directory "emuR_demoData",
"ae_emuDB")
# load emuDB into current R session
= load_emuDB(path2directory) ae
7.1 Extracting pre-defined tracks
To access data that are stored in files, the user has to define tracks for a database that point to sequences of samples in files that match a user-specified file extension. The user-defined name of such a track can then be used to reference the track in the signal data extraction process. Internally, emuR
uses wrassp
to read the appropriate files from disk, extract the sample sequences that match the result of a query and return values to the user for further inspection and evaluation. The R code snippet below shows how a signal track that is already defined in the ae
demo database can be extracted for all annotation items on the Phonetic
level containing the label ai.
# list currently available tracks
list_ssffTrackDefinitions(ae)
## name columnName fileExtension
## 1 dft dft dft
## 2 fm fm fms
# query all "ai" phonetic segments
= query(ae, "Phonetic == ai")
ai_segs
# get "fm" track data for these segments
# (verbose = F is only set to avoid additional output in manual)
= get_trackdata(ae,
ai_td_fm seglist = ai_segs,
ssffTrackName = "fm",
verbose = FALSE)
# show ai_td_fm (F1-F4 in columns T1-T4)
ai_td_fm
## # A tibble: 183 x 24
## sl_rowIdx labels start end db_uuid session bundle start_item_id end_item_id
## <int> <chr> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 2 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 3 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 4 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 5 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 6 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 7 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 8 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 9 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 10 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## # … with 173 more rows, and 15 more variables: level <chr>, attribute <chr>,
## # start_item_seq_idx <int>, end_item_seq_idx <int>, type <chr>,
## # sample_start <int>, sample_end <int>, sample_rate <int>, times_orig <dbl>,
## # times_rel <dbl>, times_norm <dbl>, T1 <int>, T2 <int>, T3 <int>, T4 <int>
Being able to access data that is stored in files is important for two main reasons. Firstly, it is possible to generate files using external programs such as VoiceSauce (Shue et al. 2011), which can export its calculated output to the general purpose SSFF file format. This file mechanism is also used to access data produced by EMA, EPG or many other forms of signal data recordings. Secondly, it is possible to track, save and access manipulated data such as formant values that have been manually corrected. It is also worth noting that the get_trackdata()
function has a predefined track which is always available without it having to be defined. The name of this track is MEDIAFILE_SAMPLES
which references the actual samples of the audio files of the database. The R code snippet below shows how this predefined track can be used to access the audio samples belonging to the segments in ai_segs
.
# get media file samples
# (verbose = F is only set to avoid additional output in manual)
= get_trackdata(ae,
ai_td_mfs seglist = ai_segs,
ssffTrackName = "MEDIAFILE_SAMPLES",
verbose = FALSE)
# ai_td_mfs (sample values in column T1)
ai_td_mfs
## # A tibble: 18,386 x 21
## sl_rowIdx labels start end db_uuid session bundle start_item_id end_item_id
## <int> <chr> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 2 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 3 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 4 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 5 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 6 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 7 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 8 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 9 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 10 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## # … with 18,376 more rows, and 12 more variables: level <chr>, attribute <chr>,
## # start_item_seq_idx <int>, end_item_seq_idx <int>, type <chr>,
## # sample_start <int>, sample_end <int>, sample_rate <int>, times_orig <dbl>,
## # times_rel <dbl>, times_norm <dbl>, T1 <int>
7.2 Adding new tracks
As described in detail in Section 8.7, the signal processing routines provided by the wrassp
package can be used to produce SSFF files containing various derived signal data (e.g., formants, fundamental frequency, etc.). The R code snippet below shows how the add_ssffTrackDefinition()
can be used to add a new track to the ae
emuDB
. Using the onTheFlyFunctionName
parameter, the add_ssffTrackDefinition()
function automatically executes the wrassp
signal processing function ksvF0
(onTheFlyFunctionName = "ksvF0"
) and stores the results in SSFF files in the bundle directories.
# add new track and calculate
# .f0 files on-the-fly using wrassp::ksvF0()
# (verbose = F is only set to avoid additional output in manual)
add_ssffTrackDefinition(ae,
name = "F0",
onTheFlyFunctionName = "ksvF0",
verbose = FALSE)
# show newly added track
list_ssffTrackDefinitions(ae)
## name columnName fileExtension
## 1 dft dft dft
## 2 fm fm fms
## 3 F0 F0 f0
# show newly added files
list_files(ae, fileExtension = "f0")
## # A tibble: 7 x 4
## session bundle file absolute_file_path
## <chr> <chr> <chr> <chr>
## 1 0000 msajc003 msajc003… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 2 0000 msajc010 msajc010… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 3 0000 msajc012 msajc012… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 4 0000 msajc015 msajc015… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 5 0000 msajc022 msajc022… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 6 0000 msajc023 msajc023… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
## 7 0000 msajc057 msajc057… /tmp/Rtmpns5ycU/emuR_demoData/ae_emuDB/0000_ses/ms…
# extract newly added trackdata
# (verbose = F is only set to avoid additional output in manual)
= get_trackdata(ae,
ai_td seglist = ai_segs,
ssffTrackName = "F0",
verbose = FALSE)
# show ai_td (F0 values in column T1)
ai_td
## # A tibble: 183 x 21
## sl_rowIdx labels start end db_uuid session bundle start_item_id end_item_id
## <int> <chr> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 2 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 3 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 4 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 5 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 6 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 7 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 8 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 9 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 10 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## # … with 173 more rows, and 12 more variables: level <chr>, attribute <chr>,
## # start_item_seq_idx <int>, end_item_seq_idx <int>, type <chr>,
## # sample_start <int>, sample_end <int>, sample_rate <int>, times_orig <dbl>,
## # times_rel <dbl>, times_norm <dbl>, T1 <dbl>
7.3 Calculating tracks on-the-fly
With the wrassp
package, we were able to implement a new form of signal data extraction which was not available in the legacy system. The user is now able to select one of the signal processing routines provided by wrassp
and pass it on to the signal data extraction function. The signal data extraction function can then apply this wrassp
function to each audio file as part of the signal data extraction process. This means that the user can quickly manipulate function parameters and evaluate the result without having to store to disk the files that would usually be generated by the various parameter experiments. In many cases this new functionality eliminates the need for defining a track definition for the entire database for temporary data analysis purposes. The R code snippet below shows how the onTheFlyFunctionName
parameter of the get_trackdata()
function is used.
# (verbose = F is only set to avoid additional output in manual)
= get_trackdata(ae,
ai_td_pit seglist = ai_segs,
onTheFlyFunctionName = "mhsF0",
verbose = FALSE)
# show ai_td_pit (F0 values in column T1)
ai_td_pit
## # A tibble: 183 x 21
## sl_rowIdx labels start end db_uuid session bundle start_item_id end_item_id
## <int> <chr> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 2 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 3 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 4 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 5 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 6 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 7 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 8 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 9 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 10 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## # … with 173 more rows, and 12 more variables: level <chr>, attribute <chr>,
## # start_item_seq_idx <int>, end_item_seq_idx <int>, type <chr>,
## # sample_start <int>, sample_end <int>, sample_rate <int>, times_orig <dbl>,
## # times_rel <dbl>, times_norm <dbl>, T1 <dbl>
7.4 The resulting object: tibble
As of version 2.0.0 of emuR
the default resulting object of a call to get_trackdata()
is of class tibble
(see R code snippet below).
# show class vector of ai_td_pit
class(ai_td_pit)
## [1] "tbl_df" "tbl" "data.frame"
# show ai_td_pit (F0 values in column T1)
ai_td_pit
## # A tibble: 183 x 21
## sl_rowIdx labels start end db_uuid session bundle start_item_id end_item_id
## <int> <chr> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 2 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 3 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 4 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 5 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 6 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 7 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 8 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 9 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## 10 1 ai 863. 1016. 0fc618… 0000 msajc… 161 161
## # … with 173 more rows, and 12 more variables: level <chr>, attribute <chr>,
## # start_item_seq_idx <int>, end_item_seq_idx <int>, type <chr>,
## # sample_start <int>, sample_end <int>, sample_rate <int>, times_orig <dbl>,
## # times_rel <dbl>, times_norm <dbl>, T1 <dbl>
As can be seen by the first row output of the R code snippet above, the tibble
object is an amalgamation of both a segment list and the actual signal data. The first sl_rowIdx
column of the ai_emuRtd_pit
object indicates the row index of the segment list the current row belongs to, the times_rel
and times_orig
columns represent the relative time and the original time of the samples contained in the current row (see above R code snippet) and T1 (to Tn in n-dimensional tracks) contains the actual signal sample values. As is often the case with tabular data, the tibble
object carries certain redundant information (e.g. segment start and end times). However, the benefit of having a data.frame
object that contains all the information needed to process the data is the ability to replace package specific functions (e.g. the legacy eplot()
etc.) with standardized data.frame
processing and visualization procedures that can be applied to any data.frame
object independent of the package that generated it. Therefore, the knowledge that is necessary to process a tibble
object can be transferred to/from other packages which was not the case for the legacy trackdata
object. For examples on how functions provided by packages belonging to the tidyverse can be used to replace the legacy eplot()
and dplot()
functions see 22. The legacy dcut()
can simply be replaced using normalize_length()
in combination with dplyr::filter()
. Finally, it is worth noting that for backward compatibility the legacy trackdata
object is still available by explicitly setting the resultType
parameter of get_trackdata()
.
7.5 Conclusion
This chapter introduced the signal data extraction mechanics of the emuR
package. The combination of the get_trackdata()
function and the file handling and signal processing abilities of the wrassp
package (see Chapter 8 for further details) provide the user with a flexible system for extracting derived or complementary signal data belonging to their queried annotation items.
Parts of this chapter have been published in Winkelmann, Harrington, and Jänsch (2017).↩︎