Programando en C para Atari ST / STE

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 26 Jun 2019 20:20

Último mensaje de la página anterior:

explorer escribió:Si fuesen solo dos voces, valdría con hacer un rorx.b, pero al ser tres voces... la cosa se complica mucho.

¿Por qué ha de ser tres voces, y no dos, o cuatro?

Por ejemplo, si miras en mi código, a partir de la etiqueta AMIGA, verás que hago la media aritmética para los dos primeros canales del tracker para ponerlos en el canal derecho del DMA (más bien escribo dos bytes, pero no recuerdo el porqué), y luego lo mismo para los otros dos canales para el canal izquierdo. Y la media aritmética es un rorx.b, en los dos casos.

P.D.: me estoy dando cuenta de lo horrible que es mi código. Pero era la forma de programar de los años 90, cuando eras joven e inexperto: tirar líneas de ensamblador, con muy pocos comentarios, sin sangrados ni macros que facilitaran la compresión de lo que se quiere hacer... Horrible. Hoy lo haría de otra manera más eficiente y clara, por supuesto.


hmm... usted sabe mucho de las instrucciones del 68000, eso es muy bueno para lo que nos traemos entre manos :)

el código que mezcla ahora es muy simple, pero sé que es ineficiente, porque debe estar escribiendo en memoria el valor de las variables según cambian su valor... mientras que habría que hacerlo usando un registro de la CPU y guardar el valor sólo cuando se ha terminado de mezclar... es por este tipo de cosas que quiero escribir esa parte en ensamblador. Ahora mismo es un triste "while":

Código: Seleccionar todo

valor = "posicion del stream DMA que toque";
valor2 = valor + (unsigned char)250;

while(valor < valor2)
{
   dma_stream[valor] = pcm_sample1[position_pcm1] + pcm_sample2[position_pcm2] + pcm_sample3[position_pcm3];
   position_pcm1++;//Esto hay que hacerlo usando registros d0-d7
   position_pcm2++;//y las direcciones de los streams con a0-a7 y post incremento    (a0)+
   position_pcm3++;
   valor++;
}



Al bucle quiero hacerle un unroll, para que en lugar de repetirse 250 veces, se repita 10 veces o así, para reducir el número de comparaciones del "while" e instrucciones de salto al mismo,

Lo dejé en 3 voces para no seguir añadiendo sumas al bucle... pero cuéntame bien el uso de rorx.b y le metemos 4 voces en un momento,
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 27 Jun 2019 09:44

Por lo que entiendo, puede ser útil si las muestras de sonido que utilizas no las has amplificado (con un factor de db negativo, -4db a -8 db parace ir muy bien para usar los samples en el STE) previamente para evitar que, alguna vez, al sumar se superen los umbrales por encima y por debajo.

De todas formas, por lo que he "cacharreado", magnitudes promedias de 50 o 60 en un sonido dan lugar a que se oigan bastante altos. Recordemos que el PCM en el STE es de 8 bits, siendo la magnitud máxima 127; estar cerca del umbral máximo da lugar a un efecto muy saturado.

Debido a esto, entiendo que hacer la media no sería especialmente útil si se ha tenido cuidadín al trabajar las muestras de sonido,

Lo quer estaría muy bien, sería una forma de sumar números con signo, que fuese más eficiente que la instrucción de sumar del 68000; leía algo sobre operaciones lógicas XOR y luego tratar el acarreo, pero no sé si será más rápido que la instrucción de sumar (desconozco cuantos ciclos son necesarios para sumar y cuantos se necesitan para el asunto con XOR y acarreo).
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

Avatar de Usuario
explorer
Mensajes: 321
Registrado: 10 Ene 2016 18:43
Ubicación: Valladolid, España
Agradecido : 7 veces
Agradecimiento recibido: 291 veces
Contactar:

Re: Programando en C para Atari ST / STE

Mensajepor explorer » 27 Jun 2019 13:55

Las muestras se toman del archivo MOD tal cual llegan porque se supone que el autor ya ha normalizado su volumen. Son valores absolutos (números enteros positivos), pero el DMA exige valores con signo.

Para ello, en la rutina AMIGA, hago el proceso de composición del búfer haciendo la media aritmética sobre los datos, pero al final de la misma (líneas 1979 a 1983) hago un proceso de inversión de bits altos de todos los bytes, pasándoles entonces a valores con signo (los valores menores de 128 pasan a ser negativos, los mayores de 127, positivos).

