/** .PSG/.SND Player *****************************************/
/**                                                         **/
/**                       psgplay.c                         **/
/**                                                         **/
/** This program will play .SND and .PSG sound files gene-  **/
/** rated by some emulators.                                **/
/**                                                         **/
/** Copyright (C) Marat Fayzullin 1996                      **/
/**     You are not allowed to distribute this software     **/
/**     commercially. Please, notify me, if you make any    **/
/**     changes to this file.                               **/
/*************************************************************/

#ifdef MSDOS
#include "SB.h"
#endif

#ifdef UNIX
#include "DSP.h"
#define delay(N)     usleep(N*1000)
#define InitSound(M) InitSound(M,0)
#endif

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

static int MasterVolume = 200; /* Master Volume (0..255)     */
static int LoopPlay     = 0;   /* 1: Loop playback           */
static int MasterTick   = 0;   /* Forced tick frequency (Hz) */

static void OnBreak(int Arg) { TrashSound();exit(0); }

static int PlaySND(char *Name,FILE *F)
{
  int Tick,Chn,I,J,K;
  unsigned char Buf[16];

  J=fgetc(F);        /* Version of file format  */
  Chn=fgetc(F);      /* Total number of ch-nels */
  if(Chn>6) Chn=6;   /* Up to 6 channels        */
  Tick=fgetc(F);     /* Tick frequency (Hz)     */
  fread(Buf,1,9,F);  /* Read rest of the header */

  printf("PSGPLAY: Now playing '%s' (SND v.%d)\n",Name,J);

  /* Set master volume and turn channels on */
  SetChannels(MasterVolume,(1<<Chn)-1);

  /* If master tick frequency set, use it */
  if(MasterTick) Tick=MasterTick;

  /* Reset all channels and their types */
  for(J=0;J<6;J++) { Sound(J,0,0);SetSound(J,SND_MELODIC); }

  /* Play the file */
  while((J=fgetc(F))>=0)
    switch(J)
    {
      case 0xFF: delay(1000/Tick);break;
      case 0xFD: delay(1000*fgetc(F)/Tick);break;
      case 0xFE:
        J=fgetc(F);I=fgetc(F);
        if(J<Chn) SetSound(J,I);
        break;
      default:
        I=fgetc(F);I+=fgetc(F)*256;K=fgetc(F);
        if(J<Chn) Sound(J,I,K);
        break;
    }

  return(1);
}

static int PlayAY8910(char *Name,FILE *F)
{
  int Tick,I,J,K;
  unsigned char Buf[16];

  J=fgetc(F);        /* Version of file format  */
  Tick=fgetc(F);     /* Tick frequency (Hz)     */
  fread(Buf,1,3,F);  /* Read rest of the header */

  printf("PSGPLAY: Can't play '%s' (PSG AY8910 v.%d) yet\n",Name,J);
  return(0);
}

static int PlaySN76489(char *Name,FILE *F)
{
  int Tick,I,J,K;
  unsigned char Buf[16];

  J=fgetc(F);        /* Version of file format  */
  Tick=fgetc(F);     /* Tick frequency (Hz)     */
  fread(Buf,1,2,F);  /* Read rest of the header */

  printf("PSGPLAY: Can't play '%s' (PSG SN76489 v.%d) yet\n",Name,J);
  return(0);
}

int main(int argc,char *argv[])
{
  FILE *F;
  int J,N;
  char S[128];

  if(argc<2)
  {
    fprintf(stderr,"PSGPLAY Music Player v.1.0 by Marat Fayzullin\n");
    fprintf(stderr,"  This program recognizes .SND files saved by iNES,\n");
    fprintf(stderr,"  VirtualGameBoy, MasterGear, and ColEm\n");
    fprintf(stderr,"Usage: %s [-l] [-vVolume] [-fFreq] file file ...\n",argv[0]);
    fprintf(stderr,"  -l - Loop play\n");
    fprintf(stderr,"  -v - Set volume (0..255)\n");
    fprintf(stderr,"  -f - Set tempo (Hz)\n");
    return(1);
  }

  if(!InitSound(4))
  { fprintf(stderr,"PSGPLAY: Can't initialize sound\n");return(1); }

  signal(SIGTERM,OnBreak);
  signal(SIGINT,OnBreak);

  printf("PSGPLAY: Initialized sound...\n");

  for(N=1;N<argc;)
  {
    if(argv[N][0]=='-')
      switch(argv[N][1])
      {
        case 'l': LoopPlay=1;break;
        case 'q': sscanf(argv[N],"-q%d",&J);
                  TrashSound();
                  InitSound(J&7);
                  break;
        case 'v': sscanf(argv[N],"-v%d",&MasterVolume);
                  MasterVolume&=0xFF;break;
        case 'f': if(!strcmp(argv[N],"-f")) MasterTick=0;
                  else sscanf(argv[N],"-f%d",&MasterTick);
                  MasterTick&=0xFF;break;
      }
    else   
      if(F=fopen(argv[N],"rb"))
      {
        /* Extract file type string */
        for(J=0;J<127;J++)
        {
          S[J]=fgetc(F);
          if(S[J]=='\032') break;
        }
        S[J]='\0';

        /* Determine file type and play */
        if(!strcmp(S,"SND"))         PlaySND(argv[N],F);
        if(!strcmp(S,"PSG AY8910"))  PlayAY8910(argv[N],F);
        if(!strcmp(S,"PSG SN76489")) PlaySN76489(argv[N],F);

        fclose(F);
      }
      else
      { fprintf(stderr,"PSGPLAY: Can't open '%s'\n",argv[N]);return(1); }

    /* Go to the next argument */
    N++;
    if(LoopPlay&&(N==argc)) N=1; 
  }

  TrashSound();
  return(0);
}
