#include <stdlib.h>
#include <getopt.h>
#include <strings.h>
#include <typeinfo>
#include <string>
#include <fstream>

#include <vdr/menuitems.h>
#include <vdr/menu.h>
#include <vdr/plugin.h>
#include <vdr/osd.h>
#include <vdr/interface.h>
#include <vdr/skins.h>

#include "mp3control.h"
#include "common.h"
#include "skin.h"
#include "setup.h"
#include "setup-mp3.h"
#include "data-mp3.h"
#include "player-mp3.h"
#include "menu.h"
#include "decoder.h"
#include "decoder-mp3.h"
#include "i18n.h"
#include "stream.h"
#include "vars.h"
#include "config.h"

#include "symbols/shutdown.xpm"
#include "symbols/shuffle.xpm"
#include "symbols/loop.xpm"
#include "symbols/stop.xpm"
#include "symbols/play.xpm"
#include "symbols/pause.xpm"
#include "symbols/copy.xpm"
#include "symbols/text.xpm"
#include "symbols/rec.xpm"

#include "symbols/delstar.xpm"
#include "symbols/rate00.xpm"
#include "symbols/rate05.xpm"
#include "symbols/rate10.xpm"
#include "symbols/rate15.xpm"
#include "symbols/rate20.xpm"
#include "symbols/rate25.xpm"
#include "symbols/rate30.xpm"
#include "symbols/rate35.xpm"
#include "symbols/rate40.xpm"
#include "symbols/rate45.xpm"
#include "symbols/rate50.xpm"

#include "symbols/vol.xpm"
#include "symbols/mute.xpm"


#ifdef DEBUG
#include <mad.h>
#endif

#define eDvbColor int
#define INLINE

#define CELLWIDTH (600 / 4) -1)




cBitmap cMP3Control::bmShutdown(shutdown_xpm);
cBitmap cMP3Control::bmShuffle(shuffle_xpm);
cBitmap cMP3Control::bmLoop(loop_xpm);
cBitmap cMP3Control::bmStop(stop_xpm);
cBitmap cMP3Control::bmPlay(play_xpm);
cBitmap cMP3Control::bmPause(pause_xpm);
cBitmap cMP3Control::bmCopy(copy_xpm);
cBitmap cMP3Control::bmText(text_xpm);
cBitmap cMP3Control::bmRec(rec_xpm);

cBitmap cMP3Control::bmDelStar(delstar_xpm);
cBitmap cMP3Control::bmRate00(rate00_xpm);
cBitmap cMP3Control::bmRate05(rate05_xpm);
cBitmap cMP3Control::bmRate10(rate10_xpm);
cBitmap cMP3Control::bmRate15(rate15_xpm);
cBitmap cMP3Control::bmRate20(rate20_xpm);
cBitmap cMP3Control::bmRate25(rate25_xpm);
cBitmap cMP3Control::bmRate30(rate30_xpm);
cBitmap cMP3Control::bmRate35(rate35_xpm);
cBitmap cMP3Control::bmRate40(rate40_xpm);
cBitmap cMP3Control::bmRate45(rate45_xpm);
cBitmap cMP3Control::bmRate50(rate50_xpm);

cBitmap cMP3Control::bmVol(vol_xpm);
cBitmap cMP3Control::bmMute(mute_xpm);


// --- cMP3Control -------------------------------------------------------------
cMP3Control::cMP3Control(void)
:cControl(player=new cMP3Player)
,cmdMenu(NULL),rateMenu(NULL),trackList(NULL)
{
  jumpactive=false;
  skipfwd=skiprew=visible=selecting=refresh=muted=showmessage=false;
  ShowSA=MP3Setup.EnableVis;
  showbuttons=0;  
  lastkeytime=number=vol=laststatus=0;
  visualization=channelsSA=bandsSA=cw=x1=depth=rows=0;
  lastMode=0;
  framesPerSecond=SecondsToFrames(1);
  if(!osd) osd=0;

  pFontUser       = MusicConfig.GetFont(FONT_TOP);
  pFontText       = MusicConfig.GetFont(FONT_STATUS);
  pFontList       = MusicConfig.GetFont(FONT_LIST);
  pFontListActive = MusicConfig.GetFont(FONT_LISTACTIVE);
  pFontTitle      = MusicConfig.GetFont(FONT_TITLE);
  pFontInfo       = MusicConfig.GetFont(FONT_INFO);
  pFontCommands   = MusicConfig.GetFont(FONT_BOTTOM);

  MP3Setup.EnableShutDown = 0;

#if APIVERSNUM >= 10338
  cStatus::MsgReplaying(this,"MP3",0,true);
#else
  cStatus::MsgReplaying(this,"MP3");
#endif
  coversize = 0;
}

cMP3Control::~cMP3Control()
{
#ifdef HAVE_TUNED_GTFT
    cPlugin *graphtft=cPluginManager::GetPlugin("graphtft");
    if(graphtft) cStatus::MsgImageFile("");
#else
    cPlugin *graphtft=cPluginManager::GetPlugin("graphtft");
    if(graphtft) graphtft->SetupParse("CoverImage", "");
#endif

  if(cmdMenu) {delete cmdMenu;}
  cmdMenu = NULL;

  if(rateMenu) {delete rateMenu;}
  rateMenu = NULL;

  if(trackList) {delete trackList;}
  trackList = NULL;

  delete lastMode;
  Hide();
  InfoCache.Save(true);
  Stop();
}

void cMP3Control::Stop(void)
{
  if(MP3Setup.RecordStream) {cmdMenu->StopRecord();}
#if APIVERSNUM >= 10338
  cStatus::MsgReplaying(this,0,0,false);
#else
  cStatus::MsgReplaying(this,0);
#endif
  delete player; player=0;
  mgr->Halt();
  mgr->Flush(); //XXX remove later
}

bool cMP3Control::SetPlayList(cPlayList *plist)
{
  bool res;
  char *buff;
  
  cControl *control=cControl::Control();

  // is there a running MP3 player?
  if(control && typeid(*control)==typeid(cMP3Control)) {
    // add songs to running playlist
    mgr->Add(plist);
    res=true;
    }    
  else {
    mgr->Flush();
    mgr->Add(plist);
    cControl::Launch(new cMP3Control);
    res=false;
  }

  // Save List to @current.m3u
  asprintf(&buff, "%s/%s", BaseSource, "@current.m3u");

  if(mgr->SaveList(buff, false)) {
    d(printf("music: ctrl: refreshed playlist: %s\n", buff));
    }
  else
    d(printf("music: ctrl: couldn't refresh current playlist"));

  free(buff);

  delete plist;
  return res;
}


void cMP3Control::Hide(void)
{
  if (cmdMenu) {
    delete cmdMenu;
    cmdMenu=NULL;
    }

  if (rateMenu) {
    delete rateMenu;
    rateMenu=NULL;
    }

  if (trackList) {
    delete trackList;
    trackList=NULL;
    }

  if(visible) {
    delete osd; osd=0;
#if VDRVERSNUM >= 10500
    visible = false;
    SetNeedsFastResponse(visible);
#else    
    needsFastResponse=false;
    visible=false;
#endif
    }
}


void cMP3Control::LoadCover(void)
{
  int bmpcolors=14;
  int w1=120;
  int h1=120;
  int g1=0;
  int g2=0;


/*
  if(Connecting) {
    std::string c_cover;
    c_cover = config;
    c_cover = c_cover + "/themes/defaultcover";
    c_cover = c_cover + "/music-stream-connecting.png";
  
    strncpy(coverpicture, c_cover.c_str(), sizeof(coverpicture));
  }    
*/       
  if (coverpicture == NULL)
    d(printf("music: ctrl: Oops cant load coverpicture : %s\n",coverpicture))
  else {
    fw=6;
    fh=26;

    if(MP3Setup.showcoveronly) {
      if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode) {
        bmpcolors = 14;
        w1 = 264;
        h1 = 256;
        g1 = Setup.OSDWidth  /2 - 126;
        g2 = Setup.OSDHeight /2 - 126;
        }
      else {	
        switch(coversize) {
          case 0:
            bmpcolors = 252;
            w1 = 120;
            h1 = 120;
            osd->DrawRectangle(g1 , g2, w1 -1, h1 -1, clrBlack);
            osd->DrawText( g1, h1 -fh, "Load...", clrWhite, clrBlack, pFontText, w1, pFontText->Height(), taCenter);
            Flush();
            break;  
          case 1:  
            bmpcolors = 252;
            w1 = 274;
            h1 = 274;
            osd->DrawRectangle(g1 , g2, w1 -1, h1 -1, clrBlack);
            osd->DrawText( g1, h1 -fh, "Load...", clrWhite, clrBlack,  pFontText, w1, pFontText->Height(), taCenter);
            Flush();
            break;
          case 2:
            bmpcolors = 252;
            w1 = 300;
            h1 = 256;
            osd->DrawRectangle(g1 , g2, w1 -1, h1 -1, clrBlack);
            osd->DrawText( g1, h1 -fh, "Load...", clrWhite, clrBlack, pFontText, w1, pFontText->Height(), taCenter);
            Flush();
            break;
          case 3:
            bmpcolors = 252;
            w1 = 720;
            h1 = 576;
            osd->DrawRectangle(g1 , g2, w1 -1, h1 -1, clrBlack);
            osd->DrawText( g1, h1 -fh, "Load...", clrWhite, clrBlack, pFontText, w1, pFontText->Height(), taCenter);
            Flush();
            break;
        }	        
      }

    }
    else {
      w1 = 128;
      h1 = 128;
    }

    cMP3Bitmap *bmp;

    if((bmp = cMP3Bitmap::Load(coverpicture, imgalpha, h1, w1, bmpcolors)) !=NULL) {
      if(MP3Setup.showcoveronly) {
        osd->DrawRectangle( g1, g2, w1 -1, h1 -1, clrTransparent);
        osd->DrawBitmap( g1, g2, bmp->Get(), clrTransparent, clrTransparent, true);
        }
      else {
        osd->DrawRectangle(0,  2*fh +1,  cw -1 , 2*fh +144 ,clrBG);
        osd->DrawRectangle(fh, 2*fh +1,  cw -1 , 2*fh +144 ,clrCoverBG);
        osd->DrawEllipse(  fh          , 2*fh +1             , fh +10 , 2*fh +11     , clrBG , -2); // oben links
        osd->DrawEllipse(  (cw -1) -10 , 2*fh +1             , cw -1  , 2*fh +11     , clrBG, -1);  // oben rechts
        osd->DrawEllipse(  fh          , 2*fh +134 , fh +10 , 2*fh +144 , clrBG , -3); // unten links
        osd->DrawEllipse(  (cw -1) -10 , 2*fh +134 , cw -1  , 2*fh +144 , clrBG, -4);  // unten rechts
        osd->DrawBitmap(fh +7 , 2*fh +8, bmp->Get(), clrTransparent, clrTransparent, true);
      }
    }


    // TODO: FIX NOT SHOWING VISCOVER, only workaround here
    if(!MP3Setup.EnableVis) {
#ifdef HAVE_TUNED_GTFT
      cPlugin *graphtft=cPluginManager::GetPlugin("graphtft");
      if(graphtft) cStatus::MsgImageFile(coverpicture ? coverpicture:"");
#else
      cPlugin *graphtft=cPluginManager::GetPlugin("graphtft");
      if(graphtft) graphtft->SetupParse("CoverImage", coverpicture ? coverpicture:"");
#endif
    }

  }
  MP3Setup.CanLoadCover = 0;
}


