PiEfSi de speech recognition

Started by Drumpi, February 12, 2010, 06:17:19 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Drumpi

O lo que es lo mismo, unas gotas de lo que es mi proyecto de fin de carrera sobre reconocimiento de palabras.

De momento, hago este hilo porque veo que el mejor método que tengo ahora para estudiar las propiedades del sonido es la de usar bennu para abrir un WAV y ver la forma de onda y su FFT, por lo que es probable que consiga un prg para hacer dicha transformada básica en el tema de sonido (y parece ser que imagen).
Como es algo estandar, no creo que influya en temas de derechos y demás.

La idea es poder VER cómo varían las frecuencias de una voz a otra, a distintos tonos e incluso diciendo palabras simples, y a lo mejor necesito que me echeis una mano.
De momento dejo el hilo abierto, hoy he empezado a ver mi voz con otro programa, pero espero poder hacer lo propio con un código bennu, y visto lo visto apenas usa unas pocas frecuencias.

En el momento que vea que la cosa funciona en Bennu, pasaré a trasladarlo a la beagle y aqui ya no tendré más que mostrar, hasta que termine y me ponga a hacer el módulo.

Ya iré comentando cosas e iré pidiendo ayuda ;). Splinter, espero que hayas hecho tus deberes con los float :D :D :D :D :D
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Windgate

¿Ya hay alguna forma de conocer la forma de onda de un .wav con Bennu?
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

SplinterGU

no realmente desde bennu, pero creo que la idea no es analizar un wav, sino capturar uno...

con respecto a analizar la onda de un sonido se podria indagar en los filtros de SDL_mixer... que sirven en base a un wav cargado en memoria hacerle post-processing...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Rein (K´)ah Al-Ghul

Para visualizar la voz, planeas usar algo similar a un ecualizador y/o un espectrografo??
si recuerdo bien, la voz humana va desde 80 Hz hasta los 1100 Hz...
supongo que las demas frecuencias se dan por descartadas :P

Rein (K´)ah Al-Ghul
Infected with the Krieger strain of the Human-MetaHuman Vampiric Virus.

en vez de darme Karma positivo, denme (K´)arma negativ

Drumpi

#4
La idea es coger un archivo en formato wav, que va sin compresión, y leer todos los datos para obtener una forma de onda, es decir, la amplitud de la señal en cada momento discreto del tiempo, y con eso crear una imagen, pixel por pixel, de la señal.
Después mostrar esa información por la pantalla y crear un algoritmo de FFT para obtener la descomposición en frecuencias en cada posición del tiempo, y verlo.

Obviamente, fread y put_pixel serán mis herramientas básicas ;D

De esta forma, conseguir ver en qué frecuencias se descompone la voz y cómo varía. Ver qué frecuencias son las de cada persona, cuales representan el tono y así descartarlas para obtener la de la letra o sílaba, si es posible.
La idea es obtener las frecuencias que representan los fonemas, descartando tono y características propias de las personas, si es posible (algo tiene que haber o las personas no seríamos capaces de entendernos unas con otras).

Quizás con eso pueda elaborar un diccionario reducido para el proyecto y no tenga que recurrir a otras bases de datos.
De frecuencias no descarto nada, pues quiero intentar un estudio desde lo más básico. He leido bastante del tema y todo se centra en un diccionario con distintas voces (creo, porque no recuerdo la cifra exacta, que un diccionario completo consta de más de 104000 minutos de audio) y quien sabe, a lo mejor encuentro un método sencillo ^^U
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

grisendo

Mola tío :D

Yo no sé mucho de sonido, soy más bien de imágenes pero hay muchas cosas en común
en las cuales igual te puedo dar algún tipo de ayuda... Aunque me imagino que te habrás
mirado mil cosas y sabrás de todo más que yo jeje.

Así a ojo, y utilizado terminología poco seria, creo que el timbre viene dado por los "adornos"
de la onda (si es más triangulada, cuadrada o sinusoidal), la amplitud de onda el volumen y
el tono viene dado por la frecuencia de la onda...

