instituto politecnico nacional escuela superior de ingenieria

Transcripción

instituto politecnico nacional escuela superior de ingenieria
INSTITUTO POLITECNICO NACIONAL
ESCUELA SUPERIOR DE INGENIERIA MECANICA Y ELECTRICA
UNIDAD ZACATENCO
DISEÑO DE UN ECUALIZADOR GRÁFICO DE SONIDO
Tesis que presenta
Juan Sı́muta Peña
Para Obtener el Titulo de
Ingeniero en Comunicaciones y Electrónica
En la Especialidad de
Acústica
Asesores:
Dr. Maximino Peña Guerrero.
Ing. José de Jesús Negrete Redondo
México D.F.
2006
Trabajo de tesis que forma parte de los resultados obtenidos con nuestro proyecto
de investigación, KLDSP: Compilador de C para procesamiento de señales digitales
acusticas, número de registro 20050293 asignado por la Coordinacon General de Posgrado e Investigación del Instituto Politécnico Nacional durante febrero 2005 a enero
2006, desarrollado en el laboratorio de la academia de acústica de la ESIME Zacatenco, y dirigido por Dr.Maximino Peña Guerrero, Ing. José de Jesus Negrete Redondo
y Dr.Pablo Lizana Paulin.
ii
iii
RESUMEN
Un ecualizador o igualador es un dispositivo diseñado para corregir, modificar,
compensar y acondicionar la respuesta a la frecuencia de un sistema de audio.
Lo anterior se realiza por medio del empleo de filtros, alterando mediante la actuación sobre sus controles la señal recibida y obteniendo ası́, la respuesta idónea
para el local y tipo de música deseada. Ası́ al ser un procesador de sonido nos permite particionar y obtener porciones de la señal de audio original y alterar su nivel
de volumen en forma independiente.
Basándonos en los algoritmos computacionales de la Transformada Rápida de
Fourier, hemos desarrollado un ecualizador gráfico. Los componentes del ecualizador
se implementaron en Visual C++.NET, como son los potenciómetros deslizables que
varı́an la amplitud de las frecuencias que componen la señal de entrada. Esta es
mostrada en la pantalla gráfica como espectro de frecuencias. Empleando la transformada inversa de Fourier obtenemos la señal ecualizada en el dominio del tiempo,
la cual es procesada por las rutinas de sonido y enviadas a la tarjeta de audio de la
computadora.
iv
OBJETIVO
Desarrollar un ecualizador gráfico con veinte bandas que controle múltiples niveles
de sonido digital.
JUSTIFICACION
Un ecualizador nos permite amplificar o atenuar una amplia gama de sonidos,
para compensar la no linealidad y dado que ecualizar es fundamental en un sistema
de audio, se realizo el presente trabajo mediante un entorno de programación que
pudiera utilizarse en versiones Windows 95 o superiores.
v
Agradecimientos
A mis padres: Juan Sı́muta Lázaro y Marina Peña Garcı́a por su cariño, su esfuerzo, sus enseñanzas y consejos, su ejemplo de trabajo, honradez y dedicación, por
su fe y confianza que en mi depositaron y por darme la mejor de las herencias que yo
pueda recibir, con todo mi respeto les dedico este trabajo.
A mi hermana: Fabiola Sı́muta Peña. Por apoyarme siempre, por ser una gran
amiga y una compañı́a en mi vida.
A los ingenieros y profesores: Maximino Peña Guerrero y José de Jesús Negrete
Redondo. Por su paciencia y excelente guı́a para la realización del presente trabajo.
A mis maestros: Por compartir sus conocimientos, mismos que han sido fundamentales para mi formación, tanto personal como académica.
Al Instituto Politécnico Nacional y a la E.S.I.M.E.: Por brindarme la oportunidad
de realizar una de mis metas en la vida y por todas las experiencias que en sus aulas
vivi, disfruté y por siempre recordaré.
Y a las personas que directa o indirectamente colaboraron para la realización de
este trabajo.
Juan Simuta Peña
vi
Todo lo que vivamente
imaginamos, ardientemente
deseamos,
sinceramente
creamos
y
entusiastamente emprendemos ...inevitablemente
sucederá.
Anónimo
vii
Índice general
1. Introducción
1.1. Antecedentes . .
1.2. Los Ecualizadores
1.3. Control de tonos
1.4. Mi Trabajo . . .
.
.
.
.
6
6
6
8
9
2. Fundamentos de la Ecualización de Sonido
2.1. Principios de funcionamiento . . . . . . . . . . . . . . . . . . . . . . .
2.2. Métodos de programación . . . . . . . . . . . . . . . . . . . . . . . .
10
10
11
3. Aspectos del Diseño
3.1. Filtros Pasivos . .
3.2. Filtros Activos .
3.3. Filtros digitales .
14
14
18
20
. . . . .
Gráficos
. . . . .
. . . . .
de
. .
. .
. .
un
. .
. .
. .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Ecualizador
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
4. Diseño de Nuestro Ecualizador de Veinte Bandas
4.1. Computadoras digitales . . . . . . . . . . . . . . . .
4.2. Estructura de una tarjeta de sonido . . . . . . . . .
4.3. Estructuras del controlador de sonido . . . . . . . .
4.4. Programación de una señal senoidal . . . . . . . . .
4.5. Graficación y controles gráficos . . . . . . . . . . .
4.6. Algoritmo computacional FFT . . . . . . . . . . . .
5. Pruebas y Resultados
5.1. Método Orientado a Procedimientos .
5.2. Trabajando con las barras verticales .
5.3. Normalización de las gráficas . . . . .
5.4. Lectura de un archivo .wav . . . . . .
5.5. Formatos bigendian vs. littleendian .
5.6. Visualización de las señales . . . . . .
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
27
28
31
33
35
.
.
.
.
.
.
39
39
40
42
42
46
46
6. Conclusiones y Trabajos Futuros
6.1. Trabajos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
53
A. Transformada Rápida de Fourier
A.1. Algoritmo FFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.2. Decimación en Tiempo . . . . . . . . . . . . . . . . . . . . . . . . . .
A.3. Decimación en frecuencia . . . . . . . . . . . . . . . . . . . . . . . . .
55
55
56
57
B. Código fuente del ecualizador
60
2
Índice de figuras
3.1. Filtro pasa altas desbalanceado de red en L (a) y de red en T (b). . .
3.2. Filtro pasa bajas desbalanceado de sección en L (a) y de sección pi (b).
3.3. Filtro pasa banda balanceado LC (a) y filtro pasa banda desbalanceado
LC (b). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4. Filtro de rechazo de banda LC balanceado (a) y filtro de rechazo de
banda LC desbalanceado (b). . . . . . . . . . . . . . . . . . . . . . .
3.5. Diagrama esquemático del filtro Butterworth para pasa bajas (a), pasa
altas (b) y pasa banda (c). . . . . . . . . . . . . . . . . . . . . . . . .
3.6. Diagrama esquemático del filtro Chebyshev para pasabajas (a), pasa
altas (b) y pasa banda (c). . . . . . . . . . . . . . . . . . . . . . . . .
3.7. Filtro activo pasabajos (a) y pendiente práctica (b). . . . . . . . . . .
3.8. Filtro activo pasa altas (a) y respuesta del filtro (b). . . . . . . . . . .
3.9. Filtro activo pasa banda (a) y la respuesta del filtro (b). . . . . . . .
16
17
18
19
20
21
22
23
24
4.1. Diagrama en bloques de la organización de una computadora digital.
4.2. Diagrama en bloques de una tarjeta de sonido. . . . . . . . . . . . . .
4.3. A mayor número de muestras se aprecia mejor el periodo de la onda
seno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4. La regresión se realiza haciendo el if (f Angle > 2∗P I) y luego f Angle− =
2 ∗ P I. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5. Algunos ejemplos de recursos . . . . . . . . . . . . . . . . . . . . . .
34
35
5.1.
5.2.
5.3.
5.4.
5.5.
5.6.
5.7.
5.8.
43
46
47
47
48
48
48
49
Panel de control de 20 bandas . . . . . . . . . . . . . . . . . .
Señal de entrada senoidal . . . . . . . . . . . . . . . . . . . . .
Ruido blanco como señal de entrada . . . . . . . . . . . . . . .
Espectro de magnitud de la señal senoidal . . . . . . . . . . .
Espectro de magnitud del ruido blanco . . . . . . . . . . . . .
Señal senoidal resultante, una vez ecualizada . . . . . . . . . .
Ruido blanco una vez ecualizado . . . . . . . . . . . . . . . . .
Vista general del ecualizador gráfico teniendo como señal ruido
3
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
blanco.
26
27
33
5.9. Vista general del ecualizador gráfico teniendo como señal una onda
senoidal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
A.1.
A.2.
A.3.
A.4.
57
58
58
59
Separación de la DFT de N puntos en dos DFT´s de N/2
Separación de la DFT para la decimación en frecuencia .
Decimacion en tiempo para 8 muestras (N = 8) . . . . .
Decimación en frecuencia para 8 muestras (N = 8) . . .
4
puntos
. . . . .
. . . . .
. . . . .
.
.
.
.
.
.
.
.
Índice de tablas
5.1. Encabezado de un archivo de sonido WAVE . . . . . . . . . . . . . .
5
43
Capı́tulo 1
Introducción
1.1.
Antecedentes
Existen diferentes tipos de altavoces que producen una gran variedad de sonidos
cuando se emplean con el mismo amplificador; también, un juego de altavoces puede
tener diferentes sonidos cuando se emplea con diferentes sistemas de audio. Utilizando
un ecualizador, pueden evitarse estas discrepancias.
Un ecualizador o igualador es un dispositivo diseñado para corregir, modificar,
compensar y acondicionar la respuesta a la frecuencia de un sistema de audio.
Lo anterior se realiza por medio del empleo de filtros, alterando mediante la actuación sobre sus controles la señal recibida y obteniendo ası́, la respuesta idónea
para el local y tipo de música deseada. Ası́ al ser un procesador de sonido nos permite particionar y obtener porciones de la señal de audio original y alterar su nivel
de volumen en forma independiente.
Los ecualizadores más simples son los controles de graves-agudos, que tienen todos
los amplificadores estereofónicos, fonógrafos y tocacintas.
1.2.
Los Ecualizadores Gráficos
Algunos de los ecualizadores más complejos tienen generalmente varios potenciómetros lineales de contacto deslizante, situados uno al lado del otro. Cada potenciómetro controla la ganancia en un intervalo de frecuencias diferente. Puede haber
6
ocho o más de estos potenciómetros. Ası́, el ajuste de los potenciómetros da la impresión de un despliegue gráfico de la curva de respuesta a la frecuencia que se aplica a
la señal. Por lo anterior expuesto es que se les denomina ecualizadores gráficos.
Dependiendo del modelo y la marca,podemos encontrarnos con 15, 30 o 31 potenciometros en los casos más comunes. Cada banda se encarga de aumentar o disminuir
la señal de una frecuencia determinada, éstas van desde los 20 Hz hasta los 20kHz.
Nótese que aunque en principio con el uso de los ecualizadores lo que se persigue
es obtener una curva de comportamiento lo más neutra posible, es decir, aquélla en la
que los niveles de energı́a se reparten por igual en cada octava, también es posible su
uso para la obtención de ciertos modos acústicos preponderantes. Los ecualizadores
son sumamente útiles en sistemas de audio ubicados en salas de especial sonorización,
salas reverberantes y salas mal acondicionadas.
Otra caracterı́stica de este tipo de ecualizador es que algunos de ellos disponen de
un led de color en cada potenciómetro deslizante, lo cual permite una rápida visión
de ecualización realizada.
Uno de los ejemplos mas tı́picos del ecualizador gráfico es el ecualizador de octava
en el que encontramos 10 puntos de control. Recordemos que el ancho de banda
audible recorre 10 octavas: 30, 60, 125, 250, 500 Hz, 1, 2, 4, 8 y 16 KHz, y estas
son las frecuencias de actuación del ecualizador. En general los ecualizadores gráficos
permiten reforzar o atenuar la señal en unos 6 a 15 dB, siempre sobre la misma
frecuencia de trabajo.
Habitualmente los ecualizadores profesionales suelen disponer de un selector de
BY-PASS o puenteado de la señal. También es usual disponer de dos secciones de
filtrado independientes para los canales izquierdo y derecho del sistema. Sus acciones
serán totalmente independientes.
Otro tipo de ecualizadores que no podemos dejar pasar son los paramétricos, que
controlan los tres parámetros fundamentales: ancho de banda, frecuencia central de
actuación (Q) y amplitud de la señal. Aunque hasta el momento los ecualizadores
7
más difundidos son los gráficos, cada dı́a irrumpen con más fuerza los paramétricos
en el terreno profesional. Estos ecualizadores están considerados como de los más
potentes del mercado por su posibilidad de variación sobre todos los parámetros
del filtro. Se utilizan básicamente para corregir problemas puntuales, localizando la
frecuencia central en aquellos lugares exactos de la curva de respuesta en los que
haya irregularidades. Una vez posicionados, ajustaremos el ancho de banda para que
sea el más parecido posible al de la irregularidad (cresta o valle) y se utilizará el
control de ganancia de manera inversa a la acción de la curva. Para tener acceso a
una buena ecualización son necesarios, al menos, cuatro filtros en paralelo, cada uno
correspondiente a las cuatro bandas en que dividimos el espectro (agudos, medios,
bajos y muy bajos). Función importante es que nos permite compensar, ajustar o
mejorar el sonido según nuestros gustos.
1.3.
Control de tonos
Un control de tonos funciona de la siguiente manera: A una frecuencia de 63 Hz
se destacan los sonidos graves masivos como los de tambores, órganos, etc. dando una
sensación de grandiosidad. Subiendo la frecuencia nos da una sensación de plenitud,
esto es 125 Hz ya que si baja, aumenta la transparencia. Ahora bajando a 250 Hz el
control, disminuye el posible eco. Si uno aumenta a 500 Hz se entiende que aumenta
la fuerza del sonido pero si se baja da la sensación de que el sonido no es completo.
A partir de aquı́ las frecuencias siguen en aumento y la frecuencia de 1 kHZ actúa
sobre la voz del cantante y se puede dejar casi inaudible. Para 2 kHz se estimula el
oı́do, pero puede dar sensación metálica, entonces hay que disminuirlo. En 4 kHz el
sonido puede estar muy alto y en consecuencia dar también una sensación metálica
y dura. Una octava que aumenta la brillantez de instrumentos de cuerda y viento, es
la de 8 kHz y la de 16 kHz es la que aumenta la presencia de sonidos sutiles, como
platillos, triángulos, etc.
8
1.4.
Mi Trabajo
Esta tesis presenta el diseño de un ecualizador gráfico de sonido mediante rutinas en lenguaje C y está organizada de la siguiente manera: El segundo capı́tulo son
los fundamentos necesarios para la ecualización de sonido tales como, ondas sonoras,
frecuencia, análisis de Fourier, entre otros. El tercer capı́tulo esta enfocado a la explicación de los filtros, como lo son los pasivos los activos y los digitales que son parte
fundamental dentro de cualquier ecualizador. El cuarto capı́tulo es entrar en materia
de programación, es decir, la explicación de diferentes estructuras computacionales
para la graficación y la obtención del sonido. En el capı́tulo cinco se mostrará las
pruebas realizadas y por consecuencia los resultados obtenidos de estas mismas. Y
por último, en el capitulo seis se presentaran las conclusiones que se obtuvieron del
presente trabajo asi como algunas propuestas para mejorar el mismo.
9
Capı́tulo 2
Fundamentos de la Ecualización de
Sonido
En el presente capı́tulo se darán algunas definiciones o conceptos, mismos que
son importantes en cuanto a su estudio para el tratamiento de esta tesis y que están
estrechamente ligados con el tema del ecualizador virtual, algunos de estos conceptos
son: ondas sonoras, audio, sintetizador,gráficos, herramientas de programación entre
otros que son muy útiles e interesantes. Un ecualizador utiliza de cierta forma todos estos conceptos del que por supuesto resalta el de frecuencia; ası́ que para este
concepto se explicará lo que es el análisis de Fourier.
2.1.
Principios de funcionamiento
Para cualquier perturbación periódica, la rapidez con la que se repite un ciclo se
le llama frecuencia. Su unidad es el Hertz (ciclos/seg.), y se abrevia Hz. El intervalo
de audiofrecuencias al cual puede detectar energı́a acústica el oı́do humano, varı́a
alrededor de 20 Hz a 20 KHz.
A un movimiento ondulatorio longitudinal que se produce mediante una perturbación periódica en el aire se le denomina onda sonora. De aquı́ se puede definir el
sonido como los perturbaciones longitudinales producidas en el aire que son percibidas
por el oı́do humano.
Un concepto ligado a los anteriores es el audio, que es la representación eléctrica
10
del sonido, de tal manera que puede ser amplificada, atenuada, acoplada, medida,
transportada a grandes distancias, igualada, mezclada, grabada, procesada, distorsionada, retardada, transmitida por medios electromagnéticos, etc.
Una herramienta matemática muy importante es el Análisis de Fourier, nombre
dado en honor de Jean-Baptiste-Joseph Fourier (1768-1830) matemático francés, introdujo los métodos mas sencillos para la solución de los problemas de valor en la
frontera, que se presentan en el tratamiento analı́tico de la conducción del calor. En
la actualidad se ha convertido en método indispensable para el tratamiento de casi
toda cuestión de fı́sica moderna, sistemas lineales, teorı́a de comunicaciones, etc.
El método matemático que nos permite obtener el espectro de potencia como
función de la frecuencia para una forma de onda de la señal dada es la Transformada
de Fourier. Se utiliza para transformar una señal representada en el dominio del
tiempo al dominio de la frecuencia sin alterar su contenido de información, solo es
una forma diferente de representarla.
Estas transformaciones permiten la evaluación de formas de onda, tanto periódicas
como aperiódicas. Cualquier forma de onda puede aproximarse matemáticamente
sobre un intervalo finito, con tal de que exista un número finito de máximos y mı́nimos
en el intervalo.
2.2.
Métodos de programación
Una de las técnicas y de las capacidades mas importantes de las PC actuales para
comprender las relaciones entre conjuntos de datos es la graficación, ya que sin esta
herramienta la mayorı́a del trabajo de carácter administrativo, técnico y cientı́fico
se perderı́a en un mar de datos. Para pintar gráficos (incluyendo texto) ası́ como
para mostrar los elementos que componen una interfaz de usuario, Windows utiliza
la interfaz de dispositivos gráficos (GDI: Graphics Device Interface), dicho de otra
forma, la GDI es el medio que Windows proporciona para dibujar sobre dispositivos
gráficos.
11
Para el procesamiento informático del sonido es necesario realizar su generación
y captura mediante métodos computacionales y almacenarlo en su memoria o disco.
Existe una infinidad de tarjetas que pueden realizar la generación y la captura, aunque
las más implantadas son las Sound Blaster de Creative.
El proceso básico para la captura de sonidos se puede dividir en tres pasos:
Primero, el sonido se transmite por el aire hasta el micrófono, el cual transforma
la señal acústica a niveles eléctricos. Segundo, la señal analógica pasa a través de un
convertidor analógico-digital. Este resulta ser el elemento más importante, sus caracterı́sticas establecen la frecuencia máxima a la que se puede trabajar y el número de
bits que se utilizan para cuantificar cada muestra. Y, tercero, mediante un buffer de
audio se copia cada muestra a la memoria principal de la computadora .
Otra aplicación muy útil para la generación y captura de sonido es Multimedia.
Esto quiere decir que es la capacidad para comunicarse en mas de una forma además
de ser una combinación de animaciones, gráficos, sonido, texto y video. Por supuesto
que para obtener una infinidad de sonidos la computadora deberá de contar con una
tarjeta de sonido como la que se menciono arriba.
Algo muy importante para el desarrollo de la presente tesis son las Herramientas
de Programación. Ası́ como los sistemas operativos tienen funciones especificas de
control y administración , el software o programas de desarrollo se utilizan para crear
aplicaciones que resuelvan diversos problemas cientı́ficos, comerciales administrativos
o del cualquier tipo. Estos programas se denominan lenguajes de programación y están
integrados por programas y utilerı́as que facilitan la construcción de las aplicaciones
para los usuarios del sistema informatico.
Un concepto que no se debe pasar por alto y que es básico para el entendimiento
de un lenguaje de programación es el del algoritmo, que es una secuencia ordenada
de pasos, bien precisos, que permite obtener la solución de un problema dado.
Es importante mencionar que estos lenguajes tienen un conjunto de sı́mbolos,
instrucciones y enunciados que están sujetos a una serie de reglas y como cualquier
12
lenguaje humano utiliza un léxico, una sintaxis y un semántica.
Un entorno y un lenguaje de programación denominado de alto nivel, en el que
se combinan la programación orientada a objetos (C++) y el sistema de desarrollo diseñado especialmente para crear aplicaciones gráficas para Windows (SDK) es
Visual C++.
13
Capı́tulo 3
Aspectos del Diseño de un
Ecualizador
Diseñar es parte fundamental para la ciencia, ya que una vez que se ha madurado
una idea, esta se empieza a desarrollar, utilizando los componentes que para ello sean
necesarios. En este capı́tulo se trataran los dispositivos que pueden se utilizados para
el diseño de un ecualizador, siendo los filtros parte esencial del mismo, sin olvidar,
por supuesto, algunas otras definiciones que están inmersas en este tema como son:
la resistencia, la inductancia y la capacitancia, solo por mencionar algunas.
3.1.
Filtros Pasivos
Empezaré con los componentes básicos para este tipo de diseño, los cuales son
llamados pasivos. Uno de ellos es el capacitor, que tiene la capacidad de almacenar
la energı́a eléctrica, a esta propiedad se le llama capacitancia, se representa por la
letra C y se mide en unidades llamadas farads. En relación esto, otro componente
es el resistor, que proporciona un valor fijo para oponerse al paso de la corriente, a
esta propiedad se le llama resistencia, depende de las dimensiones del material y su
unidad es el ohm. Un componente más es el inductor, que esta especialmente diseñado
para proporcionar una cantidad controlada de inductancia, siendo esta propiedad, la
capacidad de almacenar energı́a en forma de campo magnético, se representa por la
letra L y su unidad es el henry.
14
Siguiendo con este contexto, diré que un filtro es una red capaz de hacer una
selección entre frecuencias, dejando pasar componentes o señales conducidas en una
banda de frecuencias y bloqueando el paso de estas mismas que van fuera de esa
banda de frecuencias.
Ahora, existen los filtros pasivos, que son redes diseñadas con resistores, capacitores e inductores conectados para ser selectivos en cuanto a la frecuencia, además, no
requieren de fuente externa de alimentación para su operación. Para la construcción
de diversas formas de filtros, atenuadores, etc., se utiliza una red pi que es un circuito
desbalanceado y que como se vera en el capı́tulo, la mayorı́a de los filtros la tienen
implementada.
Uno de ellos es el filtro pasa altas, que es una combinación de capacitancia, inductancia y/o resistencia, cuyo objetivo es producir un alto nivel de atenuación debajo
de ciertas frecuencia y poca o nula atenuación arriba de esa frecuencia. La frecuencia
a la que ocurre la transición se llama frecuencia de corte. Los filtros pasaaltas mas
simples consisten en un inductor en paralelo y capacitores en serie. Los mas elaborados tienen una combinación de inductores en paralelo y capacitores en serie, como
los mostrados en la figura (3.1).
Una combinación de capacitancia, inductancia y/o resistencia, que produce un alto
nivel de atenuación arriba de una frecuencia especı́fica, y poca o ninguna atenuación
debajo de esa frecuencia es el filtro pasa bajas. En un filtro pasa bajas se pueden
sustituir los inductores por resistores. La figura (3.2) muestra los filtros pasaabajos
mas elaborados ya que tienen una combinación de inductores en paralelo y capacitores
en serie.
Cualquier circuito resonante o combinación de circuitos resonantes, diseñado para
hacer discriminación contra todas las frecuencias, con excepción de una frecuencia
f o, o una banda de frecuencias comprendidas entre dos frecuencias limitadoras f 0 y
f 1 se llama filtro pasa banda, mostrado en la figura (3.3). Cabe mencionar que un
circuito resonante es aquel que contiene reactancias finitas que se cancelan entre si.
15
Figura 3.1: Filtro pasa altas desbalanceado de red en L (a) y de red en T (b).
Un filtro de rechazo de banda es un circuito resonante diseñado para dejar pasar
energı́a a todas las frecuencias, con excepción de las comprendidas dentro de un cierto
intervalo. Este es mostrado en la figura (3.4). Existe cierta semejanza entre estos filtros
y los de pasa banda. La difrencia fundamental es que el filtro de rechazo de banda
esta formado por circuitos en paralelo LC conectados en serie con la trayectoria de la
señal o circuitos en serie LC conectados en paralelo con la trayectoria de la señal, en
cambio en los filtros pasabanda los circuitos resonantes en serie están conectados en
serie, y los circuitos de resonancia en paralelo están conectados en paralelo.
A un tipo especial de filtro selectivo, diseñado para tener una respuesta plana en
su pasa banda y una caracterı́stica uniforme de atenuación progresiva, es denominado, filtro Butterworth. Puede diseñarse para respuesta de pasa bajas, pasa altas y
pasa banda. Deben escogerse correctamente las impedancias de entrada y de carga
para obtener un funcionamiento adecuado; los valores de los resistores, inductores y
16
Figura 3.2: Filtro pasa bajas desbalanceado de sección en L (a) y de sección pi (b).
capacitores del filtro dependen de las impedancias de entrada y carga. La figura (3.5)
muestra este tipo de filtro.
Otro filtro especial selectivo es el llamado filtro de Chebyshev (que tambien se
escribe Tschebyscheff, Tschebyshev) mostrado en la figura (3.6), su caracterı́stica es
que tiene respuesta casi plana dentro de su pasa banda, atenuación casi completa
fuera del pasabanda y respuesta de corte precisa. Puede diseñarse para repuestas
iguales al de Butterworth.
Es importante mencionar lo que es el ancho de banda, ya que es un término que se
usa para definir la frecuencia ocupada por una señal y la que se requiere paratransferir
efectivamente la información que va a portar la señal. Un filtro pasabanda tiene un
ancho de banda de una respuesta rectangular con la misma tasa de transferencia de
energı́a y se le llama ancho de banda efectivo.
17
Figura 3.3: Filtro pasa banda balanceado LC (a) y filtro pasa banda desbalanceado
LC (b).
3.2.
Filtros Activos
Antes de continuar con otro tipo de filtros es debido mencionar el dispositivo llamado amplificador operacional, este amplificador exhibe una gran estabilidad, además
de tener una ganancia muy alta, con una elevada impedancia de entrada y una baja
impedancia de salida.
Esta mención es importante debido a que los filtros activos incluyen un amplificador de este tipo, sin olvidar que también cuentan con elementos pasivos. Son
adecuados para circuitos de estado sólido, porque eliminan la necesidad de inductores
abultados, por otra parte, pueden amplificar la señal o proporcionar ganancia, pero
requieren de una fuente de alimentación y tienen un gran uso en audiofrecuencias.
Un filtro que suministra amplificación desde dc hasta una frecuencia de corte y
luego no pasa señales por arriba de esas frecuencias, se dice que es un filtro pasa
18
Figura 3.4: Filtro de rechazo de banda LC balanceado (a) y filtro de rechazo de banda
LC desbalanceado (b).
bajas. Un filtro pasa bajas de primer orden usa un solo resistor y capacitor tiene una
pendiente práctica de -20 dB por década. Este es mostrado en la figura (3.7)
Al proporcionar o pasar señales por arriba de una frecuencia de corte, estamos
hablando de un filtro pasa altas. El filtro mostrado en la figura (3.8)es de primer
orden, dado que solo tiene un solo resistor y capacitor
Cuando el circuito de filtro pasa señales arriba de una frecuencia de corte y debajo
de una segunda frecuencia de corte, es llamado filtro pasa banda. La figura(3.9) nos
muestra que para conformar este filtro se utiliza la sección pasa altas y la sección
pasa bajas
Otro filtro activo de circuito integrado que no requiere para su operación de capacitores ni de inductores discretos, es el filtro de capacitor conmutado , también es capaz
de remplazar a los filtros LC de inductancia-capacitancia. La figura(??) muestra un
19
Figura 3.5: Diagrama esquemático del filtro Butterworth para pasa bajas (a), pasa
altas (b) y pasa banda (c).
diagrama de un filtro de esta clase, formada por una sección de conmutación y un
amplificador operacional. Los interruptores S1 y S2 son transistores MOS disparados
por pulsos de reloj.
3.3.
Filtros digitales
Inseparable es el proceso de filtrado para el audio digital. Se necesitan filtros
analógicos o digitales -y en ocasiones, ambos- en los ADC, DAC, en los canales de
datos de los grabadores digitales y en los sistemas de transmisión, asi como en los
conversores y ecualizadores de la frecuencia de muestreo. La diferencia principal entre
los filtros analógicos y los digitales es que en dominio digital pueden construirse
arquitecturas muy complejas a bajo costo y que los cálculos aritméticos no estan
sujetos a la tolerancia o a las variaciones de los componentes.
20
Figura 3.6: Diagrama esquemático del filtro Chebyshev para pasabajas (a), pasa altas
(b) y pasa banda (c).
El filtrado puede modificar la respuesta en frecuencia de un sistema y la respuesta
de fase. Toda combinación entre la respuesta en frecuencia y la de fase determina la
respuesta impulsiva en el dominio temporal. En un filtro perfecto todas las frecuencias
deben experimentar el mismo retardo temporal. Dado que un impulso contiene un
espectro infinito, un filtro que presente un error de retardo de grupo separará las
distintas frecuencias de un impulso a lo largo del eje temporal.
Un retardo puro provoca un desplazamiento de fase proporcional a la frecuencia
y un filtro que presente esta caracteristica se dice que es de fase lineal. La respuesta
impúlsiva de un filtro de fase lineal es simetrica. Es practicamente imposible fabricar
un filtro analógico con una fase lineal perfecta por lo que muchos filtros van seguidos
de una etapa de ecualización que a menudo es igual de compleja que el propio filtro.
En el dominio digital es fácil realizar un filtro de fase lineal por lo que la ecualización
21
Figura 3.7: Filtro activo pasabajos (a) y pendiente práctica (b).
de fase no es necesaria. Debido a la naturaleza muestreada de la señal cualquiera que
sea la respuesta a bajas frecuencias todos los canales digitales ( asi como los analógicos
muestreados) funcionan como filtros pasabajo de corte en el limite de Nyquist o a la
mitad de la frecuencia de muestreo.
22
Figura 3.8: Filtro activo pasa altas (a) y respuesta del filtro (b).
23
Figura 3.9: Filtro activo pasa banda (a) y la respuesta del filtro (b).
24
Capı́tulo 4
Diseño de Nuestro Ecualizador de
Veinte Bandas
He llegado al capı́tulo en donde el ecualizador será diseñado mediante la implementación del algoritmo computacional de la Transformada Rápida de Fourier, ası́ como también mediante la utilización de diversas estructuras de sonido, mismas que son
necesarias para que se pueda programar la tarjeta de sonido de nuestra computadora
digital.
4.1.
Computadoras digitales
A todo dispositivo que ayude y facilite el cálculo, ya sea desde un ábaco hasta una
calculadora electrónica se le puede llamar computadora. En la década de los cincuentas
se le llamaron computadoras a los equipos electrónicos, formados por potenciómetros
y amplificadores operacionales con tubos al vacı́o, siendo esta la primera generación.
Con el paso del tiempo, se sustituyeron los tubos del vacı́o por transistores siendo esta
la segunda generación, luego vino la era del silicio y los circuitos integrados, esta fue
la llamada tercera generación; la cuarta generación son los microcomputadores y las
computadoras personales, mejor conocidas como PC (por sus siglas en inglés Personal
Computer)que se logro gracias a la miniaturización de los circuitos integrados. La era
en que vivimos es la quinta generación donde el objetivo es que los mecanismos de
computo sean cada ves mas rápidos y pequeños.
25
Por otra parte, existen dos tipos básicos de computadoras electrónicas: las analógicas y las digitales, las primeras efectúan cálculos en forma de analogı́as eléctricas de
números o de variables fı́sicas. Las segundas además de contar, se distinguen de otros
dispositivos de cálculo, por su velocidad, su memoria interna y la ejecución automática
de un programa +almacenado en su memoria.
En la siguiente ilustración, se presenta un bosquejo general de la organización
de un computadora digital, de la cual nos interesan los dispositivos periféricos, en
especial uno, que es la tarjeta de sonido, ya que es la encargada de generar, capturar
y reproducir el sonido, aparte de que sin ella, simple y sencillamente seria muy difı́cil
utilizar los programas multimedia.
Figura 4.1: Diagrama en bloques de la organización de una computadora digital.
26
4.2.
Estructura de una tarjeta de sonido
Cuando una tarjeta crea un sonido, se dice que el sonido es sintetizado y es entonces cuando actúa como un instrumento musical. Esta se divide en dos partes ,
la parte analógica y la parte MIDI (M usicalIntrumentDigitalInterf ace) asi que a
nosotros nos corresponde trabajar con la parte analógica. Durante varios años,han
creado efectos musicales por medio de una tecnologı́a simple denominada sı́ntesis FM
misma que utilizan las tarjetas Sound Blaster. Hay otra tecnologı́a que reemplaza a
la anterior y es la wavetable y es porque en esta tecnologı́a ya no se crea música con
tonos computarizados, mas bien, buscan el instrumento deseado en una tabla (una
selección integrada con grabaciones reales y crean el sonido con base a la muestra).
Figura 4.2: Diagrama en bloques de una tarjeta de sonido.
Estas tarjetas son básicas para poder trabajar con la combinación que involucra
texto, sonido, video y animación que sea producida por cualquier medio electrónico,
27
para que una determinada presentación cobre vida y se haga mas realista.
Para la creación de sonidos, un método más que utiliza la tarjeta de sonido consiste
en la reproducción de muestras, esto es, de una prueba se hace el sonido realmente
grabado, mientras mas muestras haya en un archivo de sonido , mas real sonará éste.
4.3.
Estructuras del controlador de sonido
Entrando ahora en materia de programación, es sabido que el presente trabajo se
realizará con el compilador Visual C++, ası́ que es importante hacer mención de la
diferentes estructuras y funciones que se utilizaran para las pruebas y desarrollo del
ecualizador gráfico virtual; dentro de este lenguaje se utiliza la notación húngara, que
básicamente utiliza letras minúsculas para indicar el inicio del nombre de la variable,
ası́ como su tipo.
A continuación, se observará que las estructuras y definiciones usan la palabra
”WAVE”,(ON DA), porque se trabajarán con archivos de forma de onda,ası́ que para
comenzar tenemos la estructura W AV EF ORM AT EX que contiene la información
más común de los datos de una forma de onda y la cual define el formato. Cabe
mencionar que para formatos que requieren mayor información, esta se incluirá como
primer miembro en otra estructura con la información adicional, la función tiene la
siguiente estructura:
typedef
WORD
WORD
DWORD
DWORD
WORD
WORD
WORD
struct (
wFormatTag;
nChannels;
nSamplesPerSec;
nAvgBytesPerSec;
nBlockAlign;
wbitsPerSample;
CbSize; ) WAVEFORMATEX;
Se puede ver en la estructura que wF ormatT ag es del tipo W ORD ya que especifica el tipo de formato de la forma de onda; nChannels, del tipo igual al anterior,
especifica el número de canales a utilizar; del tipo DW ORD es nSamplesP erSec,
que es el número de muestras por segundo, que se reproducirán o grabarán en cada
28
canal y nAvgBytesP erSec que hace un promedio de la transferencia de datos en
bytes por segundo; para el alineamiento de bloques en bytes esta nBlockAlign, que
también es la unidad mı́nima de datos para el tipo de formato de la forma de onda y
wBitsperSample son los bits por muestra para wF ormatT ag.
Dado que un ecualizador utiliza señales de entrada y salida, a continuación se
mencionarán las estructuras que sirven para este fin; primero mencionare la función
waveOutOpen, del tipo M M RESU LT , la cual es la encargada de abrir el dispositivo
de salida, he aquı́ su estructura:
MMRESULT
LPHWAVEOUT
UINT
LPWAVEFORMATEX
DWORD
DWORD
waveOutOpen(
phwo,
uDeviceID,
pwfx,
dwCallBackInstance,
fdwOpen
);
De aquı́ se puede decir que phwo es del tipo LP HW AV EOU T y es ocupado para
identificar y relacionar las diferentes funciones de salida; para identificar el dispositivo
a utilizar ya sea de entrada o salida es uDeviceID que es del tipo U IN T .
Otra función de salida es waveOutP repareHader que es la que prepara un bloque
de datos de la forma de onda, para reproducirlo y su estructura es:
MMRESULT
HWAVEOUT
LPWAVEHDR
UINT
waveOutPrepareHeader (
hwi,
phw,
cbwh
);
Donde, el manejador del dispositivo de salida de la forma de onda es hwo; phw
es una dirección de la estructura W AV EHDR que es utilizada para definir los bloques de datos que se van a preparar y cbwh es el tamaño en bytes de la estructura
W AV EHDR.
Ligada a la anterior función es waveOutU nprepareHeader, solo que esta limpia
la preparación que es realizada por waveOutP repareHeader, la función debe ser
llamada después de que el dispositivo termine con un bloque de datos y antes de
liberar el buffer. A continuación se presenta su estructura.
29
MMRESULT
HWAVEOUT
LPWAVEHDR
UINT
waveOutUnprepareHeader (
hwi,
phw,
cbwh
);
Es importante mencionar que los parámetros hwi, phw y cbwh funcionan de la
misma forma que en waveOutU nprapareHader y también son utilizados en la siguiente función que es la que manda un bloque de datos a la salida del dispositivo y
es denominada waveOutW rite siendo su estructura:
MMRESULT
HWAVEOUT
LPWAVEHDR
UINT
waveOutWrite (
hwo,
pwh,
cbwh
);
Para cerrar el dispositivo de salida de forma de onda existe la función llamada
waveOutClose y tiene una sencilla estructura como se muestra a continuación:
MMRESULT
HWAVEOUT
waveOutClose(
hwo
);
Ası́ mismo la función con una estructura muy simple es waveOutReset, que detiene
el dispositivo de salida y reincia a cero.
MMRESULT waveOutReset (
HWAVEOUT hwo
);
Continuando, ahora se describirán las estructura y funciones de entrada, siendo
muy similares a las de salida.
Una de estas funciones es waveInOpen, que se requiere para abrir el dispositivo
de entrada de la forma de onda para después grabarlo, su estructura es la siguiente:
MMRESULT
LPHWAVEIN
UINT
LPWAVEFORMATEX
DWORD
DWORD
waveInOpen (
phwi,
uDeviceID,
pwfx,
dwCallBackInstance,
fdwOpen
);
De la cual el parámetro phwi es del tipo LP HW AV EIN y llena una dirección
con un manija identificada para abrir el dispositivo de entrada; uDeviceID es un
30
identificador de entrada del dispositivo; pwf x es para direccionar una estructura
W AV EF ORM AT EX,misma que identifica el formato deseado para grabar la forma
de onda; del tipo DW ORD son dwCallback, dwCallbackInstance y f dwOpen.
Para cerrar el dispositivo dado de la forma de onda de audio se emplea la función
waveInClose, siendo su estructura:
MMRESULT waveInClose(
HWAVEIN hwi
);
Otra función es la que prepara un buffer para la forma de onda de audio y se
llama waveInP repareHeader, y tiene como estructura:
MMRESULT
HWAVEIN
LPWAVEHDR
UINT
waveInPrepareHeader (
hwi,
phw
cbwh
);
Cuando se limpia la preparación desarrollada por la anterior la función se denomina waveInU nprepareHeader y puede ser llamada después que el controlador del
dispositivo llena un buffer y retorna a esta aplicación, su estructura es:
MMRESULT
HWAVEIN
LPWAVEHDR
UINT
waveInUnprepareHeader (
hwi,
pwh,
cbwh
);
Si uno desea detener la forma de onda de audio dada por el dispositivo y reiniciar
en la posición de cero, se debe utilizar la función denominada waveInReset, esta
función tiene una estructura muy sencilla:
MMRESULT waveInReset (
HWAVEIN hwi
);
4.4.
Programación de una señal senoidal
A continuación se tratará cómo generar la función seno, es decir algo como esto
f (x) = Asenwt, de donde se sabe que A representa a la amplitud de la onda y w es
la frecuencia angular multiplicada por el tiempo t. Este tipo de función utiliza una
31
medida angular o circular que se encuentra alrededor del perı́metro de un cı́rculo sobre
una longitud igual al radio del circulo llamada radián. En relación a esto se puede
decir que la circunferencia de una cı́rculo es 2π veces el radio, de manera que hay 2π
radianes en un cı́rculo de 360 grados, siendo los grados unidad de medida angular.
También se utiliza los que es un fasor, y que es un número complejo que expresa la
magnitud y la fase de una cantidad que varı́a con el tiempo.
Pero, ¿cuál es el problema de generar esta función por medio de algún lenguaje de
programación? el problema radica en que no es nada fácil intentar sacar o meter una
onda senoidal para poder escucharla, ası́ que continuación se presenta una función
llamada fillbuffer (llenar buffer), escrita en lenguaje C, misma que sirve de apoyo y
es fundamental dentro del proceso del diseño. Sabiendo que, un buffer es un depósito
de datos intermedio, es decir, una parte reservada de la memoria donde los datos son
almacenados temporalmente y esta función ayuda al entendimiento de cómo es que
se llena un buffer y su relación con la función seno.
VOID fillbuffer (LPBYTE Pbuffer, int iFreq){
static double fAngle;
int i;
for (i=0 ; i<BUFFER_SIZE; i++)
{
pBuffer[i] = (BYTE) (127+127 * sin (fAngle);
fAngle += 2* PI *iFreq / SAMPLE_RATE;
}
}
if (fAngle > 2 * PI)
fAngle -= 2* PI ;
Para el análisis de esta función, se debe tomar en cuenta que un buffer tiene valores
desde 0 hasta 256 (0-FF), por esta razón al parámetro pBuffer realiza la operación
que arriba se indica, esto es porque el producto de 127 ∗ sin(f Angle) nos da un valor
entre 0 y 127 (la función seno tiene un rango entre 1 y -1 ) y sumándole el otro 127
nos da como máximo 256 (FF), que es el tamaño del buffer cuyos elementos del tipo
BYTE son de 8 bit por muestra. Ahora fAngle se refiere al valor del ángulo, que es
32
resultado del producto 2 por PI por iFreq (que es la frecuencia que se desea) por
SAM P LERAT E que es la razón de muestra, y que se puede explicar por medio del
teorema de Nyquist que nos dice que una señal (en este caso la onda seno) debe de ser
muestreada a una velocidad que sea por lo menos el doble de la frecuencia mas alta
que se encuentra en la señal, es decir, que si nuestra onda seno tiene un frecuencia
de 1000 Hz la frecuencia de muestreo debe de ser mı́nimo de 2000 Hz, o dicho de
otra forma, entre más muestras se tengan de la señal mejor se podrá trabajar con
ella, ya que se tendrá mas información acerca de esta. Para que esto quede claro se
hará una analogı́a de un buffer con un metro, siendo las rayitas”de los centı́metros
las muestras.
Figura 4.3: A mayor número de muestras se aprecia mejor el periodo de la onda seno.
La función entonces se encarga de llenar un buffer de datos que representan una
forma de onda, en este caso, una onda seno, para después pasar a la Interface de
Programa de Aplicación (API: Aplication Program Interface). Para una onda de amplitud continua, lo que hace la función es tomar solo un ciclo de esta onda, para que
cuando llegue a 2 veces π o 360◦ cumpla su propósito de llenar el buffer.
4.5.
Graficación y controles gráficos
La graficación como ya se mencionó anteriormente, es parte fundamental dentro
del área de la informática, en nuestro caso es básica para la programación, es decir,
33
Figura 4.4: La regresión se realiza haciendo el if (f Angle > 2∗P I) y luego f Angle− =
2 ∗ P I.
es una implementación para obtener un resultado en forma de un dibujo. Para esto
su usan los pixeles, que son pequeños puntos que forman una extensa capa a lo largo
y ancho de la pantalla.
Como es sabido, se está utilizando el lenguaje Visual C++ para el desarrollo de
programas que son de mucha utilidad, dentro del mismo existen los llamados recursos,
que vienen siendo los mapas de bits, el cursor, una caja de dialogo, un icono, una
barra de herramientas y la versión, existiendo un editor para cada uno de estos tipos.
También existen las ventanas, que son objetos con ciertas propiedades y a las
cuales se les asocia un código, ası́ que es evidente que la programación de Windows
es orientada a objetos. generalmente una ventana principal (ventana madre), tiene
diferentes elementos como los son: un tı́tulo con el nombre de la aplicación, un menú,
bordes de tamaño y cuando son necesarias barras de desplazamiento (horizontal y
vertical).Esta ventana, a su vez puede contener otras ventanas denominadas ventanas
hijas.
34
Figura 4.5: Algunos ejemplos de recursos
A las notificaciones que Windows envı́a a una aplicación que se está ejecutando
para indicarle que algo ha sucedido se les llaman mensajes. Algunos ejemplos sencillos
pueden ser el hacer clic sobre un botón, mover el ratón, pulsar una tecla, etc. En
un mapa de mensajes, se distinguen tres tipos de mensajes: mensajes de órdenes,
mensajes de notificación y mensajes de ventana.
Y es precisamente en una ventana madre en donde colocaremos las barras de
desplazamiento, que son los recursos mas significativos a utilizar, cabe mencionar que
se trabaja con estas, dado que, pueden desplazar la información hacia arriba o hacia
abajo para representar un valor entero.
4.6.
Algoritmo computacional FFT
Para trabajar dentro Visual C++ se implemento un programa escrito en lenguaje
C , que nos permite obtener de manera numérica y gráfica los resultados que deseamos
35
obtener. Asi que una vez que realizamos la interface gráfica agregamos el algoritmo
denominado mariposa que es el que nos permite realizar las operaciones con una
mayor velocidad de calculo. El programa utilizado es el siguiente:
#include<windows.h>
#include<math.h>
#define pi 3.1415926
#define Tmuestreo 0.0000226757 //44.1 kHz
#define frec 1000 //1 KHZ
void bitrev(int N, float XR[1024],float XI[1024]);
main()
{
int i, j, k, M,M1,M2;
float C, S,tempr, tempi, XR[2048], XI[2048], WR[2048], WI[2048];
int N=1024, L=10, N1, N2, I1, I2;
for(i=0;i<=N-1;i++)
{
WR[i] = cos(2*pi*i/N);
WI[i] = -sin(2*pi*i/N);
}
for(i=0;i<=N-1;i++)
{
XR[i] = sin(2*pi*frec*Tmuestreo*i);
XI[i] = 0.0;
}
N2 = N;
for(i=0;i<L;i++)
{
N1=N2;
N2=N2/2;
I1=0;
I2=N/N1;
for(j=0;j<N2;j++)
{
C=WR[I1];
S=WI[I1];
I1=I1+I2;
for(k=j;k<N;k+=N1)
{
M=k+N2;
tempr=XR[k]-XR[M];
XR[k]=XR[k]+XR[M];
tempi=XI[k]-XI[M];
XI[k]=XI[k]+XI[M];
XR[M]=C*tempr-S*tempi;
XI[M]=C*tempi+S*tempr;
36
}
}
}
bitrev(N,XR,XI);
for(i=0;i<=(N-1)/2;i++)
{
X[i]=(sqrt(pow(XR[i],2)+pow(XI[i],2)));
LineTo(hdc,i+100,(int)(200.0-X[i]));
}
En este programa se toma una muestra x[n] real con un número de N muestras
potencia de dos, (es decir 2v = N ) donde v es el número de etapas de la Transformada
Rápida. Al observar el programa empieza con un desplegado en pantalla que pide el
numero de muestras que se desean transformar y las almacena en la variable N, a
continuación llama a una función int log2(int N) que obtiene el número de etapas de
la Transformada mediante el algoritmo base 2 del número de muestras, luego, genera
una tabla con los valores WN y se almacena en los arreglos para la parte real y la
imaginaria WR[N] y WI[N]. Después se hace una iteración para pedir por el teclado
el valor de cada uno de los elementos del arreglo que representará a la muestra y se
almacena en el arreglo X[N], teniendo esto se procede a realizar el algoritmo.
Como se puede apreciar en el último for es donde se localiza el resultado de la
Transformada, representado por cuestiones de graficación por el valor absoluto.
Otro punto a tomar en cuenta es que, ya sea el método de decimación en frecuencia
o en tiempo la secuencia de entrada es dada en orden normal y la salida queda con bits
invertidos, ası́ que para solucionar esta situación, se realiza la función llamada bitrev
(inversión de bits) que permiten que una secuencia del cálculo de la Transformada
Rápida sea reordenada para obtener el resultado deseado.
Se puede ilustrar con el caso N = 8, representado por tres bits. Los bits que deben
de ser cambiados de sus posiciones son el 3 y 1. Por ejemplo, (100)b queda (001)b.
Esto permite que el dato que estaba en la posición de memoria 4 = (100)b pase a la
37
posición 1 = (001)b.
Entonces, para que el resultado quede almacenado en los arreglos XR[N] y XI[N]
en orden natural, se utiliza la siguiente función:
void bitrev(int N, float XR[1024], float XI[1024])
{
float temp;
int i, j, k;
j=0;
for(i=0;i<N-1;i++)
{
if(i<j)
{
temp=XR[j];
XR[j]=XR[i];
XR[i]=temp;
temp=XI[j];
XI[j]=XI[i];
XI[i]=temp;
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
else
{
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
}
}
38
Capı́tulo 5
Pruebas y Resultados
En el presente capı́tulo se presentan las pruebas efectuadas para diferentes tipos
de señales a el algoritmo de la transformadada rápida de fourier, tales como una onda
senoidal, ruido blanco y un archivo .wav, de las cuales se muestran los resultados
obtenidos. También se muestra el procedimiento de programación mediante el cual
se desarrolló nuestro panel de control, asi como también las gráficas pertinentes para
cada tipo de señal.
5.1.
Método Orientado a Procedimientos
Es importante mencionar que sigo trabajando dentro del entorno Visual C++ solo
que ahora sin clases, sino que adaptamos el código fuente llamado sinewave.c con los
respectivos archivos de recursos y de cabecera.
Entonces dado que la ruitna de sonido permite trabajar con 2 buffers para que se
oiga de una manera continua, lo que hicimos fue lo siguiente: ir adaptando las veinte
barras de desplazamiento vertical, el algoritmo de la FFT, los marcos, etc., como a
continuación se explica:
La rutina de sonido se inicializa mediante la declaración de 2 buffers (buffer1 y
buffer2), hecho esto realiza un direccionamiento a la memoria; después por medio de
un botón genera un mensaje por el cual manda a llamar las funciones WaveOutWrite y
WaveOutprepareHeader que prepara el primer buffer para se tocado, a continuación
39
el case W M DON E es el encargado de que mientras un buffer esta tocando (esta
lleno) el otro se esta llenando en espera de ser tocado y asi sucesivamente; esta acción
se termina cuando uno oprime otro botón que genera otro mensaje y manda llamar
las estructuras W aveOutClose y W aveU nprepareHeader.
5.2.
Trabajando con las barras verticales
Continuando con las barras de desplazamiento, las cuales en este codigo fuente se
trabajarán con la diferencia de que ahora cada una tendra su propia estructura para
que de esta forma trabajen de una forma independiente una de otra. La estructura a
utilizar es la siguiente:
case WM_INITDIALOG:
hsc = GetDlgItem (hwnd, IDC_SCROLL) ;
SetScrollRange (hsc, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc, SB_CTL, 128,FALSE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE) ;
.
.
.
hsc = GetDlgItem (hwnd, IDC_SCROLL20) ;
SetScrollRange (hsc20, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc20, SB_CTL, 128,FALSE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE) ;
case WM_LINELEFT:
if(lParam==(LPARAM)hsc) var1--;
.
.
.
if(lParam==(LPARAM)hsc20) var20--;
case WM_LINERIGHT:
if(lParam==(LPARAM)hsc) var1++;
.
.
.
if(lParam==(LPARAM)hsc20) var20++;
case SB_THUMBTRACK:
if (lParam==(LPARAM)hsc) var1=HIWORD(wParam);
.
.
.
if (lParam==(LPARAM)hsc20) var20=HIWORD(wParam);
case SB_BOTTOM:
if (lParam==(LPARAM)hsc)
GetScrollRange(hsc,SB_CTL,&iDummy,&var1);
.
40
.
.
if (lParam==(LPARAM)hsc20)
GetScrollRange(hsc,SB_CTL,&iDummy20,&var20);
break ;
}
SetScrollPos (hsc,SB_CTL,var1,TRUE);
.
.
.
SetScrollPos (hsc,SB_CTL,var20,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT5,255-var1,TRUE);
.
.
.
SetDlgItemInt(hwnd,IDC_TEXT5,255-var20,TRUE);
Después de esto se inserta el algoritmo de la FFT, el cual se hara de una manera
modular para facilitar su manejo, esto es que el código se ha ido separando en funciones, dado que de esta forma solo se manda a llamar la parte del programa con lo
que nos interesa trabajar, quedando lo anterior de la siguiente manera:
//funcionseno(entrada);
ruidoblanco(entrada);
graficarentrada(hwnd,1024,entrada);
fft(nm,entrada,salida);
modificarfft(nm,salida,salidafft);
graficartransformadafft(hwnd,1024,salidafft);
ifft(nm,salidafft,salida3);
graficartransformadaifft(hwnd,1024,salida3);
Como se puede observar, como prueba se tienen dos señales, una es senoidal y otra
que genera ruido blanco. La señal que uno desee se toma como entrada para graficarse,
luego se le asigna a la Transformada Rápida de Fourier para obtener su espectro de
frecuencias, y aqui es donde se encuentra la parte medular de el presente trabajo: la
ecualización, misma que se obtiene al mover las barras, para que a continuación este
resultado se le asigne a la Transformada Inversa de Fourier para quedar en el dominio
del tiempo nuevamente y asi poder esucharlo por medio de la tarjeta de sonido.
41
5.3.
Normalización de las gráficas
Para normalizar las gráficas y presentarlas de una manera adecuada lo que se hizo
fue lo siguiente, se conoció el valor en pixels de cada uno de nuestros marcos mediante
las instrucciones MoveTo y LineTo obteniendo como resultado un marco de 1010 por
142 pixeles, y dado que los marcos son iguales se implemento la siguiente instruccion
dentro de nuestras funciones de graficación
MoveToEx(hdc,0,y,NULL);
for(i=0;i<=1010;i++)
{
y=(bentrada[i]/255)*142;
yy=y+240;
LineTo(hdc,i,yy);
}
garantizando con esto que cualquier señal que nosotros queramos graficar no rebasara los margenes de los marcos.
He dicho que para dar la impresión de atenuar o subir el nivel de la señal se
hará mediante las barras de desplazamiento; anteriormente se explico como se hará esto, recordando que son veinte, el primer paso fue colocar una por una y darles una
presentación adecuada para mostrar el panel de control como en la figura (5.1). Como
se puede apreciar a cada barra le corresponde una frecuencia que estan divididas en
intervalos desde 20 hasta 20k Hz, con lo cual se trata de cubrir las frecuencias mas significativas desde los agudas hasta las mas graves, obteniendo con esto la ecualización
de la señal senoidal.
5.4.
Lectura de un archivo .wav
De acuerdo con la Figura (5.1), se puede ver de una manera detallada cómo ha sido
diseñado el formato de un archivo .wav. Consideremos una matriz de m x n donde
n (0H-FH) son las filas, y m (0H-FH) son las columnas. Los elementos de la matriz
son números hexadecimales que constituyen cada uno de los campos que definen las
42
Figura 5.1: Panel de control de 20 bandas
caracteristicas de un archivo .wav. A continuación se describen cada uno de dichos
campos.
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
0
52
B0
B0
d4
1
49
B1
B1
d5
2
46
B2
B0
d6
3
46
B3
B1
d7
4
B0
B0
64
d8
5
B1
B1
61
d9
6
B2
B0
76
d10
7
B3
B1
61
d11
8
57
B0
B0
d12
9
41
B1
B1
d13
A
56
B2
B2
d14
B
45
B3
B3
d15
C
66
B0
d0
d16
D
62
B1
d1
d17
E
74
B2
d2
d18
F
20
B3
d3
d19
Tabla 5.1: Encabezado de un archivo de sonido WAVE
El primer campo de la matriz ocupa los elementos 00, 01, 02 y 03. En ellos se encuentran los cuatro números que identifican a un archivo de sonido WAV. Agrupándolos en cuatro bytes corresponderán a una cadena de caracteres ASCII que contienen
la palabra RIF F la cual es conocida como ”número mágico”. Dichos números en
hexadecimal son: 52H, 49H, 46H, y 46H.
43
El siguiente campo corresponde al tamaño del archivo que contiene el sonido
WAV. Estos números corresponden a la secuencia B0 , B1 , B2 , y B3 , los cuales ocupan
los elementos de la matriz 04, 05, 06, 07. Nótese que primero se lee el byte menos
significativo, y hasta el último se lee el byte más significativo.
Continuando con nuestra descripción, el siguiente campo numerado con los elementos 08,09,0A y 0B de la matriz contienen una cadena de caracteres ASCII que
corresponde a la palabra W AV E cuya secuencia de números en hexadecimal son 57H,
41H, 56H, y 45H.
En cuanto al siguente campo numerado con 0C,0D,0E y 0F, contiene una secuencia
de cracteres ASCII que corresponden a la palabra f mt. Nótese que dicha palabra
termina con un espacio en blanco. Entonces, su secuencia de números hexadecimales
serán 66H, 6DH, 74H y 20H. Este último corresponde al carácter espacio (20H).
Ahora bien, el campo que sigue se encuentra en las posiciones 10,11, 12 y 13 de
la matriz. En ellas se encuentra un número entero de 4 bytes que nos especifica el
tamano del bloque. Este número contiene la secuencia B0 , B1 , B2 , y B3 semejante en
orden a como se ha descrito en el campo Tamaño del Archivo. Es evidente que su
valor variará de acuerdo con un archivo.wav determinado.
Por otra parte, el siguiente campo (elementos 14 y 15) contienen un numero entero
formado por 2 bytes (B0 y B1 ) para indicar el tipo de formato. Si este número es igual
a cero, entonces indica que el archivo se ha grabado de manera monoaural (un sólo
microfono). Pero si dicho entero es igual a uno, entonces el sonido se grabado con dos
micrófonos, es decir, en estereofonı́a.
Prosiguiendo con la explicación,en nuestro siguiente campo se tiene como contenido el número de canales utilizados por el archivo.wav. Este es un número entero
de 2 bytes que tiene la secuencia B0 y B1 , misma que está contenida en los elementos
16 y 17 de la matriz en cuestión. Cabe mencionar que este número tiene que ver con
la forma de grabación del archivo.wav, es decir,que si es igual a uno entonces significa
que se grabo en formato monoaural, pero si es igual a dos, significa que se grabo en
44
formato estereo.
A continuación, el campo siguiente se refiere a la frecuencia de muestreo del archivo.wav, que puede tener un valor de 11,025, 22,050 o 44,100 Hz. Para este número
entero de 4 bytes los elementos que le corresponden en la matriz son 18, 19, 1A y 1B,
con una secuencia dada por B0 , B1 , B2 , y B3
El siguiente campo corresponde al número de bytes por segundo que se deben
intercambiar con la tarjeta de sonido para poder grabar o reproducir un archivo.wav.
Este es un número entero de 4 bytes que contiene una secuencia: B0 , B1 , B2 , y B3 y
cuyas posiciones de los elementos en la matriz corresponden con 1C,1D, 1E y 1F.
Siguiendo con la descripción, el siguiente campo nos indica los bytes por muestra
de nuestro archivo.wav. Este es un número entero de 2 bytes que tiene una secuencia
dada por B0 y B1 y sus elementos en la matriz son 20 y 21. Es preciso decir que si este
número es igual a uno tendremos ocho bits monoaurales, si es igual a 2 tendremos
ocho bits estereo o dieciseis monoaurales y si es igual a 4 tendremos dieciseis bits
estereo.
Para continuar con nuestro análisis, tenemos el campo que corresponde a los bits
por muestra, mismos que pueden ser ocho o dieciseis bits dependiendo de un determinado archivo.wav. Esta caracterı́stica es un número entero de dos bytes cuya secuencia
corresponde con B0 y B1 y que tiene sus elementos de la matriz posicionados en 22 y
23.
El siguiente campo contiene una cadena de caracteres ASCII que forman la palabra
data cuyos elementos en la matriz están ubicados en 24, 25, 26 y 27, teniendo una
secuencia de números hexadecimales dada por 64H, 61H, 76H y 61H
Finalmente tenemos la caracterı́stica que corresponde a la cantidad de datos que
es casi igual al Tamaño del Archivo. En consecuencia este también sera un número
entero de cuatro bytes, al cual le corresponde una secuencia B0 , B1 , B2 , y B3 y cuyos
elementos en la matriz tienen las posiciones 28,29, 2A y 2B.
Después de las caracteristicas mencionadas, a los campos subsecuentes correspon45
derán los datos de audio del archivo.wav
5.5.
Formatos bigendian vs. littleendian
Son formatos de almacenamiento de datos utilizados por los microprocesadores
para describir la relación que existe entre el orden y el almacenamiento de los bytes
(el mas significativo o el menos significativo). Por ejemplo Intel y Motorola tienen sus
datos en memoria de formas opuestas, es decir que si el 80386 (Intel) almacena 1234
5678 el 68020 (Motorola) leerá 7856 3412. Estos términos fueron usados por Danny
Cohen en octubre de 1981.
5.6.
Visualización de las señales
Ahora bien, teniendo como pruebas una señal senoidal igual con sen(2 ∗ pi ∗ f rec ∗
T muestreo∗i) y otra señal aleatoria que es la que nos genera el ruido blanco mostradas
en las Figuras (5.2) y (5.3) respectivamente:
Figura 5.2: Señal de entrada senoidal
y aplicando el programa de la Transformada Rápida se obtienen las figuras (5.4)
y (5.5), que nos muestran los espectros de magnitud para cada señal:
46
Figura 5.3: Ruido blanco como señal de entrada
Como se puede observar es el espectro de magnitud de la señal, mismo que se
controlará mediante una barra de desplazamiento vertical que dará la impresión de
atenuar o disminuir su amplitud.
Después de esto, lo que se quiere es regresar al dominio del tiempo, y esto se logra
mediante la transformada inversa, que esencialmente es el mismo programa solo que
la entrada ahora será el resultado de la Transformada Rápida, es decir, el espectro
de magnitud, obteniendo nuevamente la señal de entrada, pero ya ecualizada como
se muestra en las figuras (5.6) y (5.7):
47
Figura 5.4: Espectro de magnitud de la señal senoidal
Figura 5.5: Espectro de magnitud del ruido blanco
48
Figura 5.6: Señal senoidal resultante, una vez ecualizada
Figura 5.7: Ruido blanco una vez ecualizado
49
Figura 5.8: Vista general del ecualizador gráfico teniendo como señal ruido blanco.
50
Figura 5.9: Vista general del ecualizador gráfico teniendo como señal una onda
senoidal.
51
Capı́tulo 6
Conclusiones y Trabajos Futuros
El mundo moderno en que vivimos, crece y evoluciona de una manera vertiginosa, aplicándose esto a cualquier rubro, pero especialmente en la ciencia, que como
sabemos es una sola, pero para su estudio se divide en muchas ramas, lo cual nos permite la posibilidad de estudiarla y comprenderla de una mejor manera. En nuestro
caso esta posibilidad la tomamos y aplicamos en ramas como las matemáticas y la
computación.
Como es sabido las matemáticas las ha utilizado el hombre desde hace miles de
años, y con el tiempo las ha ido razonando, estudiando y por consecuencia desarrollando métodos que han ayudado a facilitar la forma de obtener los resultados deseados;
tal es el caso de Jean Baptiste Joseph Fourier, con su análisis sobre la conducción del
calor.
Nosotros nos basamos en este análisis, especı́ficamente con la llamada Transformada de Fourier, y aquı́ es donde interviene la otra rama antes mencionada: la computación. Y es que en estos dı́as es imprescindible esta poderosa herramienta, ya que
por principios de cuentas nos permite procesar grandes cantidades de información en
cuestión de segundos. Ası́ que utilizando este concepto se ha desarrollado un algoritmo computacional llamado Transformada Rápida de Fourier, mismo que tomamos
como base para desarrollar el ecualizador gráfico virtual.
Esto viene aunado a otra rama como lo es la acústica que es la encargada de
52
estudiar la generación, propagación y efecto de las ondas sonoras. Entonces una forma
de trabajar con el efecto de estas ondas es ecualizándolas, y para esto se utilizo el
algoritmo computacional antes mencionado.
El inicio de nuestro proyecto fue la elección de un lenguaje de programación que
nos permitiera el diseño de una interfase gráfica de acuerdo a nuestras necesidades.
Asi que de esta manera optamos por el lenguaje Visual C++ .NET, ya que este
lenguaje nos permitio un aprendizaje asi como también un fácil manejo. Asi pues
el diseñp de nuestro ecualizador gráfico fue realizado con utilidades al alcanze de
cualquier usuario.
Desde un principio se tuvo presente que el método matemático en el cuál deberiamos emplear seria la transf ormada rapida de F ourier (F F T ). Nuestros resultados
deberı́an presentarse graficamente por medio de una ventana principal para poder
visualisar las diferentes formas de onda. Lo anterior se logro mediante ciertas técnicas
de graficación y la implementación de una rutina para el algoritmo FFT realizada en
lenguaje C, la cual posteriormente fue insertada en el ambiente de Visual C++ .NET
para su compilación.
De esta forma al momento de realizar las diferentes pruebas nos mostraron gráfica
y correctamente los espectros de magnitud en el dominio de la frecuencia, asi como
también el resultado al regresar al dominio del tiempo una vez que se hubieron ecualizado las diversas señales con lo que pudimos comprobar que nuestros algoritmos FFT
y IFFT funcionaban correctamente
Nuestro siguiente paso fue comenzar a trabajar con el sonido, es decir enviar los
datos almacenados en un buf f er a otro buf f er que se esta incorporado al driver de
la tarjeta de sonido. En este punto nos topamos con otro problema, y es que al hacer
una investigación acerca de este tema descubrimos que en México existe muy poca
información al respecto, asi que lo que logro auxiliarnos fue el articulo encontrado en
una revista.
Entonces ahora si se comenzo a implementar la rutina la cual nos permitia llenar
53
en forma paulatina los buf f ers antes mencionados para que el sonida que se produjese
fuera constante. Nuevamente se probo con una onda senoidal, para después probar
con la generación de ruido blanco dándonos un resultado satisfactorio para las tres
señales.
Una vez hecho esto se juntaron ambas rutinas (la de la interfase gráfica y la del
sonido) para que de esta forma se pudiera llevar a cabo la ecualización de las señales
mediante las barras verticales.
En resumen las contribuciones mas importante de esta tesis son:
- La implementación de un algoritmo para la F F T mediante rutinas en lenguaje
C.
- La lectura de diversas señales de audio por medio de instrucciones de abjo nivel.
- Técnicas de gráficación en Visual C++ .NET
- Y por último un ecualizador gráfico de veinte bandas que puede ejecutarse en
sistemas Windows 95 o superiores.
6.1.
Trabajos futuros
A continuacion se presentan algunas sugerencias para la mejora y aplicación del
presente trabajo. Para una mejor calidad de presentación se pueden implementar
diversos elementos los cuales nos permitirán mejorar la apariencia, la funcionalidad
y la aplicación cientı́fica.
En lo que respecta a la estetica se puede mejorar la apariencia de las barras
verticales, dondoles por ejemplo una apariencia en tercera dimensión o mediante un
programa de edición hacer que esos controles se vean como en un ecualizador fı́sicas,
ademas de que las gráficas pueden ser de colores diferentes.
En cuanto a la funcionalidad una de las mejoras que se podrian realizar es que
mediante diversos métodos de programación se logre ecualizar en tiempo real con
cualquier tipo de archivo se sonido.
Ahora, como es sabido un ecualizador es fundamental es un sistema de audio
54
profesional asi que una utilidad futura seria que formara parte de uno, es decir, que
pueda se implementado a una consola, asi para un músico que disponga de una PC
podria utilizarlo de una manera rápida y fácil.
Una utilidad muy interesante es la implementación de un archivo .wav en tiempo
real la cual se seguirá investigando y desarrollando.
Por otra parte la presente tesis puede utilizarse con fines acádemicos para un mejor
entendimiento del análisis de Fourier refiriendose esto a la transformada rápida. O
bien el algoritmo podria ser adaptado para realizar un analizador de espectro, o
implementarlo para que pueda ser utilizado como un sismográfo, en fin estas solo son
algunas de las muchas aplicaciones que el algoritmo FFT pudiera tener.
Para finalizar, es importante mencionar la labor conjunta que se realizó con el
Dr. Maximino Peña Guerrero y el Ing. José de Jesús Negrete Redondo, profesores
de la academia de acústica de la ESIME-Zacatenco. Actualmente continuan con el
desarrollo de diversos proyectos en ciencia y tecnologı́a acústica.
55
Anexo A
Transformada Rápida de Fourier
En este apendice se trata de una manera breve pero detallada como es que esta
basado el algoritmo de la FFT, es decir como es que la transformada de descomopone
en transformadas más pequeñas y a partir de este punto se combinan para obtener
la transformada final. Una observación importante es que este algoritmo puede ser
realizado en los dominios del tiempo y de la frecuencia.
A.1.
Algoritmo FFT
Partiremos a partir de la transformada discreta de donde el problema es obtener
la secuencia de longitud N de la siguiente fórmula:
X(k) =
NP
−1
n=0
x(n)W nk donde
El factor W = e
−j2π
N
k = 0, 1....N − 1 y
N = 2a , a = 1, 2, 3...
(1)
con e−jx = cos(x) − jsen(x), en donde la expresión exponen-
cial representa un número complejo en coordenadas polares.
De la ecuación anterior, se puede calcular un punto de la transformada discreta
mismo que es dado por:
X(k) = x(0)W 0 + x(1)W k + x(2)W 2 k + ....x(N − 1)W k(N −1)
(2)
Si se desarrolla la ecuación (2) para k con N valores posibles se obtendrá una matriz
de tamaño N xN y además se calcula el número de operaciones necesarias para hacer
la transformación de los datos mediante este algoritmo, ası́ que, el número de sumas
complejas que se deben realizar es de (N − 1)N y la cantidad de multiplicaciones
56
complejas es igual a N 2. Dado que es una cantidad de operaciones muy alta, el
cálculo directo de la Transformada no resulta eficiente, debido a que no explota las
propiedades desimetrı́a y periocidad del factor de fase W n.
Observando la ecuación (2) es claro que las N 2 multiplicaciones no son necesarias
realizarlas porque los valores de los factores W 0 = 1 no son necesarios de multiplicar
A.2.
Decimación en Tiempo
Este proceso es conocido también con el nombre de ”mariposa”, siendo muy eficiente para el cálculo de la transformada de Fourier. El número de muestras que se
tomarán en este proceso es una potencia de 2, es decir N = 2v . En este método
la aproximación es realizada mediante la descomposición de la transformada de N
puntos en dos transformadas de N/2 muestras, después la descomposición de cada
transformada de N puntos en dos transformadas de N/4 puntos, y se continua este
proceso hasta obtener transformadas de 2 puntos. Tomando la ecuación (1) y dividiéndola en dos partes, una para los valores con ı́ndice par y otra para los valores con
ı́ndice impar, se tiene:
X(k) =
NP
−2
n=0
x[n]W kn +
NP
−1
n=1
x[n]W kn
(3)
Haciendo un arreglo para cada parte de X(k) en transformadas de N/2 puntos y
usando:
W 2kr = (W 2 )rk = e(
−j2π
N
−j2π
)(2kr) = e( N/2 )(kr) = W rk
(4)
nos queda lo siguiente:
X(k) =
N/2−1
P
r=1
x[2r]W rk + W k
N/2
P
r=0
x[2r + 1]W rk
(5)
La ecuación (5) puede ser escrita de la siguiente forma si G(k) y H(k) representan
las transformadas de N/2 puntos de la secuencia de valores con ı́ndice par e impar:
X(k) = G(k) + W ( H(k))
k = 0, 1, 2....
(6)
Este primer paso en la descomposición divide la transformada en dos transformadas de N/2 puntos y los factores proporcionan el álgebra combinacional como se
muestra en la Fig. (A.1).
57
Figura A.1: Separación de la DFT de N puntos en dos DFT´s de N/2 puntos
Como resultado de este proceso, las X quedan ordenadas en grupos de pares e
impares. El proceso de descomposición puede ser repetido nuevamente pero esta vez
para N/4 y asi sucesivamente hasta llegar a la transformada de 2 puntos. En general
una FFT de N puntos tendrá a etapas con N = 2a como lo muestra la Fig. (A.3).
A.3.
Decimación en frecuencia
Este procedimiento es dual al de la decimación en tiempo, ya que tienen propiedades
similares, en este caso la entrada es dada en su orden natural, mientras que la salida
es con la inversión de bits. El numero total de mariposas, factores W , y operaciones
son idénticas a aquellas que en la decimación en tiempo, la Fig. (A.2) es un ejemplo
de ello
58
Figura A.2: Separación de la DFT para la decimación en frecuencia
Figura A.3: Decimacion en tiempo para 8 muestras (N = 8)
59
Figura A.4: Decimación en frecuencia para 8 muestras (N = 8)
60
Anexo B
Código fuente del ecualizador
*-----------------------------------------------------SINEWAVE.C -- Ecualizador Gráfico de Sonido.
-- Dr.Maximino Pe~
na Guerrero.
Ing. José de Jesús Negrete Redondo.
Juan Sı́muta Pe~
na.
México D.F.
2006.
------------------------------------------------------*/
#include
#include
#include
#include
<windows.h>
<math.h>
"resource.h"
<mmsystem.h>
#define pi 3.14159
#define Tmuestreo 0.0000226757
#define frec 1000 //1 KHz
void
void
void
void
//44.1 MHz
fft(int,float[],float[]);
ifft(int,float[],float[]);
bitrev(int N, float XR[1024],float XI[1024]);
bitrev2(int N, float XR2[1024],float XI2[1024]);
#define
#define
#define
#define
#define
#define
SAMPLE_RATE
44100
FREQ_MIN
20
FREQ_MAX
5000
FREQ_INIT
127
OUT_BUFFER_SIZE 4096
PI
3.14159
static
static
static
static
static
static
static
static
static
BOOL
HWAVEOUT
HWND
HWND
HWND
HWND
HWND
HWND
HWND
bShutOff, bClosing ;
hWaveOut ;
hsc ;
hsc2 ;
hsc3 ;
hsc4 ;
hsc5 ;
hsc6 ;
hsc7 ;
61
static
static
static
static
static
static
static
static
static
static
static
static
static
static
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
HWND
hsc8 ;
hsc9 ;
hsc10;
hsc11;
hsc12;
hsc13;
hsc14;
hsc15;
hsc16;
hsc17;
hsc18;
hsc19;
hsc20;
hsc21;
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
int
iFreq =128;
var1 = 128;
var2 = 128;
var3 = 128;
var4 = 128;
var5 = 128;
var6 = 128;
var7 = 128;
var8 = 128;
var9 = 128;
var10 =128;
var11 =128;
var12 =128;
var13 =128;
var14 =128;
var15 =128;
var16 =128;
var17 =128;
var18 =128;
var19 =128;
var20 =128;
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
static
PBYTE
pBuffer1, pBuffer2 ;
PWAVEHDR
pWaveHdr1, pWaveHdr2 ;
WAVEFORMATEX waveformat ;
int
iDummy ;
int
iDummy2 ;
int
iDummy3 ;
int
iDummy4 ;
int
iDummy5 ;
int
iDummy6 ;
int
iDummy7 ;
int
iDummy8 ;
int
iDummy9 ;
int
iDummy10 ;
int
iDummy11 ;
int
iDummy12 ;
int
iDummy13 ;
62
static
static
static
static
static
static
static
static
BOOL
VOID
VOID
VOID
VOID
BOOL
VOID
VOID
VOID
VOID
VOID
VOID
VOID
VOID
VOID
VOID
VOID
int
int
int
int
int
int
int
int
iDummy14
iDummy15
iDummy16
iDummy17
iDummy18
iDummy19
iDummy20
iDummy21
;
;
;
;
;
;
;
;
CALLBACK DlgProc(HWND,UINT,WPARAM,LPARAM) ;
OnLoop(HWND,LPARAM);
OnAbrir(HWND);
OnCerrar(HWND);
FillBuffer(PBYTE,int);
OnGenerar(HWND);
Repintar(HWND,LPARAM);
graficar(HWND);
ruidoblanco(PBYTE);
ondacuadrada(PBYTE);
graficarbuffer(HWND);
funcionseno(PBYTE);
graficarentrada(HWND);
graficartransformadafft(HWND);
graficartransformadaifft(HWND);
modificarfft(float[],float[]);
copiarbuffer(float[],float[]);
static
static
static
static
static
static
static
static
HWAVEOUT
int
PBYTE
PBYTE
PWAVEHDR
PWAVEHDR
WAVEFORMATEX
HWND
hWaveOut;
wVeces=0;
pBuffer1;
pBuffer2;
pWaveHdr1;
pWaveHdr2;
waveformat;
hdlg;
int nm=1024;
float entrada[1024];
float salida[1024];
float salida2[1024];
float salidafft[1024];
float salida3[1024];
float salida4[1024];
TCHAR szAppName[]=TEXT("SineWave") ;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
{
if(-1==DialogBox(hInstance,szAppName,NULL,DlgProc))
MessageBox(NULL,TEXT("Requiere Windows NT!"),szAppName,MB_ICONERROR);
}
63
return(0);
}
BOOL CALLBACK DlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
//ruidoblanco(entrada);
funcionseno(entrada);
return 0;
case WM_INITDIALOG:
hsc = GetDlgItem (hwnd, IDC_SCROLL) ;
SetScrollRange (hsc, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc, SB_CTL, 128,FALSE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE) ;
hsc2 = GetDlgItem (hwnd, IDC_SCROLL2) ;
SetScrollRange (hsc2, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc2, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT5, FREQ_INIT, FALSE) ;
hsc3 = GetDlgItem (hwnd, IDC_SCROLL3) ;
SetScrollRange (hsc3, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc3, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc4 = GetDlgItem (hwnd, IDC_SCROLL4) ;
SetScrollRange (hsc4, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc4, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc5 = GetDlgItem (hwnd, IDC_SCROLL5) ;
SetScrollRange (hsc5, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc5, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc6 = GetDlgItem (hwnd, IDC_SCROLL6) ;
SetScrollRange (hsc6, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc6, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc7 = GetDlgItem (hwnd, IDC_SCROLL7) ;
SetScrollRange (hsc7, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc7, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
64
hsc8 = GetDlgItem (hwnd, IDC_SCROLL8) ;
SetScrollRange (hsc8, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc8, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc9 = GetDlgItem (hwnd, IDC_SCROLL9) ;
SetScrollRange (hsc9, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc9, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc10 = GetDlgItem (hwnd, IDC_SCROLL10) ;
SetScrollRange (hsc10, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc10, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc11 = GetDlgItem (hwnd, IDC_SCROLL11) ;
SetScrollRange (hsc11, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc11, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc12 = GetDlgItem (hwnd, IDC_SCROLL12) ;
SetScrollRange (hsc12, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc12, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc13 = GetDlgItem (hwnd, IDC_SCROLL13) ;
SetScrollRange (hsc13, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc13, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc14 = GetDlgItem (hwnd, IDC_SCROLL14) ;
SetScrollRange (hsc14, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc14, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc15 = GetDlgItem (hwnd, IDC_SCROLL15) ;
SetScrollRange (hsc15, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc15, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc16 = GetDlgItem (hwnd, IDC_SCROLL16) ;
SetScrollRange (hsc16, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc16, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc17 = GetDlgItem (hwnd, IDC_SCROLL17) ;
SetScrollRange (hsc17, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc17, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
65
hsc18 = GetDlgItem (hwnd, IDC_SCROLL18) ;
SetScrollRange (hsc18, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc18, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc19 = GetDlgItem (hwnd, IDC_SCROLL19) ;
SetScrollRange (hsc19, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc19, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc20 = GetDlgItem (hwnd, IDC_SCROLL20) ;
SetScrollRange (hsc20, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc20, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
hsc21 = GetDlgItem (hwnd, IDC_SCROLL21) ;
SetScrollRange (hsc21, SB_CTL, 0, 255, FALSE) ;
SetScrollPos
(hsc21, SB_CTL, 128, TRUE) ;
SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE);
break;
case WM_VSCROLL:
switch (LOWORD (wParam))
{
case SB_LINEL
if(lParam==(LPARAM)hsc) iFreq--;
if(lParam==(LPARAM)hsc2) var1--;
if(lParam==(LPARAM)hsc3) var2--;
if(lParam==(LPARAM)hsc4) var3--;
if(lParam==(LPARAM)hsc5) var4--;
if(lParam==(LPARAM)hsc6) var5--;
if(lParam==(LPARAM)hsc7) var6--;
if(lParam==(LPARAM)hsc8) var7--;
if(lParam==(LPARAM)hsc9) var8--;
if(lParam==(LPARAM)hsc10) var9--;
if(lParam==(LPARAM)hsc11) var10--;
if(lParam==(LPARAM)hsc12) var11--;
if(lParam==(LPARAM)hsc13) var12--;
if(lParam==(LPARAM)hsc14) var13--;
if(lParam==(LPARAM)hsc15) var14--;
if(lParam==(LPARAM)hsc16) var15--;
if(lParam==(LPARAM)hsc17) var16--;
if(lParam==(LPARAM)hsc18) var17--;
if(lParam==(LPARAM)hsc19) var18--;
if(lParam==(LPARAM)hsc20) var19--;
if(lParam==(LPARAM)hsc21) var20--;
break;
case SB_LINERIGHT:
if(lParam==(LPARAM)hsc) iFreq++;
if(lParam==(LPARAM)hsc2) var1++;
if(lParam==(LPARAM)hsc3) var2++;
if(lParam==(LPARAM)hsc4) var3++;
66
if(lParam==(LPARAM)hsc5) var4++;
if(lParam==(LPARAM)hsc6) var5++;
if(lParam==(LPARAM)hsc7) var6++;
if(lParam==(LPARAM)hsc8) var7++;
if(lParam==(LPARAM)hsc9) var8++;
if(lParam==(LPARAM)hsc10) var9++;
if(lParam==(LPARAM)hsc11) var10++;
if(lParam==(LPARAM)hsc12) var11++;
if(lParam==(LPARAM)hsc13) var12++;
if(lParam==(LPARAM)hsc14) var13++;
if(lParam==(LPARAM)hsc15) var14++;
if(lParam==(LPARAM)hsc16) var15++;
if(lParam==(LPARAM)hsc17) var16++;
if(lParam==(LPARAM)hsc18) var17++;
if(lParam==(LPARAM)hsc19) var18++;
if(lParam==(LPARAM)hsc20) var19++;
if(lParam==(LPARAM)hsc21) var20++;
break;
case SB_THUMBTRACK:
if (lParam==(LPARAM)hsc) iFreq=HIWORD(wParam);
if (lParam==(LPARAM)hsc2) var1=HIWORD(wParam);
if (lParam==(LPARAM)hsc3) var2=HIWORD(wParam);
if (lParam==(LPARAM)hsc4) var3=HIWORD(wParam);
if (lParam==(LPARAM)hsc5) var4=HIWORD(wParam);
if (lParam==(LPARAM)hsc6) var5=HIWORD(wParam);
if (lParam==(LPARAM)hsc7) var6=HIWORD(wParam);
if (lParam==(LPARAM)hsc8) var7=HIWORD(wParam);
if (lParam==(LPARAM)hsc9) var8=HIWORD(wParam);
if (lParam==(LPARAM)hsc10) var9=HIWORD(wParam);
if (lParam==(LPARAM)hsc11) var10=HIWORD(wParam);
if (lParam==(LPARAM)hsc12) var11=HIWORD(wParam);
if (lParam==(LPARAM)hsc13) var12=HIWORD(wParam);
if (lParam==(LPARAM)hsc14) var13=HIWORD(wParam);
if (lParam==(LPARAM)hsc15) var14=HIWORD(wParam);
if (lParam==(LPARAM)hsc16) var15=HIWORD(wParam);
if (lParam==(LPARAM)hsc17) var16=HIWORD(wParam);
if (lParam==(LPARAM)hsc18) var17=HIWORD(wParam);
if (lParam==(LPARAM)hsc19) var18=HIWORD(wParam);
if (lParam==(LPARAM)hsc20) var19=HIWORD(wParam);
if (lParam==(LPARAM)hsc21) var20=HIWORD(wParam);
break;
case SB_BOTTOM:
if (lParam==(LPARAM)hsc)
GetScrollRange(hsc,SB_CTL,&iDummy,&iFreq);
if (lParam==(LPARAM)hsc2)
GetScrollRange(hsc2,SB_CTL,&iDummy2,&var1);
if (lParam==(LPARAM)hsc3)
GetScrollRange(hsc3,SB_CTL,&iDummy3,&var2);
if (lParam==(LPARAM)hsc4)
67
GetScrollRange(hsc4,SB_CTL,&iDummy4,&var3);
if (lParam==(LPARAM)hsc5)
GetScrollRange(hsc5,SB_CTL,&iDummy5,&var4);
if (lParam==(LPARAM)hsc6)
GetScrollRange(hsc6,SB_CTL,&iDummy6,&var5);
if (lParam==(LPARAM)hsc7)
GetScrollRange(hsc7,SB_CTL,&iDummy7,&var6);
if (lParam==(LPARAM)hsc8)
GetScrollRange(hsc8,SB_CTL,&iDummy8,&var7);
if (lParam==(LPARAM)hsc9)
GetScrollRange(hsc9,SB_CTL,&iDummy9,&var8);
if (lParam==(LPARAM)hsc10)
GetScrollRange(hsc10,SB_CTL,&iDummy10,&var9);
if (lParam==(LPARAM)hsc11)
GetScrollRange(hsc11,SB_CTL,&iDummy11,&var10);
if (lParam==(LPARAM)hsc12)
GetScrollRange(hsc12,SB_CTL,&iDummy12,&var11);
if (lParam==(LPARAM)hsc13)
GetScrollRange(hsc13,SB_CTL,&iDummy13,&var12);
if (lParam==(LPARAM)hsc14)
GetScrollRange(hsc14,SB_CTL,&iDummy14,&var13);
if (lParam==(LPARAM)hsc15)
GetScrollRange(hsc15,SB_CTL,&iDummy15,&var14);
if (lParam==(LPARAM)hsc16)
GetScrollRange(hsc16,SB_CTL,&iDummy16,&var15);
if (lParam==(LPARAM)hsc17)
GetScrollRange(hsc17,SB_CTL,&iDummy17,&var16);
if (lParam==(LPARAM)hsc18)
GetScrollRange(hsc18,SB_CTL,&iDummy18,&var17);
if (lParam==(LPARAM)hsc19)
GetScrollRange(hsc19,SB_CTL,&iDummy19,&var18);
if (lParam==(LPARAM)hsc20)
GetScrollRange(hsc20,SB_CTL,&iDummy20,&var19);
if (lParam==(LPARAM)hsc21)
GetScrollRange(hsc21,SB_CTL,&iDummy21,&var20);
break ;
68
}
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
SetScrollPos
(hsc,SB_CTL,iFreq,TRUE);
(hsc2,SB_CTL,var1,TRUE);
(hsc3,SB_CTL,var2,TRUE);
(hsc4,SB_CTL,var3,TRUE);
(hsc5,SB_CTL,var4,TRUE);
(hsc6,SB_CTL,var5,TRUE);
(hsc7,SB_CTL,var6,TRUE);
(hsc8,SB_CTL,var7,TRUE);
(hsc9,SB_CTL,var8,TRUE);
(hsc10,SB_CTL,var9,TRUE);
(hsc11,SB_CTL,var10,TRUE);
(hsc12,SB_CTL,var11,TRUE);
(hsc13,SB_CTL,var12,TRUE);
(hsc14,SB_CTL,var13,TRUE);
(hsc15,SB_CTL,var14,TRUE);
(hsc16,SB_CTL,var15,TRUE);
(hsc17,SB_CTL,var16,TRUE);
(hsc18,SB_CTL,var17,TRUE);
(hsc19,SB_CTL,var18,TRUE);
(hsc20,SB_CTL,var19,TRUE);
(hsc21,SB_CTL,var20,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT5,255-var1,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT6,255-var2,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT7,255-var3,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT8,255-var4,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT9,255-var5,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT10,255-var6,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT11,255-var7,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT12,255-var8,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT13,255-var9,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT14,255-var10,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT15,255-var11,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT16,255-var12,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT17,255-var13,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT18,255-var14,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT19,255-var15,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT20,255-var16,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT21,255-var17,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT22,255-var18,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT23,255-var19,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT24,255-var20,TRUE);
SetDlgItemInt(hwnd,IDC_TEXT25,255-iFreq,TRUE);
graficar(hwnd);
case WM_COMMAND:
switch (wParam)
{
case IDC_GENERAR:
69
}
}
OnGenerar(hwnd);
break;
case IDC_PARAR:
waveOutReset(hWaveOut);
waveOutClose(hWaveOut);
break;
break;
case MM_WOM_OPEN:
OnAbrir(hwnd);
break;
// Generado por waveOutOpen().
case MM_WOM_DONE:
OnLoop(hwnd,lParam);
break;
// Generado por waveOutWrite()
case MM_WOM_CLOSE:
OnCerrar(hwnd);
break;
// Generado por waveOutClose()
case WM_SYSCOMMAND:
switch(wParam)
{
case SC_CLOSE:
if (hWaveOut!=NULL)
waveOutReset(hWaveOut);
else
EndDialog(hwnd,0);
return(TRUE);
}
break;
}
return(FALSE);
VOID OnCerrar(HWND hwnd)
{
SetDlgItemText(hwnd,IDC_TEXT2,TEXT("MM_WOM_CLOSE:"));
}
waveOutUnprepareHeader(hWaveOut,pWaveHdr1,sizeof(WAVEHDR));
waveOutUnprepareHeader(hWaveOut,pWaveHdr2,sizeof(WAVEHDR));
free(pWaveHdr1);
free(pWaveHdr2);
free(pBuffer1);
free(pBuffer2);
hWaveOut=NULL;
VOID OnAbrir(HWND hwnd)
{
SetDlgItemText(hwnd,IDC_TEXT2,TEXT("MM_WOM_OPEN:"));
70
}
//Enviar 2 buffers al driver de sonido.
//FillBuffer(pBuffer1,1000) ;
copiarbuffer(salida3,pBuffer1);
waveOutWrite(hWaveOut,pWaveHdr1,sizeof(WAVEHDR)) ;
copiarbuffer(salida3,pBuffer2);
//FillBuffer(pBuffer2, 1000);
waveOutWrite (hWaveOut,pWaveHdr2,sizeof(WAVEHDR)) ;
VOID OnLoop(HWND hwnd,LPARAM lParam)
{
SetDlgItemText(hwnd,IDC_TEXT2,TEXT("MM_WOM_DONE:"));
SetDlgItemInt(hwnd,IDC_TEXT3,wVeces++,FALSE) ; // print int
SetDlgItemInt(hwnd,IDC_TEXT4,((PWAVEHDR)lParam)->lpData ,FALSE) ;
// Fill and send out a new buffer
// FillBuffer(((PWAVEHDR)lParam)->lpData,1000);
copiarbuffer(salida3,((PWAVEHDR)lParam)->lpData);
waveOutWrite(hWaveOut,(PWAVEHDR)lParam, sizeof(WAVEHDR));
}
BOOL OnGenerar(HWND hwnd)
{
if(hWaveOut) return(TRUE); // Ya esta inicializado el driver ?
// Memoria para 2 headers y 2 buffers
pWaveHdr1 = malloc(sizeof (WAVEHDR)) ;
pWaveHdr2 = malloc(sizeof (WAVEHDR)) ;
pBuffer1 = malloc(OUT_BUFFER_SIZE) ;
pBuffer2 = malloc(OUT_BUFFER_SIZE) ;
if (!pWaveHdr1 || !pWaveHdr2 || !pBuffer1 || !pBuffer2)
{
if (!pWaveHdr1) free (pWaveHdr1);
if (!pWaveHdr2) free (pWaveHdr2);
if (!pBuffer1) free (pBuffer1);
if (!pBuffer2) free (pBuffer2);
error("No hay memoria.");
}
// Abrir el driver de salida.
waveformat.wFormatTag
= WAVE_FORMAT_PCM ;
waveformat.nChannels
= 1 ;
waveformat.nSamplesPerSec = SAMPLE_RATE ;
waveformat.nAvgBytesPerSec = SAMPLE_RATE ;
waveformat.nBlockAlign
= 1 ;
waveformat.wBitsPerSample = 8 ;
waveformat.cbSize
= 0 ;
if(waveOutOpen(&hWaveOut,WAVE_MAPPER, &waveformat,
(DWORD)hwnd,0,CALLBACK_WINDOW) != MMSYSERR_NOERROR)
{
free(pWaveHdr1);
free(pWaveHdr2);
free(pBuffer1);
free(pBuffer2);
hWaveOut = NULL;
71
error("No driver.");
}
// Preparar dos descriptores.
pWaveHdr1->lpData
= pBuffer1 ;
pWaveHdr1->dwBufferLength = OUT_BUFFER_SIZE ;
pWaveHdr1->dwBytesRecorded = 0 ;
pWaveHdr1->dwUser
= 0 ;
pWaveHdr1->dwFlags
= 0 ;
pWaveHdr1->dwLoops
= 1 ;
pWaveHdr1->lpNext
= NULL ;
pWaveHdr1->reserved
= 0 ;
waveOutPrepareHeader(hWaveOut,pWaveHdr1,sizeof(WAVEHDR));
pWaveHdr2->lpData
pWaveHdr2->dwBufferLength
pWaveHdr2->dwBytesRecorded
pWaveHdr2->dwUser
pWaveHdr2->dwFlags
pWaveHdr2->dwLoops
pWaveHdr2->lpNext
pWaveHdr2->reserved
=
=
=
=
=
=
=
=
pBuffer2 ;
OUT_BUFFER_SIZE ;
0 ;
0 ;
0 ;
1 ;
NULL ;
0 ;
waveOutPrepareHeader(hWaveOut,pWaveHdr2,sizeof(WAVEHDR));
}
return(TRUE);
VOID FillBuffer(PBYTE pBuffer,int iFreq)
{
int i;
static double fAngle ;
}
for (i=0;i<OUT_BUFFER_SIZE;i++)
{
pBuffer[i]= (BYTE) (127+127*sin(fAngle));
fAngle += 2 * PI * iFreq/SAMPLE_RATE;
if (fAngle > 2*PI)
fAngle -= 2*PI;
}
BOOL error(LPCSTR mmsg)
{
}
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(hdlg,mmsg,szAppName,MB_ICONEXCLAMATION | MB_OK);
return(TRUE);
VOID graficar(HWND hwnd)//Pag: 1213 Petzold.
{
72
int nm=1024; // Numero de muestras.
HDC hdc;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
hdc=GetDC(hwnd);
//---------------------------------------------------graficarentrada(hwnd,1024,entrada);
fft(nm,entrada,salida);
modificarfft(nm,salida,salidafft);
graficartransformadafft(hwnd,1024,salidafft);
ifft(nm,salidafft,salida3);
graficartransformadaifft(hwnd,1024,salida3);
//----------------------------------------------------}
ReleaseDC(hwnd,hdc);
VOID graficarentrada(HWND hwnd,int n,float bentrada[])
{
int i;
int x,y,yy;
HDC hdc;
UpdateWindow(hwnd);
hdc=GetDC(hwnd);
MoveToEx(hdc,0,y,NULL);
for(i=0;i<=1010;i++)
{
y=(bentrada[i]/255)*142;
yy=y+240;
LineTo(hdc,i,yy);
}
ReleaseDC(hwnd,hdc);
}
VOID graficartransformadafft(HWND hwnd,int n, float bfft[])
{
int i;
int yy,y;
HDC hdc;
UpdateWindow(hwnd);
hdc=GetDC(hwnd);
for(i=0;i<=1010;i=i++)
{
MoveToEx(hdc,i,540,NULL);
73
y=-(bfft[i]/0x0FFFFFF)*142;
yy=(y+540);
LineTo(hdc,i,yy);
}
ReleaseDC(hwnd,hdc);
}
VOID graficartransformadaifft(HWND hwnd,int n, float bifft[])
{
int i,x,y,yy;
HDC hdc;
UpdateWindow(hwnd);
hdc=GetDC(hwnd);
MoveToEx(hdc,0,y,NULL);
for(i=0;i<=1010;i++)
{
y=-(bifft[i]/0x0FFFFFFF)*142;
yy=y+635;
LineTo(hdc,i,yy);
}
ReleaseDC(hwnd,hdc);
}
VOID funcionseno(float pS[])
{
int i;
float fAngle ;
for (i=0;i<OUT_BUFFER_SIZE;i++)
{
pS[i]= (BYTE)((127+127 * sin(fAngle)));
fAngle += 2 * PI * 1000 / SAMPLE_RATE;
if (fAngle > 2*PI)
fAngle -= 2 * PI;
}
}
VOID copiarbuffer(float entra[], float sale[])
{
int i;
for (i=0;i<1024;i++)
{
sale[i]=entra[i];
74
}
}
VOID ruidoblanco(float pB[])
{
int i;
for (i=0;i<1024;i++)
{
}
}
pB[i]=(BYTE) rand()%255;
VOID ondacuadrada(float pt[])
{
int i;
int k=0;
int periodo=30;
for (i=0;i<OUT_BUFFER_SIZE;i++)
{
if (k==0)
pt[i]=0;
else
//__--__--__--__
pt[i]=127;
}
k=(k+1)%periodo;
}
void fft(int N,float XR[],float X[])
{
int i,j,k,M,N1,I1,I2, N2;
int L=10;
float C,S;
float tempr,tempi;
float WR[1024];
float WI[1024];
float XI[1024];
// Iniciar
for(i=0;i<=N-1;i++)
{
WR[i]=cos(2*pi*i/N);
WI[i]=sin(2*pi*i/N);
XI[i]=0.0;
}
// Calcular FFT.
N2=N;
for(i=0;i<L;i++)
75
{
N1=N2;
N2=N2/2;
I1=0;
I2=N/N1;
for(j=0;j<N2;j++)
{
C=WR[I1];
S=WI[I1];
I1=I1+I2;
for(k=j;k<N;k+=N1)
{
M=k+N2;
tempr=XR[k]-XR[M];
XR[k]=XR[k]+XR[M];
tempi=XI[k]-XI[M];
XI[k]=XI[k]+XI[M];
XR[M]=C*tempr-S*tempi;
XI[M]=C*tempi+S*tempr;
}
}
}
// Invertir el orden.
bitrev(N,XR,XI);
// Calcular magnitud.
for(i=0;i<=N-1;i++)
{
X[i]=(sqrt(pow(XR[i],2)+pow(XI[i],2)));
//X[i]=XR[i]+XI[i];
}
}
void modificarfft(int N,float T[],float R[])
{
int i;
for(i=0;i<=N-1;i++)
{
if
if
if
if
if
if
if
if
if
(i
(i
(i
(i
(i
(i
(i
(i
(i
>=
>=
>=
>=
>=
>=
>=
>=
>=
0
4
8
10
20
40
80
100
200
&&
&&
&&
&&
&&
&&
&&
&&
&&
i
i
i
i
i
i
i
i
i
<
<
<
<
<
<
<
<
<
4 )
8 )
10 )
20 )
40 )
80 )
100)
200)
300)
(R[i]=T[i]*(255-var1));
(R[i]=T[i]*(255-var2));
(R[i]=T[i]*(255-var3));
(R[i]=T[i]*(255-var4));
(R[i]=T[i]*(255-var5));
(R[i]=T[i]*(255-var6));
(R[i]=T[i]*(255-var7));
(R[i]=T[i]*(255-var8));
(R[i]=T[i]*(255-var9));
76
if
if
if
if
if
if
if
if
if
if
if
(i
(i
(i
(i
(i
(i
(i
(i
(i
(i
(i
>=
>=
>=
>=
>=
>=
>=
>=
>=
>=
>=
300
400
500
600
700
800
850
900
950
1000
1005
&&
&&
&&
&&
&&
&&
&&
&&
&&
&&
&&
i
i
i
i
i
i
i
i
i
i
i
<
<
<
<
<
<
<
<
<
<
<
400)
500)
600)
700)
800)
850)
900)
950)
1000)
1005)
1015)
(R[i]=T[i]*(255-var10));
(R[i]=T[i]*(255-var11));
(R[i]=T[i]*(255-var12));
(R[i]=T[i]*(255-var13));
(R[i]=T[i]*(255-var14));
(R[i]=T[i]*(255-var15));
(R[i]=T[i]*(255-var16));
(R[i]=T[i]*(255-var17));
(R[i]=T[i]*(255-var18));
(R[i]=T[i]*(255-var19));
(R[i]=T[i]*(255-var20));
}
}
void ifft(int N,float X2[],float X3[])
{
int i,j,k,M,N1,I1,I2, N2;
int L=10;
float C2,S2;
float tempr2,tempi2;
float WR2[1024];
float WI2[1024];
float XI2[1024];
float XR2[1024];
for(i=0;i<=N-1;i++)
{
WR2[i]=cos(2*pi*i/N);
WI2[i]=sin(2*pi*i/N);
XR2[i]=X2[i];
XI2[i]=0.0;
}
N2=N;
for(i=0;i<L;i++)
{
N1=N2;
N2=N2/2;
I1=0;
I2=N/N1;
for(j=0;j<N2;j++)
{
C2=WR2[I1];
S2=WI2[I1];
I1=I1+I2;
for(k=j;k<N;k+=N1)
{
77
M=k+N2;
tempr2=XR2[k]-XR2[M];
XR2[k]=XR2[k]+XR2[M];
tempi2=XI2[k]-XI2[M];
XI2[k]=XI2[k]+XI2[M];
XR2[M]=C2*tempr2-S2*tempi2;
XI2[M]=C2*tempi2+S2*tempr2;
}
}
}
bitrev2(N,XR2,XI2);
for(i=0;i<=N-1;i++)
{
X3[i]=(XR2[i]+XI2[i]);// Resultado de la FFT Inversa
}
}
void bitrev(int N, float XR[1024], float XI[1024])
{
float temp;
int i, j, k;
j=0;
for(i=0;i<N-1;i++)
{
if(i<j)
{
temp=XR[j];
XR[j]=XR[i];
XR[i]=temp;
temp=XI[j];
XI[j]=XI[i];
XI[i]=temp;
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
else
{
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
78
}
}
}
void bitrev2(int N, float XR2[1024], float XI2[1024])
{
float temp2;
int i, j, k;
j=0;
for(i=0;i<N-1;i++)
{
if(i<j)
{
temp2=XR2[j];
XR2[j]=XR2[i];
XR2[i]=temp2;
temp2=XI2[j];
XI2[j]=XI2[i];
XI2[i]=temp2;
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
else
{
k=N/2;
while(k<=j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
}
}
79
Bibliografı́a
[1] Gibilisco Stan, Diccionario Enciclopédico, Mc. Graw Hill, Vol. 1,2,3., 1995.
[2] Ceballos F. Javier, Visual C++, Aplicaciones para Win 32, 2a Edición,Alfaomega, 2004. 717 pgs.
[3] Petzold Charles “Exploring Waveform Audio-Generating Sine Waves in Software”, PC Magazine, November 26, 1991, pp:505-510.
[4] Herrera Enrique, Comunicaciones 1, Señales, Modulación y Transmisión
Limusa, pp: 30-35, 2000.
[5] Bernal Jesús Reconocimiento de Voz y Fonética Acústica, Alfaomega, pp: 169171, 207, 1999.
[6] Hsu Hwei P, Análisis de Fourier, Prentice Hall,1998, 274 pgs.
[7] Boylestad Robert L, Electrónica: Teorı́a de Circuitos 6a Edición, Prentice Hall,
1997, 949 pgs .
[8] Petzold Charles, Programming Windows, 5a Edición, Microsoft Press, 1999,1479
pgs.
[9] Peña G. M “Captura de Múltiples Eventos MIDI en tiempo de ejecución”,
Inédita. México. Tesis presentada para aspirar al grado de Doctor en Ciencias de
Ingeniero en Comunicaciones y Electrónica, Centro de Investigación y Estudios
avanzados del IPN, 2005. 160 pgs.
[10] Moog Bob, “MIDI: Musical Instrument Digital Interface”, Journal of the Audio
Engeering Society, may 1986, v. 34 No. 5. pp. 394-404.
[11] Sedgewick Robert,
cana,1995,726 pgs.
Algoritmos en C++,
Addison-Wesley
Iberoameri-
[12] Pappas Chris H., Visual C++ 6.00, Manual de Referencia Mc. Graw Hill,1999,
945 pgs.
80
Φ
81

Documentos relacionados