/*

      Copyright (c) Florian Xaver 2000

      florianx@drdos.org

      Updates by Owen Rudge, 23/4/2001
      orudge@freeuk.com * www.owenrudge.co.uk

      Updated for Seal2 kernel include by Julien Etelain 02/09/2001
      julien@pmad.net - www.sealsystem.org - www.pmad.net

      Updated for enhanced SFA Player by Owen Rudge, 16/9/2001

      SFA extended sound library for SEAL
      Bad Seal compatible version

      License: GPL

  *******************************************************************
  Revision History (as of 04/10/2001):

  - 04/10/2001   Added support for About command (orudge)

  All dates are in UK time (DD/MM/YYYY)
  *******************************************************************
*/

#include <seal.h>
#include <app.h>
#include <sound.h>

#define TXT_INITSOUNDCARD        INI_TEXT("Launching sound driver, init soundcard ...")
#define TXT_SOUNDCARD            INI_TEXT("Launching sound driver, soundcard found: %s")
#define TXT_CANNOTINITSOUNDCARD  INI_TEXT("Cannot init the soundcard: %s\n\nPlease edit seal.cfg!")
#define TXT_CANNOTINITSOUNDINPUT INI_TEXT("Cannot install sound input: %s ")

//#define SHOW_INFO // does not work with Bad Seal
#define DO_SEARCH

/* sound format item functions */

/*
   make new sound format item

   look at dlxsound.h


*/

// list of all sound format dlx loaded

p_list sound_format_list;


     /**[txh]**********************************************************************

      Function:p_soundformat_item  new_soundformat_item(   l_text extension,
                                            l_text info,
                                            l_int (*init_file) (p_soundformat_item o, l_text file),
                                            l_int (*play_file) (p_soundformat_item o),
                                            l_int (*poll_file)(p_soundformat_item o),
                                            l_int (*stop_file)(p_soundformat_item o),
                                            l_int (*pause_file)(p_soundformat_item o),
                                            l_int (*forward_file)(p_soundformat_item o, l_int relpos),
                                            l_int (*rewind_file)(p_soundformat_item o, l_int relpos),
                                            l_int (*set_pos)(p_soundformat_item o, l_int pos),
                                            l_int (*get_pos)(p_soundformat_item o),
                                            l_int (*get_len_file)(p_soundformat_item o),
                                            l_int (*get_time)(p_soundformat_item o),
                                            l_int (*is_stereo)(p_soundformat_item o),
                                            l_text (*get_additional_info)(p_soundformat_item o),
                                            l_int (*about_box)(p_soundformat_item o) // OCR, 4/10/2001
                                            )


      Description: Stores all funktions in a list

      Return: p_soundformat_item
      Example:       p_soundformat_item k = new_soundformat_item(("mp3"),
                                                     ("MP3 files"),
                                                     ("(c) Florian Xaver GNU GPL - virtual sound file"),
                                                     &mp3_init_file,
                                                     &mp3_play_file,
                                                     &mp3_poll_file,
                                                     &mp3_stop_file,
                                                     &mp3_pause_file,
                                                     &mp3_forward_file,
                                                     &mp3_rewind_file,
                                                     &mp3_set_pos,
                                                     &mp3_get_pos,
                                                     &mp3_get_len_file,
                                                     &mp3_get_time,
                                                     &mp3_is_stereo,
                                                     &mp3_get_additional_info,
                                                     &mp3_display_about
                                                     );

           sound_format_list->insert(sound_format_list, k);


     *****************************************************************************/