Pero vamos, posiblemente necesites utilizar entrenadores/clasificadores como redes neuronales,
máquinas vector soporte, etc... de eso sé algo más.

Si puedes poner por aquí alguna bibliografía básica sobre el tema estaría muy bien :)
Y si cuando termines el PFC me pasas la memoria para que aprenda sobre el tema, ya ni te cuento :P


l1nk3rn3l

#7
http://www.google.com/Top/Computers/Speech_Technology/

AUNQUE pensandolo bien lo que propones para bennu es
muy bueno , ya tenemos deteccion de movimientos con camara
ahora solo falta ordenes de voz en ingles o castellano,
para mover unidades ...

o hacer alguna otra cosa posible con la voz como insultar al oponente..   ;D

grisendo

Quizá esto te sirva... o no  ::)

He hecho este PRG donde la función loadRawWav(fichero) lee un archivo .WAV sin compresión (PCM, de 8 o 16 bits, mono o estéreo) y lo almacena en los vectores globales raw_left y raw_right, cuyo tamaño final se almacena en la global raw_max_length. Si es mono, ambos vectores tienen los mismos valores.

pintaOnda() te muestra la onda en pantalla de cada canal (una parte de ella, para moverse hay que usar las teclas IZQUIERDA y DERECHA)
el canal izquierdo es el de arriba y el canal derecho es el de abajo.

Solo he comprobado que funciona con el "chord.wav" de windows xp (c:\windows\media\chord.wav) y comparando con un editor de audio
parece que las ondas coinciden... No me he molestado en comparar más archivos :)

A partir de esos vectores con los valores de la onda, puedes calcular la DFT, FFT, DCT...

Aunque para hacer todo esto... es más fácil con Matlab! Sobretodo porque o usas todo sonidos sin compresión o tienes que implementar
la codificación para cada tipo de archivo de audio que vayas a utilizar... Y porque tiene miles de funciones (FFT y tal) ya implementadas!!

Pero bueno, ahí te lo dejo ;)

[code language="bennu"]PROGRAM test;

CONST
    WIDTH = 800;
    HEIGHT = 600;

    Y_LEFT_CENTER = 200;
    Y_RIGHT_CENTER = 400;
    MAX_HEIGHT = 100;
    X_STEP = 20;

END

GLOBAL
    int *raw_left;
    int *raw_right;
    unsigned int raw_max_length;

    unsigned int fileSize;
    unsigned int channels;
    unsigned int sampleRate;
    unsigned int bitsPerSample;
    unsigned int dataSize;

    int cargado;

    unsigned int max_value;
END

BEGIN
    set_fps(25, 0);
    set_mode(WIDTH, HEIGHT, 32, MODE_WINDOW);
    cargado = 0;
    loadRawWav("chord.wav");
    pintaOnda();
    LOOP
        FRAME;
    END
END

PROCESS pintaOnda()
PRIVATE
    int x_i, x_e;
    int x_len;
    int i;
    int fondo;
BEGIN
    x_len = WIDTH;
    x_i = 0;
    drawing_color(rgb(255, 0, 0));
    fondo = map_new(HEIGHT, WIDTH, 32);
    LOOP
        x_e = x_i + x_len;
        FOR(i=x_i; i<x_e; i++)
            IF((i>=0)AND(i<raw_max_length))
                map_put_pixel(0, fondo, (i-x_i), Y_LEFT_CENTER+raw_left*MAX_HEIGHT/max_value, rgb(255, 0, 0));
                map_put_pixel(0, fondo, (i-x_i), Y_LEFT_CENTER, rgb(0, 255, 0));
                map_put_pixel(0, fondo, (i-x_i), Y_RIGHT_CENTER+raw_right*MAX_HEIGHT/max_value, rgb(255, 0, 0));
                map_put_pixel(0, fondo, (i-x_i), Y_RIGHT_CENTER, rgb(0, 255, 0));
            END
        END
        IF(key(_right))
            map_clear(0, fondo, rgb(0,0,0));
            x_i += X_STEP;
        END
        IF(key(_left))
            map_clear(0, fondo, rgb(0,0,0));
            x_i -= X_STEP;
        END
        IF(key(_esc))
            BREAK;
        END
        put_screen(0, fondo);
        FRAME;
    END
