home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / emulate / d64.lha / d64.c < prev    next >
C/C++ Source or Header  |  1993-02-27  |  10KB  |  291 lines

  1. /********************************\
  2. *      >>> DATASETTE 64 <<<      *
  3. *--------------------------------*
  4. *  ©1993 by ARTSOFT Productions  *
  5. *           Holger Schemel       *
  6. *           Sennehof 28          *
  7. *           4800 Bielefeld 12    *
  8. *           Tel.: (0521) 493245  *
  9. *--------------------------------*
  10. *  LAST UPDATE:   27/02/93       *
  11. \********************************/
  12.  
  13. /************************************************************\
  14. * >>> Programm zum Einlesen von C64-Datasettenprogrammen <<< *
  15. *------------------------------------------------------------*
  16. * Programm konvertiert C64-Programme, die im TURBO TAPE 64 - *
  17. * Format auf Magnetkassetten gespeichert sind. Um diese auf  *
  18. * C64-Emulatoren wie "TheA64Package" oder "The 64 Emulator"  *
  19. * verwenden zu können, wenn zur Konvertierung kein C64, ge-  *
  20. * schweige denn eine Datasette, mehr zur Verfügung steht,    *
  21. * muß das Programm zunächst mit einem Kassettenrecorder bzw. *
  22. * einem Tapedeck sowie einem handelsüblichen Sounddigitizer  *
  23. * mit maximaler Samplefrequenz (über 40 kHz) digitalisiert   *
  24. * werden (z.B. mit Audiomaster). Der Anfang des Samples muß  *
  25. * alsdann maximal vergrößert (Audiomaster: 599 Bytes) werden *
  26. * und der Anfang mit 'Cut' soweit abgeschnitten werden, daß  *
  27. * sowohl das anfängliche Bandrauschen als auch Tonschwankun- *
  28. * gen (Welle liegt kurzzeitig völlig über oder unter der     *
  29. * Mittellinie) vollständig beseitigt sind. Vom Anfang kann   *
  30. * ruhig ein Teil des Synchronisationssignales fehlen. Fängt  *
  31. * nun das Sample mit einer Folge von sieben kleineren und    *
  32. * einer größeren Welle an, kann es abgespeichert und mit dem *
  33. * Programm 'Datasette64' behandelt werden.                   *
  34. *------------------------------------------------------------*
  35. * Aufbau einer TurboTape64-Datei:                            *
  36. * """""""""""""""""""""""""""""""                            *
  37. * 1. Synchonisation:                                         *
  38. *    - 5 mal (246 mal Byte 2)                                *
  39. *    - Countdownbytes 9,8,7,6,5,4,3,2,1                      *
  40. * 2. Vorspann:                                               *
  41. *    - Sekundäradresse 1                                     *
  42. *    - Low- und Highbyte der Startadresse                    *
  43. *    - Low- und Highbyte der Endadresse                      *
  44. *    - Füllbyte (0)                                          *
  45. *    - Dateiname                                             *
  46. *    - Rest wird auf 193 Zeichen mit SPACE aufgefüllt        *
  47. * 3. Synchonisation:                                         *
  48. *    - 2 mal (246 mal Byte 2)                                *
  49. *    - Countdownbytes 9,8,7,6,5,4,3,2,1                      *
  50. *    - Null-Byte                                             *
  51. * 4. Daten                                                   *
  52. * 5. Prüfsumme: EXOR aller Datenbytes (255 mal)              *
  53. *                                                            *
  54. *------------------------------------------------------------*
  55. * Um sich das manuelle Entfernen des einleitenden Bandrau-   *
  56. * schens zu ersparen, empfiehlt es sich, das Bandlaufwerk    *
  57. * einige Umdrehungen vor Beginn der Aufzeichnung zu starten  *
  58. * (wobei sich der Bandlauf stabilisieren kann) und den Digi- *
  59. * talisiervorgang zu beginnen, wenn der Synchronisationston  *
  60. * ertönt. Der Ton bzw. das Signal ist lang genug, um vorne   *
  61. * etwas verkürzt werden zu können.                           *
  62. *------------------------------------------------------------*
  63. * Erhält man die Meldung "Prüfsumme OK!", so wurde die Datei *
  64. * vollständig korrekt gelesen. Die Meldung "Prüfsummenfeh-   *
  65. * ler" kann zwei Gründe haben:                               *
  66. * - Ein oder mehrere Bits wurden falsch erkannt              *
  67. * - Ein oder mehrere Bits fehlen oder sind zuviel            *
  68. * Während der erste Fall nur ein falsches Byte nach sich     *
  69. * zieht, führt der zweite zu einem bitweise verschobenen     *
  70. * Programm, das ab der Fehlerstelle unbrauchbar ist. Meist   *
  71. * gibt das Programm dann Wellenlängenabweichungsfehler aus,  *
  72. * die oftmals von Hand korrigiert werden können, da die Po-  *
  73. * sition des Fehlers in der Sampledatei genannt wird.        *
  74. \************************************************************/
  75.  
  76. #include <exec/memory.h>
  77. #include <libraries/dos.h>
  78.  
  79. extern VOID *Open(), *AllocMem();
  80. extern LONG Read(), Seek(), Write();
  81. extern VOID Chk_Abort();
  82. extern WORD Enable_Abort;
  83. UBYTE *Lower2Upper();
  84. UBYTE ScanBit();
  85. UBYTE ScanByte();
  86.  
  87. #define ENDOFFILE       (ptr>=max)
  88. #define SCANWHILE(cond) while(ptr<max && (cond))
  89.  
  90. struct DatasetteFileHeader
  91. {
  92.    UBYTE FileAddress2;
  93.    UBYTE startlow;
  94.    UBYTE starthigh;
  95.    UBYTE endlow;
  96.    UBYTE endhigh;
  97.    UBYTE filler;
  98.    UBYTE filename[187];
  99. } DSHeader;
  100.  
  101. BYTE dbyte,check;
  102. BYTE synctab[100],synccnt,hisync,losync,sync,halfsync,doubsync;
  103. BYTE *ptr,*max,*fptr,*hptr,*FileBuf1=0,*FileBuf2=0;
  104. UWORD *file1=0,*file2=0;
  105. ULONG len1,len2,FileLen1,FileLen2;
  106. LONG i;
  107.  
  108. main(argc,argv)   /*------------ HAUPTPROGRAMM ------------*/
  109. WORD argc;
  110. BYTE *argv[];
  111. {
  112.    if (argc<3 || *argv[1]=='?')
  113.       CloseAll("Usage: Datasette64 <tape file> <disk file> [<sync>]");
  114.  
  115.    printf("SEARCHING FOR %s\n",Lower2Upper(argv[1]));
  116.    if (!(file1=Open(argv[1],MODE_OLDFILE)))
  117.       CloseAll("?FILE NOT FOUND ERROR");
  118.    Seek(file1,0L,OFFSET_END);
  119.    FileLen1=Seek(file1,0L,OFFSET_BEGINNING);
  120.    printf("LOADING\n");
  121.    if (!(ptr=FileBuf1=AllocMem(FileLen1,MEMF_PUBLIC)))
  122.       CloseAll("?OUT OF MEMORY ERROR");
  123.    len1=Read(file1,FileBuf1,FileLen1);
  124.    max=FileBuf1+(BYTE *)len1;
  125.    Close(file1); file1=0;
  126.    Chk_Abort();
  127.  
  128.    if (Equal(ptr,"FORM"))     /* IFF-Datei? */
  129.    {
  130.       SCANWHILE(!Equal(ptr,"BODY")) ptr++;
  131.       if (!ENDOFFILE)
  132.       {
  133.          ptr+=4;
  134.          max=ptr+(BYTE *)(*(ULONG *)ptr)+4L;
  135.          ptr+=4;
  136.       }
  137.       else ptr=FileBuf1;
  138.    }
  139.  
  140.    SCANWHILE(*ptr>=0) ptr++;  /* Erste vollständige positive */
  141.    SCANWHILE(*ptr< 0) ptr++;  /* Zahlenreihe suchen          */
  142.  
  143.    synccnt=0;
  144.    SCANWHILE(synccnt<100)     /* Wellenlängen 0/1-Bits ermitteln */
  145.    {
  146.       synctab[synccnt]=0;
  147.       SCANWHILE(*ptr>=0) { synctab[synccnt]++; ptr++; }
  148.       SCANWHILE(*ptr< 0) { synctab[synccnt]++; ptr++; }
  149.       synccnt++;
  150.    }
  151.    hisync=losync=synctab[0];
  152.    for(i=1;i<synccnt;i++)
  153.    {
  154.       if (synctab[i]>hisync) hisync=synctab[i];
  155.       if (synctab[i]<losync) losync=synctab[i];
  156.    }
  157.    sync=(hisync+losync)/2;    /* Vergleichswert: "0"<sync<"1" */
  158.  
  159.    if (argc==4)
  160.    {
  161.       printf("Ermittelter Sync-Wert: %d\n",sync);
  162.       if (*argv[3]!='?') sync=atoi(argv[3]);
  163.       printf("-->Sync: <%d>>> %d <<<%d>\n",losync,sync,hisync);
  164.    }
  165.    halfsync=sync-2*(sync-losync);
  166.    doubsync=sync+2*(hisync-sync);
  167.  
  168.    SCANWHILE(!ScanBit());     /* Synchronisationsanfang suchen: */
  169.    ScanBit();                 /* ?-mal Byte 2 = %00000010       */
  170.  
  171.    SkipSync();                /* Erste Synchronisation überspringen */
  172.  
  173.    hptr=(BYTE *)&DSHeader;
  174.    for(i=0;i<193;i++) *hptr++=ScanByte();
  175.  
  176.    printf("-->Header:\n");
  177.    printf("   - Sekundäradresse: %d\n",DSHeader.FileAddress2);
  178.    printf("   - Startadresse LO: %d\n",DSHeader.startlow);
  179.    printf("   - Startadresse HI: %d\n",DSHeader.starthigh);
  180.    printf("   - Endadresse   LO: %d\n",DSHeader.endlow);
  181.    printf("   - Endadresse   HI: %d\n",DSHeader.endhigh);
  182.    dbyte=DSHeader.filename[40];
  183.    DSHeader.filename[40]=0;
  184.    printf("   - Dateiname      : %s\n",DSHeader.filename);
  185.    DSHeader.filename[40]=dbyte;
  186.  
  187.    SkipSync();                /* Zweite Synchronisation überspringen */
  188.    if (ScanByte()) CloseAll("?LOAD ERROR");
  189.  
  190.    len2=DSHeader.endhigh*256+DSHeader.endlow;
  191.    len2-=DSHeader.starthigh*256+DSHeader.startlow;
  192.    FileLen2=len2+2L;
  193.    if (!(fptr=FileBuf2=AllocMem(FileLen2,MEMF_PUBLIC)))
  194.       CloseAll("?OUT OF MEMORY ERROR");
  195.  
  196.    *fptr++=0x01;
  197.    *fptr++=0x08;
  198.    check=0;
  199.  
  200.    SCANWHILE(len2--) check^=(*fptr++=(BYTE)ScanByte());
  201.    if (ENDOFFILE) CloseAll("?OUT OF DATA ERROR");
  202.  
  203.    if (check==ScanByte()) printf("-->Prüfsumme OK!\n");
  204.    else                   printf("-->Prüfsummenfehler!\n");
  205.  
  206.    if (!(file2=Open(argv[2],MODE_NEWFILE)))
  207.       CloseAll("?OPEN ERROR");
  208.    printf("SAVING\n");
  209.    if (Write(file2,FileBuf2,FileLen2)<0)
  210.       CloseAll("?WRITE ERROR");
  211.    Close(file2); file2=0;
  212.  
  213.    CloseAll(0L);
  214. }
  215.  
  216. UBYTE *Lower2Upper(str)
  217. UBYTE *str;
  218. {
  219.    static UBYTE up[40];
  220.    register BYTE z;
  221.  
  222.    for(z=0;*str && z<40;z++,str++) up[z]=toupper(*str);
  223.    return(up);
  224. }
  225.  
  226. Equal(p,s)
  227. UBYTE *p,*s;
  228. {
  229.    UBYTE *sp=s;
  230.    WORD rc=1;
  231.  
  232.    while(*s) if(*p++!=*s++) rc=0;
  233.    return(rc);
  234. }
  235.  
  236. UBYTE ScanBit()
  237. {
  238.    register WORD scnt=0;
  239.    static WORD cnt=0;
  240.  
  241.    if (cnt++>25) { Chk_Abort(); cnt=0; }
  242.    SCANWHILE(*ptr>=0) { scnt++; ptr++; }
  243.    SCANWHILE(*ptr< 0) { scnt++; ptr++; }
  244.    if (scnt<halfsync || scnt>doubsync)
  245.      printf("-->Wellenlängeninkonsistenz in Byte %ld\n",(LONG)ptr-FileBuf1);
  246.  
  247.    return(scnt>sync);
  248. }
  249.  
  250. UBYTE ScanByte()
  251. {
  252.    register UBYTE i,sbyte=0;
  253.  
  254.    for(i=0;i<8;i++)
  255.    {
  256.       sbyte<<=1;
  257.       sbyte|=ScanBit();
  258.    }
  259.    return(sbyte);
  260. }
  261.  
  262. SkipSync()
  263. {
  264.    register UBYTE i,sbyte=0;
  265.  
  266.    SCANWHILE((sbyte=ScanByte())==0x02);   /* Syncbytes überspringen */
  267.    for(i=9;i>0;i--)                       /* Countdown prüfen       */
  268.    {
  269.       if (i<9) sbyte=ScanByte();
  270.       if (sbyte!=i) CloseAll("?LOAD ERROR");
  271.    }
  272. }
  273.  
  274. void _abort()
  275. {
  276.    CloseAll("*** User Break");
  277. }
  278.  
  279. CloseAll(txt)
  280. UBYTE *txt;
  281. {
  282.    if (FileBuf1) FreeMem(FileBuf1,FileLen1);
  283.    if (FileBuf2) FreeMem(FileBuf2,FileLen2);
  284.    if (file1) Close(file1);
  285.    if (file2) Close(file2);
  286.    if (txt) printf("%s\n",txt);
  287.    printf("READY.\n");
  288.    exit(txt!=0L);
  289. }
  290.  
  291.