home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / MM1 / SOUNDUTILS / mm1_tracker.lzh / TRACKER4.6 / main.c < prev    next >
Text File  |  1994-11-24  |  14KB  |  525 lines

  1. /* main.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* plays sound/noisetracker files on Sparc, silicon graphics.
  6.  * Authors  : Liam Corner - zenith@dcs.warwick.ac.uk
  7.  *            Marc Espie - espie@ens.fr
  8.  *            Steve Haehnichen - shaehnic@ucsd.edu
  9.  *            Andrew Leahy - alf@st.nepean.uws.edu.au
  10.  *
  11.  * Usage    : tracker <filename> 
  12.  *  this version plays compressed files as well.
  13.  */
  14.  
  15. /* $Id: main.c,v 4.6 1994/11/15 16:11:01 espie Exp espie $
  16.  * $Log: main.c,v $
  17.  * Revision 4.6  1994/11/15  16:11:01  espie
  18.  * *** empty log message ***
  19.  *
  20.  * Revision 4.5  1994/08/23  18:19:46  espie
  21.  * Added speed mode option.
  22.  * Added looping option.
  23.  * Nice OPT_CUT/OPT_ADD.
  24.  * Slight input/output changes.
  25.  * No more call to create_notes_table().
  26.  * Some notice to status.
  27.  * Use new pref scheme.
  28.  * Use info facility instead of printf for usage message.
  29.  * Options changes.
  30.  * Changed extended file semantics.
  31.  * Amiga support.
  32.  * Fixed upo previous song bug.
  33.  * Added bg/fg test.
  34.  * Added loads of new options.
  35.  * Added finetune.
  36.  *
  37.  * Revision 2.20  1992/11/17  17:06:25  espie
  38.  * Added PREVIOUS_SONG handling ???
  39.  * Use streamio for new interface (obsolescent signal handlers), and
  40.  * related changes.
  41.  * Cleaned up path reader, and better signal handling.
  42.  * Support for open_file.
  43.  * Added imask.
  44.  * Use transparent decompression/path lookup through open_file/close_file.
  45.  * Added setup_audio().
  46.  * Added some frequency/oversample/stereo change on the fly.
  47.  * Necessitates rightful closing/reopening of audio.
  48.  * Added compression methods. Changed getopt.
  49.  * Separated mix/stereo stuff.
  50.  * Added transpose feature.
  51.  * Added possibility to get back to MONO for the sgi.
  52.  * Added stereo capabilities to the indigo version.
  53.  * Added recovery and reread for automatic recognition
  54.  * of old/new tracker files.
  55.  * Added two level of fault tolerancy.
  56.  * Added more rational options.
  57.  * Moved almost everything to audio and automaton.
  58.  * Structured part of the code, especially replay ``automaton''
  59.  * and setting up of effects.
  60.  *
  61.  * Revision 1.26  1991/11/17  17:09:53  espie
  62.  * Added missing prototypes.
  63.  * Some more info while loading files.
  64.  * Added FAULT env variable, FAULT resistant playing,
  65.  * for playing modules which are not quite correct.
  66.  * Serious bug: dochangespeed was not reset all the time.
  67.  * Check all these parameters, they MUST be reset for
  68.  * each new song.
  69.  * Fixed a stupid bug: when env variable LOOPING was
  70.  * undefined, we got a segv on strcmp.
  71.  * Now we just test for its existence, since this is
  72.  * about all we want...
  73.  * Bug correction: when doing arpeggio, there might not
  74.  * be a new note, so we have to save the old note value
  75.  * and do the arppeggio on that note.
  76.  * Completely added control with OVERSAMPLE and FREQUENCY.
  77.  * Added control flow.
  78.  * Added pipe decompression, so that now you can do
  79.  * str32 file.Z directly.
  80.  * stdin may go away.
  81.  * Added arpeggio.
  82.  * Added vibslide and portaslide.
  83.  * Added speed command.
  84.  * Added signal control.
  85.  * Error checking: there shouldn't be that many
  86.  * segv signals any more.
  87.  * Moved every command to commands.c.
  88.  * Added some debug code for showing the full
  89.  * sequence for a file.
  90.  * Corrected the bug in volume slide: there is
  91.  * no default value, i.e., if it is 0, it is 0,
  92.  * as stupid as it may seem.
  93.  * Added vibrato.
  94.  * Added fastskip/corrected skip.
  95.  * Modified control flow of the player till
  96.  * it looks like something reasonable (i.e.,
  97.  * the structure is more natural and reflects
  98.  * the way stuff is played actually...)
  99.  * Do not restart the sound when we change instruments
  100.  * on the fly. A bit strange, but it works that way.
  101.  * Modified main to use new data structures.
  102.  * The sound player is MUCH cleaner, it uses now
  103.  * a 3-state automaton for each voice.
  104.  * Corrected ruckus with data type of sample.
  105.  */
  106.      
  107.  
  108. #include "defs.h"
  109.  
  110. #include <stdio.h>
  111. #include <signal.h>
  112. #include <stdlib.h>
  113. #include <string.h>
  114. #ifdef MALLOC_NOT_IN_STDLIB
  115. #include <malloc.h>
  116. #endif
  117. #include <ctype.h>
  118. #ifdef VOLUME_CONTROL
  119. #ifdef __hpux
  120. #define true /* kludge to avoid typedef of boolean (name clash with macro) */
  121. #include <audio/Alib.h>
  122. #undef true
  123. AGainDB    volume = -20;
  124. char use_speaker = 0;
  125. #endif
  126. #endif
  127.  
  128.      
  129. #include "song.h"
  130. #include "extern.h"
  131. #include "options.h"
  132.  
  133. #include "getopt.h"
  134. #include "tags.h"
  135. #include "prefs.h"
  136.      
  137. ID("$Id: main.c,v 4.6 1994/11/15 16:11:01 espie Exp espie $")
  138.  
  139.  
  140. LOCAL void print_usage()
  141.    {
  142.    GENERIC handle;
  143.    
  144.    handle = begin_info("Usage");
  145.    info(handle, "Usage: tracker [options] filename [...]");
  146.    info(handle, "-help               Display usage information");
  147.    info(handle, "-quiet              Print no output other than errors");
  148.    info(handle, "-picky              Do not tolerate any faults (default is to ignore most)");
  149.    info(handle, "-tolerant           Ignore all faults");
  150.    info(handle, "-mono               Select single audio channel output");
  151.    info(handle, "-stereo             Select dual audio channel output");
  152.    info(handle, "-verbose            Show text representation of song");
  153.    info(handle, "-repeats <count>    Number of repeats (0 is forever) (default 1)");
  154.     info(handle, "-loop               Loops the song list (plays again and again)");
  155.    info(handle, "-speed <speed>      Song speed.  Some songs want 60 (default 50)");
  156.    info(handle, "-mix <percent>      Percent of channel mixing. (0 = spatial, 100 = mono)");
  157.    info(handle, "-new -old -both     Select default reading type (default is -both)");
  158.    info(handle, "-frequency <freq>   Set playback frequency in Hz");
  159.    info(handle, "-oversample <times> Set oversampling factor");
  160.    info(handle, "-transpose <n>      Transpose all notes up");
  161.    info(handle, "-scroll             Show what's going on");
  162.    info(handle, "-sync               Try to synch audio output with display");
  163. #ifdef VOLUME_CONTROL
  164.     info(handle, "-speaker                 Output audio to internal speaker");
  165.     info(handle, "-volume <n>         Set volume in dB");
  166. #endif
  167.    info(handle, "");
  168.    info(handle, "RunTime:");
  169.    info(handle, "e,x     exit program");
  170.    info(handle, "n       next song");
  171.    info(handle, "p       restart/previous song");
  172.    info(handle, ">       fast forward");
  173.    info(handle, "<       rewind");
  174.    info(handle, "S       NTSC tempo\t s\tPAL tempo");
  175.    end_info(handle);
  176.    }
  177.  
  178. /* Command-line options. */
  179. LOCAL struct long_option long_options[] =
  180. {
  181.    {"help",                0, 'H', OPT_HELP},
  182.    {"quiet",               0, 'Q', OPT_QUIET}, 
  183.    {"picky",               0, 'P', OPT_PICKY},
  184.    {"tolerant",            0, 'L', OPT_TOLERANT},
  185.    {"new",                 0, 'N', OPT_NEWONLY},
  186.    {"old",                 0, 'O', OPT_OLDONLY},
  187.    {"both",                0, 'B', OPT_BOTH},
  188.    {"mono",                0, 'M', OPT_MONO},
  189.    {"stereo",              0, 'S', OPT_STEREO},
  190.    {"verbose",             0, 'V', OPT_VERBOSE},
  191.    {"frequency",           1, 'f', OPT_FREQUENCY},
  192.    {"oversample",          1, 'o', OPT_OVERSAMPLE},
  193.    {"transpose",           1, 't', OPT_TRANSPOSE},
  194.    {"repeats",             1, 'r', OPT_REPEATS},
  195.    {"speed",               1, 's', OPT_SPEED},
  196.    {"mix",                 1, 'm', OPT_MIX},
  197.    {"start",               1, 'X', OPT_START},
  198.    {"cut",                 1, '-', OPT_CUT},
  199.    {"add",                 1, '+', OPT_ADD},
  200.    {"scroll",              0, 'v', OPT_SHOW},
  201.    {"sync",                0, '=', OPT_SYNC},
  202.     {"loop",                        0, 'l', OPT_LOOP},
  203.     {"speedmode",               1, '?', OPT_SPEEDMODE},
  204. #ifdef VOLUME_CONTROL
  205.     {"speaker",                    0, '#', OPT_SPEAKER},
  206.     {"volume",                    1, 'u', OPT_VOLUME},
  207. #endif
  208.    {0,                     0,  0 , 0}
  209. };
  210.  
  211.  
  212. /* global variable to catch various types of errors
  213.  * and achieve the desired flow of control
  214.  */
  215. int error;
  216.  
  217. LOCAL int optvalue(def)
  218. int def;
  219.    {
  220.    int d;
  221.  
  222.    if (sscanf(optarg, "%d", &d) == 1)
  223.       return d;
  224.    else
  225.       {
  226.       optind--;
  227.       return def;
  228.       }
  229.    }
  230.  
  231. LOCAL struct song *do_read_song(name, type)
  232. char *name;
  233. int type;
  234.    {
  235.    struct song *song;
  236.    struct exfile *file;
  237.  
  238.    file = open_file(name, "r", getenv("MODPATH"));
  239.    if (!file)
  240.       return NULL;
  241.    song = read_song(file, type); 
  242.    close_file(file);
  243.    return song;
  244.    }
  245.  
  246. LOCAL int ask_freq;
  247. LOCAL int oversample;
  248. LOCAL int stereo;
  249. LOCAL int start;
  250. LOCAL int transpose;
  251. LOCAL int loop = FALSE;
  252.  
  253.  
  254. LOCAL void parse_options(argc, argv)
  255. int argc;
  256. char *argv[];
  257.    {
  258.    int c;
  259.    
  260.    while ((c = getlongopt(argc, argv, long_options))
  261.       != BAD_OPTION)
  262.       switch(c)
  263.          {
  264.         case OPT_LOOP:
  265.             loop = TRUE;
  266.             break;
  267.         case OPT_CUT:
  268.         case OPT_ADD:
  269.             {
  270.             int i;
  271.             unsigned long imask = 0;
  272.       
  273.             for (i = 0; optarg[i]; i++)
  274.                 {
  275.                 char c = tolower(optarg[i]);
  276.  
  277.                 if (c >= '1' && c <= '9')
  278.                     imask |= 1<< (c-'1');
  279.                 else if (c >= 'a' && c <= 'z')
  280.                     imask |= 1 << (c-'a'+9);
  281.                 }
  282.             if (c == OPT_ADD)
  283.                 set_pref_scalar(PREF_IMASK, ~imask);
  284.             else
  285.                 set_pref_scalar(PREF_IMASK, imask);
  286.             }        
  287.          break;
  288.         case OPT_SPEEDMODE:
  289.             if (stricmp(optarg, "old") == 0)
  290.                 set_pref_scalar(PREF_SPEEDMODE, OLD_SPEEDMODE);
  291.             else if (stricmp(optarg, "normal") == 0)
  292.                 set_pref_scalar(PREF_SPEEDMODE, NORMAL_SPEEDMODE);
  293.             else if (stricmp(optarg, "finefirst") == 0)
  294.                 set_pref_scalar(PREF_SPEEDMODE, FINESPEED_ONLY);
  295.             else if (stricmp(optarg, "normalfirst") == 0)
  296.                 set_pref_scalar(PREF_SPEEDMODE, SPEED_ONLY);
  297.             break;
  298.             
  299.       case OPT_OLDONLY:   /* old tracker type */
  300.          set_pref_scalar(PREF_TYPE, OLD);
  301.          break;
  302.       case OPT_NEWONLY:   /* new tracker type */
  303.          set_pref_scalar(PREF_TYPE, NEW);
  304.          break;
  305.       case OPT_SHOW:
  306.          set_pref_scalar(PREF_SHOW, TRUE);
  307.          break;
  308.       case OPT_SYNC:
  309.          set_pref_scalar(PREF_SYNC, TRUE);
  310.          break;
  311.       case OPT_BOTH:   /* both tracker types */
  312.          set_pref_scalar(PREF_TYPE, BOTH);
  313.          break;
  314.       case OPT_REPEATS:   /* number of repeats */
  315.          set_pref_scalar(PREF_REPEATS, optvalue(0));
  316.          break;
  317.       case OPT_SPEED:  
  318.          set_pref_scalar(PREF_SPEED, optvalue(50));
  319.          break;
  320.       case OPT_MONO:  
  321.          stereo = FALSE;
  322.          break;
  323.       case OPT_STEREO:  
  324.          stereo = TRUE;
  325.          break;
  326.       case OPT_OVERSAMPLE:  
  327.          oversample = optvalue(1);
  328.          break;
  329.       case OPT_FREQUENCY:
  330.          ask_freq = optvalue(0);
  331.          break;
  332.       case OPT_TRANSPOSE:
  333.          transpose = optvalue(0);
  334.          break;
  335.       case OPT_PICKY:
  336.          set_pref_scalar(PREF_TOLERATE, 0);
  337.          break;
  338.       case OPT_TOLERANT:
  339.          set_pref_scalar(PREF_TOLERATE, 2);
  340.          break;
  341.       case OPT_MIX:     /* % of channel mix. 
  342.                          * 0->full stereo, 100->mono */
  343.          set_mix(optvalue(30));
  344.          break;
  345.       case OPT_START:
  346.          start = optvalue(0);
  347.          break;
  348.       case OPT_HELP:
  349.          print_usage();
  350.          end_all(0);
  351.          /* NOTREACHED */
  352.       case OPT_VERBOSE:
  353.          set_pref_scalar(PREF_DUMP, TRUE);
  354.             break;
  355. #ifdef VOLUME_CONTROL
  356.         case OPT_VOLUME:
  357.             volume = optvalue(-20);
  358.             break;
  359.         case OPT_SPEAKER:
  360.             use_speaker = 1;
  361.             break;
  362. #endif
  363.          }
  364.    }
  365.  
  366. LOCAL struct song *load_song(name)
  367. char *name;
  368.    {
  369.    struct song *song;
  370.    char *buffer;
  371.    int i, j;
  372.    
  373.    i = strlen(name);
  374.    
  375.    for (j = i; j > 0; j--)
  376.       if (name[j] == '/' || name[j] == '\\')
  377.          {
  378.          j++;
  379.          break;
  380.          }
  381.    
  382.    buffer = malloc( i - j + 5);
  383.    if (buffer)
  384.       {
  385.       sprintf(buffer, "%s...", name + j);
  386.       status(buffer);
  387.       }
  388.  
  389.    
  390.    switch(get_pref_scalar(PREF_TYPE))
  391.       {
  392.    case BOTH:
  393.       song = do_read_song(name, NEW);
  394.       if (song)
  395.             break;
  396.       /* FALLTHRU */
  397.    case OLD:
  398.       song = do_read_song(name, OLD);
  399.       break;
  400.       /* this is explicitly flagged as a new module,
  401.        * so we don't need to look for a signature.
  402.        */
  403.    case NEW:
  404.       song = do_read_song(name, NEW_NO_CHECK);
  405.       break;
  406.       }
  407.     if (buffer)
  408.         {
  409.         status(0);
  410.         free(buffer);
  411.         }
  412.     return song;
  413.    }
  414.  
  415. int main(argc, argv)
  416. int argc;
  417. char **argv;
  418.    {
  419.    struct song *song;
  420.    int *is_song;
  421.    int i;
  422.  
  423.    struct tag *result;
  424.  
  425.     EXPAND_WILDCARDS(argc,argv);
  426.  
  427.    is_song = (int *)malloc(sizeof(int) * argc);
  428.    if (!is_song)
  429.       end_all("No memory left");
  430.  
  431.    for (i = 0; i < argc; i++)
  432.       is_song[i] = FALSE;        /* For termination */
  433.  
  434.    start = 0;
  435.    set_pref_scalar(PREF_IMASK, 0);
  436.    set_pref_scalar(PREF_BCDVOL, 0);
  437.    set_pref_scalar(PREF_DUMP, FALSE);
  438.    set_pref_scalar(PREF_SHOW, FALSE);
  439.    set_pref_scalar(PREF_SYNC, FALSE);
  440.    set_pref_scalar(PREF_TYPE, BOTH);
  441.    set_pref_scalar(PREF_REPEATS, 1);
  442.    set_pref_scalar(PREF_SPEED, 50);
  443.    set_pref_scalar(PREF_TOLERATE, 1);
  444.     set_pref_scalar(PREF_SPEEDMODE, NORMAL_SPEEDMODE);
  445.  
  446.    if (argc == 1)
  447.       {
  448.       print_usage();
  449.       end_all(0);
  450.       }
  451.  
  452.    ask_freq = read_env("FREQUENCY", 0);
  453.    oversample = read_env("OVERSAMPLE", 1);
  454.    transpose = read_env("TRANSPOSE", 0);
  455.    stereo = !getenv("MONO");
  456.    set_mix(30);
  457.  
  458.  
  459.  
  460.       /* check the command name for default reading type */
  461.  
  462.  
  463. looping:
  464.    for (optind = 1; optind < argc; optind++)
  465.       {
  466.       parse_options(argc, argv);
  467.       if (optind >= argc)
  468.          end_all(0);
  469.          
  470.    
  471.       song = load_song(argv[optind]);   
  472.       if (song)
  473.          is_song[optind] = TRUE;
  474.       else
  475.          {
  476.          puts("not a song");
  477.          is_song[optind] = FALSE;
  478.          continue;
  479.          }
  480. play_on:
  481.       if (get_pref_scalar(PREF_DUMP))
  482.          dump_song(song); 
  483.       transpose_song(song, transpose);
  484.       setup_audio(ask_freq, stereo, oversample);
  485.       result = play_song(song, start);
  486.       release_song(song);
  487.       status(0);
  488.       while (result = get_tag(result))
  489.          {
  490.          switch (result->type)
  491.             {
  492.          case PLAY_PREVIOUS_SONG:
  493.             optind--;
  494.             while ((optind > 0) && !is_song[optind])
  495.                optind--;
  496.             if (optind == 0)
  497.                     {
  498.                     if (loop)
  499.                         optind = argc - 1;
  500.                     else
  501.                         end_all(0);
  502.                     }
  503.                 song = load_song(argv[optind]);
  504.                 goto play_on;
  505.             /* NOTREACHED */
  506.          case PLAY_LOAD_SONG:
  507.             song = load_song(result->data.pointer);
  508.             free(result->data.pointer);
  509.             if (song)
  510.                goto play_on;
  511.          default:
  512.             break;
  513.             }
  514.          result++;
  515.          }
  516.             
  517.       }
  518.     if (loop)
  519.         goto looping;
  520.    end_all(0);
  521.    /* NOTREACHED */
  522.    }
  523.  
  524.  
  525.