/*----------------------------------------------------------------------

  WAV2PRG - a program which converts .WAV samples
  of Turbo Tape 64 files in .PRG, .P00 or .T64 files
  for use in emulators
  by Fabrizio Gennari and Janne Veli Kujala, (C) 1999
  
  This program 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 2, 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, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  --------------------------------------------------------------------*/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <ctype.h>

#ifndef MSDOS
#include <linux/soundcard.h>
#define O_BINARY 0
#endif

#include <signal.h>
#if !defined (SOUNDDEV)
#define SOUNDDEV "/dev/dsp"
#endif

#define NOT_VALID    0
#define WAV          1
#define WRONG_FORMAT 2
#define TAP          3

int inverted_waveform=0;
int ingresso;
int end_of_file=0;
int p00=0;
char try[24];
int skip_this;
int uscita;
int writing = 0;
int verbose = 1;
int argomenti_non_opzioni;
struct{
  unsigned char start_low;
  unsigned char start_high;
  unsigned char end_low;
  unsigned char end_high;
  char name[17];
}list_element[65536];
char* temporary_file_name;
int dsp_input=0;
/*int tap=0;*/
unsigned char tap_version;
int (*generic_bit)();

void help(){
  printf("Usage: wav2prg -h|-v\n");
  printf("       wav2prg [-i] [-p|-d|-t file[.t64] [-n name]] [input .WAV file]\n");
  printf("Options:\n");
  printf("       -a: enters adjust mode\n");
  printf("       -d: obsolete, for backwards compatibility only\n");
  printf("       -h: show this help message and exit successfully\n");
  printf("       -i: tell WAV2PRG that the .WAV file has inverted waveform\n");
  printf("       -n name: choose the internal name of the .t64 file\n");
  printf("       -p: output to .pXX files (PC64 emulator files, XX ranges
           from 00 to 99)\n");
  printf("       -t file[.t64]: output to file.t64\n");
  printf("       -v: show version and copyright info and exit successfully\n");
}

void version(){
  printf("WAV2PRG version 1.3, (C) by Fabrizio Gennari and Janne Veli Kujala, 1999, 2001\n");
  printf("This program is distributed under the GNU General Public License\n");
  printf("Read the file LICENSE for details\n\n");
  printf("This product uses functions for reducing the filenames to 8\n");
  printf("characters according to PC64 rules written by Wolfgang Lorenz.\n");
}

void SIGINThandler(int i)
{

  end_of_file = 1;

}


#define BUFSIZE 256
static unsigned char buf[BUFSIZE];
static int buf_len = BUFSIZE;
static int buf_pos = BUFSIZE;

void init_buffering()
{
  buf_len = BUFSIZE;
  buf_pos = buf_len;
}

int buffered_read_byte(int fd)
{
  if (buf_pos == buf_len) 
    {
      buf_pos = 0;
      buf_len = read(fd, buf, buf_len);
      if (buf_len <= 0) 
	return -1;
    }

  return buf[buf_pos++];
}

int buffered_position(int fd)
{
  return lseek(fd, 0, SEEK_CUR) - (buf_len - buf_pos);
}

int check_if_WAV(int ingresso){
  int byteletti;
  char WAV_header[16]={1,0,1,0,68,172,0,0,68,172,0,0,1,0,8,0};
  char lettura[16];
  lseek(ingresso,0,SEEK_SET);
  byteletti=read(ingresso,lettura,4);
  lettura[4]=0;
  if ((byteletti!=4)||(strcmp(lettura,"RIFF")))
    return NOT_VALID;
  if ((byteletti=lseek(ingresso,8,SEEK_SET))!=8)
    return NOT_VALID;
  byteletti=read(ingresso,lettura,8);
  lettura[8]=0;
  if ((byteletti!=8)||(strcmp(lettura,"WAVEfmt ")))
    return NOT_VALID;
  if ((byteletti=lseek(ingresso,20,SEEK_SET))!=20)
    return NOT_VALID;
  byteletti=read(ingresso,lettura,16);
  if (byteletti!=16)
    return NOT_VALID;
  if (memcmp(lettura,WAV_header,16))
    return WRONG_FORMAT;
  return WAV;
}

