| stft_simple | R Documentation |
Short-Time Fourier Transform and its inverse for converting a signal between
time and frequency domains. stft_simple returns the full complex
spectrogram containing both positive and negative frequencies. Any final
samples that do not fit into a complete frame are silently dropped unless
padWithSilence = TRUE. istft_simple performs inverse STFT.
stft_simple(
x,
samplingRate = NULL,
wl = 512,
step = wl%/%2,
wn = "gaussian",
zp = 0,
padWithSilence = FALSE
)
istft_simple(
spec,
wl,
step,
wn = "gaussian",
wnSyn = c("wola", "rectangle"),
type = c("half", "full"),
fade = FALSE,
tol = 1e-06
)
istft_timevar(
spec,
wl,
step,
wn = "gaussian",
type = c("half", "full"),
multPitch = 1,
timeStretch = 1,
fade = TRUE,
tol = 1e-06
)
x |
numeric vector |
samplingRate |
sampling rate (Hz). If left NULL, time and frequency labels are not added (faster, but not by much) |
wl |
window length in samples (can be even or odd, but >=3). If wl
exceeds the length of input vector, it is reset to wl = length(x). For
maximum speed, set |
step |
step in samples |
wn |
window type accepted by |
zp |
window length after zero padding, samples. No padding is performed
if |
padWithSilence |
if TRUE, pads the sound at both ends with half a window length of silence to resolve the edges properly and avoid dropping the last few samples (not needed if your sound is already padded with some silence) |
spec |
input complex spectrogram (rows = frequency, columns = time) |
wnSyn |
synthesis window: 'wola' = weighted overlap-add (WOLA) / STFT pseudoinverse, avoids spectral artifacts when the complex spectrogram is modified prior to iSTFT (default, recommended for most applications); 'rectangle' = no synthesis window, allows reconstructing the original signal exactly provided that the spectrogram is not modified between STFT and iSTFT |
type |
"full" = the full spectrogram returned by |
fade |
if TRUE, a linear fade-in and fade-out of length wl (but no more than 1/4 of input length) is applied to the output vector ("wola" method only) |
tol |
to avoid division by 0, denominator values smaller than |
multPitch |
pitch multiplier interpolated across frames; > 1 –> raise pitch; must be positive |
timeStretch |
time stretch factor interpolated across frames; > 1 –> increase duration; must be positive |
If wnSyn = "rectangle", no synthesis window is applied and the
original signal can be recovered exactly, without any distortion at the
beginning and the end (windows that taper to 0 give edge samples zero weight,
so pad with silence to reconstruct them). The reconstruction is then exact
for the covered portion of the signal when inverting an unnormalized windowed
STFT produced by stft_simple, provided there is no zero-padding and
the frame grid covers the signal. However, this works only if the complex
spectrogram is not modified between STFT and iSTFT. When the spectrogram is
modified - for example, when some filter is applied in the frequency domain -
it is better to set wnSyn = "wola", which applies the same windowing
function to the iFFT of each frame. Finally, the much slower function
istft_timevar works with time-variable step sizes in the context of
dynamic pitch shifting or time stretching (see shiftPitch). The
zp argument of stft_simple() is for analysis/display only.
Spectrograms produced with zp > wl cannot be inverted by
istft_simple() or istft_timevar() in their current form.
stft_simple returns a complex spectrogram with both positive
and negative frequencies as a matrix. If samplingRate is not NULL, row
names give frequency in kHz and column names give time in ms. If
samplingRate is NULL, no row or column names are added. Rows beyond the
Nyquist frequency (half the sampling rate) correspond to negative
frequencies. Time stamps correspond to the middle of each frame, starting
with half a window length if padWithSilence = FALSE or starting at 0
ms if padWithSilence = TRUE. istft_simple returns a numeric
vector.
## Ex. 1: obtaining a spectrogram
data(speechEx, package = "soundgen")
spec = stft_simple(speechEx@left[1:10000], samplingRate = speechEx@samp.rate,
wl = 512, step = 100)
image(t(Mod(spec)))
# the spectrum of one frame
plot(as.numeric(rownames(spec)), Mod(spec[, 15]), type = 'l', xlab = 'Freq, kHz')
spec[1:5, 1:5]
# To get the positive frequencies only, use:
halfspec = spec[1:(nrow(spec) %/% 2 + 1), , drop = FALSE]
image(t(Mod(halfspec)))
## Ex. 2: manual narrow-band spectral filter to turn white noise into a whistle
samplingRate = 16000
wl = 317; step = 51
noise = fade(rnorm(samplingRate), samplingRate = samplingRate)
spec = stft_simple(noise, samplingRate, wl = wl, step = step, zp = 0)
spec = spec[1:(wl %/% 2 + 1), ] # discard negative frequencies
# amplify one frequency band by 50 dB
spec_filtered = spec
spec_filtered[50, ] = spec_filtered[50, ] * 10^(50/20)
image(y = as.numeric(rownames(spec_filtered)), t(log(Mod(spec_filtered))))
# inverse STFT using wnSyn = 'wola'
noise_filtered = fade(istft_simple(spec_filtered, wl = wl, step = step,
type = 'half', wnSyn = 'wola'), samplingRate = samplingRate)
spectrogram(noise_filtered, samplingRate)
# playme(noise_filtered, samplingRate)
## Ex. 3: reconstructing the input exactly with wnSyn = 'rectangle'
a = rnorm(64)
wl = 11; step = 3 # any wl and step are fine, even or odd
spec_full = stft_simple(a, wl = wl, step = step, wn = 'gaussian')
new_1 = istft_simple(spec_full, wl = wl, step = step, type = "full",
wn = 'gaussian', wnSyn = 'rectangle')
plot(a, type = "l"); lines(new_1, col = 'green')
# note the missing bit at the end - incomplete final frame dropped
spec_half = spec_full[1:(nrow(spec_full) %/% 2 + 1), ]
new_2 = istft_simple(spec_half, wl = wl, step = step, type = "half",
wn = 'gaussian', wnSyn = 'wola') # wola is also exact here
plot(a, type = "l"); lines(new_2, col = 'green')
## Ex. 4: identity check for istft_timevar()
new_timevar = istft_timevar(spec_full, wl = wl, step = step,
type = "full", multPitch = 1, timeStretch = 1, fade = FALSE)
plot(a, type = "l"); lines(new_timevar, col = 'green')
all(round(new_2, 5) == round(new_timevar, 5)) # should be TRUE
all(round(new_timevar, 5) == round(a[1:length(new_timevar)], 5))
# should be identical as well, except that two last samples in "a" are dropped
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.