Para el tema del volumen o amplificación final, lo dejaba todo en manos del interfaz Microwire, donde puedes controlar el volumen general, el volumen por cada canal, y la ganancia o atenuación de agudos y graves (página 5.21 del Atari Compendium).

No entiendo a qué te refieres con lo de que la media no es útil. Es una solución para "meter" dos muestras en un canal (o cuatro muestras en dos canales). Todos los tracker lo hacen así. Si no lo haces así, ¿qué alternativa tienes? ¿ponderar más un canal que otro usando tablas o con otro cálculo matemático?

Para dividir números con signo tienes la instrucción DIVS.

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 28 Jun 2019 10:00

explorer escribió:
No entiendo a qué te refieres con lo de que la media no es útil.

Para sumar números con signo tienes la instrucción DIVS.


Ahora lo vas a entender; ten presente que el uso que va a tener el PCM del STE en las Atari Game Tools está intencionado para reproducir efectos de sonido, los FX de toda la vida.

Se van a reproducir en mono, no en estéreo, y están ya guardados como datos de 8 bits con signo. Por eso la media no se la ve interesante en este caso. El LM1992 está configurado de manera normal, que su efecto sea neutro, para que se mantenga la fidelidad de los FX a reproducir.

Para la música se utilizará el Yamaha de toda la vida,

voy a mirar los del DIVS... me suena a Signed Divide ¿no hay un ADDS, o detecta el signo solito viendo el CCR o algo así?
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

Avatar de Usuario
explorer
Mensajes: 321
Registrado: 10 Ene 2016 18:43
Ubicación: Valladolid, España
Agradecido : 7 veces
Agradecimiento recibido: 291 veces
Contactar:

Re: Programando en C para Atari ST / STE

Mensajepor explorer » 28 Jun 2019 20:40

Entonces, es obvio que si el número de canales de sonido que quieres reproducir es menor que el número de canales físicos, no necesitas empaquetar dos en uno. La conversación empezó porque comentabas que querías meter tres canales.

Y no, no hay un ADDS. La adición siempre es binaria. Queda a cargo del programador tomar las acciones oportunas (esto me ha quedado demasiado formal, lo siento).

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 04 Jul 2019 14:41

Hoy he podido sacar algo de tiempo para probar a hacer un "unroll" del bucle que realiza la mezcla de audio, manteniéndome aún en lenguaje C.

El resultado ha sido sorprendente:



    Con un unroll de 8 el código del mezclador se ejecuta 2,96 veces más rápido.

    Con un unroll de 25 el código se ejecuta 3,45 veces más rápido.

    Con un unroll de 50 el código se ejecuta 3,77 veces más rápido.

    Con un unroll completo el código se ejecuta más lento -shock


Por supuesto, me he quedado con la versión que tiene un unroll de 50, ahora el bucle se ejecuta sólo 5 veces; también he utilizado
las variables de esta forma: pcm_sample1[position + offset] + ... ; en lugar de ir actualizando los valores de las variables.

Me ha sorprendido gratamente la increíble mejora en la velocidad de ejecución; el tiempo lo mido con una instrucción en ensamblador que cambia el color del fondo al entrar a la función (a modo de marcador) y otro marcador que vuelve a dejar el color como estaba.

También me ha llamado la atención, que eliminar el bucle, haya dado peores resultados... ¿tiene el 68000 del Atari ST una caché de instrucciones donde guarda el código del bucle o alguna capacidad de este estilo? Porque de otra manera no me salen las cuentas, pero los resultados ahí están.



explorer escribió:Entonces, es obvio que si el número de canales de sonido que quieres reproducir es menor que el número de canales físicos, no necesitas empaquetar dos en uno. La conversación empezó porque comentabas que querías meter tres canales.

Y no, no hay un ADDS. La adición siempre es binaria. Queda a cargo del programador tomar las acciones oportunas (esto me ha quedado demasiado formal, lo siento).


Parece que contemplamos escenarios distintos, en mi caso considero que tengo una única voz de salida, que es mono; y tengo unas cuantas voces en forma de datos que tengo que juntar en una sola; así que hago una suma de ondas y una vez hecho, a atacar la voz de salida.
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

