/*
    ZEsarUX  ZX Second-Emulator And Released for UniX
    Copyright (C) 2013 Cesar Hernandez Bano

    This file is part of ZEsarUX.

    ZEsarUX is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

/*

Contains code from PlayTZX for Linux

Version v0.12c by Philip Kendall 2005-05-16
Based very heavily on original PlayTZX v0.56b by Tomaz Kac 1998

*/


#include "audio.h"
//#include "au-file.h"

/* .au file things for TZX-stuff
 *
 * Created 27.10.1997 by Tero Turtiainen
 *
 * I was too lazy to make this little/big-endian independant. I will do it
 * later
 */

typedef struct
{
    int magic;               /* magic number SND_MAGIC */
    int dataLocation;        /* offset or pointer to the data */
    int dataSize;            /* number of bytes of data */
    int dataFormat;          /* the data format code */
    int samplingRate;        /* the sampling rate */
    int channelCount;        /* the number of channels */
    char info[4];            /* optional text information */
} SNDSoundStruct;

#define SND_MAGIC 0x2e736e64

#define SND_FORMAT_LINEAR_8 2


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

#include "debug.h"
#include "utils.h"

#define HTYPES  0x10
#define HIDS    0x1E

char htype[HTYPES][256]=                {

    "Computer","External Storage","ROM/RAM Type Add-On","Sound Device",
    "Joystick","Mouse","Other Controller","Serial Port","Parallel Port",
    "Printer","Modem","Digitiser","Network Adapter","Keyboard or Keypad",
    "AD/DA Converter","EPROM Programmer"
};
char hid[HTYPES][HIDS][256]={
    {
        "ZX Spectrum 16k", "ZX Spectrum 48k, plus","ZX Spectrum 48k Issue 1",
        "ZX Spectrum 128k (Sinclair)","ZX Spectrum 128k +2 (Grey case)",
        "ZX Spectrum 128k +2A, +3","Timex Sinclair TC-2048",
        "Timex Sinclair TS-2068","Pentagon 128","Sam Coupe","Didaktik M",
        "Didaktik Gama","ZX-81 with 1k RAM","ZX-81 with 16k RAM or more",
        "ZX Spectrum 128k, Spanish version","ZX Spectrum, Arabic version",
        "TK 90-X","TK 95","Byte","Elwro","ZS Scorpion",
        "Amstrad CPC 464","Amstrad CPC 664","Amstrad CPC 6128",
        "Amstrad CPC 464+","Amstrad CPC 6128+","Jupiter ACE",
        "Enterprise", "Commodore 64", "Commodore 128"
    },
    {
        "Microdrive","Opus Discovery","Disciple","Plus-D",
        "Rotronics Wafadrive","TR-DOS (BetaDisk)","Byte Drive","Watsford",
        "FIZ","Radofin","Didaktik disk drives","BS-DOS (MB-02)",
        "ZX Spectrum +3 disk drive","JLO (Oliger) disk interface",
        "FDD3000","Zebra disk drive","Ramex Millenia","Larken"
    },
    {
        "Sam Ram","Multiface","Multiface 128k","Multiface +3","MultiPrint",
        "MB-02 ROM/RAM expansion"
    },
    {
        "Classic AY hardware (compatible with 128k ZXs)",
        "Fuller Box AY sound hardware","Currah microSpeech","SpecDrum",
        "AY ACB stereo; Melodik","AY ABC stereo"
    },
    {
        "Kempston","Cursor, Protek, AGF","Sinclair 2 Left",
        "Sinclair 1 Right","Fuller"
    },
    { "AMX Mouse","Kempston mouse" },
    { "Trickstick","ZX Light Gun","Zebra Graphics Tablet" },
    { "ZX Interface 1","ZX Spectrum 128k" },
    {
        "Kempston S","Kempston E","ZX Spectrum +3","Tasman","DK'Tronics",
        "Hilderbay","INES Printerface","ZX LPrint Interface 3",
        "MultiPrint","Opus Discovery","Standard 8255 chip"
    },
    {
        "ZX Printer, Alphacom 32 & Compatibles","Generic Printer",
        "EPSON Compatible"
    },
    { "VTX 5000","T/S 2050 or Westridge 2050" },
    { "RD Digital Tracer","DK'Tronics Light Pen","British MicroGraph Pad" },
    { "ZX interface 1" },
    { "Keypad for ZX Spectrum 128k" },
    { "Harley Systems ADC 8.2","Blackboard Electronics" },
    { "Orme Electronics" }
};


/* Major revision of the format this program supports */
#define MAJREV 1

/* Minor revision of the format this program supports */
#define MINREV 13

/* C64 Loader defines ...*/

#define ROM_S_HALF      616	/* ROM Loader SHORT  Half Wave */
#define ROM_M_HALF      896	/* ROM Loader MEDIUM Half Wave */
#define ROM_L_HALF      1176	/* ROM Loader LONG   Half Wave */

#define STT_0_HALF      426	/* Standard Turbo Tape BIT 0 Half Wave */
#define STT_1_HALF      596	/* Standard Turbo Tape BIT 1 Half Wave */

int playtzx_Error(char *errstr)
{
    /* exits with an error message *errstr */

    debug_printf (VERBOSE_ERR,"Error: %s", errstr);
    return 1;

}



int n, m;
int num;
char *d;
int line = 3;
//int fh;				/* Input File Handle */

FILE *ptr_archivo_entrada;

int ofh;			/* Output File Handle */
int flen;			/* File Length */

unsigned char *mem;		/* File in Memory */
unsigned char *memorig;		/* Valor de mem justo al asignar memoria */

int pos;			/* Position in File */
int curr;			/* Current block that is playing */
int numblocks;			/* Total Num. of blocks */
int *block = NULL;		/* Array of Block starts */
/*size_t*/ int blocks_allocated = 0;	/* The current size of the block[] array */
double cycle;			/* Freq/3500000 */

char *sbbuf[2];			/* SB Buffers */
int sbbuflen = 1024;		/* Length of buffers */
int freq = 44100;		/* Sample Freq.  (SHOULD THIS BE 45454 ????) NOT !!! */
int sbcurrpage = 1;		/* Buffer that is currently available for writing */
int sbpos = 0;			/* Position in the buffer */
int amp;			/* Amplitude of the current signal */
int prvi;

int cpc = 0;			/* Amstrad CPC tape ? */
int sam = 0;			/* SAM Coupe tape ? */

int id;				/* Current Block ID */
int pilot;			/* Len of Pilot signal (in hp's) */
int sb_pilot;			/* Pilot pulse */
int sb_sync1;			/* Sync first half-period (hp) */
int sb_sync2;			/* Sync second */
int sb_bit0;			/* Bit-0 */
int sb_bit1;			/* Bit-1 */
int sb_pulse;			/* Pulse in Sequence of pulses and direct recording block */
int lastbyte;			/* How many bits are in last byte of data ? */
int tzx_pause;			/* Pause after current block (in 1s/10) */
unsigned char *data;			/* Data to be played */
int datalen;			/* Len of ^^^ */
int datapos;			/* Position in ^^^ */
int bitcount;			/* How many bits to play in current byte ? */
int sb_bit;			/* should we play bit 0 or 1 ? */
char databyte;			/* Current Byte to be replayed of the data */
signed short jump;		/* Relative Jump */
int not_rec;			/* Some blocks were not recognised ?? */
int files = 0;			/* Number of Files on the command line */
char finp[255];			/* Input File  (First Command Line Option) */
char fout[255];			/* Output File (Second Command Line Option or First with .VOC) */
char errstr[255];		/* Error String */
int starting = 1;		/* starting block */
int ending = 0;			/* ending block */

int voc = 0;			/* Are we making a .VOC file ? */
int au = 0;			/* Are we making a .au file? */
int tzx_info = 0;			/* if info=1 then show EXTENSIVE information */
/* info=2 then show ONE LINE of Info per block */
int pages = 0;			/* Waiting after each page of the info ? */
int expand = 0;			/* Expand Groups ? */
int draw = 1;			/* Local flag for outputing a line when in a
group */
int mode128 = 0;		/* Are we working in 128k mode ? (for Stop in 48k block) */