void cMP3Control::ShowSAOnly(bool open)
{
  int l1=Setup.OSDWidth /2 - 136;
  int t1=Setup.OSDHeight /2 -136;
  int sadepth=4;

  if(!cOsd::IsOpen()) {
    if(!visible && !open) {
      open=true;
    }
  }

  if(!visible && open) {

    if (MP3Skin.isMpeg == 1) {
        MP3Skin.saonly = true;
		MP3Skin.reloadmpeg = true;
//		player->CheckMpeg(true);
    }
	
    visualization = MP3Setup.Visualization; 
    channelsSA    = MP3Setup.ChannelsSA;
    bandsSA       = MP3Setup.BandsSA;
    clrCoverBar   = MP3Setup.clrCoverBar;

    imgalpha = 255;


    osd=cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
    if(!osd) return;

    tArea Area[] = {{ l1, t1, l1 + 271 , t1 + 271, sadepth}, };
    eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(tArea));
    if (result == oeOk) {
      osd->SetAreas(Area, sizeof(Area) / sizeof(tArea));
      }
    else  {
      const char *errormsg = NULL;
      switch (result) {
        case oeTooManyAreas:
	  errormsg = "Too many OSD areas"; break;
	case oeTooManyColors:
	  errormsg = "Too many colors"; break;
	case oeBppNotSupported:
	  errormsg = "Depth not supported"; break;	
	case oeAreasOverlap:
	  errormsg = "Areas are overlapped"; break;
	case oeWrongAlignment:
	  errormsg = "Areas not correctly aligned"; break;
	case oeOutOfMemory:
	  errormsg = "OSD memory overflow"; break;
	case oeUnknown:
          errormsg = "Unknown OSD error"; break;
	default:
	break;
        }	
      esyslog("music: ctrl: ERROR! osd open failed! can't handle areas (%d)-%s\n", result, errormsg);
      if(osd){ delete osd; osd=0;}

      return;
    }

    mgr->playnow = false;
    player->LoadImage(Songname, NULL, false);
    MP3Setup.CanLoadCover = 0;

#if VDRVERSNUM >= 10500
    visible = true;
    SetNeedsFastResponse(visible);
#else      
    needsFastResponse=true;
    visible=true;
#endif

    delete lastMode; lastMode=0;
  }

  cMP3PlayInfo *mode=new cMP3PlayInfo;
  bool valid=mgr->Info(-1,mode);
  bool changed=(!lastMode || mode->Hash!=lastMode->Hash || refresh);
  char buf[256];

  if(valid) { // send progress to status monitor
    if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) {
      snprintf(buf,sizeof(buf),mode->Artist[0]?"[%c%c] (%d/%d) %s - %s":"[%c%c] (%d/%d) %s",
               mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,mode->Title,mode->Artist);
#if APIVERSNUM >= 10338
      cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true);
#else
      cStatus::MsgReplaying(this,buf);
#endif
    }
  }

  if(visible) { // refresh the OSD display
    flush=false;

    if(MP3Setup.CanLoadCover) {
      LoadCover();
      flush = true;
    }


    // Spectrum Analyzer visualization begins here...
    if ( MP3Setup.EnableVis && ShowSA)	{

      if (cPluginManager::CallFirstService(SPAN_GET_BAR_HEIGHTS_ID, NULL))	{
        Span_GetBarHeights_v1_0 GetBarHeights;
        unsigned int bar;
        unsigned int *barHeights             = new unsigned int[bandsSA];
        unsigned int *barHeightsLeftChannel  = new unsigned int[bandsSA];
        unsigned int *barHeightsRightChannel = new unsigned int[bandsSA];
        unsigned int volumeLeftChannel;
        unsigned int volumeRightChannel;
        unsigned int volumeBothChannels;
        unsigned int *barPeaksBothChannels   = new unsigned int[bandsSA];
        unsigned int *barPeaksLeftChannel    = new unsigned int[bandsSA];
        unsigned int *barPeaksRightChannel   = new unsigned int[bandsSA];
 								
        GetBarHeights.bands 		          = bandsSA;
        GetBarHeights.barHeights		  = barHeights;
        GetBarHeights.barHeightsLeftChannel       = barHeightsLeftChannel;
        GetBarHeights.barHeightsRightChannel      = barHeightsRightChannel;
        GetBarHeights.volumeLeftChannel	          = &volumeLeftChannel;
        GetBarHeights.volumeRightChannel	  = &volumeRightChannel;
        GetBarHeights.volumeBothChannels	  = &volumeBothChannels;
        GetBarHeights.name			  = "Music";
        GetBarHeights.falloff		          = MP3Setup.FalloffSA;
        GetBarHeights.barPeaksBothChannels	  = barPeaksBothChannels;
        GetBarHeights.barPeaksLeftChannel	  = barPeaksLeftChannel;
        GetBarHeights.barPeaksRightChannel	  = barPeaksRightChannel;

        if ( cPluginManager::CallFirstService(SPAN_GET_BAR_HEIGHTS_ID, &GetBarHeights )) {

          int i;
          int barPeakHeight = 3;
          int barPeak       = 0;
          int barWidth      = 0;
          int coverleft     = l1 +13;
          int coverright    = l1 + 269;
          int covertop      = t1 +13;
          int coverbottom   = t1 + 260;

          if(player !=NULL) {
            switch(visualization) {

              case 1:
                LoadCover();
                for ( i=0; i < bandsSA; i++ ) {

                  barWidth = 256/bandsSA;
                  bar      = (barHeights[i]*248)/100;
                  barPeak  = barPeaksBothChannels[i]*248/100;
                  if(barPeak > 0) {
                    osd->DrawRectangle(coverleft +(i*barWidth) , covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 248 - barPeak -barPeakHeight, clrCoverBar);
                    osd->DrawRectangle(coverleft +(i*barWidth) , covertop +248 -barPeak +1, coverleft + (i*barWidth) +barWidth -1, covertop +248  - bar, clrCoverBar);
                    }
		  else {
		    osd->DrawRectangle(coverleft +(i*barWidth) , covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 248 - bar, clrCoverBar);
		  }  
                }
		break;

	      case 2:
                LoadCover();
 	        for ( i=0; i < bandsSA; i++ ) {
 	          barWidth = 128/bandsSA;
		  bar = barHeightsLeftChannel[i]*246/100;
		  barPeak = barPeaksLeftChannel[i]*246/100;
		  if(barPeak > 0) {
                    osd->DrawRectangle(coverleft +(i*barWidth) -2   , covertop, coverleft +(i*barWidth) +barWidth -1    , covertop + 246 - barPeak -barPeakHeight, clrCoverBar);
                    osd->DrawRectangle(coverleft +(i*barWidth) -2   , covertop + 246 -barPeak +1, coverleft +(i*barWidth) +barWidth -1    , covertop + 246 - bar, clrCoverBar);
		    }
		  else {
 		    osd->DrawRectangle(coverleft +(i*barWidth) -2   , covertop, coverleft +(i*barWidth) +barWidth -1    , covertop + 246 - bar, clrCoverBar);
                  }		       	 
	          bar = barHeightsRightChannel[i]*246/100;
                  barPeak = barPeaksRightChannel[i]*246/100;
		  if( barPeak > 0) {
 		    osd->DrawRectangle(coverleft + 130 +(i*barWidth), covertop, coverleft + 130 +(i*barWidth) +barWidth -1, covertop + 246 - barPeak -barPeakHeight, clrCoverBar);
 		    osd->DrawRectangle(coverleft + 130 +(i*barWidth), covertop + 246 -barPeak +1, coverleft + 130 +(i*barWidth) +barWidth -1, covertop + 246 - bar, clrCoverBar);
		    }
		  else {
     		    osd->DrawRectangle(coverleft + 130 +(i*barWidth), covertop, coverleft + 130 +(i*barWidth) +barWidth -1, covertop + 246 - bar, clrCoverBar);
		  }
                }
		break;

              case 3:
                LoadCover();
 	        for ( i=0; i < bandsSA; i++ ) {
 	          barWidth = 62;
	          bar      = (volumeLeftChannel*246)/100;
		  osd->DrawRectangle(coverleft +30 , covertop, coverleft + 30 + barWidth , covertop + 246 - bar,  clrCoverBar);
	          bar      = (volumeRightChannel*246)/100;
		  osd->DrawRectangle(coverleft +164 , covertop, coverleft + 164 + barWidth , covertop + 246 - bar, clrCoverBar);
                }
                break;

	      case 4:
                LoadCover();
 	        for ( i=0; i < bandsSA; i++ ) {
 	          barWidth = 8;
 	          bar = barHeightsLeftChannel[i]*246/100;
 		  osd->DrawRectangle(coverleft                , coverbottom -(i*barWidth) - barWidth , coverleft + 127 -(bar/2), coverbottom -(i*barWidth) -1, clrCoverBar);
 		  bar = barHeightsRightChannel[i]*246/100;
 		  osd->DrawRectangle(coverright - 127 +(bar/2), coverbottom -(i*barWidth) - barWidth , coverright              , coverbottom -(i*barWidth) -1, clrCoverBar);
                }
                // Ausgleich
                osd->DrawRectangle(coverleft , coverbottom -1 , coverright              , coverbottom +1, clrCoverBar);

		break;

	      case 5:
                LoadCover();
 	        for ( i=0; i < bandsSA; i++ ) {
	          barWidth = 2;
	          bar = barHeightsLeftChannel[i]*246/100;
	          osd->DrawRectangle(coverleft                , coverbottom -(i*barWidth) - barWidth, coverleft + 127 -(bar/2), coverbottom -(i*barWidth) -1, clrCoverBar);
	          bar = barHeightsRightChannel[i]*246/100;
	          osd->DrawRectangle(coverright - 127 +(bar/2), coverbottom -(i*barWidth) - barWidth, coverright              , coverbottom -(i*barWidth) -1, clrCoverBar);
                }
                // Ausgleich
                osd->DrawRectangle(coverleft , covertop       , coverright        , covertop +1   , clrCoverBar);
                osd->DrawRectangle(coverleft , coverbottom -1 , coverright        , coverbottom +1, clrCoverBar);
		break;

	      case 6:
                LoadCover();
 	        for ( i=0; i < bandsSA; i++ ) {
                  barWidth = 256/bandsSA;
	          bar      = (barHeights[i]*246)/100;
                  barPeak  = barPeaksBothChannels[i]*246/100;
		  if(barPeak > 0) {
		    osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 246 - barPeak -barPeakHeight, clrCoverBar);
		    osd->DrawRectangle(coverleft +(i*barWidth), covertop +246 -barPeak +1, coverleft + (i*barWidth) +barWidth -1, coverbottom + 3, clrCoverBar);
                    }
		  else {
		    osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, coverbottom + 3, clrCoverBar);
		  }  
                }
		break;


              case 7:
                LoadCover();
                for ( i=0; i < bandsSA; i++ ) {
                  barWidth = 256/bandsSA;
                  bar      = (barHeights[i]*246)/100;
                  osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop +246 -bar, clrCoverBar);
                  osd->DrawRectangle(coverleft +(i*barWidth), covertop + 246 -bar +4, coverleft + (i*barWidth) +barWidth -1, coverbottom +3, clrCoverBar);
                 }

                break;

              default: break;
	    }
          }

          flush = true;
        }
	
        delete [] barHeights;
        delete [] barHeightsLeftChannel;
        delete [] barHeightsRightChannel;
        delete [] barPeaksBothChannels;
        delete [] barPeaksLeftChannel;
        delete [] barPeaksRightChannel;
      }
      else {
        osd->DrawRectangle(l1 + 13 , t1 + 13, l1 + 269, t1 + 260, clrCoverBar);
        flush = true;
      }
    }
    // SA ends here.......

    if(flush) Flush();
  }

  delete lastMode; lastMode=mode;
  refresh = false;

}      


