/***************************************************************************
****************************************************************************
****************************************************************************
*
* FunktrackerGOLD - By Jason Nunn
*
* Using Curses (ANSI C) NON-preemptive Processing
*
* Snail: 32 Rothdale Road, Moil, Darwin, NT, 0810, Australia
*
* =========================================================
*
* The main file. Read README. Install for installation instructions. Modify
* the options.h & Makefile before attempting to make.
*
* =========================================================
*
* miwi: Changed to read maxy from ncurses LINES, and fill out the xterm
*       in y-direction. x-direction was not changed because the columns do
*       not scroll anyway. bug: resizing while running is not noticed.
*       Michael.Will@student.uni-tuebingen.de, May, 27th, 1996
*
****************************************************************************
****************************************************************************
***************************************************************************/
#include <ncurses.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#pragma pack(1)
#include "everything.h"   /*version info, byte sex*/
#include "funktracker.h"  /*funktracker structures*/
#include "funkmisc.h"
#pragma pack()
#include "funkgold.h"

int ch,maxy;
char song_directory[1024];
char sample_directory[1024];
char song_filename[256]; /*posix length ?*/
char sam_filename[256];
unsigned char song_fpos_real = 0;
unsigned char song_fpos_hl = 0;
unsigned char song_fpos_hl_old = 0;
unsigned char sam_fpos_real = 0;
unsigned char sam_fpos_hl = 0;
unsigned char sam_fpos_hl_old = 0;

char edit_mode;
#define SONGNAME_SIZE 50
char filename[SONGNAME_SIZE + 1];
char menu_option = 0;

char nibble_display[] = "0123456789ABCDEF";
char *note_display[] = {
  "C-1","C#1","D-1","D#1","E-1","F-1","F#1","G-1","G#1","A-1","A#1","B-1",
  "C-2","C#2","D-2","D#2","E-2","F-2","F#2","G-2","G#2","A-2","A#2","B-2",
  "C-3","C#3","D-3","D#3","E-3","F-3","F#3","G-3","G#3","A-3","A#3","B-3",
  "C-4","C#4","D-4","D#4","E-4","F-4","F#4","G-4","G#4","A-4","A#4","B-4",
  "C-5","C#5","D-5","D#5","E-5","F-5","F#5","G-5","G#5","A-5","A#5","B-5",
  "???","RLO","***","   "
};

/*ncurses 1.9.2c doesn't make this function public.. so, we do it here*/
extern int wgetnstr(WINDOW *win, char *str, int maxlen);

/*protos funktracker.c*/
#pragma pack(1)
extern tfunk_info funk_info;
#pragma pack()

/*protos from funkmisc.c*/
extern int ferr_val;
extern char *ferr_messages[];
extern void get_environment(void);
extern void dealloc_funk_mem(void);
extern void new_funk_module(void);
extern void load_funk_module(char *filename);
extern void save_funk_module(char *filename);
extern void load_mod_module(char *filename);
extern void save_mod_module(char *filename);
extern void save_ntrac_funk_module(char *filename,int new_no_active_channels);
extern void opti_funk_module(char *filename);
extern void convprec_funk_module(char *filename,int to_type);

/*protos from dsp_mixxer*/
extern int no_active_channels;
extern int open_dsp(int srate,int prec,int st,int frames,int fragment);
extern void close_dsp(void);
extern int sample_precision;

/*protos from funkgold_sm*/
extern unsigned char sm_pos_real;
extern unsigned char sm_pos_hl;
extern unsigned char sm_pos_hl_old;
extern unsigned char sm_sd_option;
extern void sm_display_bg(void);
extern void sm_display_all(void);
extern void sm_main(void);

/*protos from funkgold_se*/
extern unsigned char se_pos_real;
extern unsigned char se_pos_hl;
extern unsigned char se_pos_hl_old;
extern void se_display_bg(void);
extern void se_display_all(void);
extern void se_main(void);

/*protos from funkgold_pe*/
extern unsigned char pe_pattern_no;
extern unsigned char pe_note_no;
extern unsigned char pe_octave_no;
extern unsigned char pe_chan_real;
extern unsigned char pe_pos_real;
extern unsigned char pe_chan_hl;
extern unsigned char pe_pos_hl;
extern unsigned char pe_chan_hl_old;
extern unsigned char pe_pos_hl_old;
extern unsigned char pe_nodischans;
extern void pe_display_bg(void);
extern void pe_display_all(void);
extern void pe_main(void);