Avatar de Usuario
explorer
Mensajes: 321
Registrado: 10 Ene 2016 18:43
Ubicación: Valladolid, España
Agradecido : 7 veces
Agradecimiento recibido: 291 veces
Contactar:

Re: Programando en C para Atari ST / STE

Mensajepor explorer » 04 Jul 2019 22:51

masteries escribió:también he utilizado las variables de esta forma: pcm_sample1[position + offset] + ... ; en lugar de ir actualizando los valores de las variables.
Cuidado con esto: hasta que no veas el código generado, no sabremos si ha optimizado esa suma de "position" + "offset". Lo ideal es que tomes un puntero al elemento [0] y luego ir incrementando el puntero. La notación es rara para el uso diario de un programador de C/C++, pero era muy normal hacerlo hace décadas.

masteries escribió:Me ha sorprendido gratamente la increíble mejora en la velocidad de ejecución; el tiempo lo mido con una instrucción en ensamblador que cambia el color del fondo al entrar a la función (a modo de marcador) y otro marcador que vuelve a dejar el color como estaba.
Es normal: al desenrollar el bucle lo que hacemos es ejecutar menos instrucciones "burocráticas" de control de bucle (incrementar el contador, comprobar si hemos llegado al final del bucle, salto al inicio del bucle). Al final, todos los ciclos de reloj cuentan.

masteries escribió:También me ha llamado la atención, que eliminar el bucle, haya dado peores resultados...
Lo dicho antes: es posible que al desenrollarlo el compilador no haga alguna optimización, y eso se traduzca en más instrucciones y más ciclos.

Si vas a mi código, solo hay un momento en que se desenrolla un bucle. En la línea 1979:

* inversión de signo rápida
move.l #$80808080,d0
inversion:
REPT (FRAMES*LFRAME_3*2/4)
eor.l d0,(a4)+
ENDR

Esto se hace después de componer la música en el búfer. Como necesito pasarlo a bytes con signo (de - 128 a + 127), aplico un or-exclusivo a 4 bytes, solo en el bit más alto. Esto lo debo hacer para todo el búfer. FRAMES = 2, LFRAME_3 = 1002 (dos cuadros multiplicado por el número de muestras que se reproducen a 50 066 hz. Multiplicado por 2 por ser dos canales en estéreo, y dividido por 4 porque la operación or-exclusivo la aplicamos a palabras largas (4 bytes a la vez). Eso da... 1002 instrucciones "eor.l" seguidas. Esto es mucho más rápido que un solo bucle de dos líneas (eor.l y luego un dbra).

masteries escribió:
explorer escribió:Entonces, es obvio que si el número de canales de sonido que quieres reproducir es menor que el número de canales físicos, no necesitas empaquetar dos en uno. La conversación empezó porque comentabas que querías meter tres canales.

Parece que contemplamos escenarios distintos, en mi caso considero que tengo una única voz de salida, que es mono; y tengo unas cuantas voces en forma de datos que tengo que juntar en una sola; así que hago una suma de ondas y una vez hecho, a atacar la voz de salida.

Siempre que la suma esa esté dentro del rango del canal de reproducción (8 bits con signo), perfecto.

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 05 Jul 2019 10:58

Gracias a Explorer, se acaba de añadir una nueva optimización; siguiendo los buenos consejos de Explorer, nos aseguramos de que el compilador haga lo que realmente queremos (los tiempos del bueno de Borland, ¿dónde están?, ese compilador si que se daba cuenta de estas cosas él solito).

Bueno, pues con la historia de tomar punteros, ¡el código se ejecuta ahora 4.66 veces más rápido! -drinks


Código: Seleccionar todo

 
    pcm_mix = (unsigned char)0;//pcm_mix is a variable turned into true at timer A IRQ function
   
    aux = dma_position * (unsigned char)250;//SAMPLING_PER_FRAME
   
    aux2 = aux + (unsigned char)250;//SAMPLING_PER_FRAME
       
        sdma = &dma_frame[aux];//Tomar punteros, buen consejo de Explorer
   s0 = &sample0[pcm_sample0_position];
   s1 = &sample1[pcm_sample1_position];
   s2 = &sample2[pcm_sample2_position];
   
        //Mixing, con unroll de 50
   while(aux < aux2)
   {
             *sdma = *(s0) + *(s1) + *(s2);
      *(sdma +1) = *(s0 + 1) + *(s1 + 1) + *(s2 + 2);
           ...
                *(sdma + 49) = *(s0 + 49) + *(s1 + 49) + *(s2 + 49);
      
      aux += (unsigned char)50;
      
      pcm_sample0_position += (unsigned char)50;
      pcm_sample1_position += (unsigned char)50;
      pcm_sample2_position += (unsigned char)50;
      
          //Update pointers positions
      sdma = &dma_frame[aux];
           s0 = &sample0[pcm_sample0_position];
           s1 = &sample1[pcm_sample1_position];
           s2 = &sample2[pcm_sample2_position];
      
   }//End of while
     



Sinceramente, considero que ya no podrá optimizarse más;
he probado, por deformación de MISRA C, a indicarle al compilador el tipo de datos que deseo para las constantes:

Código: Seleccionar todo

*(sdma + (unsigned char)1) = *(s0 + (unsigned char)1) + *(s1 + (unsigned char)1) + *(s2 + (unsigned char)1);


Pero con el compilador que utiliza por defecto las Atari Game Tools (el de Vincent Riviere) se ve que ya detecta el tipo de dato más adecuado de las constantes; de todas formas, por increíble que os parezca, hay compiladores que toman como tipo de dato predeterminado el int, si no especificas el "casting"; es común que suceda esto:

Código: Seleccionar todo

unsigned short a = 20;


La variable "a" es efectivamente un ushort, pero el 20 se guarda en la RAM o en la ROM como un int; pero parece que en el ST / STE esto no pasa, menos mal :)

