Logicielsmoto.com
http://www.logicielsmoto.com/phpBB/

MO6 problems loading files
http://www.logicielsmoto.com/phpBB/viewtopic.php?f=13&t=516
Page 1 sur 3

Auteur:  W_oo_d [ 13 Fév 2015, 13:56 ]
Sujet du message:  MO6 problems loading files

Hi,

I have been coding for the Thomson machines for sometime and now I have the opportunity to check my programs on a real MO6(I have also a TO8D but unfortunately I can't pass my programs to it yet as I haven't bought a floppy emulator.). I have got a tape adapter that I connect to my PC or to a mp3 player. But I am having problems. I can load some games, like sortileges and bobo, but others refuse to load. The wav files I tried to load I have downloaded from DCMOTO's website.

Regarding my own programs, if I save the binaries to wav format with SAVEM using MESS in MO6 emulation they will not load on my MO6 (If I save a basic program it will load fine though). If I save the binary from the MO5 MESS emulation it will load also fine.

If I use PulkoMandy's program f2k5 and then Daniel Coulom's tool to convert it to WAV it won't load on my MO6.

Daniel Coulom told me:

Citation:
I guess the problem is mainly the tape adapter signal shape and level. These adapters are made for analog audio. The MO6 uses digital signal. Even with a perfect square in the .wav file, the limited bandwith of the adapter makes a rounded signal, this doesn't help.

The signal shape and level should be monitored with an oscilloscope, from the output of the PC to the MO6 amplifier and TTL converter, then to the 6821 PIA on the motherboard. With these data it should be possible to pinpoint the error and possibly find a solution.


Considering the above, any ideas on how to handle the wav file so I can make it more likely to load?

If there is no way to make this work with the tape adpater I would be thankfull to anyone who could get me some gadget to get my programs into the MO6 and/or TO8, I don't know anything about electronics nor do I know someone here near me who does. Just tell me how much it would be and I will consider your proposal.

Any help with this situation is appreciated. Thanks

Auteur:  Prehisto [ 13 Fév 2015, 22:39 ]
Sujet du message:  Re: MO6 problems loading files

Could you post on attachment:
- The initial file
- The result of PulkoMandy's program f2k5
- The result of Daniel Coulom's tool
and all that for a file which works and for a file which does not ?

Auteur:  W_oo_d [ 13 Fév 2015, 22:48 ]
Sujet du message:  Re: MO6 problems loading files

Sure, tomorrow I will post them here.

Auteur:  Prehisto [ 13 Fév 2015, 22:55 ]
Sujet du message:  Re: MO6 problems loading files

... or just give the links to the files you upload on an "upload for free" site, I think it would be better. We wont need those files eternally and it will spare LogicielsMoto's server space.

Auteur:  W_oo_d [ 14 Fév 2015, 11:34 ]
Sujet du message:  Re: MO6 problems loading files

No worries I meant the links and not the files themselves.

test.bin http://s000.tinyupload.com/index.php?file_id=55168106489063892256
test.k5 http://s000.tinyupload.com/index.php?file_id=63193231171781853820
TESTfromdcmok7.wavhttp://s000.tinyupload.com/index.php?file_id=44250148012335597502
TESTfromMO5.wav http://s000.tinyupload.com/index.php?file_id=09641967445464213070
TESTfromMo6BASIC1.wav http://s000.tinyupload.com/index.php?file_id=92709270774244192280
TESTfromMO6BASIC128.wav http://s000.tinyupload.com/index.php?file_id=29699943872636917611

All the wav files created from MESS using SAVEM are loading fine on my MO6 but the one create by dcmok7 doesn't load.

The games I have downloaded the wav files from the DCMOTO website:

work:


sortileges (mo5)
brain-power (mo5)
bobo(mo6)
prohibition(mo6)


don't work:

quad - finds first file but doesn't load it then when it reads the second header it throws an I/O error
mach3 - crashes at minute ~7
bivouac - doesn't load at all
mission - loads the presentation screen and the file plays to the end but nothing happens.
space-racer: using BASIC 128 I get the same result as above on QUAD, if I use BASIC 1 it will load part of the loading screen and then will throw an error 53, I/O error I presume