#pragma pack(1)
extern tslot *pe_slot;
extern tslot *pe_copy_buffer;
#pragma pack()

/*copying*/
extern unsigned char pe_mchan_begin;
extern unsigned char pe_mchan_end;
extern unsigned char pe_mpos_begin;
extern unsigned char pe_mpos_end;
extern unsigned char pe_mflag;
extern unsigned char pe_copied_flag;

/*protos for filefinder*/
extern int get_song_file_name(
  char *directory,
  unsigned char *fpos_real,
  unsigned char *fpos_hl,
  unsigned char *fpos_hl_old,
  char *filename);
extern int get_sam_file_name(
  char *directory,
  unsigned char *fpos_real,
  unsigned char *fpos_hl,
  unsigned char *fpos_hl_old,
  char *filename);

/***************************************************************************
*
***************************************************************************/
void display_topbar(void)
{
  clear();
  move(0,0);
  attron(A_REVERSE);
  addstr(" FunktrackerGOLD " FUNK_VERSION "                           "
         "                   by Jason Nunn ");
}

/***************************************************************************
* Utility functions
***************************************************************************/

/************************************
*
************************************/
void hl_bar(char option,char x)
{
  if(option == x)
    attron(A_REVERSE);
  else
    attroff(A_REVERSE);
}

void update_screen(void)
{
  attroff(A_REVERSE);
  move(0,0);
  refresh();
}

/************************************
*
************************************/
void byte2str(char *str,unsigned char value)
{
  *str       = nibble_display[value >> 4];
  *(str + 1) = nibble_display[value & 0x0f];
}

void word2str(char *str,unsigned long value)
{
  *str       = nibble_display[(value >> 12) & 0xf];
  *(str + 1) = nibble_display[(value >> 8) & 0xf];
  *(str + 2) = nibble_display[(value >> 4) & 0xf];
  *(str + 3) = nibble_display[value & 0xf];
}

void dword2str(char *str,unsigned long value)
{
  *str       = nibble_display[(value >> 28) & 0xf];
  *(str + 1) = nibble_display[(value >> 24) & 0xf];
  *(str + 2) = nibble_display[(value >> 20) & 0xf];
  *(str + 3) = nibble_display[(value >> 16) & 0xf];
  *(str + 4) = nibble_display[(value >> 12) & 0xf];
  *(str + 5) = nibble_display[(value >> 8) & 0xf];
  *(str + 6) = nibble_display[(value >> 4) & 0xf];
  *(str + 7) = nibble_display[value & 0xf];
}

int find_hex(char chh)
{
  register int x;
  for(x = 0; x < 16;x++)
  {
    if(chh == nibble_display[x]) return x;
    if(chh == (nibble_display[x] + 'a' - 'A')) return x;
  }
  return -1;
}

int hex2nib(char *str)
{
  register int a = find_hex(str[0]);
  if(a == -1) return -1;
  return a;
}

int hex2char(char *str)
{
  register int a = find_hex(str[0]);
  register int b = find_hex(str[1]);
  if((a == -1) || (b == -1)) return -1;
  return (a << 4) + b;
}

long hex2long(char *str)
{
  register int a = hex2char(str);
  register int b = hex2char(str + 2);
  register int c = hex2char(str + 4);
  register int d = hex2char(str + 6);
  if((a == -1) || (b == -1) || (c == -1) || (d == -1))
    return -1;
  return (a << 24) + (b << 16) + (c << 8) + d;
}

/************************************
*
************************************/
void get_string(char y, char x,char *str,int maxlen)
{
  register int a;

  attron(A_REVERSE);
  for(a = 0;a < maxlen;a++)
  {
    move(y,x + a);
    addch(' ');
  }
  echo();
  move(y,x);
  wgetnstr(stdscr,str,maxlen);
  noecho();
}

/************************************
*
************************************/
void clear_area(char y1,char x1,char y2,char x2)
{
  register char a;
  for(y1 = y1;y1 <= y2;y1++)
    for(a = x1;a <= x2;a++)
    {
      move(y1,a);
      addch(' ');
    }
}

