/* main.c */

/* plays sound/noisetracker files on Sparc, silicon graphics.
 * Authors  : Liam Corner - zenith@dcs.warwick.ac.uk
 *            Marc Espie - espie@dmi.ens.fr
 *            Steve Haehnichen - shaehnic@ucsd.edu
 *
 * Usage    : tracker <filename> 
 *  this version plays compressed files as well.
 */

/* $Author: espie $
 * $Id: main.c,v 2.17 1992/07/23 13:52:28 espie Exp espie $
 * $Revision: 2.17 $
 * $Log: main.c,v $
 * Revision 2.17  1992/07/23  13:52:28  espie
 * Cleaned up path reader, and better signal handling.
 *
 * Revision 2.16  1992/07/22  14:50:25  espie
 * Support for open_file.
 *
 * Revision 2.15  1992/07/17  13:43:00  espie
 * Added imask.
 *
 * Revision 2.14  1992/07/16  17:02:00  espie
 * Use transparent decompression/path lookup through open_file/close_file.
 *
 * Revision 2.13  1992/07/15  12:45:41  espie
 * Added setup_audio().
 *
 * Revision 2.12  1992/07/14  14:23:41  espie
 * Added some frequency/oversample/stereo change on the fly.
 * Necessitates rightful closing/reopening of audio.
 *
 * Revision 2.11  1992/07/14  13:20:53  espie
 * Added compression methods. Changed getopt.
 *
 * Revision 2.9  1991/12/04  08:28:53  espie
 * Separated mix/stereo stuff.
 *
 * Revision 2.8  1991/12/03  23:03:39  espie
 * Added transpose feature.
 *
 * Revision 2.7  1991/12/03  20:43:46  espie
 * Added possibility to get back to MONO for the sgi.
 *
 * Revision 2.6  1991/12/03  18:07:38  espie
 * Added stereo capabilities to the indigo version.
 *
 * Revision 2.5  1991/12/03  17:10:11  espie
 * Added recovery and reread for automatic recognition
 * of old/new tracker files.
 *
 * Revision 2.4  1991/11/20  20:46:35  espie
 * Minor correction.
 *
 * Revision 2.3  1991/11/18  01:23:30  espie
 * Added two level of fault tolerancy.
 *
 * Revision 2.2  1991/11/18  01:10:45  espie
 * Added more rational options.
 *
 * Revision 2.1  1991/11/17  23:07:58  espie
 * Moved almost everything to audio and automaton.
 *
 * Revision 2.0  1991/11/17  21:42:08  espie
 * Structured part of the code, especially replay ``automaton''
 * and setting up of effects.
 *
 * Revision 1.26  1991/11/17  17:09:53  espie
 * Added missing prototypes.
 *
 * Revision 1.25  1991/11/17  16:30:48  espie
 * Corrected cosmetic details, mostly.
 *
 * Revision 1.24  1991/11/16  16:57:01  espie
 * Forgot that read_song only returned NULL on read problem.
 * Should test that before printing Ok.
 *
 * Revision 1.23  1991/11/16  16:54:19  espie
 * Some more info while loading files.
 * Added FAULT env variable, FAULT resistant playing,
 * for playing modules which are not quite correct.
 *
 * Revision 1.22  1991/11/16  15:42:43  espie
 * tabs.
 *
 * Revision 1.21  1991/11/15  20:57:34  espie
 * Minor cleanup, mostly comments.
 *
 * Revision 1.20  1991/11/15  18:22:10  espie
 * Serious bug: dochangespeed was not reset all the time.
 * Check all these parameters, they MUST be reset for
 * each new song.
 *
 * Revision 1.19  1991/11/09  20:01:56  espie
 * Fixed a stupid bug: when env variable LOOPING was
 * undefined, we got a segv on strcmp.
 * Now we just test for its existence, since this is
 * about all we want...
 *
 * Revision 1.18  1991/11/09  17:47:33  espie
 * Bug correction: when doing arpeggio, there might not
 * be a new note, so we have to save the old note value
 * and do the arppeggio on that note.
 *
 * Revision 1.17  1991/11/08  14:47:52  espie
 * Completely added control with OVERSAMPLE and FREQUENCY.
 *
 * Revision 1.15  1991/11/08  13:35:57  espie
 * Added control flow.
 *
 * Revision 1.14  1991/11/08  12:37:37  espie
 * Added pipe decompression, so that now you can do
 * str32 file.Z directly.
 * stdin may go away.
 *
 * Looping is now controlled by an environment variable.
 *
 * Revision 1.13  1991/11/07  21:40:16  espie
 * Added arpeggio.
 *
 * Revision 1.12  1991/11/07  20:12:34  espie
 * Minor problem with version id.
 *
 * Revision 1.11  1991/11/07  20:09:06  espie
 * Added embedded version id.
 *
 * Revision 1.10  1991/11/07  20:05:53  espie
 * Added vibslide and portaslide.
 *
 * Revision 1.9  1991/11/07  15:27:02  espie
 * Added speed command.
 * Added signal control.
 * Error checking: there shouldn't be that many
 * segv signals any more.
 *
 * Revision 1.8  1991/11/06  09:46:06  espie
 * Moved every command to commands.c.
 *
 * Revision 1.7  1991/11/06  00:03:11  espie
 * Added effect #9, change offset in sample.
 * It seems to work quite correctly (example: sampled annie).
 *
 * Revision 1.6  1991/11/05  22:49:03  espie
 * Added some debug code for showing the full
 * sequence for a file.
 * Corrected the bug in volume slide: there is
 * no default value, i.e., if it is 0, it is 0,
 * as stupid as it may seem.
 * Added vibrato.
 * Added fastskip/corrected skip.
 *
 * Revision 1.5  1991/11/05  11:14:59  espie
 * Modified control flow of the player till
 * it looks like something reasonable (i.e.,
 * the structure is more natural and reflects
 * the way stuff is played actually...)
 *
 * Added some #define for a slightly higher level
 * of abstraction ( :-)    ).
 *
 * Revision 1.4  1991/11/04  20:27:05  espie
 * Do not restart the sound when we change instruments
 * on the fly. A bit strange, but it works that way.
 *
 * Revision 1.3  1991/11/04  13:23:59  espie
 * Modified main to use new data structures.
 * The sound player is MUCH cleaner, it uses now
 * a 3-state automaton for each voice.
 *
 * Revision 1.2  1991/11/04  08:01:20  espie
 * Corrected ruckus with data type of sample.
 *
 * Revision 1.1  1991/11/03  22:47:05  espie
 * Initial revision
 *
 *
 */
     

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
     
