💾 Archived View for uscoffings.net › retro-computing › systems › TI994a › x99tape › x99tape_src › ma… captured on 2022-06-04 at 01:07:26.
View Raw
More Information
-=-=-=-=-=-=-
/*
Portable TI99 tape encoder/decoder
main.c: Console main() function, including command-line parser
syntax examples:
decode memory dump tape:
x99tape -d -m ROM2.wav ROM2.raw
x99tape -d -m basic_le�on1.wav basic_le�on1.raw
x99tape -d -m basic_le�on2.wav basic_le�on2.raw
x99tape -d -m basic_le�on3.wav basic_le�on3.raw
x99tape -d -m grom_dump1.wav grom_dump1.raw
x99tape -d -m intro.wav INTRO
x99tape -d -m poker.wav poker.raw
x99tape -d -m puissance_4.wav PUISSANCE4
x99tape -d -m splat(XB).wav splat(XB).raw
x99tape -d -m voyage.wav voyage.raw
x99tape -d -m test.wav TEST
decode multirecord tape:
x99tape -d -f ROM3.wav ROM3.raw
x99tape -d -f -r114 grille1.wav GRILLE1
x99tape -d -f -r128 grille1.wav GRILLE1
x99tape -d -f -r128 grille1b.wav GRILLE1B
encode a tape (TIFILE format):
x99tape -e INTRO test.wav
x99tape -e GRILLE1 grille1b.wav
x99tape -e PUISSANCE4 puissance_4.wav
encode memory dump tape (obsolete):
x99tape -e -m ROM2.raw ROM2.wav
x99tape -e -m grom_dump1.raw grom_dump1.wav
encode multirecord tape (obsolete):
x99tape -e -f -r114 grille1.raw grille1.wav
Raphael Nabet 2002
#include <console.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "my_bool.h"
#include "my_int.h"
#include "tifiles.h"
#include "wave.h"
#include "tape_dec.h"
#include "tape_enc.h"
/*
Set to 1 to display elapsed time after each file is processed
#define COMPUTE_ELAPSED_TIME 1
#if COMPUTE_ELAPSED_TIME
#include <time.h>
#endif
/*
Static prototypes
static error_t do_decode(const char *src_fname, const char *dst_fname, ftype_t file_type, unsigned int record_len);
static error_t do_encode(const char *src_fname, const char *dst_fname, ftype_t default_type, unsigned int default_reclen);
#if 0
/*
error strings
static char *error_strings[error_string_len-1] =
{
"Internal error", /* incorrect function parameter */
"This cannot be a multi-record tape", /* the tape cannot be a multi-record tape */
"Invalid record length", /* provided record len cannot be correct */
"This is not a wave file", /* wave file is incorrect */
"Only PCM-encoded wave files are supported", /* wave file may be correct, but belongs to a type that the program cannot handle */
"Can't open file", /* can't open file */
"Read error", /* error or unexpected EOF when reading file */
"Write error", /* error when writing file */
"EOF", /* expected EOF when reading file */
"Time out", /* timed out while looking for data */
};
#endif
/*
Defaults when no command line option is specified
enum
{
encode_default = false, /* decode tapes */
tape_type_default = ftype_program /* tapes are assumed to be program tapes */
};
/*
main func:
parse command line parameters
int main(int argc, char **argv)
{
error_t error;
bool encode;
ftype_t tape_type;
unsigned int record_len;
char *src_fname;
char *dst_fname;
int i;
int parse_step;
int file_processed_count;
bool suppress_option_parsing;
#if 1
/* Macintosh hack */
argc = ccommand(&argv);
#endif
/*if (strcmp(argv[0], "decode"))
encode = false;
else if (strcmp(argv[0], "encode"))
encode = true;
else*/
encode = encode_default;
tape_type = tape_type_default;
record_len = 0;
parse_step = 0;
file_processed_count = 0;
suppress_option_parsing = false;
for (i=1; i<argc; i++)
{
if ((argv[i][0] == '-') && (! suppress_option_parsing))
{
if (parse_step == 2)
{
fprintf(stderr, "Options should *precede* source file name.\n"
"Type: %s -h for help.\n", argv[0]);
return 1;
}
parse_step = 1;
if (argv[i][1] == '\0')
{
suppress_option_parsing = true;
}
else
{
switch (argv[i][1])
{
case 'h':
case 'H':
/* display help */
fprintf(stderr, "TI99 tape encoder/decoder\n"
"help:\n"
"\t%s -h\n"
"encode/decode:\n"
"\t%s [-d|-e] [-b|-m] [-r|-rNNN] [-] source1 dest1 [[[-e|-d] [-b|-m] [-r|-rNNN] [-] source2 dest2] ...]\n"
"-h: display this help message\n"
"-d: decode sampled tape into data file\n"
"-e: encode data file into sampled tape\n"
"-m: decode as memory dump tape\n"
"-f: decode as multirecord file tape\n"
"-r: use default record len for multirecord file tapes (64, 128 or 192 according to number of blocks per record)\n"
"-rNNN: specify record len for multirecord file tapes (should be in [1,192])\n"
"-: force next 2 parameters to be regarded as file names (required if either file name (or both) starts with a '-')\n", argv[0], argv[0]);
if (i == (argc-1))
return 0;
else
{
fprintf(stderr, "Help asked, ignoring remaining command line parameters\n");
return 1;
}
case 'e':
/* enter tape encode mode */
encode = true;
break;
case 'd':
/* enter tape decode mode */
encode = false;
break;
case 'f':
/* enter sequential file tape mode */
tape_type = ftype_data;
break;
case 'm':
/* enter memory dump tape mode */
tape_type = ftype_program;
break;
case 'r':
/* enter record len */
if (! argv[i][2])
/* no len: use default record len */
record_len = 0;
else
{ /* parse record len */
if (sscanf(argv[i]+2, "%u", &record_len) != 1)
{
fprintf(stderr, "Can't read record len NNN in '-rNNN' option.\n"
"Type: %s -h for help.\n", argv[0]);
return 1;
}
if ((record_len < 1) || (record_len > 192))
{
fprintf(stderr, "Incorrect record len %d (should be in [1,192])\n"
"Type: %s -h for help.\n", record_len, argv[0]);
return 1;
}
}
break;
default:
/* unknown option */
fprintf(stderr, "Unrecognized option.\n"
"Type: %s -h for help.\n", argv[0]);
return 1;
}
}
}
else
{
if ((parse_step == 0) || (parse_step == 1))
{
src_fname = argv[i];
parse_step = 2;
}
else
{
dst_fname = argv[i];
if (encode)
error = do_encode(src_fname, dst_fname, tape_type, record_len);
else
error = do_decode(src_fname, dst_fname, tape_type, record_len);
if (error)
{
fprintf(stderr, "error\n");
return 1;
}
file_processed_count++;
suppress_option_parsing = false;
parse_step = 0;
}
}
}
if (parse_step == 1)
{ /* some options, but no file name */
fprintf(stderr, "Source and destination file names missing.\n"
"Type: %s -h for help.\n", argv[0]);
return 1;
}
else if (parse_step == 2)
{ /* a source file name, but no destination */
fprintf(stderr, "Destination file name missing.\n"
"Type: %s -h for help.\n", argv[0]);
return 1;
}
else if (file_processed_count == 0)
{ /* No file was processed - not an error strictly speaking , but the user could obviously
use some help */
fprintf(stderr, "TI99 tape encoder/decoder\n"
"Type: %s -h for help.\n", argv[0]);
}
return 0;
}
/*
handle decode command
src_fname: name of source file
dst_fname: name of destination file
file_type: memory dump or data file
record_len: record length in bytes ([1,192], 0 for automatic)
static error_t do_decode(const char *src_fname, const char *dst_fname, ftype_t file_type, unsigned int record_len)
{
FILE *src, *dst;
error_t error = no_error;
wave_file_in_t wave_file;
tifile_out_t tifile;
#if COMPUTE_ELAPSED_TIME
clock_t start;
#endif
/*if (! file_type)
record_len = 64;*/
if ((record_len < 0) || (record_len > 192))
{
error = invalid_parameters;
goto error;
}
src = fopen(src_fname, "rb");
if (! src)
{
error = cant_open;
goto error;
}
dst = fopen(dst_fname, "wb");
if (! dst)
{
error = cant_open;
goto error2;
}
error = open_wave_in(src, & wave_file);
if (error)
goto error3;
error = open_tifile_out(dst, &tifile, file_type, record_len);
if (error)
goto error3;
#if COMPUTE_ELAPSED_TIME
start = clock();
#endif
error = read_tape(& wave_file, &tifile);
if (error)
goto error4;
#if COMPUTE_ELAPSED_TIME
fprintf(stderr, "Elapsed time (s): %f\n", (double) (clock()-start) / CLOCKS_PER_SEC);
#endif
error4:
close_tifile_out(&tifile);
error3:
fclose(dst);
error2:
fclose(src);
error:
return error;
}
/*
handle encode command
src_fname: name of source file
dst_fname: name of destination file
default_type: for raw binary source format: memory dump or data file
default_reclen: for raw binary source format: record length in bytes
([1,192], 0 admitted if encoding a program file (memory dump))
static error_t do_encode(const char *src_fname, const char *dst_fname, ftype_t default_type, unsigned int default_reclen)
{
FILE *src, *dst;
error_t error = no_error;
tifile_in_t tifile;
wave_file_out_t wave_file;
/* open source */
src = fopen(src_fname, "rb");
if (! src)
{
error = cant_open;
goto error;
}
error = open_tifile_in(src, & tifile, default_type, default_reclen);
if (error)
goto error3;
dst = fopen(dst_fname, "wb");
if (! dst)
{
error = cant_open;
goto error2;
}
error = open_wave_out(dst, 22050L, & wave_file);
if (error)
goto error3;
error = write_tape(& tifile, & wave_file);
if (error)
goto error3;
error = close_wave_out(& wave_file);
if (error)
goto error3;
error3:
fclose(dst);
error2:
fclose(src);
error:
return error;
}