/************************************
* miwi 27/05/96
************************************/
void ferr_message(char *mess_str)
{
  register amaxy = maxy - 2;

  attron(A_BLINK);
  move(amaxy,0);
  addstr(mess_str);
  addstr(" [hit key]");
  attroff(A_BLINK);
  beep();
  update_screen();
  getch();
  clear_area(amaxy,0,amaxy,79);
  update_screen();
}

/***************************************************************************
****************************************************************************
****************************************************************************
*
* Main screen
*
****************************************************************************
****************************************************************************
***************************************************************************/

/***************************************************************************
*
***************************************************************************/
void main_editor_dis_bg(void)
{
  switch(edit_mode)
  {
    case EM_SAMPLE:
      sm_display_bg();
      sm_display_all();
      break;
    case EM_SEQUENCE:
      se_display_bg();
      se_display_all();
      break;
    case EM_PATTERN:
      pe_display_bg();
      pe_display_all();
      break;
  }
  update_screen();
}

/***************************************************************************
* miwi 27/05/96
***************************************************************************/
void save_song(int song_type)
{
  if(chdir(song_directory) == -1)
    ferr_message("Couldn't locate song directory.");
  else
  {
    if(song_type)
      save_funk_module(song_filename);
    else
      save_mod_module(song_filename);
    if(ferr_val == FERR_OK)
    {
      move(maxy - 2,0);
      addstr(song_filename);
      addstr(" saved..");
      if(!song_type) addstr("(as a .MOD file)");
      update_screen();
    }
    else
      ferr_message(ferr_messages[ferr_val]);
  }
}

/***************************************************************************
* miwi 27/05/96
***************************************************************************/
int quit_confirm(void)
{
  register int amaxy = maxy - 2;

  attron(A_BLINK);
  clear_area(amaxy,0,amaxy,79);
  move(amaxy,0);
  addstr("Quit to main menu yes? [y/N]");
  attroff(A_BLINK);
  beep();
  update_screen();
  ch = getch();
  clear_area(amaxy,0,amaxy,79);
  update_screen();
  if((ch == 'y') || (ch == 'Y'))
    return 1;
  ch = 0;
  return 0;
}

/***************************************************************************
*
***************************************************************************/
void main_editor_loop(void)
{
  pe_copy_buffer = malloc(64 * MAXIMUM_CHANNELS * sizeof(tslot));
  if(pe_copy_buffer != NULL)
  {
    edit_mode = EM_SAMPLE;
/*sample editor*/
    sm_pos_real = 0;
    sm_pos_hl = 0;
    sm_pos_hl_old = 0;
    sm_sd_option = 0;
/*sequence editor*/
    se_pos_real = 0;
    se_pos_hl = 0;
    se_pos_hl_old = 0;
/*pattern editor*/
    pe_pattern_no = 0;
    pe_note_no = 0;
    pe_octave_no = 2;
    pe_chan_real = 0; 
    pe_pos_real = 0;
    pe_chan_hl = 0;
    pe_pos_hl = 0;
    pe_chan_hl_old = 0;
    pe_pos_hl_old = 0;
    pe_nodischans = no_active_channels;
    if(pe_nodischans > 8) pe_nodischans = 8;

    pe_mchan_begin = 0;
    pe_mchan_end = 0;
    pe_mpos_begin = 0;
    pe_mpos_end = 0;
    pe_mflag = 0;
    pe_copied_flag = 0;

    main_editor_dis_bg();
    while(edit_mode != EM_MAIN)
    {
      ch = getch();
      switch(edit_mode)
      {
        case EM_SAMPLE:
          sm_main();
          break;
        case EM_SEQUENCE:
          se_main();
          break;
        case EM_PATTERN:
          pe_main();
          break;
      }
    }
    dealloc_funk_mem();
    free(pe_copy_buffer);
  }
  else
    ferr_message("Error: Couldn't allocate copy buffer.");
}

