FUSE y cintas en formato tap y tzx

Emuladores y aplicaciones que ayudarán a la perpetuación del Spectrum y su software en el futuro

Moderador: Sir Cilve Sinclair

Responder
ultimate
Herbert
Mensajes: 54
Registrado: Dom Nov 09, 2008 2:08 am

FUSE y cintas en formato tap y tzx

Mensaje por ultimate » Jue Sep 14, 2023 7:06 pm

Este post contiene en realidad dos preguntas, una digamos de nivel usuario y otra a nivel técnico.

Empecemos con la de nivel usuario...

Estaba pasando el rato con el emulador fuse, haciendo chorraditas que pretendia grabar en una cinta en formato tap y me encuentro con una curiosa circunstancia.

Para grabar en una cinta lo que hago es crear un fichero vacío y luego grabar con comandos save del spectrum, generando bloques en la cinta.

El primer problema es obtener el fichero vacío inicial, si uso el menú Media > Tape > Write y le indico un nombre de fichero inexistente, da un montón de errores, recorriendo los distintos tipos de bloques que reconoce fuse, porque al ser una cinta vacia no hay bloques que grabar (se entiende que no hay cinta insertada). Si elegimos entonces el camino obvio y primero insertamos una cinta mediante el menú Media > Tape > Open y le indico un fichero no existente (para que lo cree) nos indica que no existe el fichero, da un error y no crea nada (otros emuladores sí crean un fichero si le indicas uno que no existe)

Entonces solo queda una solución, o partes de un fichero tap existente y lo copias en un nuevo fichero, a modo de template, o creas un fichero de 0 bytes con extensión .tap (fuse deduce el tipo de formato de la extensión del fichero)

En mi caso, creo un fichero de 0 bytes pues quiero una cinta vacía, por ejemplo z.tap, lo abro con Media > Tape > Open y a partir de ahí tengo una cinta insertada en el emulador. Media > Tape > Browser no muestra ningún contenido.

Creo un programilla de prueba y SAVE "p" <enter>, voy a Media > Tape > Record Start y pulso una tecla, obtengo el mensaje de OK y voy a Media > Tape > Record Stop
Ahora voy a ver el contenido de la cinta con Media > Tape > Browser y veo que hay un bloque de tipo RLE Pulse.

Bien, pues ahora quiero grabar la cinta en un fichero de formato tap, así que voy a Media > Tape > Write e indico un nombre de fichero nuevo, digamos zz.tap y Fuse me da el error "libspectrum: skip_block: skipping RLE Pulse (ID 0x100); conversion almost certainly won't work"
Este error tiene sentido pues hasta donde yo sé los ficheros tap usan bloques ROM estándar y no bloques RLE. Pese al error me genera el fichero zz.tap con tamaño 0. Por lo tanto he perdido mi programilla.

Pruebo entonces a guardar la cinta en formato txz en lugar de tap, por el mismo procedimiento, solo que indicando como fichero zz.tzx y entonces obtengo un fichero zz.tzx de 57 kb y si lo abro desde fuse puedo cargar mi programa.
Sin embargo, cuando cargo la cinta zz.tzx mediante Media > Tape > Open y miro su contenido con Media > Tape > Browser veo que contiene un bloque de tipo Raw Data de 57835 bytes.

Recapitulando, si abro un fichero .tap vacio como cinta insertada y grabo un programa, obtengo en la cinta insertada un bloque RLE Pulse (no indica tamaño) que no puedo escribir (Write) en un fichero .tap pero sí en un fichero .tzx que si luego abro como cinta insertada me encuentro que contiene un bloque Raw Data de 57kb.

La pregunta obvia es como hacer para crear una cinta de cero y guardarla en formato .tap en Fuse, la menos obvia es para qué guarda Fuse los bloques grabados en cinta en un formato que no puede escribir, no tiene mucho sentido.
La mayoria de ficheros .tap (todos hasta donde yo sé) contienen bloques ROM estándar y de hecho si abres en Fuse un tap generado por otro emulador (por ej el fantástico zesarux) y miras el contenido te encuentras bloques del tipo Standard Speed Data.
Entiendo que Fuse debería guardar los bloques en ese formato también y si no sabe qué formato usar pues todavía no has hecho un Write a un formato concreto, al menos debería poder convertir sus bloques RLE internos al tipo de bloque esperado por el formato destino.