char vochead[0x20] = {'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'V', 'o', 'i', 'c', 'e', ' ', 'F', 'i', 'l', 'e',
    0x1A, 0x1A, 0x00, 0x0A, 0x01, 0x29, 0x11};
    char *vocbuf;			/* Buffer for .VOC block */
    int vocbuflen = 0xFFFF;		/* Length of .VOC block (and buffer) */
    char vocstart[4] = {0x02, 0xFF, 0xFF, 0x00};
    int vocpos;			/* Length of current .VOC block */

    int nfreq = 0;			/* Did we choose new frequency with /freq switch ? */
    char k;
    int speed;
    int x, last, lastlen;

    int silence_beginning=0;

    int loop_start = 0;		/* Position of the last Loop Start block */
    int loop_count = 0;		/* Counter of the Loop */
    int call_pos = 0;		/* Position of the last Call Sequence block */
    int call_num = 0;		/* Number of Calls in the last Call Sequence block */
    int call_cur = 0;		/* Current Call to be made */
    int num_sel;			/* Number of Selections in the Select block */
    int jumparray[256];		/* Array of all possible jumps in Select block */

    int sb_bit0_f, sb_bit0_s, sb_bit1_f, sb_bit1_s, xortype, sb_finishbyte_f, sb_finishbyte_s,
    sb_finishdata_f, sb_finishdata_s, num_lead_in, xorvalue;
    int trailing, sb_trailing;
    char lead_in_byte;
    int endian;
    char add_bit;

    #define LOAMP   0x10		/* Low Level Amplitude */
    #define HIAMP   0xF0		/* High Level Amplitude */

    char tstr[255];
    char tstr2[255];
    char tstr3[255];
    char tstr4[255];
    char spdstr[255];
    char pstr[255];

    SNDSoundStruct auhead;  /* .au-file header */

    int numt, nump, t2;

    /* Conversion functions to get 2,3 and 4 byte words ...*/
    int
    Get2(unsigned char *mem)
    {
        return (mem[0] + (mem[1] * 256));
    }

    int
    Get3(unsigned char *mem)
    {
        return (mem[0] + (mem[1] * 256) + (mem[2] * 256 * 256));
    }

    int
    Get4(unsigned char *mem)
    {
        return (mem[0] + (mem[1] * 256) + (mem[2] * 256 * 256) + (mem[3] * 256 * 256 * 256));
    }

    /* This will convert a sampling value in Z80 T-States to samples for SoundBlaster/VOC output */
    int
    ConvSB(int n)
    {
        return ((int) (0.5 + (cycle * (double) n)));
    }

    //#define GetCh() getchar()

    #define GetCh() 0

    #define PLAYTZX_AUDIO_BUFFER_SIZE 4096
    unsigned char playtzx_audio_buffer[PLAYTZX_AUDIO_BUFFER_SIZE];
    int buf_index = 0;
    int audiofd;

    int
    FileLength(int fh)
    {
        int curpos, size;

        curpos = lseek(fh, 0, SEEK_CUR);
        size = lseek(fh, 0, SEEK_END);
        lseek(fh, curpos, SEEK_SET);
        return (size);
    }

    int
    kbhit()
    {
        return (1);
    }



    int
    lsb_write(int fh, int value)
    {
        char buffer[4];

        buffer[3] = value & 0xff;
        value >>= 8;

        buffer[2] = value & 0xff;
        value >>= 8;

        buffer[1] = value & 0xff;
        value >>= 8;

        buffer[0] = value & 0xff;

        return (write(fh, buffer, 4));
    }

    void
    PlayAU(char amp, int len)
    {

        /* Puts amplitude amp to .VOC file buffer for len time ... This .VOC file
         *buffer is also used for .au files */

        auhead.dataSize += len;

        while (len) {
            vocbuf[vocpos] = amp;

            len--;
            vocpos++;

            if (vocpos == vocbuflen) {	/* Do we need to write the buffer to the .VOC file ? */
                /* write(ofh, vocstart, 4); */

                write(ofh, vocbuf, vocbuflen);

                vocpos = 0;
            }
        }

    }

    void
    PlaySB(char amp, int len)
    {

        /* Puts amplitude amp to SoundBlaster buffer for len time (or calls PlayVOC if converting) ...*/
        /* This would be fun to do in C++ :)*/

        if (voc) {
            //PlayVOC(amp, len);
            return;
        }
        else if (au) {
            PlayAU(amp, len);
            return;
        }
        while (len) {
            playtzx_audio_buffer[buf_index++] = amp;

            len--;

            //if (buf_index == PLAYTZX_AUDIO_BUFFER_SIZE) {	/* Is the buffer full ? */
            //  flushSBBuffer();
            //}
        }

    }


    void
    PauseSB(char amp, int tzx_pause)
    {

        /* Waits for tzx_pause milliseconds*/
        int p;


        p = (int) ((((float) tzx_pause) * freq) / 1000.0);

        PlaySB(amp, p);

    }



    void
    InitAU()
    {

        /* Prepares AU file to be written to ... */
        auhead.magic = SND_MAGIC;
        auhead.dataLocation = 32;
        auhead.dataSize = 0;		/* will be filled when the file is written */
        auhead.dataFormat = SND_FORMAT_LINEAR_8;
        auhead.samplingRate = freq;
        auhead.channelCount = 1;
        /* head.info = '    '; */

        vocbuf = (char *) malloc(vocbuflen + 256);

        if (vocbuf == NULL) {
            free(memorig);
            playtzx_Error("Not enough memory to set up .VOC file buffer!");
            //return 1;
            return;
        }


        ofh = open(fout, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

        /* No meter cabecera AU
         * write(ofh, &auhead, 0x1A);	// this is propably rubbish now... :)
         *
         * // then go to position 32 from the beginning of the file
         * lseek(ofh, 32, SEEK_SET);
         */

        int i;
        char byte_to_write=0;
        for (i=0;i<silence_beginning;i++) write(ofh, &byte_to_write, 1);

        vocpos = 0;
    }

    void
    StopAU()
    {
        /* Finishes the au recording (writes the last buffer and puts the header to
         *the beginning of the file */

        if (vocpos) {
            write(ofh, vocbuf, vocpos);
        }


        /* Desactivar escritura cabecera AU
         * lseek(ofh, 0, SEEK_SET);
         *
         * // now write the header info in LSB-format
         *
         * lsb_write(ofh, auhead.magic);
         * lsb_write(ofh, auhead.dataLocation);
         * lsb_write(ofh, auhead.dataSize);
         * lsb_write(ofh, auhead.dataFormat);
         * lsb_write(ofh, auhead.samplingRate);
         * lsb_write(ofh, auhead.channelCount);
         */

        free(vocbuf);

        close(ofh);
    }

    void
    ToggleAmp()
    {
        /* Toggles the amplitude of the output*/

        if (amp == LOAMP)
            amp = HIAMP;
        else
            amp = LOAMP;
    }

    void
    PlayC64SB(int len)
    {
        PlaySB(amp, len);
        ToggleAmp();
        PlaySB(amp, len);
        ToggleAmp();
    }

    void
    GetC64ROMName(char *name, unsigned char *data)
    {
        char d;

        for (n = 0; n < 16; n++) {
            d = data[14 + n];
            if (d < 32 || d > 125)
                name[n] = ' ';
            else
                name[n] = d;
        }
        name[n] = 0;
    }

    char
    MirrorByte(char s)
    {
        return ((s << 7) + ((s << 5) & 64) + ((s << 3) & 32) + ((s << 1) & 16) + ((s >> 1) & 8) + ((s >> 3) & 4) + ((s >> 5) & 2) + (s >> 7));
    }

    void
    GetC64StandardTurboTapeName(char *name, unsigned char *data)
    {
        char d;

        for (n = 0; n < 16; n++) {
            d = data[15 + n];
            if (d < 32 || d > 125)
                name[n] = ' ';
            else
                name[n] = d;
        }
        name[n] = 0;
    }

    void
    IdentifyC64ROM(int pos, unsigned char *data, int type)
    {
        char name[255];

        /* Determine Loader type */
        if (sb_pilot == ROM_S_HALF && sb_sync1 == ROM_L_HALF && sb_sync2 == ROM_M_HALF &&
            sb_bit0_f == ROM_S_HALF && sb_bit0_s == ROM_M_HALF && sb_bit1_f == ROM_M_HALF &&
            sb_bit1_s == ROM_S_HALF && xortype == 0x01) {
            /* ROM Loader */
            if (data[0] == 0x89 && data[1] == 0x88 && data[2] == 0x87 && data[3] == 0x86 &&
                data[4] == 0x85 && data[5] == 0x84 && data[6] == 0x83 && data[7] == 0x82 &&
                data[8] == 0x81) {
                if (pos == 202) {
                    if (!type) {
                        strcpy(name, "Header: ");
                        GetC64ROMName(name + 8, data);
                    } else {
                        strcpy(name, "ROM Header: ");
                        GetC64ROMName(name + 12, data);
                    }
                } else {
                    if (!type) {
                        strcpy(name, "Data Block              ");
                    } else {
                        strcpy(name, "ROM: Data Block");
                    }
                }
                } else {
                    if (!type)
                        strcpy(name, "------------------------");
                    else
                        strcpy(name, "ROM: Last Block Repeated");
                }
                strcpy(tstr, name);
                strcpy(spdstr, "C64 ROM Data ");
                return;
            }
            if (!type)
                strcpy(tstr, "------------------------");
            else
                strcpy(tstr, "Unknown");
            strcpy(spdstr, "C64 Data     ");
    }

    void
    IdentifyC64Turbo(int pos, unsigned char *data, int type)
    {
        char name[255];

        /* Determine Loader type */
        if (sb_bit0 == STT_0_HALF && sb_bit1 == STT_1_HALF && lead_in_byte == 0x02) {
            /* Standard Turbo Tape Loader */
            if (data[0] == 0x09 && data[1] == 0x08 && data[2] == 0x07 && data[3] == 0x06 &&
                data[4] == 0x05 && data[5] == 0x04 && data[6] == 0x03 && data[7] == 0x02 &&
                data[8] == 0x01) {
                if (pos == 32 && data[9] != 0x00) {
                    if (!type) {
                        strcpy(name, "Header: ");
                        GetC64StandardTurboTapeName(name + 8, data);
                    } else {
                        strcpy(name, "TurboTape Header: ");
                        GetC64StandardTurboTapeName(name + 18, data);
                    }
                } else {
                    if (!type) {
                        strcpy(name, "------------------------");
                    } else {
                        strcpy(name, "TurboTape Data Block");
                    }
                }
                } else {
                    if (!type)
                        strcpy(name, "------------------------");
                    else
                        strcpy(name, "TurboTape Unknown");
                }
                strcpy(tstr, name);
                strcpy(spdstr, "C64 Turbo    ");
                return;
        }
        if (!type)
            strcpy(tstr, "------------------------");
        else
            strcpy(tstr, "Unknown");
        strcpy(spdstr, "C64 Data     ");
    }

    void
    Identify(int len, unsigned char *temp, int type)
    {
        int n, s;

        if (cpc) {
            if (temp[0] == 44) {
                if (!type)
                    s = 4;
                else
                    s = 0;

                strcpy(tstr, "    ");

                for (n = 0; n < 16; n++) {
                    if (temp[n + 1])
                        tstr[n + s] = temp[n + 1];
                    else
                        tstr[n + s] = ' ';
                }

                for (n = 0; n < 4; n++)
                    tstr[n + s + 16] = ' ';

                tstr[n + s + 16] = 0;

            } else {
                if (!type)
                    strcpy(tstr, "    ------------------  ");
                else
                    strcpy(tstr, "Headerless");
            }

            return;
        }
        if (sam) {
            if (temp[0] == 1 && (len > 80 && len < 84) && (temp[1] >= 0x10 && temp[1] <= 0x13)) {
                if (!type) {
                    s = 14;

                    switch (temp[1]) {
                        case 0x10:
                            strcpy(tstr, "    Program : ");
                            break;

                        case 0x11:
                            strcpy(tstr, " Num. Array : ");
                            break;

                        case 0x12:
                            strcpy(tstr, "Char. Array : ");
                            break;

                        case 0x13:
                            strcpy(tstr, "      Bytes : ");
                            break;

                    }
                } else {
                    switch (temp[1]) {
                        case 0x10:
                            strcpy(tstr, "Program : ");
                            s = 10;
                            break;

                        case 0x11:
                            strcpy(tstr, "Num. Array : ");
                            s = 13;
                            break;

                        case 0x12:
                            strcpy(tstr, "Char. Array : ");
                            s = 14;
                            break;

                        case 0x13:
                            strcpy(tstr, "Bytes : ");
                            s = 8;
                            break;

                    }
                }

                for (n = 0; n < 10; n++) {
                    if (temp[n + 2] > 31 && temp[n + 2] < 127)
                        tstr[n + s] = temp[n + 2];
                    else
                        tstr[n + s] = 32;
                }

                tstr[n + s] = 0;
            } else {
                if (!type)
                    strcpy(tstr, "    --------------------");	/* Not Header */
                    else
                        strcpy(tstr, "Headerless");
            }
            return;
        }
        if (temp[0] == 0 && (len == 19 || len == 20) && temp[1] < 4) {
            if (!type) {
                s = 14;

                switch (temp[1]) {
                    case 0x00:
                        strcpy(tstr, "    Program : ");
                        break;

                    case 0x01:
                        strcpy(tstr, " Num. Array : ");
                        break;

                    case 0x02:
                        strcpy(tstr, "Char. Array : ");
                        break;

                    case 0x03:
                        strcpy(tstr, "      Bytes : ");
                        break;

                }
            } else {
                switch (temp[1]) {
                    case 0x00:
                        strcpy(tstr, "Program : ");
                        s = 10;
                        break;

                    case 0x01:
                        strcpy(tstr, "Num. Array : ");
                        s = 13;
                        break;

                    case 0x02:
                        strcpy(tstr, "Char. Array : ");
                        s = 14;
                        break;

                    case 0x03:
                        strcpy(tstr, "Bytes : ");
                        s = 8;
                        break;
                }
            }

            for (n = 0; n < 10; n++) {
                if (temp[n + 2] > 31 && temp[n + 2] < 127)
                    tstr[n + s] = temp[n + 2];
                else
                    tstr[n + s] = 32;

            }

            tstr[n + s] = 0;
        } else {
            if (!type)
                strcpy(tstr, "    --------------------");	/* Not Header */
                else
                    strcpy(tstr, "Headerless");
        }

    }


    int
    getnumber(char *s)
    {
        /* Returns the INT number contained in string *s */

        int i;

        sscanf(s, "%d", &i);
        return (i);
    }


    void
    ChangeFileExtension(char *str, char *ext)
    {
        /* Changes the File Extension of String *str to *ext */
        int n;

        n = strlen(str);
        while (str[n] != '.')
            n--;

        n++;
        str[n] = 0;
        strcat(str, ext);
    }


    void
    invalidoption(char *s)
    {
        /* Prints the Invalid Option error */

        sprintf(errstr, "Invalid Option %s !", s);
        playtzx_Error(errstr);
        //return 1;
        return;
    }

    char *GetCheckSum(unsigned char *data, int len)
    {
        /* Calculates a XOR checksum for a block and returns a STRING containing the result*/
        unsigned char c = 0;
        int n;

        for (n = 0; n < len - 1; n++)
            c ^= data[n];

        if (c == data[len - 1])
            return ("OK");
        else {
            sprintf(pstr, "Wrong, should be %3d ($%02X)", c, c);
            return (pstr);
        }
    }


    void
    CopyString(char *dest, unsigned char *sour, int len)
    {
        /* Could just use strpy ... */
        int n;

        for (n = 0; n < len; n++)
            dest[n] = sour[n];
        dest[n] = 0;
    }


    void
    writeout(char *s)
    {
        /* Simple and not too accurate method of waiting after pages ...*/
        //char k;

        if (pages) {
            line++;
        }
        debug_printf(VERBOSE_INFO,s);
    }


    int
    MultiLine(char *s, int spaces, char *d)
    {
        /* This will convert a text which has lines separated by a single LF (13 dec)*/
        /* character to the text that can be outputed by MSDOS (LF NL) ... it will also*/
        /* Add a number of spaces to the beginning of each line (EXCEPT the first one -*/
        /* so you can use the Description: Text stuff ;) )*/
        /* NOTE: Some UNIX system like LINUX can cope with just LF char (13), some*/
        /*       other systems will need just CR char (10) ... experiment :)*/

        int n = 0;
        int m = 0;
        int i;
        int l = 0;

        while (s[n]) {
            if (s[n] == 13) {
                d[m] = 13;
                d[m + 1] = 10;		/* Here is the MS-DOS output for line-end */
                m += 2;
                for (i = 0; i < spaces; i++) {
                    d[m] = ' ';
                    m++;
                }

                l++;
            } else {
                d[m] = s[n];
                m++;
            }
            n++;

        }

        d[m] = 0;

        return (l);
    }

    void
    MakeFixedString(char *s, int i)
    {
        /* This will create a fixed length string from null-terminated one...*/

        int n = 0;
        int k = 0;

        while (i) {
            if (!s[n])
                k = 1;
            if (k)
                s[n] = ' ';
            n++;
            i--;
        }
        s[n] = 0;
    }

    void
    PlayC64ROMByte(char byte, int finish)
    {
        xorvalue = xortype;
        while (bitcount) {
            if (!endian)
                sb_bit = byte & 0x01;
            else
                sb_bit = byte & 0x80;
            if (sb_bit) {
                if (sb_bit1_f)
                    PlayC64SB(sb_bit1_f);
                if (sb_bit1_s)
                    PlayC64SB(sb_bit1_s);
                xorvalue ^= sb_bit;
            } else {
                if (sb_bit0_f)
                    PlayC64SB(sb_bit0_f);
                if (sb_bit0_s)
                    PlayC64SB(sb_bit0_s);
                xorvalue ^= sb_bit;
            }
            if (!endian)
                byte >>= 1;
            else
                byte <<= 1;
            bitcount--;
        }
        if (xortype != 0xFF) {
            if (xorvalue) {
                if (sb_bit1_f)
                    PlayC64SB(sb_bit1_f);
                if (sb_bit1_s)
                    PlayC64SB(sb_bit1_s);
            } else {
                if (sb_bit0_f)
                    PlayC64SB(sb_bit0_f);
                if (sb_bit0_s)
                    PlayC64SB(sb_bit0_s);
            }
        }
        if (!finish) {
            if (sb_finishbyte_f)
                PlayC64SB(sb_finishbyte_f);
            if (sb_finishbyte_s)
                PlayC64SB(sb_finishbyte_s);
        } else {
            if (sb_finishdata_f)
                PlayC64SB(sb_finishdata_f);
            if (sb_finishdata_s)
                PlayC64SB(sb_finishdata_s);
        }
    }

    void
    PlayC64TurboByte(char byte)
    {
        int add_num;

        add_num = add_bit & 3;
        if (add_num && !(add_bit & 4)) {
            while (add_num) {
                if (add_bit & 8)
                    PlayC64SB(sb_bit1);
                else
                    PlayC64SB(sb_bit0);
                add_num--;
            }
        }
        while (bitcount) {
            if (!endian)
                sb_bit = byte & 0x01;
            else
                sb_bit = byte & 0x80;
            if (sb_bit)
                PlayC64SB(sb_bit1);
            else
                PlayC64SB(sb_bit0);
            if (!endian)
                byte >>= 1;
            else
                byte <<= 1;
            bitcount--;
        }
        if (add_num && (add_bit & 4)) {
            while (add_num) {
                if (add_bit & 8)
                    PlayC64SB(sb_bit1);
                else
                    PlayC64SB(sb_bit0);
                add_num--;
            }
        }
    }

    int main_playtzx(int argc, char *argv[])
    {
        files=0;
        //debug_printf(VERBOSE_INFO,"ZXTape Utilities - Play TZX , TZX to VOC Converter and TZX Info v0.12c for Linux");

        //int kk;
        //for (kk=0;kk<argc;kk++) {
        //    printf("arg %d: [%s]\n",kk,argv[kk]);
        //}

        if (argc < 2) {
            debug_printf(VERBOSE_INFO,"Usage: playtzx [switches] file.tzx [output.voc|output.au]");
            debug_printf(VERBOSE_INFO,"       Switches:  -voc      Create a .VOC file instead of audio output");
            debug_printf(VERBOSE_INFO,"                  -au       Create a .au file instead of audio output");
            debug_printf(VERBOSE_INFO,"                  -freq n   Set sampling frequency to n Hz");
            debug_printf(VERBOSE_INFO,"                  -info     Show extensive Info on TZX file");
            debug_printf(VERBOSE_INFO,"                  -one      Show One line of Info per block (condensed form)");
            debug_printf(VERBOSE_INFO,"                  -x        eXpand the Groups in one line mode");
            debug_printf(VERBOSE_INFO,"                  -b    n   Start replay/conversion  at block n");
            debug_printf(VERBOSE_INFO,"                  -e    n   End replay/conversion after block n");
            debug_printf(VERBOSE_INFO,"                  -p        Wait after each page of Info");
            debug_printf(VERBOSE_INFO,"                  -128      Work in 128k mode");
            debug_printf(VERBOSE_INFO,"                  -sil  n   Adds n bytes of silence at the beginning");
            exit(0);
        }
        /* Check for command line options */
        /* I should change this to use getopt-things */
        for (n = 1; n < argc; n++) {
            if (argv[n][0] == '-') {
                switch (argv[n][1]) {
                    case 'a':
                        if (strcmp(argv[n], "-au"))
                            invalidoption(argv[n]);

                        au = 1;
                        break;

                    case 'v':
                        if (strcmp(argv[n], "-voc"))
                            invalidoption(argv[n]);

                        voc = 1;
                        freq = 30303;
                        break;

                    case 'i':
                        if (strcmp(argv[n], "-info"))
                            invalidoption(argv[n]);

                        tzx_info = 1;
                        break;

                    case 'o':
                        if (strcmp(argv[n], "-one"))
                            invalidoption(argv[n]);

                        tzx_info = 2;
                        break;

                    case 'p':
                        if (strcmp(argv[n], "-p"))
                            invalidoption(argv[n]);

                        pages = 1;
                        break;

                    case 'b':
                        if (strcmp(argv[n], "-b"))
                            invalidoption(argv[n]);

                        starting = getnumber(argv[n + 1]);
                        n++;
                        break;

                    case 'e':
                        if (strcmp(argv[n], "-e"))
                            invalidoption(argv[n]);

                        ending = getnumber(argv[n + 1]);
                        n++;
                        break;

                    case 'f':
                        if (strcmp(argv[n], "-freq"))
                            invalidoption(argv[n]);

                        nfreq = getnumber(argv[n + 1]);
                        n++;
                        break;

                    case 's':
                        if (strcmp(argv[n], "-sil"))
                            invalidoption(argv[n]);

                        silence_beginning = getnumber(argv[n + 1]);
                        n++;
                        break;

                    case 'x':
                        if (strcmp(argv[n], "-x"))
                            invalidoption(argv[n]);

                        expand = 1;
                        break;

                    case '1':
                        if (strcmp(argv[n], "-128"))
                            invalidoption(argv[n]);

                        mode128 = 1;
                        break;

                    default:
                        invalidoption(argv[n]);
                }
            } else {
                files++;

                switch (files) {
                    case 1:
                        strcpy(finp, argv[n]);
                        break;

                    case 2:
                        strcpy(fout, argv[n]);
                        break;

                    default:
                        playtzx_Error("Too Many files on command line!");
                        return 1;
                        break;
                }
            }
        }

        if (voc && tzx_info) {
            playtzx_Error("Both -voc AND -info (or -one) switches selected !");
            return 1;
        }

        if (files == 0) {
            playtzx_Error("No Files specified !");
            return 1;
        }

        if (files == 1) {
            if (voc) {
                strcpy(fout, finp);
                ChangeFileExtension(fout, "VOC");
            } else if (au) {
                strcpy(fout, finp);
                ChangeFileExtension(fout, "au");
            }
        }
        if (nfreq)
            freq = nfreq;

        /**/

        /*if ((fh = open(finp, O_RDONLY)) == -1) {
            playtzx_Error("File not found");
            return 1;
        }
        */

        ptr_archivo_entrada=fopen(finp,"rb");
        if (ptr_archivo_entrada==NULL) {
            playtzx_Error("File not found");
            return 1;
        }

        //flen = FileLength(fh);
        flen=get_file_size(finp);
        debug_printf (VERBOSE_DEBUG,"File length: %d",flen);

        mem = malloc(flen);

        if (mem == NULL) {
            playtzx_Error("Not enough memory to load the file!");
            return 1;
        }

        memorig=mem;

        /* Start reading file...*/
        //read(fh, mem, 10);


        /*Leemos todo el archivo de golpe
         * Esto antes hacia dos read, uno de 10 bytes y luego el restante, pero en windows la segunda operacion
         * read no leia nada. De hecho segun el manual de read:
         *
         *        On  files that support seeking, the read operation commences at the current file offset,
         * and the file offset is incremented by the number of
         *  bytes read.  If the current file offset is at or past the end of file, no bytes are read, and read() returns zero.
         *
         * Pues debe ser que en mingw no soporta seek
        */
        //int leidos=read(fh, mem, flen);
        int leidos=fread(mem,1,flen,ptr_archivo_entrada);
        debug_printf (VERBOSE_INFO,"Read %d bytes",leidos);
        if (leidos!=flen) {
            debug_printf(VERBOSE_ERR,"Error: %s",strerror(errno));
            return 1;
        }


        mem[7] = 0;


        //temp debug
        /*
        int indice;
        for (indice=0;indice<10;indice++) {
            unsigned char caracter=mem[indice];
            printf ("%d: %d ",indice,caracter);
            if (caracter>=32 && caracter<=127) printf ("%c",caracter);
            else printf (".");
            printf ("\n");
        }
        */
        //fin temp debug


        if (strcmp((const char *) mem, "ZXTape!")) {
            free(memorig);
            playtzx_Error("File is not in ZXTape format!");
            return 1;
        }
        debug_printf(VERBOSE_INFO,"ZXTape file revision %d.%02d", mem[8], mem[9]);

        if (!mem[8]) {
            playtzx_Error("Development versions of ZXTape format are not supported!");
            return 1;
        }

        if (mem[8] > MAJREV) {
            debug_printf(VERBOSE_INFO,"-- Warning: Some blocks may not be recognised and used!");
            line += 2;
        }
        if (mem[8] == MAJREV && mem[9] > MINREV) {
            debug_printf(VERBOSE_INFO,"-- Warning: Some of the data might not be properly recognised!");
            line += 2;
        }
        /*int leidos=read(fh, mem, flen - 10);
        debug_printf (VERBOSE_INFO,"Read %d additional bytes",leidos);
        if (leidos==0) {
            debug_printf(VERBOSE_INFO,"Error: %s",strerror(errno));
        }
        */


        //temp debug

        /*int indice;
        for (indice=0;indice<10;indice++) {
            unsigned char caracter=mem[indice];
            printf ("%d: %d ",indice,caracter);
            if (caracter>=32 && caracter<=127) printf ("%c",caracter);
            else printf (".");
            printf ("\n");
        }
        */

        //fin temp debug
        //Saltamos los primeros 10 bytes de cabecera
        mem +=10;

        numblocks = 0;
        pos = 0;

        not_rec = 0;
        /* Go through the file and record block starts ... (not necessary, could just go right through it)*/
        while (pos < flen - 10) {

            if( numblocks >= blocks_allocated ) {

                size_t new_size = (blocks_allocated >= 8 ? 2 * blocks_allocated : 16);
                debug_printf (VERBOSE_DEBUG,"Reallocating memory to %d bytes",new_size * sizeof( int ) );

                int *ptr = realloc( block, new_size * sizeof( int ) );


                if( !ptr ) {
                    playtzx_Error( "out of memory allocating space for blocks[]" );
                    return 1;
                }

                block = ptr;
                blocks_allocated = new_size;
            }

            block[numblocks] = pos;

            pos++;

            debug_printf (VERBOSE_DEBUG,"Tag id 0x%02X on position %d",mem[pos - 1],pos-1);

            switch (mem[pos - 1]) {
                case 0x10:
                    pos += Get2(&mem[pos + 0x02]) + 0x04;
                    break;

                case 0x11:
                    pos += Get3(&mem[pos + 0x0F]) + 0x12;
                    break;

                case 0x12:
                    pos += 0x04;
                    break;

                case 0x13:
                    pos += (mem[pos + 0x00] * 0x02) + 0x01;
                    break;

                case 0x14:
                    pos += Get3(&mem[pos + 0x07]) + 0x0A;
                    break;

                case 0x15:
                    pos += Get3(&mem[pos + 0x05]) + 0x08;
                    break;

                case 0x16:
                    pos += Get4(&mem[pos + 0x00]) + 0x04;
                    break;

                case 0x17:
                    pos += Get4(&mem[pos + 0x00]) + 0x04;
                    break;

                case 0x20:
                    pos += 0x02;
                    break;

                case 0x21:
                    pos += mem[pos + 0x00] + 0x01;
                    break;

                case 0x22:
                    break;

                case 0x23:
                    pos += 0x02;
                    break;

                case 0x24:
                    pos += 0x02;
                    break;

                case 0x25:
                    break;

                case 0x26:
                    pos += Get2(&mem[pos + 0x00]) * 0x02 + 0x02;
                    break;

                case 0x27:
                    break;

                case 0x28:
                    pos += Get2(&mem[pos + 0x00]) + 0x02;
                    break;

                case 0x2A:
                    pos += 0x04;
                    break;

                case 0x30:
                    pos += mem[pos + 0x00] + 0x01;
                    break;

                case 0x31:
                    pos += mem[pos + 0x01] + 0x02;
                    break;

                case 0x32:
                    pos += Get2(&mem[pos + 0x00]) + 0x02;
                    break;

                case 0x33:
                    pos += (mem[pos + 0x00] * 0x03) + 0x01;
                    break;

                case 0x34:
                    pos += 0x08;
                    break;

                case 0x35:
                    pos += Get4(&mem[pos + 0x10]) + 0x14;
                    break;


                case 0x40:
                    pos += Get3(&mem[pos + 0x01]) + 0x04;
                    break;


                case 0x5A:
                    pos += 0x09;
                    break;


                default:
                    debug_printf (VERBOSE_DEBUG,"Tag id 0x%02X not recognized",mem[pos - 1]);
                    pos += Get4(&mem[pos + 0x00]) + 0x04;
                    not_rec = 1;

            }

            numblocks++;

        }

        debug_printf(VERBOSE_INFO,"Number of Blocks: %d", numblocks);

        if (not_rec) {
            debug_printf(VERBOSE_INFO,"-- Warning: Some blocks were *NOT* recognised!");
            line += 2;
        }
        curr = 0;

        if (starting > 1) {
            if (starting > numblocks) {
                free(memorig);
                playtzx_Error("Invalid Starting Block");
                return 1;
            }
            curr = starting - 1;
        }
        if (ending > 0) {
            if (ending > numblocks || ending < starting) {
                free(memorig);
                playtzx_Error("Invalid Ending Block");
                return 1;
            }
            numblocks = ending;
        }
        if (!tzx_info) {
            if (voc)
                debug_printf(VERBOSE_INFO,"Creating .VOC file using %d Hz frequency.", freq);
            else
                debug_printf(VERBOSE_INFO,"Starting playback using %d Hz frequency.", freq);
        }



        if (!tzx_info) {
            if (voc) {
                //InitVOC();
            }
            else if (au)
                InitAU();
            //else
            //  InitSB();
        }
        amp = LOAMP;
        cycle = (double) freq / 3500000.0;	/* This is for the conversion later ... */

        if (tzx_info== 2)
            line++;


        /* Start replay of blocks ...*/
        while (curr < numblocks) {
            if (!tzx_info) {
                if (draw)
                    debug_printf(VERBOSE_INFO,"Block %3d:", curr + 1);
            } else {
                if (tzx_info== 2 && draw) {
                    if (pages) {
                        line++;
                    }
                    debug_printf(VERBOSE_INFO,"%3d-%5X:", curr + 1, block[curr] + 10);
                }
            }

            id = mem[block[curr]];
            data = &mem[block[curr] + 1];

            switch (id) {
                /* Standard Loading Data block */
                case 0x10:
                    tzx_pause = Get2(&data[0]);
                    datalen = Get2(&data[2]);
                    data += 4;

                    if (data[0] == 0x00)
                        pilot = 8064;
                    else
                        pilot = 3220;

                    sb_pilot = ConvSB(2168);
                    sb_sync1 = ConvSB(667);
                    sb_sync2 = ConvSB(735);
                    sb_bit0 = ConvSB(885);

                    sb_bit1 = ConvSB(1710);

                    lastbyte = 8;

                    if (tzx_info== 1) {
                        Identify(datalen, data, 1);

                        sprintf(pstr, "Block %3d (%5X):  10 - Standard Loading Data - %s", curr + 1,
                            block[curr] + 10, tstr);
                        writeout(pstr);

                        sprintf(tstr, "                Length: %5d bytes", datalen);
                        writeout(tstr);

                        sprintf(tstr, "                  Flag: %5d ($%02X)", data[0], data[0]);
                        writeout(tstr);

                        sprintf(tstr, "              CheckSum: %5d ($%02X) - %s",
                            data[datalen - 1], data[datalen - 1], GetCheckSum(data, datalen));
                        writeout(tstr);

                        sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                        line++;
                        writeout(tstr);
                    }
                    break;

                    /* Custom Loading Data block */
                    case 0x11:
                        sb_pilot = ConvSB(Get2(&data[0]));
                        sb_sync1 = ConvSB(Get2(&data[2]));
                        sb_sync2 = ConvSB(Get2(&data[4]));
                        sb_bit0 = ConvSB(Get2(&data[6]));
                        sb_bit1 = ConvSB(Get2(&data[8]));

                        speed = (int) ((1710.0 / (double) Get2(&data[8])) * 100.0);
                        pilot = Get2(&data[10]);
                        lastbyte = (int) data[12];
                        tzx_pause = Get2(&data[13]);
                        datalen = Get3(&data[15]);

                        data += 18;

                        if (tzx_info== 1) {
                            Identify(datalen, data, 1);

                            sprintf(pstr, "Block %3d (%5X):  11 - Custom Loading Data - %s", curr + 1,
                                block[curr] + 10, tstr);
                            writeout(pstr);

                            sprintf(tstr, "                Length: %5d bytes", datalen);
                            writeout(tstr);

                            sprintf(tstr, "                  Flag: %5d ($%02X)", data[0], data[0]);
                            writeout(tstr);

                            if (!cpc) {
                                sprintf(tstr, "              CheckSum: %5d ($%02X) - %s",
                                    data[datalen - 1], data[datalen - 1], GetCheckSum(data, datalen));
                                writeout(tstr);
                            }
                            sprintf(tstr, "           Pilot pulse: %5d T-States", Get2(data - 18));
                            writeout(tstr);

                            sprintf(tstr, "          Pilot length: %5d pulses", pilot);
                            writeout(tstr);

                            sprintf(tstr, "      Sync first pulse: %5d T-States", Get2(data - 16));
                            writeout(tstr);

                            sprintf(tstr, "     Sync second pulse: %5d T-States", Get2(data - 14));
                            writeout(tstr);

                            sprintf(tstr, "           Bit-0 pulse: %5d T-States", Get2(data - 12));
                            writeout(tstr);

                            sprintf(tstr, "           Bit-1 pulse: %5d T-States", Get2(data - 10));
                            writeout(tstr);

                            sprintf(tstr, "        Last byte used: %5d bits", lastbyte);
                            writeout(tstr);

                            sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                            line++;
                            writeout(tstr);
                        }
                        break;

                        /* Pure Tone */
                        case 0x12:
                            sb_pilot = ConvSB(Get2(&data[0]));
                            pilot = Get2(&data[2]);

                            if (tzx_info!= 1) {
                                if (draw)
                                    debug_printf(VERBOSE_INFO,"    Pure Tone             Length: %5d", pilot);

                                if (tzx_info!= 2) {
                                    while (pilot) {
                                        PlaySB(amp, sb_pilot);
                                        ToggleAmp();
                                        pilot--;
                                    }
                                }
                            } else {
                                sprintf(tstr, "Block %3d (%5X):  12 - Pure Tone", curr + 1, block[curr] + 10);
                                writeout(tstr);

                                sprintf(tstr, "          Pulse length: %5d T-States", Get2(data));
                                writeout(tstr);

                                sprintf(tstr, "           Tone length: %5d pulses", pilot);
                                line++;
                                writeout(tstr);
                            }
                            break;

                            /* Sequence of Pulses */
                            case 0x13:
                                pilot = (int) data[0];
                                data++;

                                if (tzx_info!= 1) {
                                    if (draw)
                                        debug_printf(VERBOSE_INFO,"    Sequence of Pulses    Length: %5d", pilot);

                                    if (tzx_info!= 2) {
                                        while (pilot) {
                                            sb_pulse = ConvSB(Get2(&data[0]));

                                            PlaySB(amp, sb_pulse);
                                            ToggleAmp();
                                            pilot--;
                                            data += 2;
                                        }
                                    }
                                } else {
                                    sprintf(tstr, "Block %3d (%5X):  13 - Sequence of Pulses", curr + 1,
                                        block[curr] + 10);
                                    writeout(tstr);

                                    sprintf(tstr, "      Number of Pulses: %5d", pilot);
                                    line++;
                                    writeout(tstr);
                                }
                                break;

                                /* Pure Data */
                                case 0x14:
                                    sb_pilot = pilot = sb_sync1 = sb_sync2 = 0;
                                    sb_bit0 = ConvSB(Get2(&data[0]));
                                    sb_bit1 = ConvSB(Get2(&data[2]));

                                    speed = (int) ((1710.0 / (double) Get2(&data[2])) * 100.0);

                                    lastbyte = (int) data[4];
                                    tzx_pause = Get2(&data[5]);
                                    datalen = Get3(&data[7]);
                                    data += 10;

                                    if (tzx_info== 1) {
                                        sprintf(tstr, "Block %3d (%5X):  14 - Pure Data", curr + 1, block[curr] + 10);
                                        writeout(tstr);

                                        sprintf(tstr, "                Length: %5d bytes", datalen);
                                        writeout(tstr);

                                        sprintf(tstr, "                  Flag: %5d ($%02X)", data[0], data[0]);
                                        writeout(tstr);

                                        sprintf(tstr, "              CheckSum: %5d ($%02X) - %s",
                                            data[datalen - 1], data[datalen - 1], GetCheckSum(data, datalen));
                                        writeout(tstr);

                                        sprintf(tstr, "           Bit-0 pulse: %5d T-States", Get2(data - 10));
                                        writeout(tstr);

                                        sprintf(tstr, "           Bit-1 pulse: %5d T-States", Get2(data - 8));
                                        writeout(tstr);

                                        sprintf(tstr, "        Last byte used: %5d bits", lastbyte);
                                        writeout(tstr);

                                        sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                                        line++;
                                        writeout(tstr);
                                    }
                                    break;

                                    /* Direct Recording */
                                    case 0x15:
                                        sb_pulse = ConvSB(Get2(&data[0]));

                                        /* For now the BEST way is to use the sample frequency for replay that is */
                                        /* exactly the SAME as the Original Freq. used when sampling this block ! */
                                        /* i.e. NO downsampling is handled YET ... use TAPER when you need it !  ;-) */
                                        if (!sb_pulse)
                                            sb_pulse = 1;		/* In case sample frequency > 44100 */

                                        tzx_pause = Get2(&data[2]);	/* (Should work for frequencies upto 48000) */
                                        lastbyte = (int) data[4];
                                        datalen = Get3(&data[5]);

                                        if (tzx_info!= 1) {
                                            if (draw) {
                                                debug_printf
                                                (VERBOSE_INFO,"    Direct Recording      Length:%6d  Original Freq.: %5d Hz",
                                                 datalen, (int) (0.5 + (3500000.0 / (double) Get2(&data[0]))));

                                            }

                                                if (tzx_info!= 2) {
                                                    data = &data[8];
                                                    datapos = 0;

                                                    /* Replay Direct Recording block ... */
                                                    while (datalen) {
                                                        if (datalen != 1)
                                                            bitcount = 8;
                                                        else
                                                            bitcount = lastbyte;

                                                        databyte = data[datapos];

                                                        while (bitcount) {
                                                            if (databyte & 0x80)
                                                                amp = HIAMP;
                                                            else
                                                                amp = LOAMP;

                                                            PlaySB(amp, sb_pulse);

                                                            databyte <<= 1;

                                                            bitcount--;
                                                        }

                                                        datalen--;
                                                        datapos++;
                                                    }
                                                    amp = LOAMP;

                                                    if (tzx_pause)
                                                        PauseSB(amp, tzx_pause);
                                                }
                                        } else {
                                            sprintf(tstr, "Block %3d (%5X):  15 - Direct Recording", curr + 1,
                                                block[curr] + 10);
                                            writeout(tstr);

                                            sprintf(tstr, "                Length:%6d bytes", datalen);
                                            writeout(tstr);

                                            sprintf(tstr,
                                                "    Original Frequency: %5d T-States/Sample (%5d Hz)",
                                                Get2(data), (int) (0.5 + (3500000.0 / (double) Get2(data))));
                                            writeout(tstr);

                                            sprintf(tstr, "        Last byte used: %5d samples", lastbyte);
                                            writeout(tstr);

                                            sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                                            line++;
                                            writeout(tstr);
                                        }
                                        break;

                                        /* C64 ROM Type Data Block */
                                        case 0x16:
                                            data += 4;
                                            sb_pilot = Get2(&data[0]);
                                            pilot = Get2(&data[2]);
                                            sb_sync1 = Get2(&data[4]);
                                            sb_sync2 = Get2(&data[6]);
                                            sb_bit0_f = Get2(&data[8]);
                                            sb_bit0_s = Get2(&data[10]);
                                            sb_bit1_f = Get2(&data[12]);
                                            sb_bit1_s = Get2(&data[14]);
                                            xortype = (int) (data[16]);
                                            sb_finishbyte_f = Get2(&data[17]);
                                            sb_finishbyte_s = Get2(&data[19]);
                                            sb_finishdata_f = Get2(&data[21]);
                                            sb_finishdata_s = Get2(&data[23]);
                                            sb_trailing = Get2(&data[25]);
                                            trailing = Get2(&data[27]);
                                            lastbyte = (int) (data[29]);
                                            endian = data[30];
                                            tzx_pause = Get2(&data[31]);
                                            datalen = Get3(&data[33]);
                                            data += 36;
                                            IdentifyC64ROM(datalen, data, 1);
                                            if (tzx_info== 1) {
                                                sprintf(pstr, "Block %3d (%5X):  16 - C64 ROM Type Data - %s", curr + 1, block[curr] + 10, tstr);
                                                writeout(pstr);
                                                sprintf(tstr, "                Length: %5d bytes", datalen);
                                                writeout(tstr);
                                                sprintf(tstr, "                  Flag: %5d ($%02X)", data[0], data[0]);
                                                writeout(tstr);
                                                if (pilot) {
                                                    sprintf(tstr, "           Pilot pulse: %5d T-States, length: %5d pulses", sb_pilot, pilot);
                                                    writeout(tstr);
                                                } else {
                                                    sprintf(tstr, "           Pilot pulse:  None");
                                                    writeout(tstr);
                                                }
                                                sprintf(tstr, "           Sync pulses: %5d & %5d T-States", sb_sync1, sb_sync2);
                                                writeout(tstr);
                                                sprintf(tstr, "          Bit-0 pulses: %5d & %5d T-States", sb_bit0_f, sb_bit0_s);
                                                writeout(tstr);
                                                sprintf(tstr, "          Bit-1 pulses: %5d & %5d T-States", sb_bit1_f, sb_bit1_s);
                                                writeout(tstr);
                                                sprintf(tstr, "        Last byte used: %5d bits", lastbyte);
                                                writeout(tstr);
                                                if (xortype != 0xFF) {
                                                    sprintf(tstr, "         Byte XOR Type: %d XOR all bits", xortype);
                                                    writeout(tstr);
                                                } else {
                                                    sprintf(tstr, "         Byte XOR Type:  None");
                                                    writeout(tstr);
                                                }
                                                sprintf(tstr, "    Finish Byte pulses: %5d & %5d T-States", sb_finishbyte_f, sb_finishbyte_s);
                                                writeout(tstr);
                                                sprintf(tstr, "    Finish Data pulses: %5d & %5d T-States", sb_finishdata_f, sb_finishdata_s);
                                                writeout(tstr);
                                                if (trailing) {
                                                    sprintf(tstr, "   Trailing Tone pulse: %5d T-States, length: %5d pulses", sb_trailing, trailing);
                                                    writeout(tstr);
                                                } else {
                                                    sprintf(tstr, "   Trailing Tone pulse:  None");
                                                    writeout(tstr);
                                                }
                                                if (endian)
                                                    strcpy(pstr, "MSb");
                                                else
                                                    strcpy(pstr, "LSb");
                                                sprintf(tstr, "             Endianess:   %s", pstr);
                                                writeout(tstr);
                                                sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                                                line++;
                                                writeout(tstr);

                                                sprintf(tstr, "     First: %02X , Last: %02X, Len: %d", data[0], data[datalen - 1], datalen);
                                                line++;
                                                writeout(tstr);
                                            }
                                            break;
                                            /* C64 Turbo Tape Data Block */
                                            case 0x17:
                                                data += 4;
                                                sb_bit0 = Get2(&data[0]);
                                                sb_bit1 = Get2(&data[2]);
                                                add_bit = data[4];
                                                num_lead_in = Get2(&data[5]);
                                                lead_in_byte = data[7];
                                                lastbyte = (int) data[8];
                                                endian = data[9];
                                                trailing = Get2(&data[10]);
                                                sb_trailing = data[12];
                                                tzx_pause = Get2(&data[13]);
                                                datalen = Get3(&data[15]);
                                                data += 18;
                                                IdentifyC64Turbo(datalen, data, 1);
                                                if (tzx_info== 1) {
                                                    sprintf(pstr, "Block %3d (%5X):  17 - C64 Turbo Tape Type Data - %s", curr + 1, block[curr] + 10, tstr);
                                                    writeout(pstr);
                                                    sprintf(tstr, "                Length: %5d bytes", datalen);
                                                    writeout(tstr);
                                                    sprintf(tstr, "                  Flag: %5d ($%02X)", data[0], data[0]);
                                                    writeout(tstr);
                                                    if (num_lead_in) {
                                                        sprintf(tstr, "         Lead In Bytes: %5d, Value: %3d ($%02X)", num_lead_in, lead_in_byte, lead_in_byte);
                                                        writeout(tstr);
                                                    } else {
                                                        sprintf(tstr, "         Lead In Bytes:  None");
                                                        writeout(tstr);
                                                    }
                                                    sprintf(tstr, "           Bit-0 pulse: %5d T-States", sb_bit0);
                                                    writeout(tstr);
                                                    sprintf(tstr, "           Bit-1 pulse: %5d T-States", sb_bit1);
                                                    writeout(tstr);
                                                    if (add_bit & 3) {
                                                        if (add_bit & 4)
                                                            strcpy(pstr, "After");
                                                        else
                                                            strcpy(pstr, "Before");
                                                        sprintf(tstr, "       Additional Bits: %5d %s Byte, Value %1d", add_bit & 3, pstr, (add_bit >> 3) & 1);
                                                        writeout(tstr);
                                                    } else {
                                                        sprintf(tstr, "       Additional Bits:  None");
                                                        writeout(tstr);
                                                    }
                                                    sprintf(tstr, "        Last byte used: %5d bits", lastbyte);
                                                    writeout(tstr);
                                                    if (endian)
                                                        strcpy(pstr, "MSb");
                                                    else
                                                        strcpy(pstr, "LSb");
                                                    sprintf(tstr, "             Endianess:   %s", pstr);
                                                    writeout(tstr);
                                                    if (trailing) {
                                                        sprintf(tstr, "        Trailing Bytes: %5d, Value: %3d ($%02X)", trailing, sb_trailing, sb_trailing);
                                                        writeout(tstr);
                                                    } else {
                                                        sprintf(tstr, "        Trailing Bytes:  None");
                                                        writeout(tstr);
                                                    }
                                                    sprintf(tstr, "     Pause after block: %5d milliseconds", tzx_pause);
                                                    line++;
                                                    writeout(tstr);
                                                }
                                                break;

                                                /* Pause or Stop the Tape command */
                                                case 0x20:
                                                    tzx_pause = Get2(&data[0]);

                                                    amp = LOAMP;

                                                    if (tzx_pause) {
                                                        if (tzx_info!= 1) {
                                                            if (draw) {
                                                                debug_printf(VERBOSE_INFO,"    Pause                 Length: %2.3fs",
                                                                         ((float) tzx_pause) / 1000.0);
                                                            }

                                                                if (tzx_info!= 2) {
                                                                    PauseSB(amp, tzx_pause);
                                                                    amp = LOAMP;
                                                                }
                                                        } else {
                                                            sprintf(tstr, "Block %3d (%5X):  20 - Pause (Silence)", curr + 1,
                                                                block[curr] + 10);
                                                            writeout(tstr);

                                                            sprintf(tstr, "              Duration: %5d milliseconds", tzx_pause);
                                                            line++;
                                                            writeout(tstr);
                                                        }
                                                    } else {
                                                        if (tzx_info!= 1) {
                                                            if (!voc) {
                                                                if (tzx_info!= 2) {
                                                                    //if (draw)
                                                                    //  debug_printf(VERBOSE_INFO,"    Stop the tape command - Press any key to continue!");

                                                                    PlaySB(amp, sbbuflen << 1);	/* finish last block ... */

                                                                    //StopSB();


                                                                    //InitSB();
                                                                }
                                                                else {
                                                                    if (draw) debug_printf(VERBOSE_INFO,"    Stop the tape command!");
                                                                }
                                                            }
                                                            else {
                                                                if (draw) debug_printf(VERBOSE_INFO,"    Stop the tape command!");

                                                                if (tzx_info!= 2) {
                                                                    PauseSB(amp, 5000);
                                                                    amp = LOAMP;
                                                                }
                                                            }
                                                        } else {
                                                            sprintf(tstr, "Block %3d (%5X):  20 - Stop the Tape Command", curr + 1,
                                                                block[curr] + 10);
                                                            line++;
                                                            writeout(tstr);
                                                        }
                                                    }
                                                    break;

                                                    /* Group Start */
                                                    case 0x21:
                                                        CopyString(pstr, &data[1], data[0]);

                                                        if (tzx_info!= 1) {
                                                            if (draw)
                                                                debug_printf(VERBOSE_INFO,"    Group: %s", pstr);
                                                        } else {
                                                            sprintf(tstr, "Block %3d (%5X):  21 - Group: %s", curr + 1, block[curr] + 10,
                                                                pstr);
                                                            line++;
                                                            writeout(tstr);
                                                        }

                                                        if (!expand)
                                                            draw = 0;

                                                        break;

                                                        /* Group End */
                                                        case 0x22:
                                                            if (tzx_info!= 1) {
                                                                if (draw)
                                                                    debug_printf(VERBOSE_INFO,"    Group End");
                                                            } else {
                                                                sprintf(tstr, "Block %3d (%5X):  22 - Group End", curr + 1, block[curr] + 10);
                                                                line++;
                                                                writeout(tstr);
                                                            }

                                                            draw = 1;
                                                            break;

                                                            /* Jump To Relative */
                                                            case 0x23:
                                                                jump = (signed short) (data[0] + data[1] * 256);

                                                                if (tzx_info!= 1) {
                                                                    if (draw)
                                                                        debug_printf(VERBOSE_INFO,"    Jump Relative: %d (To Block %d)", jump, curr + jump + 1);

                                                                    if (!tzx_info) {
                                                                        curr += jump;
                                                                        curr--;
                                                                    }
                                                                } else {
                                                                    sprintf(tstr,
                                                                        "Block %3d (%5X):  23 - Jump Relative: %d (To Block %d)",
                                                                        curr + 1, block[curr] + 10, jump, curr + jump + 1);
                                                                    line++;
                                                                    writeout(tstr);
                                                                }
                                                                break;

                                                                /* Loop Start */
                                                                case 0x24:
                                                                    loop_start = curr;
                                                                    loop_count = Get2(&data[0]);

                                                                    if (tzx_info!= 1) {
                                                                        if (draw)
                                                                            debug_printf(VERBOSE_INFO,"    Loop Start, Counter: %d", loop_count);
                                                                    } else {
                                                                        sprintf(tstr, "Block %3d (%5X):  24 - Loop Start, Counter: %d", curr + 1,
                                                                            block[curr] + 10, loop_count - 1);
                                                                        line++;
                                                                        writeout(tstr);
                                                                    }
                                                                    break;

                                                                    /* Loop End */
                                                                    case 0x25:
                                                                        if (tzx_info!= 1) {
                                                                            if (tzx_info!= 2) {
                                                                                loop_count--;

                                                                                if (loop_count > 0) {
                                                                                    if (draw)
                                                                                        debug_printf(VERBOSE_INFO,"    Loop End, Still To Go %d Time(s)!", loop_count);

                                                                                    curr = loop_start;
                                                                                } else {
                                                                                    if (draw)
                                                                                        debug_printf(VERBOSE_INFO,"    Loop End, Finished");
                                                                                }
                                                                            } else {
                                                                                if (draw)
                                                                                    debug_printf(VERBOSE_INFO,"    Loop End");
                                                                            }
                                                                        } else {
                                                                            sprintf(tstr, "Block %3d (%5X):  25 - Loop End", curr + 1, block[curr] + 10);
                                                                            line++;
                                                                            writeout(tstr);
                                                                        }
                                                                        break;

                                                                        /* Call Sequence */
                                                                        case 0x26:
                                                                            call_pos = curr;
                                                                            call_num = Get2(&data[0]);
                                                                            call_cur = 0;

                                                                            if (tzx_info== 1) {
                                                                                sprintf(tstr,
                                                                                    "Block %3d (%5X):  26 - Call Sequence, Number of Calls : %d", curr + 1,
                                                                                    block[curr] + 10, call_num);
                                                                                line++;
                                                                                writeout(tstr);
                                                                            } else {
                                                                                if (tzx_info== 2) {
                                                                                    if (draw)
                                                                                        debug_printf(VERBOSE_INFO,"    Call Sequence, Number of Calls : %d", call_num);
                                                                                } else {
                                                                                    jump = (signed short) (data[2] + data[3] * 256);

                                                                                    if (draw) {
                                                                                        debug_printf(VERBOSE_INFO,"    Call Sequence, Number of Calls : %d, First: %d (To Block %d)",
                                                                                                 call_num, jump, curr + jump + 1);

                                                                                    }

                                                                                        curr += jump;
                                                                                    curr--;
                                                                                }
                                                                            }
                                                                            break;

                                                                            /* Return from Sequence */
                                                                            case 0x27:
                                                                                call_cur++;

                                                                                if (tzx_info== 1) {
                                                                                    sprintf(tstr, "Block %3d (%5X):  27 - Return from Call", curr + 1,
                                                                                        block[curr] + 10);
                                                                                    line++;
                                                                                    writeout(tstr);
                                                                                } else {
                                                                                    if (tzx_info== 2) {
                                                                                        if (draw)
                                                                                            debug_printf(VERBOSE_INFO,"    Return from Call");
                                                                                    } else {
                                                                                        if (call_cur == call_num) {
                                                                                            if (draw)
                                                                                                debug_printf(VERBOSE_INFO,"    Return from Call, Last Call Finished");

                                                                                            curr = call_pos;
                                                                                        } else {
                                                                                            curr = call_pos;
                                                                                            data = &mem[block[curr] + 1];
                                                                                            jump = (signed short) (data[call_cur * 2 + 2] + data[call_cur * 2 + 3] * 256);

                                                                                            if (draw) {
                                                                                                debug_printf
                                                                                                (VERBOSE_INFO,"    Return from Call, Calls Left: %d, Next: %d (To Block %d)",
                                                                                                 call_num - call_cur, jump, curr + jump + 1);
                                                                                            }

                                                                                                curr += jump;
                                                                                            curr--;
                                                                                        }
                                                                                    }
                                                                                }
                                                                                break;

                                                                                /* Select Block */
                                                                                case 0x28:
                                                                                    num_sel = data[2];

                                                                                    if (tzx_info== 2) {
                                                                                        if (draw) {
                                                                                            sprintf(tstr, "    Select block");
                                                                                            MakeFixedString(tstr, 69);
                                                                                            strcpy(tstr + 52, " (-info for more)");
                                                                                            debug_printf(VERBOSE_INFO,"%s", tstr);
                                                                                        }
                                                                                    } else {
                                                                                        if (tzx_info== 1) {
                                                                                            sprintf(tstr, "Block %3d (%5X):  28 - Select Block", curr + 1,
                                                                                                block[curr] + 10);
                                                                                            writeout(tstr);

                                                                                            data += 3;

                                                                                            for (n = 0; n < num_sel; n++) {
                                                                                                jump = (signed short) (data[0] + data[1] * 256);

                                                                                                CopyString(spdstr, &data[3], data[2]);

                                                                                                sprintf(tstr, "%5d - Jump: %3d (To Block %4d) : %s", n + 1, jump,
                                                                                                    curr + jump + 1, spdstr);
                                                                                                writeout(tstr);

                                                                                                data += 3 + data[2];
                                                                                            }

                                                                                            //sprintf(tstr, "\n");
                                                                                            //writeout(tstr);
                                                                                        } else {
                                                                                            debug_printf(VERBOSE_INFO,"    Select :");

                                                                                            data += 3;

                                                                                            for (n = 0; n < num_sel; n++) {
                                                                                                jump = (signed short) (data[0] + data[1] * 256);

                                                                                                jumparray[n] = jump;

                                                                                                CopyString(spdstr, &data[3], data[2]);

                                                                                                debug_printf(VERBOSE_INFO,"%5d : %s", n + 1, spdstr);

                                                                                                data += 3 + data[2];
                                                                                            }

                                                                                            //debug_printf(VERBOSE_INFO,">> Press the number!");

                                                                                            if (!voc) {
                                                                                                PlaySB(amp, sbbuflen << 1);	/* finish last block ... */
                                                                                                //StopSB();
                                                                                            } else {
                                                                                                PauseSB(amp, 5000);
                                                                                                amp = LOAMP;
                                                                                            }

                                                                                            //k = GetCh();
                                                                                            debug_printf (VERBOSE_ERR,"TZX tag 0x28 not supported");
                                                                                            return 1;

                                                                                            if (k == 27) {
                                                                                                free(memorig);
                                                                                                //close(fh);
                                                                                                fclose(ptr_archivo_entrada);
                                                                                                playtzx_Error("ESCAPE key pressed!");
                                                                                                return 1;
                                                                                            }
                                                                                            //if (!voc)
                                                                                            //InitSB();

                                                                                            k -= 48;

                                                                                            if (k < 1 || k > num_sel)
                                                                                                debug_printf(VERBOSE_INFO,"Illegal Selection... Continuing...");
                                                                                            else {
                                                                                                curr += jumparray[k - 1];
                                                                                                curr--;
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                    break;

                                                                                    /* Stop the tape if in 48k mode */
                                                                                    case 0x2A:
                                                                                        if (tzx_info== 1) {
                                                                                            sprintf(tstr, "Block %3d (%5X):  2A - Stop the tape if in 48k mode", curr + 1, block[curr] + 10);
                                                                                            line++;
                                                                                            writeout(tstr);
                                                                                            break;
                                                                                        }
                                                                                        if (tzx_info== 2) {
                                                                                            if (draw)
                                                                                                debug_printf(VERBOSE_INFO,"    Stop the tape if in 48k mode!");
                                                                                            break;
                                                                                        }
                                                                                        if (mode128) {
                                                                                            if (draw)
                                                                                                debug_printf(VERBOSE_INFO,"    Stop the tape only in 48k mode!");
                                                                                        } else {
                                                                                            if (voc || au) {
                                                                                                if (draw)
                                                                                                    debug_printf(VERBOSE_INFO,"    Stop the tape in 48k mode!");
                                                                                                PauseSB(amp, 5000);
                                                                                                amp = LOAMP;
                                                                                            } else {
                                                                                                if (draw)
                                                                                                    debug_printf(VERBOSE_INFO,"    Stop the tape in 48k mode - Press any key to continue!");
                                                                                                PlaySB(amp, sbbuflen << 1);	/* finish last block ... */
                                                                                                //StopSB();
                                                                                                //InitSB();
                                                                                            }
                                                                                        }
                                                                                        break;

                                                                                        /* Description */
                                                                                        case 0x30:
                                                                                            CopyString(pstr, &data[1], data[0]);

                                                                                            if (tzx_info!= 1) {
                                                                                                if (draw)
                                                                                                    debug_printf(VERBOSE_INFO,"    Description: %s", pstr);
                                                                                            } else {
                                                                                                sprintf(tstr, "Block %3d (%5X):  30 - Description: %s", curr + 1,
                                                                                                    block[curr] + 10, pstr);
                                                                                                line++;
                                                                                                writeout(tstr);
                                                                                            }

                                                                                            break;

                                                                                            /* Message */
                                                                                            case 0x31:
                                                                                                CopyString(pstr, &data[2], data[1]);

                                                                                                if (tzx_info!= 1) {
                                                                                                    if (draw)
                                                                                                        debug_printf(VERBOSE_INFO,"    Message: %s", pstr);
                                                                                                }
                                                                                                /* Pause in Message block is ignored ... */
                                                                                                else {
                                                                                                    line += MultiLine(pstr, 34, spdstr);

                                                                                                    sprintf(tstr, "Block %3d (%5X):  31 - Message: %s", curr + 1, block[curr] + 10,
                                                                                                        spdstr);
                                                                                                    writeout(tstr);

                                                                                                    sprintf(tstr, "               Duration: %d seconds", data[0]);
                                                                                                    line++;
                                                                                                    writeout(tstr);
                                                                                                }
                                                                                                break;

                                                                                                /* Archive Info */
                                                                                                case 0x32:
                                                                                                    if (tzx_info!= 1) {
                                                                                                        if (draw) {
                                                                                                            if (data[3] == 0) {
                                                                                                                CopyString(spdstr, &data[5], data[4]);
                                                                                                                sprintf(tstr, "    Title: %s", spdstr);
                                                                                                                MakeFixedString(tstr, 69);
                                                                                                                strcpy(tstr + 52, " (-info for more)");
                                                                                                                debug_printf(VERBOSE_INFO,"%s", tstr);
                                                                                                            } else {
                                                                                                                sprintf(tstr, "    Archive Info");
                                                                                                                MakeFixedString(tstr, 69);
                                                                                                                strcpy(tstr + 52, " (-info for more)");
                                                                                                                debug_printf(VERBOSE_INFO,"%s", tstr);
                                                                                                            }
                                                                                                        }
                                                                                                    } else {
                                                                                                        num = data[2];
                                                                                                        data += 3;

                                                                                                        sprintf(tstr, "Block %3d (%5X):  32 - Archive Info:", curr + 1, block[curr] + 10);
                                                                                                        writeout(tstr);

                                                                                                        while (num) {
                                                                                                            switch (data[0]) {
                                                                                                                case 0x00:
                                                                                                                    sprintf(pstr, "         Title:");
                                                                                                                    break;

                                                                                                                case 0x01:
                                                                                                                    sprintf(pstr, "     Publisher:");
                                                                                                                    break;

                                                                                                                case 0x02:
                                                                                                                    sprintf(pstr, "     Author(s):");
                                                                                                                    break;

                                                                                                                case 0x03:
                                                                                                                    sprintf(pstr, "  Release Date:");
                                                                                                                    break;

                                                                                                                case 0x04:
                                                                                                                    sprintf(pstr, "      Language:");
                                                                                                                    break;

                                                                                                                case 0x05:
                                                                                                                    sprintf(pstr, "     Game Type:");
                                                                                                                    break;

                                                                                                                case 0x06:
                                                                                                                    sprintf(pstr, "         Price:");
                                                                                                                    break;

                                                                                                                case 0x07:
                                                                                                                    sprintf(pstr, "        Loader:");
                                                                                                                    break;

                                                                                                                case 0x08:
                                                                                                                    sprintf(pstr, "        Origin:");
                                                                                                                    break;

                                                                                                                default:
                                                                                                                    sprintf(pstr, "      Comments:");
                                                                                                                    break;
                                                                                                            }

                                                                                                            CopyString(spdstr, &data[2], data[1]);

                                                                                                            line += MultiLine(spdstr, 16, tstr);

                                                                                                            sprintf(spdstr, "%s %s", pstr, tstr);
                                                                                                            writeout(spdstr);

                                                                                                            data += data[1] + 2;
                                                                                                            num--;
                                                                                                        }

                                                                                                        //sprintf(tstr, "\n");
                                                                                                        //writeout(tstr);
                                                                                                    }
                                                                                                    break;

                                                                                                    /* Hardware Info */
                                                                                                    case 0x33:
                                                                                                        if (data[1] == 0 && data[2] > 0x14 && data[2] < 0x1a && data[3] == 1)
                                                                                                            cpc = 1;

                                                                                                        if (data[1] == 0 && data[2] == 0x09 && data[3] == 1)
                                                                                                            sam = 1;

                                                                                                        if (tzx_info!= 1) {
                                                                                                            if (draw) {
                                                                                                                if (data[1] != 0 || data[3] != 1) {
                                                                                                                    sprintf(tstr, "    Hardware Type");
                                                                                                                    MakeFixedString(tstr, 69);
                                                                                                                    strcpy(tstr + 52, " (-info for more)");
                                                                                                                    debug_printf(VERBOSE_INFO,"%s", tstr);
                                                                                                                } else {
                                                                                                                    debug_printf(VERBOSE_INFO,"    This tape is made for %s !", hid[0][data[2]]);
                                                                                                                }
                                                                                                            }
                                                                                                        } else {
                                                                                                            num = data[0];

                                                                                                            data += 1;

                                                                                                            sprintf(tstr, "Block %3d (%5X):  33 - Hardware Info:", curr + 1, block[curr] + 10);
                                                                                                            writeout(tstr);

                                                                                                            for (n = 0; n < 4; n++) {
                                                                                                                prvi = 1;

                                                                                                                d = (char *) data;

                                                                                                                for (m = 0; m < num; m++) {
                                                                                                                    if (d[2] == n) {
                                                                                                                        if (prvi) {
                                                                                                                            prvi = 0;

                                                                                                                            switch (n) {
                                                                                                                                case 0:
                                                                                                                                sprintf(pstr, "  Runs on the following hardware:");
                                                                                                                                writeout(pstr);
                                                                                                                                break;

                                                                                                                                case 1:
                                                                                                                                sprintf(pstr, "  Uses the following hardware:");
                                                                                                                                writeout(pstr);
                                                                                                                                break;

                                                                                                                                case 2:
                                                                                                                                sprintf(pstr,
                                                                                                                                "  Runs, but it doesn't use the following hardware:");
                                                                                                                                writeout(pstr);
                                                                                                                                break;

                                                                                                                                case 3:
                                                                                                                                sprintf(pstr, "  Doesn't run on the following hardware:");
                                                                                                                                writeout(pstr);
                                                                                                                                break;
                                                                                                                            }
                                                                                                                        }
                                                                                                                        if (!prvi && last == d[0]) {
                                                                                                                            for (x = 0; x < lastlen; x++)
                                                                                                                                spdstr[x] = ' ';
                                                                                                                            spdstr[x] = 0;
                                                                                                                            //sprintf(pstr, "      %s  %s", spdstr, hid[d[0]][d[1]]);
                                                                                                                            int jj=d[0];
                                                                                                                            int ii=d[1];

                                                                                                                            sprintf(pstr, "      %s  %s", spdstr, hid[jj] [ii] );
                                                                                                                            writeout(pstr);
                                                                                                                        } else {
                                                                                                                            //sprintf(pstr, "      %s: %s", htype[d[0]], hid[d[0]][d[1]]);
                                                                                                                            int jj=d[0];
                                                                                                                            int ii=d[1];
                                                                                                                            sprintf(pstr, "      %s: %s", htype[jj], hid[jj][ii]);
                                                                                                                            writeout(pstr);
                                                                                                                        }
                                                                                                                        int jj=d[0];
                                                                                                                        //lastlen = strlen(htype[ d[0] ] );
                                                                                                                        lastlen = strlen(htype[ jj ] );
                                                                                                                        last = d[0];
                                                                                                                    }
                                                                                                                    d += 3;
                                                                                                                }
                                                                                                            }
                                                                                                            //sprintf(tstr, "\n");
                                                                                                            //writeout(tstr);
                                                                                                        }
                                                                                                        break;

                                                                                                        /* Emulation info */
                                                                                                        case 0x34:
                                                                                                            if (tzx_info!= 1) {
                                                                                                                if (draw)
                                                                                                                    debug_printf(VERBOSE_INFO,"    Information for emulators.");
                                                                                                            } else {
                                                                                                                sprintf(tstr, "Block %3d (%5X):  34 - Emulation Info", curr + 1,
                                                                                                                    block[curr] + 10);
                                                                                                                line++;
                                                                                                                writeout(tstr);
                                                                                                            }
                                                                                                            break;

                                                                                                            /* Custom Info */
                                                                                                            case 0x35:
                                                                                                                CopyString(pstr, data, 16);

                                                                                                                if (tzx_info!= 1) {
                                                                                                                    if (draw) {
                                                                                                                        if (strcmp(pstr, "POKEs           "))
                                                                                                                            debug_printf(VERBOSE_INFO,"    Custom Info: %s", pstr);	/* Only Name of Custom
                                                                                                                            info except POKEs is
                                                                                                                            used ... */
                                                                                                                            else {
                                                                                                                                sprintf(tstr, "    Custom Info: %s", pstr);
                                                                                                                                MakeFixedString(tstr, 69);
                                                                                                                                strcpy(tstr + 52, " (-info for more)");
                                                                                                                                debug_printf(VERBOSE_INFO,"%s", tstr);
                                                                                                                            }
                                                                                                                    }
                                                                                                                } else {
                                                                                                                    sprintf(tstr, "Block %3d (%5X):  35 - Custom Info: %s", curr + 1, block[curr] + 10, pstr);
                                                                                                                    writeout(tstr);
                                                                                                                    if (!strcmp(pstr, "POKEs           ")) {
                                                                                                                        data += 20;
                                                                                                                        if (data[0]) {
                                                                                                                            sprintf(pstr, "  Description:");
                                                                                                                            CopyString(spdstr, &data[1], data[0]);
                                                                                                                            line += MultiLine(spdstr, 15, tstr) + 1;
                                                                                                                            sprintf(spdstr, "%s %s", pstr, tstr);
                                                                                                                            writeout(spdstr);
                                                                                                                        }
                                                                                                                        data += data[0] + 1;
                                                                                                                        numt = data[0];
                                                                                                                        data++;
                                                                                                                        sprintf(pstr, "          Trainer Description                       Poke Val Org Page");
                                                                                                                        writeout(pstr);
                                                                                                                        sprintf(pstr, "         -------------------------------------------------------------");
                                                                                                                        writeout(pstr);
                                                                                                                        while (numt) {
                                                                                                                            CopyString(pstr, &data[1], data[0]);
                                                                                                                            data += data[0] + 1;
                                                                                                                            nump = data[0];
                                                                                                                            data++;
                                                                                                                            for (n = 0; n < nump; n++) {
                                                                                                                                sprintf(spdstr, "          %s", pstr);
                                                                                                                                MakeFixedString(spdstr, 48);
                                                                                                                                if (data[0] & 8)
                                                                                                                                strcpy(tstr2, "   -");
                                                                                                                                else
                                                                                                                                sprintf(tstr2, "%4d", data[0] & 7);
                                                                                                                                if (data[0] & 32)
                                                                                                                                strcpy(tstr, "  -");
                                                                                                                                else
                                                                                                                                sprintf(tstr, "%3d", data[4]);
                                                                                                                                if (data[0] & 16)
                                                                                                                                strcpy(tstr3, "  -");
                                                                                                                                else
                                                                                                                                sprintf(tstr3, "%3d", data[3]);
                                                                                                                                if (n > 0)
                                                                                                                                strcpy(tstr4, "+");
                                                                                                                                else
                                                                                                                                strcpy(tstr4, " ");
                                                                                                                                sprintf(pstr, "%s %s %5d %s %s %s", spdstr, tstr4, Get2(&data[1]), tstr3, tstr, tstr2);
                                                                                                                                writeout(pstr);
                                                                                                                                data += 5;
                                                                                                                                pstr[0] = 0;
                                                                                                                            }
                                                                                                                            numt--;
                                                                                                                        }
                                                                                                                    }
                                                                                                                    //sprintf(tstr, "\n");
                                                                                                                    //writeout(tstr);
                                                                                                                }
                                                                                                                break;

                                                                                                                /* Snapshot */
                                                                                                                case 0x40:
                                                                                                                    if (tzx_info!= 1) {
                                                                                                                        if (draw)
                                                                                                                            debug_printf(VERBOSE_INFO,"    Snapshot               (Not Supported yet)");
                                                                                                                    } else {
                                                                                                                        sprintf(tstr, "Block %3d (%5X):  40 - Snapshot", curr + 1, block[curr] + 10);
                                                                                                                        line++;
                                                                                                                        writeout(tstr);

                                                                                                                        switch (data[0]) {
                                                                                                                            case 0:
                                                                                                                                sprintf(pstr, "Type: Z80");
                                                                                                                                break;

                                                                                                                            case 1:
                                                                                                                                sprintf(pstr, "Type: SNA");
                                                                                                                                break;

                                                                                                                            default:
                                                                                                                                sprintf(pstr, "Unknown Type");
                                                                                                                                break;
                                                                                                                        }
                                                                                                                        sprintf(tstr, "                      %s", pstr);
                                                                                                                        line++;
                                                                                                                        writeout(tstr);
                                                                                                                    }

                                                                                                                    break;

                                                                                                                    /* ZXTape!xx */
                                                                                                                    case 0x5A:
                                                                                                                        if (tzx_info!= 1) {
                                                                                                                            if (draw)
                                                                                                                                debug_printf(VERBOSE_INFO,"    Start of the new tape  (Merged Tapes)");
                                                                                                                        } else {
                                                                                                                            sprintf(tstr, "Block %3d (%5X):  5A - Merget Tapes", curr + 1, block[curr] + 10);
                                                                                                                            line++;
                                                                                                                            writeout(tstr);
                                                                                                                        }
                                                                                                                        break;

                                                                                                                        /* Other (unknown) blocks */
                                                                                                                        default:
                                                                                                                            if (tzx_info!= 1) {
                                                                                                                                if (draw)
                                                                                                                                debug_printf(VERBOSE_INFO,"    Unknown block %02X !", id);
                                                                                                                            } else {
                                                                                                                                sprintf(tstr, "Block %3d (%5X):  %02X Unknown Block ", curr + 1,
                                                                                                                                block[curr] + 10, id);
                                                                                                                                line++;
                                                                                                                                writeout(tstr);
                                                                                                                            }
                                                                                                                            break;
            }

            if (tzx_info!= 1 && (id == 0x10 || id == 0x11 || id == 0x14)) {	/* One of the data
                blocks ... */
                if (id != 0x14)
                    Identify(datalen, data, 0);
                else
                    strcpy(tstr, "    Pure Data           ");

                if (id == 0x10)
                    sprintf(spdstr, "Normal Speed");
                else
                    sprintf(spdstr, " Speed: %3d%%", speed);

                if (curr == numblocks - 1)
                    //sprintf(pstr, "\0");
                    pstr[0]=0;

                else
                    sprintf(pstr, ",Pause: %2.3fs", ((float) tzx_pause) / 1000.0);

                if (draw)
                    debug_printf(VERBOSE_INFO,"%s  Length:%6d  %s %s", tstr, datalen, spdstr, pstr);

                if (tzx_info!= 2) {
                    while (pilot) {
                        PlaySB(amp, sb_pilot);
                        ToggleAmp();
                        pilot--;
                    }			/* Play PILOT TONE */

                    if (sb_sync1) {
                        PlaySB(amp, sb_sync1);
                        ToggleAmp();
                    }			/* Play SYNC PULSES */
                    if (sb_sync2) {
                        PlaySB(amp, sb_sync2);
                        ToggleAmp();
                    }
                    datapos = 0;

                    while (datalen) {	/* Play actual DATA */
                        if (datalen != 1)
                            bitcount = 8;
                        else
                            bitcount = lastbyte;

                        databyte = data[datapos];

                        while (bitcount) {
                            if (databyte & 0x80)
                                sb_bit = sb_bit1;
                            else
                                sb_bit = sb_bit0;

                            PlaySB(amp, sb_bit);
                            ToggleAmp();

                            PlaySB(amp, sb_bit);
                            ToggleAmp();

                            databyte <<= 1;

                            bitcount--;
                        }

                        datalen--;
                        datapos++;
                    }

                    /* If there is pause after block present then make first millisecond
                     *	the oposite */
                    /* pulse of last pulse played and the rest in LOAMP ... otherwise
                     *	don't do ANY pause */


                    if (tzx_pause) {
                        PauseSB(amp, 1);
                        amp = LOAMP;
                        if (tzx_pause > 1)
                            PauseSB(amp, tzx_pause - 1);
                    }
                }
            }
            if (tzx_info!= 1 && id == 0x16) {	/* C64 ROM data block ... */
                IdentifyC64ROM(datalen, data, 0);

                if (curr == numblocks - 1)
                    //sprintf(pstr, "\0");
                    pstr[0]=0;
                else
                    sprintf(pstr, ",Pause: %2.3fs", ((float) tzx_pause) / 1000.0);

                if (draw)
                    debug_printf(VERBOSE_INFO," %s Length:%6d  %s%s", tstr, datalen, spdstr, pstr);
                if (tzx_info!= 2) {
                    sb_pilot = ConvSB(sb_pilot);
                    sb_sync1 = ConvSB(sb_sync1);
                    sb_sync2 = ConvSB(sb_sync2);
                    sb_bit1_f = ConvSB(sb_bit1_f);
                    sb_bit1_s = ConvSB(sb_bit1_s);
                    sb_bit0_f = ConvSB(sb_bit0_f);
                    sb_bit0_s = ConvSB(sb_bit0_s);
                    sb_finishbyte_f = ConvSB(sb_finishbyte_f);
                    sb_finishbyte_s = ConvSB(sb_finishbyte_s);
                    sb_finishdata_f = ConvSB(sb_finishdata_f);
                    sb_finishdata_s = ConvSB(sb_finishdata_s);
                    sb_trailing = ConvSB(sb_trailing);
                    num_lead_in = 0;
                    amp = LOAMP;		/* This might be just opposite !!!! */
                    while (pilot) {
                        PlayC64SB(sb_pilot);
                        pilot--;
                    }			/* Play PILOT TONE */
                    if (sb_sync1)
                        PlayC64SB(sb_sync1);	/* Play SYNC PULSES */


                    if (sb_sync2)
                            PlayC64SB(sb_sync2);
                        datapos = 0;
                    while (datalen) {	/* Play actual DATA */
                        if (datalen != 1) {
                            bitcount = 8;
                            PlayC64ROMByte(data[datapos], 0);
                        } else {
                            bitcount = lastbyte;
                            PlayC64ROMByte(data[datapos], 1);
                        }
                        databyte = data[datapos];
                        datalen--;
                        datapos++;
                    }
                    while (trailing) {
                        PlayC64SB(sb_trailing);
                        trailing--;
                    }			/* Play TRAILING TONE */
                    /* If there is pause after block present then make first millisecond
                     *	the oposite */
                    /* pulse of last pulse played and the rest in LOAMP ... otherwise
                     *	don't do ANY tzx_pause */


                    /*            if (tzx_pause) { PauseSB(amp,1); amp=LOAMP; if (tzx_pause>1) PauseSB(amp,tzx_pause-1); }*/


                    if (tzx_pause) {
                        PauseSB(amp, tzx_pause / 2);
                        ToggleAmp();
                        PauseSB(amp, (tzx_pause / 2) + (tzx_pause % 2));
                        ToggleAmp();
                    }
                }
            }
            if (tzx_info!= 1 && id == 0x17) {	/* C64 Turbo Tape data block ... */
                IdentifyC64Turbo(datalen, data, 0);

                if (curr == numblocks - 1)
                    //sprintf(pstr, "\0");
                    pstr[0]=0;
                else
                    sprintf(pstr, ",Pause: %2.3fs", ((float) tzx_pause) / 1000.0);

                if (draw)
                    debug_printf(VERBOSE_INFO," %s Length:%6d  %s%s", tstr, datalen, spdstr, pstr);
                if (tzx_info!= 2) {
                    sb_bit1 = ConvSB(sb_bit1);
                    sb_bit0 = ConvSB(sb_bit0);
                    amp = LOAMP;		/* This might be just opposite !!!! */
                    while (num_lead_in) {	/* Lead In bytes ! */
                        bitcount = 8;
                        PlayC64TurboByte(lead_in_byte);
                        num_lead_in--;
                    }
                    datapos = 0;
                    while (datalen) {	/* Play actual DATA */
                        if (datalen != 1)
                            bitcount = 8;
                        else
                            bitcount = lastbyte;
                        PlayC64TurboByte(data[datapos]);
                        databyte = data[datapos];
                        datalen--;
                        datapos++;
                    }
                    while (trailing) {	/* Trailing bytes ! */
                        bitcount = 8;
                        PlayC64TurboByte((unsigned char) sb_trailing);
                        trailing--;
                    }
                    /* If there is pause after block present then make first millisecond
                     *	the oposite */
                    /* pulse of last pulse played and the rest in LOAMP ... otherwise
                     *	don't do ANY tzx_pause */


                    /*            if (tzx_pause) { PauseSB(amp,1); amp=LOAMP; if (tzx_pause>1) PauseSB(amp,tzx_pause-1); }*/


                    if (tzx_pause) {
                        PauseSB(amp, tzx_pause / 2);
                        ToggleAmp();
                        PauseSB(amp, (tzx_pause / 2) + (tzx_pause % 2));
                        ToggleAmp();
                    }
                }
            }
            curr++;
        }

        if (!tzx_info) {
            PauseSB(amp, 1000);		/* Finish the loading with 1s pause ... */

            if (voc) {
                //StopVOC();
            }
            else if (au)
                StopAU();
            //else
            //StopSB();
        }
        //flushSBBuffer();		/* play the final bits in the audio buffer ?? */
        /**/
        free(memorig);

        //close(fh);
        fclose(ptr_archivo_entrada);

        return 0;
    }