/***************************************************************************
* miwi 27/05/96
***************************************************************************/
void ms_menu(void)
{
  hl_bar(menu_option,0);
  move(3,2);
  addstr(" NEW SONG  ");
  hl_bar(menu_option,1);
  move(4,2);
  addstr(" LOAD SONG ");
  hl_bar(menu_option,2);
  move(6,2);
  addstr("SET SNG DIR");
  hl_bar(menu_option,3);
  move(8,2);
  addstr(" OPTIMISE  ");
  hl_bar(menu_option,4);
  move(9,2);
  addstr(" CHG TRCKS ");
  hl_bar(menu_option,5);
  move(10,2);
  addstr("08bit -> 16");
  hl_bar(menu_option,6);
  move(11,2);
  addstr("16bit -> 08");
  hl_bar(menu_option,7);
  move(13,2);
  addstr("   QUIT    ");
}

void ms_display_bg(void)
{
  register int y;
  register int amaxy = maxy - 5;

  display_topbar();
  for(y = 1;y < (maxy - 5);y++)
  {
    move(y,0);
    addch(' ');
    move(y,14);
    addch(' ');
    move(y,79);
    addch(' ');
  }
  move(y,0);
  clear_area(amaxy,0,amaxy,79);
  ms_menu();
}

/***************************************************************************
* miwi 27/05/96
***************************************************************************/
void ms_nfile_display(char option)
{
  char str[3];

  hl_bar(option,0);
  move(3,16);
  addstr("     Name:                                                   ");
  move(3,27);
  addstr(filename);
  move(4,16);
  hl_bar(option,1);
  addstr("Precision: ");
  if(sample_precision == 16)
    addstr("16 bit");
  else
    addstr("08 bit");
  addstr(" Module");

  hl_bar(option,2);
  move(5,16);
  addstr(" Channels:    Channels");
  move(5,27);
  sprintf(str,"%d",no_active_channels);
  addstr(str);

  hl_bar(option,3);
  move(7,16);
  addstr(">                        B  A  C  K                         <");

  hl_bar(option,4);
  move(8,16);
  addstr(">                           O  K                            <");
}

void ms_new_file(void)
{
  char quit_f = 1,option = 0;

  sample_precision = 8;
  clear_area(3,16,(maxy - 6),78);
  strcpy(filename,"New_Song");
  move((maxy - 8),17);
  addstr("Use the arrow keys to select attribute");
  move((maxy - 7),17);
  addstr("then enter to change.");

  ms_nfile_display(option);
  update_screen();
  while(quit_f)
  {
    ch = getch();
    switch(ch)
    {
      case FC_ARROW_UP:
        if(option > 0) option--;
        ms_nfile_display(option);
        update_screen();
        break;
      case FC_ARROW_DN:
        if(option < (5 - 1)) option++;
        ms_nfile_display(option);
        update_screen();
        break;
      case FC_ENTER:
        switch(option)
        {
          case 0:
            get_string(3,27,filename,SONGNAME_SIZE);
            ms_nfile_display(option);
            update_screen();
            break;
          case 1:
            if(sample_precision == 8)
              sample_precision = 16;
            else
              sample_precision = 8;
            ms_nfile_display(option);
            update_screen();
            break;
          case 3:
            quit_f = 0;
            break;
          case 4:
            if(strlen(filename))
            {
              strcpy(song_filename,filename);
              strcat(song_filename,".Funk");
              new_funk_module();
              if(ferr_val == FERR_OK)
              {
                main_editor_loop();
                quit_f = 0;
                ms_display_bg();
              }
            }
            else
              ferr_message("You need to give new song a name before proceeding.");
            break;
        }
        break;
      case FC_ARROW_RIGHT:
        switch(option)
        {
          case 2:
            if(no_active_channels < MAXIMUM_CHANNELS)
              no_active_channels++;
            ms_nfile_display(option);
            update_screen();
            break;
        }
        break;
      case FC_ARROW_LEFT:
        switch(option)
        {
          case 2:
            if(no_active_channels > 4)
              no_active_channels--;
            ms_nfile_display(option);
            update_screen();
            break;
        }
        break;
    }
  }
  clear_area(3,16,(maxy - 6),78);
  update_screen();
}