ONEXIT
    let_me_alone();
END

FUNCTION loadRawWav(string fichero)
PRIVATE
    int i;
    int handle;

    int value;

    unsigned byte oneByte;
    unsigned short twoBytes;
    unsigned int fourBytes;

    signed short twoBytesSigned;

    int channel;
BEGIN

    // Formato WAV PCM explicado en https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

    handle = fopen(fichero, O_READ);

    fread(handle, fourBytes); // Leo ChunkID: "RIFF"
    fread(handle, fourBytes); // Leo ChunkSize: Tamanyo del fichero - 8
    fileSize = fourBytes + 8;

    fread(handle, fourBytes); // Leo Format: "WAVE"
    fread(handle, fourBytes); // Leo Subchunk1ID: "fmt "
    fread(handle, fourBytes); // Leo Subchunk1Size: 16
    fread(handle, twoBytes); // Leo AudioFormat: 1
    fread(handle, twoBytes); // Leo NumChannels: 2
    channels = twoBytes;

    fread(handle, fourBytes); // Leo SampleRate
    sampleRate = fourBytes;

    fread(handle, fourBytes); // Leo ByteRate
    fread(handle, twoBytes); // Leo BlockAlign
    fread(handle, twoBytes); // Leo BitsPerSample
    bitsPerSample = twoBytes;

    fread(handle, fourBytes); // Leo Subchunk2ID: "data"
    fread(handle, fourBytes); // Leo Subchunk2Size: Tamanyo de los datos
    dataSize = fourBytes / channels;

    IF(bitsPerSample==8)
        max_value = 255;
    ELSE
        max_value = 32767;
    END

    channel = 0;
    raw_max_length = 0;

    raw_left = mem_alloc(dataSize*sizeof(int));
    raw_right = mem_alloc(dataSize*sizeof(int));

    FOR(i=0; i<dataSize; i++)
        IF(!feof(handle))
            IF(bitsPerSample == 8)
                fread(handle, oneByte);
                value = oneByte;
            ELSIF(bitsPerSample == 16)
                fread(handle, twoBytesSigned);
                value = twoBytesSigned;
            END
            IF(channels == 1)
                raw_left[raw_max_length] = value;
                raw_right[raw_max_length] = value;
                raw_max_length++;
            ELSE
                IF(channel == 0)
                    raw_left[raw_max_length] = value;
                    channel = 1;
                ELSE
                    raw_right[raw_max_length] = value;
                    raw_max_length++;
                    channel = 0;
                END
            END
        ELSE
            RETURN(0);
        END
    END
    fclose(handle);
    RETURN(1);
END[/code]

Drumpi

Juer, que no me deja responder:

Muchas gracias por los enlaces, L1nk3rn3l, les echaré un vistacillo, pero no creo que me valgan, pues son programas enfocados al inglés, y su fonética no tiene nada que ver con la que quiero desarrollar, en español. Además, usan el API de Windows, lo que me deja el código cerrado, que es lo que quiero ver.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Drumpi

Y a ti también, Grisendo. Me he estado leyendo el PFC que nos pasastes y es muy completo, además, se entiende de miedo y me está ayudando mucho a buscar cosas. Pena que la base de datos, Aurora2, es en inglés, me habría ahorrado mucho trabajo (y diversión ;D). He estado buscando otras bases de datos en español, pero sólo encuentro sudamericanas, y además con muy pocas palabras.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Drumpi