p_soundformat_item  new_soundformat_item(   l_text extension,
                                            l_text filedesc,
                                            l_text info,
                                            l_int (*init_file) (p_soundformat_item o, l_text file),
                                            l_int (*play_file) (p_soundformat_item o),
                                            l_int (*poll_file)(p_soundformat_item o),
                                            l_int (*stop_file)(p_soundformat_item o),
                                            l_int (*pause_file)(p_soundformat_item o),
                                            l_int (*forward_file)(p_soundformat_item o, l_int relpos),
                                            l_int (*rewind_file)(p_soundformat_item o, l_int relpos),
                                            l_int (*set_pos)(p_soundformat_item o, l_int pos),
                                            l_int (*get_pos)(p_soundformat_item o),
                                            l_int (*get_len_file)(p_soundformat_item o),
                                            l_int (*get_time)(p_soundformat_item o),
                                            l_int (*is_stereo)(p_soundformat_item o),
                                            l_text (*get_additional_info)(p_soundformat_item o),
                                            l_int (*about_box)(p_soundformat_item o)
                                            )



{

  p_soundformat_item i = (p_soundformat_item)_malloc(sizeof(t_soundformat_item));

  if ( i ) {
     i->extension = _strdup(extension);
     i->info = strdup(info);
     i->filedesc = strdup(filedesc);
     i->init_file = init_file;
     i->play_file = play_file;
     i->poll_file = poll_file;
     i->stop_file = stop_file;
     i->pause_file = pause_file;
     i->forward_file = forward_file;
     i->rewind_file = rewind_file;
     i->set_pos = set_pos;
     i->get_pos = get_pos;
     i->get_len_file = get_len_file;
     i->get_time = get_time;
     i->is_stereo = is_stereo;
     i->get_additional_info = get_additional_info;
     i->about_box = about_box;
  };

  return i;

};

/* free soundformat item */

void  free_soundformat_item ( void *o )
{

   if ( o ) {

      if (((p_soundformat_item)o)->extension)_free(((p_soundformat_item)o)->extension);
      if (((p_soundformat_item)o)->info) _free(((p_soundformat_item)o)->info);
      if (((p_soundformat_item)o)->filedesc) _free(((p_soundformat_item)o)->filedesc);

      _free(o);

   };

};