void cMP3Control::ShowCoverOnly(bool open)
{

  int w2=119;
  int h2=119;
  int x =0;
  int y =0;
  int depths=8;

  if(!cOsd::IsOpen()) {
    if(!visible && !open) {
      open=true;
    }
  }

  

  if(!visible && open) {

    x = Setup.OSDLeft;
	y = Setup.OSDTop;
  
    coversize=MP3Setup.Coversize;

    switch(coversize) {
      case 0:
      depths = 8;
	  w2 = 119;
	  h2 = 119;
	break;  
      case 1:  
	  depths = 8;
	  w2 = 273;
	  h2 = 273;
	break;
      case 2:  
	  depths = 8;
	  w2 = 299;
	  h2 = 255;
	break;
      case 3:
	  depths = 8;
	  w2 = 720;
	  h2 = 576;
      x  = 0;
	  y  = 0;
    break;
    }	        

    osd=cOsdProvider::NewOsd(x , y);
    if(!osd) return;

    tArea Area[] = {{ 0, 0, w2 -1, h2 -1, depths}, };
    eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(tArea));
    if (result == oeOk) {
      osd->SetAreas(Area, sizeof(Area) / sizeof(tArea));
      }
    else  {
      const char *errormsg = NULL;
      switch (result) {
        case oeTooManyAreas:
	  errormsg = "Too many OSD areas"; break;
	case oeTooManyColors:
	  errormsg = "Too many colors"; break;
	case oeBppNotSupported:
	  errormsg = "Depth not supported"; break;	
	case oeAreasOverlap:
	  errormsg = "Areas are overlapped"; break;
	case oeWrongAlignment:
	  errormsg = "Areas not correctly aligned"; break;
	case oeOutOfMemory:
	  errormsg = "OSD memory overflow"; break;
	case oeUnknown:
          errormsg = "Unknown OSD error"; break;
	default:
	break;
        }	
      esyslog("music: ctrl: ERROR! osd open failed! can't handle areas (%d)-%s\n", result, errormsg);
      if(osd){ delete osd; osd=0;}

      return;
    }

    mgr->playnow = false;

    osd->DrawRectangle(0 , 0, w2 -1, h2 -1, clrTransparent); // Cover

    visible=true;

    force = true;

    delete lastMode; lastMode=0;
  }

  cMP3PlayInfo *mode=new cMP3PlayInfo;
  bool valid=mgr->Info(-1,mode);
  bool changed=(!lastMode || mode->Hash!=lastMode->Hash || refresh);
  char buf[256];

  if(valid) { // send progress to status monitor
    if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) {
      snprintf(buf,sizeof(buf),mode->Artist[0]?"[%c%c] (%d/%d) %s - %s":"[%c%c] (%d/%d) %s",
               mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,mode->Title,mode->Artist);
#if APIVERSNUM >= 10338
      cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true);
#else
      cStatus::MsgReplaying(this,buf);
#endif
    }
  }

  if(visible) { // refresh the OSD display
    flush=false;


    if ( mode->Filename && !(strcmp(mode->Filename,lastfile) ==0) || force) {
      printf("ShowCoverOnly: Force the Display\n");
  	  strncpy(lastfile, mode->Filename,sizeof(lastfile));
      force = false;

      player->LoadImage(mode->Filename, mode->Artist, true);
      LoadCover();
      flush = true;
    }
    if(flush) Flush();
  }

#if VDRVERSNUM >= 10500
  SetNeedsFastResponse(false);
#else  
  needsFastResponse=false;
#endif
  delete lastMode; lastMode=mode;
  refresh = false;

}      



void cMP3Control::Flush(void)
{
  if(osd) osd->Flush();
}


