/* main.c 
	vi:ts=3 sw=3:
 */

/* $Id: main.c,v 4.37 1995/10/13 18:08:40 espie Exp espie $
 * $Log: main.c,v $
 * Revision 4.37  1995/10/13 18:08:40  espie
 * Cleanup.
 *
 * Revision 4.36  1995/09/16 15:33:18  espie
 * *** empty log message ***
 *
 * Revision 4.35  1995/09/07 14:33:35  espie
 * *** empty log message ***
 *
 * Revision 4.34  1995/09/05 19:21:00  espie
 * *** empty log message ***
 *
 * Revision 4.33  1995/09/03 15:50:59  espie
 * *** empty log message ***
 *
 * Revision 4.32  1995/09/03 13:39:48  espie
 * *** empty log message ***
 *
 * Revision 4.31  1995/08/31 13:30:53  espie
 * NO_OUTPUT option.
 *
 * Revision 4.30  1995/07/04 08:37:12  espie
 * *** empty log message ***
 *
 * Revision 4.29  1995/07/02 17:52:32  espie
 * randomizer.
 *
 * Revision 4.28  1995/06/23 09:35:35  espie
 * *** empty log message ***
 *
 * Revision 4.27  1995/05/30  16:32:08  espie
 * Bug fix: forgot to check for bad song... Used to loop.
 *
 * Revision 4.26  1995/05/23  13:24:38  espie
 * New automaton.
 *
 * Revision 4.24  1995/04/22  17:50:20  espie
 * *** empty log message ***
 *
 * Revision 4.23  1995/03/17  00:32:22  espie
 * TERM from #ifdef to pref option.
 *
 * Revision 4.22  1995/03/11  23:06:33  espie
 * version changed.
 *
 * Revision 4.21  1995/03/06  22:35:38  espie
 * Color can be default.
 *
 * Revision 4.20  1995/03/01  15:24:51  espie
 * options -half/-double.
 *
 * Revision 4.19  1995/02/24  15:36:39  espie
 * Case forgotten: if file does not open, song is not set.
 *
 * Revision 4.18  1995/02/21  21:13:16  espie
 * Cleaned up source. Moved minor pieces of code around.
 *
 * Revision 4.17  1995/02/21  17:54:32  espie
 * Internal problem: buggy RCS. Fixed logs.
 *
 * Revision 4.13  1995/02/15  14:30:09  espie
 * optarg being NULL not checked -> segmentation.
 *
 * Revision 4.11  1995/02/14  04:02:28  espie
 * Added version number.
 *
 * Revision 4.9  1995/02/01  20:41:45  espie
 * Added color.
 *
 * Revision 4.8  1995/02/01  16:39:04  espie
 * Loading formats thru rewind.
 *
 * Revision 4.5  1994/08/23  18:19:46  espie
 * Added speed mode option.
 * Added looping option.
 * Nice OPT_CUT/OPT_ADD.
 * Slight input/output changes.
 * No more call to create_notes_table().
 * Some notice to status.
 * Use new pref scheme.
 * Use info facility instead of printf for usage message.
 * Options changes.
 * Changed extended file semantics.
 * Amiga support.
 * Fixed upo previous song bug.
 * Added bg/fg test.
 * Added loads of new options.
 * Added finetune.
 *
 * Revision 2.20  1992/11/17  17:06:25  espie
 * Added PREVIOUS_SONG handling ???
 * Use streamio for new interface (obsolescent signal handlers), and
 * related changes.
 * Cleaned up path reader, and better signal handling.
 * Support for open_file.
 * Added imask.
 * Use transparent decompression/path lookup through open_file/close_file.
 * Added setup_audio().
 * Added some frequency/oversample/stereo change on the fly.
 * Necessitates rightful closing/reopening of audio.
 * Added compression methods. Changed getopt.
 * Separated mix/stereo stuff.
 * Added transpose feature.
 * Added possibility to get back to MONO for the sgi.
 * Added stereo capabilities to the indigo version.
 * Added recovery and reread for automatic recognition
 * of old/new tracker files.
 * Added two level of fault tolerancy.
 * Added more rational options.
 * Moved almost everything to audio and automaton.
 * 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.
 * Some more info while loading files.
 * Added FAULT env variable, FAULT resistant playing,
 * for playing modules which are not quite correct.
 * Serious bug: dochangespeed was not reset all the time.
 * Check all these parameters, they MUST be reset for
 * each new song.
 * 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...
 * 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.
 * Completely added control with OVERSAMPLE and FREQUENCY.
 * Added control flow.
 * Added pipe decompression, so that now you can do
 * str32 file.Z directly.
 * stdin may go away.
 * Added arpeggio.
 * Added vibslide and portaslide.
 * Added speed command.
 * Added signal control.
 * Error checking: there shouldn't be that many
 * segv signals any more.
 * Moved every command to commands.c.
 * 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.
 * 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...)
 * Do not restart the sound when we change instruments
 * on the fly. A bit strange, but it works that way.
 * Modified main to use new data structures.
 * The sound player is MUCH cleaner, it uses now
 * a 3-state automaton for each voice.
 * Corrected ruckus with data type of sample.
 */
     

