Programación MIDI en C con una API de bajo nivel PortMusic Taller de Música Electrónica Sergi Jordà, 2005 E.S.U.P., Universitat Pompeu Fabra Barcelona Índice • Programa MIDI: introducción • • Polling, interrupciones, sincronía… Relojes, eventos, callbacks y multithreads • • • • • Introducción: MIDI en Windows Introducción a PortMusic (instalación, funciones…) Relojes, callbacks y procesos Sincronía en multithreading Eventos MIDI • • Control de tiempo: tempo, ticks… Standard MIDI Files • Artículos y bibliografía • • • • Apéndice A: Ejemplos de bucles de control Apéndice B: Callbacks & punteros a funciones Apéndice C: Ciclos interactivos – Escalas temporales Apéndice D: Standard MIDI Files Un programa MIDI… • Es un buen ejemplo de programa que funciona a t.real § Recibe inputs § Los procesa § Ejecuta outputs • Además es mucho más estricto que otros tipos de programas en cuanto al control del tiempo. En qué? & porqué? § Frecuencia del ciclo § Estabilidad del ciclo Un programa MIDI… • Es un buen ejemplo de programa que funciona a t.real § Recibe inputs § Los procesa § Ejecuta outputs • Además es mucho más estricto que otros tipos de programas en cuanto al control del tiempo. En qué? & porqué? § Frecuencia del ciclo § Estabilidad del ciclo Polling, interrupciones, sincronía… Relojes, eventos, callbacks y multithreads Síncronos – asíncronos • A veces se toma “síncrono” como sinónimo de “en tiempo real”, con lo que se implica que los sistemas en tiempo real NO pueden ser asíncronos. Esto no tiene porque ser así, ya que todos ellos (síncrono, asíncrono, t.real) son conceptos un tanto relativos • En un sistema de t.real síncrono, el sistema responde “instantáneamente” a los eventos externos § “Instantaneamente” : en un tiempo notablemente inferior al del lapso entre eventos • En un sistema de t.real asíncrono, se presupone que la densidad de los eventos puede llegar a ser muy alta (o su granularidad temporal muy pequeña) por lo que el sistema tan sólo debe dar un compromiso tipo “tiempo máximo de espera” • En la mayoría de APIs MIDI (y de audio), lo que se realiza es una combinación de ambos mecanismos Polling vs. Interrupciones Existen 2 formas de implementar un sistema con entradas en t.real • Polling § Es el caso más sencillo § el sistema mira entradas externas periódicamente § Adecuado para un input de tipo continuo (analógico), pero no para uno con eventos (ya que podrían perderse) • Interrupciones § Los eventos externos provocan un servicio de interrupción, que ejecuta un programa breve (que debería terminar antes de que deban comenzar otras tareas) § En el más “breve” de los casos, este programa o proceso simplemente pone el evento en una cola de entrada § Una vez terminado este proceso el programa principal retoma el punto en el que estaba Entrada contínua vs. eventos • • • Si el input fuera mirar la posición del ratón, el valor de un sensor que nos manda valores continuos, etc…los miramos a cada ciclo y ya está… Pero si el input genera eventos? (e.g. click ratón, teclado MIDI…) Estos eventos probablemente puedan producirse en cualquier instante… En muchos sistemas y APIs (incluidas APIs MIDI) se utiliza una combinación de ambos (polling & interrupciones) 1. Las entradas MIDI ejecutan una interrupción que se limita a poner los datos en un buffer de entrada • Que estructura debe tener este buffer? pila, cola, ….? • más bien cola…. aunque… algunos tipos de datos (e.g. varios controles de volumen) se puedan saltar y coger sólo el último (si nuestro sistema es sólo capaz de procesar un control/ciclo, manejar todos los volúmenes que se han almacenado podría suponer un retardo considerable). Otros tipos de datos (e.g. notas) no deberían saltarse • De forma periódica (polling) se consulta esta estructura • En este punto, se procesa la cola hasta que esté vacía Entrada contínua vs. eventos • • • Si el input fuera mirar la posición del ratón, el valor de un sensor que nos manda valores continuos, etc…los miramos a cada ciclo y ya está… Pero si el input genera eventos? (e.g. click ratón, teclado MIDI…) Estos eventos probablemente puedan producirse en cualquier instante… En muchos sistemas y APIs (incluidas APIs MIDI) se utiliza una combinación de ambos (polling & interrupciones) 1. Las entradas MIDI ejecutan una interrupción que se limita a poner los datos en un buffer de entrada • Que estructura debe tener este buffer? pila, cola, ….? • más bien cola…. aunque… algunos tipos de datos (e.g. varios controles de volumen) se puedan saltar y coger sólo el último (si nuestro sistema es sólo capaz de procesar un control/ciclo, manejar todos los volúmenes que se han almacenado podría suponer un retardo considerable). Otros tipos de datos (e.g. notas) no deberían saltarse • De forma periódica (polling) se consulta esta estructura • En este punto, se procesa la cola hasta que esté vacía Relojes (timers) y funciones callback • Un sistema de tipo polling puede ejecutarse § en un único proceso, con un bucle principal (cfg. Apéndice A) § mediante la programación de un reloj, que llamará periódicamente a otro proceso • • Un sistema basado en interrupciones, suele asociar un proceso a un evento: evento: la entrada de un dato è proceso: llamada a función El caso del reloj es similar ya que el reloj produce periódicamente un evento de reloj Sistema con 1 solo ciclo • • En el caso más sencillo, el sistema tiene un único ciclo En este ciclo se deben § Mirar las entradas § Mapearlas y procesarlas § Generar y mostrar las salidas • A nivel de programación esto conlleva un único bucle principal que realiza estas tareas siempre en el mismo orden Se debería garantizar que los procesos de un ciclo se pueden completar en menos de lo que dura un ciclo (antes del inicio del nuevo ciclo) (τ < h) El programa debe también garantizar que no se “adelantará”. Es decir, una vez terminado el bucle, no deberá comenzar uno nuevo “hasta que toque” (más adelante veremos varios algoritmos para controlar estos tiempos) (h = cte) Muchos sintetizadores de audio por software funcionan así. A continuación se describen varios aspectos tomando un programa de este tipo como ejemplo • • • Relojes (timers) y funciones callback • Un sistema de tipo polling puede ejecutarse § en un único proceso, con un bucle principal (cfg. Apéndice A) § mediante la programación de un reloj, que llamará periódicamente a otro proceso • • • Un sistema basado en interrupciones, suele asociar un proceso a un evento: evento: la entrada de un dato è proceso: llamada a función El caso del reloj es similar ya que el reloj produce periódicamente un evento de reloj La asociación de estos eventos (e.g. entradas, relos, etc.) a una función se suele realizar mediante funciones callback Funciones Callback • Una función callback es una función que se llama desde un proceso que nosotros no controlamos (normalmente desde una API) • Esta llamada puede ser periódica (eg. llenar un frame de audio) o motivada por determinados eventos (e.g. recibir mensaje MIDI, procesar frame video) En realidad están siempre generadas por eventos (en el primer caso, un evento de RELOJ) Se suelen implementar mediante punteros a funciones (cfg. Apéndice B) • • • En una función callback, no es conveniente realizar gestión de memoria, acceso a ficheros, refresco de pantalla… y ningún tipo de acceso a los recursos del sistema que pueda suponer un retardo para el resto de los procesos Relojes • Los timers son fundamentales para que las aplicaciones realicen operaciones periódicas en varios procesos y con máxima precisión temporal En windows (por ej.) existe un Timer multimedia con una resolución de hasta 1 ms, y el standard, que tiene una resolución de ~ 40-50 ms • • Un Timer se suele poner en marcha mediante una llamada a una función a la que se suele pasar los siguientes parámetros: § § § § Periodicidad Callback function Tolerancia [opc] (Periodicidad +- Tolerancia) Puntero [opc] (para intercambio de información entre procesos) // ejemplo de PortMIDI Pt_Start(1, &process_midi, (void*)&iData); // start a timer with millisecond accuracy Multithreading • Si usamos este tipo de arquitecturas (relojes con callbacks o interrupciones en lugar de polling) tendremos al menos dos “procesos” (el principal y el llamado de vez en cuando por las interrupciones) è multithreading § NOTA: la diferencia entre threads y procesos es que los primeros comparten el mismo espacio de memoria, variables, etc… • Sin embargo, en bastantes casos, el programador no gestiona directamente estos threads, cuyo uso puede venir facilitado por las librerías que se utilicen • Ejemplos: § Salida de audio a la tarjeta: una librería (e.g. DirectX) se encarga de esto a partir de unos frames de tamaño predefinido (y “rellenados” por nuestro programa) § Entrada de datos MIDI o serie: las librerías suele invocar un thread que coloca los datos en una cola § Procesado de imagen a t.real: las librerías suele llamar a una función a la que le pasan el frame (imagen) recién capturado. En estos casos, nuestro programa NO controla el bucle principal… § Si utilizamos alguna librería de audio de más alto nivel que DirectX (e.g. CLAM, PortAudio…) la librería puede comportarse de forma similar al caso de vídeo. En lugar de responsabilizarnos del bucle principal, debemos escribir la función que se ejecuta periódicamente y que se encarga de “rellenar” un frame de audio (calcular todas sus muestras). La llamada a esta función (callback) queda como responsabilidad del scheduler de la librería La librería PortMusic Cada dispositivo-puerto MIDI (hardware o virtual) tiene un driver asociado MIDI en Windows (drivers virtuales: e.g. MidiYoke) Entre la aplicación y el driver existe una capa intermedia (winmm.dll) con centenares de funciones para •Audio (Wave), MIDI, Timers, Video, Joystick En cualquiera de estos casos, deberemos incluir mmsystem.h y linkar con winmm.lib Winmm • En el caso de MIDI, las funciones básicas nos permiten § Preguntar por puertos disponibles (I & O) y sus propiedades § Abrirlos / cerrarlos § Recibir mensajes de los puertos de entrada § Mandar mensajes a los puertos de salida § Además también habrá que utilizar las de relojes… • Winmm es suficiente para aplicaciones sencillas (sólo MIDI OUT) (cfg. Anaya cap. 17), pero demasiado laborioso para aplicaciones más complejas... Por ello es recomendable utilizar alguna API adicional Uso de la API PortMusic (en C) • • • • • • • MIDI + Audio (con PortAudio) Multiplataforma (Win MME, Win DX, Win Asio, Linux ALSA, Mac OS) Encapsula timers y colas de entrada Facilita gestión de colas adicionales Todo el código es abierto Bajo nivel, no añade latencia En el caso de Windows, se puede crear aplicaciones MFC, de consola, o con cualquier otro GUI Toolkit. La API sigue llamando a winmm.dll por lo que habrá que seguir linkando con winmm.lib (además de las propias de PortMusic) Instalación • • • Download (sólo 85Kb) y la documentación (sólo un .h, que contiene una descripción de cada una de las funciones) Hay que compilar los proyectos para obtener las librerías (portmidi.lib, porttime.lib y pm_dll.dll) Se incluyen los proyectos que generan estas librerías, junto con ejemplos sencillos § Entrada y salida § Envío sistema exclusivo § Aplición multithreaded § … Funciones PortMusic • • • • Listar y abrir puertos MIDI (IN & OUT) Recibir mensajes del IN y enviar mensajes al OUT Crear timers con callbacks para procesar las entradas Gestionar colas de mensajes para comunicar callbacks y otros procesos Estructuras de datos PortMusic • • • Mensaje MIDI 3 bytes Win usa un ULONG con el status en el LSB: MSBà 00 data2 data1 status ß LSB #define Pm_Message(status, ch, data1, data2) ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status | ch) & 0xFF)) • • Evento MIDI: mensaje + timestamp El timestamp no se mide en ms sino en ticks (ULONG) typedef long PmMessage; typedef struct { PmMessage message; PmTimestamp timestamp; } PmEvent; Entradas y salidas Entrada y salida (varias opciones) 1. 2. El puerto de entrada ejecuta un thread independiente que se activa (otra callback) cuando recibe mensajes El puerto de entrada deja mensajes en una cola. La callback de salida mira si hay mensajes en la cola (poll) y los procesa (aún así tenemos como mínimo 2 threads de que preocuparnos: principal + timer-callback) Esta función podría estar mirando en un array (o lista o array, etc.) de eventos (con timestamp) para ver si debe mandar algo a la salida (los ticks los debe controlar la función) • Esta función no debería ejecutar ninguna llamada tipo leer/escribir en fichero, consola… se podría retrasar Comunicación entre threads Caso A) Imaginemos que al definir la callback indicamos una variable de intercambio de 32 bits int iData; Pt_Start(1,&process_midi,(void*)&iData); //1 ms, callback, variable de intercambio Thread principal y callback comparten esta información. OK. Caso B) struct Data data[10]; StartTimer(1,&process_midi,(void*)data); //1 ms, callback, zona memoria de intercambio Ahora pueden surgir problemas. Porqué? Cual es la diferencia? Sincronía en Multithreading • Por definición, si dos threads son independientes es imposible garantizar la sincronía entre ellos, con una precisión “máxima” • Esto es generalizable al uso de cualquier dato compartido por 2 o más threads § Orden de actualización? § Problema más grave: que el thread A que escribe los datos, se interrumpa durante la escritura para dar paso al thread B que los leerá (parcialmente actualizados) è 2 procesos leyendo y escribiendo “simultáneamente” de las mismas posiciones de memoria • Soluciones: § Semáforos: mecanismos de bloqueo de acceso § Más simple: intercambio de datos entre threads mediante colas de mensajes • Sólo uno de los threads debe tener acceso de escritura • Si 2 threads deben intercambiar datos mutuamente (ambos con posibilidad I/O) è 2 colas • PortMusic implementa estas colas de comunicación (ej. midithread.c) Control de tiempos, tempo, ficheros… Tempo y ticks • • • Tempo = negras/minuto Resolución del secuenciador = ticks/negra Duración de un tick = ms/tick • Cómo calcular la duración de un tick en función del tempo y la resolución? 60.000 [ms] 1 [min] ----------------- x ---------------------------------1 [min] Tempo*Resolución [tick] Problemas? Tempo y ticks • • • Tempo = negras/minuto Resolución del secuenciador = ticks/negra Duración de un tick = ms/tick • Cómo calcular la duración de un tick en función del tempo y la resolución? 60.000 [ms] 1 [min] ----------------- x ---------------------------------1 [min] Tempo*Resolución [tick] Problemas? En la práctica, no todos los tempos son posibles, ya que la duración de 1 tick es int Soluciones: èCuantizar los tempos (si el usuario introduce un tempo imposible, se le avisa del redondeo – poco prof!) èAcumular errores y corregir (e.g. si la duración teórica de 1 tick es 1,5 ms, cada 2 ticks de 1 ms se añade 1 tick fantasma que no se cuenta - ~años bisiestos) Además, El timestamp puede ser absoluto o relativo (en SMF es relativo, en PortMusic es abierto) Si es relativo, al insertar un evento hay que corregir el TimeStamp del siguiente Standard MIDI Files http://www.sfu.ca/sca/Manuals/247/midi/fileformat.html http://www.sonicspot.com/guide/midifiles.html Un SMF se almacena como varias pistas, cada una de ellas con TimeStamps relativos (a los eventos de esta pista) Para reproducir el fichero 1. Se convierte cada pista a t absolutos 2. Se combinan todas las pistas en una sola en memoria 3. Opcionalmente (si nuestro reloj funciona con relativos), se vuelven a “relativizar” Si no trabajamos con SMF, y lo hacemos con t absolutos, no es necesario todo esto: • • • • Podemos tener un array 2D (un array de secuencias donde cada secuencia es un array de eventos) Y un array de índices (cada índice indica el próximo evento de la secuencia) A cada tick, miramos para cada secuencia si el timestamp del próximo evento coincide con el tick actual. Si sí, lo mandamos a la salida e incrementamos el índice. Si además de un secuenciador, quisiéramos un editor, los arrays no son suficientes (hay que insertar/borrar…). Habría que trabajar con listas enlazadas. Varios artículos sobre diseño de lenguajes y sistemas para interactividad en tiempo real (especialmente en audio) § Dannenberg, ``Software Design for Interactive Multimedia Performance,'' Interface - Journal of New Music Research, 22(3) (August 1993), pp. 213-228. § Brandt and Dannenberg, ``Low-Latency Music Software Using OffThe-Shelf Operating Systems,'' in Proceedings of the International Computer Music Conference, San Francisco: International Computer Music Association, (1998), pp.137-141. § Brandt and Dannenberg, ``Time in Distributed Real-Time Systems,'' in Proceedings of the 1999 International Computer Music Conference, San Francisco: International Computer Music Association, (1999), pp. 523-526. § Bencina and Burk, “PortAudio – an Open Source Cross Platform Audio API”, in Proceedings of the 2001 International Computer Music Conference, San Francisco: International Computer Music Association, (2001). § è What is latency and how to tune it? Apéndice A Ejemplos de bucles de control • NB: Se incluyen a “título informativo” ya que la mayoría de APIs (incl. PortMusic) ya se encargan de la gestión de estos bucles Suposiciones: • Queremos hacer algo periódicamente, cada h • El sistema es multithreated: que un proceso espere un rato determinado, no significa que el sistema se quede sin hacer nada Ejemplos de bucles control • Cuales son los problemas de estos ejemplos? § sleep(h) indica que el proceso espera un tiempo relativo h (podría ser wait, delay, etc.) § sleepUntil(t) indica que el proceso espera hasta el instante t while (true) do { executeController(); sleep(h); } while (true) { start = getCurrentTime(); executeController(); end = getCurrentTime(); sleep(h - (end - start)); } while (true) { start = getCurrentTime(); executeController(); nexttime = start + h; sleepUntil(nexttime); } No se tiene en cuenta el tiempo de ejecución del proceso Podría ser que la tarea se haya interrumpido entre las líneas 4 y 5 Tampoco se tiene en cuenta el tiempo transcurrido entre las líneas 5 y 2 Ejemplos de bucles control • Cuales son los problemas de estos ejemplos? § sleep(h) indica que el proceso espera un tiempo relativo h (podría ser wait, delay, etc.) § sleepUntil(t) indica que el proceso espera hasta el instante t while (true) do { executeController(); sleep(h); } while (true) { start = getCurrentTime(); executeController(); end = getCurrentTime(); sleep(h - (end - start)); } while (true) { start = getCurrentTime(); executeController(); nexttime = start + h; sleepUntil(nexttime); } No se tiene en cuenta el tiempo de ejecución del proceso Podría ser que la tarea se haya interrumpido entre las líneas 4 y 5 Tampoco se tiene en cuenta el tiempo transcurrido entre las líneas 5 y 2 Ejemplos de bucles control • Cuales son los problemas de estos ejemplos? § sleep(h) indica que el proceso espera un tiempo relativo h (podría ser wait, delay, etc.) § sleepUntil(t) indica que el proceso espera hasta el instante t while (true) do { executeController(); sleep(h); } while (true) { start = getCurrentTime(); executeController(); end = getCurrentTime(); sleep(h - (end - start)); } while (true) { start = getCurrentTime(); executeController(); nexttime = start + h; sleepUntil(nexttime); } No se tiene en cuenta el tiempo de ejecución del proceso Pudiera ser que la tarea se hubiera interrumpido entre las líneas 4 y 5 Tampoco se tiene en cuenta el tiempo transcurrido entre las líneas 5 y 2 Ejemplos de bucles control • Cuales son los problemas de estos ejemplos? § sleep(h) indica que el proceso espera un tiempo relativo h (podría ser wait, delay, etc.) § sleepUntil(t) indica que el proceso espera hasta el instante t while (true) do { executeController(); sleep(h); } while (true) { start = getCurrentTime(); executeController(); end = getCurrentTime(); sleep(h - (end - start)); } while (true) { start = getCurrentTime(); executeController(); nexttime = start + h; sleepUntil(nexttime); } No se tiene en cuenta el tiempo de ejecución del proceso Pudiera ser que la tarea se hubiera interrumpido entre las líneas 4 y 5 Tampoco se tiene en cuenta el tiempo transcurrido entre las líneas 5 y 2 Ejemplos de bucles control (y 2) nexttime = getCurrentTime(); while (true) { executeController(); nexttime = nexttime + h; sleepUntil(nexttime); } • Esto ya es correcto • Que sucede cuando un ciclo dura más de la cuenta? è Que el siguiente dura menos Ejemplos de bucles control (y 2) nexttime = getCurrentTime(); while (true) { executeController(); nexttime = nexttime + h; sleepUntil(nexttime); } • Esto ya es correcto • Que sucede cuando un ciclo dura más de la cuenta? è Que el siguiente dura menos (se mantiene el promedio) Esto puede ser lo que busquemos o puede que no… Por ello, se deja al estudiante, la modificación de este fragmento, para el caso en que se deseara que el ciclo siguiente a un ciclo demasiado largo, siguiera teniendo la duración correcta (para ello, tal vez haya que descomponer executeController() en varias fases [input, output…] ) Apéndice B Punteros a funciones • Las llamadas de tipo callback se implementan mediante punteros a funciones Punteros a funciones (1) • Los punteros a funciones son punteros al inicio de la función en memoria, a la dirección inicial dentro del código donde comienza la función. • • • Se utilizan para ofrecer algoritmos alternativos dentro de un algoritmo mayor… Para personalizar fragmentos de código dentro de procesos predefinidos… Permiten crear arrays de funciones de forma que cada elemento del array toma la dirección de una función … • Para pasar una función (f2) como parámetro (de una función f1) se escribe: f1(f2) Esto es así, porqué al igual que el nombre de un array (sin [ ]) es igual a la dirección de su primer elemento, el nombre de una función (sin ( ) ) equivale a la dirección de inicio de esta función en memoria • En el prototipo de la función f1 deberemos indicar también el prototipo de la función f2. Por ejemplo si f2 es: int f2 (char *), y f1 recibe f2 como argumento, entonces la declaración de f1 será: f1(int(*f2)(char *)) Para llamar a f2, desde el código de f1, escribiremos: (*f2)(…) f1(int(*f2)(char *)) { char *p; int a; .... a=(*f2)(p); ... } En el caso de funciones callback, f1 suele estar escrito. Lo que debemos hacer es “rellenar” el código de f2 • • Punteros a funciones (y 2) • • Los punteros a funciones se utilizan mucho par ordenaciones. En las ordenaciones se realizan dos acciones básicas: la de comparación y la de cambio de lugar. La comparación no es algo trivial. No es válido el símbolo < para comparar cadenas, o muchos otros tipos de datos. A una función de ordenación le podremos determinar cómo se compara para que sea genérica. El prototipo de una función de este estilo podría ser: int ordenar (void *array_a_ordenar, unsigned int n_elem, unsigned int tam_elem, int (*pfcomparacion)(const void *, const void *)) § El const se utiliza para evitar que la función de comparación pueda modificar los elementos a comparar § El puntero a elementos a ordenar es de tipo void para poder ordenar cualquier cosa § Por esta misma razón, es necesario indicar el tamaño de cada elemento • En ANSI C existe la función qsort, que utiliza el algoritmo quick sort. Lo único que deberemos escribir para que funcione es la función que compara. • Otra aplicación de los punteros a funciones es la de crear menús u opciones diferentes: int f1(void); int f2(void); int f3(void); inf (*pf[3])( ); // esto es un array de punteros a cada una de estas tres funciones Para llamar a una de estas funciones podríamos hacer: while ((i=opcion( ) ) > 0 && i < 3) (*pf[i] )( ); Apéndice C Ciclos interactivos – Escalas temporales Antes hemos hablado de ciclos que deben ser estables ¿pero … que frecuencia deben tener? ¿cuanto deben valer este tiempo justo? Ciclos Interactivos – Escalas temporales Imagen • • A partir de ~10 Hz percibimos un continuo de movimiento § Cine ? § TV ? § Generada por ordenador ? Una cosa es la continuidad de movimiento (evitar saltos) y otra es la continuidad de brillo (evitar flickering), que mejora conforme aumenta la frecuencia § Por ello, estos sistemas muestran cada imagen 2 veces (cine=48 Hz, PAL=50 Hz, NTSC=60 Hz) § Como se ve entonces una película en TV? • En Europa (PAL) + rápido (en un factor 24/25 = 0,96). Una película de 90 minutos dura 86,4 en TV • En USA (NTSC) cada par de frames se repite x2 y x3 resp (48+72=60+60) Ciclos Interactivos – Escalas temporales Imagen • • A partir de ~10 Hz percibimos un continuo de movimiento § Cine : inicios: 12-16 fps – actual: 24 fps – dibuj.anim.: 12-30 fps § TV : PAL: 25 fps – NTSC: 30 fps § Generada por ordenador : ~12-30 fps (flexible) Una cosa es la continuidad de movimiento (evitar saltos) y otra es la continuidad de brillo (evitar flickering), que mejora conforme aumenta la frecuencia § Por ello, estos sistemas muestran cada imagen 2 veces (cine=48 Hz, PAL=50 Hz, NTSC=60 Hz) § Como se ve entonces una película en TV? • En Europa (PAL) + rápido (en un factor 24/25 = 0,96). Una película de 90 minutos dura 86,4 en TV • En USA (NTSC) cada par de frames se repite x2 y x3 resp (48+72=60+60) Ciclos Interactivos – Escalas temporales Sonido • Sonido: la freq. de muestreo está relacionada con la máxima freq. audible (T.Nyquist dice que debe ser como mínimo el doble) § Comprensión “perfecta” voz hablada : a partir de ~3 ó 4.000 Hz § Calidad CD : 44.100 Hz § Sistemas grabación profesionales : 96.000 Hz • Significa esto que un sistema interactivo sonoro debe funcionar varios miles de veces + rápido que un sistema interactivo visual? No se debe confundir el ciclo o la frecuencia de reproducción de medios, con el ciclo o la frecuencia de interacción Ciclos Interactivos – Escalas temporales Sonido • Sonido: la freq. de muestreo está relacionada con la máxima freq. audible (T.Nyquist dice que debe ser como mínimo el doble) § Comprensión “perfecta” voz hablada : a partir de ~3 ó 4.000 Hz § Calidad CD : 44.100 Hz § Sistemas grabación profesionales : 96.000 Hz • Significa esto que un sistema interactivo sonoro debe funcionar varios miles de veces + rápido que un sistema interactivo visual? No se debe confundir el ciclo o la frecuencia de reproducción de medios, con el ciclo o la frecuencia de interacción Duración de un ciclo? • Necesidades de la interacción (depende del tipo de aplicación, de centésimas a centenares de Hz) Limitaciones velocidad hard+soft (todos los procesos de un ciclo deberían completarse antes del inicio del nuevo ciclo) • • Algunos ejemplos § § Windows GUI (timer...) Termostato aire acondicionado vs. Termostato reactor nuclear • • § § § • • Sistemas blandos vs. duros (donde pasar del ciclo puede ser catastrófico) Para asegurar la estabilidad, de acuerdo con el T.Nyquist, en principio la duración de un ciclo debería ser como mínimo, igual a la mitad del tiempo de cambio de cualquier parámetro externo Aplicación interactiva procesado de vídeo t.real Reconocimiento de gestos Teclado + Secuenciador MIDI La frecuencia del ciclo de entrada no siempre tiene que coincidir con la del de salida (e.g. reconocimiento de gestos) Excepto casos como el teclado MIDI, el ciclo de entrada en HCI suele estar entre 20-100 Hz (10-50 ms) Duración de un ciclo? • Necesidades de la interacción (depende del tipo de aplicación, de centésimas a centenares de Hz) Limitaciones velocidad hard+soft (todos los procesos de un ciclo deberían completarse antes del inicio del nuevo ciclo) • • Algunos ejemplos § § Windows GUI (timer...) ~20 Hz Termostato aire acondicionado vs. Termostato reactor nuclear • • § § § • • Sistemas blandos vs. duros (donde pasar del ciclo puede ser catastrófico) Para asegurar la estabilidad, de acuerdo con el T.Nyquist, en principio la duración de un ciclo debería ser como mínimo, igual a la mitad del tiempo de cambio de cualquier parámetro externo Aplicación interactiva procesado de vídeo t.real: al frame rate, a no ser que è Reconocimiento de gestos: frecuencia min. doble de la del gesto Teclado + Secuenciador MIDI: en algunos programas hasta 1000 Hz! La frecuencia del ciclo de entrada no siempre tiene que coincidir con la del de salida (e.g. reconocimiento de gestos) Excepto casos como el teclado MIDI, el ciclo de entrada en HCI suele estar entre 20-100 Hz (10-50 ms) Escalas de tiempos The Dictionary of Computer Science (Van Nostrand Reinhold, 1993) defines a simple table of average response times, and processing methods and models: Computer Processing Modes and Times § § § § § § Card Oriented Batch Keyboard Oriented Batch Interactive Computing Online Inquiry and Transactions Message Switching Data Acquisition and Control 100-10000s 1-100s 1-10s 1-10s 0.1-10s 0.01-10s Which of these are real-time? è (extraído de Real-Time Computing for Human Computer Interfacing, Perry Cook)