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