Los sonidos en R se pueden representar en 3 clases de objetos:

  • Clases comunes (vector numérico, matriz numérica)
  • Clases de series de tiempo (ts, mts)
  • Clases específicas de sonido (Wave y audioSample)

 

Clases no especificas

Vectores

Cualquier vector numérico puede tratarse como un sonido si se proporciona una frecuencia de muestreo. Por ejemplo, un sonido sinusoidal de 440 Hz muestreado a 8000 Hz durante un segundo puede generarse así:

# cargar paquete
library(seewave)

# crear un sonido sinuosoidal a 440 Hz
s1 <- sin(2 * pi * 440 * seq(0, 1, length.out = 8000))

is.vector(s1)
## [1] TRUE
mode(s1)
## [1] "numeric"

 

Estas secuencias de valores solo toman sentido cuando se especifica la tasa de muestreo a la que se crearon:

oscillo(s1, f = 8000, from = 0, to = 0.01)

 

Matrices

Se puede leer cualquier matriz de una sola columna:

s2<-as.matrix(s1)

is.matrix(s2)
## [1] TRUE
dim(s2)
## [1] 8000    1
oscillo(s2, f = 8000, from = 0, to = 0.01)

 

Si la matriz tiene más de una columna, solo se considerará la primera columna:

x<-rnorm(8000)

s3<-cbind(s2,x)

is.matrix(s3)
## [1] TRUE
dim(s3)
## [1] 8000    2
oscillo(s3, f = 8000, from = 0, to = 0.01)

 

Series de tiempo

La clase ts y las funciones relacionadas ts, as.ts, is.ts se pueden usar también para generar objetos de sonido en R. Aquí se muestra el comando para generar de manera similar una serie de tiempo correspondiente a un sonido sinusoidal de 440 Hz muestreado a 8000 Hz durante un segundo:

s4 <- ts(data = s1, start = 0, frequency = 8000)

str(s4)
##  Time-Series [1:8000] from 0 to 1: 0 0.339 0.637 0.861 0.982 ...

 

Para generar un ruido aleatorio de 0.5 segundos:

s4 <- ts(data = runif(4000, min = -1, max = 1), start = 0, end = 0.5, frequency = 8000)

str(s4)
##  Time-Series [1:4001] from 0 to 0.5: -0.941 0.337 0.643 -0.824 0.924 ...

 

Las funciones frequency() y deltat() devuelven la frecuencia de muestreo (\(f\)) y la resolución de tiempo (\(Delta t\)) respectivamente:

frequency(s4)
## [1] 8000
deltat(s4)
## [1] 0.000125

 

Como la frecuencia está incorporada en los objetos ts, no es necesario especificarla cuando se utilizan dentro de funciones dedicadas a audio:

oscillo(s4, from = 0, to = 0.01)

 

En el caso de series temporales múltiples, las funciones de seewave considerarán solo la primera serie:

s5 <- ts(data = s3, f = 8000)

class(s5)
## [1] "mts"    "ts"     "matrix"
oscillo(s5, from = 0, to = 0.01)

Clases específicas para sonido

Hay dos clases de objetos correspondientes al formato binario wav o al formato comprimidomp3:

  • Clase Wave del paquete tuneR
  • Clase audioSample del paquete audio

 

Clase Wave (tuneR)

La clase Wave viene con el paquete tuneR. Esta clase S4 incluye diferentes “ranuras” (slots) con los datos de amplitud (canal izquierdo o derecho), la frecuencia de muestreo (o frecuencia), el número de bits (8/16/24/32) y el tipo de sonido (mono/estéreo). Altas tasas de muestreo (> 44100 Hz) pueden ser leídas en este tipo de objetos.

La función para importar archivos .wav desde el disco duro esreadWave:

# cargar paquete
library(tuneR)

s6 <- readWave("./ejemplos/Phae.long1.wav")

 

Podemos verificar la clase del objeto así:

# clase de objeto
class(s6) 
## [1] "Wave"
## attr(,"package")
## [1] "tuneR"

 

Los objetos S4 tienen una estructura similar a las listas pero utilizan ‘@’ para acceder a cada posición (slot):

# estructura
str(s6)
## Formal class 'Wave' [package "tuneR"] with 6 slots
##   ..@ left     : int [1:56251] 162 -869 833 626 103 -2 43 19 47 227 ...
##   ..@ right    : num(0) 
##   ..@ stereo   : logi FALSE
##   ..@ samp.rate: int 22500
##   ..@ bit      : int 16
##   ..@ pcm      : logi TRUE
# extraer una posicion
[email protected] 
## [1] 22500

 