El caso es que debido a esto Fuse no puede guardar archivos .tap desde bloques de cinta que has ido SAVEando (salvo que haga algo mal que es posible), pero bueno, al menos sí puede guardar archivos .tzx no?

Pues el caso es que sí pero no, me explico, el formato de bloques que guarda en el archivo .txz es muy particular pues utiliza un tipo de bloque soportado por el formato tzx que hace prácticamente imposible convertir el tzx generado a formato tap con alguna de las utilidades existentes.

y con esto llegamos a la pregunta técnica...

Fuse graba los bloques guardados en cinta como bloques RLE y cuando los guarda en formato tzx los guarda como bloques "Raw Data" en terminología Fuse, que son los bloque de tipo ID 15 - Direct Recording definidos en el formato tzx

Estos bloques tienen la siguiente estructura [1]:

Código: Seleccionar todo

length: [05,06,07]+08
Offset	Value	Type	Description
0x00	-	WORD	Number of T-states per sample (bit of data)
0x02	-	WORD	Pause after this block in milliseconds (ms.)
0x04	-	BYTE	Used bits (samples) in last byte of data (1-8) (e.g. if this is 2, only first two samples of the last byte will be played)
0x05	N	BYTE[3]	Length of samples
0x08	-	BYTE[N]	Samples data. Each bit represents a state on the EAR port (i.e. one sample). MSb is played first.
[1] https://worldofspectrum.net/TZXformat.html#STDSPEED

Como un archivo TAP contiene bloques estándar, todos los programas de conversión de tzx a tap que conozco se saltan los bloques que no son estándar y como resultado obtienes en el mejor de los casos un archivo tap de 0 bytes como resultado de la conversión y en el peor un error.

La pregunta es ¿sería posible convertir un bloque 15 en una secuencia de bloques estándar para escribir en un archivo tap?

El bloque 15 contiene los samples generados por EAR, es decir una reproducción "analógica" de la cinta tal cual la grabaría un spectrum real, mientras que según entiendo, un archivo .tap tiene los bytes de la cinta tal y como los leería el spectrum, información digital.

Entonces para convertir el bloque 15 en bloques estandar, habría que ir leyendo cada grupo de "8 samples" e ir convirtiendolo a un byte con el valor apropiado. No recuerdo ahora mismo el formato de grabación en cinta que usa el spectrum pero seguramente un byte no serán exactamente 8 samples porque quizá haya información de paridad, sincronismo, etc

Entiendo que a efectos de una conversión a tap, los dos primeros campos del bloque (número de t-states por sample y pausa en ms despues del bloque) no tienen efecto, porque en el campo de datos ya viene toda la secuencia de samples sin importar la duración ni la frecuencia de cada sample, quizá estos valores sean importantes para un emulador pero no para una utilidad de conversión.
El cuarto campo, bits en el ultimo byte de datos, sí parece importante porque al leer la secuencia de samples puedes no tener un multiplo de 8 samples, 8 bits, sino que el ultimo byte puede tener menos samples (bits), en este caso no tengo muy claro como se interpreta su valor, imagino que serán los menos significativos.

Por tanto un posible algoritmo de conversión en pseudoC (uso los campos sin prefijarlos con el nombre de la estructura donde se definen por claridad) sería algo así:

Código: Seleccionar todo

TAP_block = RECORD {byte size[2]; byte flag; byte DATA[N]}
TZX_block = RECORD { byte tstates[2]; ...; byte bits_last_byte; byte length_samples[3]; byte SAMPLES[N]}
memcpy(DATA,SAMPLES,length_samples-1)
byte b=SAMPLES[length_samples-1]
DATA[length_samples-1] = b >> bits_last_byte
flag=FF
size=length_samples
asumiendo que cada sample es un bit 1 o 0 y por tanto leer un byte de samples nos da el valor binario del byte y que el último byte tiene solamente los bits_last_bytes menos significativos.

