Primeros pasos para pogramar un emulador

Foro dedicado a la emulación de sistemas clásicos en el PC o en otros sistemas.
ZX-81
Amstrad PCW 8256
Amstrad PCW 8256
Mensajes: 128
Registrado: 04 Ene 2013, 16:43
Sistema Favorito: Spectrum +2
primer_sistema: ZX81
consola_favorita: Nintendo DS/3DS
Primera consola: Sega Genesis/Megadrive
Ubicación: La orilla del mar Mediterráneo
Gracias dadas: 16 veces
Gracias recibidas: 27 veces
Contactar:

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX-81 » 02 Dic 2021, 21:01

ZX81 escribió:Hola,
Estoy intentando poner sonido al emulador, pero no me funciona bien, el sonido va como 8 veces más acelerado de lo normal, cuando la velocidad del emulador es más o menos normal. Por ejemplo, cuando cargo el Abu Simbel la melodía va súper rápido :shock: .
La frecuencia de muestreo que he puesto es de 48000Hz, y cada 20.8us envío una muestra a la tarjeta de sonido, que por 960(48Khz/50Hz) dan 20ms, un campo de TV.

Con el método setValor guardo el dato OUT que envía el Z80, para que mas tarde lo pueda guardar el método guardarMuestra cada 73 T-States, y el método play reproduce el sonido cada 69888 T-States.


Ojalá fueran las cosas tan simples...

3.500.000 / 48000 = 72.91 t-states por sample.

¿Has oído decir alguna vez eso de que el demonio está en los detalles?. Pues créeme si te digo que esta es una de esas ocasiones. Quita los decimales por exceso o defecto y nunca sonará bien.

Por otro lado, 69888 * 50 = 3.494.400 Hz, te faltan cosas ahí. La frecuencia exacta de refresco son 3.500.000 / 69888 = 50.08 Hz.

Y de paso, (1 / 3.500.000) * 69888 = 0.011968, o sea, 19.968 ms por cuadro, nada de 20 ms. Y los decimales, vuelven a contar y mucho.

Al final, todo depende de la precisión que quieras conseguir. Pero lo que no tolera la más mínima tontería es el sonido porque, por desgracia, es lo único que funciona quasi en tiempo real (con algún frame de retraso), en cuando el buffer de audio se te vacía 1ms, ya oyes aliens llamándote a cenar.

Lo de la velocidad debe ser una cosa trivial. Lo de que suene bien es otra cosa. Tienes que ser coherente al final, si vas a ajustarlo todo a 20ms por cuadro, ajusta todo lo demás. El sonido se escuchará ligerísimamente fuera de tono, pero no mal y mucha gente ni lo apreciará a menos que tenga un oído entrenado en música.

Y si solo almacenas valores de sample que tengan máximo y mínimo valor, tampoco sonará bien. Necesitas algún tipo de suavizado, para que la señal suba y baje más lentamente. No hace falta un filtro de la pera, pero sí algo modere los cambios bruscos.

Ni te imaginas los meses que tardé en tener una rutina de BEEP que sonara a BEEP. Melodías sencillas pueden dar muchísima guerra, por ejemplo, la del Babaliba. Por no hablar de la voz digitalizada del Cobra's Arc.

Si supieras donde te has metido... habrías preferido aprender sanscrito. <XX
Todo espacio de dimensión finita distinta de cero con producto interno tiene una base ortonormal. Tiene sentido, cuando no piensas sobre ello.
Profesor de Matemáticas U.C. Berkeley

Empieza a jugar sin tener que compilar: JSpeccy
Emulador bare-metal para la Raspberry PI 2/3: ZXBaremulator

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 04 Dic 2021, 11:48

Namek escribió:
ZX81 escribió:
Namek escribió:Si dices que va 8 veces mas rápido me suena a que estas montando cada cambio de estado del bit de sonido en un bit de un sample de 8 bits? Cada cambio de estado en el bit de audio del spectrum correspondería con un byte de un sample de 8 bits o 2 bytes de un sample de 16 bits. Parece una tontería, pero como dices que va 8 veces mas rápido es lo único que se me ocurre... :roll:

También tienes que tener en cuenta que cuando se cambia el estado del bit de sonido y lo registras para producir el sonido también tienes que registrar los momentos en que no se esta cambiando el bit de audio, osea debes registrar el estado actual del bit de audio en el tiempo aunque no se este cambiando en un momento dado.


Hola,
Sí cuando OUT hace un cambio de estado lo actualizo, y luego cuando toca se añade al array de muestras de sonido, poniendo el cero como valor mínimo de nivel de volumen y el uno como valor máximo. Luego lo reproduzco mediante el método play, pero va acelerado, y también con algo de ruido.

Con este video se verá más claro: :-({|=
https://youtu.be/GjBdzUE38h8

Saludos.

Pero sigues sin aclararme si añades la información de la forma de onda cuando no se esta haciendo un OUT, aunque no se haga un OUT, el estado a 1 o a 0 del bit de sonido debe registrarse en la forma de onda final, ya que el tiempo que pasa entre un OUT y el siguiente es también tiempo de onda que debe ser registrado.


Hola,
Sí, cuando no se está haciendo un OUT la señal se registra como un cero. Al final la velocidad de reproducción ya va más o menos normal, aunque con ruido. Al final el problema de la velocidad de reproducción era que estaban mal los valores de los T-States de las instrucciones JR de la emulación del Z80. :mrgreen:

https://youtu.be/tXRDqfzpkp4
10 REM ESTA LINEA NO HACE NADA

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 04 Dic 2021, 12:20

ZX-81 escribió:
ZX81 escribió:Hola,
Estoy intentando poner sonido al emulador, pero no me funciona bien, el sonido va como 8 veces más acelerado de lo normal, cuando la velocidad del emulador es más o menos normal. Por ejemplo, cuando cargo el Abu Simbel la melodía va súper rápido :shock: .
La frecuencia de muestreo que he puesto es de 48000Hz, y cada 20.8us envío una muestra a la tarjeta de sonido, que por 960(48Khz/50Hz) dan 20ms, un campo de TV.

Con el método setValor guardo el dato OUT que envía el Z80, para que mas tarde lo pueda guardar el método guardarMuestra cada 73 T-States, y el método play reproduce el sonido cada 69888 T-States.


Ojalá fueran las cosas tan simples...

3.500.000 / 48000 = 72.91 t-states por sample.

¿Has oído decir alguna vez eso de que el demonio está en los detalles?. Pues créeme si te digo que esta es una de esas ocasiones. Quita los decimales por exceso o defecto y nunca sonará bien.

Por otro lado, 69888 * 50 = 3.494.400 Hz, te faltan cosas ahí. La frecuencia exacta de refresco son 3.500.000 / 69888 = 50.08 Hz.

Y de paso, (1 / 3.500.000) * 69888 = 0.011968, o sea, 19.968 ms por cuadro, nada de 20 ms. Y los decimales, vuelven a contar y mucho.

Al final, todo depende de la precisión que quieras conseguir. Pero lo que no tolera la más mínima tontería es el sonido porque, por desgracia, es lo único que funciona quasi en tiempo real (con algún frame de retraso), en cuando el buffer de audio se te vacía 1ms, ya oyes aliens llamándote a cenar.

Lo de la velocidad debe ser una cosa trivial. Lo de que suene bien es otra cosa. Tienes que ser coherente al final, si vas a ajustarlo todo a 20ms por cuadro, ajusta todo lo demás. El sonido se escuchará ligerísimamente fuera de tono, pero no mal y mucha gente ni lo apreciará a menos que tenga un oído entrenado en música.

Y si solo almacenas valores de sample que tengan máximo y mínimo valor, tampoco sonará bien. Necesitas algún tipo de suavizado, para que la señal suba y baje más lentamente. No hace falta un filtro de la pera, pero sí algo modere los cambios bruscos.

Ni te imaginas los meses que tardé en tener una rutina de BEEP que sonara a BEEP. Melodías sencillas pueden dar muchísima guerra, por ejemplo, la del Babaliba. Por no hablar de la voz digitalizada del Cobra's Arc.

Si supieras donde te has metido... habrías preferido aprender sanscrito. <XX


Hola,
Sí, así he puesto el muestreo, cada 73 T-states.

Código: Seleccionar todo

            if ((z.gettStates() - muestra) > 73) {//Cada 20uS guarda incrementa la posición del sample del array -->73T-States * (1/3500000Hz CLK Spectrum)=20.8us
                muestra = z.gettStates();//Muestreo 48000Hz/50Hz=960 muestras cada 20ms. 20.8us x 960=19.968ms
                //Incrementa contador Array sample
                sonido.guardaMuestra();
            }
            if (z.gettStates() > 69888) {//A los 69888 T-States se completa un cuadro de TV
                finTemp = System.currentTimeMillis();//Averigua el tiempo que
                long difTemp = finTemp - inicioTemp;//han tardado en ejecutarse 69888 T-States
                frames++;//Incrementa el número de cuadros
                if (!reproduciendoSonido) {
                    reproduciendoSonido = true;
                    sonido.play();
                }
                try {


La reproducción de audio he conseguido que más o menos salga a la velocidad adecuada, pero con ruido (imagino que son los aliens que comentas, jeje) , igual también me falta suavizar la onda por así decirlo tal y como comentas. :chaparron
Bueno , cualquier comentario poder para aprender es bien recibido, voy a ver si consigo hacer algo más, que ya no me podré poner con el emulador durante un tiempecito, cosas de familia y trabajo. :yeah:

Saludos.
10 REM ESTA LINEA NO HACE NADA

Avatar de Usuario
Namek
Atari 1040 STf
Atari 1040 STf
Mensajes: 838
Registrado: 11 Jul 2011, 13:13
Gracias dadas: 18 veces
Gracias recibidas: 63 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor Namek » 05 Dic 2021, 03:06

ZX81 escribió:Hola,
Sí, cuando no se está haciendo un OUT la señal se registra como un cero. Al final la velocidad de reproducción ya va más o menos normal, aunque con ruido. Al final el problema de la velocidad de reproducción era que estaban mal los valores de los T-States de las instrucciones JR de la emulación del Z80. :mrgreen:

No, cuando no se esta haciendo un OUT la señal hay que registrarla como la dejó el ultimo OUT, si el ultimo OUT fue un 1 hay que registrar 1 y si fue 0 pues 0.

Y el ruido que se escucha en el vídeo es habitual en otros emuladores, es por culpa de la velocidad de muestreo, realmente ese ruido también existe en el Spectrum de verdad, solo que a tan alta frecuencia que no lo oímos, por eso si aumentas la frecuencia se atenúa y si la diminuyes se incrementa.

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 19 Feb 2022, 17:03

Hola,
Me he puesto y rato a mirar el tema del emulador y he conseguido que el audio se escuche más o menos bien, pero veo que el video parece que se vaya saltando cuadros, vamos que va a trompicones, sin embargo cuando le quito el audio parece que el video vaya fluido. La pausa de 20ms mientras hay audio la hago con una llamada a line.write(muestras, 0, posMuestra);, mientras que cuando no hay audio la hago con un Thread.sleep. He probado a poner el audio con un hilo independiente y sucede lo mismo. Así que no entiendo por qué puede estar pasando esto, ¿alguien tiene alguna idea?

Adjunto un video para que veáis lo que sucede:
https://www.youtube.com/watch?v=nliPwelAoFk

Saludos.
10 REM ESTA LINEA NO HACE NADA

Avatar de Usuario
Fer
Dragon 32
Dragon 32
Mensajes: 22
Registrado: 30 Ene 2022, 19:23
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: ZX81
consola_favorita: Videopac
Gracias dadas: 6 veces
Gracias recibidas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor Fer » 20 Feb 2022, 19:47

Con sonido va a saltos.

ZX81 escribió:10 REM ESTA LINEA NO HACE NADA

Ocupar unos bytes. ;)

ZX81 escribió:Por no hablar de la voz digitalizada del Cobra's Arc.

Con tu permiso lo matizo, la voz es sintetizada.

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 22 Feb 2022, 15:27

Fer escribió:Con sonido va a saltos.


Sí, alguna idea de por qué puede pasar?

Saludos.
10 REM ESTA LINEA NO HACE NADA

Avatar de Usuario
Fer
Dragon 32
Dragon 32
Mensajes: 22
Registrado: 30 Ene 2022, 19:23
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: ZX81
consola_favorita: Videopac
Gracias dadas: 6 veces
Gracias recibidas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor Fer » 23 Feb 2022, 07:18

ZX81 escribió:
Fer escribió:Con sonido va a saltos.
Sí, alguna idea de por qué puede pasar?


¿Un pequeño retraso que va acumulándose hasta que llega un momento en el que se van perdiendo frames? ¿Salta un poco también al desplegar el menú?

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 23 Feb 2022, 20:23

Hola,
Acabo de comprobar porque se salta algunos cuadros. Por lo visto cuando se llama al método de la clase que reproduce el sonido, una de cada diez veces o nueve, tarda en ejecutarse 140ms y las otras veces tarda en ejecutarse como mucho 1ms, cuando en principio tendrían que ser 20ms cada vez que se llama al método. Ni idea que puede estar pasando. >|


Código: Seleccionar todo

T=140
T=0
T=0
T=0
T=0
T=0
T=0
T=1
T=1
T=139
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=140
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=140
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=0
T=0


Esta es la clase que llama al método para reproducir el sonido:

Código: Seleccionar todo

 if (z.gettStates() > 69888) {//A los 69888 T-States se completa un cuadro de TV
                finTemp = System.currentTimeMillis();//Averigua el tiempo que
                long difTemp = finTemp - inicioTemp;//han tardado en ejecutarse 69888 T-States
                frames++;//Incrementa el número de cuadros
                long t1 = System.currentTimeMillis();
                if (sonidoActivado) {
                    sonido.play();
                }
                try {
                    if (difTemp < 21 && !sonidoActivado) {
                        Thread.sleep(20 - difTemp);//Si el tiempo es menor que 20ms hace una pausa hasta que se cumplan 20ms
                    }

                } catch (InterruptedException ex) {
                    Logger.getLogger(Spectrum.class.getName()).log(Level.SEVERE, null, ex);
                }
                long t2 = System.currentTimeMillis();
                if (frames > 16) {
                    p.setAstable(p.getAstable() ^ 1);//Realiza el parpadeo de la pantalla (FLASH)
                    frames = 0;
                }
                p.repaint();//Actualiza la pantalla
                System.out.println("T=" + (t2 - t1));
                z.settStates(0);
                muestra = 0;
                inicioTemp = System.currentTimeMillis();//Guarda el tiempo inicial
                sonido.reset();
                z.Int();



Y este es el método de la clase Sonido:

Código: Seleccionar todo

    public void play() {
        // Reproduce el sonido
        line.write(muestras, 0, posMuestra);
        posMuestra = 0;
    }
10 REM ESTA LINEA NO HACE NADA

ZX81
MSX Turbo R
MSX Turbo R
Mensajes: 487
Registrado: 20 Abr 2005, 19:18
Gracias dadas: 3 veces

Re: Primeros pasos para pogramar un emulador

Mensajepor ZX81 » 24 Jul 2022, 13:43

Hola,
No sé si me explico bien.
Cuando llamo al método line.write a veces veo que tarda en ejecutarse 0ms y otras veces más de 100ms. No debería de tardar cada vez que se llama unos 20ms?

A ver si alguien me puede ayudar.

Saludos.
10 REM ESTA LINEA NO HACE NADA


Volver a “Emuladores”

¿Quién está conectado?

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