/* standard funktions for sound formats, they do nothing*/

   //play file funktion
   l_int st_init_file (p_soundformat_item o, l_text file)
         {
         seal_error(ERR_INFO, "debug: init %s", file);
         return 1;
         };

   //play file funktion
   l_int st_play_file (p_soundformat_item o)
         {
         seal_error(ERR_INFO, "debug: play");
         return 1;
         };


   //poll file
   l_int st_poll_file(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "debug_ poll");
         return 1;
         };

   //stop file
   l_int st_stop_file(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "debug: stop");
         return 1;
         };

   //pause file
   l_int st_pause_file(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   //forward
   l_int st_forward_file(p_soundformat_item o, l_int relpos)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   //rewind
   l_int st_rewind_file(p_soundformat_item o, l_int relpos)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   //set pos
   l_int st_set_pos(p_soundformat_item o, l_int pos)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   //get current pos
   l_int st_get_pos(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   //lenght of file
   l_int st_get_len_file(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   // get current time
   l_int st_get_time(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   l_int st_is_stereo(p_soundformat_item o)
         {
//         seal_error(ERR_INFO, "File format isn't supported!");
         return 1;
         };

   l_text st_get_additional_info(p_soundformat_item o)
         {
         return _strdup("debugging!");
         }

l_int st_about_box(p_soundformat_item o)
{
   msgbox(MW_INFO, MB_OK, "SFA Generic Driver\n\nCopyright (c) Florian Xaver 2000\nCopyright (c) Owen Rudge 2001");
}

/*-------------------------*/

// is the "Konstruktor"
//
// example:
//
//  p_play ex = SFA_init();
//
//  // Now you can play as many files as you want
//
//  ex->init_file(filename);
//  ex->play();
//  while (ex->poll());
//



p_play SFA_init()
{
   p_play p = (p_play)_malloc(sizeof(t_play));

   if (p)
     {
     p->init_file = &init_file;
     p->play_file = &play_file;
     p->poll_file = &poll_file;
     p->rewind_file = &rewind_file;
     p->forward_file = &forward_file;
     p->stop_file = &stop_file;
     p->pause_file = &pause_file;
     p->get_info = &get_info;
     p->set_pos = &set_pos;
     p->get_pos = &get_pos;
     p->get_len_file = &get_len_file;
     p->get_time = &get_time;
     p->is_stereo = &is_stereo;
     p->get_additional_info = &get_additional_info;
     p->about_box = &about_box;

     p->filename = 0;
     p->used_library = 0;

     }


   return p;
}

/*l_int sound_format_callback(void* ext, void* rec, l_dword ind)
{

seal_error(ERR_INFO, "%s", ((p_soundformat_item)rec)->extension);
if (!strcmp( ((p_soundformat_item)rec)->extension, ext)) return false;
ind++;
return true;

} */


/*void search_right_extension()
{

l_dword ind = 0;

sound_format_list->for_each_item(sound_format_list, "mp3", sound_format_callback, ind);

seal_error(ERR_INFO, "%d", ind);


} */

     /**[txh]**********************************************************************

      Function: l_int init_file (p_play o, l_text file)

      Description: Init the file

      Return: 0 if error
      Example: p_play pp = 0;
               pp->init_file(pp, file)

     *****************************************************************************/


   //init file
l_int init_file (p_play o, l_text file)
       {



          p_item x = sound_format_list->first(sound_format_list);
          p_item f = x;
          signed int ok = 0;
          l_text pfile = GetFile(file);
          l_int used_l = 0;


          o->used_library = 0;

//          seal_error(ERR_INFO, "searching extension %s", get_extension(file));

          do {

//            seal_error(ERR_INFO, "searching: %s found", ((p_soundformat_item)x->rec)->extension);

            if (!stricmp( ((p_soundformat_item)x->rec)->extension , get_extension(pfile) ))
               {
               o->used_library = (p_soundformat_item)x->rec;
//               seal_error(ERR_INFO, "Extension found: %s Used_library: %d Found_library: %d", ((p_soundformat_item)x->rec)->extension,
//               (o->used_library) ? 1 : 0,  ((p_soundformat_item)x->rec) ? 1 : 0);
               ok = 1;

               }


            x = x->next;


          } while ( !ok  && x != f );
//            } while (1);




         if ( o->used_library )
          {


//          seal_error(ERR_INFO, "Want to play file #2 [%s]", file);
          used_l = (o->used_library)->init_file(o->used_library, pfile);

          } else {
            DEBUG_printf("SFA Error :: Unknow File Type for \"%s\"\n",pfile);

          };

          if (pfile) _free(pfile);


//          else

//          seal_error(ERR_INFO, "Want to play file #2: error used_library == 0");



         return used_l;

      };

     /**[txh]**********************************************************************

      Function: l_int play_file (p_play o)

      Description: plays the file (must be init)

      Return: 0 if error
      Example: pp->play_file(pp)

     *****************************************************************************/


   //play file
l_int play_file (p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->play_file(o->used_library);
         }

      };

     /**[txh]**********************************************************************

      Function: l_int poll_file (p_play o)

      Description: Must be called very often!

      Return: 0 if file finished
      Example: file_is_playing = pp->poll_file(pp);

     *****************************************************************************/


l_int poll_file (p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->poll_file(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int stop_file(p_play o)

      Description: stop playing the file

      Return:
      Example: pp->stop_file(pp);

     *****************************************************************************/


   //stop file
l_int stop_file(p_play o)
      {
      if ( o->used_library )
         {
         return o->used_library->stop_file(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int pause_file(p_play o)

      Description: pauses the file

      Return:
      Example: pp->pause(pp);

     *****************************************************************************/


   //pause file
l_int pause_file(p_play o)
      {
      if ( o->used_library )
         {
         return (o->used_library)->pause_file(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int forward_file(p_play o, l_int relpos)

      Description: Set relative position (forward)

      Return:
      Example: pp->forward_file(pp, 10);

     *****************************************************************************/


   //forward
l_int forward_file(p_play o, l_int relpos)
      {
      if ( o->used_library )
         {
         return (o->used_library)->forward_file(o->used_library, relpos);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int rewind_file(p_play o, l_int relpos)

      Description: Set relative position (rewind)

      Return:
      Example: pp->rewind_file(pp, 10);

     *****************************************************************************/


   //rewind
l_int rewind_file(p_play o, l_int relpos)
      {
      if (o->used_library)
         {
         return (o->used_library)->rewind_file(o->used_library, relpos);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int set_pos(p_play o, l_int pos)

      Description: Sets position in the file

      Return:
      Example: pp->set_pos(pp, 1000);

     *****************************************************************************/


   //set pos
l_int set_pos(p_play o, l_int pos)
      {
      if (o->used_library)
         {
         return (o->used_library)->set_pos(o->used_library, pos);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int get_pos(p_play o)

      Description: gets position

      Return: position in the file
      Example: position = pp->get_position(pp);

     *****************************************************************************/


   //get current pos
l_int get_pos(p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->get_pos(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int get_len_file(p_play o)

      Description: gets len of file

      Return: len of file
      Example: len_of_file = pp->get_len_file(pp);

     *****************************************************************************/


   //lenght of file
l_int get_len_file(p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->get_len_file(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_text     get_info(p_play o)

      Description: get info of file (string), you can free it with _free();

      Return: char * string;
      Example: l_text info = pp->get_info(pp);
               ...
               _free(info);

     *****************************************************************************/


   // get file format info
l_text     get_info(p_play o)
      {
      if (o->used_library)
         {
         return _strdup((o->used_library)->info);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int     get_time(p_play o)

      Description: gets current time in seconds

      Return: time in seconds
      Example: current_time = pp->get_time(pp);

     *****************************************************************************/


   // get current time in seconds

l_int     get_time(p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->get_time(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int     is_stereo(p_play o)

      Description: is the file stereo, or mono?

      Return: 1...stereo, 0...mono
      Example: file_stereo = pp->is_stereo(pp);

     *****************************************************************************/


l_int     is_stereo(p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->is_stereo(o->used_library);
         }
      };


     /**[txh]**********************************************************************

      Function: l_text   get_additional_info(p_play o)

      Description: gets additional info (use _free() to free it)

      Return: char *, l_text
      Example: l_text add_info = pp->get_additional_info(pp);

     *****************************************************************************/


l_text   get_additional_info(p_play o)
      {
      if (o->used_library)
         {
         return (o->used_library)->get_additional_info(o->used_library);
         }
      };

     /**[txh]**********************************************************************

      Function: l_int about_box(p_play o)

      Description: Displays About dialog for driver. Driver has to display box itself.
                   It does not have to be an msgbox - it could be a configuration dialog,
                   for example. Please note that under SFA Player 0.7, it's called by
                   choosing About Driver though, so some users might not know there are
                   configuration options there.

      Return: l_int
      Example: pp->about_box();

      *****************************************************************************/

l_int about_box(p_play o)
{
   if (o->used_library)
   {
      return((o->used_library)->about_box(o->used_library));
   }
}

l_int seal_volume = 255;
l_int count_player = 0;
l_int sound_input_installed = false;
l_int sound_installed = true;

     /**[txh]**********************************************************************

      Function: l_int get_sound_input_installed()

      Description:

      Return:  >1 if sound input is installed
      Example:

     *****************************************************************************/


l_int get_sound_input_installed()
{
return sound_input_installed;
}

     /**[txh]**********************************************************************

      Function: l_int get_sound_installed()

      Description:

      Return:  true if sound input is installed
      Example:

     *****************************************************************************/


l_int get_sound_installed()
{
return sound_installed;
}



     /**[txh]**********************************************************************

      Function: void inc_count_player()

      Description: If your player starts a file you have to call it.

      Return:
      Example:

     *****************************************************************************/


void inc_count_player()
{
 count_player++;
}

     /**[txh]**********************************************************************

      Function: void dec_count_player()

      Description: If your player stops playing a file you have to execute it.

      Return:
      Example:

     *****************************************************************************/


void dec_count_player()
{
 count_player--;
}

     /**[txh]**********************************************************************

      Function: l_int get_count_player()

      Description:

      Return: how many files are playing
      Example:

     *****************************************************************************/


l_int get_count_player()
{
 return count_player;
}

     /**[txh]**********************************************************************

      Function: l_int get_seal_volume()

      Description:

      Return: current volume (0...255)
      Example:

     *****************************************************************************/


l_int get_seal_volume()
{
return seal_volume;
}

     /**[txh]**********************************************************************

      Function: l_int set_seal_volume(l_int s_v)

      Description: you can set the sound volume (0...255)

      Return:
      Example:

     *****************************************************************************/


l_int set_seal_volume(l_int s_v)
{
if (s_v < 0) s_v = 0;
if (s_v > 255) s_v = 255;
seal_volume = s_v;
set_volume(seal_volume,seal_volume);
}


/*int  ff_walker(const char* path, const struct ffblk *ff)
     {



       if (!stricmp("dlx", get_extension(path)) && !strnicmp(get_filename(path), "sfa", 3))

       {

       if ( !run_file ((l_char *) path) )

                     seal_error(ERR_INFO, "%s\n\n%s", "Cannot run file :(", path);


       DEBUG_printf("\ndlxsound:");
       DEBUG_printf(" Loaded SFA driver:");
       DEBUG_printf((l_char *) path);
       DEBUG_printf("\n");



       }


       if (strcmp(ff->ff_name, "XXXXX") == 0)
         return 42;
       return 0;
}*/


void ini_sound ( void ) {

      p_soundformat_item k;
      l_text path = 0;
      t_rect r;

      sound_format_list = list_init(_malloc(sizeof(t_list)), &free_soundformat_item, 0);


      k = new_soundformat_item(                      _strdup("*"),
                                                     _strdup("All Files"),
                                                     _strdup("(c) Florian Xaver GNU GPL - virtual sound file"),
                                                     &st_init_file,
                                                     &st_play_file,
                                                     &st_poll_file,
                                                     &st_stop_file,
                                                     &st_pause_file,
                                                     &st_forward_file,
                                                     &st_rewind_file,
                                                     &st_set_pos,
                                                     &st_get_pos,
                                                     &st_get_len_file,
                                                     &st_get_time,
                                                     &st_is_stereo,
                                                     &st_get_additional_info,
                                                     &st_about_box
                                                     );




     sound_format_list->insert(sound_format_list, k);

      DEBUG_printf("Sound init: init sound...\n");

      /* reserve_voice is very important !!!!! (mod player)*/
      reserve_voices (32, -1);     // call this before install_sound if needed (for the mod player !!!)

      DEBUG_printf("Sound init: voices reserved.\n");
      DEBUG_printf("Sound init: Installing sound...");

      if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "") == -1)
          {
          sound_installed = false;
          seal_error(ERR_INFO, TXT_CANNOTINITSOUNDCARD, allegro_error);
          DEBUG_printf("SFA INIT ERROR :: Cannnot init sound card : %s\n",allegro_error);
          return;
          }

      DEBUG_printf("   sound installed!\n");
      DEBUG_printf("Sound input init:");

      DEBUG_printf("  installed");



      set_seal_volume(255);

      // setting volume from seal.ini
    //  seal_volume = *((unsigned int *)getini_fromfile ( "seal.ini", "sound", "volume" ));
    //  set_volume(seal_volume, seal_volume);

      DEBUG_printf("Sound init: volume set");


}