void cMP3Control::ShowHelpButtons(int ShowButtons) {
  int tab;
  tab = Setup.OSDWidth/4;
  showbuttons = ShowButtons;

  switch(showbuttons) {
    case 0:
        osd->DrawEllipse(      14        , 6*fh +(rows *22) +261 , 26         , 6*fh +(rows *22) +274 , clrStatusRed    , 0);
        osd->DrawEllipse(      tab   +8  , 6*fh +(rows *22) +261 , tab + 20   , 6*fh +(rows *22) +274 , clrStatusGreen  , 0);
        osd->DrawEllipse(      2*tab +8  , 6*fh +(rows *22) +261 , 2*tab + 20 , 6*fh +(rows *22) +274 , clrStatusYellow , 0);
        osd->DrawEllipse(      3*tab +8  , 6*fh +(rows *22) +261 , 3*tab + 20 , 6*fh +(rows *22) +274 , clrStatusBlue   , 0);

        if(MP3Setup.RatingFirst)
          osd->DrawText(       34        , 6*fh +(rows *22) +255 , tr("Rating")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        else
          osd->DrawText(       34        , 6*fh +(rows *22) +255 , tr("Commands") , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        osd->DrawText(         tab   +28 , 6*fh +(rows *22) +255 , tr("Track-")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        osd->DrawText(         2*tab +28 , 6*fh +(rows *22) +255 , tr("Track+")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        osd->DrawText(         3*tab +28 , 6*fh +(rows *22) +255 , tr("More..")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
      break;
    case 1:       
        osd->DrawEllipse(      14        , 6*fh +(rows *22) +261 ,  26        , 6*fh +(rows *22) +274 , clrStatusRed    , 0);
        osd->DrawEllipse(      tab   +8  , 6*fh +(rows *22) +261 , tab + 20   , 6*fh +(rows *22) +274 , clrStatusGreen  , 0);
        osd->DrawEllipse(      2*tab +8  , 6*fh +(rows *22) +261 , 2*tab + 20 , 6*fh +(rows *22) +274 , clrStatusYellow , 0);
        osd->DrawEllipse(      3*tab +8  , 6*fh +(rows *22) +261 , 3*tab + 20 , 6*fh +(rows *22) +274 , clrStatusBlue   , 0);

        if(MP3Setup.RatingFirst)
          osd->DrawText(       34        , 6*fh +(rows *22) +255 , tr("Commands") , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        else
          osd->DrawText(       34        , 6*fh +(rows *22) +255 , tr("Rating")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        osd->DrawText(         tab   +28 , 6*fh +(rows *22) +255 , tr("Cover")    , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        osd->DrawText(         2*tab +28 , 6*fh +(rows *22) +255 , tr("Jump")     , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        if(MP3Setup.AdminMode)
          osd->DrawText(       3*tab +28 , 6*fh +(rows *22) +255 , tr("More..")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
        else  
          osd->DrawText(       3*tab +28 , 6*fh +(rows *22) +255 , tr("Parent")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
      break;
    case 2:  	
        osd->DrawEllipse(      14        , 6*fh +(rows *22) +261 ,  26        , 6*fh +(rows *22) +274 , clrStatusRed    , 0);
        osd->DrawEllipse(      tab   +8  , 6*fh +(rows *22) +261 , tab + 20   , 6*fh +(rows *22) +274 , clrStatusGreen  , 0);
	    osd->DrawEllipse(      2*tab +8  , 6*fh +(rows *22) +261 , 2*tab +20  , 6*fh +(rows *22) +274 , clrStatusYellow , 0);
	    osd->DrawEllipse(      3*tab +8  , 6*fh +(rows *22) +261 , 3*tab + 20 , 6*fh +(rows *22) +274 , clrStatusBlue   , 0);

        osd->DrawText(         34        , 6*fh +(rows *22) +255 , tr("Delete") , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         tab   +28 , 6*fh +(rows *22) +255 , tr("Clear")  , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         2*tab +28 , 6*fh +(rows *22) +255 , tr("Copy")   , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         3*tab +28 , 6*fh +(rows *22) +255 , tr("Parent") , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
      break; 
    case 3:  	
	    osd->DrawEllipse(      14        , 6*fh +(rows *22) +261 ,  26        , 6*fh +(rows *22) +274 , clrStatusRed    , 0);
	    osd->DrawEllipse(      tab   +8  , 6*fh +(rows *22) +261 , tab + 20   , 6*fh +(rows *22) +274 , clrStatusGreen  , 0);
	    osd->DrawEllipse(      2*tab +8  , 6*fh +(rows *22) +261 , 2*tab + 20 , 6*fh +(rows *22) +274 , clrStatusYellow , 0);
	    osd->DrawEllipse(      3*tab +8  , 6*fh +(rows *22) +261 , 3*tab + 20 , 6*fh +(rows *22) +274 , clrStatusBlue   , 0);

	    osd->DrawText(         34        , 6*fh +(rows *22) +255 , tr("Parent")  , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         tab   +28 , 6*fh +(rows *22) +255 , "<<"          , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         2*tab +28 , 6*fh +(rows *22) +255 , ">>"          , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
	    osd->DrawText(         3*tab +28 , 6*fh +(rows *22) +255 , tr("Min/Sec") , clrStatusFG, clrStatusBG, pFontCommands, 16*fw, fh, taLeft);
      break; 
  }         

  refresh = true;
}

void cMP3Control::ConvertRatingToChar(int value, int bgClr, int fgClr) {

  int bg=bgClr;
  int fg=fgClr;

  if(value <0) value=0;

  switch(value) {
     case 0:
       osd->DrawBitmap( cw +20 +5, 6*fh +11  , bmRate00 , fg , bg );
       break;
     case 3:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmDelStar , fg , bg );
       break;
     case 28:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate05 , fg , bg );
       break;
     case 53:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate10 , fg , bg );
       break;
     case 78:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate15 , fg , bg );
       break;
     case 104:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate20 , fg , bg );
       break;
     case 129:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate25 , fg , bg );
       break;
     case 154:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate30 , fg , bg );
       break;
     case 179:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate35 , fg , bg );
       break;
     case 205:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate40 , fg , bg );
       break;
     case 230:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate45 , fg , bg );
       break;
     case 255:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate50 , fg , bg );
       break;
     default:
       osd->DrawBitmap( cw +20 +5, 6*fh +11   , bmRate00 , fg , bg );
       break;  
  }

  flush = true;
}


void cMP3Control::SetVars(void)
{
//  font=cFont::GetFont(fontOsd);
  fw=6;
  fh=26;
  rows = MP3Setup.Rowcount;
  artistfirst = MP3Setup.ArtistFirst;
  depth                 = 4;
  clrBG                 = MP3Skin.clrBG;
  clrTopBG              = MP3Skin.clrTopBG;
  clrTopFG              = MP3Skin.clrTopFG;
  clrArtistBG           = MP3Skin.clrArtistBG;
  clrArtistFG           = MP3Skin.clrArtistFG;
  clrRatingFG           = MP3Skin.clrRatingFG;
  clrPlayStatusBG       = MP3Skin.clrPlayStatusBG;
  clrPlayStatusFG       = MP3Skin.clrPlayStatusFG;
  clrInfoBG             = MP3Skin.clrInfoBG;
  clrInfoFG             = MP3Skin.clrInfoFG;
  clrProgressbarBG      = MP3Skin.clrProgressbarBG;
  clrProgressbarFG      = MP3Skin.clrProgressbarFG;
  clrListTitle          = MP3Skin.clrListTitle;
  clrListBG             = MP3Skin.clrListBG;
  clrListFG             = MP3Skin.clrListFG;
  clrSymbolBG           = MP3Skin.clrSymbolBG;
  clrSymbolFG           = MP3Skin.clrSymbolFG;
  clrSymbolActive       = MP3Skin.clrSymbolActive;
  clrRecordingActive    = MP3Skin.clrRecordingActive;
  clrStatusBG           = MP3Skin.clrStatusBG;
  clrStatusFG           = MP3Skin.clrStatusFG;
  clrStatusRed          = MP3Skin.clrStatusRed;
  clrStatusGreen        = MP3Skin.clrStatusGreen;
  clrStatusYellow       = MP3Skin.clrStatusYellow;
  clrStatusBlue         = MP3Skin.clrStatusBlue;
  
  if(MP3Setup.EnableVis) {
    clrCoverBG          = 0xFF000000;
    clrCoverBar         = 0xFF000000;
    imgalpha = 255;
	}
  else {
    clrCoverBG          = MP3Skin.clrCoverBG;
    clrCoverBar         = MP3Skin.clrCoverBar;
    imgalpha            = MP3Setup.ImgAlpha;
  }
  
  if (MP3Skin.isMpeg == 0) {
    osdheight   = Setup.OSDHeight;
    osdwidth    = Setup.OSDWidth;
    osdtop      = Setup.OSDTop;
    osdleft     = Setup.OSDLeft;
    }
  else {
    osdheight   = MP3Skin.osdheight;
    osdwidth    = MP3Skin.osdwidth;
    osdtop      = MP3Skin.osdtop;
    osdleft     = MP3Skin.osdleft;

    if ( player->IsStream() )
      clrProgressbarBG    = 0x0A000000;
    else
      clrProgressbarBG    = MP3Skin.clrProgressbarBG;
   }

  x1 = osdwidth;

  visualization = MP3Setup.Visualization; 
  channelsSA    = MP3Setup.ChannelsSA;
  bandsSA       = MP3Setup.BandsSA;
}


void cMP3Control::SetFonts(void)
{
  pFontUser       = MusicConfig.GetFont(FONT_TOP);
  pFontText       = MusicConfig.GetFont(FONT_STATUS);
  pFontList       = MusicConfig.GetFont(FONT_LIST);
  pFontListActive = MusicConfig.GetFont(FONT_LISTACTIVE);
  pFontTitle      = MusicConfig.GetFont(FONT_TITLE);
  pFontInfo       = MusicConfig.GetFont(FONT_INFO);
  pFontCommands   = MusicConfig.GetFont(FONT_BOTTOM);
}


void cMP3Control::SetVol(void)
{
  vol   = player->CurrentVolume();
  muted = player->Muted();

  if(muted || vol == 0)
    osd->DrawBitmap(osdwidth -144 -fh , 6*fh  +(rows *22) +183 +20, bmMute, clrSymbolActive, clrSymbolBG);
  else
    osd->DrawBitmap(osdwidth -144 -fh , 6*fh  +(rows *22) +183 +20, bmVol, clrSymbolActive, clrSymbolBG);

  cProgressBar VolumeBar(100, 6, vol, 255, clrSymbolActive , clrSymbolFG);
  osd->DrawBitmap(osdwidth -110 -fh, 6*fh +(rows *22) +193 +20, VolumeBar);
  
  flush = true;
}



void cMP3Control::ShowProgress(bool open)
{

  int index, total;
  
  if(player->GetIndex(index,total) && total>=0) {


    if(!cOsd::IsOpen() && !visible && !open) {
      open=true;
      SetVars();
      vol = 0;
    }

    if(!visible && open) {

    if (MP3Skin.isMpeg == 1) {
        MP3Skin.saonly = false;
		MP3Skin.reloadmpeg = true;
//		player->CheckMpeg(false);
	}
	
	osd=cOsdProvider::NewOsd(osdleft + MP3Setup.OSDoffsetx, osdtop + MP3Setup.OSDoffsety);
      if(!osd) return;

      cw = (fh +144) & ~0x07;

      tArea Area[] = { { 0, 0, x1 -1,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +fh +10 -1 , 8} };
      if (MP3Setup.UseOneArea && osd->CanHandleAreas(Area, sizeof(Area) / sizeof(tArea)) == oeOk) {
        osd->SetAreas(Area, sizeof(Area) / sizeof(tArea));
        }
      else {	 
//        cw = (fh +8 +128 +8) & ~0x07;
    
        tArea Area[] = {
          {	0                ,0                                   ,x1 -1         ,2*fh                                       ,2},        // border top
          {	0                ,2*fh +1                             ,cw -1         ,2*fh +8 +128 +8                            ,4},        // cover
          {	cw               ,2*fh +1                             ,x1 -1         ,2*fh +8 +128 +8                            ,2},        // trackinfo
          {	0                ,2*fh +8 +128 +9                     ,x1 -1         ,2*fh +8 +128 +9 +3*fh +10 -1               ,2},        //  Progress
          {	0                ,2*fh +8 +128 +9 +3*fh +10           ,x1 -1         ,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +5 -1  ,2},        //  titel + next tracks
          {	0                ,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +5  ,x1 -1         ,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +10 -1     ,2},        //  symbolbar
          {	0                ,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +10 ,x1 -1         ,2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +fh +10 -1 ,4},        //  bottombar
        };

        eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(tArea));
        if (result == oeOk) {
          osd->SetAreas(Area, sizeof(Area) / sizeof(tArea));
          }
        else  {
          const char *errormsg = NULL;
          switch (result) {
            case oeTooManyAreas:
              errormsg = "music: Too many OSD areas"; break;
            case oeTooManyColors:
              errormsg = "music: Too many colors"; break;
            case oeBppNotSupported:
              errormsg = "music: Depth not supported"; break;	
            case oeAreasOverlap:
              errormsg = "music: Areas are overlapped"; break;
            case oeWrongAlignment:
              errormsg = "music: Areas not correctly aligned"; break;
            case oeOutOfMemory:
              errormsg = "music: OSD memory overflow"; break;
            case oeUnknown:
              errormsg = "music: Unknown OSD error"; break;
            default:
              break;
          }	
          esyslog("music: ctrl: ERROR! osd open failed! can't handle areas (%d)-%s\n", result, errormsg);
          if(osd){ delete osd; osd=0;}

          return;
        }
      }

      mgr->playnow = false;

// SetFont
      SetFonts();
      
// top field
      osd->DrawRectangle(0          , 0, x1 - 1, fh -3, clrTopBG);
      osd->DrawEllipse(0            , 0, fh/2  , fh/2 , clrTransparent, -2);
      osd->DrawEllipse(x1 -1 - fh/2 , 0, x1 -1 , fh/2 , clrTransparent, -1);
      osd->DrawRectangle(0, fh -2,    x1 -1 , 2*fh ,clrBG);

// cover field
      osd->DrawRectangle(0,  2*fh +1,  cw -1 , 2*fh +8 +128 +8 ,clrBG);
      osd->DrawRectangle(fh, 2*fh +1,  cw -1 , 2*fh +8 +128 +8 ,clrCoverBG);
      osd->DrawEllipse(  fh          , 2*fh +1             , fh +10 , 2*fh +1 +10     , clrBG , -2); // oben links
      osd->DrawEllipse(  (cw -1) -10 , 2*fh +1             , cw -1  , 2*fh +1 +10     , clrBG, -1);  // oben rechts
      osd->DrawEllipse(  fh          , 2*fh +8 +128 +8 -10 , fh +10 , 2*fh +8 +128 +8 , clrBG , -3); // unten links
      osd->DrawEllipse(  (cw -1) -10 , 2*fh +8 +128 +8 -10 , cw -1  , 2*fh +8 +128 +8 , clrBG, -4);  // unten rechts
      
// artist,rating field
      osd->DrawRectangle(cw                , 2*fh +1             , x1 -1        , 2*fh +8 +128 +8 , clrBG);          // kompletter background
      osd->DrawRectangle(cw +10            , 2*fh +1             , (x1 -1) -fh  , 2*fh +8 +128 +8 , clrArtistBG);    // Inhalt schwarz
      osd->DrawEllipse(  cw +10            , 2*fh +1             , cw + 20      , 2*fh +1 +10     , clrBG    , -2);  // oben links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +1             , (x1 -1) -fh  , 2*fh +1 +10     , clrBG    , -1);  // oben rechts
      osd->DrawEllipse(  cw +10            , 2*fh +8 +128 +8 -10 , cw + 20      , 2*fh +8 +128 +8 , clrBG    , -3);  // unten links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +8 -10 , (x1 -1) -fh  , 2*fh +8 +128 +8 , clrBG    , -4);  // unten rechts

// info,progress field
      osd->DrawRectangle(	0              , 2*fh +8 +128 +9     , x1 -1        , 2*fh +8 +128 +9 +3*fh +10 -1 , clrBG); // kompletter background
      osd->DrawRectangle(fh                , 2*fh +8 +128 +9 +10 , cw -1        , 2*fh +8 +128 +9 +3*fh +10 -1 , clrInfoBG); // playsymbol
      osd->DrawRectangle(cw +10            , 2*fh +8 +128 +9 +10 , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +10 -1 , clrInfoBG); // progress
      //playsymbol
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +10 , fh +10 , 2*fh +8 +128 +9 +20     , clrBG , -2); // oben links
      osd->DrawEllipse(  (cw -1) -10       , 2*fh +8 +128 +9 +10 , cw -1  , 2*fh +8 +128 +9 +20     , clrBG, -1);  // oben rechts
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +3*fh -1     , fh +10 , 2*fh +8 +128 +9 +3*fh -1 +10, clrBG , -3); // unten links
      osd->DrawEllipse(  (cw -1) -10       , 2*fh +8 +128 +9 +3*fh -1     , cw -1  , 2*fh +8 +128 +9 +3*fh -1 +10, clrBG , -4);  // unten rechts
      //progress
      osd->DrawEllipse(  cw +10            , 2*fh +8 +128 +9 +10   , cw +20              , 2*fh +8 +128 +9 +20      , clrBG , -2); // oben links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +10   , (x1 -1) -fh         , 2*fh +8 +128 +9 +20      , clrBG , -1); // oben rechts
      osd->DrawEllipse(  cw +10            , 2*fh +8 +128 +9 +3*fh -1  , cw +20       , 2*fh +8 +128 +9 +3*fh -1 +10, clrBG , -3); // unten links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +3*fh -1  , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh -1 +10, clrBG , -4); // unten rechts



      
// tracklist field
      osd->DrawRectangle(0                 , 2*fh +8 +128 +9 +3*fh +10          , x1 -1        , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 -1 +5, clrBG);      // kompletter background
      osd->DrawRectangle(fh                , 2*fh +8 +128 +9 +3*fh +30          , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +30 +3 +fh + (rows *22) +3 +5    , clrListBG);       // Inhalt schwarz
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +3*fh +30          , fh + 10      , 2*fh +8 +128 +9 +3*fh +40          , clrBG , -2); // oben links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +3*fh +30          , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +40          , clrBG, -1);  // oben rechts
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +3*fh +30 +3 +fh + (rows *22) +3 -5    , fh +10       , 2*fh +8 +128 +9 +3*fh +30 +3 +fh + (rows *22) +3 +5, clrBG , -3); // unten links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +3*fh +30 +3 +fh + (rows *22) +3 -5    , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +30 +3 +fh + (rows *22) +3 +5, clrBG, -4);  // unten rechts


