/***************************************************/
/* S3m/Mod player by Daniel Marks                  */
/*    GUS support by David Jeske                   */
/* (C) 1994 By Daniel Marks                        */
/* While we retain the copyright to this code,     */
/* this source code is FREE. You may NOT steal     */
/* the copyright of this code from us.             */
/* You may use it in any way you wish, in          */
/* any product you wish. We respectfully ask that  */
/* you email one of us, if possible, if you        */
/* produce something significant with this code,   */
/* or if you have any bug fixes to contribute.     */
/* We also request that you give credit where      */
/* credit is due if you include part of this code  */
/* in a program of your own.                       */
/*                                                 */
/* email: s3mod@uiuc.edu			   */
/*        jeske@uiuc.edu			   */
/*                                                 */
/* See the associated README file for Thanks       */
/***************************************************/

/* MAIN.C */

#include <stdio.h>
#include <string.h>

#include <fcntl.h>

#include "mod.h"
#include "s3m.h"
#include "play.h"
#include "main.h"
#include "cmdline.h"


/*
 * Portability conditions                
 */

#ifdef LINUX
#include <linux/soundcard.h>
#include <bytesex.h>
#endif /* LINUX */
#ifdef GUS
#include "gus.h"
#endif /* GUS */

#ifdef SUN
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <multimedia/audio_hdr.h>
#include <multimedia/audio_errno.h>
#include <multimedia/audio_device.h>

Audio_hdr hdr_save, hdr;
#endif /* ?SUN */

#ifdef DEC
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#endif /* ?DEC */

/*
 * Beginning of real code 
 */

struct option_struct options;
int gus_dev=-1;
int use_gus=1;

void help(void)
{
  printf("\nS3MOD - S3M/MOD tracker (%s) for Linux/Sun/DEC\n",VERSION);
  printf("         Linux Support by Daniel Marks \n");
  printf("           GUS Support by David Jeske (jeske@uiuc.edu)\n");
  printf("    SUN/DEC AF Support by Ricky Beam (cramer@catt.ncsu.edu)\n\n");
  printf("(C) Copyright 1994 by Daniel L. Marks and David Jeske\n\n");
  printf("For information email (s3mod@uiuc.edu).\n");
  printf("s3mod [-sbfqnl] [sampling frequency] filename\n");
  printf("     -s stereo\n");
#ifdef LINUX
  printf("     -b 16 bit samples\n");
#endif /* ?LINUX */
  printf("     -f set frequency\n");
  printf("     -q quiet (don't print anything)\n");
  printf("     -n don't loop\n");
  printf("     -l loud mode (shift voices louder)\n");
#ifdef LINUX
  printf("     -g do NOT use GUS native mode\n");
#endif /* ?LINUX */
  printf("     -p PAL speed adjustment (145bpm start)\n");
  printf("s3mod -sbf 44100 foobar.mod\n");
  printf("   plays in stereo, 16 bits, 44.1 kHz\n\n");
  printf("This player plays Screamtracker 3 files, and\n");
  printf("4,6,or 8 track MODs.\n\n");
#ifdef DEC
  printf("NOTE: DEC AF support is in it's ALPHA stages\n\n");
#endif /* ?LINUX */
  exit(1);
}



int get_dsp_device(void);

void get_audio_device(void)
{
  int found_gus=0;

#ifdef LINUX
#ifdef GUS 
  if (use_gus)
    {
      found_gus = get_gus_device();
    }

 if (!found_gus)
   {gus_dev=-1;
    get_dsp_device();
   }
#else /* GUS */
  get_dsp_device();
#endif /* GUS */
#endif /* LINUX */

#ifdef SUN
  get_sun_device();
  /* open_audio(mixspeed, stereo); */
  printf("returned\n");
#endif /* ?SUN */

#ifdef DEC
  get_dec_device();
  printf("returned\n");
#endif /* ?DEC */

}
  


#ifdef DEC

int get_dec_device(void)
{
    uint32 j;
    struct sigvec vec;

    audio = fileno(popen("aplay -f -e pcm16", "wb"));
    if (audio < 1)
    {
	printf("Could not open audio device!\n");
	exit(1);
    }
	mixspeed = 8000;
	bit16 = 1;

    /* I don't know; what's a good size? */
    audio_buffer_size = 32768;
    if (!(audio_start_buffer = (uint8 *) malloc(audio_buffer_size)))
    {
	printf("Could not get audio buffer memory!\n");
	exit(1);
    }
    audio_end_buffer = &audio_start_buffer[audio_buffer_size];
    audio_curptr = audio_start_buffer;
}

#endif /* ?DEC */


#ifdef SUN
int get_sun_device() {
  uint32 j;
  struct sigvec vec;
  
  audio = open("/dev/audio",O_WRONLY,0);
  if (audio < 1) {
    printf("Could not open audio device|\n");
    exit(1);
  }
  
  /* Save the device configuration 'cause it don't reset on its own */
  audio_get_play_config(audio, &hdr_save);
  audio_get_play_config(audio, &hdr);
  
  hdr.encoding = AUDIO_ENCODING_LINEAR;
  hdr.bytes_per_unit = 2;
  if (audio_set_play_config(audio, &hdr) != AUDIO_SUCCESS)
    fprintf(stderr, "unable to set sample encoding\n");
  
  if (stereo)
    {  /* setup stereo */
      hdr.channels = 2;
      if (audio_set_play_config(audio, &hdr) != AUDIO_SUCCESS)
	fprintf(stderr, "unable to setup stereo\n");
      audio_get_play_config(audio, &hdr);
      stereo = (hdr.channels==1)?0:1;
    }
  
  if (bit16)
    {  /* set 16 bit? */
      j = 16;
      hdr.bytes_per_unit = 2;
      if (audio_set_play_config(audio, &hdr) != AUDIO_SUCCESS)
	fprintf(stderr, "unable to setup 16 bit samples\n");
      audio_get_play_config(audio, &hdr);
      j = (hdr.bytes_per_unit==2)?16:8;
      if (j != 16) bit16 = 0;
    }
  
  /* Setup playback speed */
  hdr.sample_rate = mixspeed;
  if (audio_set_play_config(audio, &hdr) != AUDIO_SUCCESS)
    fprintf(stderr, "unable to setup sample speed\n");
  audio_get_play_config(audio, &hdr);
  mixspeed = hdr.sample_rate;
  
  /* I don't know; what's a good size? */
  audio_buffer_size = 32768;
  if (!(audio_start_buffer = (uint8 *) malloc(audio_buffer_size)))
    {
      printf("Could not get audio buffer memory!\n");
      exit(1);
    }
  audio_end_buffer = &audio_start_buffer[audio_buffer_size];
  audio_curptr = audio_start_buffer;
}
#endif /* ?SUN */