/***************************************************************************
****************************************************************************
*
* credit scroller
*
****************************************************************************
***************************************************************************/
char *credit_scroll[] =
{
  "",      /*----*/
  "=  F u n k t r a c k e r  G O L D  =",
  "",
  "A FREEWARE Digital Module Tracker for Unix",
  "8/16 bit sampling - N channel mixxing",
  "",
  "By Jason Nunn",
  "Authorship is reserved 1994,1996",
  "",      /*----*/
  "=Contacts=",
  "",
  "32 Rothdale Rd",
  "Moil Darwin",
  "Northern Territory 0810",
  "AUSTRALIA",
  "",
  "<No email address unfortunately>",
  "",      /*----*/
  "=Contributors=",
  "",
  "",
  "FreeBSD port",
  "Brian Nielsen <norman@iesd.auc.dk>",
  "",
  "Interface Enhancement",
  "<Michael.Will@student.uni-tuebingen.de>",
  "",
  "addnstr routine",
  "Stephane DUBON <twinsen@etca.fr>",
  "",     /*----*/
  "= 0.0 Beta Testers=",
  "",
  "",
  "Jim Leonard <trixter@mcs.com>",
  "",
  "Joey Hess <joey@kite.preferred.com>",
  "",
  "Predrag Balorda <pele@ezun123.ds.ulcc.ac.uk>",
  "",
  "Casey Ryder <cees@coso.com>",
  ""
};

typedef struct
{
  int pos;
  int run;
} tcredit_ptrs;

tcredit_ptrs credit_ptrs[] =
{
  {0,9},
  {8,10},
  {0,9},
  {17,13},
  {0,9},
  {29,12}
};

int sc_ptr = 0;
int ev_ptr = 0;
int ev_count = 0;
int scroll_ptr;

/*************************************
*
*************************************/
void print_credit_line(void)
{
  register int y;

  for(y = 0;y < credit_ptrs[sc_ptr].run;y++)
  {
    register int y_pos = y + scroll_ptr;
    register int y_line = credit_ptrs[sc_ptr].pos + y;
    if(y_pos < (maxy - 5))
    {
      register int x_pos;

      move(y_pos,24);
      addstr("                                            ");
      x_pos = 46 - (strlen(credit_scroll[y_line]) >> 1);
      move(y_pos,x_pos);
      addstr(credit_scroll[y_line]);
    }
  }
}

/*************************************
*
*************************************/
int ev_credit_line(int sig)
{
  signal(sig,(void *)&ev_credit_line);
  switch(ev_ptr)
  {
    case 0:
      ev_count = 0;
      ev_ptr++;
    case 1:
      if(ev_count++ > 10) ev_ptr++;
      break;
    case 2:
      scroll_ptr = (maxy - 5);
      ev_ptr++;
      break;
    case 3:
      print_credit_line();
      if(scroll_ptr == 2)
        ev_ptr++;
      else
        scroll_ptr--;
      break;
    case 4:
      ev_count = 0;
      ev_ptr++;
    case 5:
      if(ev_count++ > 100) ev_ptr++;
      break;
    case 6:
      print_credit_line();
      if(scroll_ptr == (maxy - 5))
        ev_ptr++;
      else
        scroll_ptr++;
      break;
    case 7:
      if(++sc_ptr > 5) sc_ptr = 0;
      ev_ptr = 0;
      break;
  }
  update_screen();
  return 1;
}

/***************************************************************************
*
***************************************************************************/
void print_ntrac_param(int no_channels)
{
  char tmpstr[6];

  sprintf(tmpstr," %d ",no_channels);
  move(8,44);
  addstr(tmpstr);
}

void get_ntrac_param(void)
{
  register int option = 1,new_channels;

  attron(A_REVERSE);
  clear_area(6,28,10,49);
  attroff(A_REVERSE);
  clear_area(7,29,9,48);
  move(8,30);
  addstr("New capacity: ");
  new_channels = no_active_channels;
  print_ntrac_param(new_channels);
  while(option)
  {
    ch = getch();
    switch(ch)
    {
      case FC_ENTER:
        load_funk_module(song_filename);
        if(ferr_val == FERR_OLD_FK) ferr_val = FERR_OK;
        if(ferr_val == FERR_OK)
        {
          save_ntrac_funk_module(song_filename,new_channels);
          if(ferr_val != FERR_OK)
            ferr_message(ferr_messages[ferr_val]);
        }
        else
          ferr_message(ferr_messages[ferr_val]);
        option = 0;
        break;
      case FC_ARROW_UP:
        if(--new_channels < 4) new_channels = 4;
        print_ntrac_param(new_channels);
        break;
      case FC_ARROW_DN:
        if(++new_channels > MAXIMUM_CHANNELS) new_channels = MAXIMUM_CHANNELS;
        print_ntrac_param(new_channels);
        break;
    }
  }
}

