/* * sap2ntsc.c - convert PAL SAP files to NTSC * * Copyright (C) 2012-2019 Piotr Fusik * * This file is part of ASAP (Another Slight Atari Player), * see http://asap.sourceforge.net * * ASAP 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 of the License, * or (at your option) any later version. * * ASAP 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 ASAP; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include /* public API doesn't allow us to set NTSC or FASTPLAY */ #include "asap.c" static void fatal_error(const char *format, ...) { va_list args; va_start(args, format); fprintf(stderr, "sap2ntsc: "); vfprintf(stderr, format, args); fputc('\n', stderr); va_end(args); exit(1); } static void process_file(const char *filename) { /* check filename */ const char *ext = strrchr(filename, '.'); if (ext == NULL || strcasecmp(ext, ".sap") != 0) fatal_error("%s: filename must be *.sap", filename); /* read file */ FILE *fp = fopen(filename, "rb"); if (fp == NULL) fatal_error("cannot open %s", filename); static unsigned char module[ASAPInfo_MAX_MODULE_LENGTH]; int module_len = fread(module, 1, sizeof(module), fp); fclose(fp); /* parse file */ ASAPInfo *info = ASAPInfo_New(); if (info == NULL) fatal_error("out of memory"); if (!ASAPInfo_Load(info, filename, module, module_len)) fatal_error("%s: unsupported file", filename); /* check if conversion possible */ if (ASAPInfo_IsNtsc(info)) fatal_error("%s: is already NTSC", filename); if (ASAPInfo_GetPlayerRateScanlines(info) != 312) fatal_error("%s: uses FASTPLAY", filename); /* do the conversion */ ASAPWriter *writer = ASAPWriter_New(); if (writer == NULL) fatal_error("out of memory"); info->ntsc = true; info->fastplay = 262; for (int i = 0; i < ASAPInfo_GetSongs(info); i++) { int duration = ASAPInfo_GetDuration(info, i); if (duration > 0) ASAPInfo_SetDuration(info, i, (int) (duration * (1773447 / 1789772.5 * 262 / 312))); } static unsigned char output[ASAPInfo_MAX_MODULE_LENGTH]; ASAPWriter_SetOutput(writer, output, 0, sizeof(output)); int output_len = ASAPWriter_Write(writer, filename, info, module, module_len, true); ASAPWriter_Delete(writer); if (output_len < 0) fatal_error("%s: conversion error", filename); /* write file */ fp = fopen(filename, "wb"); if (fp == NULL) fatal_error("cannot write %s", filename); if (fwrite(output, output_len, 1, fp) != 1) { fclose(fp); remove(filename); /* "unlink" is less portable */ fatal_error("%s: write error", filename); } fclose(fp); /* print summary */ printf("%s: ", filename); int warnings = 0; /* issue a warning for samples - they may break on NTSC */ /* TYPE S has FASTPLAY!=312, so it has been rejected earlier */ if (ASAPInfo_GetTypeLetter(info) == 'D') { printf("WARNING: TYPE D"); warnings++; } /* issue a warning if the 6502 code possibly reads the PAL/NTSC flag of GTIA (LDA/LDX/LDY $D014, e.g. Ghostbusters.sap). This is just a guess - false positives are possible and other code may be used for NTSC detection. */ for (int i = 0; i < module_len - 2; i++) { if (module[i] >= 0xac && module[i] <= 0xae && module[i + 1] == 0x14 && module[i + 2] == 0xd0) { if (warnings++ > 0) printf(", "); printf("WARNING: possible PAL/NTSC detection code"); break; } } ASAPInfo_Delete(info); if (warnings == 0) printf("ok"); printf("\n"); } int main(int argc, char **argv) { bool usage = true; for (int i = 1; i < argc; i++) { const char *arg = argv[i]; if (strcmp(arg, "--help") == 0) { usage = true; break; } if (strcmp(arg, "--version") == 0) { printf("sap2ntsc " ASAPInfo_VERSION "\n"); return 0; } process_file(arg); usage = false; } if (usage) { printf( "Usage: sap2ntsc FILE.sap...\n" "Replaces FILE.sap with an NTSC version\n" ); } return 0; }