Quiero intentar evitar la fase de "entrenamiento", más que nada porque dudo que me de tiempo a aprender redes neuronales, teniendo que re-aprender C, y a manejar la beagleboard. Yo soy un teleco, no informático: mi carrera consiste en tomar una señal y procesarla, no que el ordenador haga virguerías ^^U
Como mucho, que la fase de entrenamiento se dedique a extraer las características sonoras de la persona para eliminarlas de la señal.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Drumpi

Y gracias por el código, pero precisamente hoy ya he estado trabajando en ello. Precisamente venía a pedir ayuda porque tenía problemas con las signed short, ya que estoy acostumbrado a usar sólo byte, word e int, pero ya he mirado tu código y ya dispongo de lectura para SIGNED WORD.
Ya he conseguido dibujar mi primera onda: ahora debo ajustarla a la pantalla (no me ha dejado crear un mapa de 29321x65536) y empezar a transformarla en frecuencias (posiblemente la deje "bonita" metiéndole el fichero a examinar por parámetros y permitiendo cargar más de una señal, porque luego tendré que comparar).

Aun no se si dividir la señal en tramas, como en el proyecto, o hacer la conversión de forma contínua (o semi-continua, si añado sólo medio buffer de datos nuevos puedo ahorrar la mitad de cálculos).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Drumpi

Y perdón por tantos mensajes, pero llevo cuatro horas intentando responder y no me dejaba escribir un mensaje más largo :S
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

grisendo

Justamente iba a postear ahora una segunda versión más maja que la anterior :P
con líneas en vez de puntos y la posibilidad de hacer zoom y moverse con las flechas...
gracias a la cual he descubierto que o no sé hacer funcionar drawing_stipple()
o funciona mal (lo he intentado usar para pintar el eje con línea discontinua pero
no pinta nada el jodío).

Alguien sabe si hay alguna forma de emitir "pitiditos" de una determinada
amplitud? Para reproducir un sonido muestra a muestra a partir de un vector
(sí, a veces se me va la pinza y me gusta trabajar a bajísimo nivel :P)

Pongo aquí el código de dibujar, por si acaso le sirve a alguien:

[code language="bennu"]PROGRAM test2;

CONST
    WIDTH = 1280;
    HEIGHT = 1024;

    Y_LEFT_CENTER = 200;
    Y_RIGHT_CENTER = 800;
    MAX_HEIGHT = 300;
    X_STEP = 20;

END

GLOBAL
    int *raw_left;
    int *raw_right;
    unsigned int raw_max_length;

    unsigned int fileSize;
    unsigned int channels;
    unsigned int sampleRate;
    unsigned int bitsPerSample;
    unsigned int dataSize;

    int cargado;

    unsigned int max_value;
END

BEGIN
    set_fps(25, 0);
    set_mode(WIDTH, HEIGHT, 32, MODE_WINDOW);
    cargado = 0;
    loadRawWav("chord.wav");
    pintaOnda();
    LOOP
        FRAME;
    END
END

PROCESS pintaOnda()
PRIVATE
    int x_i, x_e;
    int x_len;
    int i, j;
    int fondo;
    int color, negro, linea;
    int zoom;
    int valleft[WIDTH];
    int valright[WIDTH];
    int minj, maxj;