/***************************************************************************
*
***************************************************************************/
void ms_main(void)
{
  struct itimerval oldtimer,timer;
  register int totype,credit_on = 1;

  edit_mode = EM_MAIN;
  ms_display_bg();
  update_screen();

  signal(SIGALRM,(void *)&ev_credit_line);
  timer.it_value.tv_sec = 0;
  timer.it_interval.tv_sec = 0;
  timer.it_value.tv_usec = 50000;
  timer.it_interval.tv_usec = 50000;
  setitimer(ITIMER_REAL,&timer,&oldtimer);
  while(edit_mode != EM_QUIT)
  {
    ch = getch();
    switch(ch)
    {
      case FC_ARROW_UP:
        if(menu_option > 0) menu_option--;
        ms_menu();
        update_screen();
        break;
      case FC_ARROW_DN:
        if(menu_option < (8 - 1)) menu_option++;
        ms_menu();
        update_screen();
        break;
      case FC_ENTER:
        setitimer(ITIMER_REAL,&oldtimer,&timer);
        credit_on = 0;
        switch(menu_option)
        {
          case 0: /*new song*/
            ms_new_file();
            break;
          case 1: /*load song*/
            if(get_song_file_name(song_directory,&song_fpos_real,&song_fpos_hl,
              &song_fpos_hl_old,song_filename) != -1)
            {
              if((strstr(song_filename,".Funk") != NULL) ||
                 (strstr(song_filename,".fnk") != NULL))
              {
                load_funk_module(song_filename);
                if(ferr_val == FERR_OK)
                  main_editor_loop();
                else if(ferr_val == FERR_OLD_FK)
                {
                  ferr_message(ferr_messages[ferr_val]);
                  main_editor_loop();
                }
                else
                  ferr_message(ferr_messages[ferr_val]);
              }
              else if(strstr(song_filename,".mod") != NULL)
              {
                load_mod_module(song_filename);
                if(ferr_val == FERR_OK)
                  main_editor_loop();
                else
                  ferr_message(ferr_messages[ferr_val]);
              }
              else
                ferr_message(ferr_messages[FERR_SNGUNKNOWN]);
            }
            ms_display_bg();
            update_screen();
            break;
          case 2: /*change song directory*/
            get_song_file_name(song_directory,&song_fpos_real,&song_fpos_hl,
              &song_fpos_hl_old,song_filename);
            ms_display_bg();
            update_screen();
            break;
          case 3: /*optimise module*/
            if(get_song_file_name(song_directory,&song_fpos_real,&song_fpos_hl,
              &song_fpos_hl_old,song_filename) != -1)
              if((strstr(song_filename,".Funk") != NULL) ||
                 (strstr(song_filename,".fnk") != NULL))
              {
                opti_funk_module(song_filename);
                if(ferr_val != FERR_OK)
                  ferr_message(ferr_messages[ferr_val]);
              }
              else
                ferr_message(ferr_messages[FERR_SNGUNKNOWN]);
            ms_display_bg();
            update_screen();
            break;
          case 4: /*ntrac converter*/
            if(get_song_file_name(song_directory,&song_fpos_real,&song_fpos_hl,
              &song_fpos_hl_old,song_filename) != -1)
              if((strstr(song_filename,".Funk") != NULL) ||
                 (strstr(song_filename,".fnk") != NULL))
                get_ntrac_param();
              else
                ferr_message(ferr_messages[FERR_SNGUNKNOWN]);
            ms_display_bg();
            update_screen();
            break;
          case 5: /*8 bit to 16 bit convert*/
            totype = 1;
            goto do_precconv;
          case 6: /*16 bit to 8 bit convert*/
            totype = 0;
do_precconv:
            if(get_song_file_name(song_directory,&song_fpos_real,&song_fpos_hl,
              &song_fpos_hl_old,song_filename) != -1)
              if((strstr(song_filename,".Funk") != NULL) ||
                 (strstr(song_filename,".fnk") != NULL))
              {
                convprec_funk_module(song_filename,totype);
                if(ferr_val != FERR_OK)
                  ferr_message(ferr_messages[ferr_val]);
              }
              else
                ferr_message(ferr_messages[FERR_SNGUNKNOWN]);
            ms_display_bg();
            update_screen();
            break;
          case 7: /*quit song*/
            edit_mode = EM_QUIT;
            break;
        }
        break;
    }
  }
  if(credit_on) setitimer(ITIMER_REAL,&oldtimer,&timer);
}