Auteur:  Prehisto [ 14 Fév 2015, 17:34 ]
Sujet du message:  Re: MO6 problems loading files

So, when I display a part of the WAV in EAC mode, I get this (TESTfromMO5.wav up, TESTfromdcmok7.wav down):
Fichier(s) joint(s):
hauteur.png
hauteur.png [ 130.52 Kio | Vu 8997 fois ]

The both WAV look similar, but there are unnecessary datas at start (surrounded in red) in TESTfromdcmok7.wav. Then I delete the guilty part (selected there) at every start of data blocks:
Fichier(s) joint(s):
onde.png
onde.png [ 8.08 Kio | Vu 8997 fois ]

At least, I get a corrected file : http://dl.free.fr/jTbDwoPW1, which works now on my MO6.
So there is a problem with Daniel Coulom's program.

Auteur:  W_oo_d [ 14 Fév 2015, 19:59 ]
Sujet du message:  Re: MO6 problems loading files

Thank you a lot, Prehisto. Is there any other tool besides Coulom's to convert k7 files to wav?

Can you check out if one of the games that doesn't load in my MO6 works in yours?

Auteur:  PulkoMandy [ 15 Fév 2015, 22:40 ]
Sujet du message:  Re: MO6 problems loading files

Hi,
I made some tests with my MO6 here. I had to set the volume rather low on my PC to get the files recognized (otherwise there is too much saturation).

All 3 of your test wav files work. Sortilege works. Quad doesn't work, maybe there is a problem in the WAV file?

Auteur:  W_oo_d [ 16 Fév 2015, 20:29 ]
Sujet du message:  Re: MO6 problems loading files

Thanks Pulko for trying out those games. There might be some problem with the wav files I tries. It is interesting that some work with the emulators, but emulators as everyone knows are more forgiving beasts.

Auteur:  Prehisto [ 20 Fév 2015, 09:40 ]
Sujet du message:  Re: MO6 problems loading files

I will try to explain where the problem is, in my broken English :

Synchronizing the byte reading is crucial, because the data stream is written and read synchronously on the compact cassette. That means the bits must be written and read at the same time, neither more nor less, like a real MO does.

The gap between blocks is as important as data. The program could do something that takes more or less time between blocks, and the developer could have found not very useful to stop the motor during that time. So gap lengths could vary. Unfortunately, the K7 file format does not save that kind of information.

The reading is not at its best without to be approximate: the range of time between the change of the signal and the check itself is roughly equivalent to a hundred of cycles, even though the amount of cycles to read a full bit of data is about 800 (here for a bit set to 1):

Fichier(s) joint(s):
graph1.png
graph1.png [ 4.37 Kio | Vu 8965 fois ]


Moreover, the speed between two tape readers could be different, due to the variability of adjustment and/or the oldness of the equipment. To "correct" all that, I have added the option '--modified' in the command line, that divides the synchro/change/check in three equal parts, and get sometimes a better result even with worn magnetic tapes. It could correct speed differences as well (here for a bit set to 1):

Fichier(s) joint(s):
graph2.png
graph2.png [ 4.38 Kio | Vu 8965 fois ]


The k5towav program:

Usage: k5towav [--modified] <filename>
--modified : modify the shape of signal to try to correct read errors (optional)
<filename> : a K5 file name. The WAV output will be saved in the same directory under the same name with the suffix ".wav" (16 bits/44100Hz)

The makefile :
Code:
CC=gcc
CFLAGS= -W -Wall -Werror -O2

all : k5towav