Las muestras vienen en la ranura ‘@left’:

# muestras
s6@left[1:40]
##  [1]  162 -869  833  626  103   -2   43   19   47  227   -4  205  564  171
## [15]  457  838 -216   60   76 -623 -213  168 -746 -248  175 -512  -58  651
## [29]  -85 -213  586   40 -407  371  -51 -587  -92   94 -527   40

 

El número de muestras esta dado por la duración y la tasa de muestreo.

 

¿Como podemos calcular la duración del objeto wave usando la información en el objeto?

 

Una ventaja de usar readWave() es el poder leer segmentos específicos de archivos de sonido, especialmente útil con archivos largos. Esto se hace usando los argumentosfrom y to y especificando las unidades de tiempo con los argumentosunits. Las unidades se pueden convertir en “samples”, “minutes” u “hours”. Por ejemplo, para leer solo la sección que comienza en 1s y termina en 5s del archivo “Phae.long1.wav”:

s7 <- readWave("./ejemplos/Phae.long1.wav", from = 1, to = 5, units = "seconds")

s7
## 
## Wave Object
##  Number of Samples:      33751
##  Duration (seconds):     1.5
##  Samplingrate (Hertz):   22500
##  Channels (Mono/Stereo): Mono
##  PCM (integer format):   TRUE
##  Bit (8/16/24/32/64):    16

 

Los archivos .mp3 se pueden importar a R aunque se importan en formato Wave. Esto se hace usando la función readMP3():

s7 <- readMP3("./ejemplos/Phae.long1.mp3")

s7
## 
## Wave Object
##  Number of Samples:      56448
##  Duration (seconds):     2.56
##  Samplingrate (Hertz):   22050
##  Channels (Mono/Stereo): Mono
##  PCM (integer format):   TRUE
##  Bit (8/16/24/32/64):    16

 

Para obtener información sobre el objeto (frecuencia de muestreo, número de bits, mono/estéreo), es necesario utilizar la indexación de las clases de objetos S4:

[email protected]
## [1] 22050
s7@bit
## [1] 16
s7@stereo
## [1] FALSE

 

Una propiedad que no aparece en estas llamadas es que readWave no normaliza el sonido. Los valores que describen el sonido se incluirán entre $  pm 2 ^ {bit-1} $:

range(s7@left)
## [1] -32768  32767

 

Clase sound (phonTools)

La función loadsound() de phonTools también importa archivos de sonido ‘wave’ en R, en este caso como objetos de clase sound:

library(phonTools)
## 
## Attaching package: 'phonTools'
## The following objects are masked from 'package:tuneR':
## 
##     normalize, play
## The following object is masked from 'package:seewave':
## 
##     preemphasis
s8 <- loadsound("./ejemplos/Phae.long1.wav")

s8
## 
##       Sound Object
## 
##    Read from file:         ./ejemplos/Phae.long1.wav
##    Sampling frequency:     22500  Hz
##    Duration:               2500.044  ms
##    Number of Samples:      56251
str(s8)
## List of 5
##  $ filename  : chr "./ejemplos/Phae.long1.wav"
##  $ fs        : int 22500
##  $ numSamples: num 56251
##  $ duration  : num 2500
##  $ sound     : Time-Series [1:56251] from 0 to 2.5: 0.00494 -0.02652 0.02542 0.0191 0.00314 ...
##  - attr(*, "class")= chr "sound"

 

Esta función solo importa archivos con un rango dinámico de 8 o 16 bits.

Clase audioSample (audio)

El paquete audio, es otra opción para manejar archivos .wav. El sonido puede ser importado usando la función load.wave(). La clase del objeto resultante es audioSample que es esencialmente un vector numérico (para mono) o una matriz numérica con dos filas (para estéreo). La frecuencia de muestreo y la resolución se guardan como atributos:

library(audio)
## 
## Attaching package: 'audio'
## The following object is masked from 'package:phonTools':
## 
##     play
## The following object is masked from 'package:tuneR':
## 
##     play
s10 <- load.wave("./ejemplos/Phae.long1.wav")

head(s10)
## sample rate: 22500Hz, mono, 16-bits
## [1]  4.943848e-03 -2.652058e-02  2.542114e-02  1.910400e-02  3.143311e-03
## [6] -6.103702e-05
s10$rate
## [1] 22500
s10$bits
## [1] 16

 

La principal ventaja del paquete audio es que el sonido se puede adquirir directamente dentro de una sesión de R. Esto se logra primero preparando un vector de NAs y luego usando la funciónrecord(). Por ejemplo, para obtener un sonido mono de 5 segundos muestreados a 16 kHz:

