SSFF and JSTF: reading, writing, and round-tripping
ssff-jstf-io.Rmdtrk_* functions write SSFF (Simple
Signal File Format) tracks; lst_* functions write
JSTF (JSON Track Format) summaries. Both round-trip
through matching read_*/write_* pairs and both
load straight into emuR.
SSFF: time-series tracks
Write a track to disk, then read it back with
read_ssff():
wav <- system.file("samples", "sustained", "a1.wav", package = "superassp")
out_dir <- tempdir()
trk_pitch_rapt(wav, toFile = TRUE, outputDirectory = out_dir, explicitExt = "f0")
#> Applying `trk_pitch_rapt()` to 1 recording
#> Successfully processed 1 of 1 file
f0_path <- file.path(out_dir, paste0(tools::file_path_sans_ext(basename(wav)), ".f0"))
f0_obj <- read_ssff(f0_path)
track_names(f0_obj)
#> [1] "f0"
sample_rate(f0_obj)
#> [1] 100write_ssff() is the inverse operation, for writing an
AsspDataObj you built or modified in R:
f0_obj[["f0"]][1:5, ] <- 0 # zero out the first 5 frames
out_path <- tempfile(fileext = ".f0")
write_ssff(f0_obj, out_path)
read_ssff(out_path)[["f0"]][1:5, ]
#> [1] 0 0 0 0 0read_track()/write_track() are
format-agnostic dispatchers: pass any trk_* output path and
they detect SSFF vs. JSTF from the file’s own metadata rather than the
file extension.
JSTF: summary measures
lst_* functions produce a JsonTrackObj — a
self-describing container with a field schema and one “slice” per
analysis window:
vr <- lst_voice_report(wav, toFile = FALSE, return_jstf = TRUE)
names(vr$field_schema)
#> [1] "start_time" "end_time" "selection_start"
#> [4] "selection_end" "median_pitch" "mean_pitch"
#> [7] "sd_pitch" "min_pitch" "max_pitch"
#> [10] "num_pulses" "num_periods" "mean_period"
#> [13] "sd_period" "fraction_unvoiced" "num_voice_breaks"
#> [16] "degree_voice_breaks" "jitter_local_percent" "jitter_local_abs"
#> [19] "jitter_rap_percent" "jitter_ppq5_percent" "jitter_ddp_percent"
#> [22] "shimmer_local_percent" "shimmer_local_db" "shimmer_apq3_percent"
#> [25] "shimmer_apq5_percent" "shimmer_apq11_percent" "shimmer_dda_percent"
#> [28] "mean_autocorrelation" "mean_nhr" "mean_hnr"
vr$slices[[1]]$values
#> $start_time
#> [1] 0
#>
#> $end_time
#> [1] 4.035374
#>
#> $selection_start
#> [1] 0
#>
#> $selection_end
#> [1] 4.035374
#>
#> $median_pitch
#> [1] 120.3934
#>
#> $mean_pitch
#> [1] 120.6306
#>
#> $sd_pitch
#> [1] 5.429101
#>
#> $min_pitch
#> [1] 109.6691
#>
#> $max_pitch
#> [1] 194.3577
#>
#> $num_pulses
#> [1] 312
#>
#> $num_periods
#> [1] 310
#>
#> $mean_period
#> [1] 0.008302197
#>
#> $sd_period
#> [1] 0.0002832662
#>
#> $fraction_unvoiced
#> [1] 0.3557772
#>
#> $num_voice_breaks
#> [1] 1
#>
#> $degree_voice_breaks
#> [1] 0.007434255
#>
#> $jitter_local_percent
#> [1] 0.5258646
#>
#> $jitter_local_abs
#> [1] 4.365831e-05
#>
#> $jitter_rap_percent
#> [1] 0.2692026
#>
#> $jitter_ppq5_percent
#> [1] 0.2436183
#>
#> $jitter_ddp_percent
#> [1] 0.8076078
#>
#> $shimmer_local_percent
#> [1] 4.226066
#>
#> $shimmer_local_db
#> [1] 0.3440395
#>
#> $shimmer_apq3_percent
#> [1] 1.774378
#>
#> $shimmer_apq5_percent
#> [1] 2.545493
#>
#> $shimmer_apq11_percent
#> [1] 4.347712
#>
#> $shimmer_dda_percent
#> [1] 5.323134
#>
#> $mean_autocorrelation
#> [1] NaN
#>
#> $mean_nhr
#> [1] 0.005467156
#>
#> $mean_hnr
#> [1] 22.62239Write it to a .jstf file and read it back:
jstf_path <- tempfile(fileext = ".jstf")
write_jstf(vr, jstf_path)
vr_reloaded <- read_jstf(jstf_path)
identical(vr$field_schema, vr_reloaded$field_schema)
#> [1] TRUEBuilding a JsonTrackObj from your own results
If you’re wrapping a measure that isn’t already a lst_*
function, create_json_track_obj() builds the same
self-describing structure that write_jstf() expects. It is
an internal helper (not exported — see the package’s Export Policy), so
package contributors writing a new lst_* wrapper call it
via ::::
obj <- superassp:::create_json_track_obj(
results = list(f0_mean = 150.2, f0_sd = 18.4),
function_name = "my_custom_summary",
file_path = wav,
sample_rate = 44100,
audio_duration = 1.5
)
write_jstf(obj, tempfile(fileext = ".jstf"))Loading into emuR
Both read_ssff()-produced AsspDataObjs and
read_jstf()-produced JsonTrackObjs carry the
sample rate, start time, and track names emuR expects — write with
toFile = TRUE into your emuR database’s _ssff
directory structure and the tracks load without further conversion.