// symbol field
      osd->DrawRectangle(0                 , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +5    , x1 -1        , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +64 +10 -1     , clrBG);      // kompletter background
      osd->DrawRectangle(fh                , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +20 -5, (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +64 -1 -fh +20, clrSymbolBG);       // Inhalt schwarz
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +20 -5, fh + 10      , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +10 +20 -5      , clrBG , -2); // oben links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +20 -5, (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +10 +20 -5      , clrBG , -1);  // oben rechts
      osd->DrawEllipse(  fh                , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +64 +20 -1 -fh , fh +10       , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +64 -1 -fh +20, clrBG , -3); // unten links
      osd->DrawEllipse(  (x1 -1) -fh -10   , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +64 +20 -1 -fh , (x1 -1) -fh  , 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +3 +10 +64 -1 -fh +20, clrBG , -4);  // unten rechts

      // Loof Shuffle
      osd->DrawBitmap(fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmShuffle, clrSymbolFG, clrSymbolBG);

      // Loop symbol
      osd->DrawBitmap(fh +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmLoop, clrSymbolFG, clrSymbolBG);

      // Recording symbol
      if(MP3Setup.RecordStream) {
//        osd->DrawText( 26 + 5, 2*22 +8 +128 +9 +20 +22 -4 +5, tr("RECORD"), clrRecordingActive, clrPlayStatusBG, pFontInfo, osdwidth -22 -5 -(osdwidth -cw) -5, 22, taCenter);
        osd->DrawBitmap(fh +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmRec, clrRecordingActive, clrSymbolBG);
        flush=true;
        }
      else {
        osd->DrawBitmap(fh +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmRec, clrSymbolFG, clrSymbolBG);
        flush=true;
      }
      // Lyrics
      osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmText, clrSymbolFG, clrSymbolBG);
      // Copy symbol
      osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmCopy, clrSymbolFG, clrSymbolBG);
      // Shutdown symbol
      if(MP3Setup.EnableShutDown) 
        osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmShutdown, clrSymbolActive, clrSymbolBG);
      else	
        osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmShutdown, clrSymbolFG, clrSymbolBG);

      SetVol();

//bottom
      osd->DrawRectangle(0         , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +10, x1 -1  , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +fh +10 -1 , clrStatusBG);         // border top
      osd->DrawEllipse(0           , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +10, fh/2   , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +fh +10 -1 , clrTransparent, -3);
      osd->DrawEllipse(x1 -1 -fh/2 , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +10, x1 -1  , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +3 +10 +64 +fh +10 -1 , clrTransparent, -4);

// SetKey buttons
      ShowHelpButtons(showbuttons);	


#if VDRVERSNUM >= 10500
      visible = true;
      SetNeedsFastResponse(visible);
#else      
      needsFastResponse=true;
      visible=true;
#endif
      force=true;
      
      fliptime=listtime=0; flipint=0; flip=-1; lastIndex=lastTotal=-1;
      delete lastMode; lastMode=0;

      if(MP3Setup.EnableVis) player->LoadImage("xyz","xyz",false);


    }

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    cMP3PlayInfo *mode=new cMP3PlayInfo;
    bool valid=mgr->Info(-1,mode);
    
    bool changed=(!lastMode || mode->Hash!=lastMode->Hash);
    char buf[256];

// send progress to status monitor
    if(valid) {
      if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) {
        snprintf(buf,sizeof(buf),mode->Artist[0]?"[%c%c] (%d/%d) %s - %s":"[%c%c] (%d/%d) %s",
        mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,mode->Title,mode->Artist);
        cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true);
      }
    }