int check_if_TAP(int ingresso){
  int byteletti;
  char TAP_header[12]="C64-TAPE-RAW";
  char lettura[12];
  lseek(ingresso,0,SEEK_SET);
  byteletti=read(ingresso,lettura,12);
  if ((byteletti!=12)||(strncmp(lettura,TAP_header,12)))
    return NOT_VALID;
  byteletti=read(ingresso,&tap_version,1);
  if (byteletti!=1)
    return NOT_VALID;
  return TAP;
}

int check_if_valid(int ingresso){
  int check;
  if (check=check_if_WAV(ingresso))return check;
  return check_if_TAP(ingresso);
}

static long impulse_count[2];
static long impulse_len[2];

void init_stats()
{
  impulse_count[0] = impulse_len[0] = 0;
  impulse_count[1] = impulse_len[1] = 0;
}

void print_stats()
{
  int i;
  for (i = 0; i < 2; i++)
    {
      if (impulse_count[i] == 0) break;
      printf("Bit %d: count = %ld, avg len = %.2lf (%.1lf us)\n",
	     i, impulse_count[i],
	     (double)impulse_len[i] / impulse_count[i],
	     (1000000.0 / 44100) * impulse_len[i] / impulse_count[i]);
    }
	 
}

int bit(){
  static int byte = 255;
  static int new_byte = 255;
  int old_byte;
  int up,new_up;
  int old_up=0;
  int len = 0;
  int min_pos;
  int reached_min=0;
  int c;
  
  for (;;)
    {
      old_byte = byte;
      byte=new_byte;
      old_up = up;
         
      len++;
      if ((new_byte = buffered_read_byte(ingresso)) == -1)
	{
	  end_of_file = 1;
	  return 1;
	}
      
      if (inverted_waveform) new_byte = ~new_byte;
      
      if (byte==old_byte) up=!old_up;
      else up = (byte > old_byte);
      if (up != old_up)
	{
	  if (byte==new_byte) new_up=up;
	  else new_up= (new_byte>byte);
	  if (up)
 	    {
	      if ((len>=3)&&(new_up)&&(!reached_min)){
		min_pos=len;
		reached_min=1;
	      }
	    }
	  else{
	    if ((len-min_pos>3)&&(!new_up)&&(reached_min)){
	      break;
	    }
	  }
	}
    }

  if (verbose && writing)
	{
	  impulse_count[(len >= 13)]++;
	  impulse_len[(len >= 13)] += len;
	  
	  /* Warn if impulse length is extreme or near threshold */
	  if (len < 9 || len == 12 || len >= 17)
	    {
	      c = impulse_count[0] + impulse_count[1];
	      if (!dsp_input){
		printf("Infile pos: %d, ",buffered_position(ingresso));
	      }
  	      printf("data pos: byte %d, bit %d, impulse len %d\n"
  		     , c >> 3, c & 7, len);
	    }
	}

  return len >= 13 ? 1 : 0;
    }

int tap_bit(){
  int duration, sum=1;
  duration=buffered_read_byte(ingresso)*8;
  if (duration < 0){
    end_of_file = 1;
    return 0;
  }
  if (duration==0){
    if (tap_version==0)duration=255*8;
    else do{
      duration+=sum*buffered_read_byte(ingresso);
      sum<<8;
    } while (sum <= 65536);
  }
  impulse_count[(duration < 263)]++;
  impulse_len[(duration < 263)] += duration*44100/985248;
  return (duration<263) ? 0 : 1;
}

unsigned char readbyte(){
  unsigned char byte=0;
  int b;
  for (b = 0; b < 8; b++)
    byte = (byte << 1)  | generic_bit();
  return byte;
}

void seek_for_header(){
  unsigned char memoria = 0;
  int conta;
  unsigned char controllo;
  do{
    do memoria = (memoria << 1) | generic_bit();
    while((memoria!=2)&&(!end_of_file));
    while((memoria==2)&&(!end_of_file)) memoria=readbyte();
    controllo=9;
    while((!end_of_file)&&(memoria==controllo)&&(controllo>1)){
      memoria=readbyte();
      controllo--;
    };
  }while((memoria!=controllo)&&(!end_of_file));
}

void remove_spaces(char* name){
  int byte=15;
  while((byte>=0)&&(name[byte]==' ')) name[byte--]=0;
}

char* choose_name(char* pc_name,int files_with_this_name){
  if(!p00){
    if (!files_with_this_name){
      sprintf(try,"%s.prg",pc_name);
    }
    else sprintf(try,"%s_%d.prg",pc_name,files_with_this_name);
  }
  else sprintf(try,"%s.p%02d",pc_name,files_with_this_name);
  return try;
}