#include "defs.h"
#include "extern.h"
#include "song.h"
#include "pref.h"
     
#include "getopt.h"
     
LOCAL char *id = "$Id: main.c,v 2.17 1992/07/23 13:52:28 espie Exp espie $";

#define USAGE \
"[options] filename [filename [...]]\n\
(Options may be preceeded by - or + and can be uniquely abbreviated.)\n\
-help             Display usage information\n\
-quiet            Print no output other than errors\n\
-picky            Do not tolerate any faults (default is to ignore all)\n\
-mono             Select single audio channel output\n\
-stereo           Select dual audio channel output\n\
-verbose          Show text representation of song\n\
-repeats <count>  Number of repeats (0 is forever) (default 1)\n\
-speed <speed>    Song speed.  Some songs want 60 (default 50)\n\
-mix <percent>    Percent of channel mixing. (0 = spatial, 100 = mono)\n\
-new -old -both   Select default reading type (default is -both)\n\
-frequency <freq>        Set playback frequency in Hz\n\
-oversample <times>      Set oversampling factor\n\
-transpose <half-steps>  Transpose all notes up\n"

/* Command-line options. */
struct option long_options[] =
{
  {"help",              0, NULL, 'H'},
  {"quiet",             0, NULL, 'Q'}, 
  {"picky",             0, NULL, 'P'},
  {"new",               0, NULL, 'N'},
  {"old",               0, NULL, 'O'},
  {"both",              0, NULL, 'B'},
  {"mono",              0, NULL, 'M'},
  {"stereo",            0, NULL, 'S'},
/*  {"verbose",           0, NULL, 'V'},*/
  {"frequency",         1, NULL, 'f'},
  {"oversample",        1, NULL, 'o'},
  {"transpose",         1, NULL, 't'},
  {"repeats",           1, NULL, 'r'},
  {"speed",             1, NULL, 's'},
  {"mix",               1, NULL, 'm'},
  {"start",             1, NULL, 'X'},
  {"cut",               1, NULL, '-'},
  {"add",               1, NULL, '+'},
  {NULL, 0, NULL, 0}
};


