instituto polit´ecnico nacional - Página Dr. Maximino Peña Guerrero
Transcripción
instituto polit´ecnico nacional - Página Dr. Maximino Peña Guerrero
INSTITUTO POLITÉCNICO NACIONAL ESCUELA SUPERIOR DE INGENIERÍA MECANICA Y ELÉCTRICA DEPARTAMENTO DE INGENIERÍA EN COMUNICACIONES Y ELECTRÓNICA ACADEMIA DE ACÚSTICA Diseño Elemental de un Sintetizador de Notas Musicales TESIS Que para obtener el Tı́tulo de Ingeniero en Comunicaciones y Electrónica Presentan: Victor Hugo Correa Cid Iván Guadalupe Contreras Méndez Asesores: Dr. Maximino Peña Guerrero Ing. José de Jesús Negrete Redondo México D.F. Octubre 2005 Trabajo de tesis que forma parte de los resultados obtenidos con nuestro proyecto de investigación, MAN: Red Internet II de Audio Multimedia con Servidores y Clientes Incrustados, número de registro 20040733 asignado por la Coordinación General de Posgrado e Investigación del Instituto Politécnico Nacional durante febrero 2004 a marzo 2005, desarrollado en el laboratorio de la academia de acústica de la ESIME Zacatenco, y dirigido por el Dr. Maximino Peña Guerrero. ii iii RESUMEN Actualmente los sintetizadores son instrumentos musicales que generan sonidos controlando osciladores electrónicos con un teclado de piano, o bien con dispositivos electrónicos digitales o analógicos. De esta forma es posible crear nuevos sonidos, o bien sintetizar por ejemplo el sonido de una trompeta, flauta, o un saxofón. Para lograr un sonido particular, la forma de onda que producen estos osciladores se puede modificar cambiando los parámetros que definen una nota musical (frecuencia), su volúmen (amplitud), y el timbre que permite identificar un instrumento de otro (fase y cantidad de armónicos). Esta tesis presenta el diseño básico de un sintetizador electrónico digital de notas musicales. Las caracterı́sticas que lo definen se describen dentro de un programa que corre en una PC (Personal Computer). Nuestro sintetizador trabaja con base en las series matemáticas de Fourier. Sus “osciladores” son generadores de formas de onda simples (funciones seno), los cuales se pueden modificar (timbre de una nota) con barras y controles gráficos en la pantalla de la computadora. La frecuencia fundamental (nota) del conjunto de osciladores del sintetizador es controlada con un teclado virtual de 12 notas, las cuales simulan las teclas fı́sicas de un piano de concierto. Los resultados que se obtienen son: nuestro sintetizador funcionando en un ambiente gráfico que genera un programa en Visual C++.NET y que también muestra una serie de ventanas, las cuales contienen las formas de onda de los osciladores; ası́mismo, un teclado gráfico y barras que controlan la amplitud y frecuencia de los osciladores. Por otra parte, el sonido que se produce cuando se activan las teclas del sintetizador es reproducido con el sistema de audio estándar de la computadora. Cabe mencionar que sólo utilizamos seis osciladores, pero que esta restricción, no ha impedido la investigación del funcionamiento básico de dicho dispositivo. iv OBJETIVO Diseñar un sintetizador básico de notas musicales para PC (Personal Computer), utilizando algoritmos de programación (en Visual C++.NET) y métodos numéricos. JUSTIFICACIÓN En la actualidad existen varios tipos de modelos de sintetizadores por hardware, con los cuales es posible obtener sonidos de diversos instrumentos musicales, sin embargo, para esto se necesita de multiples elementos electrónicos, por lo que pueden llegar hacer enormes, ocupar grandes espacios, ser estorbosos y poco prácticos para los usuarios. Al darnos cuenta de lo anterior observamos que un modelo por software puede igualar o incluso superar a un modelo por hardware, ya que si se cuenta con una PC, un músico o cualquier persona, puede tener acceso a un sintetizador en lugares que normalmente no seria posible (avión, tren, autobús, etc.). v Agradecimientos A mis padres: Marı́a Magdalena Cid Flores y Salomón Correa Medina, quienes con su apoyo constante me han dado fuerzas para seguir adelante y nunca detenerme. Sé que no necesito escribir todo lo que significan para mı́, pero quiero que sepan que siempre estaré para ustedes, ası́ como ustedes siempre han estado para mı́. Nunca olviden que los amo. A mis hermanas: Angélica Correa Cid y Alejandra Correa Cid, les agradezco por mostrarme el camino para llegar hasta donde estoy, ya que sin su ejemplo y apoyo nunca lo hubiera logrado. No encuentro palabras para expresar la bendición que significa tener unas hermanas como ustedes. A mis profesores: Agradezco a todos mis profesores, pero en especial al Dr. Maximino Peña Guerrero y al Ing. José de Jesús Negrete Redondo, quienes me confiaron este trabajo de tesis y me impulsaron a cumplir con el objetivo. Espero no haberlos defraudado!!!. A la Virgen de Guadalupe: Por que siempre estás cuando te necesito y sé que ahı́ seguirás!!!. Victor Hugo Correa Cid vi ”El hombre es el único ser de la naturaleza que tiene conciencia de que va a morir, por eso —y sólo por eso— tengo un profundo respeto por la raza humana, y creo que en un futuro será mucho mejor que en el presente. Aun sabiendo que sus dı́as estan contados y que todo acabará cuando menos se lo espera, hace de la vida una lucha digna de un ser eterno. Lo que las personas llaman vanidad —dejar obras, hijos, hacer que su nombre no se olvide— yo lo considero la máxima expresión de la dignidad humana. Paulo Coelho El Peregrino (Diario de un mago). vii Agradezco infinitamente a Dios por darme la oportunidad de; vivir en este tiempo y conocer a las personas que han marcado mi vida para siempre. A todas esas personas gracias, por compartir conmigo momentos de alegrı́as y tristezas. A mis padres, Julia Méndez y Silvestre Contreras les agradezco el apoyo y paciencia que me han brindando durante todos estos años. Ası́ como también agradezco a mi hermana Verónica que me brindó su apoyo en lo que necesitaba. Y muy especialmente le agradezco a mi abuela Delfina Hernández (q.p.d), que en vida siempre se preocupó por mis estudios y mi bienestar. No podı́a faltar toda mi gratitud a, mi tı́a Marı́a de la Cruz Méndez, a mi tı́o Benito Cureño Méndez y familia. A mis amigos: Arturo Iñigo, Arturo Nava, Raúl Hernández, Leonel Rios y Denys Basurto, humildemente les agradezco su confianza, su amistad y su compañı́a durante todos estos años. De la misma manera agradezco a: Lalo, Ulises, Oscar, Chucho, Moreno, Hugo, Karla y Cristina, porque con todos ellos compartı́ momentos muy agradables y siempre conté con ellos en los momentos difı́ciles. Quiero brindarles toda mi gratitud y respeto a mis profesores, que saben valorar su profesión y dı́a con dı́a dan lo mejor de sı́ mismos. Muy en especialmente al Dr. Maximino Peña Guerrero y al Ing. José de Jesús Negrete Redondo, por la confianza y el apoyo para la realización de esta tesis, igualmente a mis amigos Victor Hugo Correa y Juan Simúta. Al Instituto Politécnico Nacional y a la E.S.I.M.E.-Zacatenco... ¡simplemente mil gracias! porque en ellos no solamente aprendı́; matemáticas y fı́sica, también aprendı́; que un buen ser humano es; humilde, sencillo y respeta al prójimo. Iván Guadalupe Contreras Méndez. viii Quien ama la ciencia, la corrección ama; mas aquel que es como bruto, odia el reproche. (Proverbios 12, 1) Para el necio es recto su camino; mas el hombre prudente oye el consejo. (Proverbios 12, 15) Hay quienes pretenden ser ricos, sin tener nada; hay quienes pretenden ser pobres, siendo muy ricos. (Proverbios 13, 7) ix Índice general 1. Introducción 1.1. Antecedentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Nuestro trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3. Organización del documento . . . . . . . . . . . . . . . . . . . . . . . 2. Instrumentos Musicales Electrónicos y Digitales 2.1. Principios de funcionamiento . . . . . . . . . . . . 2.2. El sintetizador como instrumento musical . . . . . 2.3. Métodos de programación de nuestro sistema . . . 2.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Aspectos del Diseño de Sintetizadores de Música 3.1. Generadores electrónicos de formas de onda . . . . 3.2. Tipos de osciladores . . . . . . . . . . . . . . . . . 3.3. Anatomı́a de un sintetizador . . . . . . . . . . . . . 3.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . 4. Diseño de Nuestro Sintetizador de Notas 4.1. Computadoras digitales . . . . . . . . . . . . . 4.2. Estructuras del controlador (driver) de sonido 4.3. Programación de las funciones de onda . . . . 4.4. Visualización de las formas de onda . . . . . . 4.5. Anatomı́a de una tarjeta de sonido . . . . . . 4.6. Resumen . . . . . . . . . . . . . . . . . . . . . 5. Diseño de la Interfaz Gráfica 5.1. Pixeles y mapas de bits . . . . . . . . . . . . . 5.2. Ventanas, barras, y otros controles gráficos . . 5.3. Programando la interfase gráfica . . . . . . . . 5.4. Programando el controlador driver de sonido . 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 6 7 . . . . 9 9 11 12 16 . . . . 17 17 18 20 23 . . . . . . 25 25 27 31 33 35 36 . . . . 37 37 38 38 48 5.5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6. Pruebas y Resultados 6.1. Ambiente de compilación y generación de 6.2. Aspecto visual del sintetizador . . . . . . 6.3. Control de parámetros del sintetizador . 6.4. Controlando los armónicos . . . . . . . . 6.5. Control del teclado . . . . . . . . . . . . 6.6. Resumen . . . . . . . . . . . . . . . . . . 50 . . . . . . 51 51 53 54 55 57 58 7. Conclusiones y Trabajos Futuros 7.1. Trabajos Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 61 2 código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Índice de figuras 3.1. Sintetizador elemental . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4.1. Número de muestras por cada ciclo. . . . . . . . . . . . 4.2. Representación gráfica de la Serie de Fourier, mediante diseñado en C++. . . . . . . . . . . . . . . . . . . . . . 4.3. Diagrama a bloques de una tarjeta de sonido. . . . . . . . . . . . programa . . . . . . . . . . . . 32 5.1. Jerarquı́a de ventanas. . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2. Interfaz gráfica de la aplicación. . . . . . . . . . . . . . . . . . . . . . 39 40 6.1. 6.2. 6.3. 6.4. 6.5. 6.6. 6.7. 6.8. 52 53 54 55 56 56 57 58 . . un . . . . Vista principal del sintetizador. . . . . . . . . . . . . . . . . . . . . Valores mı́nimo, central y máximo de la barra horizontal. . . . . . . Barras de desplazamiento verticales, con una amplitud modificada. . Tercer armónico con amplitud modificada. . . . . . . . . . . . . . . Quinto armónico con amplitud modificada. . . . . . . . . . . . . . . Todos los armónicos modificados . . . . . . . . . . . . . . . . . . . . Vista del Teclado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . a)Tecla en reposo. b)Tecla pulsada. . . . . . . . . . . . . . . . . . . 3 . . . . . . . . 34 36 Índice de tablas 6.1. Valores de las barras de desplazamiento . . . . . . . . . . . . . . . . . 4 58 Capı́tulo 1 Introducción 1.1. Antecedentes Un dispositivo que genera los sonidos a partir de la combinación de elementos simples (normalmente señales periódicas y funciones matemáticas) es conocido como sintetizador. Con este artefacto se pueden crear nuevos sonidos ası́ como reproducir los de los instrumentos musicales conocidos, la forma de la onda generada, es alterada en su duración, altura y timbre, mediante el uso de dispositivos tales como amplificadores, mezcladores, filtros, reverberadores, secuenciadores y moduladores de frecuencia. Para encontrar los primeros sintetizadores de sonido debemos remontarnos a 1906, año de invención del Telharmonium, mientras que en los años veinte surge el Theremin. Estos primeros aparatos eran analógicos y utilizaban osciladores eléctricos como fuente sonora. Sin embargo fue en la década de 1960 que apareció uno de los sintetizadores más famosos, el Moog, llamado ası́ por su inventor, el ingeniero estadounidense Robert Moog. Este se controla con uno o más teclados y con él es posible crear un número casi infinito de sonidos y pueden imitarse muchos instrumentos. El sintetizador Moog no tiene memoria, lo que significa mover cerca de 60 botones para lograr el sonido de algún instrumento, como un violı́n o una trompeta. Las posiciones de los botones se apuntan en un cuaderno, ya que para hacer el sonido de un instrumento deben desorganizarse las posiciones del instrumento anterior. 5 Una de las controversias que se han tenido en los últimos años, es si los sintetizadores por software podı́an desplazar a los modelos por hardware. Viendo que el sonido de algunos modelos software, los han ido igualando, se decı́a que la falta de control sobre sus parámetros, el hecho de tener fastuosos interfaces de pantalla pero ningún potenciómetro a mano, los ponı́an en clara desventaja. Sin embargo hay que decir que la mayorı́a de los modelos digitales y estaciones de trabajo que se usan actualmente, tienen complejas arquitecturas y grandes cantidades de parámetros que imposibilitan construir paneles de potenciómetros que cubran todas las opciones (a no ser que midiesen un par de metros cuadrados). De esta manera hay que tener en cuenta, que en general las arquitecturas de los modelos por software actuales son mucho más amplias y ambiciosas. 1.2. Nuestro trabajo Lo anterior expuesto nos llevó a crear el diseño básico de un sintetizador elemental para PC (Personal Computer), el cual se basa en la manipulación de señales analógicas, llamadas formas de onda, que en nuestro caso serán de tipo sinusoidal. Estas señales serán manipuladas mediante un proceso para obtener sonido por medio de una sı́ntesis, llamado series de fourier. De esta manera sumando las salidas de varios osciladores de forma de onda sinusoidal, se obtendrán diversos timbres, según la amplitud que se le da a la frecuencia fundamental (la nota) y sus armónicos (notas múltiplos de la fundamental), los cuales permiten diferenciar un timbre de otro, por ejemplo un violı́n de una flauta. En la actualidad existen diferentes software que se enfocan en el desarrollo de aplicaciones para Windows, tales como: C, C++, Borland, entre otros. Sin embargo, las aplicaciones utilizadas en Windows, eran sencillas de usar para el usuario pero difı́ciles de desarrollar para el programador. Por este motivo en febrero de 1993, fue introducido uno de los mas conocidos y eficientes lenguajes de programación orientada a objetos, Visual C++, el cual ha ido evolucionando hasta llegar a su más 6 reciente versión, Visual C++ .Net o versión 7 del mismo. Desarrollar aplicaciones en un entorno de este tipo se vuelve una tarea un poco más sencilla, el programador puede crear la interfaz gráfica (ventanas, barras de desplazamiento, botones, entre otras cosas), sin necesidad de escribir nada de código. Tomando en cuenta lo anterior hemos decidido usar para el desarrollo de este sintetizador, el software antes mencionado, Visual C++ .Net. 1.3. Organización del documento Esta tesis se encuentra estructurada de la siguiente manera. El capı́tulo 2 presenta los conceptos básicos que deben ser tomados en cuenta, para el desarrollo de nuestro sintetizador, tales como: sonido, tipos de sı́ntesis, generación de sonido en PC’s, entre otros. El capı́tulo 3 presenta los aspectos de diseño para el desarrollo de nuestro sintetizador, de esta forma tomamos en cuenta el funcionamiento de los dispositivos que pueden ser empleados para generar formas de onda (osciladores), tales como: los tipo Hartley, Colpitts, LC, RC, VCO, 555, entre otros. Cabe mencionar que los diseños anteriores son de caracter explicativo, ya que no serán implementados en nuestro diseño. El capı́tulo 4 presenta el proceso de diseño de las sı́ntesis de ondas, en el que veremos las estructuras de audio más importantes utilizadas para la comunicación entre el software y la tarjeta de sonido de la PC. Al mismo tiempo desarrollaremos y explicaremos la función encargada de realizar la sı́ntesis de ondas, almacenándolas en un buffer de audio. El capı́tulo 5 presenta el diseño de la interfaz gráfica, donde se explicará paso a paso los diferentes puntos a seguir para el desarrollo del software y definiremos algunos conceptos básicos tales como pı́xel, mapa de bits, recurso gráfico, entre otros, necesarios para su mejor comprensión. El capı́tulo 6 presenta algunas pruebas y resultados de nuestro proyecto final, describiremos su operación y la forma de obtener un archivo ejecutable del proyecto, para que este sea universal. Por último el capı́tulo 7 presenta las conclusiones a las que llegamos al termino de este proyecto, ası́ como algunas propuestas para la mejora del mismo. 7 Φ 8 Capı́tulo 2 Instrumentos Musicales Electrónicos y Digitales En este capı́tulo trataremos algunos conceptos que son básicos para la comprensión de los demás capı́tulos, como son ondas sonoras, caracterı́sticas del sonido, armónicos, análisis de Fourier, sintetizadores, técnicas de sı́ntesis, muestreo, modulación, generación de sonido en PC (Personal Computer), captura de sonido y lenguajes de programación. 2.1. Principios de funcionamiento Cuando un cuerpo es excitado de alguna manera, las moléculas de aire que se encuentran en contacto con la fuente se ponen en movimiento al mismo tiempo y con la misma amplitud y fase que las superficies de dicha fuente, a esto se le conoce como Sonido. A partir de este movimiento se desarrolla una onda sonora, cuando al moverse las moléculas que están en contacto con la fuente, ponen en movimiento a las que se encuentran a continuación y éstas a su vez a las siguientes, produciendo una reacción en cadena y que continúa de acuerdo al movimiento de la fuente en ambas direcciones, generando aumento y disminución de presión, haciendo que su efecto se propague en todas direcciones. Las principales caracterı́sticas del sonido son: frecuencia, amplitud, tono y timbre. La frecuencia, es el número de oscilaciones que se cumplen en un segundo dentro de 9 un movimiento vibratorio y es expresada en Hertz (Hz.), las frecuencias que percibe el oı́do humano se encuentran entre los 20 Hz y 20,000 Hz. La amplitud esta definida, como el grado de movimiento de las moléculas de aire en una onda. El tono nos permite diferenciar un sonido grave de un sonido agudo, mientras más ciclos completos ocurren más alto será el tono. El timbre, es el atributo de la sensación auditiva por el cual, un escucha puede juzgar dos sonidos similares como diferentes entre sı́ [1]. Existen diferentes formas de onda, como la onda sinusoidal, cuadrada, diente de sierra, etc, estas ondas nos permiten distinguir una nota musical de la misma frecuencia e intensidad, producida por instrumentos diferentes. La forma de onda viene determinada por una serie de vibraciones subsidiarias, que acompañan a una vibración primaria o fundamental del movimiento ondulatorio (especialmente en los instrumentos musicales) llamados armónicos. Normalmente al hacer vibrar un cuerpo, no obtenemos un sonido puro, sino un sonido compuesto de sonidos de diferentes frecuencias. La frecuencia de los armónicos, siempre es un múltiplo de la frecuencia más baja, llamada frecuencia fundamental o primer armónico. En 1807, el matemático francés Joseph Fourier (1768-1830), envió un artı́culo a la Academia de Ciencias en Parı́s. En él, presentaba una descripción matemática de problemas relacionados con la conducción de calor. Una de las sorprendentes ramificaciones del trabajo de Fourier, fue que muchas de las funciones más conocidas podı́an expandirse en series infinitas e integrales que involucraban funciones trigonométricas, llamadas series de Fourier. La idea es importante hoy en dı́a, en el modelamiento de muchos de los fenómenos en Fı́sica e Ingenierı́a. Un método matemático para 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, que es utilizada para transformar una señal representada en el dominio del tiempo, al dominio de la frecuencia, sin alterar su contenido de información, solamente es una forma diferente de representarla. Astrónomo y matemático alemán nacido en Minden, Friedrich Bessel (1784-1846), 10 introdujo en matemáticas las funciones de Bessel como solución a ciertas ecuaciones diferenciales. Las funciones son de gran importancia para determinar la distribución y el flujo del calor o la electricidad, y para la solución de problemas relacionados con el movimiento ondulatorio, la elasticidad y la hidrodinámica. Llamadas funciones Splines, su gran popularidad se debe a que sus propiedades las hacen ideales, para atacar problemas muy variados en diversas áreas de la matemática, también son muy útiles en el diseño gráfico y en la solución numérica de ecuaciones diferenciales. Constituye un proceso importante en diferentes áreas de la ingenierı́a, la convolución representa una operación y un concepto matemático, que constituyen una aplicación que permite la obtención, de una solución real que plantea la transmisión de información, la interacción de dos cantidades en el tiempo y espacio, es la convolución de esas dos cantidades. 2.2. El sintetizador como instrumento musical Aparecido en la década de los sesentas, el sintetizador, es un dispositivo electrónico digital similar a un piano, que puede generar una gran variedad de sonidos musicales. Se denominan sintetizadores porque obtienen el sonido por medio de una sı́ntesis (proceso artificial), la cual se puede realizar por diferentes medios. Por ejemplo, los primeros sintetizadores se basaban en la teorı́a del análisis de Fourier y sumando las salidas de varios osciladores de forma de onda senoidal, obtenı́an diversos timbres según la amplitud que se le daba a la frecuencia fundamental (la nota) y sus armónicos. También utilizaban formas de onda del tipo diente de sierra, triangular y cuadrada, cada una de las cuales tiene un rico y particular contenido armónico [7]. Robert Moog, construyó el primer sintetizador analógico que aún lleva su nombre, el clásico Moog, el cual es un generador electrónico de formas de onda, que puede producir casi cualquier clase de señal periódica de audiofrecuencia. Actualmente podemos encontrar diversas formas de generar señales de audio, a 11 continuación mencionaremos las más conocidas técnicas de sı́ntesis: 1) Sı́ntesis Aditiva, parte de la idea contenida en el teorema de Fourier, según la cual todo sonido periódico, por complejo que sea, es el resultante de la suma de ondas sinusoidales sencillas de frecuencias múltiplo, de una frecuencia base. El proceso de esta sı́ntesis, fabrica sonidos mediante el modelo matemático, buscando la composición armónica; partiendo de pequeñas series armónicas y precisando la frecuencia y la amplitud de cada componente en cada instante. 2) Sı́ntesis Análoga o Substractiva, es la opción más antigua y duradera, se fundamenta en lo contrario de la aditiva, en lugar de ensamblar un sonido a partir de sus componentes, se sintetiza el resultado eliminando los componentes no deseados de un sonido parcial muy rico. La idea esencial es poder representar las variaciones de presión del sonido, en forma de variaciones de tensión. Los timbres se obtienen a partir de formas de onda complejas (ricas en armónicos) a las que se les sustraen, mediante filtros, ciertas partes de su estructura armónica. 3) Sı́ntesis Virtual, nace como la fusión de tres desarrollos técnicos de dinámica relación, primero la formal constitución del sintetizador como instrumento expresivo y la búsqueda de nuevas posibilidades para generar sonido, segundo, el constante desarrollo de microchips, unidades complejas de circuitos digitales, computación multimedia y finalmente el desarrollo de sofisticadas piezas de software, encontrándose ası́, que una computadora posee las caracterı́sticas necesarias para generar audio, modularlo y que es posible usar sonido previamente digitalizado (samples). 2.3. Métodos de programación de nuestro sistema Para la generación de sonido en la PC (Personal Computer) existen técnicas utilizadas en la Multimedia, multi (variedad) y media (medios). Se ha definido como la herramienta que emplea la PC para integrar y controlar diferentes sistemas electrónicos tales como: videodiscos, videocámaras, videocasetes, sintetizadores de video y audio, etc. Podemos mencionar que en un entorno multimedia, los elementos básicos 12 de hardware son: 1) La unidad de CD-ROM (Compact Disc Read Only Memory) y 2) La tarjeta de sonido. Se pueden utilizar diferentes técnicas de programación, para controlar los dispositivos multimedia sin ningún tipo de limitación. Por ejemplo, para tener acceso a la unidad de CD-ROM o a la tarjeta de sonido, el hardware, y los controladores de los dispositivos a utilizar, deberán estar instalados y configurados para la PC. La siguiente lista menciona el hardware que es necesario para los tipos de dispositivos MCI (Media Control Interfase) mas utilizados en el ambiente de programación Visual C++: 1) El CD de audio es controlado por la unidad de CD-ROM, 2) El secuenciador es controlado por la tarjeta de sonido, 3) El audio por forma de onda es controlado por la tarjeta de sonido. Para la administración de recursos multimedia de una forma apropiada, deben cerrarse los dispositivos MCI que se encuentren abiertos antes de salir de la aplicación o cerrar la ventana que contiene dichos dispositivos, podemos utilizar para ello la función OnDestroy con el mensaje SetCommand (close). Estas son las principales instrucciones, que se utilizan para cancelar la reproducción de audio y video [2]. En algoritmos computacionales a la representación eléctrica del sonido, se le conoce como Audio. En el proceso de conversión de la forma análoga a la forma digital de una señal y viceversa aparecen tres términos matemáticos: 1)el muestreo, 2)la cuantización y 3)la codificación. El muestreo, es el proceso de tomar medidas instantáneas de una señal análoga cambiante en el tiempo, tal como la amplitud de una forma de onda compleja, el Teorema de Muestreo o Teorema de Nyquist, establece que es posible capturar toda la información de la forma de onda, si se utiliza una frecuencia de muestreo del doble de la frecuencia más elevada contenida en la forma de onda. La cuantización, es el siguiente proceso para la reducción de la señal análoga compleja; éste permite aproximar la muestra a uno de los niveles de una escala designada. La codificación, es la representación de información analógica en una señal digital. El sistema PCM (Modulación por codificación de Pulsos) convierte la información 13 de dos canales de audio a forma digital. Una portadora puede modularse de diferentes modos, dependiendo del parámetro de la misma sobre él que se actúe. Se modula en amplitud (AM) una onda que llamaremos portadora, cuando la distancia existente entre el punto de la misma en el que la onda vale cero y los puntos en que toma el valor máximo o mı́nimo se altera. La modulación de frecuencia (FM) consiste en variar la frecuencia de la onda portadora de acuerdo con la intensidad de la onda de información. La amplitud de la onda modulada es constante e igual que la de la onda portadora. Para el procesamiento informático del sonido es necesario realizar su captura mediante una PC y almacenarlo en memoria o disco. El proceso básico para la captura de sonido es el siguiente: 1) El sonido se transmite por el aire hasta el micrófono, el cual transforma la señal acústica a niveles eléctricos, 2) La señal analógica pasa a través de un convertidor analógico/digital. Sus caracterı́sticas establecen la frecuencia y el número de bits por cada muestra, 3) Mediante un canal se copia cada muestra a la memoria de la PC. Cualquier lenguaje artificial que puede utilizarse para definir, una secuencia de instrucciones para su procesamiento por una computadora, es llamado lenguaje de programación. Vistos a muy bajo nivel, los microprocesadores procesan exclusivamente señales electrónicas binarias (0 y 1). Dar una instrucción a un microprocesador, es en realidad enviar series de unos y ceros con un espacio en el tiempo de una forma determinada. Esta secuencia de señales se denomina código de máquina. El código representa datos, números e instrucciones para manipularlos. Una manera más fácil de comprender el código de máquina es dando a cada instrucción un mnemónico, como por ejemplo STORE, ADD o JUMP. Esta abstracción da como resultado el lenguaje ensamblador, el cual es de muy bajo nivel y es especı́fico de cada microprocesador. Hay un alto nivel de abstracción entre lo que se pide a la computadora y lo que realmente comprende. Existe también una relación compleja entre los lenguajes de alto nivel y el código de máquina. Los lenguajes de alto nivel son normalmente fáciles 14 de comprender, porque están formados por elementos de lenguajes naturales, como el inglés. En BASIC, el lenguaje de alto nivel más conocido, los comandos como por ejemplo: IF CONTADOR = 10 THEN STOP pueden utilizarse para pedir a la computadora que pare si CONTADOR es igual a 10. Por otra parte, el lenguaje de programación C, fue desarrollado en 1972 por el estadounidense Dennis Ritchie en los laboratorios Bell, el cual es un lenguaje de programación de propósito general que ofrece; economı́a de sı́ntesis, control de flujo, estructuras sencillas y un buen conjunto de operadores, tiene un campo de aplicación ilimitado por que no es un lenguaje de muy alto nivel, más bien es pequeño y sencillo y no está especializado en ningún tipo de aplicación, esto lo hace un lenguaje potente, y se aprende en poco tiempo. Ahora hablemos del lenguaje C++, que es una versión orientada a objetos del lenguaje de programación llamado C, este fue desarrollado por Bjarne Stroustrup a comienzos de la década de 1980 en los laboratorios Bell. Ası́ mismo, en febrero de 1993, fue creado Microsoft Visual C++ 1.0, el cual es un entorno de desarrollo diseñado especialmente para crear aplicaciones gráficas orientadas a objetos, introduce la biblioteca MFC (Microsoft Foundation Class). Actualmente se cuenta con la versión Visual C++.Net, la cual cuenta con una mayor integración; MFC, ATL (Active Template Library) y una nueva clase de servicios web, convirtiéndose en el entorno de desarrollo, si se quiere combinar el control y el rendimiento de C++ con la compatibilidad con windows y el entorno .Net, también permite numerosas caracterı́sticas de nivel profesional y con el podemos crear aplicaciones para windows y la web muy eficaces. Ahora hablaremos del sistema unix, el cual es un sistema operativo multitarea y multiusuario. Esto quiere decir que el sistema puede ejecutar varios programas a la vez, y que puede gestionar a varios usuarios simultáneamente. Fue desarrollado originalmente por Ken Thompson y Dennis Ritchie en los laboratorios Bell en el año de 1969. Unix tiene diversas variantes (p.e. Linux) y se considera potente, más transportable e independiente de equipos concretos que otros sistemas operativos, 15 porque esta escrito en lenguaje C. 2.4. Resumen En el desarrollo de este capı́tulo tratamos conceptos básicos como: ondas sonoras, caracterı́sticas del sonido, armónicos, análisis de Fourier, sintetizadores, técnicas de sı́ntesis, muestreo, modulación, generación de sonido en PC, captura de sonido y lenguajes de programación (C, C++, Visual C++, Unix). 16 Capı́tulo 3 Aspectos del Diseño de Sintetizadores de Música En este capı́tulo presentaremos los aspectos de diseño de sintetizadores de música, ya que es necesario conocer su funcionamiento antes de ser implementado en algoritmos computacionales, por lo que mencionaremos varios tipos de osciladores básicos, los cuales usan transistores y amplificadores operacionales, tales como: osciladores RC, LC, VCO, Colpitts, Clapp, Hartley y el circuito integrado 555, describiendo cada uno de ellos. 3.1. Generadores electrónicos de formas de onda Un oscilador, es un circuito que produce una forma de onda repetitiva en su salida, con sólo el voltaje de alimentación de DC (Direct Current) como entrada, no requiere de una señal de entrada repetitiva. Diferentes tipos de osciladores producen diversos tipos de salidas, incluyendo ondas sinusoidales, cuadradas, triangulares y de diente de sierra, estos se aplican ampliamente en casi todos los sistemas de comunicación, sistemas digitales y computadoras para generar frecuencias y señales de sincronización requeridas. Un oscilador básico consta de: 1) Un amplificador para obtener la ganancia (transistor o amplificador operacional) y 2) Un circuito de realimentación positiva, que produce desfasamiento y nos introduce atenuación [4]. Mencionaremos ahora los principios de los osciladores: 1) La realimentación po17 sitiva, se caracteriza por la condición en que una parte del voltaje de salida de un amplificador, se realimenta a la entrada sin desfasamiento neto, con esto se reforza la señal de salida, esto es, se crea un lazo en donde la señal se sostiene a sı́ misma y se produce una salida en forma sinusoidal continua, por lo tanto se produce la oscilación. 2) Las condiciones para que ocurra la oscilación son dos: la primera, el desfasamiento alrededor del lazo de realimentación debe ser 0◦ , la segunda, la ganancia de voltaje alrededor del lazo cerrado de realimentación debe ser igual a la unidad. Y 3) La condición de arranque dice; que para que se inicie la oscilación, la ganancia de voltaje alrededor del lazo de realimentación positiva debe ser mayor que 1, de tal manera que para que la amplitud de salida pueda alcanzar un nivel deseado, la ganancia debe decrecer enseguida hasta 1, con el fin de conservar ese nivel. 3.2. Tipos de osciladores Dentro de los osciladores realimentados con circuitos RC (Resistencia-Capacitor) se mencionaremos tres tipos que proporcionan salidas sinusoidales: 1) El oscilador puente de Wien, su parte fundamental es una red de adelanto-atraso formada por resistencias y capacitores y que se usa en el lazo de realimentación positiva, esta red tiene una frecuencia de resonancia, en donde el desfasamiento a través de la red es 0◦ y la atenuación es 1/3. Por abajo de la frecuencia de resonancia predomina la red de adelanto y la salida se adelanta a la entrada, por arriba de la frecuencia de resonancia predomina la red de atraso y la salida se atrasa con respecto a la entrada. 2) El oscilador de corrimiento de fase, consta de tres redes RC en el lazo de realimentación, que puede proporcionar un desfasamiento máximo que tiende a 90◦ , la oscilación ocurre a la frecuencia en donde el desfasamiento total a través de las tres redes RC es de 180◦ . Y 3) El oscilador de T gemela, se conoce ası́ debido a los dos filtros RC de tipo T, que son usados en el lazo de realimentación negativa, uno de los filtros T tiene una respuesta pasa-bajas y el otro una pasa-altas, estos filtro son conectados en paralelo y producen una respuesta de un supresor de banda, 18 con frecuencia central igual a la frecuencia de oscilación deseada. Comúnmente estos osciladores se usan para frecuencias hasta de 1MHz (Mega Hertz). En osciladores que requieren frecuencias más altas de oscilación, normalmente se usan elementos de realimentación tipo LC (Bobina-Capacitor), a menudo se emplean transistores como elementos de ganancia en estos osciladores, a continuación nos introduciremos en varios tipos de osciladores LC resonantes tales como: 1) El oscilador Colpitts, denominado ası́ en honor de su inventor, en este tipo se usa un circuito LC en el lazo de realimentación, para proporcionar el desfasamiento necesario y poder operar como filtro resonante que va a pasar solamente la frecuencia de oscilación que se requiere. 2) El oscilador Clapp es una variante del Colpitts, la diferencia básica es un capacitor adicional en serie con el inductor, en el circuito resonante de realimentación. 3) El oscilador Hartley, es semejante al Colpitts, salvo que la red de realimentación está formada por dos inductores en serie y un capacitor en paralelo. 4) El oscilador Armstrong, usa un acoplamiento por transformador, con lo cual se realimenta una parte del voltaje de señal, algunas veces se le denomina oscilador de reacción en referencia al secundario del transformador, no es muy común en comparación con los anteriormente mencionados, en principio por la desventaja que presenta el tamaño y el costo del transformador. Y 5) Los osciladores controlados por cristal, son muy estables y exactos, por que usan un cristal piezoeléctrico en el lazo de realimentación, con el fin de poder controlar la frecuencia. Hemos tratado osciladores que a su salida la forma de onda es sinusoidal, sin embargo, existen osciladores que la forma de onda a su salida puede ser una onda triangular, diente de sierra, o cuadrada, algunos de estos tipos se refieren como generadores de señal o multivibradores. Continuando con los osciladores existe un tipo que es controlado por voltaje (VCO), cuya frecuencia puede cambiarse mediante un voltaje de control variable de DC, los VCO’s pueden ser sinusoidales o no sinusoidales. Por ejemplo, para construir un oscilador de diente de sierra controlado por voltaje, se puede emplear un inte19 grador con un amplificador operacional, que use un dispositivo de conmutación PUT (transistor de unı́ juntura programable) que se conecte en paralelo con el capacitor de realimentación. El PUT contiene un ánodo, un cátodo y una terminal de compuerta. La compuerta está siempre polarizada positivamente con respecto al cátodo, cuando el voltaje del ánodo excede al de la compuerta en aproximadamente 0.7 V (Volts), el PUT se enciende y opera como diodo polarizado directamente, si el voltaje del ánodo cae por debajo de este nivel, el PUT se apaga, al cumplirse estas condiciones junto con la carga y descarga del capacitor obtenemos un generador de diente de sierra. Por otra parte, tenemos a un circuito integrado muy versátil y con muchas aplicaciones, el temporizador 555, el cual se verá como oscilador. Este oscilador consta de dos comparadores, un circuito multivibrador biestable (flip-flop), un transistor de descarga y un divisor de voltaje resistivo. El multivibrador biestable, es un dispositivo digital de dos estados, cuya salida puede estar en un nivel alto de voltaje (set) o en un nivel bajo de voltaje (reset), estos estados pueden cambiarse mediante señales de entrada apropiadas. El 555 se puede conectar, para que opere en el modo astable como oscilador no sinusoidal de carrera libre. 3.3. Anatomı́a de un sintetizador Trataremos ahora los componentes elementales de un sintetizador. Conforme van pasando los años la tecnologı́a va progresando en el campo de la electrónica, por ejemplo, tenemos el caso del desarrollo y evolución del transistor, con esto es posible la construcción de generadores de sonido más finos. Ası́ en 1964 Robert Moog, en colaboración con un músico llamado Herbert Deutsch, desarrollaron los primeros VCO y VCA (Amplificador Controlado por Tensión), un año mas tarde, desarrolla los filtros controlados VCF (Filtro Controlado por Tensión), de pasa-bajas y pasa-altas, de igual manera los ADSR (generador de envolvente), esto dio paso al nacimiento del sintetizador analógico modular (llamado Moog en honor a su inventor). Más adelante se explicaremos los términos anteriormente mencionados. 20 Figura 3.1: Sintetizador elemental En la Figura 3.1 se muestra el diagrama a bloques de un sintetizador elemental, a continuación se describen cada uno de sus bloques: El teclado controlador está compuesto por una fuente la cual va a suministrar tensiones que son proporcionales a la tecla que se oprime, estas tensiones se utilizan para iniciar los generadores de envolvente. El VCO, es en este caso la fuente de sonido básica, la frecuencia de la señal que genera se obtiene como suma algebráica de las tensiones de control aplicadas a sus entradas, se usan con respuesta exponencial normalizada a 1V/Octava y disponen de varias formas de onda, sinusoidal, diente de sierra, triangular y cuadrada, y cada una de ellas dará un tipo de sonido peculiar y diferente, dado el distinto contenido armónico que tienen. El mezclador de audio, es un dispositivo que permite la combinación de una serie de señales de entrada deseadas, de manera que se obtiene otra señal que es la combinación de aquellas. El ADSR (Attack Decay Sustain Release), se refiere a cuatro zonas 21 caracterı́sticas de la amplitud de una señal de control, la zonas ADR se refiere a tiempos, mientras que S se refiere a un nivel, estos generadores de envolvente controlarán tanto la amplitud de la señal sonora como la respuesta del filtro. El VCA se combina con un generador ADSR, para impartir a los sonidos que modifica unas determinadas caracterı́sticas de ataque y decaimiento en su intensidad, de tal manera que permita la simulación de la dinámica de diversos instrumentos musicales, también es posible modular en amplitud la señal que se procesa para añadir trémolos y otros efectos que dependerán mucho de la frecuencia de la señal moduladora. Por otro lado, el VCF es un elemento que permite el paso de determinadas frecuencias de la señal de entrada y es el equivalente eléctrico de los resonadores acústicos de los instrumentos tradicionales, como la caja del violı́n, que da el sonido caracterı́stico del instrumento, este se puede configurar en varios modos, pasa bajo, pasa alto, pasa banda y supresor de banda, según sea el efecto que deseamos resaltar o atenuar de la onda básica generada por los VCO, se tiene que los parámetros caracterı́sticos de un filtro son la frecuencia de corte y la pendiente del filtro, que determina la atenuación de los sucesivos armónicos de la señal de entrada. Ya por último, el LFO (Low Frecuency Ocilator) generalmente se compone de varios osciladores independientes controlados por tensión, con varias formas de onda cada uno y que se sitúan en la banda de bajas frecuencias, hasta unos 20Hz, su salida puede usarse tanto para controlar la amplitud (trémolo), como la frecuencia (vibrato), de los VCO, obteniendo sonoridades muy variadas. Por último mencionaremos que existen técnicas para la generación de ruido, por ejemplo, la de un algoritmo computacional o un arreglo de dispositivos electrónicos, los cuales suelen proporcionar ruido blanco o rosa, ası́ como una salida de tensión de control aleatoria, pero ajustable en ciertos parámetros, estas tres señales sirven para producir sonidos no convencionales similares a los naturales, como el mar, el trueno y el siseo del aire. 22 3.4. Resumen En este capı́tulo presentamos varios tipos de osciladores, tales como: osciladores RC, LC, VCO, Colpitts, Clapp, Hartley, describiendo cada uno de ellos, también se presentó un circuito integrado muy popular, llamado temporizador 555 en su forma de oscilador, ası́ mismo describimos el diagrama de un sintetizador elemental, estos conceptos son la antesala para el diseño básico de un sintetizador elemental, que más adelante presentaremos. 23 Φ 24 Capı́tulo 4 Diseño de Nuestro Sintetizador de Notas En este capı́tulo presentaremos el diseño de nuestro sintetizador de notas musicales. Explicaremos con más detalle la programación de la sı́ntesis de onda y las estructuras de sonido más importantes que se requieren para la programación del driver que controla la tarjeta de sonido de una computadora digital PC. 4.1. Computadoras digitales Una computadora digital funciona con base al procesamiento de números digitales, y son el tipo de computadoras en el que se ha centrado el progreso moderno. Éstas se dividen en cuatro principales generaciones que son; 1) Primera generación (19511958), en la cual se usaron bulbos para almacenar la información y tarjetas perforadas para cargar datos y programas. 2) Segunda generación (1959-1964), con el invento del transistor llego esta nueva generación de computadoras, las cuales utilizaron cintas y discos magnéticos para almacenar información y disponı́an de celdas fotoeléctricas para la mejor lectura de las tarjetas perforadas. 3) Tercera generación (1964-1971), aquı́ se da la llegada de los circuitos integrados a las computadoras, con lo cual se incrementa el rendimiento de las máquinas, pudiendo ası́ trabajar a tal velocidad que se podı́a correr más de un programa de manera simultanea. Las computadoras se hicieron más pequeñas, más rápidas y desprendı́an menos calor. 4) Cuarta generación 25 (1971-a la fecha), la colocación de componentes más pequeños en un chip, permite crear el microprocesador, el cual rige las funciones principales en una computadora. Se crean memorias electrónicas, las cuales desechan a las memorias de núcleo magnético que se usaban anteriormente, aumentando ası́ su rapidez. Con la llegada de estas tecnologı́as, se hizo posible la creación de la PC (Personal Computer). Las computadoras siguen avanzando hasta nuestros dı́as, creando mejores técnicas y desarrollando nuevas tecnologı́as. Una parte importante de las computadoras hoy en dı́a es la Internet, que puede ser definida como red de redes, es decir, una red que interconecta redes de computadoras entre sı́. Una red de computadoras es un conjunto de máquinas que se comunican a través de algún medio (cable coaxial, fibra óptica, radiofrecuencia, lı́neas telefónicas, etc.) con el objeto de compartir recursos. Aunque se pueda pensar que internet inició hace pocos años, no es ası́, sus inicios nos remontan a la década de los 60’s. En plena guerra frı́a Estados Unidos creó una red de uso exclusivamente militar, para que en caso de un ataque se pudiera tener acceso a la información desde cualquier parte del paı́s. El envió de datos deberı́a descansar en un mecanismo que pudiera manejar la destrucción parcial de la red, de esta manera se decidió enviar la información en pequeños mensajes o paquetes, los cuales contendrı́an la dirección de destino, pero no una ruta especı́fica para su arribo, cada paquete buscarı́a una ruta y al final el destinatario reensambları́a el mensaje original. Esta red se creo en 1969 y fue llamada ARPANET (Advanced Research Projects Agency Network). Esta red fue situada en diferentes universidades del paı́s y creció tanto que su protocolo NCP (Network Control Protocol), quedó obsoleto. Entonces con el tiempo se dio paso a un protocolo mas sofisticado, el TCP/IP (Transmission Control Protocol / Internet Protocol), que es el protocolo utilizado hasta nuestros dı́as. TCP se encarga de convertir los mensajes a paquetes en la máquina emisora y los reensambla en la máquina destino, mientras que IP se encarga de buscar la ruta destino. En 1983 el segmento militar decide separarse de ARPANET y formar su propia red conocida 26 como MILNET (Militar Network). En 1984 la National Science Foundation, crea una nueva red llamada NSFNET (National Science Foundation Network) y con un incremento continuo de transmisión de datos de la misma, logró absorber a ARPANET. Sin embargo, el continuo crecimiento de nuevas redes de libre acceso, terminaron en la unión de éstas con NSFNET, formando ası́ el embrión de lo que ahora es Internet. Con la creación de las páginas web y del primer explorador, Internet no ha dejado de crecer y paso de ser una red de investigación militar, a un negocio y eso ha sido lo que impulsa su desarrollo. 4.2. Estructuras del controlador (driver) de sonido Por otra parte, para el diseño de sı́ntesis de ondas, necesitamos conocer el funcionamiento y caracterı́sticas principales de algunas funciones y estructuras que se utilizaran posteriormente. Empecemos con la estructura WAVEFORMATEX, la cual contiene la información más común de la forma de onda y define su formato, cuando se requiere mayor información, ésta será incluida como primer miembro en otra estructura con la información adicional. La siguiente es su estructura: typedef struct { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; }WAVEFORMATEX; Donde, wFormatTag especifica el tipo de formato de la forma de onda; nChannels especifica el número de canales a utilizar, que puede ser monoaural para un canal o estereo para dos canales; nSamplesPerSec es el número de muestras por segundo que en cada canal se reproducirán o grabarán, si wFormatTag tiene especificado WAVE FORMAT PCM, entonces los valores comunes de muestras por segundo 27 son: 8.0 KHz, 11.025 KHz, 22.05 KHz y 44.1 KHz; nAvgBytesPerSec requiere hacer un promedio de la transferencia de datos en bytes por segundo, si wFormatTag tiene especificado WAVE FORMAT PCM, entonces nAvgBytesPerSec debe ser igual al producto de nSamplesPerSec y nBlockAlign; nBlockAlign es el alineamiento de bloques en bytes, éste es la unidad mı́nima de datos para el tipo de formato, si wFormatTag tiene especificado WAVE FORMAT PCM, entonces nBlockAlign debe ser igual al producto de nChannels y wBitsPerSample, dividido entre 8; wBitsPerSample son los bits por muestra para el tipo de formato, si wFormatTag tiene especificado WAVE FORMAT PCM, entonces wBitsPerSample debe ser igual a 8 o 16; cbSize es utilizada para agregar información extra de la estructura WAVEFORMATEX, cuando el formato es diferente de PCM [9]. Quien se encarga de abrir el dispositivo de salida de la forma de onda es la función waveOutOpen y su estructura es la siguiente: MMRESULT waveOutOpen( LPHWAVEOUT {\it phwo}, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen ); Donde, phwo es ocupado para identificar y relacionar las diferentes funciones de salida de forma de onda; uDeviceID identifica el dispositivo a utilizar, el cual puede ser de entrada o salida; pwfx es una dirección de la estructura WAVEFORMATEX, la cual identifica los datos de la forma de onda que serán enviados al dispositivo, esta estructura será vaciada inmediatamente después que se pase a la función waveOutOpen; dwCallback es una dirección que asegura que la función regrese, ya sea de un manejador de eventos, de un manejador de ventana, etc., esto dependerá de la bandera que se utilice (fdwOpen), si esta función no es usada, su valor puede ser cero; dwCallbackInstance se usa para pasar datos al mecanismo de llamada de regreso; fdwOpen es un parámetro que usa banderas para abrir el dispositivo, las 28 banderas son las siguientes: CALLBACK EVENT permite manejar eventos; CALLBACK FUNCTION regresa algún procedimiento a una dirección; CALLBACK NULL no tiene mecanismo de regreso y solo cuenta con los parámetros iniciales; CALLBACK THREAD es un hilo identificado; CALLBACK WINDOW es un manejador de ventana; WAVE ALLOWSYNC indica que un dispositivo de forma de onda sı́ncrono puede estar abierto; WAVE FORMAT DIRECT especificada que el controlador ACM (Audio Compression Manager) no llevará acabo las conversiones en los datos de audio; WAVE FORMAT QUERY indica a waveOutOpen preguntar al dispositivo determinado si soporta el formato dado, pero el dispositivo no estará abierto; WAVE MAPPED indica al parámetro uDeviceID especificar un dispositivo de forma de onda para ser mapeado. Para detener el dispositivo de salida y reiniciar la corriente de posición a cero, es utilizada la función waveOutReset y su estructura es la siguiente: MMRESULT waveOutReset(HWAVEOUT hwo); donde hwo es el manejador del dispositivo de salida de forma de onda. Una estructura importante es WAVEHDR, ya que define los parámetros usados para identificar un buffer de audio de forma de onda y su estructura es la siguiente: typedef struct { LPSTR lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD dwUser; DWORD dwLoops; DWORD dwFlags; } WAVEHDR; Donde, lpData es la dirección del buffer de la forma de onda; dwBufferLength es la longitud en bytes del buffer; dwBytesRecorded es puesta cuando la estructura es usada para entrada, este miembro especifica cuantos datos hay en el buffer; dwUser son los datos de usuario; dwLoops es el número de veces que la función se repite, dentro de una iteración; dwFlags son las banderas de abastecimiento de información acerca del buffer: WHDR BEGINLOOP es el primer buffer en un lazo y solo puede 29 ser usado con buffer de salida; WHDR DONE es colocada en el controlador del dispositivo para indicar que ha finalizado el buffer y está regresando a la aplicación; WHDR ENDLOOP es el último buffer en el lazo y solo es usada con buffer de salida; WHDR INQUEUE es puesto por windows para indicar que el buffer está en cola para tocar; WHDR PREPARED también es puesto por windows para preparar al buffer, ya sea con una función de entrada o una de salida. Para preparar un bloque de datos de la forma de onda y después tocarlos utilizamos la función waveOutPrepareHeader. Su estructura es la siguiente: MMRESULT waveOutPrepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh ); Donde, hwo es el manejador del dispositivo de salida de forma de onda; pwh es una dirección de la estructura WAVEHDR, que define los bloques de datos para prepararlos; cbwh es el tamaño en bytes de la estructura WAVEHDR. Una parte importante es la función waveOutWrite, ya que es la encargada de mandar bloques de datos a la salida del dispositivo de forma de onda. Su estructura es la siguiente: MMRESULT waveOutWrite( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh ); Donde, hwo es el manejador del dispositivo de salida de forma de onda; pwh es la dirección de una estructura WAVEHDR, la cual contiene información acerca del bloque de datos; cbwh es el tamaño en bytes de la estructura WAVEHDR. Para limpiar la preparación llevada a cabo por la función waveOutPrepareHeader es utilizada la función waveOutUnprepareHeader, esta función debe ser llamada después de que el dispositivo haya finalizado con un bloque de datos y antes de liberar el buffer. Su estructura es la siguiente: 30 MMRESULT waveOutUnprepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh ); Donde, hwo es el manejador del dispositivo de salida de forma de onda; pwh es la dirección de una estructura WAVEHDR, para identificar los datos que serán limpiados; cbwh es el tamaño en bytes de la estructura WAVEHDR. Por último tenemos a la función waveOutClose, que es la encargada de cerrar el dispositivo de salida de forma de onda y su estructura es la siguiente: MMRESULT waveOutClose( HWAVEOUT hwo ); Donde, hwo es el manejador del dispositivo de salida de forma de onda. 4.3. Programación de las funciones de onda Para la generación de sonido en nuestro diseño, una de las funciones más importantes es la que llamaremos FillBuffer. Esta función es la encargada de manipular las diferentes formas de onda con las que trabajaremos, y tiene la siguiente estructura: 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; } } La función anterior genera datos digitales (bytes) que corresponden a una señal analógica (en este caso un seno), que debe estar en el rango de frecuencias audibles para el oı́do humano (de 20-20 KHz), esta será almacenada en memoria con una razón de muestras digitales que llamaremos SAMPLE RATE. Para generar una onda de 20 KHz es necesario que en cada ciclo se tomen mı́nimo dos muestras, por esta razón 31 el SAMPLE RATE toma el valor de 44100 Hz. Por ejemplo para generar una forma de onda con una frecuencia de 8820 Hz por cada ciclo se tomarán 5 muestras, como se muestra en la Figura 4.1, esto significa que el número de muestras por segundo es el SAMPLE RATE divido entre la frecuencia de la forma de onda. El seno de cada muestra será almacenado en la localidad de un buffer previamente definido. Figura 4.1: Número de muestras por cada ciclo. Se puede aprovechar que la señal con la que se está trabajando es una señal periódica, de esta manera se puede trabajar con un solo ciclo incrementando las localidades de memoria y repitiendo los ángulos de fase. El primer ángulo será 0, después la variable fAngle es incrementada 2π veces la frecuencia dividida entre el SAMPLE RATE, este procedimiento continúa hasta que fAngle es mayor que 2π, entonces será decrementado en 2π para volver a retomar los ángulos que ahora serán almacenados en diferentes localidades de memoria de nuestro buffer. Cada localidad de memoria es de 8 bits por esta razón la función seno está dada entre 0 y 254 (00 a FF) [8]. Por otro lado tenemos que, un seno es una porción fundamental en la trigonometrı́a, en un triángulo rectángulo el valor del seno de un ángulo agudo, es igual a la longitud del cateto opuesto al ángulo, dividida por la longitud de la hipotenusa. El valor numérico del seno está comprendido entre -1 y 1, la curva de este es el prototipo o modelo de todas las sinusoides. Se tiene que un ángulo representa la apertura de dos lı́neas que tienen un origen común (vértice); un arco se define como la lı́nea circular 32 que rodea al ángulo por el extremo de dos segmentos, las medidas de un ángulo se pueden expresar en radianes; el radian es el ángulo cuyo arco tiene una longitud igual al radio. Por lo tanto tenemos que, 1◦ = 0.01745 radianes y 1 radian = 57.3 grados, el grado está definido en trigonometrı́a como el arco igual a 1/360 de la circunferencia de un cı́rculo. 4.4. Visualización de las formas de onda Mediante la sumatoria de señales simples, podemos obtener una señal compleja que sea semejante a la forma de onda caracterı́stica de algún instrumento musical. Tomando en cuenta el teorema de Fourier, que dice: que por medio de la suma de funciones periódicas de distinta frecuencia es posible obtener una señal compleja, hemos creado un programa en Visual C++ que muestra gráficamente el teorema de Fourier [3]. En la Figura 4.2 se muestra el resultado de nuestro programa, que se encuentra dividido en cuatro ventanas; en la primera se representa la frecuencia más baja llamada frecuencia fundamental; en las ventanas dos y tres se representan el tercer y noveno armónico respectivamente, los cuales son múltiplos de la frecuencia fundamental; en la ventana cuatro podemos observar una forma de onda compleja, la cual es el resultado de la sumatoria de las tres ventanas anteriores. Tenemos que una serie de Fourier está representada por una sumatoria de senos y cosenos, su representación matemática es la siguiente: f (t) = a0 ∞ X cos(kw0 t) + bk n=1 ∞ X sen(kw0 t) (4.1) n=1 Una señal por compleja que sea se puede representar mediante la función f(t), las funciones pueden ser pares e impares, las funciones pares tienen una gráfica que debe ser geométrica respecto al eje vertical, las funciones impares tienen su gráfica simétrica con el origen, también existen funciones que no cumplen con la definición de función par e impar. 33 En las ventanas de la Figura 4.2 tenemos dos barras de desplazamiento, la barra horizontal representa la frecuencia (kw0 t), la barra vertical representa la amplitud de la señal (a0 , ak ,bk ). Si la señal es par entonces, bk = 0, y la señal estará representada por cosenos. Si la señal es impar entonces, a0 y ak = 0, por lo tanto la señal estará representada por senos. En la ventana superior izquierda tenemos representada a la señal: a seno(w0 t); la ventana superior derecha representa: ak seno(3w0 t); la ventana inferior izquierda representa: ak seno(9w0 t); y por último en la ventana inferior derecha, queda representada gráficamente la sumatoria de las ventanas anteriormente Figura 4.2: Representación gráfica de la Serie de Fourier, mediante un programa diseñado en C++. 34 mencionadas, dando la función: f(t) = a seno(w0 t)+ak seno(3w0 t)+ak seno(9w0 t), que es la representación de la Ecuación 4.1. Estas ventanas se implementan con un buffer y algunas estructuras de audio, para obtener el sonido de las señales que representan dichas ventanas, por lo tanto, vamos a obtener la respuesta gráfica y el audio, que pueden ser semejantes a cualquier instrumento musical. 4.5. Anatomı́a de una tarjeta de sonido Una parte muy importante de este proyecto es la tarjeta de sonido, ya que permitirá implementar la parte de audio en nuestro proyecto. En un principio la PC (Personal Computer) no fue diseñada para trabajar con sonido, sin embargo, con el desarrollo de nuevas aplicaciones (video juegos, música electrónica, etc.), tuvo que ser desarrollado un hardware diseñado para controlar el sonido y que fuese compatible con la PC, de esta manera en la década de los 80’s aparece la tarjeta de sonido. En la actualidad las tarjetas de sonido se encuentran divididas en dos partes: la parte analógica y la parte MIDI (Musical Instrument Digital Interface) [6]. En la Figura 4.3 se muestra el diagrama a bloques de una tarjeta de sonido. Se puede observar que la parte analógica se encuentra subdividida en tres bloques; el primero es un convertidor analógico-digital, que es el encargado de transformar los datos analógicos de la entrada (micrófono, guitarra, etc.) a datos digitales, ya que la PC solo trabaja con este tipo de datos; en el segundo bloque se encuentran los drivers de audio, que usa windows para manipular los datos que le pasará el primer bloque; y por último el tercer bloque es un convertidor digital-analógico, que realiza una operación inversa al primer bloque, para que el escucha pueda interpretar el sonido. La segunda parte se encuentra dividida en cuatro bloques; los bloques de entrada y salida son un receptor universal, los cuales se encargan de mandar y recibir datos; el bloque del sintetizador de sonido, consta de dos formas de sintetización de datos, una es sintetización FM, la cual se encarga de imitar el sonido por medio de formulas 35 Figura 4.3: Diagrama a bloques de una tarjeta de sonido. matemáticas y la otra es la sı́ntesis por tabla de onda, en la cual ya no se crea música computarizada, sino que se busca en una tabla con muestras de ondas del instrumento deseado [5]. Cabe mencionar que la parte de MIDI no será requerida para este proyecto. 4.6. Resumen En este capı́tulo presentamos lo más relevante del diseño de nuestro sintetizador de notas musicales, también presentamos la programación de las estructuras de audio, ası́ como el método que utilizamos para realizar la sı́ntesis de onda y por último describimos cómo se encuentra estructurada una tarjeta de sonido. En el siguiente capı́tulo presentaremos el diseño de la interfaz la gráfica de nuestro sistema. 36 Capı́tulo 5 Diseño de la Interfaz Gráfica En este capı́tulo presentaremos el diseño la interfaz gráfica, la cual es el medio de comunicación entre el usuario y las estructuras utilizadas en el diseño de sı́ntesis de ondas. Se plantearán conceptos necesarios para su comprensión, tales como: pı́xel, mapa de bits, recurso gráfico, ventana madre, ventana hija, sistema de coordenadas, entre otros. 5.1. Pixeles y mapas de bits Para dibujar sobre dispositivos gráficos se utiliza la GDI (Graphics Device Interface), la cual se encarga de llamar las rutinas de diversos dispositivos (drivers de video, impresora, y trazadores gráficos). Las aplicaciones gráficas útilizan un sistema de coordenadas (x, y) en el área de dibujo, para saber la ubicación de cada punto que se encuentre en pantalla, el valor x da la ubicación del punto sobre el eje x, con la ubicación predeterminada 0 en el extremo izquierdo, desplazándose de izquierda a derecha, el valor de y es la ubicación del punto en el eje y, con la ubicación predeterminada 0 en el extremo superior, desplazándose de arriba hacia abajo. Un punto que representa la menor unidad gráfica de medida de una pantalla es llamado pı́xel. La imagen digital de algún dibujo es conocida como mapa de bits, la imagen esta constituida por pı́xeles, donde cada uno corresponde a uno o más bits del mapa, por ejemplo: un mapa de bits de un sólo color requiere un bit por pı́xel, 37 mientras que un mapa de bits de más de un color requiere varios bits por pı́xel. 5.2. Ventanas, barras, y otros controles gráficos Existen elementos que interactúan directamente con el usuario, tales como: cajas de diálogo, ı́conos, cursores, mapas de bits, etc., estos elementos son conocidos como recursos. La lista de todos los recursos que utilice alguna aplicación se encuentra en un archivo con extensión .rc, los recursos se guardan en un directorio y pueden ser editados directamente (colocar barras de desplazamiento, cajas de texto, botones de pulsación, etc.), con los editores de recursos de Visual C++ [2]. Una ventana sirve de fondo para los controles y para los gráficos, se pueden utilizar tantas ventanas como se necesiten y dependiendo de la utilidad que se les dé, éstas pueden ser de diferentes tipos. Se pueden crear ventanas desde el editor de diálogos de Visual C++ o escribir el código en un archivo .cpp, como se muestra a continuación: CVentanaPpal::CVentanaPpal() { // Crear la ventana principal Create( NULL, "Windows - C++", WS_OVERLAPPEDWINDOW, CRect( 175, 100, 465, 300), NULL, NULL, 0, NULL ); } Las ventanas están organizadas jerárquicamente; una ventana padre o marco principal, ventana cliente o área de cliente y ventana hija o ventana marco de documento, la ventana padre es una ventana convencional; esto es, tiene una barra de tı́tulo, una barra de herramientas, un menú de control, un borde que permite redimensionar la ventana y botones para maximizar, minimizar y cerrar la ventana, el área de cliente de la ventana padre es denominada ventana cliente, en ésta se contienen las ventanas hijas, cada una de las cuales visualizan un documento(Figura 5.1). 5.3. Programando la interfase gráfica Una clase es una estructura de datos cuyos campos son métodos. Los métodos también son conocidos como funciones, estos son la base de las aplicaciones y se 38 Figura 5.1: Jerarquı́a de ventanas. encuentran declaradas en diversos archivos de cabecera incluidos en Visual C++. Para indicarle a una aplicación en ejecución, que ha sucedido algún evento (clic sobre un botón, mover el ratón, pulsar una tecla) es necesario enviar una notificación la cual es conocida como mensaje. La aplicación responde con una acción, que está determinada por la ejecución del código en una función, esto significa que enviar un mensaje equivale a ejecutar una función dentro de una aplicación. Para la implementación de la interfase de nuestra aplicación contaremos con una ventana como la que se muestra en la Figura 5.2, la cual mezclará una señal fundamental con cinco de sus armónicos, estas señales se visualizarán en la ventana ası́ como la señal resultante. Contará también con una serie de botones, los cuales simularán las teclas del piano y al hacer clic en ellas se escuchará la señal antes mencionada. A continuación explicamos el procedimiento para la realización del software antes mencionado en el lenguaje de programación Visual.C++. Inicialmente necesitamos crear un documento vacio (esqueleto de la aplicación), para esto de clic en la orden new del menú file, esto invocará a Class Wizard, en la pestaña projects se elige una aplicación MFC (Microsoft Foundation Class) AppWizard [exe] y ponga el nombre del proyecto (en este caso lo llamaremos Sintetizador) y la 39 Figura 5.2: Interfaz gráfica de la aplicación. localización, las otras opciones en esta ventana son las dadas por omisión. En ese momento comienzan los pasos que genera Class Wizard; en el paso 1 se elige un documento simple; en los pasos 2 y 3 se toman las opciones por omisión; en el paso 4 se desactivan las tres primeras casillas (Docking Toolbar, Inicial Status Bar y Printing and Print Preview), dejando sólo los controles 3D; en el paso 5 se toman las opciones por omisión; y en el paso 6 se elige la opción CFormView del menú Base Class, para obtener un formulario como vista principal. Al dar clic en el botón finalizar, se muestra la información del proyecto que se realizará cuando demos clic en el botón OK de esta ventana. El paso siguiente es dibujar sobre la vista cinco barras verticales, las cuales controlarán la amplitud de los armónicos de la frecuencia fundamental, una barra horizontal que servirá como afinador y una caja de texto por cada barra, en donde se visualizará en valor de la misma al ser pulsada. Cada objeto cuenta con un identificador 40 que es llamado ID, para modificarlo es necesario: entrar al cuadro de propiedades del objeto y asignarle un nombre que sea cómodo para ser manipulado. Cabe mencionar que usted puede acomodar los botones como más le convenga. Para facilitar la entrada y salida de datos a través de controles se utilizan variables miembro que los representen, para que el código trabaje sobre esas variables y se olvide de los controles. Ejecute Class Wizard (Ctrl.+ w), de clic en la pestaña Member Variables y seleccione el ID de la barra que desee, ahora pulse el botón Add Variable.. y añada para la barra horizontal la variable m CtrlBarraH1, para las barras verticales agregue las variables m CtrlBarraV1 hasta m CtrlBarraV5, todas de categorı́a Control y tipo CScrollBar, para la caja de texto de la barra horizontal la variable aH1 y para las cajas de texto de las barras verticales las variables aV1 hasta aV5, todas estas de tipo int. Para inicializar las barras de desplazamiento es necesario modificar la función miembro OnInitialUpdate, ya que es la primera función de la vista en ejecutarse, está se encuentra en el archivo fuente sintetizadorview.cpp. Edite la función como se muestra a continuación: void CSintetizadorView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(false); m_CtrlBarraH1.SetScrollRange(415, 466, false); m_CtrlBarraH1.SetScrollPos(440, false); m_CtrlBarraV1.SetScrollRange(0, 16, false); m_CtrlBarraV1.SetScrollPos(0, false); ... ... ... m_CtrlBarraV5.SetScrollRange(0, 16, false); m_CtrlBarraV5.SetScrollPos(0, false); } UpdateData(false); La función SetScrollRange asigna los valores mı́nimo y máximo para la barra de 41 desplazamiento especificada. La función SetScrollPos sitúa el cuadro de desplazamiento en la posición indicada. Cuando el usuario actúe sobre una de las barras de desplazamiento se genera un mensaje, si la barra es horizontal el mensaje será WM HSCROLL y si la barra es vertical el mensaje será WM VSCROLL, esto hará que se ejecute la función asociada OnHScroll o OnVScroll. Para esto invoque Class Wizard y de clic en la ventana Message Maps, enseguida seleccionando la clase CSintetizadorView, el objeto CSintetizadorView y el mensaje WM HSCROLL, de clic en el botón Add Fuction y después en el botón Edit Code y edite la función OnHScroll de la siguiente forma: void CSintetizadorView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nNuevaPo = pScrollBar->GetScrollPos(); switch( nSBCode ) { case SB_LEFT: nNuevaPo = 415; break; case SB_RIGHT: nNuevaPo = 466; break; case SB_PAGERIGHT: nNuevaPo = min(466, nNuevaPo + 5); break; case SB_PAGELEFT: nNuevaPo = max(415, nNuevaPo - 5); break; case SB_LINERIGHT: nNuevaPo = min(466, nNuevaPo + 1); break; case SB_LINELEFT: nNuevaPo = max(415, nNuevaPo - 1); break; } case SB_THUMBTRACK: nNuevaPo = nPos; break; default:; pScrollBar->SetScrollPos( nNuevaPo ); 42 aH1 = m_CtrlBarraH1.GetScrollPos(); Graficador(); } CFormView::OnHScroll(nSBCode, nPos, pScrollBar); Un procedimiento similar se hace para la función OnVScroll, esta función se ejecuta igual que la anterior pero ahora con el mensaje WM VSCROLL, y a continuación edı́tela de la siguiente forma: void CSintetizadorView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nNuevaPos = pScrollBar->GetScrollPos();l switch( nSBCode ) { case SB_LEFT: nNuevaPos = 0; break; case SB_RIGHT: nNuevaPos = 16; break; case SB_PAGERIGHT: nNuevaPos = min(16, nNuevaPos + 2); break; case SB_PAGELEFT: nNuevaPos = max(0, nNuevaPos - 2); break; case SB_LINERIGHT: nNuevaPos = min(16, nNuevaPos + 1); break; case SB_LINELEFT: nNuevaPos = max(0, nNuevaPos - 1); break; case SB_THUMBTRACK: nNuevaPos = nPos; break; CFormView::OnVScroll(nSBCode, nPos, pScrollBar); } pScrollBar->SetScrollPos( nNuevaPos ); aV1 = m_CtrlBarraV1.GetScrollPos(); aV2 = m_CtrlBarraV2.GetScrollPos(); aV3 = m_CtrlBarraV3.GetScrollPos(); aV4 = m_CtrlBarraV4.GetScrollPos(); aV5 = m_CtrlBarraV5.GetScrollPos(); 43 Graficador(); } CFormView::OnVScroll(nSBCode, nPos, pScrollBar); Las variables miembro aH1 y aV’s son igualadas con la posición en la que se encuentre la barra de desplazamiento para ser mandadas a la caja de texto y a la función Graficador que más tarde será declarada. Para una mejor manipulación de estas variables, borre su declaración que se encuentra en el archivo sintetizadorview.h y declárelas como variables globales en el archivo sintetizadorview.cpp. Al final de cada código estamos llamando a una función Graficador, está función es la encargada de dibujar la señal fundamental, los armónicos y la resultante en la vista principal. Para darla de alta ocuparemos AppWizard, esto lo hacemos dando clic en la pestaña ClassView de la ventana WorkSpace, desplegamos el menú sintetizador classes y damos clic derecho sobre la clase CSintetizadorView, al hacerlo aparecerá un menú y daremos clic sobre la opción Add Member Function, aparecerá una ventana en donde preguntará el tipo de función, que será void y la declaración o nombre de función, que será Graficador. Edite esta función de la manera siguiente: void CSintetizadorView::Graficador() { CClientDC dc(this); CClientDC dc2(this); CClientDC dc3(this); CClientDC dc4(this); CClientDC dc5(this); CClientDC dc6(this); CClientDC dc7(this); dc.SetMapMode(MM_ISOTROPIC); dc.SetViewportExt(630,20); dc.SetViewportOrg(47,400); dc2.SetMapMode(MM_ISOTROPIC); dc2.SetViewportExt(630,20); dc2.SetViewportOrg(47,560); dc3.SetMapMode(MM_ISOTROPIC); dc3.SetViewportExt(630,20); dc3.SetViewportOrg(250,416); 44 dc4.SetMapMode(MM_ISOTROPIC); dc4.SetViewportExt(630,20); dc4.SetViewportOrg(250,560); dc5.SetMapMode(MM_ISOTROPIC); dc5.SetViewportExt(630,20); dc5.SetViewportOrg(450,416); dc6.SetMapMode(MM_ISOTROPIC); dc6.SetViewportExt(630,20); dc6.SetViewportOrg(450,560); dc7.SetMapMode(MM_ISOTROPIC); dc7.SetViewportExt(630,20); dc7.SetViewportOrg(700,420); RedrawWindow(); for(x=0;x<=2000; x ++) { w = (440*2*3.14); w2 = (880*2*3.14); w3 = (1320*2*3.14); w4 = (1760*2*3.14); w5 = (2200*2*3.14); w6 = (2640*2*3.14); ysen=(int)(87+87*sin(x*w/440)); ysen2=(int)(8+aV1*sin(x*w2/880)); ysen3=(int)(8+aV2*sin(x*w3/1320)); ysen4=(int)(8+aV3*sin(x*w4/1760)); ysen5=(int)(8+aV4*sin(x*w5/2200)); ysen6=(int)(8+aV5*sin(x*w6/2640)); resul=(int)((87+87*sin(x*w/440))+(8+aV1*sin(x*w2/440))+ (8+aV2*sin(x*w3/440))+(8+aV3*sin(x*w4/440))+ (8+aV4*sin(x*w5/440))+(8+aV5*sin(x*w6/440))); } } dc.SetPixel(x*8,ysen*50,RGB(0,0,0)); dc2.SetPixel(x*8,ysen2*300,RGB(0,0,0)); dc3.SetPixel(x*8,ysen3*300,RGB(0,0,0)); dc4.SetPixel(x*8,ysen4*300,RGB(0,0,0)); dc5.SetPixel(x*8,ysen5*300,RGB(0,0,0)); dc6.SetPixel(x*8,ysen6*300,RGB(0,0,0)); dc7.SetPixel(x*12,resul*80,RGB(0,0,0)); UpdateData( false ); Declare las variables ysen a ysen6, x y resul, como tipo int y las variables w a w6 de tipo double, todas como variables globales. La función RedrawWindow se encarga de limpiar la pantalla cada vez que movemos las barras y se dibuja la función seno. 45 El CClientDC nos sirve para obtener el contexto de dispositivo del área de cliente y acceder a sus atributos a través de la función miembro de la clase del contexto de dispositivo. La función SetMapMode se encarga de ajustar el sistema de coordenadas a algún modo de proyección que en este caso es MM ISOTROPIC, el cual es un modo que se puede personalizar, permitiéndonos manipular el tamaño de las figuras cuando se redimensione la ventana. SetViewportExt establece la medida del ancho del dibujo. SetViewportOrg sitúa el origen lógico 0,0 de coordenadas, en algún punto del área de cliente (las funciones expuestas en la función Graficador son opcionales). SetPixel dibuja un punto en la pantalla, las coordenadas que utiliza son referidas por un for y por el resultado de las operaciones matemáticas, para que estas operaciones se lleven a cabo se necesita declarar la librerı́a math.h al inicio de sintetizadorview.cpp. Siguiendo con la aplicación se pretende visualizar la octava de un teclado en la vista principal. El primer paso es dibujar trece botones en el formulario, acomódelos de tal forma que aparenten el tamaño de una tecla blanca y una tecla negra como las del teclado. Cuando creamos un botón de mapa de bits es necesario poner su propiedad Owner Draw a valor true, esto hace que se visualice el mapa de bits dependiendo del estado del botón, enseguida añadiremos dos mapas de bits por cada botón para que aparenten una tecla, una para cuando la tecla este pulsada y otra para cuando este en reposo, los mapas de bits deben ser creados por usted en cualquier programa de edición de imágenes (Paint Brush, Corel Draw, etc.) en nuestro caso usamos Macromedia Flash. Ahora abra el editor de recursos para importar estas imágenes como recursos de tipo bitmap, asigne a cada una de las imágenes un ID compuesto por el titulo del botón (en nuestro caso BOTON) más una letra U o D (Up, Down) correspondiente al estado del botón, ponga los ID entre comillas para sean considerados como cadenas y no como constantes (BOTONU, BOTOND). En el archivo sintetizadorview.h declare un objeto miembro de CBitmapButton. class CSintetizadorView : public CFormView { public: 46 CBitmapButton Boton1; // Overrides } Por último, para cargar los recursos mapa de bits, el botón debe recibir el mensaje AutoLoad, el cual tiene dos parámetros: el ID del botón y la dirección al objeto. Esta operación se realiza desde la función miembro OnInitialUpdate. void CSintetizadorView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(false); } Boton1.AutoLoad(IDC_BOTON1, this); UpdateData(false); Repita los pasos anteriores para los demás botones. Cada vez que se pulsa un botón es generado el mensaje WM COMMAND, este mensaje es manipulado por la función OnCommand, la cual se encargará de llamar a la función fillplaybuffer y asignarle un valor dependiendo del botón pulsado. Ahora ejecute Class Wizard, seleccione la clase CSintetizadorView, el objeto CSintetizadorView y el mensaje OnCommand, oprima el botón Add Function.. y enseguida Edit Code y edite esta función de la siguiente manera, siguiendo la secuencia: BOOL CSintetizadorView::OnCommand(WPARAM wParam, LPARAM lParam) { switch (wParam) { case IDC_BOTON1: raiz = pow(cua, -9); fillplaybuffer(); break; case IDC_BOTON2: raiz = pow(cua, -8); fillplaybuffer(); break; ... ... ... case IDC_BOTON10: raiz = 1; fillplaybuffer(); 47 break; ... ... ... case IDC_BOTON13: raiz = pow(cua, 3); fillplaybuffer(); break; } return CFormView::OnCommand(wParam, lParam); } 5.4. Programando el controlador driver de sonido El parámetro wParam, contiene el elemento del recurso que ha hecho que se envı́e este mensaje, de esta manera mediante el uso de un switch, se puede identificar el botón sobre el que se ha pulsado. El valor raiz es enviado a la función fillplaybuffer, este valor determinará la nota que tocará cada botón, esto se explicará más adelante. La función fillplaybuffer es la encargada de llenar un buffer con los datos de la señal fundamental y sus armónicos, y de mandarlos de la tarjeta de sonido. Utilizando AppWizard declare la función fillplaybuffer de tipo void y edı́tela de la siguiente manera: void CSintetizadorView::fillplaybuffer() { HWAVEOUT fd; WAVEFORMATEX wf; WAVEHDR wh; wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = 1; wf.nSamplesPerSec = SAMPLE_RATE; wf.wBitsPerSample = 8; wf.nBlockAlign = 1; wf.nAvgBytesPerSec = SAMPLE_RATE; wf.cbSize = 0; waveOutOpen(&fd, WAVE_MAPPER, &wf, 0, 0, CALLBACK_NULL); for(i=0;i<MAXBUF;i++) { son[i]=(BYTE)((47+47*sin(fAngle))+(16+aV1*sin(fAngle2))+ (16+aV2*sin(fAngle3))+(16+aV3*sin(fAngle4))+ (16+aV4*sin(fAngle5))+(16+aV5*sin(fAngle6))); 48 fAngle += 2 * pi * aH1*raiz/SAMPLE_RATE; fAngle2 += 2 * pi * aH1*2*raiz/SAMPLE_RATE; fAngle3 += 2 * pi * aH1*3*raiz/SAMPLE_RATE; fAngle4 += 2 * pi * aH1*4*raiz/SAMPLE_RATE; fAngle5 += 2 * pi * aH1*5*raiz/SAMPLE_RATE; fAngle6 += 2 * pi * aH1*6*raiz/SAMPLE_RATE; if(fAngle > 2*pi) { fAngle -= 2*pi; } if(fAngle2 > 2*pi) { fAngle2 -= 2*pi; } if(fAngle3 > 2*pi) { fAngle3 -= 2*pi; } if(fAngle4 > 2*pi) { fAngle4 -= 2*pi; } if(fAngle5 > 2*pi) { fAngle5 -= 2*pi; } } } if(fAngle6 > 2*pi) { fAngle6 -= 2*pi; } wh.lpData = son; wh.dwBufferLength = MAXBUF; wh.dwFlags = 0L; wh.dwLoops = 0L; waveOutPrepareHeader(fd, &wh, sizeof(WAVEHDR)); waveOutWrite(fd, &wh, sizeof(WAVEHDR)); Sleep(150); waveOutReset(fd); waveOutUnprepareHeader(fd, &wh, sizeof(WAVEHDR)); waveOutClose(fd); Declare las variables; i como tipo entero, fAngle a fAngle6 como tipo double y son[MAXBUF] como tipo CHAR. La estructura utilizada para el llenado de buffer es 49 parecida a la función fillbuffer explicada en el capitulo 4, sólo que en esta ocasión realiza una serie de Fourier con los parámetros antes mencionados. El parámetro fAngle recibe el valor de la barra horizontal, el cual tiene por default 440 Hz, al mismo tiempo es multiplicado por un valor que corresponde al armónico en el que se encuentra y por un valor raiz que es enviado por el botón que se pulso. Defina un parámetro cua con un valor de raı́z doceava de dos, este valor es el que determina el intervalo que hay de una tecla a la siguiente, de esta manera en la función OnCommand, el parámetro cua es elevado a cierta potencia dependiendo del botón en el que se encuentre (nuestra tecla central es la nota LA4) y se iguala a raiz (Ecuacion 5.1), el cual es enviado a fAngle para determinar la nota. La frecuencia 440 Hz, se encuentra en el botón 10 y es a partir de ésta que se determinan las demás notas de la octava. raiz = pow(cua, Boton); (5.1) Defina las variables SAMPLE RATE con un valor de 11025, pi con un valor de 3.14159 y MAXBUF con un valor de 3200. Las estructuras utilizadas en esta función ya han sido explicadas en el capı́tulo 4, no olvide incluir el archivo de cabecera mmsystem.h e incluir en las opciones de link la librerı́a winmm.lib. 5.5. Resumen En este capı́tulo presentamos conceptos importantes para el diseño, tales como sistema de coordenadas, pı́xel, mapas de bits, recursos, entre otros. Al mismo tiempo desarrollamos y explicamos los pasos a seguir para la implementación del sintetizador, mostrando cada uno de los principales programas para la manipulación de audio analógico. 50 Capı́tulo 6 Pruebas y Resultados En el capı́tulo anterior explicamos como asignarle ciertos comportamientos a cada uno de los elementos utilizados en este proyecto, tales como el rango a las barras de desplazamiento, el sonido que se produce al pulsar los diferentes botones, dibujar las diferentes señales ocupadas, etc. En este capı́tulo presentamos algunos resultados de nuestro sistema Sintetizador y describiremos su operación. 6.1. Ambiente de compilación y generación de código Usando el lenguaje de programación Visual C++, realizamos un tipo de compilación llamado release, con esto conseguimos generar un archivo ejecutable Sintetizador.exe que podrá ser ejecutado en cualquier sistema operativo Windows (95 o superior). Para generar un archivo ejecutable .exe de tipo release, es necesario llevar acabo los siguientes pasos; a) Seleccione la configuración Win32 Release de la caja de herramientas Set Active Project Configuration, que se encuentra en el menú Build de la barra de herramientas, b) Al cambiar de un tipo de compilación a otra, deberá especificar en las opciones de linker la librerı́a winmm.lib, para esto presione ALT+F7, seleccione la pestaña Link, escriba la librerı́a en la caja de texto Object/library modules y presione el botón OK para hacerla valida, c) Y por último en el menú Build de la barra de herramientas, de clic en la opción Build Sintetizador.exe. Cabe men- 51 Figura 6.1: Vista principal del sintetizador. 52 cionar que con el tipo de compilación Debug, el archivo ejecutable no operará en PC’s (Personal Computer) que no cuenten con el software Visual C++ instalado. Una vez creado el archivo ejecutable éste se encontrará en la carpeta release, la cual está ubicada en la carpeta principal de nuestro proyecto. 6.2. Aspecto visual del sintetizador Al dar doble clic en el archivo Sintetizador.exe se visualizará nuestra aplicación ya terminada, ésta tendrá un aspecto similar al mostrado en la Figura 6.1. En la esquina superior izquierda de esta figura se encuentra un marco con el tı́tulo Afinador que contiene; una barra horizontal y una caja de texto. La barra horizontal tiene un valor inicial de 440 Hz, un valor máximo de 466 Hz y un valor mı́nimo de 415 Hz, como se muestra en la Figura 6.2, cuando el usuario actúe sobre la barra está modificará su valor, el cual se visualizará en la caja de texto y será enviado a la función que está realizando la sı́ntesis (fillplaybuffer). Ésta función es la encargada de llenar el buffer de audio para ser enviado a la tarjeta de sonido, lo cual significa que de acuerdo con los valores máximos y mı́nimos en la barra, las teclas pueden llegar a subir o a bajar un tono, por lo tanto, la barra nos servirá como un afinador. Cuando el usuario actúe sobre la barra podrá modificar el tono de las teclas para que éste sea de su agrado. Figura 6.2: Valores mı́nimo, central y máximo de la barra horizontal. Debajo del marco Afinador, se encuentra un marco con el tı́tulo Amplitud que contiene cinco barras verticales y cinco cajas de texto. Las barras representan la amplitud de los armónicos de la señal fundamental utilizados, los cuales se pueden visualizar en la parte inferior izquierda de la vista. En la parte inferior derecha se 53 visualiza la señal resultante de la suma de los armónicos, la cual es enviada a la tarjeta de sonido. Cuando el usuario actúa sobre alguna de las barras verticales cambiará su valor, el cual se visualizará en su respectiva caja de texto situada debajo de cada barra como se muestra en la Figura 6.3. Las barras pueden obtener un valor mı́nimo de cero y un máximo de dieciséis, esto es por razones de normalización, ya que en nuestro programa fuente, la amplitud máxima de cada armónico es de treinta y dos, este valor representa el 12.6 % del 100 % que nuestro buffer puede tocar sin distorsionar el sonido (8 bits, de 0 a 254), siendo la señal fundamental la de mayor amplitud con un 37 %. Cuando sumamos la señal fundamental con la amplitud máxima de los cinco armónicos nos da el 100 % de nuestro buffer. Figura 6.3: Barras de desplazamiento verticales, con una amplitud modificada. 6.3. Control de parámetros del sintetizador Cuando el usuario actúe sobre alguna de las barras su valor es enviado a la función que se encarga de realizar la sı́ntesis para el llenado del buffer, al mismo tiempo es enviado a una función encargada de graficar la señal fundamental, los armónicos y la resultante (la función Graficador fue mostrada en el capı́tulo 4). Por ejemplo, cuando el usuario actúa sobre la barra Arm 3 su valor es enviado a las funciones antes mencionadas y se visualiza un cambio de amplitud en la señal ubicada en el marco 54 con el titulo Tercer Armónico, que encontramos en la parte inferior izquierda de la vista principal del proyecto, al mismo tiempo visualizamos un cambio en la señal resultante ubicada en el marco con tı́tulo Resultante, que encontramos en la esquina inferior derecha de la vista de nuestro proyecto, como se muestra en la Figura 6.4. Figura 6.4: Tercer armónico con amplitud modificada. Cuando el usuario actúa sobre la barra Arm 5 el valor de éste es enviado a la función Graficador y se visualiza un cambio de amplitud en la señal ubicada en el marco con el tı́tulo Quinto Armónico, que se encuentra en la parte inferior izquierda de la vista principal del proyecto, al mismo tiempo visualizamos un cambio en la señal resultante ubicada en el marco con tı́tulo Resultante, que encontramos en la esquina inferior derecha de la vista de nuestro proyecto como se muestra en la Figura 6.5. 6.4. Controlando los armónicos El usuario puede actuar sobre varias barras modificando diferentes armónicos, cuando esto ocurra los valores de las barras serán enviados a las funciones antes mencionadas y se visualizará un cambio en los marcos situados en la parte inferior de la vista principal de nuestro proyecto como se muestra en la Figura 6.6. 55 Figura 6.5: Quinto armónico con amplitud modificada. Figura 6.6: Todos los armónicos modificados 56 La razón por la que utilizamos solamente cinco armónicos es por fines prácticos, ya que uno de los principales objetivos es demostrar que se puede lograr una sı́ntesis de audio mediante la serie de Fourier (usted puede adicionar o quitar el número de armónicos que desee, modificando el proyecto desde Visual C++). 6.5. Control del teclado En la parte superior derecha encontramos un marco con el tı́tulo Teclado como el que se muestra en la Figura 6.7. El teclado está conformado por 13 botones, que con la ayuda de un par de mapas de bits simulan las teclas de un sintetizador, ya sean en estado de reposo o presionadas como se muestran en la Figura 6.8, y su principal objetivo es que el usuario tenga una vista más amigable al interactuar con el proyecto. Figura 6.7: Vista del Teclado. El teclado cuenta con una frecuencia central de 440 Hz, que corresponde a la nota LA4 y se encuentra ubicada en la tecla número 10, es a partir de ésta que se calcula √ el valor de las demás teclas, multiplicando la frecuencia central por 12 2 para subir medio tono y se ubica en la tecla número 11 y multiplicar la frecuencia central por √ ( 12 2)−1 para bajar medio tono y se ubicará en la tecla número 9, para las demás √ teclas es necesario elevar el valor 12 2 a una potencia positiva o negativa dependiendo 57 de la tecla (para mayor información consulte el capı́tulo 4). Estos valores son enviados a la función fillplaybuffer mencionada en capı́tulos anteriores, para realizar el llenado del buffer y enviarlo a la salida de la tarjeta de sonido. Figura 6.8: a)Tecla en reposo. b)Tecla pulsada. A continuación se muestra una tabla, con los valores que deben tener las barras para asemejarse a un Oboe ó a un Órgano de Jazz, el sonido fue comparado con un sintetizador marca CASIO, modelo CT-680: Tabla 6.1: Valores de las barras de desplazamiento IN T RU M EN T O OBOE Organo de Jazz 6.6. Af inador 450 450 Arm2 Arm3 Arm4 Arm5 Arm3 12 10 0 8 8 16 0 0 14 11 Resumen En este capı́tulo presentamos la utilización de nuestro proyecto mostrando gráfica y textualmente los principales pasos a seguir para su funcionamiento básico. Cabe mencionar que en este proyecto no se utiliza MIDI (Music Interfaz Digital Instrument), se utiliza audio analógico digitalizado. 58 Capı́tulo 7 Conclusiones y Trabajos Futuros Esta tesis presentó el diseño elemental de un sintetizador de notas musicales, el cual describimos en un programa de computadora digital. Este dispositivo de software produce sonidos mediante la generación de señales periódicas y funciones matemáticas con la ayuda de elementos electrónicos programados, tales como osciladores, filtros, mezcladores de señales, etc. Fı́sicamente estos elementos son costosos y ocupan grandes espacios, lo cual puede llegar a ser molesto para el usuario. Pensando en esto último, nos dimos cuenta que un modelo por software puede igualar a un modelo por hardware y no ser estorboso, ya que lo único que se necesita para usarlo es una computadora digital (p.e. PC), que prácticamente es necesaria en la vida cotidiana de toda persona. Para iniciar con la elaboración de nuestro proyecto, primero debimos elegir un lenguaje de programación que permitiera diseñar la interfase de usuario. Este lenguaje deberı́a ser accesible para el programador a fin de que los resultados obtenidos pudieran observarse en una computadora estándar. El resultado de esta elección, como ya se ha mencionado, fue el lenguaje de programación Visual C++.NET, el cual nos ofreció además de su fácil manejo, la oportunidad de crear objetos bastante amigables para los usuarios. De esta manera, el diseño de nuestro sintetizador se ha realizado con medios comunes en el mercado. Desde un principio, las bases de nuestro proyecto estuvieron planteadas: crear 59 señales senoidales para representar una sumatoria, en otras palabras, programar una Serie de Fourier. El resultado deberı́a ser visible en la ventana principal del proyecto para ver la forma de onda que se estarı́a mandando a la tarjeta de sonido. Lo anterior fue logrado programando funciones matemáticas en Visual C++.NET, algunas de estas funciones fueron la suma, la multiplicación y el seno. Con estas funciones, algunas veces llamadas primitivas, programamos nuestra Serie de Fourier para comprobar las sı́ntesis de onda, con esto obtuvimos un número bastante grande de valores, los cuales tenı́amos que almacenar en memoria operativa (buf f er de audio) con el fin de tener un mejor control de los datos. Una vez generada la sı́ntesis, el siguiente paso fue enviar los datos almacenados en nuestro buf f er, a otro buf f er que se encuantra asociado al driver de la tarjeta de sonido (una Sound Blaster). Sin embargo, al iniciar este proceso nos dimos cuenta de la poca información que existe sobre cómo programar drivers de sonido. Encontramos varios libros y notas que hablaban acerca de cómo enviar un archivo WAVE, previamente grabado, a la tarjeta de sonido, pero lo anterior no era suficiente; fue hasta que se consultó el artı́culo de una revista que hablaba acerca de la generación de audio por medio de una onda senoidal, que pudimos avanzar en nuestro proyecto. Esto nos ayudó enormemente en nuestra investigación, sin embargo, el artı́culo está escrito en inglés, lo cual reafirmaba la poca información disponible en este paı́s al respecto. Para enviar los datos almacenados en el buffer a la tarjeta de sonido, ocupamos instrucciones de audio de bajo nivel que se encuentran en la biblioteca de funciones multimedia mmlib.lib. Algunas de las instrucciones de audio más importantes son; WavePrepareHeader() que se encarga de preparar al buffer para ser enviado a la tarjeta de sonido, y WaveOutWrite() que se encarga de sacar los datos de la tarjeta de sonido a los altavoces de la PC; estos procesos se explican más detalladamente en el capı́tulo 4 de esta tesis. Hecho lo anterior, los siguientes pasos fueron sencillos. Para la distribución de las notas del teclado utilizamos el valor matemático raı́z doceava de dos, que representa 60 el intervalo existente entre una nota y la siguiente (un semitono). El resultado de esta operación fue multiplicado por la frecuencia central utilizada (LA4 =440Hz) con el fin de encontrar la frecuencia de la siguiente nota (LA#), y ası́ sucesivamente. Cada uno de estos valores fueron asignados a un botón ubicado en la vista principal y ası́ darle el sonido de la nota correspondiente. Para cambiar el timbre de nuestro sintetizador, controlamos las formas de onda senoidales en su amplitud y frecuencia, esto se consiguió por medio de barras de desplazamiento, asignándole el valor de dichas barras a las amplitudes y frecuencias que se encuentran en la formula de la sı́ntesis de onda. De esta manera es posible no solo escuchar algún instrumento como una trompeta o un oboe, sino también ver su forma de onda al mismo tiempo. En resumen, las principales contribuciones de esta tesis son las siguientes: La realización de una Serie de Fourier con algoritmos de programación y métodos numéricos. La generación de audio analógico por medio de una suma de señales. La programación de instrucciones de audio de bajo nivel con lo cual se facilitará la construcción software de drivers de sonido. Técnicas de graficación en Visual C++.NET. Y por último, un sintetizador virtual para PC capáz de ejecutarse en sistemas windows 95 o superior. 7.1. Trabajos Futuros Continuando con los resultados de nuestra investigación, presentamos algunas sugerencias en cuanto a trabajos futuros. Pensamos que es posible implementar una serie de elementos, en cuanto a estética, funcionalidad, y aplicación cientı́fica. 61 Respecto a la estética, se puede mejorar la apariencia de las barras verticales y la barra horizontal, mediante la implementación de perillas giratorias en tercera dimensión, ası́ mismo, perfeccionar la apariencia del teclado. Además es posible mejorar la graficación de las señales mediante la implementación de color y aumento de la resolución de la gráfica. En cuanto a funcionalidad, se pueden efectuar varias acciones para el mejoramiento del proyecto. Por ejemplo, sólo se cuenta con la frecuencia fundamental y cinco de sus armónicos, que son señales senoidales. Para resolver esta limitante se puede implementar una mayor cantidad del contenido armónico a nuestro sistema, mediante la integración de formas de onda cuadrada, cosenoidal, diente de sierra, etc. Esto permite obtener una mayor variedad de instrumentos musicales, ya que cada forma de onda cuenta con diferente contenido armónico. Ası́ mismo, es posible crecer la funcionalidad de nuestro sintetizador en cuanto a la amplitud, tono y timbre, integrando generadores de ruido (blanco o rosa) y envolventes de onda. Esto permite la simulación dinámica de los instrumentos musicales, mediante el control del ataque, decaimiento, sostenimiento y la relajación tal como se ha descrito en el capı́tulo tres. Ya que en nuestro trabajo cuenta sólo con una octava en el teclado, en el futuro se pueden implementar cuatro o más octavas para obtener un rango mayor de frecuencias. Además, se puede agregar una función para que el sintetizador pueda dividir el teclado en dos partes. Es decir, si cuenta con cuatro octavas, las primeras dos tocarı́an un instrumento, por ejemplo el piano y las dos octavas restantes tocarı́an un acordeón como lo hacen los sintetizadores profesionales. Se puede perfeccionar el teclado, para que puedan ejecutarse acordes, esto es, aumentar el número de teclas que se tocan al mismo tiempo. Como ya se sabe, la principal función de un sintetizador es generar una gran variedad de sonidos, que simulen instrumentos musicales. Por ello, a este proyecto se puede agregar un selector de instrumentos, esto es, tener configurado el sistema para que con una perilla, pueda seleccionar el instrumento o los instrumentos que se deseen 62 tocar, por ejemplo un piano, un violı́n, una flauta, etc. Se tiene pensado realizar una versión comercial que pueda competir con la industria de los sintetizadores realizados por software, en cuanto al costo y a la transportabilidad. Respecto a las aplicaciones en la ciencia y en la tecnologı́a los resultados obtenidos pueden ser aprovechados en algunas áreas como: Procesamiento de Señales Digitales (DSPs), reconocimiento de patrones de imágenes, reconocimiento de patrones de sonido, e instrumentos de medición como osciloscopios, generadores de funciones, medidores de ruido, e instrumentos de ultrasonido. Por otra parte, para un músico puede ser de gran utilidad, ya que donde quiera que él se encuentre haciendo su trabajo (tocando), si cuenta con una PC podrá tener a su alcance un sintetizador de sonidos. Además, en la educación musical puede ser de gran ayuda como material didáctico, por ejemplo, aprender el orden de las notas en un teclado e iniciarse dentro de la música. Por útlimo, cabe mencionar que esta tesis se ha desarrollado conjuntamente con el Dr. Maximino Peña Guerrero y el Ing. José de Jesús Negrete, profesores de la academia de acústica de la ESIME-Zacatenco. Actualmente se encuentran desarrollando más proyectos en ciencia y tecnologı́a acústica. 63 Bibliografı́a [1] Beristáin, Sergio, AUDIO Ed. Particular, México D.F., Agosto de 1998, 201 pgs. (p: 10) [2] Ceballos, Fco. Javier, Visual C++ Aplicaciones para Win 32, Alfaomega Ra-Ma, México 2004, 717 pgs. (p: 38) [3] Ceballos, Fco. Javier, Visual C++ Programación Avanzada en Win 32, Alfaomega Ra-Ma, México 2000, 852 pgs. (p: 33) [4] Floyd, Thomas, Dispositivos Electrónicos, LIMUSA Noriega Editores, 1996, Colección Textos Politécnicos, 974 pgs. (p: 17) [5] Moog Robert A., “Voltaje-Controlled Electronic Music Modules”, R. A. Moog Co., Trumansburg, New York, Journal of the Audio Engeering Society, january, 1968, vol. 16 No. 1. pp. 200-206. (p: 36) [6] Moog Bob., “MIDI: Musical Instrument Digital Interface”, Journal of the Audio Engeering Society, may 1986, v. 34 No. 5. pp. 394-404. (p: 35) [7] Peña G. M., Çaptura de Múltiples Eventos MIDI en Tiempo de Ejecución”. Inédita. México. Tesis presentada para aspirar al grado de Doctor en Ciencias en Ingenierı́a Eléctrica. Centro de Investigación y de Estudios Avanzados del Instituto Politécnico Nacional, 2005. 160 pgs. (p: 11) [8] Petzold, Charles, ”Exploring Wave Form Audio Generating Sine Waves in Software”, PC Magazine, November 26, 1991, pp 505-510. (p: 32) [9] Petzold, Charles, Programing Windows, Microsoft Press, 1999, 1479 pgs. (p: 28) 64 Glosario CAC: Computer Aided Composer, Composición Asistida con Computadora. Colección de programas de sof tware agrupados en un medio ambiente de computadora digital que interactúa con el usuario para estudiar, desarrollar, simular e interpretar música de cualquier tipo, incluyendo toda clase de sonidos. Generador de tonos: Dispositivo electrónico digital que puede generar una gran variedad de sonidos musicales de acuerdo con las notas que recibe. Es un sintetizador de sonidos similares a los producidos por instrumentos musicales. Se conecta, a través de la interfaz MIDI, a computadoras digitales o cualquier otro controlador MIDI, los cuales envı́an notas musicales en forma de comandos para reproducir la música de acuerdo con la información que tiene un archivo MIDI, u otra forma de almacenamiento digital. KL: Kernel for a musical Language, núcleo para un lenguaje musical. Compilador de estructuras musicales desarrollado por el autor para estudiar el procesamiento electrónico de la música. La entrada es un programa fuente que tiene cadenas de texto escritas en lenguaje natural (do re mi[ fa sol sil fa]...) de las notas musicales (solfeo). La salida son gráficas, partituras, y/o el sonido de una canción escrita en el programa fuente. MIDI: Musical Instrument Digital Interface, interfaz digital para instrumentos musicales. Protocolo de comunicaciones de hardware y sof tware estándar diseñado por los fabricantes de instrumentos musicales electrónicos. Pentagrama: Grupo de cinco lı́neas horizontales para escribir sı́mbolos gráficos que tiene el lenguaje musical y que determina una melodı́a. Sintetizador: Dispositivo electrónico digital, similar a un piano, que puede generar una gran variedad de sonidos musicales. Las notas son activadas por el sistema de teclas, o también por aquellas que recibe a través de su interfaz MIDI interconstruida y conectada con computadoras digitales u otros dispositivos similares. Sistema de tiempo real: Dispositivo que controla una aplicación dedicada la cual tiene restricciones temporales bien definidas. 65 Solfeo: Lenguaje natural musical, compuesto por las sı́labas do, re, mi, f a, sol, la y si, para enseñar música cantando. Tiempo real: Momento actual de respuesta al procesamiento inmediato de datos que interactúan con procesos fı́sicos. UART: Unasynchronous Asynchronous Reciver Transmitter, transmisor y receptor sı́ncrono ası́ncrono. Dispositivo electrónico digital de comunicaciones serial que transforma datos con formato serie a paralelo para recibir o transmitir información. La velocidad de transferencia, cuando se utiliza en instrumentos musicales electrónicos, es de 32,250 Bauds lo que permite enviar y recibir, en promedio, hasta 142 notas musicales en un segundo. VLSI: Very Large Scale Integration (integración a escala muy elevada). Técnica de fabricación de circuitos integrados electrónicos en espacios bastantes reducidos. 66 Φ 67