jplay-sndfile es una aplicación que he estado programando la última semana y que tiene un carácter didáctico. Básicamente es un reproductor de ficheros de audio que además puede aplicar un cambio de frecuencia, y también puede hacer un barrido continuo de frecuencias sobre la muestra de audio. Es un cliente de JACK (el servidor de audio de Linux), y está basado, como punto de partida, en sndfile-jackplay que se encuentra dentro de las utilidades de la librería libsndfile (http://www.mega-nerd.com/libsndfile/tools/#jackplay).
Todo el mundo saber que cuando se reproduce un fichero de audio al doble de la frecuencia original dura la mitad de tiempo. Sería equivalente a coger una muestra de cada dos, y reproducirlas a la misma frecuencia de muestreo original.
Ahora vamos a hacer el caso contrario, queremos dividir la frecuencia por dos, y el tiempo que durará la reproducción tendría que ser el doble. Para hacerlo, lo más fácil es doblar cada muestra en dos, y reproducirlo a la frecuencia de muestreo original.
Estos dos casos especiales, multiplicar por dos y dividir por dos, son los casos fáciles y más evidentes. Un análisis de estos casos y estudiar el código fuente proporcionado puede aclarar muchos conceptos a losestudiantes de Procesamiento Digital del Señal. Ahora bien, más difícil es hacer frecuencias intermedias entre 0.5 y 2; y más difícil todavía es hacer un barrido continuo de frecuencias en un rango determinado. Todo esto es lo que se puede ver y se puede estudiar en esta aplicación que tiene un carácter didáctico.
La salida de la ayuda del programa proporciona la siguiente información:
$ jplay-sndfile -h
jplay-sndfile 1.00
Created by Joan Quintana Compte (joanillo)
joanqc arroba gmail.com – www.joanillo.org
Licensed under GPL v.3jplay-sndfile is a JACK client intended for playing audio files (wav) and pitch shifting, written basically for learning, testing and educational purposes, and the first stage for future developments. A part of playing an audio file, you can change the pitch (between *0.5 and *2) of your audio file, you can play the audio file combing the pitch between two ranges. For testing is useful a sine wave, but remember that you can use any mono (one channel) audio files.
This Jack Audio client connects automatically to system:playback_1 and system:playback_2usage: jplay-sndfile [-h] [[pitch-shift] | [pitch-shift-start pitch-shift-end]] wav-file
\t-h –help: this usage information
\t[pitch-shift] (0.5,2): shifting pitch
\t[pitch-shift-start] (0.5,2): shifting pitch start range
\t[pitch-shift-end] (0.5,2): shifting pitch end range
\twav file: mono channel audio file
\t\tExamples:
\t./jplay_sndfile samples/hellosine.wav
\t./jplay_sndfile 0.65 samples/hellosine.wav
\t./jplay_sndfile 0.5 2 samples/hellosine.wav
La muestra de audio que se presenta quiere ser un compendio de qué puede hacer jplay-sndfile, y contempla los siguientes casos:
- ./jplay_sndfile samples/test_44100.wav
- ./jplay_sndfile .5 samples/test_44100.wav
- ./jplay_sndfile .8 samples/test_44100.wav
- ./jplay_sndfile 1.4 samples/test_44100.wav
- ./jplay_sndfile 2 samples/test_44100.wav
- ./jplay_sndfile .5 2 samples/test_44100x3.wav
- ./jplay_sndfile samples/sine_440_44100.wav
- ./jplay_sndfile .5 1 samples/square_440_44100.wav
- ./jplay_sndfile 1 2 samples/saw_440_44100.wav
- ./jplay_sndfile .5 samples/waves.wav
- ./jplay_sndfile 2 samples/waves.wav
jplay-sndfile-examples by joanillo
Una de les cosas más interesants es estudiar la función callback de la API de JACK, que ha quedado bastante escueta, y donde está el meollo del asunto. Básicamente la función callback() es llamada por el servidor de audio cada vez que la interfície de audio (la tarjeta de sonido hardware) necesita llenar su buffer con más datos.
static int process (jack_nframes_t nframes, void * arg)
{\tjack_default_audio_sample_t buf ;
\tunsigned int i;
\touts = (jack_default_audio_sample_t *)jack_port_get_buffer (output_port, nframes) ;\tinfo_t *info = (info_t *) arg;
\t
\tmemcpy (outs_original, buffer2 + frames_counter_original, sizeof (jack_default_audio_sample_t) * nframes * DOUBLE_SAMPLES * 2);\tint k=0;
\tfloat k2;
\tk2 = nframes/info->shift_pitch;
\tfloat var, var2 = 0;
\tint part_entera = 0;
\tvar = 1/info->shift_pitch – 1;\tfor (i = 0 ; i < nframes ; i++)
\t{\t\t\tif (info->shift_pitch < 1) {
\t\t\tif (frames_counter + i >= info->numFrames / shift_pitch_equivalent) { // shift_pitch_equivalent = info.shift_pitch quan no faig un escombrat
\t\t\tinfo->play_done=1;
\t\t\treturn 0;
\t\t\t}
\t\t} else { // >= 1
\t\t\tif (frames_counter_original + i >= info->numFrames * DOUBLE_SAMPLES) {
\t\t\tinfo->play_done=1;
\t\t\treturn 0;
\t\t\t}
\t\t}
\t\t
\t\tif (info->shift_pitch > 1) {
\t\t\tk=(int)(i*DOUBLE_SAMPLES*info->shift_pitch + .5);
\t\t\touts[i] = outs_original[k];\t
\t\t} else if (info->shift_pitch <= 1) {
\t\t\touts[k] = outs_original[i*DOUBLE_SAMPLES];
\t\t\tif ((int)var2 != part_entera) {
\t\t\t\touts[k+1] = outs_original[i*DOUBLE_SAMPLES+1];
\t\tpart_entera = int(var2);
\t\tk++;
\t\t\t}
\t\t\tvar2 = var2 + var;
\t\t\tk++;\t\t\t
\t\t}\t}
\tframes_counter += nframes;
\tframes_counter_original += nframes * DOUBLE_SAMPLES * info->shift_pitch ;
\t
\treturn 0 ;
} /* process */
¿Y para qué sirve todo esto? Como hemos dicho es una aplicación didáctica, sirve sobre todo para aprender:
- para aprender: teoría del Procesamiento Digital del Señal
- para aprender: API de libsndfile
- para aprender API de JACK, ejemplo de cómo funciona la función de callback
pero a parte de aprender, se ha desarrollado con una idea en mente, que ha de ser el siguiente proyecto a realizar: utilizar una tableta gráfica Wacom, de las que utilizan los diseñadores gráficos, para producir sonidos realísticos, sensibles al movimiento y a la presión del lápiz, pero esto es otro proyecto: Reconocimiento real de gestos con la wacom y Síntesis de audio
- Descargar jplay-sndfile
- enlace del proyecto en la wiki