/***************************************************************************
****************************************************************************
****************************************************************************
*
* main stuff
*
****************************************************************************
****************************************************************************
***************************************************************************/
char pause_cmdline = 0;
int cmdline_sr;
int cmdline_prec;
int cmdline_stereo;
int cmdline_frames;
int cmdline_frag;

/***************************************************************************
*
***************************************************************************/
int cmdline(int argc,char *argv[])
{
  register int x;
  int y;

  for(x = 0;x < argc;x++)
  {
    if(argv[x][0] == '-')
    {
      switch(argv[x][1])
      {
        case 'h':
          printf(
            "\nUsage: funkgold <options>\n"
             " -h        Display this help info\n"
             " -!        Pause on startup\n"
             " -pxxx     Pattern allocation number 0 to 128 (default is 128)\n"
             " -sxxxxx   Sample Rate 6000 to 44100\n"
             " -Pxx      Output Precision (-P8 = 8 bit, -P16 = 16 bit)\n"
             " -Sx       Output Stereo (-S0 = Mono, -S1 = Stereo)\n"
             " -fxx      DSP number of frames XX (see options.h for description)\n"
             " -Fxx      DSP fragment size XX (see options.h for description)\n"
             "\n"
          );
          return 0;
        case '!':
          pause_cmdline = 1;
          break;
        case 'p':
          sscanf(argv[x],"-p%d",&funk_info.funk_pd_size);
          break;
        case 's':
          sscanf(argv[x],"-s%d",&cmdline_sr);
          break;
        case 'P':
          sscanf(argv[x],"-P%d",&y);
          if(y == 8) cmdline_prec = 8;
          if(y == 16) cmdline_prec = 16;
          break;
        case 'S':
          sscanf(argv[x],"-S%d",&cmdline_stereo);
          break;
        case 'f':
          sscanf(argv[x],"-f%d",&cmdline_frames);
          break;
        case 'F':
          sscanf(argv[x],"-F%d",&cmdline_frag);
          break;
      }
    }
  }
  return 1;
}

/***************************************************************************
*
***************************************************************************/
int main(int argc,char *argv[])
{
  printf("Welcome to FunktrackerGOLD %s (the Curses "
         "editor/Non-preemptive Mixxing)..\n",FUNK_VERSION);
  funk_info.funk_pd_size = MAXIMUM_PATTERNS;
  cmdline_sr = DEFAULT_SAM_RATE;
  cmdline_prec = DEFAULT_PRECISION;
  cmdline_stereo = DEFAULT_STEREO;
  cmdline_frames = FUNK_DSP_FRAMES;
  cmdline_frag = FUNK_DSP_FRAGMENT;
  if(cmdline(argc,argv))
  {
    if(funk_info.funk_pd_size < 1) funk_info.funk_pd_size = 1;
    if(funk_info.funk_pd_size > 128) funk_info.funk_pd_size = 128;
    cmdline_stereo &= 1;
    cmdline_frag &= 0xf;
    get_environment();
    printf("Max Pattern allocation: %d\n",funk_info.funk_pd_size);
    getcwd(song_directory,1024);
    getcwd(sample_directory,1024);
    if(open_dsp(cmdline_sr,
                cmdline_prec,
                cmdline_stereo,
                cmdline_frames,
                cmdline_frag))
    {
      if(pause_cmdline)
      {
        printf("Pausing for 10 seconds. Please wait...\n");
        sleep(10);
      }
      initscr();
      maxy = LINES;
      if(maxy >= 24)
      {
        if(maxy > (24 + (64 - 16))) maxy = (24 + (64 - 16));
        cbreak();
        noecho();
        keypad(stdscr,TRUE);
        ms_main();
        clear();
        refresh();
        resetterm();
        echo();
        endwin();
        printf(WELCOME);
      }
      else
      {
        endwin();
        printf("Error: Screen size is too small. Program aborted.\n");
      }
      close_dsp();
    }
  }
  return 1;
}