#ifdef LINUX 
int get_dsp_device(void)
{
  uint32 j;

  audio=open("/dev/dsp",O_WRONLY,0);
  if (audio < 1)
  {
    printf("Could not open audio device!\n");
    exit(1);
  }
  if (stereo)
  { 
    if (ioctl(audio,SNDCTL_DSP_STEREO,&stereo) == -1)
      stereo = 0;
  }
  if (bit16)
  {
    j = 16;
    if (ioctl(audio,SNDCTL_DSP_SAMPLESIZE,&j) == -1) bit16 = 0;
    if (j != 16) bit16 = 0;
  }
  j = mixspeed;
  if (ioctl(audio,SNDCTL_DSP_SPEED,&j) == -1) 
  { 
    printf("Error setting sample speed\n");
    exit(1);
  }
  mixspeed = j;
  if (ioctl(audio,SNDCTL_DSP_GETBLKSIZE, &audio_buffer_size) == -1)
  {
    printf("Unable to get audio blocksize\n");
    exit(1);
  }
  if ((audio_buffer_size < 4096) || (audio_buffer_size > 131072))
  {
    printf("Invalid audio buffer size: %d\n",audio_buffer_size);
    exit(1);
  }
  if (!(audio_start_buffer = (uint8 *) malloc(audio_buffer_size)))
  {
    printf("Could not get audio buffer memory!\n");
    exit(1);
  }
  audio_end_buffer = &audio_start_buffer[audio_buffer_size];
  audio_curptr = audio_start_buffer;  

}
#endif /* ?LINUX */





void main(int argc, char **argv)
{
  uint32 j;
  char *filename;
  long int frequency;
  int quiet = 0;
  int loud = 0;
  int use_pal = 0;

  mixspeed = DSP_SPEED;

  if (argc < 2) 
    { help();
      exit(1);
    }
 
  parm_setup(argc,argv,"","SsBbQqNnLlGgPp","Ff");

  if (read_parm(NON_FLAGGED, &filename, NULL) != 1)
  {
    help();
    printf("No executable filename found!\n");
    exit(1);
  }

  if (read_parm('S',NULL,NULL))
    stereo=1;
  else
    stereo=0;
  if (read_parm('B',NULL,NULL))
    bit16=1;
  else
    bit16=0;
  if (read_parm('Q',NULL,NULL))
    quiet=1;
  else
    quiet=0;
  if (read_parm('N',NULL,NULL))
    loop_mod = 0;
  else
    loop_mod = 1;
  if (read_parm('L',NULL,NULL))
    loud = 1;
  else
    loud = 0;
  if (read_parm('G',NULL,NULL))
    use_gus = 0;
  else
    use_gus = 1;
  if (read_parm('P',NULL,NULL))
    use_pal = 1;
  else
    use_pal = 0;

#ifdef SUN
bit16 = 1;
#endif /* ?SUN */

#ifdef DEC
bit16 = 1;
#endif /* ?DEC */

  if (read_parm('F',NULL,&frequency))
    {
      mixspeed = (frequency);
      if ((mixspeed < 8000) || (mixspeed > 44100))
	{ help();
	  printf("Invalid Frequency: %ld",frequency);
	  exit(1);
	}
    }
    
  if (use_pal)
    { options.def_tempo = DEF_TEMPO_PAL; 
      options.def_bpm   = DEF_BPM_PAL;
    }
  else
    { options.def_tempo = DEF_TEMPO_NTSC;
      options.def_bpm   = DEF_BPM_NTSC;
    }


  get_audio_device();

  if (load_s3m(filename,&mod,quiet))
    if (load_mod(filename,&mod,quiet))
    {
      printf("File is not a valid mod or s3m!\n");
      exit(1);
    }



  if (!quiet) 
  {

    if (gus_dev==-1)
      printf("Playing \"%s\"\nAt rate %d, %d bits, %s, blocksize %d\n",
	     filename,
	     mixspeed,
	     bit16 ? 16 : 8,
	     stereo ? "stereo" : "mono",
	     audio_buffer_size);
    
    else {
#ifdef GUS
      printf("GUS (ALPHA support) Playing \"%s\" \n",filename);
      printf("Using %d of %d bytes of GUS RAM\n",
	     (gus_total_mem - gus_mem_free(gus_dev)),
	     (gus_total_mem));
#else
      printf("GUS support not compiled in...\n");
      exit(1);
#endif /* GUS */
    }


  }


  if (gus_dev!=-1) {
#ifdef GUS    
    play_mod_gus(loud);
#else
    printf("GUS support not compiled in...\n");
    exit(1);
#endif
  } else {
    play_mod(loud);
  }
  

  free(audio_start_buffer);
  close(audio);
}
