El problema es que te puedes encontres con bloques de samples más largos que el tamaño de bloque de un tap (2 bytes para el tamaño de bloque tap, 3 bytes para el tamaño de samples tzx)

¿estoy muy equivocado o van por ahí los tiros y la cosa es factible?

TheMartian
rst 0
Mensajes: 25
Registrado: Dom Mar 25, 2018 2:07 pm

Re: FUSE y cintas en formato tap y tzx

Mensaje por TheMartian » Vie Sep 15, 2023 2:55 pm

¡Hola!

A tu primera pregunta:
Para que FUSE cree un fichero TAP necesitas activar Options > Media > Use Tape Traps. De este modo, FUSE capturará las llamadas a las rutinas de cinta de la ROM y "hará lo correcto". Esto sirve para cargar los TAPs instantáneamente, y para grabar en TAP.

El procedimiento sería:
1. Activas Options > Media > Use Tape Traps.
2. Si acabas de arrancar FUSE no hace falta, pero si tienes una cinta cargada: Media > Tape > Clear. Ahora tienes la imagen de cinta vacía.
3. Haces SAVE de los bloques que quieras. También puedes usar la rutina SA_BYTES de la ROM.
4. Cuando has grabado todo, haces F6 o bien Media > Tape > Write... y FUSE te pedirá un nombre de archivo mediante el selector de ficheros.

A tu segunda pregunta:
El bloque de RAW es tal cual un CSW descomprimido, que sí se podría pasar por un conversor a bloques TZX estándar antes de grabar. Sería un poco integrar el MakeTZX en el emulador, con la ventaja de que al provenir de un emulador no tienes que preocuparte de ruidos ni filtrar. Imagino que sería posible.

ultimate
Herbert
Mensajes: 54
Registrado: Dom Nov 09, 2008 2:08 am

Re: FUSE y cintas en formato tap y tzx

Mensaje por ultimate » Sab Sep 16, 2023 11:07 pm

Pues gracias por la información, efectivamente haciendo lo que indicas todo va perfecto. La opción "Use Tape Traps" ya la tenía activada, entiendo que está activa por defecto, porque yo desconocía su uso.

Quizá sea cosa de mi mente distorsionada, pero no me parece muy intuitivo esta forma de funcionar, que puedas grabar en cinta sin tener una "cinta insertada", simplemente usando los comandos del basic. Yo entendía que hay que "meter una cinta" para poder usarla y luego grabas en ella pulsando la tecla REC (Media > Tape > Record Start) y finalizas pulsando STOP (Media > Tape > Record Stop), para eso parecen estar destinadas estas opciones de Media > Tape , Load, Record Start, Record Stop y finalmente escribir la cinta en un fichero con la opción Write que vendría ser como cerrar el fichero (bien el abierto con Open bien uno nuevo). Otros emuladores funcionan de esta manera.

Con esta forma de funcionar de FUSE con "use tape traps" no acabo de ver para que hacen falta las opciones record start y record stop, pero leyendo el manual veo que están pensadas para rutinas de carga no estándar o para momentos donde es necesario "pulsar fisicamente las teclas del cassette", me sigue pareciendo confuso.

Respecto de la segunda pregunta, la técnica, no acabo de entender cómo están grabados los datos en el bloque 15 de tzx, dices que están en formato CSW sin comprimir pero según [1] CSW guarda los samples como bytes comprimidos con RLE, entonces si esto es un CSW sin comprimir deberíamos tener tantos bytes como samples. (hipotesis 1)

Por otro lado la estructura de un bloque 15 según [2] indica la longitud de los datos como número de samples, y cada sample se almacena en un bit, que es un estado alto o bajo de EAR. Por tanto si tenemos 8 samples deberíamos tener 1 byte y el valor numérico de ese byte coincide con el valor que codifica los samples. (hipótesis 2)