The k5towav C source :
Code:
/*--------------------------------------------------------*/
/* k5towav (c) Prehisto feb 2015                          */
/* To convert MO K7 file to WAV file                      */
/*--------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#ifndef TRUE
#   define  TRUE 1
#endif
#ifndef FALSE
#   define  FALSE 0
#endif

/* WAV constants */
#define WAVE_HEADER_SIZE  0x2c
#define WAVE_RIFF_CHUNK_SIZE  4
#define WAVE_FORMAT_CHUNK_SIZE  16
#define WAVE_FORMAT_PCM            1
#define WAVE_FORMAT_CHANNELS  1
#define WAVE_FORMAT_SAMPLESPERSEC  44100
#define WAVE_FORMAT_BLOCKALIGN  2
#define WAVE_FORMAT_AVGBYTEPERSEC  WAVE_FORMAT_SAMPLESPERSEC*WAVE_FORMAT_BLOCKALIGN
#define WAVE_FORMAT_BITPERSAMPLE  16

/* Sample parameters */
#define CYCLES_PER_FRAME    19968
#define MICROSEC_PER_FRAME  20000
#define MICROSEC_PER_SEC    1000000
#define CURRENT_VALUE_DEFAULT  0x7fff

static int flag_modified = FALSE;
static int current_value = CURRENT_VALUE_DEFAULT;
static double remain = 0;
static int cycles = 0;



static void write_gap (int length, FILE *file)
{
    int i;

    for (i=0; i<length; i++)
    {
        fputc (current_value&0xff, file );
        fputc ((current_value>>8)&0xff, file );
    }
}



static void write_motoroff (FILE *file)
{
    write_gap (WAVE_FORMAT_SAMPLESPERSEC/2, file);
}



static void write_motoron (FILE *file)
{
    write_gap (WAVE_FORMAT_SAMPLESPERSEC, file);
}



static void write_data_gap (FILE *file)
{
    /* Must have time to do at least :
       4+2   NEXT   LDA    ,X+
       4+2          STA    ,U+
       4+1          LEAY   -1,U
       3            BNE    NEXT
       ... a bit more! */
    write_gap (WAVE_FORMAT_SAMPLESPERSEC/8, file);
}



static void write_signal (FILE *file)
{
    int i;
    double size = ((((double)cycles*(double)MICROSEC_PER_FRAME)
                                   /(double)CYCLES_PER_FRAME)
                                   *(double)WAVE_FORMAT_SAMPLESPERSEC)
                                   /(double)MICROSEC_PER_SEC;
   
    size += remain-(double)((int)remain);
    remain = size;

    /* write signal */
    for (i=0; i<(int)size; i++)
    {
        fputc (current_value&0xff, file );
        fputc ((current_value>>8)&0xff, file );
    }

    /* invert signal */
    current_value=~current_value;

    cycles = 0;
}



static void write_byte_standard (char byte, FILE *file)
{
    int bit;
   
    /* 4     LF1AF  STA    <$2045
       2            LDB    #$08  */
    cycles += 4+2;
    for (bit=0x80; bit>0; bit>>=1)
    {
        /* 7     LF1B3  BSR    LF1CB
           2     LF1CB  LDA    #$40
           4+0          EORA    ,U
           4+0          STA     ,U  */
        cycles += 7+2+4+4;
        write_signal (file);
        /* 5            RTS
           3            LDX    #$002D
           7            BSR    LF1A2
           4+1   LF1A2  LEAX   -$01,X
           3            BNE    LF1A2
           2            CLRA
           5            RTS
           3            LDX    #$0032
           6            ASL    <$2045
           3            BCC    LF1C5  */
        cycles += 5+3+7+(0x2d*(4+1+3))+2+5+3+6+3;

        if (((int)byte & bit) == 0)
        {
            /* 7     LF1C5  BSR    LF1A2
               4+1   LF1A2  LEAX   -$01,X
               3            BNE    LF1A2
               2            CLRA
               5            RTS       */
            cycles += 7+(0x32*(4+1+3))+2+5;
        }
        else
        {
            /* 7            BSR    LF1CB
               2     LF1CB  LDA    #$40
               4+0          EORA   ,U
               4+0          STA    ,U   */
            cycles += 7+2+4+4;
            write_signal (file);
            /* 5            RTS
               4+1          LEAX   -$03,X
               7     LF1C5  BSR    LF1A2
               4+1   LF1A2  LEAX   -$01,X
               3            BNE    LF1A2
               2            CLRA
               5            RTS    */
            cycles += 5+4+1+7+((0x32-3)*(4+1+3))+2+5;
        }
        /* 2            DECB
           3            BNE    LF1B3  */
        cycles += 5;
    }
    /* 5            RTS   */
    cycles += 5;
}