#include "defs.h"


#include <signal.h>
     
#include "song.h"
#include "extern.h"

#include "tags.h"
#include "prefs.h"
#include "play_list.h"
     
ID("$Id: main.c,v 4.37 1995/10/13 18:08:40 espie Exp espie $")

XT void print_usage P((void));
XT unsigned long half_mask;
XT int ask_freq;
XT int stereo;
XT int oversample;
XT int start;
XT int trandom;
XT int loop;
XT int handle_options P((int argc, char *argv[]));
XT void set_default_prefs P((void));

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

/* song = load_song(namesong):
 * syntactic sugar around read_song
 *	- display the file name after stripping the path
 * - find the actual file
 * - read the song trying several formats
 * - handle errors gracefully
 */
LOCAL struct song *load_song(e)
ENTRY e;
   {
   struct song *song;
   char *buffer;
	struct exfile *file;
	char *name;
   int i, j;
   
	name = e->filename;
		/* display the file name */
   i = strlen(name);
   
	/*
   for (j = i; j > 0; j--)
      if (name[j] == '/' || name[j] == '\\')
         {
         j++;
         break;
         }
			*/
	j = 0;
   
   buffer = malloc( i - j + 5);
   if (buffer)
      {
      sprintf(buffer, "%s...", name + j);
      status(buffer);
      }

		/* read the song */
	file = open_file(name, "r", getenv("MODPATH"));
	if (file)
		{
		switch(e->filetype)
			{
		case NEW:
			song = read_song(file, NEW);
			break;
		case OLD:
			song = read_song(file, OLD);
			break;
		case UNKNOWN:
			switch(get_pref_scalar(PREF_TYPE))
				{
			case BOTH:
				song = read_song(file, NEW);
				if (song)
					{
					e->filetype = NEW;
					break;
					}
				else
					rewind_file(file);
				/* FALLTHRU */
			case OLD:
				song = read_song(file, OLD);
				if (song)
					e->filetype = OLD;
				break;
				/* this is explicitly flagged as a new module,
				 * so we don't need to look for a signature.
				 */
			case NEW:
				song = read_song(file, NEW_NO_CHECK);
				if (song)
					e->filetype = NEW;
				break;
			default:
				song = NULL;
				}
			close_file(file);
			}
		}
	else
		song = NULL;

	if (!song)
		notice("Not a song");
		/* remove the displayed file name */
	if (buffer)
		{
		status(0);
		free(buffer);
		}

	return song;
   }


LOCAL void adjust_song(s, m)
struct song *s;
unsigned long m;
	{
	int i, j ;

	for (i = 1; i <= s->ninstr; i++)
		if ( (1 << i) & ~m)
			{
			for (j = 0; j <= MAX_VOLUME; j++)
				s->samples[i]->volume_lookup[j] *= 2;
			}
	s->side_width++;
	}

int main(argc, argv)
int argc;
char **argv;
   {
	int song_number, n;
   struct song *song;
	ENTRY *play_list;

   struct tag *result;

	EXPAND_WILDCARDS(argc,argv);

	set_default_prefs();
   if (argc == 1)
      {
      print_usage();
      end_all(0);
      }


		/* remove the program name from the options to parse !!! */
	handle_options(argc-1, argv+1);
	if (trandom)
		randomize();
	play_list = obtain_play_list();

	song_number = 0;
	while(1)
		{
		n = last_entry_index();
		if (n < 0)
			end_all("No playable song");
		if (song_number < 0)
			song_number = n;
		if (song_number > n)
			{
			if (loop)
				song_number = 0;
			else
				end_all(0);
			}
		song = load_song(play_list[song_number]);

		if (song)
			{
			if (get_pref_scalar(PREF_DUMP))
				dump_song(song); 
			if (half_mask)
				adjust_song(song, half_mask);
			setup_audio(ask_freq, stereo, oversample);
			result = play_song(song, start);
			release_song(song);
			status(0);
			while ( (result = get_tag(result)) )
				{
				switch (result->type)
					{
				case PLAY_PREVIOUS_SONG:
					song_number--;
					break;
					/* NOTREACHED */
				case PLAY_NEXT_SONG:
				case PLAY_ENDED:
					song_number++;
					break;
				case PLAY_ERROR:
					delete_entry(play_list+song_number);
				default:
					break;
					}
				result++;
				}
			}
		else
			delete_entry(play_list+song_number);
		}
   end_all(0);
   /* NOTREACHED */
   }