La conclusión, es que gracias a optimizar a base de bien, el mezclador funciona 4,66 veces más rápido que sin optimizar, haciendo que sea posible utilizarlo en videojuegos para el STE con una calidad de sonido bastante decente (12,5 KHz)
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

Avatar de Usuario
explorer
Mensajes: 321
Registrado: 10 Ene 2016 18:43
Ubicación: Valladolid, España
Agradecido : 7 veces
Agradecimiento recibido: 291 veces
Contactar:

Re: Programando en C para Atari ST / STE

Mensajepor explorer » 05 Jul 2019 15:24

Prueba esta variación, a ver qué pasa (yo no le he probado).

Salvo que me haya equivocado en las declaraciones de tipos, debería funcionar.

#define SIZE_FRAME	250

pcm_mix = 0; // pcm_mix is a variable turned into true at timer A IRQ function

register unsigned char * s0 = &sample0[pcm_sample0_position];
register unsigned char * s1 = &sample1[pcm_sample1_position];
register unsigned char * s2 = &sample2[pcm_sample2_position];

register unsigned char * sdma = &dma_frame[dma_position * SIZE_FRAME];
register unsigned char * sdma_end = sdma + SIZE_FRAME;

// Mixing

#define MIX1 *sdma++ = *s0++ + *s1++ + *s2++;
#define MIX10 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1

while(sdma < sdma_end) {

MIX10
MIX10
MIX10
MIX10
MIX10

} //End of while

pcm_sample0_position += SIZE_FRAME;
pcm_sample1_position += SIZE_FRAME;
pcm_sample2_position += SIZE_FRAME;


Y ya puestos, si quieres probar la versión desenrollada completa...

#define SIZE_FRAME	250

pcm_mix = 0; // pcm_mix is a variable turned into true at timer A IRQ function

register unsigned char * s0 = &sample0[pcm_sample0_position];
register unsigned char * s1 = &sample1[pcm_sample1_position];
register unsigned char * s2 = &sample2[pcm_sample2_position];

register unsigned char * sdma = &dma_frame[dma_position * SIZE_FRAME];

// Mixing

#define MIX1 *sdma++ = *s0++ + *s1++ + *s2++;
#define MIX10 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1 MIX1
#define MIX50 MIX10 MIX10 MIX10 MIX10 MIX10

MIX50
MIX50
MIX50
MIX50
MIX50

pcm_sample0_position += SIZE_FRAME;
pcm_sample1_position += SIZE_FRAME;
pcm_sample2_position += SIZE_FRAME;

Humm... el atributo register es obsoleto en los últimos compiladores, así que sobra. Pero... ¡es tan bonito! -wink

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 09 Jul 2019 11:18