int file_exists(char* try){
  if ((uscita=open(try,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))==-1){
    return 1;
  }
  else return 0;
}

void automatic_rename(char* pc_name){
  int files_with_this_name=0;
  while(files_with_this_name<100){
    if (!file_exists(strcpy(try,choose_name(pc_name,files_with_this_name)))) break;
    printf("File %s exists or cannot be created\n",try);
    files_with_this_name++;
  }
  if (files_with_this_name==100){
    printf("Could not write this file. The maximum file count has
been reached.\n");
    skip_this=1;
  }
}

#ifdef MSDOS
void clean_stdin(){
  char useless_byte;
  do {
    useless_byte=fgetc(stdin);
  } while ((useless_byte!=EOF)&&(useless_byte!='\n'));
}

void manual_rename(){
  char enter;
  int choose_another_name=1;
  while (choose_another_name){
    printf("Enter new name (without the extension .prg, enter an empty
string if you want to skip this file):");
    fgets(try,9,stdin);
    if ((strlen(try)==8)&&(try[7]!='\n')) clean_stdin();
    if (try[strlen(try)-1]=='\n') try[strlen(try)-1]=0;
    if (strlen(try)==0) {
       skip_this=1;
       break;
    }
    strcat(try,".prg");
    if (!file_exists(try)) break;
    printf("File %s exists. Overwrite, Rename, Skip? [S] ",try);
    scanf("%c",&enter);
    if ((enter!=EOF)&&(enter!='\n')) clean_stdin();
    if ((enter!='r')&&(enter!='R')&&(enter!='o')&&(enter!='O')){
       skip_this=1;
       break;
    }
    if ((enter=='O')||(enter=='o')) {
       uscita=open(try,O_WRONLY|O_TRUNC|O_BINARY,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
       if (uscita==-1){
          printf("File %s cannot be created\n",try);
          choose_another_name=1;
       }
       else choose_another_name=0;
    }
    else choose_another_name=1;
  }
  return;
}
#endif /* MSDOS */

/* The following two functions were taken from
   Wolfgang Lorenz's T64TOP00.CPP, with minor
   changes */

static inline int isvocal(char c) {
  return memchr("AEIOU", c, 5) ? 1 : 0;
}

int ReduceName(const char* sC64Name, char* pDosName) {
  int iStart;
  char sBuf[16 + 1];
  int iLen = strlen(sC64Name);
  int i;
  char* p = pDosName;
  int hFile;
  if (iLen > 16) {
    return 0;
  }

  if (strpbrk(sC64Name, "*?")) {
    strcpy(pDosName, "*");
    return 1;
  }

  memset(sBuf, 0, 16);
  strcpy(sBuf, sC64Name);

  for (i = 0; i <= 15; i++) {
    switch (sBuf[i]) {
    case ' ':
    case '-':

      sBuf[i] = '_';
      break;
    default:

      if (islower(sBuf[i])) {
        sBuf[i] -= 32;
        break;
      }

      if (isalnum(sBuf[i])) {
        break;
      }

      if (sBuf[i]) {
        sBuf[i] = 0;
        iLen--;
      }
    }
  }

  if (iLen <= 8) {
    goto Copy;
  }

  for (i = 15; i >= 0; i--) {
    if (sBuf[i] == '_') {
      sBuf[i] = 0;
      if (--iLen <= 8) {
        goto Copy;
      }
    }
  }

  for (iStart = 0; iStart < 15; iStart++) {
    if (sBuf[iStart] && !isvocal(sBuf[iStart])) {
      break;
    }
  }

  for (i = 15; i >= iStart; i--) {
    if (isvocal(sBuf[i])) {
      sBuf[i] = 0;
      if (--iLen <= 8) {
        goto Copy;
      }
    }
  }

  for (i = 15; i >= 0; i--) {
    if (isalpha(sBuf[i])) {
      sBuf[i] = 0;
      if (--iLen <= 8) {
        goto Copy;
      }
    }
  }

  for (i = 0; i <= 15; i++) {
    if (sBuf[i]) {
      sBuf[i] = 0;
      if (--iLen <= 8) {
        goto Copy;
      }
    }
  }
Copy:

  if (!iLen) {
    strcpy(pDosName, "_");
    return 1;
  }

  for (i = 0; i <= 15; i++) {
    if (sBuf[i]) {
      *p++ = sBuf[i];
    }
  }
  *p = 0;

#ifdef MSDOS
    hFile = open(pDosName,O_RDONLY);
    if (hFile == -1) {
      return 1;
    }

    if (isatty(hFile)) {
      if (iLen < 8) {
        strcat(pDosName, "_");
      } else if (pDosName[7] != '_') {
        pDosName[7] = '_';
      } else {
        pDosName[7] = 'X';
      }
    }

    close(hFile);
#endif

  return 1; 
}

/* End of the part written by Wolfgang Lorenz */

void fill_with_spaces_and_convert_to_uppercase(char* dest,char* src,int string_length){
  int count;
  for(count=0;count<string_length;count++)
    if (count<strlen(src)) dest[count]=toupper(src[count]); else dest[count]=' ';
}

void create_t64(int files,int des,char* tape_name){
  char T64_header[64]={'C','6','4',' ','t','a','p','e',' ','i','m','a','g','e',' ','f','i','l','e',0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,'G','E','N','E','R','A','T','E','D',' ','B','Y',' ','W','A','V','2','P','R','G',' ',' ',' ',' '};
  int temporaneo;
  char buffer[65536];
  int count1;
  int count2;
  unsigned char byte[16]={1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  int offset=(files+2)*32;
  int file_length;
  if (tape_name!=NULL)
    fill_with_spaces_and_convert_to_uppercase(T64_header+40,tape_name,24);
  T64_header[35]=T64_header[37]=files>>8;
  T64_header[34]=T64_header[36]=files&255;
  write(des,T64_header,64);
  for(count1=0;count1<files;count1++){
    byte[2]=list_element[count1].start_low;
    byte[3]=list_element[count1].start_high;
    byte[4]=list_element[count1].end_low;
    byte[5]=list_element[count1].end_high;
    for(count2=3;count2>=0;count2--)
      byte[count2+8] = (offset >> 8*count2) & 255;
    write(des,byte,16);
    write(des,list_element[count1].name,16);
    offset=offset+byte[5]*256+byte[4]-byte[3]*256-byte[2];
  };
  temporaneo=open(temporary_file_name,O_RDONLY|O_BINARY);
  for(count1=0;count1<files;count1++){
    file_length=-list_element[count1].start_low-list_element[count1].start_high*256+list_element[count1].end_low+list_element[count1].end_high*256;
    read(temporaneo,buffer,file_length);
    write(des,buffer,file_length);
  };
  close(temporaneo);
  close(des);
  unlink(temporary_file_name);
};

int main(int numarg,char** argo){
  int opzione;
  int show_help=0;
  int show_version=0;
  int check;
  int converted_files=0;
  int errorlevel=0;
  int checksum_errors=0;
  int broken_file=0;
  unsigned char byte;
  unsigned char checksum;
  unsigned char start_address_low;
  unsigned char start_address_high;
  unsigned char end_address_low;
  unsigned char end_address_high;
  int start_address;
  int end_address;
  int write_address;
  char c64_name[17];
  char c64_name_without_trailing_spaces[17];
  char pc_name[20];
  char* t64_name;
  int count;
  int skipped_files=0;
  int t64=0;
  int t64_descriptor;
  char P00_header[8]={'C','6','4','F','i','l','e',0};
  int total_converted_files=0;
  char* tape_name=NULL;
  int append_t64=0;
  int t64_filename_length;
  int adjust=0;
  char* input_file;
  int custom_t64_name=0;

  while ((opzione=getopt(numarg,argo,"adhin:pt:v"))!=EOF){
    switch(opzione){
    case 'a':
      adjust=1;
      break;
    case 'd':
      printf("Option -d obsolete, ignoring\n");
      break;
    case 'h':
      show_help=1;
      break;
    case 'i':
      inverted_waveform=1;
      break;
    case 'n':
      custom_t64_name=1;
      tape_name=(char*)malloc(strlen(optarg)+1);
      strcpy(tape_name,optarg);
      break;
    case 'p':
      p00=1;
      break;
    case 't':
      t64=1;
      t64_name=(char*)malloc(strlen(optarg)+5);
      strcpy(t64_name,optarg);
      break;
    case 'v':
      show_version=1;
      break;
   default:
      help();
      return 1;
    };
  }
  if (show_help==1){
    help();
    return 0;
  };
  if (show_version==1){
    version();
    return 0;
  };

  signal(SIGINT, SIGINThandler);
                                
  if(adjust){

  #ifdef MSDOS
         printf("Adjust mode is not allowed on MS-DOS");
         return 1;
  }
  #else
    if ((ingresso=open(SOUNDDEV,O_RDONLY))==-1){
      printf("Could not open file %s\n",SOUNDDEV);
      return 3;
    }
    else{
      check = 44100;
      if (ioctl(ingresso, SNDCTL_DSP_SPEED, &check) != 0 || check != 44100){
	printf("Could not set sampling speed to 44100 Hz in file %s\n",SOUNDDEV);
	return 3;
      }
    };
    printf("Entering adjust mode, press Ctrl-C to exit\n");
    writing=1;
    dsp_input=1;
    while(!end_of_file) bit();
    return 0;
  };
  #endif /* MSDOS */

  /* Check if options are consistent */
  
  if ((p00==1)&&(t64==1)){
    printf("The options -p and -t cannot be used together\n");
    help();
    return 1;
  };

  if ((custom_t64_name)&&(!t64)){
    printf("The option -n can only be used along with -t\n");
    help();
    return 1;
  };

  /* Check if the right number of arguments was given */

  argomenti_non_opzioni=numarg-optind;

  switch(argomenti_non_opzioni){
  case 0:
  #ifdef MSDOS
    printf("You must specify the input file name!\n");
    return 3;
  #else
    dsp_input=1;
    input_file=(char*)malloc(strlen(SOUNDDEV)+1);
    strcpy(input_file,SOUNDDEV);
    if ((ingresso=open(SOUNDDEV,O_RDONLY))==-1){
      printf("Could not open file %s\n",SOUNDDEV);
      return 3;
    }
    else{
      check = 44100;
      if (ioctl(ingresso, SNDCTL_DSP_SPEED, &check) != 0 || check != 44100){
	printf("Could not set sampling speed to 44100 Hz in file %s\n",SOUNDDEV);
	return 3;
      }
    };
    generic_bit=bit;
    break;
  #endif /* MSDOS*/
  case 1:
    input_file=(char*)malloc(strlen(argo[optind])+1);
    strcpy(input_file,argo[optind]);
    if ((ingresso=open(argo[optind],O_RDONLY|O_BINARY))==-1){
      printf("Could not open file %s\n",argo[optind]);
      return 3;
    }
    check=check_if_valid(ingresso);
    switch(check){
    case NOT_VALID:
      printf("%s is not a WAV or a TAP file\n",argo[optind]);
      return 4;
      break;
    case WRONG_FORMAT:
      printf("WAV2PRG will only convert WAV files in this format:\n"
	     "PCM uncompressed, mono, 8 bits/sample, 44100 samples/second.\n"
	     "%s has a different format\n",argo[optind]);
      return 4;
      break;
    case WAV:
      lseek(ingresso,44,SEEK_SET);
      generic_bit=bit;
      break;
    case TAP:
      lseek(ingresso,20,SEEK_SET);
      generic_bit=tap_bit;
    default:
    };
    break;
  default:
    printf("Too many arguments\n");
    help();
    return 2;
  };
  
  if(t64){
    
    /* Create temporary file, with file descriptor uscita.
       The data will be written here. At the end, they will be
       transferred in the .T64 file */
    /*#ifdef MSDOS
    temp_name = getenv("TEMP");
#else
    strdup(temp_name,"/tmp");
    #endif*/

    if((uscita=open(temporary_file_name=tempnam(NULL/*temp_name*/,"wp"),O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))==-1){
      printf("Could not create temporary file\n");
      return 5;
    };
    
    /* If the .T64 filename doesn't end with .T64 or .t64,
       append .t64 at the end */
    
    if ((t64_filename_length=strlen(t64_name))<5) append_t64=1;
    else
      if ((strcmp(t64_name+t64_filename_length-4,".t64"))&&
	  (strcmp(t64_name+t64_filename_length-4,".T64"))) append_t64=1;
    if (append_t64) strcpy(t64_name+t64_filename_length,".t64");
    if ((t64_descriptor=open(t64_name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))==-1){
      printf("Could not create file %s\n",t64_name);
      unlink(temporary_file_name);
      return 5;
    };
  };

  /* Start the actual conversion */

  init_buffering(); /* Initialize buffering for input file */

 inizio:
  printf("Searching for a Turbo Tape header in %s...\n",input_file);
  do{
    seek_for_header();
    byte=readbyte();
    if (end_of_file) break;
  }while ((byte!=1)&&(byte!=2));
  start_address_low=readbyte();
  start_address_high=readbyte();
  start_address=start_address_low+start_address_high*256;
  end_address_low=readbyte();
  end_address_high=readbyte();
  end_address=end_address_low+end_address_high*256;
  byte=readbyte();
  for(byte=0;byte<16;byte++) c64_name[byte]=readbyte();
  c64_name[16]=0;
  for(count=1;count<=171;count++) byte=readbyte();
  seek_for_header();
  byte=readbyte();
  if (end_of_file){
    close(ingresso);
    if(t64){
      close(uscita);
      create_t64(total_converted_files,t64_descriptor,tape_name);
      if (!total_converted_files) unlink(t64_name);
    };
    printf("End of file %s\n",input_file);
    printf("Files successfully converted: %d\n",converted_files);
    printf("Files converted with checksum errors: %d\n",checksum_errors);
    printf("Skipped files: %d\n",skipped_files);
    if ((broken_file)&&(!t64)) printf("The file %s is broken\n",try);
    return errorlevel;
  };
  printf("Found %s\n",c64_name);
  printf("Start address: %d (hex %04x)\n",start_address,start_address);
  printf("End address: %d (hex %04x)\n",end_address,end_address);
  skip_this=0;
  if (!t64){
    strcpy(c64_name_without_trailing_spaces,c64_name);
    remove_spaces(c64_name_without_trailing_spaces);
    if (p00) ReduceName(c64_name_without_trailing_spaces,pc_name);
    else{
      if(strlen(c64_name_without_trailing_spaces))
	strcpy(pc_name,c64_name_without_trailing_spaces);
      else strcpy(pc_name,"default");
    };

    /* automatic_rename opens the output file
and assigns the file descriptor uscita to it. If it cannot do so
for some reasons, it sets skip_this to 1 */
#ifdef MSDOS
    if (!p00) manual_rename(); else
#endif
    automatic_rename(pc_name);
  }

  if (skip_this){
    printf("Skipping %s\n",c64_name);
    for(write_address=start_address;write_address<=end_address;write_address++)
      byte=readbyte();
    skipped_files++;
    goto inizio;
  };
  if (!t64){
    printf("Writing file %s...\n",try);
    if (p00) {
      write(uscita,P00_header,8);
      write(uscita,c64_name,16);
      write(uscita,"\0\0",2);
    };
    write(uscita,&start_address_low,1);
    write(uscita,&start_address_high,1);
  }
  else printf("Converting %s\n",c64_name);
  checksum=0;
  writing = 1;
  init_stats();
  for(write_address=start_address;write_address<end_address;write_address++){
    byte=readbyte();
    write(uscita,&byte,1);
    checksum=checksum^byte;
    if (end_of_file) break;
  };
  writing = 0;
  if (verbose)
    print_stats();

  byte=readbyte();
  if (end_of_file){
    broken_file=1;
    if (dsp_input) printf("Interrupted while converting\n");
    else printf("The WAV file ended unexpectedly\n");
    errorlevel=8;
  }
  else{
    if (byte==checksum){
      printf("Successful\n");
      converted_files++;
    }
    else{
      printf("Checksum error!\n");
      checksum_errors++;
      errorlevel=8;
    };
  };

  /* If converting to .P00 or .PRG, create one file for each program.
     If converting to .T64, convert everyting to the same file */

  if (!t64) close(uscita); 
  else{
    if(!broken_file){
      list_element[total_converted_files].start_low=start_address_low;
      list_element[total_converted_files].start_high=start_address_high;
      list_element[total_converted_files].end_low=end_address_low;
      list_element[total_converted_files].end_high=end_address_high;
      strcpy(list_element[total_converted_files].name,c64_name);
      total_converted_files++;
      if(total_converted_files==65536){ /* very unlikely... */
	end_of_file=1;
	printf("Sorry, a T64 file cannot contain more than 65536 files\n");
      };
    }
    else{
      printf("Skipping %s\n",c64_name);
      skipped_files++;
    };
  };

  printf("\n");
  goto inizio;
  }