static void write_byte_modified (char byte, FILE *file)
{
    int bit;
   
    /* 4     LF1AF  STA    <$2045
       2            LDB    #$08  */
    cycles += 4+2;
    for (bit=0x80; bit>0; bit>>=1)
    {
        /* 7     LF1B3  BSR    LF1CB
           2     LF1CB  LDA    #$40
           4+0          EORA    ,U
           4+0          STA     ,U  */
        cycles += 7+2+4+4;
        write_signal (file);
        cycles += 269;

        if (((int)byte & bit) == 1)
        {
            write_signal (file);
        }
        cycles += 564;

        /* 2            DECB
           3            BNE    LF1B3  */
        cycles += 5;
    }
    /* 5            RTS   */
    cycles += 5;
}



static void write_byte (char byte, FILE *file)
{
    if (flag_modified == FALSE)
        write_byte_standard (byte, file);
    else
        write_byte_modified (byte, file);
}



#define STOCK_LENGTH  40
#define MOTOR_STOPS_AFTER_THIS_BLOCK 0x01
#define MOTOR_STOPS_AFTER_DATA_BLOCK 0x02

static void convert_file (FILE *bin_file, FILE *wav_file)
{
    static char stock[STOCK_LENGTH];
    static size_t length = 0;
    static size_t size = 0;
    static int motor_status = 0;
    char dcmoto_mark1[] = "DCMOTO\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
    char dcmoto_mark2[] = "\xdc\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
    char basic_mark[]   = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";

    do
    {
        if ((length < STOCK_LENGTH) && (feof (bin_file) == 0))
        {
            size = fread(stock+length, 1, STOCK_LENGTH-length, bin_file);
            length += size;
        }

        if (length > 19)
        {
            if ((memcmp (dcmoto_mark1, stock, 18) == 0)
             || (memcmp (dcmoto_mark2, stock, 18) == 0)
             || (memcmp (basic_mark, stock, 18) == 0))
            {
                if (motor_status != 0)
                {
                    write_motoroff (wav_file);
                    motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
                }
                memset (stock, 0x01, 6);

                cycles = 0;
                remain = 0;

                if (stock[18] == '\0')
                {
                    write_motoron (wav_file);
                    motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
                    if ((length > (18+2+0x0d)) && (stock[18+2+0x0d] != '\0'))
                    {
                        motor_status |= MOTOR_STOPS_AFTER_DATA_BLOCK;
                    }
                    motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
                }
                else
                {
                    if ((motor_status & MOTOR_STOPS_AFTER_DATA_BLOCK) != 0)
                    {
                        write_motoron (wav_file);
                    }
                    else
                    {
                        write_data_gap (wav_file);
                    }

                    if (stock[18] == '\xff')
                    {
                        motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
                        motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
                    }
                    else
                    {
                        motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
                    }
                }
            }
        }
        cycles += 4+2+7;  /* For preparing data to be written */
        write_byte (*stock, wav_file);
        cycles += 6+3;    /* For the loop */

        memmove (stock, stock+1, STOCK_LENGTH-1);
        length--;
    } while (length > 0);
}



static void write_le4 (int value, FILE *file)
{
    fputc( value&0xff, file );
    fputc( (value>>8)&0xff, file );
    fputc( (value>>16)&0xff, file );
    fputc( (value>>24)&0xff, file );
}



static void write_le2 (int value, FILE *file)
{
    fputc( value&0xff, file );
    fputc( (value>>8)&0xff, file );
}



static void write_id (char *id, FILE *file)
{
    int size = fwrite (id, 1, 4, file);
    (void)size;
}