// refresh the OSD progress display
    if(visible) {

      //flush the osd explicitly
      if(refresh) flush = true;
      else flush = false;


// New song
    if ( mode->Filename && !(strcmp(mode->Filename,lastfile) ==0) || force || MP3Setup.ShowStatus != laststatus || changed) {
      strncpy(lastfile, mode->Filename,sizeof(lastfile));

// Rating
      if(MP3Setup.EnableRating) {
        ConvertRatingToChar(mode->Rating, clrArtistBG, clrRatingFG); 
      }

// Infofield        
        buf[0]=0;
        if(mode->Artist[0]) {
          snprintf(buf,sizeof(buf),"%s",mode->Artist);
          osd->DrawText( cw +20 +5, 2*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
          }          
        else {
          snprintf(buf,sizeof(buf),"%s: %s",tr("Artist"), tr("Unknown"));
          osd->DrawText( cw +20 +5, 2*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
        }
        
        if(mode->Album[0]) {
          snprintf(buf,sizeof(buf),"%s: %s", tr("Album"), mode->Album);
          osd->DrawText( cw +20 +5, 3*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
          }
        else {
          snprintf(buf,sizeof(buf),"%s: %s", tr("Album"),tr("Unknown"));
          osd->DrawText( cw +20 +5, 3*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
        }

        if(mode->Genre[0]) {
          snprintf(buf,sizeof(buf),"%s: %s", tr("Genre"), mode->Genre);
          osd->DrawText( cw +20 +5, 4*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
          }          
        else {
          snprintf(buf,sizeof(buf),"%s: %s", tr("Genre"), tr("Unknown"));
          osd->DrawText( cw +20 +5, 4*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
        }
          
        if(mode->Year > 2) {
          snprintf(buf,sizeof(buf),"%s: %d", tr("Year"), mode->Year);
          osd->DrawText( cw +20 +5, 5*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
          }          
        else {
          snprintf(buf,sizeof(buf),"%s: %s", tr("Year"), tr("Unknown"));
          osd->DrawText( cw +20 +5, 5*fh +7, buf, clrArtistFG, clrArtistBG, pFontListActive, x1 -cw -30 -fh -5, fh, taLeft);
        }


	  
// Tracklist		
        if (mode->Num < 1) {
          osd->DrawRectangle(fh +10 , 2*fh +8 +128 +9 +3*fh +20 +3 +10, x1 -fh -10 , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +10, clrListBG);
	      osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +10, tr("Please add some tracks..."), clrListTitle, clrListBG, pFontTitle, x1 -2*fh -20, fh, taLeft);
          }
        // last track is playing...
        else if (mode->Num == mode->MaxNum) {
          osd->DrawRectangle(fh +10 , 2*fh +8 +128 +9 +3*fh +20 +fh +3 +10, x1 -fh -10 , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +10, clrListBG);
	  osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh +10, tr("End of playlist ============================"), clrListFG, clrListBG, pFontList, x1 -2*fh -20, 22, taLeft);
        }

        // more than one track to play...
        if( (mode->MaxNum - mode->Num) >= 1 ) {
          osd->DrawRectangle(fh +10 , 2*fh +8 +128 +9 +3*fh +20 +fh +3 +10, x1 -fh -10 , 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(rows *22) +10, clrListBG);

	  cMP3PlayInfo pi;

          for(int i=0 ; i < rows; i++) {
            mgr->Info(mode->Num +i +1, &pi);
            if(pi.Title[0]) {
              if(artistfirst && pi.Artist[0]) {
	        snprintf(buf,sizeof(buf),pi.Artist[0]?"%s  -  %s":"%s",pi.Artist, pi.Title);
	        }
	      else {
	        snprintf(buf,sizeof(buf),pi.Artist[0]?"%s  -  %s":"%s",pi.Title,pi.Artist);
	      }
              osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(22 *i) +10, buf, clrListFG, clrListBG, pFontList, x1 -2*fh -20, 22, taLeft);
            }
	    else {
              osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh +(22 *i) +10, "", clrListFG, clrListBG, pFontList, x1 -2*fh -20, 22, taLeft);
            }
          } 
        }


// Lyrics exists or not symbol
        if(player->ExistsLyrics(mode->Filename)) {
          osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmText, clrSymbolActive, clrSymbolBG);
          flush=true;
          }
        else {
          osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmText, clrSymbolFG, clrSymbolBG);
          flush=true;
        }

// Load Cover
      if(!MP3Setup.EnableVis) {
        osd->DrawRectangle(0,  2*fh +1,  cw -1 , 2*fh +8 +128 +8 ,clrBG);
        osd->DrawRectangle(fh, 2*fh +1,  cw -1 , 2*fh +8 +128 +8 ,clrCoverBG);
        osd->DrawEllipse(  fh          , 2*fh +1             , fh +10 , 2*fh +1 +10     , clrCoverBG , -2); // oben links
        osd->DrawEllipse(  (cw -1) -10 , 2*fh +1             , cw -1  , 2*fh +1 +10     , clrCoverBG, -1);  // oben rechts
        osd->DrawEllipse(  fh          , 2*fh +8 +128 +8 -10 , fh +10 , 2*fh +8 +128 +8 , clrCoverBG , -3); // unten links
        osd->DrawEllipse(  (cw -1) -10 , 2*fh +8 +128 +8 -10 , cw -1  , 2*fh +8 +128 +8 , clrCoverBG, -4);  // unten rechts

        player->LoadImage(mode->Filename, mode->Artist, true);
        LoadCover();
        flush = true;
      }

      force = false;

    } // End of NewSong



        // Loof Shuffle
        if( !lastMode || mode->Shuffle!=lastMode->Shuffle) {
          if(mode->Shuffle)
            osd->DrawBitmap(fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmShuffle, clrSymbolActive, clrSymbolBG);
          else
            osd->DrawBitmap(fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmShuffle, clrSymbolFG, clrSymbolBG);
          flush = true;  
        }

        // Loop symbol
        if( !lastMode || mode->Loop!=lastMode->Loop) {
          if(mode->Loop)
            osd->DrawBitmap(fh +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmLoop, clrSymbolActive, clrSymbolBG);
          else
            osd->DrawBitmap(fh +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmLoop, clrSymbolFG, clrSymbolBG);
          flush = true;  
        }




// track changed or show status
      if(changed || refresh || MP3Setup.ShowStatus != laststatus) {

// Infofield
      if(!selecting) {
        if(mode->MaxBitrate>0) {
          snprintf(buf,sizeof(buf),"%.1f kHz, %d-%d kbps, %s", mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->MaxBitrate/1000,mode->SMode);
          osd->DrawText( cw +20 +5, 2*22 +8 +128 +9 +20 -4 +2 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, osdwidth -cw -20 -22 -10 -5, 22, taLeft);
          }
        else {
          snprintf(buf,sizeof(buf),"%.1f kHz, %d kbps, %s", mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->SMode);
          osd->DrawText( cw +20 +5, 2*22 +8 +128 +9 +20 -4 +2 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, osdwidth -cw -20 -22 -10 -5, 22, taLeft);
        }

        snprintf(buf,sizeof(buf),"%s %i %s %i","No.",mode->Num,tr("of"),mode->MaxNum);
         osd->DrawText( cw +20 +5, 2*22 +8 +128 +9 +20 +22 -4 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, osdwidth -cw -20 -22 -10 -5, 22, taLeft);

//		int totaltime = mgr->GetListLength();
//		snprintf(buf,sizeof(buf),"%s %02d:%02d", tr("Total:"),totaltime/60,totaltime%60);
//        osd->DrawText( osdwidth -22 -1 -10 -160, 2*22 +8 +128 +9 +20 +22 -4, buf, clrInfoFG, clrInfoBG, pFontInfo, 160, 22, taRight);		 

		flush=true;
      }

	
// Title          
        if(!jumpactive) {
          int showstatus = MP3Setup.ShowStatus;

          switch(showstatus) {
            case 0:
              snprintf(buf,sizeof(buf),"%s",mode->Title);
	      break;
	    case 1:  
              snprintf(buf,sizeof(buf),"%s",tr("Connecting to stream server ..."));
	      break;
            case 2:
              snprintf(buf,sizeof(buf),"%s",tr("Remote CDDB lookup..."));
              break;
	    default: break;
          }	   

          laststatus = showstatus;
	  
          if(buf[0]) {
            DisplayInfo(buf);
	  }
          
          flush = true;
        }
      }	

	
	
// Playstatus   
      if(mgr->Scanning() && mgr->maxIndex >0) {
     	osd->DrawText( 26 + 5, 2*22 +8 +128 +9 +20 +22 -4 +5, tr("SCANNING"), clrProgressbarFG, clrPlayStatusBG, pFontInfo, osdwidth -22 -5 -(osdwidth -cw) -5, 22, taCenter);
        }
      else {		
        int playstatus;
        playstatus = player->StatusMode();
        switch(playstatus) {
			case 1:
				osd->DrawText( 26 + 5, 2*22 +8 +128 +9 +20 +22 -4 +5, tr("STOPPED"), clrPlayStatusFG, clrPlayStatusBG, pFontInfo, osdwidth -22 -5 -(osdwidth -cw) -5, 22, taCenter);
				break;
			case 2:
				osd->DrawText( 26 + 5, 2*22 +8 +128 +9 +20 +22 -4 +5, tr("PLAYING"), clrPlayStatusFG, clrPlayStatusBG, pFontInfo, osdwidth -22 -5 -(osdwidth -cw) -5, 22, taCenter);
				break;
			case 3:
				osd->DrawText( 26 + 5, 2*22 +8 +128 +9 +20 +22 -4 +5, tr("PAUSED"), clrPlayStatusFG, clrPlayStatusBG, pFontInfo, osdwidth -22 -5 -(osdwidth -cw) -5, 22, taCenter);
				break;
		}
      }

      
// Progressbar      
      if(!player->IsStream()) {
        if(index!=lastIndex || total!=lastTotal) {
          index/=framesPerSecond; total/=framesPerSecond;
          if(total>0) {
            cProgressBar ProgressBar(osdwidth -cw -20 -80 -22 -10 -80 -10, 6, index, total, clrProgressbarFG , clrProgressbarBG);
            osd->DrawBitmap(cw +20 +80 +5, 2*22 +8 +128 +9 +20 +2*22 + 7 +5, ProgressBar);
          }
          snprintf(buf, sizeof(buf),"%02d:%02d", index/60, index%60);
          osd->DrawText( cw +20 +5, 2*22 +8 +128 +9 +20 +2*22 -4 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, 80, 22, taLeft);
      
          snprintf(buf, sizeof(buf),"%02d:%02d", total/60, total%60);
          osd->DrawText( osdwidth -22 -1 -10 -80 -5, 2*22 +8 +128 +9 +20 +2*22 -4 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, 80, 22, taRight);
          
          flush=true;
          }
	}  
      else {
        osd->DrawRectangle(cw + 20, 2 * 22 + 8 +128 + 9 + 20 + 2*22 +5, osdwidth -22 -11, 2*fh +8 +128 +9 +3*fh -1 +5, clrInfoBG);
      }
     
      
      
// Volumebar
      if ( vol != player->CurrentVolume() || muted != player->Muted()) {
        SetVol();
      }  
      
// Spectrum Analyzer visualization begins here...
      if ( MP3Setup.EnableVis && ShowSA)	{
        if (cPluginManager::CallFirstService(SPAN_GET_BAR_HEIGHTS_ID, NULL))	{
          Span_GetBarHeights_v1_0 GetBarHeights;
          unsigned int bar;
          unsigned int *barHeights             = new unsigned int[bandsSA];
          unsigned int *barHeightsLeftChannel  = new unsigned int[bandsSA];
          unsigned int *barHeightsRightChannel = new unsigned int[bandsSA];
          unsigned int volumeLeftChannel;
          unsigned int volumeRightChannel;
          unsigned int volumeBothChannels;
          unsigned int *barPeaksBothChannels   = new unsigned int[bandsSA];
          unsigned int *barPeaksLeftChannel    = new unsigned int[bandsSA];
          unsigned int *barPeaksRightChannel   = new unsigned int[bandsSA];
 								
          GetBarHeights.bands 		          = bandsSA;
          GetBarHeights.barHeights		  = barHeights;
          GetBarHeights.barHeightsLeftChannel     = barHeightsLeftChannel;
          GetBarHeights.barHeightsRightChannel    = barHeightsRightChannel;
          GetBarHeights.volumeLeftChannel	  = &volumeLeftChannel;
          GetBarHeights.volumeRightChannel	  = &volumeRightChannel;
          GetBarHeights.volumeBothChannels	  = &volumeBothChannels;
          GetBarHeights.name			  = "Music";
          GetBarHeights.falloff		          = MP3Setup.FalloffSA;
          GetBarHeights.barPeaksBothChannels	  = barPeaksBothChannels;
          GetBarHeights.barPeaksLeftChannel	  = barPeaksLeftChannel;
          GetBarHeights.barPeaksRightChannel	  = barPeaksRightChannel;

          if ( cPluginManager::CallFirstService(SPAN_GET_BAR_HEIGHTS_ID, &GetBarHeights )) {
            int i;
            int barPeakHeight = 3;
            int barPeak       = 0;
            int barWidth      = 0;
            int coverleft     = fh +7;
            int coverright    = fh +7 +128;
            int covertop      = 2*fh +8;
            int coverbottom   = 2*fh +8 +128;

            if(player !=NULL) {
              switch(visualization) {
                case 1:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 128/bandsSA;
                    bar      = (barHeights[i]*118)/100;
                    barPeak  = barPeaksBothChannels[i]*118/100;
                    if(barPeak > 0) {
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 122 - barPeak -barPeakHeight, clrCoverBar);
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop +122 -barPeak +1, coverleft + (i*barWidth) +barWidth -1, covertop + 122 - bar, clrCoverBar);
                      }
                    else {
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 122 - bar, clrCoverBar);
                    }  
                  }
                  break;

                case 2:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 64/bandsSA;
                    bar = barHeightsLeftChannel[i]*118/100;
                    barPeak = barPeaksLeftChannel[i]*118/100;
                    if(barPeak > 0) {
                      osd->DrawRectangle(coverleft +(i*barWidth)    , covertop, coverleft +(i*barWidth) +barWidth -1    , covertop + 122 - barPeak -barPeakHeight, clrCoverBar);
                      osd->DrawRectangle(coverleft +(i*barWidth)    , covertop +122 -barPeak +1, coverleft +(i*barWidth) +barWidth -1    , covertop + 122 - bar, clrCoverBar);
                      }
                    else {
                      osd->DrawRectangle(coverleft +(i*barWidth)    , covertop, coverleft +(i*barWidth) +barWidth -1    , covertop + 122 - bar, clrCoverBar);
                    }		       	 
                    bar = barHeightsRightChannel[i]*118/100;
                    barPeak = barPeaksRightChannel[i]*118/100;
                    if( barPeak > 0) {
                      osd->DrawRectangle(coverleft +64 +(i*barWidth), covertop, coverleft +64 +(i*barWidth) +barWidth -1, covertop + 122 - barPeak -barPeakHeight, clrCoverBar);
                      osd->DrawRectangle(coverleft +64 +(i*barWidth), covertop +122 -barPeak +1, coverleft +64 +(i*barWidth) +barWidth -1, covertop + 122 - bar, clrCoverBar);
                      }
                    else {
                      osd->DrawRectangle(coverleft +64 +(i*barWidth), covertop, coverleft +64 +(i*barWidth) +barWidth -1, covertop + 122 - bar, clrCoverBar);
                    }
                  }
                  break;

                case 3:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 34;
                    bar      = (volumeLeftChannel*118)/100;
                    osd->DrawRectangle(coverleft +16 , covertop, coverleft + 16 + barWidth , covertop + 122 - bar,  clrCoverBar);
                    bar      = (volumeRightChannel*118)/100;
                    osd->DrawRectangle(coverleft +80 , covertop, coverleft + 80 + barWidth , covertop + 122 - bar, clrCoverBar);
                  }
                  break;

                case 4:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 4;
                    bar = barHeightsLeftChannel[i]*118/100;
                    osd->DrawRectangle(coverleft           ,coverbottom -6 -(i*barWidth) -barWidth, coverleft +64 -(bar/2), coverbottom -(i*barWidth), clrCoverBar);
                    bar = barHeightsRightChannel[i]*118/100;
                    osd->DrawRectangle(coverright -64 +(bar/2),coverbottom -6 -(i*barWidth) -barWidth, coverright  , coverbottom -(i*barWidth), clrCoverBar);
                  }
                  break;

                case 5:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 1;
                    bar = barHeightsLeftChannel[i]*118/100;
                    osd->DrawRectangle(coverleft            ,coverbottom -6 -(i*barWidth) -barWidth, coverleft  +64 -(bar/2), coverbottom -(i*barWidth), clrCoverBar);
                    bar = barHeightsRightChannel[i]*118/100;
                    osd->DrawRectangle(coverright -64 +(bar/2),coverbottom -6 -(i*barWidth) -barWidth, coverright   , coverbottom -(i*barWidth), clrCoverBar);
                  }
                  break;
          
                case 6:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 128/bandsSA;
                    bar      = (barHeights[i]*118)/100;
                    barPeak  = barPeaksBothChannels[i]*118/100;
                    if(barPeak > 0) {
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop + 122 - barPeak -barPeakHeight, clrCoverBar);
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop +122 -barPeak +1, coverleft + (i*barWidth) +barWidth -1, coverbottom, clrCoverBar);
                      }
                    else {
                      osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, coverbottom, clrCoverBar);
                    }  
                  }
                  break;

                case 7:
                  LoadCover();
                  for ( i=0; i < bandsSA; i++ ) {
                    barWidth = 128/bandsSA;
                    bar      = (barHeights[i]*118)/100;
                    osd->DrawRectangle(coverleft +(i*barWidth), covertop, coverleft + (i*barWidth) +barWidth -1, covertop +122 -bar, clrCoverBar);
                    osd->DrawRectangle(coverleft +(i*barWidth), covertop + 122 -bar +4, coverleft + (i*barWidth) +barWidth -1, coverbottom, clrCoverBar);
                  }
                  break;

                default: break;
              }
            }

            flush = true;
          }
          delete [] barHeights;
          delete [] barHeightsLeftChannel;
          delete [] barHeightsRightChannel;
          delete [] barPeaksBothChannels;
          delete [] barPeaksLeftChannel;
          delete [] barPeaksRightChannel;
          }
        else {
          osd->DrawRectangle(fh +7, 2*fh +8, fh +135, 2*fh +136, clrCoverBG);
          flush = true;
        }
      }
      // SA ends here.......

      if(flush) Flush();
    }
    skiprew=0;
    skipfwd=0;
    lastIndex=index; lastTotal=total;
    delete lastMode; lastMode=mode;
    refresh=false;
  }
}