/* global variable to catch various types of errors
 * and achieve the desired flow of control
 */
int error;

/* signal handlers */

void goodbye(sig)
int sig;
    {
    printf("\nSignal %d\n", sig);
    exit(10);
    }

void nextsong(sig)
int sig;
    {
    signal(sig, nextsong);
    printf("\nSignal %d\n", sig);
    error = NEXT_SONG;
    }

/* small hack for transposing songs on the fly */

int optvalue(def)
int def;
    {
    int d;
        if (sscanf(optarg, "%d", &d) == 1)
            return d;
        else
            {
            optind--;
            return def;
            }
    }

int main (argc, argv)
int argc;
char **argv;
    {

    int ask_freq, real_freq, new_freq;
    int oversample;
    int stereo;
    int start;
    int transpose;


    struct pref pref;
    struct song *song;

    int index;
    int c;
    int default_type;

    start = 0;
    pref.imask = 0;
    pref.bcdvol = 0;
    signal(2, nextsong);
    signal(3, goodbye);

    ask_freq = read_env("FREQUENCY", 0);
    oversample = read_env("OVERSAMPLE", 1);
    transpose = read_env("TRANSPOSE", 0);
    stereo = !getenv("MONO");

    setup_audio(ask_freq, stereo, oversample);

        /* check the command name for default reading type */

    default_type = BOTH;

    pref.type = default_type;
    pref.repeats = 1;
    pref.speed = 50;
    pref.tolerate = 1;

    for (optind = 1; optind < argc; optind++)
        {
        while ((c = getopt_long_only(argc, argv, "", long_options, NULL))
                != EOF)
            switch(c)
                {
            case '-':
                if (strcmp(optarg, "all") == 0)
                    pref.imask = ~0;
                else
                    pref.imask |= 1L << optvalue(0);
                break;
            case '+':
                if (strcmp(optarg, "all") == 0)
                    pref.imask = 0;
                else
                    pref.imask &= ~ (1L << optvalue(0));
                break;
            case 'O':   /* old tracker type */
                pref.type = OLD;
                break;
            case 'N':   /* new tracker type */
                pref.type = NEW;
                break;
            case 'B':   /* both tracker types */
                pref.type = BOTH;
                break;
            case 'r':   /* number of repeats */
                pref.repeats = optvalue(0);
                break;
            case 's':   /* speed */
                pref.speed = optvalue(50);
                break;
            case 'M':   /* MONO */
                setup_audio(ask_freq, stereo = 0, oversample);
                break;
            case 'S':   /* STEREO */
                setup_audio(ask_freq, stereo = 1, oversample);
                break;
            case 'o':   /* oversample */
                setup_audio(ask_freq, stereo, oversample = optvalue(1));
                break;
            case 'f':   /* frequency */
                setup_audio(ask_freq = optvalue(0), stereo, oversample);
                break;
            case 't':   /* transpose */
                transpose = optvalue(0);
                break;
            case 'P':
                pref.tolerate = 0;
                break;
            case 'L':
                pref.tolerate = 2;
                break;
            case 'm':   /* % of channel mix. 
                         * 0->full stereo, 100->mono */
                set_mix(optvalue(30));
                break;
            case 'X':
                start = optvalue(0);
                break;
            case 'H':   /* template */
                fprintf(stderr, "Usage: %s %s", argv[0], USAGE);
                exit(2);
                }
        if (optind < argc)
            {
            switch(pref.type)
                {
            case BOTH:
                song = do_read_song(argv[optind], NEW, transpose);
                if (!song && error != NEXT_SONG)
                    song = do_read_song(argv[optind], OLD, transpose);
                break;
            case OLD:
                song = do_read_song(argv[optind], pref.type);
                break;
                /* this is explicitly flagged as a new module,
                 * so we don't need to look for a signature.
                 */
            case NEW:
                song = do_read_song(argv[optind], NEW_NO_CHECK);
                break;
                }
            if (song == NULL)
                continue;

            dump_song(song); 
            play_song(song, &pref, start);
            release_song(song);
            }
        }

    close_audio();
    return 0;
    }