static void update_wav_header (char *filename)
{
    FILE *file;
    struct stat st;

    stat( filename, &st );

    file = fopen (filename, "rb+");
    if (file != NULL)
    {
        write_id  ("RIFF", file);
        write_le4 ((int)st.st_size-WAVE_RIFF_CHUNK_SIZE, file);
        write_id  ("WAVE", file);
        write_id  ("fmt ", file);
        write_le4 (WAVE_FORMAT_CHUNK_SIZE, file);
        write_le2 (WAVE_FORMAT_PCM, file);
        write_le2 (WAVE_FORMAT_CHANNELS, file);
        write_le4 (WAVE_FORMAT_SAMPLESPERSEC, file);
        write_le4 (WAVE_FORMAT_AVGBYTEPERSEC, file);
        write_le2 (WAVE_FORMAT_BLOCKALIGN, file);
        write_le2 (WAVE_FORMAT_BITPERSAMPLE, file);
        write_id  ("data", file);
        write_le4 ((int)st.st_size-WAVE_HEADER_SIZE, file);
        fclose (file);
    }
}



static void write_wav (char *bin_name, char *wav_name)
{
    int i;
    FILE *bin_file;
    FILE *wav_file;

    bin_file = fopen (bin_name, "rb");
    if (bin_file != NULL)
    {
        wav_file = fopen (wav_name, "wb");
        if (wav_file != NULL)
        {
            /* Create WAV header gap */
            for (i=0; i<WAVE_HEADER_SIZE; i++)
            {
                fputc (0x00, wav_file);
            }

            /* Write WAV data */
            write_motoron (wav_file);
            convert_file (bin_file, wav_file);
            write_motoroff (wav_file);
            fclose (wav_file);
            update_wav_header (wav_name);
        }
        else
        {
            printf ("*** Can not write file %s\n", wav_name);
        }
        fclose (bin_file);
    }
    else
    {
        printf ("*** Can not read file %s\n", bin_name);
    }
}



static int info (void)
{
    printf ("k5towav (c) Prehisto feb 2015\n");
    printf ("     Usage : k5towav [--modified] <filename>\n");
    return EXIT_FAILURE;
}



int main (int argc, char *argv[])
{
    int i;
    char bin_name[300] = "";
    char wav_name[300] = "";

    for (i=1; i<argc; i++)
    {
        if (argv[i][0] == '-')
        {
            if (strcmp (argv[i], "--modified") == 0)
            {
                flag_modified = TRUE;
            }
            else
            {
                printf ("*** option '%s' unknown\n", argv[i]);
                return info ();
            }
        }   
        else
        {
            if (*bin_name == '\0')
            {
                strcpy(bin_name, argv[i]);
            }
            else
            {
                return info ();
            }
        }
    }

    sprintf (wav_name, "%s.wav", bin_name);

    write_wav (bin_name, wav_name);

    return EXIT_SUCCESS;
}


Conclusion: The K7 file format is just bad. Good to convert from a WAV, but totally inappropriate to convert into a WAV, especially if the file is corrupted by emulator adaptation to get round protections, like games. It is time to save the hard content of Thomson compact cassettes before it's too late...

EDIT 20 feb 2015 15:56 : The program recognizes now few DCMOTO marks. But, except to correct bugs, I will not go further. This program is just an example.
EDIT 20 feb 2015 19:47 : Bug correction. MICROSEC_PER_FRAME was increased by 10 in the calculation of 'size' in write_signal() , what was useless. Just a trace of test.
EDIT 21 feb 2015 21:51 : Simplify the code.
EDIT 21 feb 2015 22:53 : Correction of offset, condition and compilation error.
EDIT 22 feb 2015 18:27 : Simplify the code.

Auteur:  W_oo_d [ 21 Fév 2015, 22:04 ]
Sujet du message:  Re: MO6 problems loading files

Great job Prehisto! Thanks for all the info. :D

Auteur:  PulkoMandy [ 15 Mar 2015, 07:26 ]
Sujet du message:  Re: MO6 problems loading files