Cuando grabo un programa "1o print" en una cinta con el procedimiento descrito en mi primer post, obtengo un fichero tzx de 54739 bytes pero en otras ocasiones grabando el mismo programa con el mismo procedimiento obtengo un fichero tzx de 104169 bytes, primera cuestión que me intriga.

Este fichero tzx de 54739 cuando lo analizo, veo que tiene un bloque de tipo 15 y en el campo de offset 0x05, Length of samples' data, tengo un valor de 54739. Pero esto indica que hay ese numero de bytes como datos y efectivamente es así, lo cual está en sintonía con la hipótesis 1 pero no parece casar bien con lo que se indica en la cabecera del bloque 15, ya que deberían ser 54739 samples de 1 bit, es decir 6842 bytes.

Suponiendo la hipótesis 1 como correcta, significa que debemos leer 54739 bytes, pero un programa de 3 bytes no puede guardarse como 54k!

Yo estaba suponiendo que un sample (H o L) equivale a 1 bit, y por tanto 8 samples seguidos codifican un byte, con lo cual leer un byte de samples equivale a leer el valor binario que codifican esos samples, pero esto significa que para guardar 3 bytes de programa harían falta 3 bytes que equivalen a 24 samples.

Es evidente que esto no es así, entonces ¿cómo se codifican los bytes en samples en un CSW o en samples data de un bloque 15? es evidente que se utilizan muchos samples para codificar un simple byte de programa.

¿hay alguna web con info al respecto?


[1] https://rhc14.grey-panther.net/doc/tech ... s/csw.html#
[2] https://worldofspectrum.net/TZXformat.html#STDSPEED

TheMartian
rst 0
Mensajes: 25
Registrado: Dom Mar 25, 2018 2:07 pm

Re: FUSE y cintas en formato tap y tzx

Mensaje por TheMartian » Lun Sep 18, 2023 1:49 pm

Luego me explayo, que ahora no puedo. Pero: Los samples son de audio, por lo que estoy viendo, o sea, estados de EAR cada n t-states.

Entonces mi afirmación de que es como un CSW es incorrecta porque en un CSW guardas longitudes de pulsos, y aquí guardas un muestreo regular. En este sentido se parece más a un WAV o un VOC, pero con un tamaño de muestra de 1-bit.

Entonces puede que varios samples sean un bit (que son dos pulsos). Lo que dije, que estos datos son carne para MakeTZX, lo sigo sosteniendo, pero no es tan fácil como que 8 samples es 1 byte.

TheMartian
rst 0
Mensajes: 25
Registrado: Dom Mar 25, 2018 2:07 pm

Re: FUSE y cintas en formato tap y tzx

Mensaje por TheMartian » Lun Sep 18, 2023 9:41 pm

Vale, me he leído la spec.

El tag 0x15 es básicamente un muestreo del puerto EAR a una frecuencia de muestreo dada por el número de t-estados por cada sample. Como dice en la spec, 158 serían 22050Hz, y 79 serían 44100Hz.

La diferencia entre usar un VOC o un WAV y esto es que aquí guardas sólo un bit por muestra en vez de 8 ó 16.

Para procesar esto en un bloque estándar de TZX o TAP hay que analizar la señal, detectar el tono guía, los pulsos de sincronismo y los tiempos de bit.

Si grabas de esta manera y una vez te ocupa el doble que otra es porque has grabado el doble de tiempo. Lo mismo que si lo hicieras con un WAV y tardases algo más entre que arrancas la cinta y pulsas ENTER al SAVE.

El bloque 0x18 sí es CSW internamente. Aquí lo que guardas son longitudes de pulsos comprimidas en RLE o Z-RLE. Esto será más compacto para datos en cassette, porque un pulso típico de Spectrum son 1710 o 855 t-estados, que los almacenas en 2 bytes, pero si lo haces en bits a 44100 son más de 20 bits.

En ambos casos estás modelando la señal en el puerto EAR, y si quieres traducir esta señal a bytes para el TZX o el TAP hay que analizarla como harían los conversores de WAV a TZX.

Responder

¿Quién está conectado?

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