Buenas!
Me presento a esta comunidad de la NDS con mi primera demo para esta consola :)
Hace 3 días, decidí echarle un vistazo a las herramientas de programación disponibles para esta pequeña maravilla de máquina, para ver en que estado estaban las librerias y herramientas necesarias para trabajar. Mi grata sorpresa es que he encontrado material suficientemente abundante, aunque no suficientemente desarrollado.
El caso es que no os voy a engañar: hace 3 dias no sabía nada sobre programación de DS y poco conozco esta scene a la que soy un recien llegado (tengo la DS Lite desde hace muy poco y tambien hace muy poco que tengo el Passme+ M3 SD). Pero bueno, todo es solucionable y no es la primera vez que trabajo en la scene de otras consolas...
LA DEMO
Bueno, despues de este preambulo, pasemos a explicar la demo.
A mi de la DS me atrae tanto la pantalla sensitiva como la posibilidad de usar un microfono y esa era una de las cosas en las que queria centrar esta demo. Tambien me gusta controlar la generación de sonido y dar un repaso a la parte grafica, para ir cogiendo el tranquillo a la maquina.
Así pues, esta demo, utiliza la pantalla superior para mostrar un cubo 3D, que puede ser girado usando el PAD o de una forma mas curiosa aun: SOPLANDO por el microfono :)
En la pantalla inferior, se muestra un teclado de organo y esta es la segunda parte de la demo: combinacion de la pantalla sensitiva con un manejo del audio avanzado.
Pulsando las diferentes 'teclas' podemos oir el sonido de las diferentes notas. Para darle cierto timbre a la voz, utilizo dos voces, una de ellas una octava por debajo y lo destacable es que utilizo un sistema de loop continuo de la onda que cesa al dejar de pulsar la nota o al cambiarla, teniendo control de esto desde el arm9
La parte superior de esta pantalla, muestra la onda capturada por el microfono, que por cierto, me dió algun problema implementar esto porque la libreria del microfono, tiene un error en la forma de leer los samples y fue una de las cosas que me volvió loco.
Así pues, la demo consiste en un organo en el que podemos actuar sobre las teclas y un cubo 3D que podemos girar soplando al microfono. Espero que os guste ;)
LA ODISEA DE HACERLA
Cuando uno empieza a programar para una maquina nueva, uno no conoce nada y practicamente, se tiene que buscar uno la vida en todo o casi todo y a veces, problemas que otras personas se han encontrado y solucionado mil y una vez, se repiten otras tantas veces por cada persona nueva que empieza en esto.
En mi caso, yo tenia muy claro mis prioridades: la pantalla tactil y un manejo controlado del sonido, tanto en la captura como en la emision, son mis prioridades.
El primer ejemplo de sonido que compilé usando LIBNDS, tenía un problema que me estuvo volviendo loco un buen numero de horas. Por alguna extraña razón, el sonido insistia en oirse solo por el canal izquierdo, pese a que estaba todo ajustado para que se oyese en ambos canales.
El problema venia de que en un ejecutable de NDS hay dos secciones de codigo: una para arm9 (que es la que yo compilo) y otra para arm7.
Al montar el ejecutable con la NDSTOOL (cosa que hace el compilador automaticamente), no le especifica ningun binario de codigo arm7, asi que es de suponer que mete un codigo por defecto.
Dicho codigo por defecto, debe ser muy antiguo y con alguna incompatibilidad con LIBNDS o algun error y esa es la razon de que el audio solo saliese por un canal.
Revisando algunos de los ejemplos bajados, veo que hay uno que es el ejemplo base del codigo usado por la LIBNDS en el arm7. Lo compilo y enlazo ese binario con la NDSTOOL y EUREKA! ahora si funciona correctamente el audio :)
Sin embargo, veo que el audio se trabaja desde la interrupcion de retrazado vertical y no utilizando ningun medio de sincronizacion de ambos procesadores. Por eso decido investigar esta linea ya que revisando la libreria, veo que hay algunos problemas.
La NDS tiene 16 canales de audio que en la lib se usan en PCM de la siguiente forma: aunque hay 16 structuras para programar el audio, en LIBNDS se utiliza solo la primera para transmitir el audio. Eso hace que si se intentan programar varios sonidos a la vez antes de que se produzca un VBLANK, los datos se machaquen sin que el arm7 se haya dado cuenta del cambio.
El codigo original para arm7, no liga estas estructuras directamente con los canales de audio, si no que va mirando si hay algun canal libre de audio y de ser así, introduce los datos desde la estructura.
Esta forma de trabajar hace que si tu programas un sonido, esperas al vblank y programas otro sonido, puedas tener polifonía, pero si no has esperado ese vblank, lo normal es que un sonido anule al otro. Tampoco es posible programar la repeticion continua de una onda, pararla, sustituirla por otra o grabar por microfono.
Por tanto, me vi en la reflesion de 'inventar' un sistema que sin dejar de ser compatible con lo antiguo, me permitiese hacer un uso mas avanzado del sonido.
-
IPC El IPC es la forma que tenemos de comunicar los dos procesadores, sincronizandolos. Desgraciadamente, en el emulador
'Dualis' no se soporta ese metodo de sincronizacion mediante interrupciones, pero para estas contingencias, empleo un codigo que me permite usar VBLANK de forma alternativa, aunque en la consola esto no es necesario (eso es solo para compatibilizar el codigo)
Mediante IPC se consigue que en el arm9, una vez modificados los datos oportuno, mediante una escritura en un registro, se solicite la interrupcion de tratamiento en el arm7, que en mi caso, hace que se trate el sonido de forma directa, sin tener que esperar a que se produzca una interrupcion VBLANK (59,8 veces por segundo), para ser tratados.
-
Microfono Como he mencionado arriba, el mocrofono me dió un problema debido a que los datos no son leidos correctamente en LIBNDS (tendre que ponerme en contacto con la gente que la desarrolla, para comentarselo)
Ademas, el microfono solo se podía usar desde arm7 y había que comunicarlo de alguna forma. Por compatibilidad, la opcion elegida ha sido usar el mismo sistema que para enviar un sample, solo que en vez de especificar en el formato de sonido 1 o 2 (samples de 8-16 bit), en mi caso especifico 16. El audio es leido como samples de 8 bits con signo, que son almacenados un byte despues del comienzo del buffer, ya que el primer byte se utiliza como byte de estado de la lectura del microfono.
-
Audio Para el audio yo queria una plena compatibilidad con el viejo codigo de audio empleado hasta ahora (para poder compilar por ejemplo, otros codigos que hagan uso de ese metodo) y al mismo tiempo garantizar plenos poderes sobre el.
Para ello uso un sistema multicanal en el que yo mismo especifico el canal a usar (lo cual me permite reprogramar un canal ya en uso, pero dado que es mejor llevar el control desde el arm9, no hay problema) y en el formato especifico las acciones a emprender de esta forma:
1-> reproduce audio a 8 bit por sample, una vez
2-> reproduce audio a 16 bit por sample, una vez
9-> reproduce audio a 8 bit por sample, en bucle infinito
10-> reproduce audio a 16 bit por sample, en bucle infinito
32-> para el audio
16-> graba audio (8 bits por sample, primer byte estado de grab.)
17-> para (aborta) la grabacion de microfono
Como veis, formas variadas, mientras que antes no era posible salvo las dos primeras
-
Reconocimiento del audio : Bueno, la verdad es que uso un metodo 'empirico' para detectar cuando se sopla en el microfono. No es un codigo demasiado complicado
La demo hace uso de estas capacidades y solo queda crear una libreria que pueda trabajar paralelamente a la LIBNDS de forma optimizada, documentarla, etc, para que todos podais hacer uso de estas extensiones
-
Material utilizado
- NDS Lite
- Passme+ M3 SD (con una SD de 512MB)
- LIBNDS
- Codigo de ejemplos para LIBNDS
- devkitARM