I made a modified version of this tool for my own use. It may not be suitable for everyone, but here it goes:
http://pulkomandy.tk/projects/thomson/log/Thomson/tools/k5towav/k5towav.c

[*]Reduced the WAV sample rate to 11025Hz (44100/4). The generated files are 4 times smaller and they still load fine.
[*]Doubled the speed of everything to use the MO6 tape format instead of the MO5 one (this should be done more cleanly). This makes the file even smaller and it loads faster.
[*]Recognize the "DCMO6" marker in block headers.
[*]Increase the "motor off" gap to have better compatibility with setups where the "motor off" command doesn't work (when using a "line in" tape adapter for example). It would be a good idea to output separate files for each "motor off block", so it's easier to navigate between the files.

Auteur:  Prehisto [ 15 Mar 2015, 09:22 ]
Sujet du message:  Re: MO6 problems loading files

PulkoMandy a écrit:
[*]Reduced the WAV sample rate to 11025Hz (44100/4). The generated files are 4 times smaller and they still load fine.

Great. But reducing the WAV sample rate reduces the precision of the signal also. Not sure it is a good idea to make it more approximate than it could be. Just zip the 44100Hz WAV file if you really need to spare hard disk occupation.

Auteur:  Zaxxon [ 16 Nov 2015, 23:41 ]
Sujet du message:  Re: MO6 problems loading files

Bonsoir amis Thomsonistes (ça fait un bail que je ne suis pas venu sur ce forum :) )

Merci Prehisto et PulkoMandy pour ces sources.

Je viens de délaisser mon TO7 /70 pour mon MO5 (question de place), et je suis en pleine tentative de création de fichiers wav à partir de fichiers k7 récupérés un peu partout sur le net (je suis un nouveau sur MO5 :D).

J'ai modifié le lecteur de cassette du mo5 en lui rajoutant une prise jack (Si cela intéresse quelqu'un je pourrais expliquer la manip simple à faire, j'ai même pris des photos) : 2 résistances, une led, une prise jack, 2 soudures et ça roule (J'ai abandonné la partie audio, il semblerait que j'ai une boucle de masse, et c'est horrible le son).

J'ai essayé l'utilitaire de Daniel, qui fonctionne bien (Merci à lui aussi) quand les k7s ont un checksum correct (ce qui n'est pas toujours le cas de mes k7) mais qui ne m'arrange pas car sous Windows, et n'accepte qu'un fichier à la fois.

Avec ce source, je pourrais faire une conversion en masse en ligne de commande :bien:

Je viens d'essayer avec Karate, j'ai deux versions différentes en k7 (renommées en k5). Avec l'utilitaire de Daniel, j'arrive à charger le wav généré et exécuter le jeu (une de mes deux versions du jeu, l'autre ayant un checksum incorrect apparemment).

Cependant avec ce source (recompilé sous fedora), je n'ai que le loader d'intro (Pas celle avec le karatéka, celle d'avant avec le tatou Infogrammes), le programme ne s’arrête jamais de charger :-(

Quelqu'un aurait-il une idée? j'ai essayé de régler le volume, rien n'y fait .

Je vous remercie, et bonne soirée :)

Edit : Désolé je viens de me rendre compte que j'avais répondu en Français, si cela pose problème, n'hésitez pas à me le dire, j'essaierai de traduire en Anglais.

Auteur:  Prehisto [ 17 Nov 2015, 00:31 ]
Sujet du message:  Re: MO6 problems loading files

Daniel a introduit dans ses fichiers k7 des codes spéciaux. Le source ne traite pas ces codes. Donc la conversion aura de la peine à se faire. Qui plus est, comme je l'explique dans mon petit laïus plus haut, les fichiers k7 de Daniel ont été altérés pour fonctionner sur l'émulateur DCMOTO. Donc, le MO5 ne comprendra pas certains codes machine rencontrés, même si la conversion du k7 vers le WAV est correcte.

Page 1 sur 3 Heures au format UTC + 1 heure
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/