BEGIN
    zoom = 1;
    x_i = 0;
    color = rgb(255, 0, 0);
    negro = rgb(0, 0, 0);
    linea = rgb(255, 255, 255);
    fondo = map_new(WIDTH, HEIGHT, 32);
    drawing_map(0, fondo);
    LOOP
        drawing_color(negro);
        draw_box(0, 0, WIDTH-1, HEIGHT-1);
        x_len = WIDTH*zoom;
        x_e = x_i + x_len;
        minj = WIDTH;
        maxj = 0;
        FOR(i=x_i, j=0; i<x_e; i+=zoom, j++)
            IF((i>=0)AND(i<raw_max_length))
                IF(j<minj)
                    minj=j;
                END
                valleft[j]=Y_LEFT_CENTER-raw_left*MAX_HEIGHT/max_value;
                valright[j]=Y_RIGHT_CENTER-raw_right*MAX_HEIGHT/max_value;
                maxj=j;
            END
        END
        drawing_color(color);
        FOR(j=minj; j<maxj-1; j++)
            draw_line(j, valleft[j], j+1, valleft[j+1]);
            draw_line(j, valright[j], j+1, valright[j+1]);
        END
        drawing_color(linea);
        IF(minj<=maxj)
            draw_line(minj, Y_LEFT_CENTER, maxj, Y_LEFT_CENTER);
            draw_line(minj, Y_RIGHT_CENTER, maxj, Y_RIGHT_CENTER);
        END
        IF(key(_right))
            IF(x_e<raw_max_length+X_STEP*ZOOM)
                x_i += X_STEP*zoom;
            END
        ELSIF(key(_left))
            IF(x_i>-X_STEP*ZOOM)
                x_i -= X_STEP*zoom;
            END
        ELSIF(key(_down))
            IF(zoom<25)
                zoom++;
            END
        ELSIF(key(_up))
            IF(zoom>1)
                zoom--;
            END
        ELSIF(key(_esc))
            BREAK;
        END
        put_screen(0, fondo);
        FRAME;
    END
ONEXIT
    let_me_alone();
END

FUNCTION loadRawWav(string fichero)
PRIVATE
    int i;
    int handle;

    int value;

    unsigned byte oneByte;
    unsigned short twoBytes;
    unsigned int fourBytes;

    signed short twoBytesSigned;

    int channel;
BEGIN

    // Formato WAV PCM explicado en https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

    handle = fopen(fichero, O_READ);

    fread(handle, fourBytes); // Leo ChunkID: "RIFF"
    fread(handle, fourBytes); // Leo ChunkSize: Tamanyo del fichero - 8
    fileSize = fourBytes + 8;

    fread(handle, fourBytes); // Leo Format: "WAVE"
    fread(handle, fourBytes); // Leo Subchunk1ID: "fmt "
    fread(handle, fourBytes); // Leo Subchunk1Size: 16
    fread(handle, twoBytes); // Leo AudioFormat: 1
    fread(handle, twoBytes); // Leo NumChannels: 2
    channels = twoBytes;

    fread(handle, fourBytes); // Leo SampleRate
    sampleRate = fourBytes;

    fread(handle, fourBytes); // Leo ByteRate
    fread(handle, twoBytes); // Leo BlockAlign
    fread(handle, twoBytes); // Leo BitsPerSample
    bitsPerSample = twoBytes;

    fread(handle, fourBytes); // Leo Subchunk2ID: "data"
    fread(handle, fourBytes); // Leo Subchunk2Size: Tamanyo de los datos
    dataSize = fourBytes / channels;

    IF(bitsPerSample==8)
        max_value = 255;
    ELSE
        max_value = 32767;
    END

    channel = 0;
    raw_max_length = 0;

    raw_left = mem_alloc(dataSize*sizeof(int));
    raw_right = mem_alloc(dataSize*sizeof(int));

    FOR(i=0; i<dataSize; i++)
        IF(!feof(handle))
            IF(bitsPerSample == 8)
                fread(handle, oneByte);
                value = oneByte;
            ELSIF(bitsPerSample == 16)
                fread(handle, twoBytesSigned);
                value = twoBytesSigned;
            END
            IF(channels == 1)
                raw_left[raw_max_length] = value;
                raw_right[raw_max_length] = value;
                raw_max_length++;
            ELSE
                IF(channel == 0)
                    raw_left[raw_max_length] = value;
                    channel = 1;
                ELSE
                    raw_right[raw_max_length] = value;
                    raw_max_length++;
                    channel = 0;
                END
            END
        ELSE
            RETURN(0);
        END
    END
    fclose(handle);
    RETURN(1);
END[/code]