explorer escribió:Prueba esta variación, a ver qué pasa (yo no le he probado).

Salvo que me haya equivocado en las declaraciones de tipos, debería funcionar.



minter escribió:


ron escribió:


Estrayk escribió:


kikems escribió:


crashman escribió:


He probado la última propuesta de explorer,

Al igual que la vez anterior, el unrolling completo funciona muy mal, en cambio manteniendo el unrolling de 50 sigue funcionando bien.

Utilizando los "defines", se prescinde de 3 sumas y 4 asignaciones a los registros de direcciones en cada iteración; por lo que ahora
el código del mezclador se ejecuta 4,88 veces más rápido que con el código preliminar "trapero".

¡Menuda optimización se ha logrado! Entre el unrolling, el uso de punteros y los defines, el 68000 ha quedado bien exprimido;
el mezclador consume el tiempo equivalente a 34 líneas horizontales. Esto marcha muy bien señores, adjunto esta versión compilada.

He añadido funciones para:


    Cambiar el volumen

    Detener la reproducción de un sample

    Parar (quitar de la cola) la reproducción de un sample

    Indicar si un sample debe ser reproducido en bucle

    Repetir "n" veces un sample

    Reproducir en bucle o "n" veces pero con un intervalo de tiempo de separación
    (imaginemos un juego en el que haces saltar una alarma, la sirena suena a intervalos regulares y te despreocupas del timing de todo esto).


Se mantienen las características de 3 voces simultáneas a 12,5 KHz; supongo que a 6,25 KHz se podría mantener un tiempo de ejecución similar con 5 - 6 voces; y tal vez para juegos no muy exigentes, o por probar por qué no, se podrían mezclar 4 voces a 12,5 KHz. Pero vamos, que con 3 voces PCM más la música del YM2149 ya dispones de un sonido a la altura de las buenas máquinas de 16 bits.

Estoy moviéndolo con Douglas Little para integrar la funcionalidad del mezclador de audio PCM, como parte integrante de las Atari Game Tools -thumbup
Adjuntos
hiworld.rar
Versión optimizada del mezclador audio PCM a 12,5 KHz
Ejecutable de demostración
(85.54 KiB) Descargado 11 veces
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

Avatar de Usuario
explorer
Mensajes: 321
Registrado: 10 Ene 2016 18:43
Ubicación: Valladolid, España
Agradecido : 7 veces
Agradecimiento recibido: 291 veces
Contactar:

Re: Programando en C para Atari ST / STE

Mensajepor explorer » 09 Jul 2019 15:11

Es... intrigante que el unrolling funcione peor... Al final me vas a picar para que instale el AGT :D ¿me recuerdas cómo y desde dónde?

¿El proceso de compilación te genera una salida en formato assembler? Sería interesante echarle un vistazo para ver qué pasa para que el unrolling completo falle.

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 18 Ago 2019 17:54

Os escribo para comentaros que el tema sigue marcha, sólo que está algo pausado porque estoy esperando unas respuestas de Douglas Little para seguir intengrando en las Atari Game Tools; pero el amigo está montándose una nueva casa y los constructores le tienen loco, muy loco... la quiere tener lista para Septiembre, así que os podréis imaginar...
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115

masteries
Mensajes: 268
Registrado: 30 May 2018 11:33
Ubicación: Espaciando
Agradecido : 21 veces
Agradecimiento recibido: 81 veces

Re: Programando en C para Atari ST / STE

Mensajepor masteries » 18 Ago 2019 17:56

explorer escribió:Es... intrigante que el unrolling funcione peor... Al final me vas a picar para que instale el AGT :D ¿me recuerdas cómo y desde dónde?

¿El proceso de compilación te genera una salida en formato assembler? Sería interesante echarle un vistazo para ver qué pasa para que el unrolling completo falle.


Quiero preparar un paquete de instalación fácil, porque ahora mismo es un poquito raro de instalar... sé que no tendrás demasiados problemas con las herramientas en su estado actual, pero si es un poco más plug&play mejor.
La maestría interior...

Se venden trapdoor de 512 KB para Amiga 500: viewtopic.php?f=71&t=200034052

Se venden trapdoor de 1 MB para Amiga 500 Plus: viewtopic.php?f=71&t=200034115


Volver a “Software ST”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados