fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 651 lines 14 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/utils/pti/main.c * 7 * Created: 2020-04-25 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2020-2023 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include "main.h" 24#include "comment.h" 25#include "ops.h" 26 27#include <stdlib.h> 28#include <stdio.h> 29#include <string.h> 30 31#include <lib/getopt.h> 32 33#include <drivers/pti/pti.h> 34#include <drivers/pti/pti-io.h> 35 36 37int pti_info (pti_img_t *img); 38 39 40const char *arg0 = NULL; 41 42int par_verbose = 0; 43 44int par_print_info = 0; 45 46unsigned par_fmt_inp = PTI_FORMAT_NONE; 47unsigned par_fmt_out = PTI_FORMAT_NONE; 48 49unsigned long par_default_clock = PTI_CLOCK_C64_PAL; 50 51 52static pce_option_t opts[] = { 53 { '?', 0, "help", NULL, "Print usage information" }, 54 { 'c', 1, "default-clock","clock", "Set the default clock [c64-pal]" }, 55 { 'f', 0, "info", NULL, "Print image information [no]" }, 56 { 'i', 1, "input", "filename", "Load an input file" }, 57 { 'I', 1, "input-format", "format", "Set the input format [auto]" }, 58 { 'm', 1, "cat", "filename", "Concatenate an image" }, 59 { 'o', 1, "output", "filename", "Set the output file name [none]" }, 60 { 'O', 1, "output-format", "format", "Set the output format [auto]" }, 61 { 'p', 1, "operation", "name [...]", "Perform an operation" }, 62 { 's', 2, "set", "par val", "Set a parameter value" }, 63 { 'v', 0, "verbose", NULL, "Verbose operation [no]" }, 64 { 'V', 0, "version", NULL, "Print version information" }, 65 { -1, 0, NULL, NULL, NULL } 66}; 67 68 69static 70void print_help (void) 71{ 72 pce_getopt_help ( 73 "pti: convert and modify PCE Tape Image files", 74 "usage: pti [options] [input] [options] [output]", 75 opts 76 ); 77 78 fputs ( 79 "\n" 80 "operations are:\n" 81 " cat <file> Add an image to the end of the current image\n" 82 " comment-add text Add to the image comment\n" 83 " comment-load filename Load the image comment from a file\n" 84 " comment-print Print the image comment\n" 85 " comment-save filename Save the image comment to a file\n" 86 " comment-set text Set the image comment\n" 87 " duty-cycle <low> <high> Adjust the duty cycles\n" 88 " decode <type> <file> Decode tracks\n" 89 " encode <type> <file> Encode a file\n" 90 " fix-clock <clock> Set the sample clock without modifying the image\n" 91 " info Print image information\n" 92 " invert Invert the amplitude\n" 93 " new Create a new image\n" 94 " scale <factor> Scale the image by a factor\n" 95 " set-clock <clock> Set the sample clock rate\n" 96 " space-add-left <time> Add space at the beginning\n" 97 " space-add-right <time> Add space at the end\n" 98 " space-add <time> Add space at the beginning and end\n" 99 " space-auto <mintime> Convert constant levels to silence\n" 100 " space-max <time> Limit the length of silence periods\n" 101 " space-trim-left Remove space from the beginning\n" 102 " space-trim-right Remove space from the end\n" 103 " space-trim Remove space from the beginning and end\n" 104 " trim-left <time> Cut time from the beginning\n" 105 " trim-right <time> Cut time from the end\n" 106 "\n" 107 "sample clocks are:\n" 108 " c16-ntsc, c16-pal, c64-ntsc, c64-pal, pc-pic, pc-cpu, pet,\n" 109 " vic20-ntsc, vic20-pal, <int>\n" 110 "\n" 111 "parameters are:\n" 112 " default-clock, pcm-srate,\n" 113 " wav-bits, wav-lowpass, wav-lowpass-order, wav-srate\n" 114 "\n" 115 "decode types are:\n" 116 " cbm-t64, cbm-raw\n" 117 "\n" 118 "encode types are:\n" 119 " cbm-bas, cbm-prg\n" 120 "\n" 121 "file formats are:\n" 122 " cas, pcm, pti, t64(r), tap, txt, wav\n", 123 stdout 124 ); 125 126 fflush (stdout); 127} 128 129static 130void print_version (void) 131{ 132 fputs ( 133 "pti version " PCE_VERSION_STR 134 "\n\n" 135 "Copyright (C) 2020-" PCE_YEAR " Hampa Hug <hampa@hampa.ch>\n", 136 stdout 137 ); 138 139 fflush (stdout); 140} 141 142int pti_parse_double (const char *str, double *val) 143{ 144 char *end; 145 146 if ((str == NULL) || (*str == 0)) { 147 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 148 return (1); 149 } 150 151 *val = strtod (str, &end); 152 153 if ((end != NULL) && (*end == 0)) { 154 return (0); 155 } 156 157 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 158 159 return (1); 160} 161 162int pti_parse_long (const char *str, long *val) 163{ 164 char *end; 165 166 if ((str == NULL) || (*str == 0)) { 167 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 168 return (1); 169 } 170 171 *val = strtol (str, &end, 0); 172 173 if ((end != NULL) && (*end == 0)) { 174 return (0); 175 } 176 177 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 178 179 return (1); 180} 181 182int pti_parse_ulong (const char *str, unsigned long *val) 183{ 184 char *end; 185 186 if ((str == NULL) || (*str == 0)) { 187 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 188 return (1); 189 } 190 191 *val = strtoul (str, &end, 0); 192 193 if ((end != NULL) && (*end == 0)) { 194 return (0); 195 } 196 197 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 198 199 return (1); 200} 201 202int pti_parse_uint (const char *str, unsigned *val) 203{ 204 unsigned long tmp; 205 206 if (pti_parse_ulong (str, &tmp)) { 207 return (1); 208 } 209 210 *val = tmp; 211 212 return (0); 213} 214 215int pti_parse_bool (const char *str, int *val) 216{ 217 unsigned long tmp; 218 219 if (pti_parse_ulong (str, &tmp)) { 220 return (1); 221 } 222 223 *val = tmp != 0; 224 225 return (0); 226} 227 228static 229int pti_parse_clock (const char *str, unsigned long *val) 230{ 231 if (strcmp (str, "pet") == 0) { 232 *val = PTI_CLOCK_PET; 233 } 234 else if (strcmp (str, "vic20-ntsc") == 0) { 235 *val = PTI_CLOCK_VIC20_NTSC; 236 } 237 else if (strcmp (str, "vic20-pal") == 0) { 238 *val = PTI_CLOCK_VIC20_PAL; 239 } 240 else if (strcmp (str, "c64-ntsc") == 0) { 241 *val = PTI_CLOCK_C64_NTSC; 242 } 243 else if (strcmp (str, "c64-pal") == 0) { 244 *val = PTI_CLOCK_C64_PAL; 245 } 246 else if (strcmp (str, "c16-ntsc") == 0) { 247 *val = PTI_CLOCK_C16_NTSC; 248 } 249 else if (strcmp (str, "c16-pal") == 0) { 250 *val = PTI_CLOCK_C16_PAL; 251 } 252 else if ((strcmp (str, "pc-pit") == 0) || (strcmp (str, "pc") == 0)) { 253 *val = PTI_CLOCK_PC_PIT; 254 } 255 else if (strcmp (str, "pc-cpu") == 0) { 256 *val = PTI_CLOCK_PC_CPU; 257 } 258 else { 259 return (1); 260 } 261 262 return (0); 263} 264 265int pti_parse_freq (const char *str, unsigned long *val) 266{ 267 char *end; 268 269 if ((str == NULL) || (*str == 0)) { 270 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 271 return (1); 272 } 273 274 if (pti_parse_clock (str, val) == 0) { 275 return (0); 276 } 277 278 *val = strtoul (str, &end, 0); 279 280 if ((end == NULL) || (*end == 0)) { 281 return (0); 282 } 283 284 if ((*end == 'k') || (*end == 'K')) { 285 *val *= 1000; 286 end += 1; 287 } 288 else if ((*end == 'm') || (*end == 'M')) { 289 *val *= 1000000; 290 end += 1; 291 } 292 293 if (*end != 0) { 294 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 295 return (1); 296 } 297 298 return (0); 299} 300 301int pti_parse_time_sec (const char *str, double *sec) 302{ 303 char *end; 304 305 if ((str == NULL) || (*str == 0)) { 306 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 307 return (1); 308 } 309 310 *sec = strtod (str, &end); 311 312 if ((end == NULL) || (*end == 0)) { 313 return (0); 314 } 315 316 if (strcmp (end, "s") == 0) { 317 ; 318 } 319 else if (strcmp (end, "ms") == 0) { 320 *sec /= 1000.0; 321 } 322 else if (strcmp (end, "us") == 0) { 323 *sec /= 1000000.0; 324 } 325 else { 326 fprintf (stderr, "%s: bad value (%s)\n", arg0, str); 327 return (1); 328 } 329 330 return (0); 331} 332 333int pti_parse_time_clk (const char *str, unsigned long *sec, unsigned long *clk, unsigned long clock) 334{ 335 double tmp; 336 337 if (pti_parse_time_sec (str, &tmp)) { 338 return (1); 339 } 340 341 pti_time_set (sec, clk, tmp, clock); 342 343 return (0); 344} 345 346static 347int pti_set_format (const char *name, unsigned *val) 348{ 349 if (strcmp (name, "cas") == 0) { 350 *val = PTI_FORMAT_CAS; 351 } 352 else if (strcmp (name, "pcm") == 0) { 353 *val = PTI_FORMAT_PCM; 354 } 355 else if (strcmp (name, "pti") == 0) { 356 *val = PTI_FORMAT_PTI; 357 } 358 else if (strcmp (name, "tap") == 0) { 359 *val = PTI_FORMAT_TAP; 360 } 361 else if (strcmp (name, "txt") == 0) { 362 *val = PTI_FORMAT_TXT; 363 } 364 else if (strcmp (name, "wav") == 0) { 365 *val = PTI_FORMAT_WAV; 366 } 367 else { 368 fprintf (stderr, "%s: unknown format (%s)\n", arg0, name); 369 *val = PTI_FORMAT_NONE; 370 return (1); 371 } 372 373 return (0); 374} 375 376pti_img_t *pti_load_image (const char *fname) 377{ 378 pti_img_t *img; 379 380 if (par_verbose) { 381 fprintf (stderr, "%s: load image from %s\n", arg0, fname); 382 } 383 384 if (strcmp (fname, "-") == 0) { 385 img = pti_img_load_fp (stdin, par_fmt_inp); 386 } 387 else { 388 img = pti_img_load (fname, par_fmt_inp); 389 } 390 391 if (img == NULL) { 392 fprintf (stderr, "%s: loading failed (%s)\n", arg0, fname); 393 return (NULL); 394 } 395 396 if (par_print_info) { 397 par_print_info = 0; 398 pti_info (img); 399 } 400 401 return (img); 402} 403 404int pti_save_image (const char *fname, pti_img_t **img) 405{ 406 int r; 407 408 if (*img == NULL) { 409 *img = pti_img_new(); 410 } 411 412 if (*img == NULL) { 413 return (1); 414 } 415 416 if (par_verbose) { 417 fprintf (stderr, "%s: save image to %s\n", arg0, fname); 418 } 419 420 if (strcmp (fname, "-") == 0) { 421 r = pti_img_save_fp (stdout, *img, par_fmt_out); 422 } 423 else { 424 r = pti_img_save (fname, *img, par_fmt_out); 425 } 426 427 if (r) { 428 fprintf (stderr, "%s: saving failed (%s)\n", 429 arg0, fname 430 ); 431 432 return (1); 433 } 434 435 return (0); 436} 437 438static 439int pti_set_parameter (const char *name, const char *val) 440{ 441 if (strcmp (name, "default-clock") == 0) { 442 if (pti_parse_freq (val, &par_default_clock)) { 443 return (1); 444 } 445 446 pti_set_default_clock (par_default_clock); 447 } 448 else if (strcmp (name, "pcm-srate") == 0) { 449 unsigned long srate; 450 451 if (pti_parse_freq (val, &srate)) { 452 return (1); 453 } 454 455 pti_pcm_set_default_srate (srate); 456 } 457 else if (strcmp (name, "wav-bits") == 0) { 458 unsigned bits; 459 460 if (pti_parse_uint (val, &bits)) { 461 return (1); 462 } 463 464 pti_wav_set_bits (bits); 465 } 466 else if (strcmp (name, "wav-lowpass") == 0) { 467 unsigned long cutoff; 468 469 if (pti_parse_ulong (val, &cutoff)) { 470 return (1); 471 } 472 473 pti_wav_set_lowpass (cutoff); 474 } 475 else if (strcmp (name, "wav-lowpass-order") == 0) { 476 unsigned order; 477 478 if (pti_parse_uint (val, &order)) { 479 return (1); 480 } 481 482 pti_wav_set_lowpass_order (order); 483 } 484 else if (strcmp (name, "wav-srate") == 0) { 485 unsigned long srate; 486 487 if (pti_parse_freq (val, &srate)) { 488 return (1); 489 } 490 491 pti_wav_set_srate (srate); 492 } 493 else if ((strcmp (name, "wav-minimum-volume") == 0) || (strcmp (name, "wav-vol") == 0)) { 494 unsigned vol; 495 496 if (pti_parse_uint (val, &vol)) { 497 return (1); 498 } 499 500 pti_wav_set_min_volume (vol); 501 } 502 else { 503 return (1); 504 } 505 506 return (0); 507} 508 509int main (int argc, char **argv) 510{ 511 int r; 512 char **optarg; 513 pti_img_t *img; 514 const char *out; 515 516 arg0 = argv[0]; 517 518 img = NULL; 519 out = NULL; 520 521 while (1) { 522 r = pce_getopt (argc, argv, &optarg, opts); 523 524 if (r == GETOPT_DONE) { 525 break; 526 } 527 528 if (r < 0) { 529 return (1); 530 } 531 532 switch (r) { 533 case '?': 534 print_help(); 535 return (0); 536 537 case 'V': 538 print_version(); 539 return (0); 540 541 case 'c': 542 if (pti_set_parameter ("default-clock", optarg[0])) { 543 return (1); 544 } 545 break; 546 547 case 'f': 548 if (img != NULL) { 549 pti_info (img); 550 } 551 else { 552 par_print_info = 1; 553 } 554 break; 555 556 case 'i': 557 if (img != NULL) { 558 pti_img_del (img); 559 } 560 561 if ((img = pti_load_image (optarg[0])) == NULL) { 562 return (1); 563 } 564 break; 565 566 case 'I': 567 if (pti_set_format (optarg[0], &par_fmt_inp)) { 568 return (1); 569 } 570 break; 571 572 case 'm': 573 if (pti_cat (&img, optarg[0])) { 574 return (1); 575 } 576 break; 577 578 case 'o': 579 if (pti_save_image (optarg[0], &img)) { 580 return (1); 581 } 582 break; 583 584 case 'O': 585 if (pti_set_format (optarg[0], &par_fmt_out)) { 586 return (1); 587 } 588 break; 589 590 case 'p': 591 if (pti_operation (&img, optarg[0], argc, argv)) { 592 return (1); 593 } 594 break; 595 596 case 's': 597 if (pti_set_parameter (optarg[0], optarg[1])) { 598 fprintf (stderr, "%s: bad parameter (%s=%s)\n", 599 arg0, optarg[0], optarg[1] 600 ); 601 return (1); 602 } 603 break; 604 605 case 'v': 606 par_verbose = 1; 607 break; 608 609 case 0: 610 if (img == NULL) { 611 if ((img = pti_load_image (optarg[0])) == NULL) { 612 return (1); 613 } 614 } 615 else { 616 if (pti_save_image (optarg[0], &img)) { 617 return (1); 618 } 619 } 620 break; 621 622 default: 623 return (1); 624 } 625 } 626 627 if (out != NULL) { 628 if (img == NULL) { 629 img = pti_img_new(); 630 } 631 632 if (img == NULL) { 633 return (1); 634 } 635 636 if (par_verbose) { 637 fprintf (stderr, "%s: save image to %s\n", arg0, out); 638 } 639 640 r = pti_img_save (out, img, par_fmt_out); 641 642 if (r) { 643 fprintf (stderr, "%s: saving failed (%s)\n", 644 argv[0], out 645 ); 646 return (1); 647 } 648 } 649 650 return (0); 651}