void cMP3Control::DisplayInfo(const char *s)
{
  if(osd && !MP3Setup.showcoveronly) {

    if(s) 
      osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +10, s, clrListTitle, clrListBG, pFontTitle, x1 -2*fh -20, fh, taLeft);
    else
      osd->DrawText( fh +10, 2*fh +8 +128 +9 +3*fh +20 +3 +10, "", clrListBG, clrListBG, pFontTitle, x1 -2*fh -20, fh, taLeft);

//    refresh = true;
  }
}


void cMP3Control::JumpDisplay(void)
{
  char buf[64];
  const char *j=tr("Jump: "), u=jumpsecs?'s':'m';
  if(!jumpmm)
    sprintf(buf, "%s- %c", j,u);
  else
    sprintf(buf,"%s%d- %c",j,jumpmm,u);

  DisplayInfo(buf);
}      


void cMP3Control::JumpProcess(eKeys Key)
{

  int n=Key-k0, d=jumpsecs?1:60;
  switch(Key) {
    case k0 ... k9:
      if(jumpmm*10+n <= lastTotal/d) jumpmm=jumpmm*10+n;
      JumpDisplay();
      break;
    case kBlue:
      jumpsecs=!jumpsecs;
      JumpDisplay();
      break;
    case kRed:
      jumpactive= false;
      break;
    case kPlay:
    case kUp:
      jumpmm-=lastIndex/d;
      // fall through
    case kFastRew:
    case kFastFwd:
    case kGreen:
    case kYellow:
      player->SkipSeconds(jumpmm*d * ((Key==kGreen) ? -1:1));
      // fall through
    default:
      jumpactive=false;
      break;      
    }
    
  if(!jumpactive) {
    ShowHelpButtons(0);
    }
}        

void cMP3Control::Jump(void)
{
  jumpmm=0; jumpsecs=false;
  JumpDisplay();
  jumpactive=true; fliptime=0; flip=-1;
}  


void cMP3Control::CopyTrack(void)
{
FILE *copyscript;
char *buffer;
  osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmCopy, clrSymbolActive, clrSymbolBG);
  Flush();
  asprintf(&buffer, "cp -f \"%s\"  \"%s\"", Songname, MP3Setup.CopyDir);
  copyscript = popen(buffer, "r");
  dsyslog("music: ctrl: executing: %s", buffer);
  free(buffer);
  pclose(copyscript);
  osd->DrawBitmap(fh +10 +26 +10 +26 +10 +26 +10 +26 +10, 2*fh +8 +128 +9 +3*fh +20 +3 +fh + (rows *22) +10 +5 +20, bmCopy, clrSymbolFG, clrSymbolBG);
  refresh = true;
}


void cMP3Control::ShutDown(void) {
  std::string shutdowncmd;
  
  shutdowncmd = config;
  shutdowncmd = shutdowncmd + "/" + langdir;
  shutdowncmd = shutdowncmd + "/scripts/music_shutdown.sh &";
  
  isyslog("music: ctrl: player stopped. Initiate shutdown...");
  system(shutdowncmd.c_str());
  isyslog("music: ctrl: Executing '%s'", shutdowncmd.c_str());
}


void cMP3Control::ShowMessage(int Message, bool open) {
  if(!cOsd::IsOpen()) {
    if(!visible && !open) {
      open=true;
    }
  }

  if(!visible && open) {

    osd=cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
    if(!osd) return;

	int y2 = (osdheight / 2) -(2*fh);
	int message = Message;
	
	
    tArea Area[] = {{ 0, y2, osdwidth -1, y2 + 4*fh, 2}, };
    eOsdError result = osd->CanHandleAreas(Area, sizeof(Area) / sizeof(tArea));
    if (result == oeOk) {
      osd->SetAreas(Area, sizeof(Area) / sizeof(tArea));
      }
    else  {
      const char *errormsg = NULL;
      switch (result) {
        case oeTooManyAreas:
	  errormsg = "Too many OSD areas"; break;
	case oeTooManyColors:
	  errormsg = "Too many colors"; break;
	case oeBppNotSupported:
	  errormsg = "Depth not supported"; break;	
	case oeAreasOverlap:
	  errormsg = "Areas are overlapped"; break;
	case oeWrongAlignment:
	  errormsg = "Areas not correctly aligned"; break;
	case oeOutOfMemory:
	  errormsg = "OSD memory overflow"; break;
	case oeUnknown:
          errormsg = "Unknown OSD error"; break;
	default:
	break;
        }	
      esyslog("music: ctrl: ERROR! osd open failed! can't handle areas (%d)-%s\n", result, errormsg);
      if(osd){ delete osd; osd=0;}

      return;
    }

    osd->DrawRectangle(0 , y2, osdwidth -1, y2 + 4*fh, clrBG); //complete  Background
    osd->DrawRectangle(fh/2 , y2 +fh/2, osdwidth -1 -fh/2, y2 + 4*fh -fh/2, clrListBG); //Textfield
	
    visible=true;

	switch(message) {
		case 1:
				osd->DrawText( 0 +fh, y2 + fh , tr("Be patient..."), clrListTitle, clrListBG, pFontTitle, osdwidth - 2*fh, fh, taCenter);
				osd->DrawText( 0 +fh, y2 + 2*fh , tr("TRACKS become straight scanned"), clrListFG, clrListBG, pFontTitle, osdwidth - 2*fh, fh, taCenter);
				break;

		default: break;
    }		

	Flush();
  }

}