s11 <- rep(NA_real_, 16000*5)

record(s11, 16000, 1)

 

Una sesión de grabación se puede controlar mediante tres funciones complementarias: pause(),rewind(), y resume().

Exportar sonidos desde R

Para una compatibilidad máxima con otros programas de sonido, puede ser útil guardar un sonido como un simple archivo .txt. Los siguientes comandos escribirán un archivo “tico.txt” en el disco duro:

data(tico)

export(tico, f=22050)

 

Formato ‘.wav’

tuneR y audio tienen una función para escribir archivos .wav: writeWave() y save.wave() respectivamente. Dentro de seewave, la función savewav(), que se basa en writeWave(), se puede usar para guardar datos en formato .wav. De forma predeterminada, el nombre del objeto se usará para el nombre del archivo .wav:

savewav(tico)

 

Formato ‘.flac’

Free Lossless Audio Codec (FLAC) es un formato de archivo para la compresión de datos de audio sin pérdidas. FLAC reduce el ancho de banda y los requisitos de almacenamiento sin sacrificar la integridad de la fuente de audio. Las fuentes de audio codificadas en FLAC generalmente se reducen en tamaño de 40 a 50 por ciento. Consulte la página web de flac para obtener más detalles (flac.sourceforge.net).

El formato .flac no puede utilizarse como tal con R. Sin embargo, la función wav2flac() permite llamar al software FLAC directamente desde la consola. Por lo tanto, FLAC debe estar instalado en su sistema operativo. Si tiene un archivo .wav que desea comprimir en .flac, llame a:

wav2flac(file = "./ejemplos/Phae.long1.wav", overwrite = FALSE)

 

Para comprimir un archivo .wav a un formato .flac, se debe usar el argumento reverse = TRUE:

wav2flac("Phae.long1.flac", reverse = TRUE)

 

Reproducir objetos wave

Objetos wave puede ser reproducido con la función play() de tuneR. Puede pasar que los jugadores predeterminados de la función play() no estén instalados en el sistema operativo. setWavPlayer() se puede usar para definir el comando que usaráplay. Por ejemplo, si Audacious es el reproductor a usar en Linux:

setWavPlayer("audacious")

play(tico)

 

La función homónima del paquete audio hace lo mismo sobre objetos audioSample:

x <- audioSample(sin(1:8000/10), 8000)

play(x)

 

El paquete seewave incluye la función listen() (basada en play() de tuneR) que funciona de manera similar, pero ademas acepta todos las clases especificas y no especificas de objetos de sonido en R y ademas permite reproducir segmentos usando los argumentos from y to:

x <- sin(1:160000/10)

listen(x, f = 16000, from = 0, to = 2)

 

Este cuadro, tomado de Sueur (2019), resume las funciones disponibles para importar y exportar archivos de sonido en R. El cuadro esta imcompleto ya que no menciona las funciones del paquete phonTools:

tabla imp exp waves


 

  • ¿Como afecta la tasa de muestreo el tamaño de un archivo de audio?

  • ¿Como afecta el rango dinámico el tamaño de un archivo de audio?

  • Utilice la función system.time() para comparar el desempeño de las diferentes funciones para importa archivos de audio en R. Para esto utilice el archivo “LBH.374.SUR.wav” (cantos de Phaethornis longirostris) el cual dura alrededor de 2 min

 


Referencias

  1. Sueur J, Aubin T, Simonis C. 2008. Equipment review: seewave, a free modular tool for sound analysis and synthesis. Bioacoustics 18(2):213–226.

  2. Sueur, J. (2018). Sound Analysis and Synthesis with R.

  3. Sueur J. (2018). I/O of sound with R. seewave package vignette. url: https://cran.r-project.org/web/packages/seewave/vignettes/seewave_IO.pdf


Información de la sesión

## R version 3.5.3 (2019-03-11)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.2 LTS
## 
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=es_CR.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=es_CR.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=es_CR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=es_CR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] audio_0.1-6       phonTools_0.2-2.1 tuneR_1.3.3       seewave_2.1.3    
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.1      digest_0.6.18   MASS_7.3-51.1   signal_0.7-6   
##  [5] magrittr_1.5    evaluate_0.13   stringi_1.4.3   rmarkdown_1.12 
##  [9] tools_3.5.3     stringr_1.4.0   xfun_0.6        yaml_2.2.0     
## [13] compiler_3.5.3  htmltools_0.3.6 knitr_1.22