/* Copyright (C) 1996,1997,1998,1999 by Salvador E. Tropea (SET),
   see copyrigh file for details */
#include <ceditint.h>

#ifdef SUP_MP3
/*****************************************************************************

I'm using a patched libamp because:

1) formats.c: wav_end ends with exit(0) Ugh!
2) audiolib.c: undefined TRACK... to save CPU and to get track of the
   position when writing to a file.

Old stuff:
Q: Why the sound quality is so poor? the same data sent to a file and played
with GRepVoc is FAR better.
A: Seems that Allegro streaming routines are crap (22KHz 8bits).
--> So then I contributed 16 bits mixing code to Allegro project ;-)))

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


#include <limits.h>
#include <stdio.h>

#include <allegro.h>
#include <libamp.h>
#include <mp3play.h>

extern "C" {
#include <getbits.h>
#include <audio.h>
#include <formats.h>
}


MP3Player mp3;

char MP3Player::Name[PATH_MAX]="";

char MP3Player::Stoped=1;
char MP3Player::Selected=0;
char MP3Player::SelectedIsLoaded=0;
char MP3Player::Paused=0;
char MP3Player::PlayingList=0;
char MP3Player::Converting=0;

char MP3Player::Title[31];
char MP3Player::Author[31];
char MP3Player::Album[35];
char MP3Player::Comment[31];
const char *MP3Player::Genre=0;
int  MP3Player::SampleRate=0;
int  MP3Player::BitRate=0;
const char *MP3Player::Mode="";
int  MP3Player::MPEGVer=0;
int  MP3Player::Layer=0;
int  MP3Player::TotalLen=0;
int  MP3Player::PausedPos=0;
char *(*MP3Player::GetNext)()=0;
void  (*MP3Player::EndOfList)()=0;
char MP3Player::FileToPlay[PATH_MAX]="";
int  MP3Player::Strategy=mp3UnBuffered;

static
const char *GenreStr[]={
"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop", // 0-7
"Jazz","Metal","New Age","Oldies","Other","Pop","R&B","Rap","Reggae","Rock",// 8-17
"Techno","Industrial","Alternative","Ska","Death Metal","Pranks",           // 18-23
"Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal","Jazz+Funk",        // 24-29
"Fusion","Trance","Classical","Instrumental","Acid","House","Game",         // 30-36
"Sound Clip","Gospel","Noise","Alt. Rock","Bass","Soul","Punk","Space",     // 37-44
"Meditative","Instrumental Pop","Instrumental Rock","Ethnic","Gothic",      // 45-49
"Darkwave","Techno-Industrial","Electronic","Pop-Folk","Eurodance","Dream", // 50-55
"Southern Rock","Comedy","Cult","Gangsta Rap","Top 40","Christian Rap",     // 56-61
"Pop/Funk","Jungle","Native American","Cabaret","New Wave","Psychedelic",   // 62-67
"Rave","Showtunes","Trailer","Lo-Fi","Tribal","Acid Punk","Acid Jazz",      // 63-74
"Polka","Retro","Musical","Rock & Roll","Hard Rock","Folk","Folk/Rock",     // 75-81
"National Folk","Swing","Fast-Fusion","Bebob","Latin","Revival","Celtic",   // 82-88
"Bluegrass","Avantgarde","Gothic Rock","Progressive Rock",                  // 89-92
"Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band","Chorus",        // 93-97
"Easy Listening","Acoustic","Humour","Speech","Chanson","Opera",            // 98-103
"Chamber Music","Sonata","Symphony","Booty Bass","Primus","Porn Groove",    // 104-109
"Satire","Slow Jam","Club","Tango","Samba","Folklore","Ballad",             // 110-116
"Power Ballad","Rhythmic Soul","Freestyle","Duet","Punk Rock","Drum Solo",  // 117-122
"Acapella","Euro-House","Dance Hall","Goa","Drum & Bass","Club-House",      // 123-128
"Hardcore","Terror","Indie","BritPop","Negerpunk","Polsk punk","Beat",      // 129-135
"Christian Gangsta Rap","Heavy Metal","Black Metal","Crossover",            // 136-139
"Contemporary Christian","Christian Rock"                                   // 140-141
};

const int maxKnownGenre=sizeof(GenreStr)/sizeof(char *);

void MP3Player::SelectNewFile(char *fileName)
{
 strcpy(Name,fileName);
 Selected=1;
 SelectedIsLoaded=0;
}

extern struct AUDIO_HEADER amp_cur_header;

// Returns 1 if no file were selected, 2 if the file was loaded, 3 if the file
// was allready loaded and just did a play
int MP3Player::PlaySelectedFile()
{
 if (!Selected)
    return 1;

 int ret;
 PlayingList=0;

 if (SelectedIsLoaded)
   {
    replay_amp();
    Stoped=0;
    ret=3;
   }
 else
   {
    strcpy(FileToPlay,Name);
    PlayFileToPlay();
    SelectedIsLoaded=1;
    ret=2;
   }
 return ret;
}

int MP3Player::ConvertSelectedFile(char *name)
{
 if (!Selected)
    return 1;

 Converting=1;
 PlayingList=0;
 strcpy(FileToPlay,Name);
 PlayFileToPlay(name);

 return 2;
}


void MP3Player::PlayFileToPlay(char *out)
{
 long fileLen=GetMP3Info();

 if (out)
   {
    out_file=fopen(out,"wb");
    A_AUDIO_PLAY=FALSE;
    A_WRITE_TO_FILE=TRUE;
    A_FORMAT_WAVE=TRUE;
   }
 else
   {
    A_AUDIO_PLAY=TRUE;
    A_WRITE_TO_FILE=FALSE;
   }
 load_amp(FileToPlay,0);

 // Fill the information fields with the data from the header
 SampleRate=t_sampling_frequency[amp_cur_header.ID][amp_cur_header.sampling_frequency];
 BitRate=t_bitrate[amp_cur_header.ID][3-amp_cur_header.layer][amp_cur_header.bitrate_index];
 Mode=amp_cur_header.mode==3 ? "mono" : "stereo";
 MPEGVer=amp_cur_header.ID==1 ? 1 : 2;
 Layer=4-amp_cur_header.layer;
 TotalLen=(int)(fileLen/(BitRate*1000.0)*8.0);

 Stoped=0;
}

void MP3Player::StartPlayList(char *(*aGetNext)(), void (*aEndOfList)())
{
 GetNext=aGetNext;
 EndOfList=aEndOfList;
 PlayingList=1;
 PlayNext();
}

void MP3Player::PlayNext()
{
 if (!PlayingList)
    return;
 char *next=GetNext();
 if (!next)
   {
    Stoped=1;
    PlayingList=0;
    EndOfList();
   }
 else
   {
    strcpy(FileToPlay,next);
    PlayFileToPlay();
   }
}

void MP3Player::StopPlayList()
{
 Stop();
 PlayingList=0;
}

long MP3Player::GetMP3Info(void)
{
 FILE *f;
 char buffer[128];
 long ret;

 f=fopen(FileToPlay,"rb");
 if (!f)
   {
    *Title=0;
    *Author=0;
    *Album=0;
    *Comment=0;
    Genre="";
    return 0;
   }
 fseek(f,-128,SEEK_END);
 fread(buffer,128,1,f);
 ret=ftell(f);
 if (buffer[0]=='T' && buffer[1]=='A' && buffer[2]=='G')
   {
    memcpy(Title,buffer+3,30);
    Title[30]=0;
    memcpy(Author,buffer+33,30);
    Author[30]=0;
    memcpy(Album,buffer+63,34); // Plus year
    Album[34]=0;
    memcpy(Comment,buffer+97,30);
    Comment[30]=0;
    if (((unsigned char)buffer[127])>=maxKnownGenre)
       Genre=_("Unknown");
    else
       Genre=GenreStr[(unsigned char)buffer[127]];
    ret-=128;
   }
 else
   {
    int l=strlen(FileToPlay);
    if (l>30)
      {
       memcpy(Title,FileToPlay+(l-30),30);
       Title[0]=Title[1]=Title[2]='.';
       Title[30]=0;
      }
    else
      {
       memcpy(Title,FileToPlay,l);
       Title[l]=0;
      }
    *Author=0;
    *Album=0;
    *Comment=0;
   }
 fclose(f);

 return ret;
}

void MP3Player::Stop()
{
 stop_amp();
 if (A_WRITE_TO_FILE)
   {
    A_AUDIO_PLAY=TRUE;
    A_WRITE_TO_FILE=FALSE;
    wav_end(&amp_cur_header);
    fclose(out_file);
   }
 Stoped=1;
 Paused=0;
 Converting=0;
}

int MP3Player::Poll()
{
 if (!Stoped)
   {
    int ret=Strategy==mp3UnBuffered ? poll_amp() : run_amp();
    if (ret<0)
      {
       if (PlayingList)
         {
          PlayNext();
          if (Stoped)
             return 4;
          return 3;
         }
       Stoped=1;
       Converting=0;
       return 2;
      }
    return 1;
   }
 return 0;
}

int MP3Player::Init()
{
 allegro_init();
 if (install_sound(DIGI_AUTODETECT,MIDI_NONE,NULL))
   {
    printf("Unable to install Allegro sound driver\n");
    return 1;
   }
 install_amp();

 set_volume(255,-1);
 amp_reverse_phase=1;
 return 0;
}

void MP3Player::deInit()
{
 unload_amp();
 remove_sound();
}

int MP3Player::GetTime()
{
 return amp_time;
}

void MP3Player::FFwd()
{
 if (!Converting && !Stoped)
    seek_amp_rel(4*amp_samprat/amp_pollsize); /* seek 4 seconds */
}

void MP3Player::Rew()
{
 if (!Converting && !Stoped)
    seek_amp_rel(-4*amp_samprat/amp_pollsize); /* seek 4 seconds */
}

void MP3Player::TogglePause()
{
 if (!Converting && (!Stoped || Paused))
   {
    if (Paused)
      {
       Paused=0;
       //PlaySelectedFile();
       PlayFileToPlay();
       seek_amp_abs(PausedPos);
      }
    else
      {
       PausedPos=amp_frame;
       Stop();
       Paused=1;
      }
   }
}

void MP3Player::Pause()
{
 if (!Stoped && !Converting)
   {
    Stop();
    Paused=1; // After calling stop because stop resets Paused
    PausedPos=amp_frame;
   }
}

void MP3Player::SeekAbs(int seconds)
{
 seek_amp_abs(seconds*amp_samprat/amp_pollsize);
}
#endif