eOSState cMP3Control::MessageProcess(eKeys Key)
{

  if(!mgr->Scanning()) {
	  Hide();
      showmessage = false;
	  
	  if(MP3Setup.showcoveronly) {
        if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode) 
          ShowSAOnly();
        else
          ShowCoverOnly();
      }
      else
        ShowProgress();
  }

  switch(Key) {
    case kUp:
    case kDown:
    case kLeft:
    case kRight:
    case kBlue:
    case kRed:
    case kGreen:
    case kYellow:
    case kPlay:
    case kBack:
    case kOk:
	  Hide();
      showmessage = false;
	  
	  if(MP3Setup.showcoveronly) {
        if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode) 
          ShowSAOnly();
        else
          ShowCoverOnly();
      }
      else
        ShowProgress();

    default:
      break;      
    }

  return osContinue;
}        



eOSState cMP3Control::ProcessKey(eKeys Key)
{

  if(MP3Setup.EnableShutDown == 1 && player->StatusMode() == 1 && mgr->maxIndex == mgr->currIndex ) {
    ShutDown();
    return osEnd;
  }    

  if( (player->StatusMode() == 1) && (mgr->TracksAdded()) && (mgr->NewCurrent()) && (!mgr->ShuffleMode()) ) player->Play();

  if(!player->Active()) return osEnd;

  if(showmessage) { MessageProcess(Key); return osContinue; }

  if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; }


  if(MP3Setup.showcoveronly) {
    if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode) 
      ShowSAOnly();
    else
      ShowCoverOnly();
    }
  else
    ShowProgress();


//  if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; }

  if(cmdMenu) {
      
    eOSState eOSRet = cmdMenu->ProcessKey(Key);
    switch(eOSRet) {
//        case kRed:
        case osBack:
            delete cmdMenu;
	          cmdMenu = NULL;

            // Can't call function from commands, so this is the way :(
            if (MP3Setup.DeleteTrack) {
	             MP3Setup.DeleteTrack = 0;
              player->DeleteTrack(false, mgr->currIndex);
	            }
	          else {
	            if(MP3Setup.DeleteTracks) {
	              MP3Setup.DeleteTracks = false;
		            player->DeleteTrack(true, mgr->currIndex);
		            cRemote::CallPlugin("music");
		            return(osPlugin);
	            }	  
            }
            if(MP3Setup.showcoveronly) {
	            if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode)
	              ShowSAOnly();
	            else	
	              ShowCoverOnly();
	          } 	
            else
              ShowProgress();
	          return osContinue;

        default: return eOSRet;
    }
  }    		
  else if(rateMenu) {
      
    eOSState eOSRet = rateMenu->ProcessKey(Key);
    switch(eOSRet) {
//        case kRed:
        case osBack:
            delete rateMenu;
	          rateMenu = NULL;
            if(MP3Setup.showcoveronly) {
	            if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode)
	              ShowSAOnly();
	            else	
	              ShowCoverOnly();
	          } 	
            else
              ShowProgress();

	          return osContinue;

        default: return eOSRet;
    }
  }
  else if(trackList) {

    eOSState eOSRet = trackList->ProcessKey(Key);
    switch(eOSRet) {
//        case kRed:
        case osBack:
            delete trackList;
	          trackList = NULL;

            if(MP3Setup.showcoveronly) {
	            if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode)
	              ShowSAOnly();
	            else	
	              ShowCoverOnly();
	          } 	
            else
              ShowProgress();

	          return osContinue;

        default: return eOSRet;
    }
  }
  else {

    switch(Key) {
        case kMenu:
            break;
	
        case kUp:
        case kDown:
        case kLeft:
        case kRight:
            if(mgr->maxIndex <0) break;
            Hide();
			if(mgr->Scanning()) {
			  showmessage=true;
			  ShowMessage( 1, false);
			  break;
			}  
            trackList = new cTrackList(&(mgr->list), player);
	        break;

        case kFastRew:
        case kFastRew|k_Repeat:
            if(mgr->maxIndex <0) break;
            ShowSA=false;      
            if(!player->IsStream() && player->StatusMode() == 2) player->SkipSeconds(-MP3Setup.Jumptime);
            skiprew=1;
            break;

        case kFastFwd:
        case kFastFwd|k_Repeat:
            if(mgr->maxIndex <0) break;
            ShowSA=false;      
            skipfwd=1;
            if(!player->IsStream() && player->StatusMode() == 2) player->SkipSeconds(MP3Setup.Jumptime);
            break;

        case kPlay:
            if(mgr->maxIndex <0) break;
            player->Play();
	    refresh = true;
            break;

        case kRed:
            // MENUE  OK
            if(showbuttons==0) {
              if(MP3Setup.RatingFirst) {
                if(mgr->maxIndex <0) break;
                if(!player->IsStream()) {
                  Hide();
                  rateMenu = new cMP3Rating(mgr->curr);
                }
	            }    
	            else {    
                MP3Setup.DeleteTrack=MP3Setup.DeleteTracks = 0;
                Hide();
                cmdMenu = new cMP3Commands();
              }
	          }
	          else if(showbuttons==1) {
	            ShowHelpButtons(0);
              if(MP3Setup.RatingFirst) {
                MP3Setup.DeleteTrack=MP3Setup.DeleteTracks = 0;
                Hide();
                cmdMenu = new cMP3Commands();
	              }
	            else {
                if(mgr->maxIndex <0) break;
	              if(!player->IsStream()) {    
                  Hide();
                  rateMenu = new cMP3Rating(mgr->curr);
                }
              }
	          }
	          else if(showbuttons==2) {
              if(mgr->maxIndex==0) {
	              ShowHelpButtons(0);
                player->DeleteTrack(true, mgr->currIndex);
	              cRemote::CallPlugin("music");
	              return(osPlugin);
	              }   
              else if(mgr->maxIndex >0) {
	              ShowHelpButtons(0);
		            player->DeleteTrack(false, mgr->currIndex);
	            }	
	          }      

            break;

        case kPrev:
        case kPrev|k_Repeat:
            if(mgr->maxIndex <0) break;
	          mgr->Prev();
            if(!player->StatusMode() == 2)
              player->Play();
            break; 
    
        case kGreen: 
        case kGreen|k_Repeat:
            if(showbuttons==0) {
              if(mgr->maxIndex <0) break;
	            mgr->Prev();
              if(!player->StatusMode() == 2)
              player->Play();
	            }
	          else if(showbuttons==1) {
              if(!MP3Setup.showcoveronly) {
                ShowHelpButtons(0);
                MP3Setup.showcoveronly = 1;
                Hide();
                if(MP3Setup.EnableVis && MP3Setup.VisInCoverMode)
	                ShowSAOnly(false);
                else
                  ShowCoverOnly(false);
              }
              else {
	              MP3Setup.showcoveronly = 0;
	              Hide();
	              ShowProgress(false);
      	      }
	          }
	          else if(showbuttons==2) {
              ShowHelpButtons(0);
              if(mgr->maxIndex <0) break;
              player->DeleteTrack(true, mgr->currIndex);
              cRemote::CallPlugin("music");
              return(osPlugin);
	          }      
            break;

        case kNext:
        case kNext|k_Repeat:
            if(mgr->maxIndex <=0) break;
	          mgr->Next();
            if(!player->StatusMode() == 2)
  	          player->Play();
            break;

        case kYellow:
        case kYellow|k_Repeat:
            if(showbuttons==0) {
              if(mgr->maxIndex <=0) break;
	            mgr->Next();
              if(!player->StatusMode() == 2)
	              player->Play();
	          }
	          else if(showbuttons==1) {
	            if(!player->IsStream()){
	              ShowHelpButtons(3);
                if(mgr->maxIndex <0) {
	                ShowHelpButtons(0);
	                break;
	              }	
	              Jump();
	            }
	            else  
	              ShowHelpButtons(0);
	          }
	          else if(showbuttons==2) {
	            ShowHelpButtons(0);
              if(mgr->maxIndex <0) break;
	            CopyTrack();
	          }      
            break;

        case kBlue: //OK
            if(showbuttons==0) {
	            if(!MP3Setup.showcoveronly) 
                ShowHelpButtons(1);
	            else {
	              MP3Setup.showcoveronly = 0;
	              Hide();
	              ShowProgress(false);
      	      }
            }
	          else if(showbuttons==1) {
	            if(MP3Setup.AdminMode)
	              ShowHelpButtons(2);
	            else
	              ShowHelpButtons(0);  
	          } 
	          else if(showbuttons==2) {
              ShowHelpButtons(0);
	          }      
            break;

        case kPause:
            if(mgr->maxIndex <0) break;
            player->Pause();
	    refresh = true;
            break;

        case kOk:
            Hide();
	          cRemote::CallPlugin("music");
            return (osPlugin);
            break;

        case kStop:
            if(mgr->maxIndex <0) break;
            Hide();
            Stop();
            return osEnd;

        case k0 ... k9:
            number=number*10+Key-k0;
            if(lastMode && number>0 && number<=lastMode->MaxNum && !MP3Setup.showcoveronly) {
              selecting=true; lastkeytime=time_ms();
              char buf[32];
              snprintf(buf,sizeof(buf),"%s %d- %s %d","No.",number,tr("of"),lastMode->MaxNum);
			  osd->DrawText( cw +20 +5, 2*22 +8 +128 +9 +20 +22 -4 +5, buf, clrInfoFG, clrInfoBG, pFontInfo, osdwidth -cw -20 -22 -10 -5, 22, taLeft);
              flush=true;
              break;
            }
	    number=0; lastkeytime=0;

        case kNone:
            if(selecting && time_ms()-lastkeytime>SELECT_TIMEOUT) {
	      if(number>0) {mgr->Goto(number); player->Play(); }
	      if(lastMode) lastMode->Hash=-1;
	      number=0; selecting=false;
	    }
	    ShowSA=true;
            break;

        case kBack:
            Hide();
#if APIVERSNUM >= 10332
	          cRemote::CallPlugin("music");
            if(MP3Setup.ExitClose)
	            return (osBack);
	          else    
              return (osPlugin);
#else
            return osEnd;
#endif	  	  
        
        default:
            return osUnknown;
    }

  return osContinue;
  }
}


