diff -Nru vdr-plugin-music-0.9.9/debian/changelog vdr-plugin-music-0.9.9/debian/changelog --- vdr-plugin-music-0.9.9/debian/changelog 2020-11-26 21:39:10.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/changelog 2020-11-26 22:16:29.000000000 +0000 @@ -1,3 +1,9 @@ +vdr-plugin-music (0.9.9-8easyVDR1~focal) focal; urgency=high + + * added patches + + -- easyVDR-Developer Thu, 26 Nov 2020 23:17:08 +0100 + vdr-plugin-music (0.9.9-8easyVDR0~focal) focal; urgency=high * rebuild for vdr-2.4.5 diff -Nru vdr-plugin-music-0.9.9/debian/control vdr-plugin-music-0.9.9/debian/control --- vdr-plugin-music-0.9.9/debian/control 2020-11-26 21:38:22.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/control 2020-11-26 22:09:00.000000000 +0000 @@ -3,7 +3,7 @@ Priority: extra Maintainer: easyVDR-Developer Uploaders: Wolfgang Mangold -Build-Depends: debhelper (>= 7.0.50~), vdr-dev (>= 1.7.21), cdbs, gettext, pkg-config, libsndfile1-dev, libmad0-dev, libid3tag0-dev, libogg-dev, libvorbis-dev, libmagick++-dev, graphicsmagick-libmagick-dev-compat, libasound2-dev, libid3-dev, libwebp-dev +Build-Depends: debhelper (>= 7.0.50~), vdr-dev (>= 2.2.0-1), cdbs, gettext, pkg-config, libsndfile1-dev, libmad0-dev, libid3tag0-dev, libogg-dev, libvorbis-dev, libmagick++-dev, graphicsmagick-libmagick-dev-compat, libasound2-dev, libid3-dev, libwebp-dev Standards-Version: 3.8.4 Homepage: http://www.vdr.glaserei-franz.de/vdrplugins.htm diff -Nru vdr-plugin-music-0.9.9/debian/patches/01_skindesigner-menu.diff vdr-plugin-music-0.9.9/debian/patches/01_skindesigner-menu.diff --- vdr-plugin-music-0.9.9/debian/patches/01_skindesigner-menu.diff 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/patches/01_skindesigner-menu.diff 2016-12-26 23:23:43.000000000 +0000 @@ -0,0 +1,62 @@ +Index: vdr-plugin-music-0.9.9/commands.c +=================================================================== +--- vdr-plugin-music-0.9.9.orig/commands.c 2016-12-27 00:22:53.111213787 +0100 ++++ vdr-plugin-music-0.9.9/commands.c 2016-12-27 00:22:53.051213490 +0100 +@@ -296,7 +296,7 @@ + + + cMP3Themes::cMP3Themes(void) +-:cOsdMenu(tr("Music: Appearance"),4) ++:cOsdMenu(tr("Music: Appearance"),32) + { + + LoadSkinFiles(); +@@ -462,7 +462,7 @@ + + + cMP3Visual::cMP3Visual(void) +-:cOsdMenu(tr("Music: Visualizations"),4) ++:cOsdMenu(tr("Music: Visualizations"),32) + { + Add(new cOsdItem(hk(tr("Disable visualization")))); + LoadVisFiles(); +@@ -614,7 +614,7 @@ + + + cMP3User::cMP3User(void) +-:cOsdMenu(tr("Music: User"),4) ++:cOsdMenu(tr("Music: User"),32) + { + LoadUsername(); + SetHelp(); +Index: vdr-plugin-music-0.9.9/music-0.9.9/commands.c +=================================================================== +--- vdr-plugin-music-0.9.9.orig/music-0.9.9/commands.c 2016-12-27 00:22:53.111213787 +0100 ++++ vdr-plugin-music-0.9.9/music-0.9.9/commands.c 2016-12-27 00:22:53.067213569 +0100 +@@ -296,7 +296,7 @@ + + + cMP3Themes::cMP3Themes(void) +-:cOsdMenu(tr("Music: Appearance"),4) ++:cOsdMenu(tr("Music: Appearance"),32) + { + + LoadSkinFiles(); +@@ -462,7 +462,7 @@ + + + cMP3Visual::cMP3Visual(void) +-:cOsdMenu(tr("Music: Visualizations"),4) ++:cOsdMenu(tr("Music: Visualizations"),32) + { + Add(new cOsdItem(hk(tr("Disable visualization")))); + LoadVisFiles(); +@@ -614,7 +614,7 @@ + + + cMP3User::cMP3User(void) +-:cOsdMenu(tr("Music: User"),4) ++:cOsdMenu(tr("Music: User"),32) + { + LoadUsername(); + SetHelp(); diff -Nru vdr-plugin-music-0.9.9/debian/patches/02_graphicsmagick.patch vdr-plugin-music-0.9.9/debian/patches/02_graphicsmagick.patch --- vdr-plugin-music-0.9.9/debian/patches/02_graphicsmagick.patch 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/patches/02_graphicsmagick.patch 2019-01-29 19:03:38.000000000 +0000 @@ -0,0 +1,22 @@ +--- a/Makefile ++++ b/Makefile +@@ -9,7 +9,7 @@ + + # (Default) DO NOT UNCOMMENT IT IN DEVELOPER-VERSIONS + HAVE_IMAGEMAGICK=1 +-IMAGEMAGICKDIR=/usr/include/ImageMagick ++#IMAGEMAGICKDIR=/usr/include/ImageMagick + + # Uncomment the following line, if you don't have libsndfile installed + #WITHOUT_LIBSNDFILE=1 +@@ -138,8 +138,8 @@ + #endif + + ifdef HAVE_IMAGEMAGICK +- INCLUDES += -I$(IMAGEMAGICKDIR) +- LIBS += $(shell Magick++-config --libs) ++ INCLUDES += $(shell pkg-config --cflags GraphicsMagick++) ++ LIBS += $(shell pkg-config --libs GraphicsMagick++) + DEFINES += -DHAVE_IMAGEMAGICK + else + INCLUDES += -I$(IMLIB)/src diff -Nru vdr-plugin-music-0.9.9/debian/patches/menu.diff vdr-plugin-music-0.9.9/debian/patches/menu.diff --- vdr-plugin-music-0.9.9/debian/patches/menu.diff 2016-12-26 23:23:43.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/patches/menu.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -Index: vdr-plugin-music-0.9.9/commands.c -=================================================================== ---- vdr-plugin-music-0.9.9.orig/commands.c 2016-12-27 00:22:53.111213787 +0100 -+++ vdr-plugin-music-0.9.9/commands.c 2016-12-27 00:22:53.051213490 +0100 -@@ -296,7 +296,7 @@ - - - cMP3Themes::cMP3Themes(void) --:cOsdMenu(tr("Music: Appearance"),4) -+:cOsdMenu(tr("Music: Appearance"),32) - { - - LoadSkinFiles(); -@@ -462,7 +462,7 @@ - - - cMP3Visual::cMP3Visual(void) --:cOsdMenu(tr("Music: Visualizations"),4) -+:cOsdMenu(tr("Music: Visualizations"),32) - { - Add(new cOsdItem(hk(tr("Disable visualization")))); - LoadVisFiles(); -@@ -614,7 +614,7 @@ - - - cMP3User::cMP3User(void) --:cOsdMenu(tr("Music: User"),4) -+:cOsdMenu(tr("Music: User"),32) - { - LoadUsername(); - SetHelp(); -Index: vdr-plugin-music-0.9.9/music-0.9.9/commands.c -=================================================================== ---- vdr-plugin-music-0.9.9.orig/music-0.9.9/commands.c 2016-12-27 00:22:53.111213787 +0100 -+++ vdr-plugin-music-0.9.9/music-0.9.9/commands.c 2016-12-27 00:22:53.067213569 +0100 -@@ -296,7 +296,7 @@ - - - cMP3Themes::cMP3Themes(void) --:cOsdMenu(tr("Music: Appearance"),4) -+:cOsdMenu(tr("Music: Appearance"),32) - { - - LoadSkinFiles(); -@@ -462,7 +462,7 @@ - - - cMP3Visual::cMP3Visual(void) --:cOsdMenu(tr("Music: Visualizations"),4) -+:cOsdMenu(tr("Music: Visualizations"),32) - { - Add(new cOsdItem(hk(tr("Disable visualization")))); - LoadVisFiles(); -@@ -614,7 +614,7 @@ - - - cMP3User::cMP3User(void) --:cOsdMenu(tr("Music: User"),4) -+:cOsdMenu(tr("Music: User"),32) - { - LoadUsername(); - SetHelp(); diff -Nru vdr-plugin-music-0.9.9/debian/patches/music_ggc-7_fix.patch vdr-plugin-music-0.9.9/debian/patches/music_ggc-7_fix.patch --- vdr-plugin-music-0.9.9/debian/patches/music_ggc-7_fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/debian/patches/music_ggc-7_fix.patch 2017-12-06 20:21:37.000000000 +0000 @@ -0,0 +1,15 @@ +--- a/player-mp3.c ++++ b/player-mp3.c +@@ -1727,10 +1727,10 @@ + int channels=2; + CHECK(ioctl(fd,SNDCTL_DSP_CHANNELS,&channels)); + if(channels==2) { +- int real=sr; ++ int real = (int) sr; + CHECK(ioctl(fd,SNDCTL_DSP_SPEED,&real)); + d(printf("music: oss: DSP samplerate now %d\n",real)) +- if(abs(real-sr) +#include + +#include +#include +#include +#include + +#include "commands.h" +#include "i18n.h" +#include "player-mp3.h" +#include "decoder.h" +#include "skin.h" +#include "search.h" +#include "mp3id3.h" +#include "mp3id3tag.h" +#include "lyrics.h" +#include "cover.h" +#include "visual.h" +#include "options.h" +#include "vars.h" + +#define X_DISPLAY_MISSING +#define MAXLENGTH 256 +#define THEMESEXT "*.theme" +#define VISEXT "*.visual" +#define FINDCMD "cd '%s' && find '%s' -iname '%s' -printf '%%p\n' | sort -f" + +char urlname[256]; + +//---------------- cMP3UpdateWebStreams -------------------------------------------------------------------------------------------------------------------------- + + +class cMP3UpdateWebStreams : public cOsdMenu { +private: + cCommands commands; +// cOsdItem *Item(const char *name, const char *text); + void SetHelp(); + void ShowDisplay(void); + void UpdateGenre(); + eOSState Execute(void); + int limits, bitrate; + const char *bitrates[10]; +public: + cMP3UpdateWebStreams(void); + virtual ~cMP3UpdateWebStreams(); + virtual eOSState ProcessKey(eKeys Key); + void LoadCommand(); +}; + + +cMP3UpdateWebStreams::cMP3UpdateWebStreams(void) +:cOsdMenu(tr("Music: Update webstreams"),32) +{ + limits = MP3Setup.ShoutcastLimit; + bitrate = 192; +// bitrates = MP3Setup.ShoutcastBitrate; + + ShowDisplay(); +/* + Add(new cMenuEditIntItem(tr("Limit for stations"), &limits, 0 , 100)); + Add(new cMenuEditIntItem(tr("Bitrate for stations"), &bitrates, 0 , 100)); + + SetHelp(); + + LoadCommand(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } +*/ +} + +cMP3UpdateWebStreams::~cMP3UpdateWebStreams() +{ +} + +void cMP3UpdateWebStreams::ShowDisplay(void) +{ + Clear(); + Add(new cMenuEditIntItem(tr("Limit for Shoutcast"), &limits, 0 , 100)); + + bitrates[0]="32"; + bitrates[1]="48"; + bitrates[2]="56"; + bitrates[3]="64"; + bitrates[4]="96"; + bitrates[5]="128"; + bitrates[6]="160"; + bitrates[7]="192"; + bitrates[8]="256"; + bitrates[9]="320"; + Add(new cMenuEditStraItem(tr("Bitrate for Shoutcast"), &MP3Setup.ShoutcastBitrate, 10 , bitrates)); + Add(new cOsdItem(hk(tr("Update Genres")))); + + + LoadCommand(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } + + SetHelp(); + Display(); +} + +void cMP3UpdateWebStreams::SetHelp() { + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3UpdateWebStreams::LoadCommand() { + + std::string lingual; + + lingual = langdir; + lingual = lingual + "/data/shoutcast.dat"; + + commands.Load(AddDirectory(config, lingual.c_str()), true); +#ifdef DEBUG + isyslog("music: commands: load shoutcast.dat '%s%s'",config, lingual.c_str()); +#endif +} + + +void cMP3UpdateWebStreams::UpdateGenre() +{ + std::string datei; + + datei = config; + datei = datei + langdir; + datei = datei + "/scripts/music_updategenre.pl '"; + datei = datei + MP3Setup.WebstreamDat + "' '10' '192'"; + + Skins.Message(mtStatus, tr("Refreshing Genres")); + FILE *updatecmd; + updatecmd = popen(datei.c_str(), "r"); + pclose(updatecmd); + +#ifdef DEBUG + isyslog("music: commands: update genres '%s'", datei.c_str()); +#endif + + Display(); +} + + +eOSState cMP3UpdateWebStreams::Execute(void) { + + int ItemIndex = Current(); + if (ItemIndex <= 1) return osContinue; + + if (ItemIndex == 2) { + UpdateGenre(); + return osBack; + } + + + int parbit = MP3Setup.ShoutcastBitrate; + + switch(parbit) { + case 0: bitrate = 32; break; + case 1: bitrate = 48; break; + case 2: bitrate = 56; break; + case 3: bitrate = 64; break; + case 4: bitrate = 96; break; + case 5: bitrate = 128; break; + case 6: bitrate = 160; break; + case 7: bitrate = 192; break; + case 8: bitrate = 256; break; + case 9: bitrate = 320; break; + default : break; + } + + + cCommand *command = commands.Get(Current() -3); + if (command) { + char *buffer = NULL; + bool confirmed = true; + + if (command->Confirm()) { + if (asprintf(&buffer, "%s?", command->Title()) == -1) { + fprintf(stderr, "Failed to allocate string for command-Title"); + return osBack; + } + confirmed = Interface->Confirm(buffer); + free(buffer); + } + if (confirmed) { + if (asprintf(&buffer, "%s...", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command-Title"); + + Skins.Message(mtStatus, buffer); + free(buffer); + + char *parameters; + if (asprintf(¶meters, " '%d' '%d' '%s';", limits, bitrate, MP3Setup.WebstreamDat) == -1) + fprintf(stderr, "Failed to allocate string"); + + const char *Result = command->Execute(parameters); + free(parameters); + + Skins.Message(mtStatus, NULL); + if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); + return osBack; + } + } + + return osContinue; +} + + +eOSState cMP3UpdateWebStreams::ProcessKey(eKeys Key) { + + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: state = osBack; + case kGreen: + case kYellow: + case kBlue: state = osContinue; + case kOk: state = Execute(); + default: state = osContinue; + } + } + + return state; +} + + + +// ------------ cMP3ThemesItem ----------------------------------------------------------------------------------------------- // + +class cMP3ThemesItem : public cOsdItem { +private: + cFileObjItem *item; + virtual void Set(void); + int idx; +public: + cMP3ThemesItem(cFileObjItem *Item, int index); + cFileObjItem *Item(void) {return item;} + ~cMP3ThemesItem(); +}; + + +cMP3ThemesItem::cMP3ThemesItem(cFileObjItem *Item, int index) { + idx = index; + item = Item; + Set(); +} + +cMP3ThemesItem::~cMP3ThemesItem(){ +} + +void cMP3ThemesItem::Set(void) { + char *Name; + + if (asprintf(&Name,"%s", item->Name()) == -1) + fprintf(stderr, "Failed to allocate string for item->Name()"); + + SetText(Name,false); +} + + +// ------------ cMP3Themes --------------------------------------------------------------------------------------------------- // + +class cMP3Themes : public cOsdMenu { +private: + void SetHelp(); + void LoadSkinFiles(); + eOSState SetTheme(void); + cFileObjItem *newitem; +protected: + cFileObjItem *CurrentFileObjItem(void); +public: + cMP3Themes(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3Themes::cMP3Themes(void) +:cOsdMenu(tr("Music: Appearance"),4) +{ + + LoadSkinFiles(); + SetHelp(); +} + +void cMP3Themes::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3Themes::LoadSkinFiles() +{ + int count = 0; + + char *cmd = NULL; + cReadLine reader; + + std::string plugindir; + std::string themename; + std::string themefile; + std::string Base; + + plugindir = config; + plugindir = plugindir + "/themes/"; + +#ifdef DEBUG + isyslog("music: commands: load themes from '%s'", plugindir.c_str()); +#endif + + int len2 = plugindir.length()+1; + + + if (asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), THEMESEXT) == -1) + fprintf(stderr, "Failed to allocate string"); + + FILE *p = popen(cmd, "r"); + + if(p) { + char *s; + while ((s = reader.Read(p)) != NULL) { + count++; + themefile = s; + int len = themefile.length(); + std::string::size_type pos = themefile.rfind('/',len); + if(pos!=std::string::npos) { + // Filename + themename = themefile.substr(pos+1,len); + // Basedir + int sublen = len - len2 - themename.length()-1; + Base = themefile.substr(len2,sublen); + } + newitem = new cFileObjItem(plugindir.c_str(), themename.c_str(), otFile); + if(newitem && newitem->Type()==otFile) { + Add(new cMP3ThemesItem(newitem, count)); + } + } + pclose(p); + } + else + Skins.Message(mtError, tr("ERROR: Havent found any themes !")); + + free(cmd); +} + +cFileObjItem *cMP3Themes::CurrentFileObjItem(void) +{ + cMP3ThemesItem *item = (cMP3ThemesItem *)Get(Current()); + return item ? item->Item():0; +} + + +eOSState cMP3Themes::SetTheme(void) +{ + cFileObjItem *item=CurrentFileObjItem(); + + if(item && item->Type()==otFile) { + if(MP3Skin.StoreSkin(item->Name())) { + MP3Skin.ParseSkin("current.colors"); + MP3Skin.ReloadFonts=1; + return osBack; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not store/load new themefile !"), fontFix)); + } + + return osContinue; +} + + +eOSState cMP3Themes::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetTheme(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + + +// ------------ cMP3VisualItem --------------------------------------------------------------------------------------------- // + +class cMP3VisualItem : public cOsdItem { +private: + cFileObjItem *item; + virtual void Set(void); + int idx; +public: + cMP3VisualItem(cFileObjItem *Item, int index); + cFileObjItem *Item(void) {return item;} + ~cMP3VisualItem(); +}; + + +cMP3VisualItem::cMP3VisualItem(cFileObjItem *Item, int index) +{ + idx = index; + item = Item; + Set(); +} + +cMP3VisualItem::~cMP3VisualItem() +{ +} + +void cMP3VisualItem::Set(void) +{ + char *Name; + + if(asprintf(&Name,"%s", item->Name()) == -1) + fprintf(stderr, "Failed to allocate string for item->Name()"); + + SetText(Name,false); +} + + +// ------------ cMP3Visual ------------------------------------------------------------------------------------------------- // + +class cMP3Visual : public cOsdMenu { +private: + void SetHelp(); + void LoadVisFiles(); + eOSState SetVis(void); + cFileObjItem *newitem; +protected: + cFileObjItem *CurrentFileObjItem(void); +public: + cMP3Visual(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3Visual::cMP3Visual(void) +:cOsdMenu(tr("Music: Visualizations"),4) +{ + Add(new cOsdItem(hk(tr("Disable visualization")))); + LoadVisFiles(); + SetHelp(); +} + +void cMP3Visual::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3Visual::LoadVisFiles() +{ + int count = 0; + + char *cmd = NULL; + cReadLine reader; + + std::string plugindir; + std::string visname; + std::string visfile; + std::string visBase; + + plugindir = config; + plugindir = plugindir + "/visual/themes/"; + +#ifdef DEBUG + isyslog("music: commands: load visfiles from '%s'", plugindir.c_str()); +#endif + + int len2 = plugindir.length()+1; + + + if(asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), VISEXT) == -1) + fprintf(stderr, "Failed to allocate string"); + + FILE *p = popen(cmd, "r"); + + if(p) { + char *s; + while ((s = reader.Read(p)) != NULL) { + count++; + visfile = s; + int len = visfile.length(); + std::string::size_type pos = visfile.rfind('/',len); + if(pos!=std::string::npos) { + // Filename + visname = visfile.substr(pos+1,len); + // Basedir + int sublen = len - len2 - visname.length()-1; + visBase = visfile.substr(len2,sublen); + } + newitem = new cFileObjItem(plugindir.c_str(), visname.c_str(), otFile); + if(newitem && newitem->Type()==otFile) { + Add(new cMP3VisualItem(newitem, count)); + } + } + pclose(p); + } + else + Skins.Message(mtError, tr("ERROR: Cant find any visualization!")); + + free(cmd); +} + +cFileObjItem *cMP3Visual::CurrentFileObjItem(void) +{ + cMP3VisualItem *item = (cMP3VisualItem *)Get(Current()); + return item ? item->Item():0; +} + + +eOSState cMP3Visual::SetVis(void) +{ + int ItemIndex = Current(); + cFileObjItem *item=CurrentFileObjItem(); + + if(ItemIndex == 0) { + MP3Setup.EnableVis = false; + std::string file; + if(!MP3Setup.isWebstream) { + file = config; + file = file + "/themes/defaultcover/music-default-cover.png"; + strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); + } + else { + file = config; + file = file + "/themes/defaultcover/music-default-stream.png"; + strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); + } + return osBack; + } + else if (ItemIndex >= 1) { + if(item && item->Type()==otFile) { + if(MP3VisLoader.LoadVis(item->Name())) { + MP3Setup.EnableVis = true; + MP3VisLoader.SetVis(); + strncpy(coverpicture,MP3VisLoader.VisLoaderBackground(),sizeof(coverpicture)); + + if(MP3VisLoader.StoreVis(item->Name())) + isyslog("music: stored '%s' as 'current.vis'\n", item->Name()); + else + esyslog("music: could not store '%s' as 'current.vis'\n", item->Name()); + + return osBack; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not load new visualization !"), fontFix)); + } + } + + return osContinue; +} + + +eOSState cMP3Visual::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetVis(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + +// ------------ cMP3User --------------------------------------------------------------------------------------------------- // + +class cMP3User : public cOsdMenu { +private: + void SetHelp(); + void LoadUsername(); + eOSState SetUser(void); + cOsdItem *Item(const char *text); +public: + cMP3User(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3User::cMP3User(void) +:cOsdMenu(tr("Music: User"),4) +{ + LoadUsername(); + SetHelp(); +} + +void cMP3User::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +cOsdItem *cMP3User::Item(const char *text) +{ + char *buf=0; + if(asprintf(&buf, "%s",text?text:"") == -1) + fprintf(stderr, "Failed to allocate string for text"); + + cOsdItem *item = new cOsdItem(buf,osUnknown,true); + free(buf); + Add(item); return item; +} + +void cMP3User::LoadUsername() +{ + std::ifstream filestr; + std::string userfile; + std::string line; + + userfile = config; + userfile = userfile + "/data/user.dat"; + +#ifdef DEBUG + isyslog("music: commands: load user.dat from '%s'", userfile.c_str()); +#endif + + filestr.open(userfile.c_str()); + + if(filestr) { + while ((getline(filestr,line,'\n'))) { + Item(line.c_str()); + } + filestr.close(); + } +} + + +eOSState cMP3User::SetUser(void) +{ + cOsdItem *item=(cOsdItem*)Get(Current()); + + std::string datei; + datei = config; + datei = datei + "/data/current_user.dat"; + +#ifdef DEBUG + isyslog("music: commands: load current_user.dat from '%s'", datei.c_str()); +#endif + + + if(item) { + if(Interface->Confirm(tr("Change user (Music will be stopped) ?")) ) { + InfoCache.Save(true); + if( FILE *f = fopen ( datei.c_str(), "w")) { + std::string user; + user = item->Text(); + fprintf(f, "%s\n", user.c_str()); + isyslog("music: change to user <%s>\n", user.c_str()); + fclose(f); + InfoCache.Load(true); + } + return osEnd; + } + + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not change user !"), fontFix)); + + return osContinue; +} + + +eOSState cMP3User::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetUser(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + + +// ------------ cMP3EditPlaylist ---------------------------------------------------------------------------------------------- // + +cMP3EditPlaylist::cMP3EditPlaylist(const char *sz_Title) +:cOsdMenu(tr(sz_Title)) +{ +//0 + Add(new cOsdItem(hk(tr("Remove track from playlist")))); +//1 + Add(new cOsdItem(hk(tr("Remove all from playlist")))); +//2 + Add(new cOsdItem(hk(tr("Save active playlist")))); + + if(MP3Setup.AdminMode >= 2) { + +//3 + cOsdItem *item = new cOsdItem(hk("")); + Add(item, osUnknown); + item->SetSelectable(false); + +//4 + Add(new cOsdItem(hk(tr("Delete selected track from medium")))); +//5 + Add(new cOsdItem(hk(tr("Delete all tracks in playlist from medium")))); + } + + + SetHelp(); +} + + +void cMP3EditPlaylist::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +eOSState cMP3EditPlaylist::Execute(void) +{ + + int ItemIndex = Current(); + +//0/ Delete Track from playlist and save as current playlist in ConfigDir;; + if (ItemIndex == 0) { + + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); + + + if(MP3Setup.AdminMode >= 1) { + + if (mgr->maxIndex==0) + MP3Setup.DeleteTracks = 1; + else + MP3Setup.DeleteTrack = 1; + + return osBack; + } + else { + if(Interface->Confirm(tr("Remove track from playlist ?")) && Interface->Confirm(tr("Are you sure?")) ) { + if (mgr->maxIndex==0) + MP3Setup.DeleteTracks = 1; + else + MP3Setup.DeleteTrack = 1; + + return osBack; + } + } + } + + + +//1/ Empty playlist;; + if (ItemIndex == 1) { + if(MP3Setup.AdminMode >= 1) { + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + if(Interface->Confirm(tr("Remove all tracks from playlist ?")) ) { + Skins.Message(mtStatus, tr("Remove all tracks from playlist...")); + MP3Setup.DeleteTracks = 1; + Skins.Message(mtStatus, NULL); + return osBack; + } + } + } + + +//2/ Save playlist for burn..something with full path in ConfigDir;; + if (ItemIndex == 2) { + if(MP3Setup.AdminMode >= 1) { + Skins.Message(mtStatus, tr("Save playlist...")); + char *buf=0; + if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) + fprintf(stderr, "Failed to allocate string"); +#ifdef DEBUG + isyslog("music: commands: save playlust to '%s'", buf); +#endif + bool Result = mgr->SaveList(buf, true); + Skins.Message(mtStatus, NULL); + free(buf); + if (Result) + return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); + } + else { + if(Interface->Confirm(tr("Overwrite last playlist ?")) ) { + Skins.Message(mtStatus, tr("Save playlist...")); + char *buf=0; + if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) + fprintf(stderr, "Failed to allocate string"); +#ifdef DEBUG + isyslog("music: commands: save playlist to '%s'", buf); +#endif + bool Result = mgr->SaveList(buf, true); + Skins.Message(mtStatus, NULL); + free(buf); + if (Result) + return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); + } + } + } + + +//3/ Delete file from medium + if(MP3Setup.AdminMode >=1) { + if (ItemIndex == 4) { + + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); + + if(MP3Setup.AdminMode == 2) { + if (mgr->maxIndex==0) { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTrack = 1; + return osBack; + } + } + else { + if(Interface->Confirm(tr("Delete file from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { + if (mgr->maxIndex==0) { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTrack = 1; + return osBack; + } + } + } + } + + +//4/ Delete everything in playlist from medium + if (ItemIndex == 5) { + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove tracks !"), fontFix)); + + + if(Interface->Confirm(tr("Delete all in playlist from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { + Skins.Message(mtStatus, tr("Delete all tracks from medium...")); + bool Result = DeleteList(); + Skins.Message(mtStatus, NULL); + if (Result) { + return AddSubMenu(new cMenuText(tr("Delete"), tr("Tracks terminated !"), fontFix)); + MP3Setup.DeleteTracks = 1; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not delete tracks !"), fontFix)); + } + } + + } + + return osContinue; +} + +eOSState cMP3EditPlaylist::ProcessKey(eKeys Key) +{ + + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: + return osBack; + break; + case kOk: + return Execute(); + break; + default: + state = osContinue; + } + } + + return state; +} + + +bool cMP3EditPlaylist::DeleteList(void) +{ + std::ifstream filestr; + std::string datei; + std::string line; + int count=0; + bool res = false; + + datei=config; + datei=datei + "/playlists/deletelist.m3u"; + +#ifdef DEBUG + isyslog("music: commands: get deletelist.m3u from '%s'", datei.c_str()); +#endif + + if(mgr->SaveList(datei.c_str(), true)) { + filestr.open (datei.c_str()); + while ((getline(filestr,line,'\n'))) { + count++; + isyslog("music: delete file : %i %s\n",count,line.c_str()); + RemoveFileOrDir(line.c_str(), false); + } + filestr.close(); + res = true; + } + + return res; +} + + + +// ------------ cMP3Commands --------------------------------------------------------------------------------------------------- // + +cMP3Commands::cMP3Commands(void) +:cOsdMenu(tr("Music: Commands")) +{ +/* 0*/ Add(new cOsdItem(hk(tr("Edit playlist...")))); +/* 1*/ Add(new cOsdItem(hk(tr("Search for songs...")))); +/* 2*/ Add(new cOsdItem(hk(tr("Show ID3 information of song")))); +/* 3*/ Add(new cOsdItem(hk(tr("Edit ID3 information")))); +/* 4*/ Add(new cOsdItem(hk(tr("Quick settings...")))); +/* 5*/ Add(new cOsdItem(hk(tr("Search for lyric...")))); +/* 6*/ Add(new cOsdItem(hk(tr("Download coverpicture...")))); +/* 7*/ Add(new cOsdItem(hk(tr("Update webstreams...")))); +/* 8*/ Add(new cOsdItem(hk(tr("Start imageviewer")))); +/* 9*/ if(!MP3Setup.RecordStream) + Add(new cOsdItem(hk(tr("Start Recording")))); + else + Add(new cOsdItem(hk(tr("Stop Recording")))); +/* 10*/ Add(new cOsdItem(hk(tr("Change Appearance...")))); +/* 11*/ Add(new cOsdItem(hk(tr("Visualizations...")))); +/* 12*/ Add(new cOsdItem(hk(tr("Change user...")))); + + + SetHelp(); + LoadCommands(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } + + Display(); +} + + +cMP3Commands::~cMP3Commands() +{ +} + +void cMP3Commands::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + +void cMP3Commands::LoadCommands() +{ + std::string datei; + datei = langdir; + datei = datei + "/data/musiccmds.dat"; +#ifdef DEBUG + isyslog("music: commands: load commands from '%s%s'", config, datei.c_str()); +#endif + commands.Load(AddDirectory(config, datei.c_str()), true); +} + + +eOSState cMP3Commands::Execute(void) +{ + int ItemIndex = Current(); + +//0/ Edit Playlist;; + if (ItemIndex == 0) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + else + return AddSubMenu(new cMP3EditPlaylist("Edit playlist...")); + } + + +//1/ Search;; + if (ItemIndex == 1) { + if(mgr->maxIndex >0) { + std::string artist =""; + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { songinfo = mgr->Current()->Info(); } + if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } + return AddSubMenu(new cMP3Search(artist.c_str())); + } + else { + return AddSubMenu(new cMP3Search("")); + } + } + + +//2/ Show ID3Info;; + if (ItemIndex == 2) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + if(mgr->Current()) { + return AddSubMenu(new cMP3SearchID3Info(mgr->curr)); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); + } + } + + +//3/ Edit ID3 Tags + if (ItemIndex == 3) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + if(mgr->Current() && MP3Setup.user_is_admin && (MP3Setup.AdminMode >=2)) { + return AddSubMenu(new cMP3id3Tag(mgr->curr)); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: no songinfo or not allowed !"), fontFix)); + } + + } + + +//4/ Some options/commands + if (ItemIndex == 4) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + else + return AddSubMenu(new cMP3Options()); + } + + +//5/ Show Lyrics;; + if (ItemIndex == 5) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + return AddSubMenu(new cMP3Lyrics()); + } + + + if (ItemIndex == 1) { + std::string artist =""; + if(mgr->maxIndex >0) { + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { songinfo = mgr->Current()->Info(); } + if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } + return AddSubMenu(new cMP3Search(artist.c_str())); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); + } + } + + +//6/ Download Cover;; + if (ItemIndex == 6) { + std::string::size_type pos; + std::string artist = ""; + std::string album = ""; + std::string title = ""; + std::string baseDir = ""; + std::string filename = ""; + std::string Filenoext= ""; + + if(mgr->maxIndex >=0) { + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { + songinfo = mgr->Current()->Info(); + } + + if(songinfo) { + if(songinfo->Artist) { + artist = songinfo->Artist; + } + if(songinfo->Album) { + album = songinfo->Album; + } + if(songinfo->Title) { + title = songinfo->Title; + } + + cSong *s = mgr->curr; + + if(s) { + filename = s->Fullname(); + // get dir + int len = filename.length(); + pos = filename.rfind("/",len); + if(pos != std::string::npos) { + baseDir = filename.substr(0, pos+1); + } + // get file w/o ext. + pos = filename.rfind(".",len); + if(pos != std::string::npos) { + Filenoext = filename.substr(0, pos+1); + } + } + return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); + } + } +// else { +// return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); +// } + } + + +//7/ Update Webstreams;; + if (ItemIndex == 7) { + return AddSubMenu(new cMP3UpdateWebStreams()); + } + +//8/ Open Imageviewer;; + if (ItemIndex == 8) { + cRemote::CallPlugin("picselshow"); + return (osPlugin); + } + + +//9/ Start<->Stop Recording;; + if (ItemIndex == 9) { + + if (MP3Setup.AdminMode >= 2) { + if (MP3Setup.RecordStream) { + StopRecord(); + return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); + } + else { + if (MP3Setup.isWebstream) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + StartRecord(); + return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); + } + } + else { + if(MP3Setup.RecordStream) { + if(Interface->Confirm(tr("Stop recording ?")) ) { + StopRecord(); + return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); + } + } + else { + if (MP3Setup.isWebstream) { + if(Interface->Confirm(tr("Start recording ?")) ) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + StartRecord(); + return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); + } + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); + } + } + } + + +//10/ Themes;; + if (ItemIndex == 10) { + return AddSubMenu(new cMP3Themes()); + } + + +//11/ Visualization;; + if (ItemIndex == 11) { + return AddSubMenu(new cMP3Visual()); + } + + +//12/ User;; + if (ItemIndex == 12) { + return AddSubMenu(new cMP3User()); + } + + + +// From NOW on execute usercommands;; + if (ItemIndex >= 13) { + cCommand *command = commands.Get(ItemIndex-13); + if (command) { + char *buffer = NULL; + bool confirmed = true; + + std::string Artist =""; + std::string Album =""; + std::string Coverdir =""; + + cSongInfo *si = mgr->Current()->Info(false); + if(!si) si = mgr->Current()->Info(); + if(si && si->Artist)Artist = si->Artist; + if(si && si->Album) Album = si->Album; + if (command->Confirm()) { + if(asprintf(&buffer, "%s?", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command->Title()"); + confirmed = Interface->Confirm(buffer); + free(buffer); + } + if (confirmed) { + if(asprintf(&buffer, "%s...", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command->Title()"); + Skins.Message(mtStatus, buffer); + free(buffer); + + if(asprintf(&buffer, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", Songname, MP3Setup.CopyDir, Artist.c_str(), Album.c_str(), MP3Setup.CoverDir, config) == -1) + fprintf(stderr, "Failed to allocate string"); + + const char *Result = command->Execute(buffer); + + d(printf("music: commands: Executed: '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: executed: '%s'\n", buffer); +#endif + free(buffer); + Skins.Message(mtStatus, NULL); + if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); + return osBack; + } + } + } + + return osContinue; +} + +// ------------------ STARTRECORD -----------------------// +void cMP3Commands::StartRecord(void) +{ + FILE *recordcmd; + char *buffer; + + std::string url; + url = "\""; + url = url + urlname; + url = url + "\""; + + + d(printf("music: commands: Started Recording\n")); + if(asprintf(&buffer, "screen -A -m -d -S RECORD /usr/bin/streamripper %s -d '%s' -w %s%s/data/parse_rules.txt %s", url.c_str(), MP3Setup.RecordDir, config, langdir, MP3Setup.RecordOpts) == -1) + fprintf(stderr, "Failed to allocate string"); + + recordcmd = popen(buffer, "r"); + d(printf("music: commands: Starting recording '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: starting recording '%s'", buffer); +#endif + pclose(recordcmd); + + free(buffer); + MP3Setup.RecordStream = 1; +} + +// ------------------ STOPRECORD -----------------------// +void cMP3Commands::StopRecord(void) +{ + FILE *stoprecordcmd; + char *buffer; + + d(printf("music: commands: Stopped Recording\n")); + if(asprintf(&buffer, "killall -15 streamripper") == -1) + fprintf(stderr, "Failed to allocate string"); + + stoprecordcmd = popen(buffer, "r"); + d(printf("music: commands: Stop recording '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: stop recording '%s'", buffer); +#endif + pclose(stoprecordcmd); + + free(buffer); + MP3Setup.RecordStream = 0; +} + +eOSState cMP3Commands::ProcessKey(eKeys Key) +{ + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: + return osBack; + break; + case kOk: + return Execute(); + break; + default: + state = osContinue; + } + } + + return state; +} diff -Nru vdr-plugin-music-0.9.9/.pc/01_skindesigner-menu.diff/music-0.9.9/commands.c vdr-plugin-music-0.9.9/.pc/01_skindesigner-menu.diff/music-0.9.9/commands.c --- vdr-plugin-music-0.9.9/.pc/01_skindesigner-menu.diff/music-0.9.9/commands.c 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/01_skindesigner-menu.diff/music-0.9.9/commands.c 2020-11-26 22:13:28.000000000 +0000 @@ -0,0 +1,1357 @@ + +#include +#include + +#include +#include +#include +#include + +#include "commands.h" +#include "i18n.h" +#include "player-mp3.h" +#include "decoder.h" +#include "skin.h" +#include "search.h" +#include "mp3id3.h" +#include "mp3id3tag.h" +#include "lyrics.h" +#include "cover.h" +#include "visual.h" +#include "options.h" +#include "vars.h" + +#define X_DISPLAY_MISSING +#define MAXLENGTH 256 +#define THEMESEXT "*.theme" +#define VISEXT "*.visual" +#define FINDCMD "cd '%s' && find '%s' -iname '%s' -printf '%%p\n' | sort -f" + +char urlname[256]; + +//---------------- cMP3UpdateWebStreams -------------------------------------------------------------------------------------------------------------------------- + + +class cMP3UpdateWebStreams : public cOsdMenu { +private: + cCommands commands; +// cOsdItem *Item(const char *name, const char *text); + void SetHelp(); + void ShowDisplay(void); + void UpdateGenre(); + eOSState Execute(void); + int limits, bitrate; + const char *bitrates[10]; +public: + cMP3UpdateWebStreams(void); + virtual ~cMP3UpdateWebStreams(); + virtual eOSState ProcessKey(eKeys Key); + void LoadCommand(); +}; + + +cMP3UpdateWebStreams::cMP3UpdateWebStreams(void) +:cOsdMenu(tr("Music: Update webstreams"),32) +{ + limits = MP3Setup.ShoutcastLimit; + bitrate = 192; +// bitrates = MP3Setup.ShoutcastBitrate; + + ShowDisplay(); +/* + Add(new cMenuEditIntItem(tr("Limit for stations"), &limits, 0 , 100)); + Add(new cMenuEditIntItem(tr("Bitrate for stations"), &bitrates, 0 , 100)); + + SetHelp(); + + LoadCommand(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } +*/ +} + +cMP3UpdateWebStreams::~cMP3UpdateWebStreams() +{ +} + +void cMP3UpdateWebStreams::ShowDisplay(void) +{ + Clear(); + Add(new cMenuEditIntItem(tr("Limit for Shoutcast"), &limits, 0 , 100)); + + bitrates[0]="32"; + bitrates[1]="48"; + bitrates[2]="56"; + bitrates[3]="64"; + bitrates[4]="96"; + bitrates[5]="128"; + bitrates[6]="160"; + bitrates[7]="192"; + bitrates[8]="256"; + bitrates[9]="320"; + Add(new cMenuEditStraItem(tr("Bitrate for Shoutcast"), &MP3Setup.ShoutcastBitrate, 10 , bitrates)); + Add(new cOsdItem(hk(tr("Update Genres")))); + + + LoadCommand(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } + + SetHelp(); + Display(); +} + +void cMP3UpdateWebStreams::SetHelp() { + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3UpdateWebStreams::LoadCommand() { + + std::string lingual; + + lingual = langdir; + lingual = lingual + "/data/shoutcast.dat"; + + commands.Load(AddDirectory(config, lingual.c_str()), true); +#ifdef DEBUG + isyslog("music: commands: load shoutcast.dat '%s%s'",config, lingual.c_str()); +#endif +} + + +void cMP3UpdateWebStreams::UpdateGenre() +{ + std::string datei; + + datei = config; + datei = datei + langdir; + datei = datei + "/scripts/music_updategenre.pl '"; + datei = datei + MP3Setup.WebstreamDat + "' '10' '192'"; + + Skins.Message(mtStatus, tr("Refreshing Genres")); + FILE *updatecmd; + updatecmd = popen(datei.c_str(), "r"); + pclose(updatecmd); + +#ifdef DEBUG + isyslog("music: commands: update genres '%s'", datei.c_str()); +#endif + + Display(); +} + + +eOSState cMP3UpdateWebStreams::Execute(void) { + + int ItemIndex = Current(); + if (ItemIndex <= 1) return osContinue; + + if (ItemIndex == 2) { + UpdateGenre(); + return osBack; + } + + + int parbit = MP3Setup.ShoutcastBitrate; + + switch(parbit) { + case 0: bitrate = 32; break; + case 1: bitrate = 48; break; + case 2: bitrate = 56; break; + case 3: bitrate = 64; break; + case 4: bitrate = 96; break; + case 5: bitrate = 128; break; + case 6: bitrate = 160; break; + case 7: bitrate = 192; break; + case 8: bitrate = 256; break; + case 9: bitrate = 320; break; + default : break; + } + + + cCommand *command = commands.Get(Current() -3); + if (command) { + char *buffer = NULL; + bool confirmed = true; + + if (command->Confirm()) { + if (asprintf(&buffer, "%s?", command->Title()) == -1) { + fprintf(stderr, "Failed to allocate string for command-Title"); + return osBack; + } + confirmed = Interface->Confirm(buffer); + free(buffer); + } + if (confirmed) { + if (asprintf(&buffer, "%s...", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command-Title"); + + Skins.Message(mtStatus, buffer); + free(buffer); + + char *parameters; + if (asprintf(¶meters, " '%d' '%d' '%s';", limits, bitrate, MP3Setup.WebstreamDat) == -1) + fprintf(stderr, "Failed to allocate string"); + + const char *Result = command->Execute(parameters); + free(parameters); + + Skins.Message(mtStatus, NULL); + if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); + return osBack; + } + } + + return osContinue; +} + + +eOSState cMP3UpdateWebStreams::ProcessKey(eKeys Key) { + + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: state = osBack; + case kGreen: + case kYellow: + case kBlue: state = osContinue; + case kOk: state = Execute(); + default: state = osContinue; + } + } + + return state; +} + + + +// ------------ cMP3ThemesItem ----------------------------------------------------------------------------------------------- // + +class cMP3ThemesItem : public cOsdItem { +private: + cFileObjItem *item; + virtual void Set(void); + int idx; +public: + cMP3ThemesItem(cFileObjItem *Item, int index); + cFileObjItem *Item(void) {return item;} + ~cMP3ThemesItem(); +}; + + +cMP3ThemesItem::cMP3ThemesItem(cFileObjItem *Item, int index) { + idx = index; + item = Item; + Set(); +} + +cMP3ThemesItem::~cMP3ThemesItem(){ +} + +void cMP3ThemesItem::Set(void) { + char *Name; + + if (asprintf(&Name,"%s", item->Name()) == -1) + fprintf(stderr, "Failed to allocate string for item->Name()"); + + SetText(Name,false); +} + + +// ------------ cMP3Themes --------------------------------------------------------------------------------------------------- // + +class cMP3Themes : public cOsdMenu { +private: + void SetHelp(); + void LoadSkinFiles(); + eOSState SetTheme(void); + cFileObjItem *newitem; +protected: + cFileObjItem *CurrentFileObjItem(void); +public: + cMP3Themes(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3Themes::cMP3Themes(void) +:cOsdMenu(tr("Music: Appearance"),4) +{ + + LoadSkinFiles(); + SetHelp(); +} + +void cMP3Themes::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3Themes::LoadSkinFiles() +{ + int count = 0; + + char *cmd = NULL; + cReadLine reader; + + std::string plugindir; + std::string themename; + std::string themefile; + std::string Base; + + plugindir = config; + plugindir = plugindir + "/themes/"; + +#ifdef DEBUG + isyslog("music: commands: load themes from '%s'", plugindir.c_str()); +#endif + + int len2 = plugindir.length()+1; + + + if (asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), THEMESEXT) == -1) + fprintf(stderr, "Failed to allocate string"); + + FILE *p = popen(cmd, "r"); + + if(p) { + char *s; + while ((s = reader.Read(p)) != NULL) { + count++; + themefile = s; + int len = themefile.length(); + std::string::size_type pos = themefile.rfind('/',len); + if(pos!=std::string::npos) { + // Filename + themename = themefile.substr(pos+1,len); + // Basedir + int sublen = len - len2 - themename.length()-1; + Base = themefile.substr(len2,sublen); + } + newitem = new cFileObjItem(plugindir.c_str(), themename.c_str(), otFile); + if(newitem && newitem->Type()==otFile) { + Add(new cMP3ThemesItem(newitem, count)); + } + } + pclose(p); + } + else + Skins.Message(mtError, tr("ERROR: Havent found any themes !")); + + free(cmd); +} + +cFileObjItem *cMP3Themes::CurrentFileObjItem(void) +{ + cMP3ThemesItem *item = (cMP3ThemesItem *)Get(Current()); + return item ? item->Item():0; +} + + +eOSState cMP3Themes::SetTheme(void) +{ + cFileObjItem *item=CurrentFileObjItem(); + + if(item && item->Type()==otFile) { + if(MP3Skin.StoreSkin(item->Name())) { + MP3Skin.ParseSkin("current.colors"); + MP3Skin.ReloadFonts=1; + return osBack; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not store/load new themefile !"), fontFix)); + } + + return osContinue; +} + + +eOSState cMP3Themes::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetTheme(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + + +// ------------ cMP3VisualItem --------------------------------------------------------------------------------------------- // + +class cMP3VisualItem : public cOsdItem { +private: + cFileObjItem *item; + virtual void Set(void); + int idx; +public: + cMP3VisualItem(cFileObjItem *Item, int index); + cFileObjItem *Item(void) {return item;} + ~cMP3VisualItem(); +}; + + +cMP3VisualItem::cMP3VisualItem(cFileObjItem *Item, int index) +{ + idx = index; + item = Item; + Set(); +} + +cMP3VisualItem::~cMP3VisualItem() +{ +} + +void cMP3VisualItem::Set(void) +{ + char *Name; + + if(asprintf(&Name,"%s", item->Name()) == -1) + fprintf(stderr, "Failed to allocate string for item->Name()"); + + SetText(Name,false); +} + + +// ------------ cMP3Visual ------------------------------------------------------------------------------------------------- // + +class cMP3Visual : public cOsdMenu { +private: + void SetHelp(); + void LoadVisFiles(); + eOSState SetVis(void); + cFileObjItem *newitem; +protected: + cFileObjItem *CurrentFileObjItem(void); +public: + cMP3Visual(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3Visual::cMP3Visual(void) +:cOsdMenu(tr("Music: Visualizations"),4) +{ + Add(new cOsdItem(hk(tr("Disable visualization")))); + LoadVisFiles(); + SetHelp(); +} + +void cMP3Visual::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +void cMP3Visual::LoadVisFiles() +{ + int count = 0; + + char *cmd = NULL; + cReadLine reader; + + std::string plugindir; + std::string visname; + std::string visfile; + std::string visBase; + + plugindir = config; + plugindir = plugindir + "/visual/themes/"; + +#ifdef DEBUG + isyslog("music: commands: load visfiles from '%s'", plugindir.c_str()); +#endif + + int len2 = plugindir.length()+1; + + + if(asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), VISEXT) == -1) + fprintf(stderr, "Failed to allocate string"); + + FILE *p = popen(cmd, "r"); + + if(p) { + char *s; + while ((s = reader.Read(p)) != NULL) { + count++; + visfile = s; + int len = visfile.length(); + std::string::size_type pos = visfile.rfind('/',len); + if(pos!=std::string::npos) { + // Filename + visname = visfile.substr(pos+1,len); + // Basedir + int sublen = len - len2 - visname.length()-1; + visBase = visfile.substr(len2,sublen); + } + newitem = new cFileObjItem(plugindir.c_str(), visname.c_str(), otFile); + if(newitem && newitem->Type()==otFile) { + Add(new cMP3VisualItem(newitem, count)); + } + } + pclose(p); + } + else + Skins.Message(mtError, tr("ERROR: Cant find any visualization!")); + + free(cmd); +} + +cFileObjItem *cMP3Visual::CurrentFileObjItem(void) +{ + cMP3VisualItem *item = (cMP3VisualItem *)Get(Current()); + return item ? item->Item():0; +} + + +eOSState cMP3Visual::SetVis(void) +{ + int ItemIndex = Current(); + cFileObjItem *item=CurrentFileObjItem(); + + if(ItemIndex == 0) { + MP3Setup.EnableVis = false; + std::string file; + if(!MP3Setup.isWebstream) { + file = config; + file = file + "/themes/defaultcover/music-default-cover.png"; + strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); + } + else { + file = config; + file = file + "/themes/defaultcover/music-default-stream.png"; + strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); + } + return osBack; + } + else if (ItemIndex >= 1) { + if(item && item->Type()==otFile) { + if(MP3VisLoader.LoadVis(item->Name())) { + MP3Setup.EnableVis = true; + MP3VisLoader.SetVis(); + strncpy(coverpicture,MP3VisLoader.VisLoaderBackground(),sizeof(coverpicture)); + + if(MP3VisLoader.StoreVis(item->Name())) + isyslog("music: stored '%s' as 'current.vis'\n", item->Name()); + else + esyslog("music: could not store '%s' as 'current.vis'\n", item->Name()); + + return osBack; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not load new visualization !"), fontFix)); + } + } + + return osContinue; +} + + +eOSState cMP3Visual::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetVis(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + +// ------------ cMP3User --------------------------------------------------------------------------------------------------- // + +class cMP3User : public cOsdMenu { +private: + void SetHelp(); + void LoadUsername(); + eOSState SetUser(void); + cOsdItem *Item(const char *text); +public: + cMP3User(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +cMP3User::cMP3User(void) +:cOsdMenu(tr("Music: User"),4) +{ + LoadUsername(); + SetHelp(); +} + +void cMP3User::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +cOsdItem *cMP3User::Item(const char *text) +{ + char *buf=0; + if(asprintf(&buf, "%s",text?text:"") == -1) + fprintf(stderr, "Failed to allocate string for text"); + + cOsdItem *item = new cOsdItem(buf,osUnknown,true); + free(buf); + Add(item); return item; +} + +void cMP3User::LoadUsername() +{ + std::ifstream filestr; + std::string userfile; + std::string line; + + userfile = config; + userfile = userfile + "/data/user.dat"; + +#ifdef DEBUG + isyslog("music: commands: load user.dat from '%s'", userfile.c_str()); +#endif + + filestr.open(userfile.c_str()); + + if(filestr) { + while ((getline(filestr,line,'\n'))) { + Item(line.c_str()); + } + filestr.close(); + } +} + + +eOSState cMP3User::SetUser(void) +{ + cOsdItem *item=(cOsdItem*)Get(Current()); + + std::string datei; + datei = config; + datei = datei + "/data/current_user.dat"; + +#ifdef DEBUG + isyslog("music: commands: load current_user.dat from '%s'", datei.c_str()); +#endif + + + if(item) { + if(Interface->Confirm(tr("Change user (Music will be stopped) ?")) ) { + InfoCache.Save(true); + if( FILE *f = fopen ( datei.c_str(), "w")) { + std::string user; + user = item->Text(); + fprintf(f, "%s\n", user.c_str()); + isyslog("music: change to user <%s>\n", user.c_str()); + fclose(f); + InfoCache.Load(true); + } + return osEnd; + } + + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not change user !"), fontFix)); + + return osContinue; +} + + +eOSState cMP3User::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if(state==osUnknown) { + switch(Key) { + case kOk: + state = SetUser(); + break; + case kBlue: + case kGreen: + case kYellow: + case kRed: return osBack; + default: return osContinue;; + } + } + return state; +} + + + +// ------------ cMP3EditPlaylist ---------------------------------------------------------------------------------------------- // + +cMP3EditPlaylist::cMP3EditPlaylist(const char *sz_Title) +:cOsdMenu(tr(sz_Title)) +{ +//0 + Add(new cOsdItem(hk(tr("Remove track from playlist")))); +//1 + Add(new cOsdItem(hk(tr("Remove all from playlist")))); +//2 + Add(new cOsdItem(hk(tr("Save active playlist")))); + + if(MP3Setup.AdminMode >= 2) { + +//3 + cOsdItem *item = new cOsdItem(hk("")); + Add(item, osUnknown); + item->SetSelectable(false); + +//4 + Add(new cOsdItem(hk(tr("Delete selected track from medium")))); +//5 + Add(new cOsdItem(hk(tr("Delete all tracks in playlist from medium")))); + } + + + SetHelp(); +} + + +void cMP3EditPlaylist::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + + +eOSState cMP3EditPlaylist::Execute(void) +{ + + int ItemIndex = Current(); + +//0/ Delete Track from playlist and save as current playlist in ConfigDir;; + if (ItemIndex == 0) { + + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); + + + if(MP3Setup.AdminMode >= 1) { + + if (mgr->maxIndex==0) + MP3Setup.DeleteTracks = 1; + else + MP3Setup.DeleteTrack = 1; + + return osBack; + } + else { + if(Interface->Confirm(tr("Remove track from playlist ?")) && Interface->Confirm(tr("Are you sure?")) ) { + if (mgr->maxIndex==0) + MP3Setup.DeleteTracks = 1; + else + MP3Setup.DeleteTrack = 1; + + return osBack; + } + } + } + + + +//1/ Empty playlist;; + if (ItemIndex == 1) { + if(MP3Setup.AdminMode >= 1) { + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + if(Interface->Confirm(tr("Remove all tracks from playlist ?")) ) { + Skins.Message(mtStatus, tr("Remove all tracks from playlist...")); + MP3Setup.DeleteTracks = 1; + Skins.Message(mtStatus, NULL); + return osBack; + } + } + } + + +//2/ Save playlist for burn..something with full path in ConfigDir;; + if (ItemIndex == 2) { + if(MP3Setup.AdminMode >= 1) { + Skins.Message(mtStatus, tr("Save playlist...")); + char *buf=0; + if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) + fprintf(stderr, "Failed to allocate string"); +#ifdef DEBUG + isyslog("music: commands: save playlust to '%s'", buf); +#endif + bool Result = mgr->SaveList(buf, true); + Skins.Message(mtStatus, NULL); + free(buf); + if (Result) + return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); + } + else { + if(Interface->Confirm(tr("Overwrite last playlist ?")) ) { + Skins.Message(mtStatus, tr("Save playlist...")); + char *buf=0; + if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) + fprintf(stderr, "Failed to allocate string"); +#ifdef DEBUG + isyslog("music: commands: save playlist to '%s'", buf); +#endif + bool Result = mgr->SaveList(buf, true); + Skins.Message(mtStatus, NULL); + free(buf); + if (Result) + return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); + } + } + } + + +//3/ Delete file from medium + if(MP3Setup.AdminMode >=1) { + if (ItemIndex == 4) { + + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); + + if(MP3Setup.AdminMode == 2) { + if (mgr->maxIndex==0) { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTrack = 1; + return osBack; + } + } + else { + if(Interface->Confirm(tr("Delete file from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { + if (mgr->maxIndex==0) { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTracks = 1; + return osBack; + } + else { + RemoveFileOrDir(Songname, false); + MP3Setup.DeleteTrack = 1; + return osBack; + } + } + } + } + + +//4/ Delete everything in playlist from medium + if (ItemIndex == 5) { + if(mgr->maxIndex <= -1) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove tracks !"), fontFix)); + + + if(Interface->Confirm(tr("Delete all in playlist from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { + Skins.Message(mtStatus, tr("Delete all tracks from medium...")); + bool Result = DeleteList(); + Skins.Message(mtStatus, NULL); + if (Result) { + return AddSubMenu(new cMenuText(tr("Delete"), tr("Tracks terminated !"), fontFix)); + MP3Setup.DeleteTracks = 1; + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not delete tracks !"), fontFix)); + } + } + + } + + return osContinue; +} + +eOSState cMP3EditPlaylist::ProcessKey(eKeys Key) +{ + + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: + return osBack; + break; + case kOk: + return Execute(); + break; + default: + state = osContinue; + } + } + + return state; +} + + +bool cMP3EditPlaylist::DeleteList(void) +{ + std::ifstream filestr; + std::string datei; + std::string line; + int count=0; + bool res = false; + + datei=config; + datei=datei + "/playlists/deletelist.m3u"; + +#ifdef DEBUG + isyslog("music: commands: get deletelist.m3u from '%s'", datei.c_str()); +#endif + + if(mgr->SaveList(datei.c_str(), true)) { + filestr.open (datei.c_str()); + while ((getline(filestr,line,'\n'))) { + count++; + isyslog("music: delete file : %i %s\n",count,line.c_str()); + RemoveFileOrDir(line.c_str(), false); + } + filestr.close(); + res = true; + } + + return res; +} + + + +// ------------ cMP3Commands --------------------------------------------------------------------------------------------------- // + +cMP3Commands::cMP3Commands(void) +:cOsdMenu(tr("Music: Commands")) +{ +/* 0*/ Add(new cOsdItem(hk(tr("Edit playlist...")))); +/* 1*/ Add(new cOsdItem(hk(tr("Search for songs...")))); +/* 2*/ Add(new cOsdItem(hk(tr("Show ID3 information of song")))); +/* 3*/ Add(new cOsdItem(hk(tr("Edit ID3 information")))); +/* 4*/ Add(new cOsdItem(hk(tr("Quick settings...")))); +/* 5*/ Add(new cOsdItem(hk(tr("Search for lyric...")))); +/* 6*/ Add(new cOsdItem(hk(tr("Download coverpicture...")))); +/* 7*/ Add(new cOsdItem(hk(tr("Update webstreams...")))); +/* 8*/ Add(new cOsdItem(hk(tr("Start imageviewer")))); +/* 9*/ if(!MP3Setup.RecordStream) + Add(new cOsdItem(hk(tr("Start Recording")))); + else + Add(new cOsdItem(hk(tr("Stop Recording")))); +/* 10*/ Add(new cOsdItem(hk(tr("Change Appearance...")))); +/* 11*/ Add(new cOsdItem(hk(tr("Visualizations...")))); +/* 12*/ Add(new cOsdItem(hk(tr("Change user...")))); + + + SetHelp(); + LoadCommands(); + + for (cCommand *command = commands.First(); command; command = commands.Next(command)) { + cOsdItem *item = new cOsdItem(hk(command->Title())); + Add(item, osUnknown); + if(strstr(item->Text(), "----------")) + item->SetSelectable(false); + else + item->SetSelectable(true); + } + + Display(); +} + + +cMP3Commands::~cMP3Commands() +{ +} + +void cMP3Commands::SetHelp() +{ + cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); +} + +void cMP3Commands::LoadCommands() +{ + std::string datei; + datei = langdir; + datei = datei + "/data/musiccmds.dat"; +#ifdef DEBUG + isyslog("music: commands: load commands from '%s%s'", config, datei.c_str()); +#endif + commands.Load(AddDirectory(config, datei.c_str()), true); +} + + +eOSState cMP3Commands::Execute(void) +{ + int ItemIndex = Current(); + +//0/ Edit Playlist;; + if (ItemIndex == 0) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + else + return AddSubMenu(new cMP3EditPlaylist("Edit playlist...")); + } + + +//1/ Search;; + if (ItemIndex == 1) { + if(mgr->maxIndex >0) { + std::string artist =""; + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { songinfo = mgr->Current()->Info(); } + if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } + return AddSubMenu(new cMP3Search(artist.c_str())); + } + else { + return AddSubMenu(new cMP3Search("")); + } + } + + +//2/ Show ID3Info;; + if (ItemIndex == 2) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + if(mgr->Current()) { + return AddSubMenu(new cMP3SearchID3Info(mgr->curr)); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); + } + } + + +//3/ Edit ID3 Tags + if (ItemIndex == 3) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + if(mgr->Current() && MP3Setup.user_is_admin && (MP3Setup.AdminMode >=2)) { + return AddSubMenu(new cMP3id3Tag(mgr->curr)); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: no songinfo or not allowed !"), fontFix)); + } + + } + + +//4/ Some options/commands + if (ItemIndex == 4) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + else + return AddSubMenu(new cMP3Options()); + } + + +//5/ Show Lyrics;; + if (ItemIndex == 5) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + + return AddSubMenu(new cMP3Lyrics()); + } + + + if (ItemIndex == 1) { + std::string artist =""; + if(mgr->maxIndex >0) { + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { songinfo = mgr->Current()->Info(); } + if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } + return AddSubMenu(new cMP3Search(artist.c_str())); + } + else { + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); + } + } + + +//6/ Download Cover;; + if (ItemIndex == 6) { + std::string::size_type pos; + std::string artist = ""; + std::string album = ""; + std::string title = ""; + std::string baseDir = ""; + std::string filename = ""; + std::string Filenoext= ""; + + if(mgr->maxIndex >=0) { + cSongInfo *songinfo = mgr->Current()->Info(false); + if(!songinfo) { + songinfo = mgr->Current()->Info(); + } + + if(songinfo) { + if(songinfo->Artist) { + artist = songinfo->Artist; + } + if(songinfo->Album) { + album = songinfo->Album; + } + if(songinfo->Title) { + title = songinfo->Title; + } + + cSong *s = mgr->curr; + + if(s) { + filename = s->Fullname(); + // get dir + int len = filename.length(); + pos = filename.rfind("/",len); + if(pos != std::string::npos) { + baseDir = filename.substr(0, pos+1); + } + // get file w/o ext. + pos = filename.rfind(".",len); + if(pos != std::string::npos) { + Filenoext = filename.substr(0, pos+1); + } + } + return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); + } + } +// else { +// return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); +// } + } + + +//7/ Update Webstreams;; + if (ItemIndex == 7) { + return AddSubMenu(new cMP3UpdateWebStreams()); + } + +//8/ Open Imageviewer;; + if (ItemIndex == 8) { + cRemote::CallPlugin("picselshow"); + return (osPlugin); + } + + +//9/ Start<->Stop Recording;; + if (ItemIndex == 9) { + + if (MP3Setup.AdminMode >= 2) { + if (MP3Setup.RecordStream) { + StopRecord(); + return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); + } + else { + if (MP3Setup.isWebstream) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + StartRecord(); + return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); + } + } + else { + if(MP3Setup.RecordStream) { + if(Interface->Confirm(tr("Stop recording ?")) ) { + StopRecord(); + return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); + } + } + else { + if (MP3Setup.isWebstream) { + if(Interface->Confirm(tr("Start recording ?")) ) { + if(mgr->maxIndex <0) + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); + StartRecord(); + return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); + } + } + else + return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); + } + } + } + + +//10/ Themes;; + if (ItemIndex == 10) { + return AddSubMenu(new cMP3Themes()); + } + + +//11/ Visualization;; + if (ItemIndex == 11) { + return AddSubMenu(new cMP3Visual()); + } + + +//12/ User;; + if (ItemIndex == 12) { + return AddSubMenu(new cMP3User()); + } + + + +// From NOW on execute usercommands;; + if (ItemIndex >= 13) { + cCommand *command = commands.Get(ItemIndex-13); + if (command) { + char *buffer = NULL; + bool confirmed = true; + + std::string Artist =""; + std::string Album =""; + std::string Coverdir =""; + + cSongInfo *si = mgr->Current()->Info(false); + if(!si) si = mgr->Current()->Info(); + if(si && si->Artist)Artist = si->Artist; + if(si && si->Album) Album = si->Album; + if (command->Confirm()) { + if(asprintf(&buffer, "%s?", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command->Title()"); + confirmed = Interface->Confirm(buffer); + free(buffer); + } + if (confirmed) { + if(asprintf(&buffer, "%s...", command->Title()) == -1) + fprintf(stderr, "Failed to allocate string for command->Title()"); + Skins.Message(mtStatus, buffer); + free(buffer); + + if(asprintf(&buffer, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", Songname, MP3Setup.CopyDir, Artist.c_str(), Album.c_str(), MP3Setup.CoverDir, config) == -1) + fprintf(stderr, "Failed to allocate string"); + + const char *Result = command->Execute(buffer); + + d(printf("music: commands: Executed: '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: executed: '%s'\n", buffer); +#endif + free(buffer); + Skins.Message(mtStatus, NULL); + if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); + return osBack; + } + } + } + + return osContinue; +} + +// ------------------ STARTRECORD -----------------------// +void cMP3Commands::StartRecord(void) +{ + FILE *recordcmd; + char *buffer; + + std::string url; + url = "\""; + url = url + urlname; + url = url + "\""; + + + d(printf("music: commands: Started Recording\n")); + if(asprintf(&buffer, "screen -A -m -d -S RECORD /usr/bin/streamripper %s -d '%s' -w %s%s/data/parse_rules.txt %s", url.c_str(), MP3Setup.RecordDir, config, langdir, MP3Setup.RecordOpts) == -1) + fprintf(stderr, "Failed to allocate string"); + + recordcmd = popen(buffer, "r"); + d(printf("music: commands: Starting recording '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: starting recording '%s'", buffer); +#endif + pclose(recordcmd); + + free(buffer); + MP3Setup.RecordStream = 1; +} + +// ------------------ STOPRECORD -----------------------// +void cMP3Commands::StopRecord(void) +{ + FILE *stoprecordcmd; + char *buffer; + + d(printf("music: commands: Stopped Recording\n")); + if(asprintf(&buffer, "killall -15 streamripper") == -1) + fprintf(stderr, "Failed to allocate string"); + + stoprecordcmd = popen(buffer, "r"); + d(printf("music: commands: Stop recording '%s'\n", buffer)); +#ifdef DEBUG + isyslog("music: commands: stop recording '%s'", buffer); +#endif + pclose(stoprecordcmd); + + free(buffer); + MP3Setup.RecordStream = 0; +} + +eOSState cMP3Commands::ProcessKey(eKeys Key) +{ + bool hadSubmenu = HasSubMenu(); + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (hadSubmenu && !HasSubMenu()) + return osBack; + + if (state == osUnknown) { + switch (Key) { + case kRed: + return osBack; + break; + case kOk: + return Execute(); + break; + default: + state = osContinue; + } + } + + return state; +} diff -Nru vdr-plugin-music-0.9.9/.pc/02_graphicsmagick.patch/Makefile vdr-plugin-music-0.9.9/.pc/02_graphicsmagick.patch/Makefile --- vdr-plugin-music-0.9.9/.pc/02_graphicsmagick.patch/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/02_graphicsmagick.patch/Makefile 2020-11-26 22:13:41.000000000 +0000 @@ -0,0 +1,223 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + + +# You can change the compile options here or create a Make.config +# in the VDR directory an set them there. + +# (Default) DO NOT UNCOMMENT IT IN DEVELOPER-VERSIONS +HAVE_IMAGEMAGICK=1 +IMAGEMAGICKDIR=/usr/include/ImageMagick + +# Uncomment the following line, if you don't have libsndfile installed +#WITHOUT_LIBSNDFILE=1 + +# Uncomment the following line, if you don't have libvorbisfile installed +#WITHOUT_LIBVORBISFILE=1 + + +BROKEN_PCM=1 + +# Uncomment the following line, if you want to include debug symbols +#DBG=1 + +# Uncomment if you want debug output on stdout +DEBUG=1 + +# internal use +# BUGHUNT +#BUGHUNT=1 + +# internal use +# DEBUG_COVER +#DEBUG_COVER=1 + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# IMPORTANT: the presence of this macro is important for the Make.config +# file. So it must be defined, even if it is not used here! +# +PLUGIN = music + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses + +### The directory environment: + +VDRDIR = ../../.. +LIBDIR = ../../lib +TMPDIR = /tmp + +### Make sure that necessary options are included: + +-include $(VDRDIR)/Make.global + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + + +DOXYGEN = /usr/bin/doxygen +DOXYFILE = Doxyfile + +### The version number of VDR's plugin API (taken from VDR's "config.h"): + +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### Test whether VDR has locale support +VDRLOCALE = $(shell grep '^LOCALEDIR' $(VDRDIR)/Make.config) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include + +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +ifdef BROKEN_PCM + DEFINES += -DBROKEN_PCM +endif + +ifeq ($(shell test -f $(VDRDIR)/fontsym.h ; echo $$?),0) + DEFINES += -DHAVE_BEAUTYPATCH +endif + +ifdef DBG + CXXFLAGS += -g +endif + +ifdef DEBUG + DEFINES += -DDEBUG +else + DEFINES += -DNO_DEBUG +endif + +ifdef BUGHUNT + DEFINES += -DBUGHUNT +endif + +ifdef DEBUG_COVER + DEFINES += -DDEBUG_COVER +endif + + +### The object files (add further files here): + +OBJS = $(PLUGIN).o config.o vars.o bitmap.o \ + commands.o options.o lyrics.o funct.o cover.o skin.o visual.o tracklist.o \ + search.o mp3id3.o mp3id3tag.o rating.o menubrowse.o mp3control.o \ + i18n.o icons.o data.o menu.o \ + data-mp3.o setup-mp3.o player-mp3.o stream.o network.o \ + decoder.o decoder-mp3.o decoder-mp3-stream.o decoder-snd.o \ + decoder-ogg.o + +LIBS += -lasound -lmad -lid3tag -lz -lid3 + + +# for older versions +#ifdef HAVE_MAGICK +# LIBS += -lMagick -lMagick++ +# DEFINES += -DHAVE_MAGICK +#else +# LIBS += -lImlib2 +# DEFINES += -DHAVE_IMLIB2 +#endif + +ifdef HAVE_IMAGEMAGICK + INCLUDES += -I$(IMAGEMAGICKDIR) + LIBS += $(shell Magick++-config --libs) + DEFINES += -DHAVE_IMAGEMAGICK +else + INCLUDES += -I$(IMLIB)/src + LIBS += $(shell imlib2-config --libs) + DEFINES += -DHAVE_IMLIB2 +endif + +ifndef WITHOUT_LIBSNDFILE + LIBS += -lsndfile + DEFINES += -DHAVE_SNDFILE +endif + +ifndef WITHOUT_LIBVORBISFILE + LIBS += -lvorbisfile -lvorbis + DEFINES += -DHAVE_VORBISFILE +endif + +### The main target: + +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Make.config + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(subst i18n.c,,$(OBJS:%.o=%.c)) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) + +### Targets: + +.PHONY: all dist clean + +all: libvdr-$(PLUGIN).so i18n + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@ + @cp $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ diff -Nru vdr-plugin-music-0.9.9/.pc/applied-patches vdr-plugin-music-0.9.9/.pc/applied-patches --- vdr-plugin-music-0.9.9/.pc/applied-patches 2016-12-26 23:22:53.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/applied-patches 2020-11-26 22:13:51.000000000 +0000 @@ -1 +1,3 @@ -menu.diff +01_skindesigner-menu.diff +02_graphicsmagick.patch +music_ggc-7_fix.patch diff -Nru vdr-plugin-music-0.9.9/.pc/menu.diff/commands.c vdr-plugin-music-0.9.9/.pc/menu.diff/commands.c --- vdr-plugin-music-0.9.9/.pc/menu.diff/commands.c 2016-12-26 23:22:53.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/menu.diff/commands.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1357 +0,0 @@ - -#include -#include - -#include -#include -#include -#include - -#include "commands.h" -#include "i18n.h" -#include "player-mp3.h" -#include "decoder.h" -#include "skin.h" -#include "search.h" -#include "mp3id3.h" -#include "mp3id3tag.h" -#include "lyrics.h" -#include "cover.h" -#include "visual.h" -#include "options.h" -#include "vars.h" - -#define X_DISPLAY_MISSING -#define MAXLENGTH 256 -#define THEMESEXT "*.theme" -#define VISEXT "*.visual" -#define FINDCMD "cd '%s' && find '%s' -iname '%s' -printf '%%p\n' | sort -f" - -char urlname[256]; - -//---------------- cMP3UpdateWebStreams -------------------------------------------------------------------------------------------------------------------------- - - -class cMP3UpdateWebStreams : public cOsdMenu { -private: - cCommands commands; -// cOsdItem *Item(const char *name, const char *text); - void SetHelp(); - void ShowDisplay(void); - void UpdateGenre(); - eOSState Execute(void); - int limits, bitrate; - const char *bitrates[10]; -public: - cMP3UpdateWebStreams(void); - virtual ~cMP3UpdateWebStreams(); - virtual eOSState ProcessKey(eKeys Key); - void LoadCommand(); -}; - - -cMP3UpdateWebStreams::cMP3UpdateWebStreams(void) -:cOsdMenu(tr("Music: Update webstreams"),32) -{ - limits = MP3Setup.ShoutcastLimit; - bitrate = 192; -// bitrates = MP3Setup.ShoutcastBitrate; - - ShowDisplay(); -/* - Add(new cMenuEditIntItem(tr("Limit for stations"), &limits, 0 , 100)); - Add(new cMenuEditIntItem(tr("Bitrate for stations"), &bitrates, 0 , 100)); - - SetHelp(); - - LoadCommand(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } -*/ -} - -cMP3UpdateWebStreams::~cMP3UpdateWebStreams() -{ -} - -void cMP3UpdateWebStreams::ShowDisplay(void) -{ - Clear(); - Add(new cMenuEditIntItem(tr("Limit for Shoutcast"), &limits, 0 , 100)); - - bitrates[0]="32"; - bitrates[1]="48"; - bitrates[2]="56"; - bitrates[3]="64"; - bitrates[4]="96"; - bitrates[5]="128"; - bitrates[6]="160"; - bitrates[7]="192"; - bitrates[8]="256"; - bitrates[9]="320"; - Add(new cMenuEditStraItem(tr("Bitrate for Shoutcast"), &MP3Setup.ShoutcastBitrate, 10 , bitrates)); - Add(new cOsdItem(hk(tr("Update Genres")))); - - - LoadCommand(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } - - SetHelp(); - Display(); -} - -void cMP3UpdateWebStreams::SetHelp() { - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3UpdateWebStreams::LoadCommand() { - - std::string lingual; - - lingual = langdir; - lingual = lingual + "/data/shoutcast.dat"; - - commands.Load(AddDirectory(config, lingual.c_str()), true); -#ifdef DEBUG - isyslog("music: commands: load shoutcast.dat '%s%s'",config, lingual.c_str()); -#endif -} - - -void cMP3UpdateWebStreams::UpdateGenre() -{ - std::string datei; - - datei = config; - datei = datei + langdir; - datei = datei + "/scripts/music_updategenre.pl '"; - datei = datei + MP3Setup.WebstreamDat + "' '10' '192'"; - - Skins.Message(mtStatus, tr("Refreshing Genres")); - FILE *updatecmd; - updatecmd = popen(datei.c_str(), "r"); - pclose(updatecmd); - -#ifdef DEBUG - isyslog("music: commands: update genres '%s'", datei.c_str()); -#endif - - Display(); -} - - -eOSState cMP3UpdateWebStreams::Execute(void) { - - int ItemIndex = Current(); - if (ItemIndex <= 1) return osContinue; - - if (ItemIndex == 2) { - UpdateGenre(); - return osBack; - } - - - int parbit = MP3Setup.ShoutcastBitrate; - - switch(parbit) { - case 0: bitrate = 32; break; - case 1: bitrate = 48; break; - case 2: bitrate = 56; break; - case 3: bitrate = 64; break; - case 4: bitrate = 96; break; - case 5: bitrate = 128; break; - case 6: bitrate = 160; break; - case 7: bitrate = 192; break; - case 8: bitrate = 256; break; - case 9: bitrate = 320; break; - default : break; - } - - - cCommand *command = commands.Get(Current() -3); - if (command) { - char *buffer = NULL; - bool confirmed = true; - - if (command->Confirm()) { - if (asprintf(&buffer, "%s?", command->Title()) == -1) { - fprintf(stderr, "Failed to allocate string for command-Title"); - return osBack; - } - confirmed = Interface->Confirm(buffer); - free(buffer); - } - if (confirmed) { - if (asprintf(&buffer, "%s...", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command-Title"); - - Skins.Message(mtStatus, buffer); - free(buffer); - - char *parameters; - if (asprintf(¶meters, " '%d' '%d' '%s';", limits, bitrate, MP3Setup.WebstreamDat) == -1) - fprintf(stderr, "Failed to allocate string"); - - const char *Result = command->Execute(parameters); - free(parameters); - - Skins.Message(mtStatus, NULL); - if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); - return osBack; - } - } - - return osContinue; -} - - -eOSState cMP3UpdateWebStreams::ProcessKey(eKeys Key) { - - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: state = osBack; - case kGreen: - case kYellow: - case kBlue: state = osContinue; - case kOk: state = Execute(); - default: state = osContinue; - } - } - - return state; -} - - - -// ------------ cMP3ThemesItem ----------------------------------------------------------------------------------------------- // - -class cMP3ThemesItem : public cOsdItem { -private: - cFileObjItem *item; - virtual void Set(void); - int idx; -public: - cMP3ThemesItem(cFileObjItem *Item, int index); - cFileObjItem *Item(void) {return item;} - ~cMP3ThemesItem(); -}; - - -cMP3ThemesItem::cMP3ThemesItem(cFileObjItem *Item, int index) { - idx = index; - item = Item; - Set(); -} - -cMP3ThemesItem::~cMP3ThemesItem(){ -} - -void cMP3ThemesItem::Set(void) { - char *Name; - - if (asprintf(&Name,"%s", item->Name()) == -1) - fprintf(stderr, "Failed to allocate string for item->Name()"); - - SetText(Name,false); -} - - -// ------------ cMP3Themes --------------------------------------------------------------------------------------------------- // - -class cMP3Themes : public cOsdMenu { -private: - void SetHelp(); - void LoadSkinFiles(); - eOSState SetTheme(void); - cFileObjItem *newitem; -protected: - cFileObjItem *CurrentFileObjItem(void); -public: - cMP3Themes(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3Themes::cMP3Themes(void) -:cOsdMenu(tr("Music: Appearance"),4) -{ - - LoadSkinFiles(); - SetHelp(); -} - -void cMP3Themes::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3Themes::LoadSkinFiles() -{ - int count = 0; - - char *cmd = NULL; - cReadLine reader; - - std::string plugindir; - std::string themename; - std::string themefile; - std::string Base; - - plugindir = config; - plugindir = plugindir + "/themes/"; - -#ifdef DEBUG - isyslog("music: commands: load themes from '%s'", plugindir.c_str()); -#endif - - int len2 = plugindir.length()+1; - - - if (asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), THEMESEXT) == -1) - fprintf(stderr, "Failed to allocate string"); - - FILE *p = popen(cmd, "r"); - - if(p) { - char *s; - while ((s = reader.Read(p)) != NULL) { - count++; - themefile = s; - int len = themefile.length(); - std::string::size_type pos = themefile.rfind('/',len); - if(pos!=std::string::npos) { - // Filename - themename = themefile.substr(pos+1,len); - // Basedir - int sublen = len - len2 - themename.length()-1; - Base = themefile.substr(len2,sublen); - } - newitem = new cFileObjItem(plugindir.c_str(), themename.c_str(), otFile); - if(newitem && newitem->Type()==otFile) { - Add(new cMP3ThemesItem(newitem, count)); - } - } - pclose(p); - } - else - Skins.Message(mtError, tr("ERROR: Havent found any themes !")); - - free(cmd); -} - -cFileObjItem *cMP3Themes::CurrentFileObjItem(void) -{ - cMP3ThemesItem *item = (cMP3ThemesItem *)Get(Current()); - return item ? item->Item():0; -} - - -eOSState cMP3Themes::SetTheme(void) -{ - cFileObjItem *item=CurrentFileObjItem(); - - if(item && item->Type()==otFile) { - if(MP3Skin.StoreSkin(item->Name())) { - MP3Skin.ParseSkin("current.colors"); - MP3Skin.ReloadFonts=1; - return osBack; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not store/load new themefile !"), fontFix)); - } - - return osContinue; -} - - -eOSState cMP3Themes::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetTheme(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - - -// ------------ cMP3VisualItem --------------------------------------------------------------------------------------------- // - -class cMP3VisualItem : public cOsdItem { -private: - cFileObjItem *item; - virtual void Set(void); - int idx; -public: - cMP3VisualItem(cFileObjItem *Item, int index); - cFileObjItem *Item(void) {return item;} - ~cMP3VisualItem(); -}; - - -cMP3VisualItem::cMP3VisualItem(cFileObjItem *Item, int index) -{ - idx = index; - item = Item; - Set(); -} - -cMP3VisualItem::~cMP3VisualItem() -{ -} - -void cMP3VisualItem::Set(void) -{ - char *Name; - - if(asprintf(&Name,"%s", item->Name()) == -1) - fprintf(stderr, "Failed to allocate string for item->Name()"); - - SetText(Name,false); -} - - -// ------------ cMP3Visual ------------------------------------------------------------------------------------------------- // - -class cMP3Visual : public cOsdMenu { -private: - void SetHelp(); - void LoadVisFiles(); - eOSState SetVis(void); - cFileObjItem *newitem; -protected: - cFileObjItem *CurrentFileObjItem(void); -public: - cMP3Visual(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3Visual::cMP3Visual(void) -:cOsdMenu(tr("Music: Visualizations"),4) -{ - Add(new cOsdItem(hk(tr("Disable visualization")))); - LoadVisFiles(); - SetHelp(); -} - -void cMP3Visual::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3Visual::LoadVisFiles() -{ - int count = 0; - - char *cmd = NULL; - cReadLine reader; - - std::string plugindir; - std::string visname; - std::string visfile; - std::string visBase; - - plugindir = config; - plugindir = plugindir + "/visual/themes/"; - -#ifdef DEBUG - isyslog("music: commands: load visfiles from '%s'", plugindir.c_str()); -#endif - - int len2 = plugindir.length()+1; - - - if(asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), VISEXT) == -1) - fprintf(stderr, "Failed to allocate string"); - - FILE *p = popen(cmd, "r"); - - if(p) { - char *s; - while ((s = reader.Read(p)) != NULL) { - count++; - visfile = s; - int len = visfile.length(); - std::string::size_type pos = visfile.rfind('/',len); - if(pos!=std::string::npos) { - // Filename - visname = visfile.substr(pos+1,len); - // Basedir - int sublen = len - len2 - visname.length()-1; - visBase = visfile.substr(len2,sublen); - } - newitem = new cFileObjItem(plugindir.c_str(), visname.c_str(), otFile); - if(newitem && newitem->Type()==otFile) { - Add(new cMP3VisualItem(newitem, count)); - } - } - pclose(p); - } - else - Skins.Message(mtError, tr("ERROR: Cant find any visualization!")); - - free(cmd); -} - -cFileObjItem *cMP3Visual::CurrentFileObjItem(void) -{ - cMP3VisualItem *item = (cMP3VisualItem *)Get(Current()); - return item ? item->Item():0; -} - - -eOSState cMP3Visual::SetVis(void) -{ - int ItemIndex = Current(); - cFileObjItem *item=CurrentFileObjItem(); - - if(ItemIndex == 0) { - MP3Setup.EnableVis = false; - std::string file; - if(!MP3Setup.isWebstream) { - file = config; - file = file + "/themes/defaultcover/music-default-cover.png"; - strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); - } - else { - file = config; - file = file + "/themes/defaultcover/music-default-stream.png"; - strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); - } - return osBack; - } - else if (ItemIndex >= 1) { - if(item && item->Type()==otFile) { - if(MP3VisLoader.LoadVis(item->Name())) { - MP3Setup.EnableVis = true; - MP3VisLoader.SetVis(); - strncpy(coverpicture,MP3VisLoader.VisLoaderBackground(),sizeof(coverpicture)); - - if(MP3VisLoader.StoreVis(item->Name())) - isyslog("music: stored '%s' as 'current.vis'\n", item->Name()); - else - esyslog("music: could not store '%s' as 'current.vis'\n", item->Name()); - - return osBack; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not load new visualization !"), fontFix)); - } - } - - return osContinue; -} - - -eOSState cMP3Visual::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetVis(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - -// ------------ cMP3User --------------------------------------------------------------------------------------------------- // - -class cMP3User : public cOsdMenu { -private: - void SetHelp(); - void LoadUsername(); - eOSState SetUser(void); - cOsdItem *Item(const char *text); -public: - cMP3User(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3User::cMP3User(void) -:cOsdMenu(tr("Music: User"),4) -{ - LoadUsername(); - SetHelp(); -} - -void cMP3User::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -cOsdItem *cMP3User::Item(const char *text) -{ - char *buf=0; - if(asprintf(&buf, "%s",text?text:"") == -1) - fprintf(stderr, "Failed to allocate string for text"); - - cOsdItem *item = new cOsdItem(buf,osUnknown,true); - free(buf); - Add(item); return item; -} - -void cMP3User::LoadUsername() -{ - std::ifstream filestr; - std::string userfile; - std::string line; - - userfile = config; - userfile = userfile + "/data/user.dat"; - -#ifdef DEBUG - isyslog("music: commands: load user.dat from '%s'", userfile.c_str()); -#endif - - filestr.open(userfile.c_str()); - - if(filestr) { - while ((getline(filestr,line,'\n'))) { - Item(line.c_str()); - } - filestr.close(); - } -} - - -eOSState cMP3User::SetUser(void) -{ - cOsdItem *item=(cOsdItem*)Get(Current()); - - std::string datei; - datei = config; - datei = datei + "/data/current_user.dat"; - -#ifdef DEBUG - isyslog("music: commands: load current_user.dat from '%s'", datei.c_str()); -#endif - - - if(item) { - if(Interface->Confirm(tr("Change user (Music will be stopped) ?")) ) { - InfoCache.Save(true); - if( FILE *f = fopen ( datei.c_str(), "w")) { - std::string user; - user = item->Text(); - fprintf(f, "%s\n", user.c_str()); - isyslog("music: change to user <%s>\n", user.c_str()); - fclose(f); - InfoCache.Load(true); - } - return osEnd; - } - - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not change user !"), fontFix)); - - return osContinue; -} - - -eOSState cMP3User::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetUser(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - - -// ------------ cMP3EditPlaylist ---------------------------------------------------------------------------------------------- // - -cMP3EditPlaylist::cMP3EditPlaylist(const char *sz_Title) -:cOsdMenu(tr(sz_Title)) -{ -//0 - Add(new cOsdItem(hk(tr("Remove track from playlist")))); -//1 - Add(new cOsdItem(hk(tr("Remove all from playlist")))); -//2 - Add(new cOsdItem(hk(tr("Save active playlist")))); - - if(MP3Setup.AdminMode >= 2) { - -//3 - cOsdItem *item = new cOsdItem(hk("")); - Add(item, osUnknown); - item->SetSelectable(false); - -//4 - Add(new cOsdItem(hk(tr("Delete selected track from medium")))); -//5 - Add(new cOsdItem(hk(tr("Delete all tracks in playlist from medium")))); - } - - - SetHelp(); -} - - -void cMP3EditPlaylist::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -eOSState cMP3EditPlaylist::Execute(void) -{ - - int ItemIndex = Current(); - -//0/ Delete Track from playlist and save as current playlist in ConfigDir;; - if (ItemIndex == 0) { - - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); - - - if(MP3Setup.AdminMode >= 1) { - - if (mgr->maxIndex==0) - MP3Setup.DeleteTracks = 1; - else - MP3Setup.DeleteTrack = 1; - - return osBack; - } - else { - if(Interface->Confirm(tr("Remove track from playlist ?")) && Interface->Confirm(tr("Are you sure?")) ) { - if (mgr->maxIndex==0) - MP3Setup.DeleteTracks = 1; - else - MP3Setup.DeleteTrack = 1; - - return osBack; - } - } - } - - - -//1/ Empty playlist;; - if (ItemIndex == 1) { - if(MP3Setup.AdminMode >= 1) { - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - if(Interface->Confirm(tr("Remove all tracks from playlist ?")) ) { - Skins.Message(mtStatus, tr("Remove all tracks from playlist...")); - MP3Setup.DeleteTracks = 1; - Skins.Message(mtStatus, NULL); - return osBack; - } - } - } - - -//2/ Save playlist for burn..something with full path in ConfigDir;; - if (ItemIndex == 2) { - if(MP3Setup.AdminMode >= 1) { - Skins.Message(mtStatus, tr("Save playlist...")); - char *buf=0; - if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) - fprintf(stderr, "Failed to allocate string"); -#ifdef DEBUG - isyslog("music: commands: save playlust to '%s'", buf); -#endif - bool Result = mgr->SaveList(buf, true); - Skins.Message(mtStatus, NULL); - free(buf); - if (Result) - return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); - } - else { - if(Interface->Confirm(tr("Overwrite last playlist ?")) ) { - Skins.Message(mtStatus, tr("Save playlist...")); - char *buf=0; - if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) - fprintf(stderr, "Failed to allocate string"); -#ifdef DEBUG - isyslog("music: commands: save playlist to '%s'", buf); -#endif - bool Result = mgr->SaveList(buf, true); - Skins.Message(mtStatus, NULL); - free(buf); - if (Result) - return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); - } - } - } - - -//3/ Delete file from medium - if(MP3Setup.AdminMode >=1) { - if (ItemIndex == 4) { - - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); - - if(MP3Setup.AdminMode == 2) { - if (mgr->maxIndex==0) { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTrack = 1; - return osBack; - } - } - else { - if(Interface->Confirm(tr("Delete file from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { - if (mgr->maxIndex==0) { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTrack = 1; - return osBack; - } - } - } - } - - -//4/ Delete everything in playlist from medium - if (ItemIndex == 5) { - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove tracks !"), fontFix)); - - - if(Interface->Confirm(tr("Delete all in playlist from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { - Skins.Message(mtStatus, tr("Delete all tracks from medium...")); - bool Result = DeleteList(); - Skins.Message(mtStatus, NULL); - if (Result) { - return AddSubMenu(new cMenuText(tr("Delete"), tr("Tracks terminated !"), fontFix)); - MP3Setup.DeleteTracks = 1; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not delete tracks !"), fontFix)); - } - } - - } - - return osContinue; -} - -eOSState cMP3EditPlaylist::ProcessKey(eKeys Key) -{ - - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: - return osBack; - break; - case kOk: - return Execute(); - break; - default: - state = osContinue; - } - } - - return state; -} - - -bool cMP3EditPlaylist::DeleteList(void) -{ - std::ifstream filestr; - std::string datei; - std::string line; - int count=0; - bool res = false; - - datei=config; - datei=datei + "/playlists/deletelist.m3u"; - -#ifdef DEBUG - isyslog("music: commands: get deletelist.m3u from '%s'", datei.c_str()); -#endif - - if(mgr->SaveList(datei.c_str(), true)) { - filestr.open (datei.c_str()); - while ((getline(filestr,line,'\n'))) { - count++; - isyslog("music: delete file : %i %s\n",count,line.c_str()); - RemoveFileOrDir(line.c_str(), false); - } - filestr.close(); - res = true; - } - - return res; -} - - - -// ------------ cMP3Commands --------------------------------------------------------------------------------------------------- // - -cMP3Commands::cMP3Commands(void) -:cOsdMenu(tr("Music: Commands")) -{ -/* 0*/ Add(new cOsdItem(hk(tr("Edit playlist...")))); -/* 1*/ Add(new cOsdItem(hk(tr("Search for songs...")))); -/* 2*/ Add(new cOsdItem(hk(tr("Show ID3 information of song")))); -/* 3*/ Add(new cOsdItem(hk(tr("Edit ID3 information")))); -/* 4*/ Add(new cOsdItem(hk(tr("Quick settings...")))); -/* 5*/ Add(new cOsdItem(hk(tr("Search for lyric...")))); -/* 6*/ Add(new cOsdItem(hk(tr("Download coverpicture...")))); -/* 7*/ Add(new cOsdItem(hk(tr("Update webstreams...")))); -/* 8*/ Add(new cOsdItem(hk(tr("Start imageviewer")))); -/* 9*/ if(!MP3Setup.RecordStream) - Add(new cOsdItem(hk(tr("Start Recording")))); - else - Add(new cOsdItem(hk(tr("Stop Recording")))); -/* 10*/ Add(new cOsdItem(hk(tr("Change Appearance...")))); -/* 11*/ Add(new cOsdItem(hk(tr("Visualizations...")))); -/* 12*/ Add(new cOsdItem(hk(tr("Change user...")))); - - - SetHelp(); - LoadCommands(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } - - Display(); -} - - -cMP3Commands::~cMP3Commands() -{ -} - -void cMP3Commands::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - -void cMP3Commands::LoadCommands() -{ - std::string datei; - datei = langdir; - datei = datei + "/data/musiccmds.dat"; -#ifdef DEBUG - isyslog("music: commands: load commands from '%s%s'", config, datei.c_str()); -#endif - commands.Load(AddDirectory(config, datei.c_str()), true); -} - - -eOSState cMP3Commands::Execute(void) -{ - int ItemIndex = Current(); - -//0/ Edit Playlist;; - if (ItemIndex == 0) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - else - return AddSubMenu(new cMP3EditPlaylist("Edit playlist...")); - } - - -//1/ Search;; - if (ItemIndex == 1) { - if(mgr->maxIndex >0) { - std::string artist =""; - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { songinfo = mgr->Current()->Info(); } - if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } - return AddSubMenu(new cMP3Search(artist.c_str())); - } - else { - return AddSubMenu(new cMP3Search("")); - } - } - - -//2/ Show ID3Info;; - if (ItemIndex == 2) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - if(mgr->Current()) { - return AddSubMenu(new cMP3SearchID3Info(mgr->curr)); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); - } - } - - -//3/ Edit ID3 Tags - if (ItemIndex == 3) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - if(mgr->Current() && MP3Setup.user_is_admin && (MP3Setup.AdminMode >=2)) { - return AddSubMenu(new cMP3id3Tag(mgr->curr)); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: no songinfo or not allowed !"), fontFix)); - } - - } - - -//4/ Some options/commands - if (ItemIndex == 4) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - else - return AddSubMenu(new cMP3Options()); - } - - -//5/ Show Lyrics;; - if (ItemIndex == 5) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - return AddSubMenu(new cMP3Lyrics()); - } - - - if (ItemIndex == 1) { - std::string artist =""; - if(mgr->maxIndex >0) { - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { songinfo = mgr->Current()->Info(); } - if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } - return AddSubMenu(new cMP3Search(artist.c_str())); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); - } - } - - -//6/ Download Cover;; - if (ItemIndex == 6) { - std::string::size_type pos; - std::string artist = ""; - std::string album = ""; - std::string title = ""; - std::string baseDir = ""; - std::string filename = ""; - std::string Filenoext= ""; - - if(mgr->maxIndex >=0) { - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { - songinfo = mgr->Current()->Info(); - } - - if(songinfo) { - if(songinfo->Artist) { - artist = songinfo->Artist; - } - if(songinfo->Album) { - album = songinfo->Album; - } - if(songinfo->Title) { - title = songinfo->Title; - } - - cSong *s = mgr->curr; - - if(s) { - filename = s->Fullname(); - // get dir - int len = filename.length(); - pos = filename.rfind("/",len); - if(pos != std::string::npos) { - baseDir = filename.substr(0, pos+1); - } - // get file w/o ext. - pos = filename.rfind(".",len); - if(pos != std::string::npos) { - Filenoext = filename.substr(0, pos+1); - } - } - return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); - } - } -// else { -// return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); -// } - } - - -//7/ Update Webstreams;; - if (ItemIndex == 7) { - return AddSubMenu(new cMP3UpdateWebStreams()); - } - -//8/ Open Imageviewer;; - if (ItemIndex == 8) { - cRemote::CallPlugin("picselshow"); - return (osPlugin); - } - - -//9/ Start<->Stop Recording;; - if (ItemIndex == 9) { - - if (MP3Setup.AdminMode >= 2) { - if (MP3Setup.RecordStream) { - StopRecord(); - return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); - } - else { - if (MP3Setup.isWebstream) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - StartRecord(); - return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); - } - } - else { - if(MP3Setup.RecordStream) { - if(Interface->Confirm(tr("Stop recording ?")) ) { - StopRecord(); - return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); - } - } - else { - if (MP3Setup.isWebstream) { - if(Interface->Confirm(tr("Start recording ?")) ) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - StartRecord(); - return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); - } - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); - } - } - } - - -//10/ Themes;; - if (ItemIndex == 10) { - return AddSubMenu(new cMP3Themes()); - } - - -//11/ Visualization;; - if (ItemIndex == 11) { - return AddSubMenu(new cMP3Visual()); - } - - -//12/ User;; - if (ItemIndex == 12) { - return AddSubMenu(new cMP3User()); - } - - - -// From NOW on execute usercommands;; - if (ItemIndex >= 13) { - cCommand *command = commands.Get(ItemIndex-13); - if (command) { - char *buffer = NULL; - bool confirmed = true; - - std::string Artist =""; - std::string Album =""; - std::string Coverdir =""; - - cSongInfo *si = mgr->Current()->Info(false); - if(!si) si = mgr->Current()->Info(); - if(si && si->Artist)Artist = si->Artist; - if(si && si->Album) Album = si->Album; - if (command->Confirm()) { - if(asprintf(&buffer, "%s?", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command->Title()"); - confirmed = Interface->Confirm(buffer); - free(buffer); - } - if (confirmed) { - if(asprintf(&buffer, "%s...", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command->Title()"); - Skins.Message(mtStatus, buffer); - free(buffer); - - if(asprintf(&buffer, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", Songname, MP3Setup.CopyDir, Artist.c_str(), Album.c_str(), MP3Setup.CoverDir, config) == -1) - fprintf(stderr, "Failed to allocate string"); - - const char *Result = command->Execute(buffer); - - d(printf("music: commands: Executed: '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: executed: '%s'\n", buffer); -#endif - free(buffer); - Skins.Message(mtStatus, NULL); - if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); - return osBack; - } - } - } - - return osContinue; -} - -// ------------------ STARTRECORD -----------------------// -void cMP3Commands::StartRecord(void) -{ - FILE *recordcmd; - char *buffer; - - std::string url; - url = "\""; - url = url + urlname; - url = url + "\""; - - - d(printf("music: commands: Started Recording\n")); - if(asprintf(&buffer, "screen -A -m -d -S RECORD /usr/bin/streamripper %s -d '%s' -w %s%s/data/parse_rules.txt %s", url.c_str(), MP3Setup.RecordDir, config, langdir, MP3Setup.RecordOpts) == -1) - fprintf(stderr, "Failed to allocate string"); - - recordcmd = popen(buffer, "r"); - d(printf("music: commands: Starting recording '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: starting recording '%s'", buffer); -#endif - pclose(recordcmd); - - free(buffer); - MP3Setup.RecordStream = 1; -} - -// ------------------ STOPRECORD -----------------------// -void cMP3Commands::StopRecord(void) -{ - FILE *stoprecordcmd; - char *buffer; - - d(printf("music: commands: Stopped Recording\n")); - if(asprintf(&buffer, "killall -15 streamripper") == -1) - fprintf(stderr, "Failed to allocate string"); - - stoprecordcmd = popen(buffer, "r"); - d(printf("music: commands: Stop recording '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: stop recording '%s'", buffer); -#endif - pclose(stoprecordcmd); - - free(buffer); - MP3Setup.RecordStream = 0; -} - -eOSState cMP3Commands::ProcessKey(eKeys Key) -{ - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: - return osBack; - break; - case kOk: - return Execute(); - break; - default: - state = osContinue; - } - } - - return state; -} diff -Nru vdr-plugin-music-0.9.9/.pc/menu.diff/music-0.9.9/commands.c vdr-plugin-music-0.9.9/.pc/menu.diff/music-0.9.9/commands.c --- vdr-plugin-music-0.9.9/.pc/menu.diff/music-0.9.9/commands.c 2016-12-26 23:22:53.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/menu.diff/music-0.9.9/commands.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1357 +0,0 @@ - -#include -#include - -#include -#include -#include -#include - -#include "commands.h" -#include "i18n.h" -#include "player-mp3.h" -#include "decoder.h" -#include "skin.h" -#include "search.h" -#include "mp3id3.h" -#include "mp3id3tag.h" -#include "lyrics.h" -#include "cover.h" -#include "visual.h" -#include "options.h" -#include "vars.h" - -#define X_DISPLAY_MISSING -#define MAXLENGTH 256 -#define THEMESEXT "*.theme" -#define VISEXT "*.visual" -#define FINDCMD "cd '%s' && find '%s' -iname '%s' -printf '%%p\n' | sort -f" - -char urlname[256]; - -//---------------- cMP3UpdateWebStreams -------------------------------------------------------------------------------------------------------------------------- - - -class cMP3UpdateWebStreams : public cOsdMenu { -private: - cCommands commands; -// cOsdItem *Item(const char *name, const char *text); - void SetHelp(); - void ShowDisplay(void); - void UpdateGenre(); - eOSState Execute(void); - int limits, bitrate; - const char *bitrates[10]; -public: - cMP3UpdateWebStreams(void); - virtual ~cMP3UpdateWebStreams(); - virtual eOSState ProcessKey(eKeys Key); - void LoadCommand(); -}; - - -cMP3UpdateWebStreams::cMP3UpdateWebStreams(void) -:cOsdMenu(tr("Music: Update webstreams"),32) -{ - limits = MP3Setup.ShoutcastLimit; - bitrate = 192; -// bitrates = MP3Setup.ShoutcastBitrate; - - ShowDisplay(); -/* - Add(new cMenuEditIntItem(tr("Limit for stations"), &limits, 0 , 100)); - Add(new cMenuEditIntItem(tr("Bitrate for stations"), &bitrates, 0 , 100)); - - SetHelp(); - - LoadCommand(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } -*/ -} - -cMP3UpdateWebStreams::~cMP3UpdateWebStreams() -{ -} - -void cMP3UpdateWebStreams::ShowDisplay(void) -{ - Clear(); - Add(new cMenuEditIntItem(tr("Limit for Shoutcast"), &limits, 0 , 100)); - - bitrates[0]="32"; - bitrates[1]="48"; - bitrates[2]="56"; - bitrates[3]="64"; - bitrates[4]="96"; - bitrates[5]="128"; - bitrates[6]="160"; - bitrates[7]="192"; - bitrates[8]="256"; - bitrates[9]="320"; - Add(new cMenuEditStraItem(tr("Bitrate for Shoutcast"), &MP3Setup.ShoutcastBitrate, 10 , bitrates)); - Add(new cOsdItem(hk(tr("Update Genres")))); - - - LoadCommand(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } - - SetHelp(); - Display(); -} - -void cMP3UpdateWebStreams::SetHelp() { - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3UpdateWebStreams::LoadCommand() { - - std::string lingual; - - lingual = langdir; - lingual = lingual + "/data/shoutcast.dat"; - - commands.Load(AddDirectory(config, lingual.c_str()), true); -#ifdef DEBUG - isyslog("music: commands: load shoutcast.dat '%s%s'",config, lingual.c_str()); -#endif -} - - -void cMP3UpdateWebStreams::UpdateGenre() -{ - std::string datei; - - datei = config; - datei = datei + langdir; - datei = datei + "/scripts/music_updategenre.pl '"; - datei = datei + MP3Setup.WebstreamDat + "' '10' '192'"; - - Skins.Message(mtStatus, tr("Refreshing Genres")); - FILE *updatecmd; - updatecmd = popen(datei.c_str(), "r"); - pclose(updatecmd); - -#ifdef DEBUG - isyslog("music: commands: update genres '%s'", datei.c_str()); -#endif - - Display(); -} - - -eOSState cMP3UpdateWebStreams::Execute(void) { - - int ItemIndex = Current(); - if (ItemIndex <= 1) return osContinue; - - if (ItemIndex == 2) { - UpdateGenre(); - return osBack; - } - - - int parbit = MP3Setup.ShoutcastBitrate; - - switch(parbit) { - case 0: bitrate = 32; break; - case 1: bitrate = 48; break; - case 2: bitrate = 56; break; - case 3: bitrate = 64; break; - case 4: bitrate = 96; break; - case 5: bitrate = 128; break; - case 6: bitrate = 160; break; - case 7: bitrate = 192; break; - case 8: bitrate = 256; break; - case 9: bitrate = 320; break; - default : break; - } - - - cCommand *command = commands.Get(Current() -3); - if (command) { - char *buffer = NULL; - bool confirmed = true; - - if (command->Confirm()) { - if (asprintf(&buffer, "%s?", command->Title()) == -1) { - fprintf(stderr, "Failed to allocate string for command-Title"); - return osBack; - } - confirmed = Interface->Confirm(buffer); - free(buffer); - } - if (confirmed) { - if (asprintf(&buffer, "%s...", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command-Title"); - - Skins.Message(mtStatus, buffer); - free(buffer); - - char *parameters; - if (asprintf(¶meters, " '%d' '%d' '%s';", limits, bitrate, MP3Setup.WebstreamDat) == -1) - fprintf(stderr, "Failed to allocate string"); - - const char *Result = command->Execute(parameters); - free(parameters); - - Skins.Message(mtStatus, NULL); - if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); - return osBack; - } - } - - return osContinue; -} - - -eOSState cMP3UpdateWebStreams::ProcessKey(eKeys Key) { - - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: state = osBack; - case kGreen: - case kYellow: - case kBlue: state = osContinue; - case kOk: state = Execute(); - default: state = osContinue; - } - } - - return state; -} - - - -// ------------ cMP3ThemesItem ----------------------------------------------------------------------------------------------- // - -class cMP3ThemesItem : public cOsdItem { -private: - cFileObjItem *item; - virtual void Set(void); - int idx; -public: - cMP3ThemesItem(cFileObjItem *Item, int index); - cFileObjItem *Item(void) {return item;} - ~cMP3ThemesItem(); -}; - - -cMP3ThemesItem::cMP3ThemesItem(cFileObjItem *Item, int index) { - idx = index; - item = Item; - Set(); -} - -cMP3ThemesItem::~cMP3ThemesItem(){ -} - -void cMP3ThemesItem::Set(void) { - char *Name; - - if (asprintf(&Name,"%s", item->Name()) == -1) - fprintf(stderr, "Failed to allocate string for item->Name()"); - - SetText(Name,false); -} - - -// ------------ cMP3Themes --------------------------------------------------------------------------------------------------- // - -class cMP3Themes : public cOsdMenu { -private: - void SetHelp(); - void LoadSkinFiles(); - eOSState SetTheme(void); - cFileObjItem *newitem; -protected: - cFileObjItem *CurrentFileObjItem(void); -public: - cMP3Themes(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3Themes::cMP3Themes(void) -:cOsdMenu(tr("Music: Appearance"),4) -{ - - LoadSkinFiles(); - SetHelp(); -} - -void cMP3Themes::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3Themes::LoadSkinFiles() -{ - int count = 0; - - char *cmd = NULL; - cReadLine reader; - - std::string plugindir; - std::string themename; - std::string themefile; - std::string Base; - - plugindir = config; - plugindir = plugindir + "/themes/"; - -#ifdef DEBUG - isyslog("music: commands: load themes from '%s'", plugindir.c_str()); -#endif - - int len2 = plugindir.length()+1; - - - if (asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), THEMESEXT) == -1) - fprintf(stderr, "Failed to allocate string"); - - FILE *p = popen(cmd, "r"); - - if(p) { - char *s; - while ((s = reader.Read(p)) != NULL) { - count++; - themefile = s; - int len = themefile.length(); - std::string::size_type pos = themefile.rfind('/',len); - if(pos!=std::string::npos) { - // Filename - themename = themefile.substr(pos+1,len); - // Basedir - int sublen = len - len2 - themename.length()-1; - Base = themefile.substr(len2,sublen); - } - newitem = new cFileObjItem(plugindir.c_str(), themename.c_str(), otFile); - if(newitem && newitem->Type()==otFile) { - Add(new cMP3ThemesItem(newitem, count)); - } - } - pclose(p); - } - else - Skins.Message(mtError, tr("ERROR: Havent found any themes !")); - - free(cmd); -} - -cFileObjItem *cMP3Themes::CurrentFileObjItem(void) -{ - cMP3ThemesItem *item = (cMP3ThemesItem *)Get(Current()); - return item ? item->Item():0; -} - - -eOSState cMP3Themes::SetTheme(void) -{ - cFileObjItem *item=CurrentFileObjItem(); - - if(item && item->Type()==otFile) { - if(MP3Skin.StoreSkin(item->Name())) { - MP3Skin.ParseSkin("current.colors"); - MP3Skin.ReloadFonts=1; - return osBack; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not store/load new themefile !"), fontFix)); - } - - return osContinue; -} - - -eOSState cMP3Themes::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetTheme(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - - -// ------------ cMP3VisualItem --------------------------------------------------------------------------------------------- // - -class cMP3VisualItem : public cOsdItem { -private: - cFileObjItem *item; - virtual void Set(void); - int idx; -public: - cMP3VisualItem(cFileObjItem *Item, int index); - cFileObjItem *Item(void) {return item;} - ~cMP3VisualItem(); -}; - - -cMP3VisualItem::cMP3VisualItem(cFileObjItem *Item, int index) -{ - idx = index; - item = Item; - Set(); -} - -cMP3VisualItem::~cMP3VisualItem() -{ -} - -void cMP3VisualItem::Set(void) -{ - char *Name; - - if(asprintf(&Name,"%s", item->Name()) == -1) - fprintf(stderr, "Failed to allocate string for item->Name()"); - - SetText(Name,false); -} - - -// ------------ cMP3Visual ------------------------------------------------------------------------------------------------- // - -class cMP3Visual : public cOsdMenu { -private: - void SetHelp(); - void LoadVisFiles(); - eOSState SetVis(void); - cFileObjItem *newitem; -protected: - cFileObjItem *CurrentFileObjItem(void); -public: - cMP3Visual(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3Visual::cMP3Visual(void) -:cOsdMenu(tr("Music: Visualizations"),4) -{ - Add(new cOsdItem(hk(tr("Disable visualization")))); - LoadVisFiles(); - SetHelp(); -} - -void cMP3Visual::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -void cMP3Visual::LoadVisFiles() -{ - int count = 0; - - char *cmd = NULL; - cReadLine reader; - - std::string plugindir; - std::string visname; - std::string visfile; - std::string visBase; - - plugindir = config; - plugindir = plugindir + "/visual/themes/"; - -#ifdef DEBUG - isyslog("music: commands: load visfiles from '%s'", plugindir.c_str()); -#endif - - int len2 = plugindir.length()+1; - - - if(asprintf(&cmd, FINDCMD, plugindir.c_str(), plugindir.c_str(), VISEXT) == -1) - fprintf(stderr, "Failed to allocate string"); - - FILE *p = popen(cmd, "r"); - - if(p) { - char *s; - while ((s = reader.Read(p)) != NULL) { - count++; - visfile = s; - int len = visfile.length(); - std::string::size_type pos = visfile.rfind('/',len); - if(pos!=std::string::npos) { - // Filename - visname = visfile.substr(pos+1,len); - // Basedir - int sublen = len - len2 - visname.length()-1; - visBase = visfile.substr(len2,sublen); - } - newitem = new cFileObjItem(plugindir.c_str(), visname.c_str(), otFile); - if(newitem && newitem->Type()==otFile) { - Add(new cMP3VisualItem(newitem, count)); - } - } - pclose(p); - } - else - Skins.Message(mtError, tr("ERROR: Cant find any visualization!")); - - free(cmd); -} - -cFileObjItem *cMP3Visual::CurrentFileObjItem(void) -{ - cMP3VisualItem *item = (cMP3VisualItem *)Get(Current()); - return item ? item->Item():0; -} - - -eOSState cMP3Visual::SetVis(void) -{ - int ItemIndex = Current(); - cFileObjItem *item=CurrentFileObjItem(); - - if(ItemIndex == 0) { - MP3Setup.EnableVis = false; - std::string file; - if(!MP3Setup.isWebstream) { - file = config; - file = file + "/themes/defaultcover/music-default-cover.png"; - strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); - } - else { - file = config; - file = file + "/themes/defaultcover/music-default-stream.png"; - strncpy(coverpicture,file.c_str(),sizeof(coverpicture)); - } - return osBack; - } - else if (ItemIndex >= 1) { - if(item && item->Type()==otFile) { - if(MP3VisLoader.LoadVis(item->Name())) { - MP3Setup.EnableVis = true; - MP3VisLoader.SetVis(); - strncpy(coverpicture,MP3VisLoader.VisLoaderBackground(),sizeof(coverpicture)); - - if(MP3VisLoader.StoreVis(item->Name())) - isyslog("music: stored '%s' as 'current.vis'\n", item->Name()); - else - esyslog("music: could not store '%s' as 'current.vis'\n", item->Name()); - - return osBack; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not load new visualization !"), fontFix)); - } - } - - return osContinue; -} - - -eOSState cMP3Visual::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetVis(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - -// ------------ cMP3User --------------------------------------------------------------------------------------------------- // - -class cMP3User : public cOsdMenu { -private: - void SetHelp(); - void LoadUsername(); - eOSState SetUser(void); - cOsdItem *Item(const char *text); -public: - cMP3User(void); - virtual eOSState ProcessKey(eKeys Key); -}; - - -cMP3User::cMP3User(void) -:cOsdMenu(tr("Music: User"),4) -{ - LoadUsername(); - SetHelp(); -} - -void cMP3User::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -cOsdItem *cMP3User::Item(const char *text) -{ - char *buf=0; - if(asprintf(&buf, "%s",text?text:"") == -1) - fprintf(stderr, "Failed to allocate string for text"); - - cOsdItem *item = new cOsdItem(buf,osUnknown,true); - free(buf); - Add(item); return item; -} - -void cMP3User::LoadUsername() -{ - std::ifstream filestr; - std::string userfile; - std::string line; - - userfile = config; - userfile = userfile + "/data/user.dat"; - -#ifdef DEBUG - isyslog("music: commands: load user.dat from '%s'", userfile.c_str()); -#endif - - filestr.open(userfile.c_str()); - - if(filestr) { - while ((getline(filestr,line,'\n'))) { - Item(line.c_str()); - } - filestr.close(); - } -} - - -eOSState cMP3User::SetUser(void) -{ - cOsdItem *item=(cOsdItem*)Get(Current()); - - std::string datei; - datei = config; - datei = datei + "/data/current_user.dat"; - -#ifdef DEBUG - isyslog("music: commands: load current_user.dat from '%s'", datei.c_str()); -#endif - - - if(item) { - if(Interface->Confirm(tr("Change user (Music will be stopped) ?")) ) { - InfoCache.Save(true); - if( FILE *f = fopen ( datei.c_str(), "w")) { - std::string user; - user = item->Text(); - fprintf(f, "%s\n", user.c_str()); - isyslog("music: change to user <%s>\n", user.c_str()); - fclose(f); - InfoCache.Load(true); - } - return osEnd; - } - - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not change user !"), fontFix)); - - return osContinue; -} - - -eOSState cMP3User::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if(state==osUnknown) { - switch(Key) { - case kOk: - state = SetUser(); - break; - case kBlue: - case kGreen: - case kYellow: - case kRed: return osBack; - default: return osContinue;; - } - } - return state; -} - - - -// ------------ cMP3EditPlaylist ---------------------------------------------------------------------------------------------- // - -cMP3EditPlaylist::cMP3EditPlaylist(const char *sz_Title) -:cOsdMenu(tr(sz_Title)) -{ -//0 - Add(new cOsdItem(hk(tr("Remove track from playlist")))); -//1 - Add(new cOsdItem(hk(tr("Remove all from playlist")))); -//2 - Add(new cOsdItem(hk(tr("Save active playlist")))); - - if(MP3Setup.AdminMode >= 2) { - -//3 - cOsdItem *item = new cOsdItem(hk("")); - Add(item, osUnknown); - item->SetSelectable(false); - -//4 - Add(new cOsdItem(hk(tr("Delete selected track from medium")))); -//5 - Add(new cOsdItem(hk(tr("Delete all tracks in playlist from medium")))); - } - - - SetHelp(); -} - - -void cMP3EditPlaylist::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - - -eOSState cMP3EditPlaylist::Execute(void) -{ - - int ItemIndex = Current(); - -//0/ Delete Track from playlist and save as current playlist in ConfigDir;; - if (ItemIndex == 0) { - - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); - - - if(MP3Setup.AdminMode >= 1) { - - if (mgr->maxIndex==0) - MP3Setup.DeleteTracks = 1; - else - MP3Setup.DeleteTrack = 1; - - return osBack; - } - else { - if(Interface->Confirm(tr("Remove track from playlist ?")) && Interface->Confirm(tr("Are you sure?")) ) { - if (mgr->maxIndex==0) - MP3Setup.DeleteTracks = 1; - else - MP3Setup.DeleteTrack = 1; - - return osBack; - } - } - } - - - -//1/ Empty playlist;; - if (ItemIndex == 1) { - if(MP3Setup.AdminMode >= 1) { - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - if(Interface->Confirm(tr("Remove all tracks from playlist ?")) ) { - Skins.Message(mtStatus, tr("Remove all tracks from playlist...")); - MP3Setup.DeleteTracks = 1; - Skins.Message(mtStatus, NULL); - return osBack; - } - } - } - - -//2/ Save playlist for burn..something with full path in ConfigDir;; - if (ItemIndex == 2) { - if(MP3Setup.AdminMode >= 1) { - Skins.Message(mtStatus, tr("Save playlist...")); - char *buf=0; - if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) - fprintf(stderr, "Failed to allocate string"); -#ifdef DEBUG - isyslog("music: commands: save playlust to '%s'", buf); -#endif - bool Result = mgr->SaveList(buf, true); - Skins.Message(mtStatus, NULL); - free(buf); - if (Result) - return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); - } - else { - if(Interface->Confirm(tr("Overwrite last playlist ?")) ) { - Skins.Message(mtStatus, tr("Save playlist...")); - char *buf=0; - if(asprintf(&buf, "%s%s", config, "/playlists/burnlist.m3u") == -1) - fprintf(stderr, "Failed to allocate string"); -#ifdef DEBUG - isyslog("music: commands: save playlist to '%s'", buf); -#endif - bool Result = mgr->SaveList(buf, true); - Skins.Message(mtStatus, NULL); - free(buf); - if (Result) - return AddSubMenu(new cMenuText(tr("Save playlist"), tr("Playlist saved as burnlist.m3u !"), fontFix)); - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not save playlist burnlist.m3u !"), fontFix)); - } - } - } - - -//3/ Delete file from medium - if(MP3Setup.AdminMode >=1) { - if (ItemIndex == 4) { - - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove track !"), fontFix)); - - if(MP3Setup.AdminMode == 2) { - if (mgr->maxIndex==0) { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTrack = 1; - return osBack; - } - } - else { - if(Interface->Confirm(tr("Delete file from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { - if (mgr->maxIndex==0) { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTracks = 1; - return osBack; - } - else { - RemoveFileOrDir(Songname, false); - MP3Setup.DeleteTrack = 1; - return osBack; - } - } - } - } - - -//4/ Delete everything in playlist from medium - if (ItemIndex == 5) { - if(mgr->maxIndex <= -1) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not remove tracks !"), fontFix)); - - - if(Interface->Confirm(tr("Delete all in playlist from medium ?")) && Interface->Confirm(tr("Are you sure?")) ) { - Skins.Message(mtStatus, tr("Delete all tracks from medium...")); - bool Result = DeleteList(); - Skins.Message(mtStatus, NULL); - if (Result) { - return AddSubMenu(new cMenuText(tr("Delete"), tr("Tracks terminated !"), fontFix)); - MP3Setup.DeleteTracks = 1; - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not delete tracks !"), fontFix)); - } - } - - } - - return osContinue; -} - -eOSState cMP3EditPlaylist::ProcessKey(eKeys Key) -{ - - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: - return osBack; - break; - case kOk: - return Execute(); - break; - default: - state = osContinue; - } - } - - return state; -} - - -bool cMP3EditPlaylist::DeleteList(void) -{ - std::ifstream filestr; - std::string datei; - std::string line; - int count=0; - bool res = false; - - datei=config; - datei=datei + "/playlists/deletelist.m3u"; - -#ifdef DEBUG - isyslog("music: commands: get deletelist.m3u from '%s'", datei.c_str()); -#endif - - if(mgr->SaveList(datei.c_str(), true)) { - filestr.open (datei.c_str()); - while ((getline(filestr,line,'\n'))) { - count++; - isyslog("music: delete file : %i %s\n",count,line.c_str()); - RemoveFileOrDir(line.c_str(), false); - } - filestr.close(); - res = true; - } - - return res; -} - - - -// ------------ cMP3Commands --------------------------------------------------------------------------------------------------- // - -cMP3Commands::cMP3Commands(void) -:cOsdMenu(tr("Music: Commands")) -{ -/* 0*/ Add(new cOsdItem(hk(tr("Edit playlist...")))); -/* 1*/ Add(new cOsdItem(hk(tr("Search for songs...")))); -/* 2*/ Add(new cOsdItem(hk(tr("Show ID3 information of song")))); -/* 3*/ Add(new cOsdItem(hk(tr("Edit ID3 information")))); -/* 4*/ Add(new cOsdItem(hk(tr("Quick settings...")))); -/* 5*/ Add(new cOsdItem(hk(tr("Search for lyric...")))); -/* 6*/ Add(new cOsdItem(hk(tr("Download coverpicture...")))); -/* 7*/ Add(new cOsdItem(hk(tr("Update webstreams...")))); -/* 8*/ Add(new cOsdItem(hk(tr("Start imageviewer")))); -/* 9*/ if(!MP3Setup.RecordStream) - Add(new cOsdItem(hk(tr("Start Recording")))); - else - Add(new cOsdItem(hk(tr("Stop Recording")))); -/* 10*/ Add(new cOsdItem(hk(tr("Change Appearance...")))); -/* 11*/ Add(new cOsdItem(hk(tr("Visualizations...")))); -/* 12*/ Add(new cOsdItem(hk(tr("Change user...")))); - - - SetHelp(); - LoadCommands(); - - for (cCommand *command = commands.First(); command; command = commands.Next(command)) { - cOsdItem *item = new cOsdItem(hk(command->Title())); - Add(item, osUnknown); - if(strstr(item->Text(), "----------")) - item->SetSelectable(false); - else - item->SetSelectable(true); - } - - Display(); -} - - -cMP3Commands::~cMP3Commands() -{ -} - -void cMP3Commands::SetHelp() -{ - cOsdMenu::SetHelp(tr("Parent"),NULL,NULL,NULL); -} - -void cMP3Commands::LoadCommands() -{ - std::string datei; - datei = langdir; - datei = datei + "/data/musiccmds.dat"; -#ifdef DEBUG - isyslog("music: commands: load commands from '%s%s'", config, datei.c_str()); -#endif - commands.Load(AddDirectory(config, datei.c_str()), true); -} - - -eOSState cMP3Commands::Execute(void) -{ - int ItemIndex = Current(); - -//0/ Edit Playlist;; - if (ItemIndex == 0) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - else - return AddSubMenu(new cMP3EditPlaylist("Edit playlist...")); - } - - -//1/ Search;; - if (ItemIndex == 1) { - if(mgr->maxIndex >0) { - std::string artist =""; - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { songinfo = mgr->Current()->Info(); } - if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } - return AddSubMenu(new cMP3Search(artist.c_str())); - } - else { - return AddSubMenu(new cMP3Search("")); - } - } - - -//2/ Show ID3Info;; - if (ItemIndex == 2) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - if(mgr->Current()) { - return AddSubMenu(new cMP3SearchID3Info(mgr->curr)); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); - } - } - - -//3/ Edit ID3 Tags - if (ItemIndex == 3) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - if(mgr->Current() && MP3Setup.user_is_admin && (MP3Setup.AdminMode >=2)) { - return AddSubMenu(new cMP3id3Tag(mgr->curr)); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: no songinfo or not allowed !"), fontFix)); - } - - } - - -//4/ Some options/commands - if (ItemIndex == 4) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - else - return AddSubMenu(new cMP3Options()); - } - - -//5/ Show Lyrics;; - if (ItemIndex == 5) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - - return AddSubMenu(new cMP3Lyrics()); - } - - - if (ItemIndex == 1) { - std::string artist =""; - if(mgr->maxIndex >0) { - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { songinfo = mgr->Current()->Info(); } - if(songinfo && songinfo->Artist) { artist = songinfo->Artist; } - return AddSubMenu(new cMP3Search(artist.c_str())); - } - else { - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: Could not get songinfo !"), fontFix)); - } - } - - -//6/ Download Cover;; - if (ItemIndex == 6) { - std::string::size_type pos; - std::string artist = ""; - std::string album = ""; - std::string title = ""; - std::string baseDir = ""; - std::string filename = ""; - std::string Filenoext= ""; - - if(mgr->maxIndex >=0) { - cSongInfo *songinfo = mgr->Current()->Info(false); - if(!songinfo) { - songinfo = mgr->Current()->Info(); - } - - if(songinfo) { - if(songinfo->Artist) { - artist = songinfo->Artist; - } - if(songinfo->Album) { - album = songinfo->Album; - } - if(songinfo->Title) { - title = songinfo->Title; - } - - cSong *s = mgr->curr; - - if(s) { - filename = s->Fullname(); - // get dir - int len = filename.length(); - pos = filename.rfind("/",len); - if(pos != std::string::npos) { - baseDir = filename.substr(0, pos+1); - } - // get file w/o ext. - pos = filename.rfind(".",len); - if(pos != std::string::npos) { - Filenoext = filename.substr(0, pos+1); - } - } - return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); - } - } -// else { -// return AddSubMenu( new cMP3Cover(artist.c_str(), album.c_str(), title.c_str(), baseDir.c_str(), Filenoext.c_str()) ); -// } - } - - -//7/ Update Webstreams;; - if (ItemIndex == 7) { - return AddSubMenu(new cMP3UpdateWebStreams()); - } - -//8/ Open Imageviewer;; - if (ItemIndex == 8) { - cRemote::CallPlugin("picselshow"); - return (osPlugin); - } - - -//9/ Start<->Stop Recording;; - if (ItemIndex == 9) { - - if (MP3Setup.AdminMode >= 2) { - if (MP3Setup.RecordStream) { - StopRecord(); - return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); - } - else { - if (MP3Setup.isWebstream) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - StartRecord(); - return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); - } - } - else { - if(MP3Setup.RecordStream) { - if(Interface->Confirm(tr("Stop recording ?")) ) { - StopRecord(); - return AddSubMenu(new cMenuText(tr("Stop Recording"), tr("Recording stopped !"), fontFix)); - } - } - else { - if (MP3Setup.isWebstream) { - if(Interface->Confirm(tr("Start recording ?")) ) { - if(mgr->maxIndex <0) - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("ERROR: No track(s) loaded !"), fontFix)); - StartRecord(); - return AddSubMenu(new cMenuText(tr("Start Recording"), tr("Recording started !"), fontFix)); - } - } - else - return AddSubMenu(new cMenuText(tr("ERROR:"), tr("What you want to record ?!"), fontFix)); - } - } - } - - -//10/ Themes;; - if (ItemIndex == 10) { - return AddSubMenu(new cMP3Themes()); - } - - -//11/ Visualization;; - if (ItemIndex == 11) { - return AddSubMenu(new cMP3Visual()); - } - - -//12/ User;; - if (ItemIndex == 12) { - return AddSubMenu(new cMP3User()); - } - - - -// From NOW on execute usercommands;; - if (ItemIndex >= 13) { - cCommand *command = commands.Get(ItemIndex-13); - if (command) { - char *buffer = NULL; - bool confirmed = true; - - std::string Artist =""; - std::string Album =""; - std::string Coverdir =""; - - cSongInfo *si = mgr->Current()->Info(false); - if(!si) si = mgr->Current()->Info(); - if(si && si->Artist)Artist = si->Artist; - if(si && si->Album) Album = si->Album; - if (command->Confirm()) { - if(asprintf(&buffer, "%s?", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command->Title()"); - confirmed = Interface->Confirm(buffer); - free(buffer); - } - if (confirmed) { - if(asprintf(&buffer, "%s...", command->Title()) == -1) - fprintf(stderr, "Failed to allocate string for command->Title()"); - Skins.Message(mtStatus, buffer); - free(buffer); - - if(asprintf(&buffer, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", Songname, MP3Setup.CopyDir, Artist.c_str(), Album.c_str(), MP3Setup.CoverDir, config) == -1) - fprintf(stderr, "Failed to allocate string"); - - const char *Result = command->Execute(buffer); - - d(printf("music: commands: Executed: '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: executed: '%s'\n", buffer); -#endif - free(buffer); - Skins.Message(mtStatus, NULL); - if(Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); - return osBack; - } - } - } - - return osContinue; -} - -// ------------------ STARTRECORD -----------------------// -void cMP3Commands::StartRecord(void) -{ - FILE *recordcmd; - char *buffer; - - std::string url; - url = "\""; - url = url + urlname; - url = url + "\""; - - - d(printf("music: commands: Started Recording\n")); - if(asprintf(&buffer, "screen -A -m -d -S RECORD /usr/bin/streamripper %s -d '%s' -w %s%s/data/parse_rules.txt %s", url.c_str(), MP3Setup.RecordDir, config, langdir, MP3Setup.RecordOpts) == -1) - fprintf(stderr, "Failed to allocate string"); - - recordcmd = popen(buffer, "r"); - d(printf("music: commands: Starting recording '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: starting recording '%s'", buffer); -#endif - pclose(recordcmd); - - free(buffer); - MP3Setup.RecordStream = 1; -} - -// ------------------ STOPRECORD -----------------------// -void cMP3Commands::StopRecord(void) -{ - FILE *stoprecordcmd; - char *buffer; - - d(printf("music: commands: Stopped Recording\n")); - if(asprintf(&buffer, "killall -15 streamripper") == -1) - fprintf(stderr, "Failed to allocate string"); - - stoprecordcmd = popen(buffer, "r"); - d(printf("music: commands: Stop recording '%s'\n", buffer)); -#ifdef DEBUG - isyslog("music: commands: stop recording '%s'", buffer); -#endif - pclose(stoprecordcmd); - - free(buffer); - MP3Setup.RecordStream = 0; -} - -eOSState cMP3Commands::ProcessKey(eKeys Key) -{ - bool hadSubmenu = HasSubMenu(); - - eOSState state = cOsdMenu::ProcessKey(Key); - - if (hadSubmenu && !HasSubMenu()) - return osBack; - - if (state == osUnknown) { - switch (Key) { - case kRed: - return osBack; - break; - case kOk: - return Execute(); - break; - default: - state = osContinue; - } - } - - return state; -} diff -Nru vdr-plugin-music-0.9.9/.pc/music_ggc-7_fix.patch/player-mp3.c vdr-plugin-music-0.9.9/.pc/music_ggc-7_fix.patch/player-mp3.c --- vdr-plugin-music-0.9.9/.pc/music_ggc-7_fix.patch/player-mp3.c 1970-01-01 00:00:00.000000000 +0000 +++ vdr-plugin-music-0.9.9/.pc/music_ggc-7_fix.patch/player-mp3.c 2020-11-26 22:13:51.000000000 +0000 @@ -0,0 +1,2772 @@ +/* + * MP3/MPlayer plugin to VDR (C++) + * + * (C) 2001-2005 Stefan Huelswitt + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "i18n.h" +#include "common.h" +#include "setup-mp3.h" +#include "setup.h" +#include "player-mp3.h" +#include "data-mp3.h" +#include "decoder.h" +#include "decoder-core.h" +#include "skin.h" +#include "visual.h" +#include "vars.h" + +#ifndef NO_DEBUG +#define DEBUG_MODE // debug playmode changes +#define DEBUG_BGR // debug backround scan thread +#define DEBUG_DELAY 300 // debug write/decode delays +//#define ACC_DUMP // dump limiter lookup table to /tmp/limiter +#endif + +#if !defined(NO_DEBUG) && defined(DEBUG_MODE) +#define dm(x) { (x); } +#else +#define dm(x) ; +#endif + +#if !defined(NO_DEBUG) && defined(DEBUG_BGR) +#define db(x) { (x); } +#else +#define db(x) ; +#endif + +// ---------------------------------------------------------------- + +#define MP3BUFSIZE (1024*1024) // output ringbuffer size +#define OUT_BITS 16 // output 16 bit samples to DVB driver +#define OUT_FACT (OUT_BITS/8*2) // output factor is 16 bit & 2 channels -> 4 bytes +// cResample +#define MAX_NSAMPLES (1152*7) // max. buffer for resampled frame +// cNormalize +#define MIN_GAIN 0.03 // min. gain required to launch the normalizer +#define MAX_GAIN 3.0 // max. allowed gain +#define USE_FAST_LIMITER +#define LIM_ACC 12 // bit, accuracy for lookup table +#define F_LIM_MAX (mad_fixed_t)((1<<(MAD_F_FRACBITS+2))-1) // max. value covered by lookup table +#define LIM_SHIFT (MAD_F_FRACBITS-LIM_ACC) // shift value for table lookup +#define F_LIM_JMP (mad_fixed_t)(1<newrate*6) { // out of range + esyslog("music: WARNING: samplerate %d out of range 8000-%d\n",oldrate,newrate*6); + return 0; + } + ratio=mad_f_tofixed((double)oldrate/(double)newrate); + step=0; last=0; +#ifdef DEBUG + static mad_fixed_t oldratio=0; + if(oldratio!=ratio) { + printf("music: mad: new resample ratio %f (from %d kHz to %d kHz)\n",mad_f_todouble(ratio),oldrate,newrate); + oldratio=ratio; + } +#endif + return ratio!=MAD_F_ONE; +} + +unsigned int cResample::ResampleBlock(unsigned int nsamples, const mad_fixed_t *old) +{ + // This resampling algorithm is based on a linear interpolation, which is + // not at all the best sounding but is relatively fast and efficient. + // + // A better algorithm would be one that implements a bandlimited + // interpolation. + + mad_fixed_t *nsam=resampled; + const mad_fixed_t *end=old+nsamples; + const mad_fixed_t *begin=nsam; + + if(step < 0) { + step = mad_f_fracpart(-step); + + while (step < MAD_F_ONE) { + *nsam++ = step ? last+mad_f_mul(*old-last,step) : last; + step += ratio; + if(((step + 0x00000080L) & 0x0fffff00L) == 0) + step = (step + 0x00000080L) & ~0x0fffffffL; + } + step -= MAD_F_ONE; + } + + while (end - old > 1 + mad_f_intpart(step)) { + old += mad_f_intpart(step); + step = mad_f_fracpart(step); + *nsam++ = step ? *old + mad_f_mul(old[1] - old[0], step) : *old; + step += ratio; + if (((step + 0x00000080L) & 0x0fffff00L) == 0) + step = (step + 0x00000080L) & ~0x0fffffffL; + } + + if (end - old == 1 + mad_f_intpart(step)) { + last = end[-1]; + step = -step; + } + else step -= mad_f_fromint(end - old); + + return nsam-begin; +} + +// --- cLevel ---------------------------------------------------------------- + +// The normalize algorithm and parts of the code has been adapted from the +// Normalize 0.7 project. (C) 1999-2002, Chris Vaill + +// A little background on how normalize computes the volume +// of a wav file, in case you want to know just how your +// files are being munged: +// +// The volumes calculated are RMS amplitudes, which corre­ +// spond (roughly) to perceived volume. Taking the RMS ampli­ +// tude of an entire file would not give us quite the measure +// we want, though, because a quiet song punctuated by short +// loud parts would average out to a quiet song, and the +// adjustment we would compute would make the loud parts +// excessively loud. +// +// What we want is to consider the maximum volume of the +// file, and normalize according to that. We break up the +// signal into 100 chunks per second, and get the signal +// power of each chunk, in order to get an estimation of +// "instantaneous power" over time. This "instantaneous +// power" signal varies too much to get a good measure of the +// original signal's maximum sustained power, so we run a +// smoothing algorithm over the power signal (specifically, a +// mean filter with a window width of 100 elements). The max­ +// imum point of the smoothed power signal turns out to be a +// good measure of the maximum sustained power of the file. +// We can then take the square root of the power to get maxi­ +// mum sustained RMS amplitude. + +class cLevel { +private: + double maxpow; + mad_fixed_t peak; + struct Power { + // smooth + int npow, wpow; + double powsum, pows[POW_WIN]; + // sum + unsigned int nsum; + double sum; + } power[2]; + // + inline void AddPower(struct Power *p, double pow); +public: + void Init(void); + void GetPower(struct mad_pcm *pcm); + double GetLevel(void); + double GetPeak(void); + }; + +void cLevel::Init(void) +{ + for(int l=0 ; l<2 ; l++) { + struct Power *p=&power[l]; + p->sum=p->powsum=0.0; p->wpow=p->npow=p->nsum=0; + for(int i=POW_WIN-1 ; i>=0 ; i--) p->pows[i]=0.0; + } + maxpow=0.0; peak=0; +} + +void cLevel::GetPower(struct mad_pcm *pcm) +{ + for(int i=0 ; ichannels ; i++) { + struct Power *p=&power[i]; + mad_fixed_t *data=pcm->samples[i]; + for(int n=pcm->length ; n>0 ; n--) { + if(*data < -peak) peak = -*data; + if(*data > peak) peak = *data; + double s=mad_f_todouble(*data++); + p->sum+=(s*s); + if(++(p->nsum)>=pcm->samplerate/100) { + AddPower(p,p->sum/(double)p->nsum); + p->sum=0.0; p->nsum=0; + } + } + } +} + +void cLevel::AddPower(struct Power *p, double pow) +{ + p->powsum+=pow; + if(p->npow>=POW_WIN) { + if(p->powsum>maxpow) maxpow=p->powsum; + p->powsum-=p->pows[p->wpow]; + } + else p->npow++; + p->pows[p->wpow]=pow; + p->wpow=(p->wpow+1) % POW_WIN; +} + +double cLevel::GetLevel(void) +{ + if(maxpowmaxpow) maxpow=power[0].powsum; + if(power[1].powsum>maxpow) maxpow=power[1].powsum; + } + double level=sqrt(maxpow/(double)POW_WIN); // adjust for the smoothing window size and root + d(printf("music: norm: new volumen level=%f peak=%f\n",level,mad_f_todouble(peak))) + return level; +} + +double cLevel::GetPeak(void) +{ + return mad_f_todouble(peak); +} + +// --- cNormalize ------------------------------------------------------------ + +class cNormalize { +private: + mad_fixed_t gain; + double d_limlvl, one_limlvl; + mad_fixed_t limlvl; + bool dogain, dolimit; +#ifdef DEBUG + // stats + unsigned long limited, clipped, total; + mad_fixed_t peak; +#endif + // limiter +#ifdef USE_FAST_LIMITER + mad_fixed_t *table, tablestart; + int tablesize; + inline mad_fixed_t FastLimiter(mad_fixed_t x); +#endif + inline mad_fixed_t Limiter(mad_fixed_t x); +public: + cNormalize(void); + ~cNormalize(); + void Init(double Level, double Peak); + void Stats(void); + void AddGain(struct mad_pcm *pcm); + }; + +cNormalize::cNormalize(void) +{ + d_limlvl=(double)MP3Setup.LimiterLevel/100.0; + one_limlvl=1-d_limlvl; + limlvl=mad_f_tofixed(d_limlvl); + d(printf("music: norm: lim_lev=%f lim_acc=%d\n",d_limlvl,LIM_ACC)) + +#ifdef USE_FAST_LIMITER + mad_fixed_t start=limlvl & ~(F_LIM_JMP-1); + tablestart=start; + tablesize=(unsigned int)(F_LIM_MAX-start)/F_LIM_JMP + 2; + table=new mad_fixed_t[tablesize]; + if(table) { + d(printf("music: norm: table size=%d start=%08x jump=%08x\n",tablesize,start,F_LIM_JMP)) + for(int i=0 ; i=limlvl ; x-=mad_f_tofixed(1e-4)) { + mad_fixed_t diff=mad_f_abs(Limiter(x)-FastLimiter(x)); + if(diff>maxdiff) maxdiff=diff; +#ifdef ACC_DUMP + fprintf(out,"%0.10f\t%0.10f\t%0.10f\t%0.10f\t%0.10f\n", + mad_f_todouble(x),mad_f_todouble(Limiter(x)),mad_f_todouble(FastLimiter(x)),mad_f_todouble(diff),mad_f_todouble(maxdiff)); + if(ferror(out)) break; +#endif + } +#ifdef ACC_DUMP + fclose(out); +#endif + d(printf("music: norm: accuracy %.12f\n",mad_f_todouble(maxdiff))) + if(mad_f_todouble(maxdiff)>1e-6) { + esyslog("music: ERROR: accuracy check failed, normalizer disabled"); + delete table; table=0; + } + } + else esyslog("music: ERROR: no memory for lookup table, normalizer disabled"); +#endif // USE_FAST_LIMITER +} + +cNormalize::~cNormalize() +{ +#ifdef USE_FAST_LIMITER + delete[] table; +#endif +} + +void cNormalize::Init(double Level, double Peak) +{ + double Target=(double)MP3Setup.TargetLevel/100.0; + double dgain=Target/Level; + if(dgain>MAX_GAIN) dgain=MAX_GAIN; + gain=mad_f_tofixed(dgain); + // Check if we actually need to apply a gain + dogain=(Target>0.0 && fabs(1-dgain)>MIN_GAIN); +#ifdef USE_FAST_LIMITER + if(!table) dogain=false; +#endif + // Check if we actually need to do limiting: + // we have to if limiter is enabled, if gain>1 and if the peaks will clip. + dolimit=(d_limlvl<1.0 && dgain>1.0 && Peak*dgain>1.0); +#ifdef DEBUG + printf("music: norm: gain=%f dogain=%d dolimit=%d (target=%f level=%f peak=%f)\n",dgain,dogain,dolimit,Target,Level,Peak); + limited=clipped=total=0; peak=0; +#endif +} + +void cNormalize::Stats(void) +{ +#ifdef DEBUG + if(total) + printf("music: norm: stats tot=%ld lim=%ld/%.3f%% clip=%ld/%.3f%% peak=%.3f\n", + total,limited,(double)limited/total*100.0,clipped,(double)clipped/total*100.0,mad_f_todouble(peak)); +#endif +} + +mad_fixed_t cNormalize::Limiter(mad_fixed_t x) +{ +// Limiter function: +// +// / x (for x <= lev) +// x' = | +// \ tanh((x - lev) / (1-lev)) * (1-lev) + lev (for x > lev) +// +// call only with x>=0. For negative samples, preserve sign outside this function +// +// With limiter level = 0, this is equivalent to a tanh() function; +// with limiter level = 1, this is equivalent to clipping. + + if(x>limlvl) { +#ifdef DEBUG + if(x>MAD_F_ONE) clipped++; + limited++; +#endif + x=mad_f_tofixed(tanh((mad_f_todouble(x)-d_limlvl) / one_limlvl) * one_limlvl + d_limlvl); + } + return x; +} + +#ifdef USE_FAST_LIMITER +mad_fixed_t cNormalize::FastLimiter(mad_fixed_t x) +{ +// The fast algorithm is based on a linear interpolation between the +// the values in the lookup table. Relays heavly on libmads fixed point format. + + if(x>limlvl) { + int i=(unsigned int)(x-tablestart)/F_LIM_JMP; +#ifdef DEBUG + if(x>MAD_F_ONE) clipped++; + limited++; + if(i>=tablesize) printf("music: norm: overflow x=%f x-ts=%f i=%d tsize=%d\n", + mad_f_todouble(x),mad_f_todouble(x-tablestart),i,tablesize); +#endif + mad_fixed_t r=x & (F_LIM_JMP-1); + x=MAD_F_ONE; + if(i>MAD_F_FRACBITS + // which is senseless in the case of following <>LIM_SHIFT; // better, don't know if works on all machines + } + } + return x; +} +#endif + +#ifdef USE_FAST_LIMITER +#define LIMITER_FUNC FastLimiter +#else +#define LIMITER_FUNC Limiter +#endif + +void cNormalize::AddGain(struct mad_pcm *pcm) +{ + if(dogain) { + for(int i=0 ; ichannels ; i++) { + mad_fixed_t *data=pcm->samples[i]; +#ifdef DEBUG + total+=pcm->length; +#endif + if(dolimit) { + for(int n=pcm->length ; n>0 ; n--) { + mad_fixed_t s=mad_f_mul(*data,gain); + if(s<0) { + s=-s; +#ifdef DEBUG + if(s>peak) peak=s; +#endif + s=LIMITER_FUNC(s); + s=-s; + } + else { +#ifdef DEBUG + if(s>peak) peak=s; +#endif + s=LIMITER_FUNC(s); + } + *data++=s; + } + } + else { + for(int n=pcm->length ; n>0 ; n--) { + mad_fixed_t s=mad_f_mul(*data,gain); +#ifdef DEBUG + if(s>peak) peak=s; + else if(-s>peak) peak=-s; +#endif + if(s>MAD_F_ONE) s=MAD_F_ONE; // do clipping + if(s<-MAD_F_ONE) s=-MAD_F_ONE; + *data++=s; + } + } + } + } +} + +// --- cScale ---------------------------------------------------------------- + +// The dither code has been adapted from the madplay project +// (audio.c) found in the libmad distribution + +enum eAudioMode { amRoundBE, amDitherBE, amRoundLE, amDitherLE }; + +class cScale { +private: + enum { MIN=-MAD_F_ONE, MAX=MAD_F_ONE - 1 }; +#ifdef DEBUG + // audio stats + unsigned long clipped_samples; + mad_fixed_t peak_clipping; + mad_fixed_t peak_sample; +#endif + // dither + struct dither { + mad_fixed_t error[3]; + mad_fixed_t random; + } leftD, rightD; + // + inline mad_fixed_t Clip(mad_fixed_t sample, bool stats=true); + inline unsigned long Prng(unsigned long state); + signed long LinearRound(mad_fixed_t sample); + signed long LinearDither(mad_fixed_t sample, struct dither *dither); +public: + void Init(void); + void Stats(void); + unsigned int ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode); + }; + +void cScale::Init(void) +{ +#ifdef DEBUG + clipped_samples=0; peak_clipping=peak_sample=0; +#endif + memset(&leftD,0,sizeof(leftD)); + memset(&rightD,0,sizeof(rightD)); +} + +void cScale::Stats(void) +{ +#ifdef DEBUG + printf("music: scale stats clipped=%ld peak_clip=%f peak=%f\n", + clipped_samples,mad_f_todouble(peak_clipping),mad_f_todouble(peak_sample)); +#endif +} + +// gather signal statistics while clipping +mad_fixed_t cScale::Clip(mad_fixed_t sample, bool stats) +{ +#ifndef DEBUG + if (sample > MAX) sample = MAX; + if (sample < MIN) sample = MIN; +#else + if(!stats) { + if (sample > MAX) sample = MAX; + if (sample < MIN) sample = MIN; + } + else { + if (sample >= peak_sample) { + if (sample > MAX) { + ++clipped_samples; + if (sample - MAX > peak_clipping) + peak_clipping = sample - MAX; + sample = MAX; + } + peak_sample = sample; + } + else if (sample < -peak_sample) { + if (sample < MIN) { + ++clipped_samples; + if (MIN - sample > peak_clipping) + peak_clipping = MIN - sample; + sample = MIN; + } + peak_sample = -sample; + } + } +#endif + return sample; +} + +// generic linear sample quantize routine +signed long cScale::LinearRound(mad_fixed_t sample) +{ + // round + sample += (1L << (MAD_F_FRACBITS - OUT_BITS)); + // clip + sample=Clip(sample); + // quantize and scale + return sample >> (MAD_F_FRACBITS + 1 - OUT_BITS); +} + +// 32-bit pseudo-random number generator +unsigned long cScale::Prng(unsigned long state) +{ + return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; +} + +// generic linear sample quantize and dither routine +signed long cScale::LinearDither(mad_fixed_t sample, struct dither *dither) +{ + // noise shape + sample += dither->error[0] - dither->error[1] + dither->error[2]; + dither->error[2] = dither->error[1]; + dither->error[1] = dither->error[0] / 2; + // bias + mad_fixed_t output = sample + (1L << (MAD_F_FRACBITS + 1 - OUT_BITS - 1)); + const int scalebits = MAD_F_FRACBITS + 1 - OUT_BITS; + const mad_fixed_t mask = (1L << scalebits) - 1; + // dither + const mad_fixed_t random = Prng(dither->random); + output += (random & mask) - (dither->random & mask); + dither->random = random; + // clip + output=Clip(output); + sample=Clip(sample,false); + // quantize + output &= ~mask; + // error feedback + dither->error[0] = sample - output; + // scale + return output >> scalebits; +} + +#define PUT_BE(data,sample) { *data++=(sample)>>8; *data++=(sample)>>0; } +#define PUT_LE(data,sample) { *data++=(sample)>>0; *data++=(sample)>>8; } + +// write a block of signed 16-bit PCM samples +unsigned int cScale::ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode) +{ + unsigned int len=size/OUT_FACT; + if(len>nsamples) { len=nsamples; size=len*OUT_FACT; } + nsamples-=len; + switch(mode) { + case amRoundBE: + while(len--) { + signed int sample=LinearRound(*left++); + PUT_BE(data,sample); + if(right) sample=LinearRound(*right++); + PUT_BE(data,sample); + } + break; + case amDitherBE: + while(len--) { + signed int sample=LinearDither(*left++,&leftD); + PUT_BE(data,sample); + if(right) sample=LinearDither(*right++,&rightD); + PUT_BE(data,sample); + } + break; + case amRoundLE: + while(len--) { + signed int sample=LinearRound(*left++); + PUT_LE(data,sample); + if(right) sample=LinearRound(*right++); + PUT_LE(data,sample); + } + break; + case amDitherLE: + while(len--) { + signed int sample=LinearDither(*left++,&leftD); + PUT_LE(data,sample); + if(right) sample=LinearDither(*right++,&rightD); + PUT_LE(data,sample); + } + break; + } + return size; +} + +// --- cShuffle ---------------------------------------------------------------- + +class cShuffle { +private: + int *shuffle, max; + unsigned int seed; + // + int Index(int pos); +public: + cShuffle(void); + ~cShuffle(); + void Shuffle(int num, int curr); + void Del(int pos); + void Flush(void); + int First(void); + int Next(int curr); + int Prev(int curr); + int Goto(int pos, int curr); + }; + + +cShuffle::cShuffle(void) +{ + shuffle=0; max=0; + seed=time(0); +} + +cShuffle::~cShuffle(void) +{ + Flush(); +} + +void cShuffle::Flush(void) +{ + delete shuffle; shuffle=0; + max=0; +} + +int cShuffle::Index(int pos) +{ + if(pos>=0) + for(int i=0; imax) { + memcpy(ns,shuffle,max*sizeof(int)); + oldmax=max; + } + delete shuffle; + } + shuffle=ns; max=num; + } + if(!oldmax) curr=-1; + for(int i=oldmax ; i=2) { + for(int i=in ; i= i); + int t=shuffle[i]; + shuffle[i]=shuffle[ran+in]; + shuffle[ran+in]=t; + } + } +#ifdef DEBUG + printf("music: shuffle: order (%d , %d -> %d) ",num,curr,in); + for(int i=0 ; i=0) { + if(i+1=0 && i+10) ? shuffle[i-1] : -1; +} + +int cShuffle::Goto(int pos, int curr) +{ + int i=Index(curr); + int g=Index(pos); + if(g>=0) { + if(gi) { + for(int l=g; l>i+1; l--) shuffle[l]=shuffle[l-1]; + shuffle[i+1]=pos; + } +#ifdef DEBUG + printf("music: shuffle: goto order (%d -> %d , %d -> %d) ",pos,g,curr,i); + for(int i=0 ; i0); + shuffleMode=(MP3Setup.InitShuffleMode>0); +} + +cPlayManager::~cPlayManager() +{ + Flush(); + Release(); + listMutex.Lock(); + stopscan=true; bgCond.Broadcast(); + listMutex.Unlock(); + Cancel(2); + delete shuffle; +} + +void cPlayManager::ThrottleWait(void) +{ + while(!stopscan && !release && throttle) { + db(printf("music: mgr: background scan throttled\n")) + bgCond.Wait(listMutex); + db(printf("music: mgr: background scan throttle wakeup\n")) + } +} + +void cPlayManager::Action(void) +{ + db(printf("music: mgr: background scan thread started (pid=%d)\n", getpid())) + nice(5); + listMutex.Lock(); + while(!stopscan) { + for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) { +// ThrottleWait(); + listMutex.Unlock(); + if(!(scan->user & SCANNED_ID3)) { + scanning = true; + db(printf("music: mgr: scanning (id3) %s\n",scan->Name())) + cSongInfo *si=scan->Info(true); + if(si && si->Level>0.0) scan->user|=SCANNED_LVL; + scan->user|=SCANNED_ID3; +// TEST IT + scanning=false; + } + listMutex.Lock(); + } + if(MP3Setup.BgrScan>1) { + pass2=true; + for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) { + if(scan==curr) continue; + ThrottleWait(); + listMutex.Unlock(); + if(!(scan->user & SCANNED_LVL)) { + cDecoder *dec=scan->Decoder(); + if(dec) { +// TEST IT + scanning=true; + cSongInfo *si=scan->Info(false); + if(!dec->IsStream() && (!si || si->Level<=0.0) && dec->Start()) { + db(printf("music: mgr: scanning (lvl) %s\n",scan->Name())) + cLevel level; + level.Init(); + bool go=true; + while(go && !release) { + if(throttle) { + listMutex.Lock(); ThrottleWait(); listMutex.Unlock(); + continue; + } + struct Decode *ds=dec->Decode(); + switch(ds->status) { + case dsPlay: + level.GetPower(ds->pcm); + break; + case dsSkip: + case dsSoftError: + break; + case dsEof: + { + double l=level.GetLevel(); + if(l>0.0) { + cSongInfo *si=dec->SongInfo(false); + cFileInfo *fi=dec->FileInfo(); + if(si && fi) { + si->Level=l; + si->Peak=level.GetPeak(); + InfoCache.Cache(si,fi); + } + } + } + //fall through + case dsOK: + case dsError: + scan->user|=SCANNED_LVL; + go=false; + break; + } + } + } + else scan->user|=SCANNED_LVL; + dec->Stop(); + } +// TEST IT + scanning=false; + } + listMutex.Lock(); + } + pass2=false; + } + do { + scan=0; release=false; fgCond.Broadcast(); + db(printf("music: mgr: background scan idle\n")) + scanning = false; + bgCond.Wait(listMutex); + db(printf("music: mgr: background scan idle wakeup\n")) + scanning = true; + } while(!stopscan && (release || throttle)); + } + listMutex.Unlock(); + db(printf("music: mgr: background scan thread ended (pid=%d)\n", getpid())) +//TEST IT + scanning=false; +} + + +bool cPlayManager::Scanning(void) +{ + bool res = false; + res = scanning; + + return res; +} + + +bool cPlayManager::SaveList(const char *pl_filename, bool full) //Path for playlist , save with fullpath +{ + char *buffer; + bool res=false; + + if( FILE *f = fopen ( pl_filename , "w")) { + + if(full) { + for(cSong *song=list.First(); song; song=list.Next(song)) { + asprintf(&buffer, "%s\n", song->Fullname()); + fprintf(f, buffer); + d(printf("music: mgr: add track to %s: %s",pl_filename, buffer)); + free(buffer); + } + } + else { + for(cSong *song=list.First(); song; song=list.Next(song)) { + asprintf(&buffer, "%s\n", song->BASEDIR()); + fprintf(f, buffer); + d(printf("music: mgr: add track to %s: %s",pl_filename, buffer)); + free(buffer); + } + } + + fclose(f); + res = true; + } + + return res; +} + + +void cPlayManager::DeleteRecord(int Sidx) +{ + +// maxIndex beginnt mit 0 +// wenn 1. Lied spielt , dann currIndex = 0 +// wenn 1. Lied spielt , dann currindex = 0 + + char *buff; + int sidx=Sidx; + + if(MP3Setup.BgrScan) { + stopscan=true; +// if(Active()) Stop(); + } + bgCond.Broadcast(); + + if(!maxIndex==0 && !shuffleMode) { + cMutexLock lock(&listMutex); + + cSong *ns=curr; + + if(sidx<0) { sidx=currIndex; ns=curr; } + else { ns=list.Get(sidx); } + + if(sidx==maxIndex && currIndex==maxIndex) { + Goto(1); + currIndex=0; + currindex = 0; + } + else if(sidx == currIndex){ + Next(); + if(!currIndex==0) {currIndex=currIndex -1; currindex = currIndex;} + } + else if(sidx run (%d)\n",time_ms())) + listMutex.Lock(); + throttle=false; bgCond.Broadcast(); + listMutex.Unlock(); + } + if(thr && !throttle) { + db(printf("music: mgr: bgr-scan -> throttle (%d)\n",time_ms())) + throttle=true; + } + } +} + +void cPlayManager::ToggleShuffle(void) +{ + shuffleMode=!shuffleMode; + d(printf("music: mgr: shuffle mode toggled : %d\n",shuffleMode)) + if(shuffleMode && !eol) { + curr=0; currIndex=-1; + shuffle->Shuffle(maxIndex+1,-1); + Next(); + } +} + +void cPlayManager::ToggleLoop(void) +{ + loopMode=!loopMode; + d(printf("music: mgr: loop mode toggled : %d\n",loopMode)) +} + + +bool cPlayManager::Info(int num, cMP3PlayInfo *pi) +{ + cSong *s; + + int idx=num-1; + if(idx<0) { idx=currIndex; s=curr; } + else { s=list.Get(idx); } + memset(pi,0,sizeof(*pi)); + pi->Num=idx+1; + pi->MaxNum=maxIndex+1; + pi->Loop=loopMode; + pi->Shuffle=shuffleMode; + bool res=false; + + if(s) { + strn0cpy(pi->Title,s->Name(),sizeof(pi->Title)); + strn0cpy(pi->Filename,s->FullPath(),sizeof(pi->Filename)); + cSongInfo *si=s->Info(false); + if(si && si->HasInfo()) { + static const char *modestr[] = { "Mono","Dual","Joint-Stereo","Stereo" }; + + if(si->Title) strn0cpy(pi->Title,si->Title,sizeof(pi->Title)); + if(si->Artist) strn0cpy(pi->Artist,si->Artist,sizeof(pi->Artist)); + if(si->Album) strn0cpy(pi->Album,si->Album,sizeof(pi->Album)); + if(si->Genre) strn0cpy(pi->Genre,si->Genre,sizeof(pi->Genre)); + if(si->Comment) strn0cpy(pi->Comment,si->Comment,sizeof(pi->Comment)); + strn0cpy(pi->SMode,modestr[si->ChMode],sizeof(pi->SMode)); + pi->Year=si->Year; + pi->Rating=si->Rating; + pi->SampleFreq=si->SampleFreq; + pi->Bitrate=si->Bitrate; + pi->MaxBitrate=si->MaxBitrate; + res=true; + } + } + pi->Hash=MakeHashBuff((char *)pi,(char *)&pi->Loop-(char *)pi); + return res; +} + +/* +char *cPlayManager::TrackInfo(int index, bool toggleSort) { + + int idx = index; + cSong *s; + std::string result(tr("Unknown")); + static char tmpFile[256]; + char *res = NULL; + + s = (idx>=0) ? list.Get(idx) :0; + + cSongInfo *si=s->Info(false); + if(!si) si=s->Info(); + + if(si && si->HasInfo()) { + if(!toggleSort) { + if(si->Artist) result = si->Artist; + result = result + " - "; + if(si->Title) + result = result + si->Title; + else + result = result + tr("Unknown"); + } + else { + if(si->Title) result = si->Title; + result = result + " - "; + if(si->Artist) + result = result + si->Artist; + else + result = result + tr("Unknown"); + } + } + else { + result = result + " - "; + result = result + tr("Unknown"); + } + + strncpy(tmpFile,result.c_str(),sizeof(tmpFile)); + res = tmpFile; + + return res; +} +*/ + +void cPlayManager::RateSong(int sz_rating, cSong *r_Song) { + cSong *s; +// s=curr; + + s = r_Song; + + cSongInfo *si=s->Info(false); + if(!si) si=s->Info(); + cFileInfo *fi= new cFileInfo(s->FullPath()); + + if(si && fi) { + if(sz_rating>=0) si->Rating = sz_rating; + InfoCache.Update(sz_rating, fi); + } + + delete fi; +} + + +void cPlayManager::UpdateSong(const char *sz_artist, const char *sz_album, const char *sz_title, const char *sz_genre, int sz_year, int sz_rating, cSong *r_Song) { + cSong *s; + + s = r_Song; + cSongInfo *si=s->Info(false); + if(!si) si=s->Info(); + cFileInfo *fi= new cFileInfo(s->FullPath()); + if(si && fi) { + if(sz_artist && si->Artist) strcpy(si->Artist,sz_artist); + if(sz_album && si->Album) strcpy(si->Album ,sz_album); + if(sz_title && si->Title) strcpy(si->Title ,sz_title); + if(sz_genre && si->Genre) strcpy(si->Genre ,sz_genre); + if(sz_year>=0) si->Year = sz_year; + if(sz_rating>=0) si->Rating = sz_rating; + } + delete fi; +} + + +int cPlayManager::GetListLength(void) { + length = 0; + for(cSong *song=list.First(); song; song=list.Next(song)) { + cSongInfo *si=song->Info(false); + if(si && si->HasInfo()) { + if(si->Total) { length = length + si->Total; } + } + } + + return length; +} + + +void cPlayManager::Add(cPlayList *pl) +{ + char *buf; + + d(printf("music: mgr: Add1: maxIndex: %d , currIndex-> %d\n",maxIndex, currIndex)) + + cMutexLock lock(&listMutex); + bool real=false; + for(cSong *song=pl->First(); song; song=pl->cList::Next(song)) { + cSong *ns=new cSong(song); + + list.Add(ns); + real=true; + } + if(real) { + if(MP3Setup.BgrScan) { stopscan=false; if(!Active()) Start(); } + else stopscan=true; + bgCond.Broadcast(); + maxIndex=list.Count()-1; + + d(printf("music: mgr: Add2: maxIndex: %d , currIndex-> %d\n",maxIndex, currIndex)) + + if(shuffleMode) shuffle->Shuffle(maxIndex+1,currIndex); + if(!curr) Next(); + else + if(InStopMode) { + Next(); + tracksadded = true; + } + } + + // Save current playlist to file + asprintf(&buf, "%s/%s", BaseSource, "@current.m3u"); + if(SaveList(buf, false)) { + isyslog("music: ctrl: refreshed playlist to file: %s\n", buf); + } + else + esyslog("music: ctrl: couldnt save current playlist to file"); + free(buf); +} + +void cPlayManager::Flush(void) +{ + cMutexLock lock(&listMutex); + Halt(); + list.Clear(); + shuffle->Flush(); +} + +void cPlayManager::Halt(void) +{ + cMutexLock lock(&listMutex); + curr=0; currIndex=-1; maxIndex=-1; currindex = maxIndex; + playNew=true; + stopscan=true; bgCond.Broadcast(); + NoScan(0); + NoPlay(0); +} + +void cPlayManager::NoScan(cSong *nono) +{ + // call with listMutex locked!! + while((nono && pass2 && scan==nono) || (!nono && scan)) { + release=true; bgCond.Broadcast(); + d(printf("music: mgr: waiting for bgr release ... (pass2=%d nono=%p scan=%p)\n",pass2,nono,scan)) + fgCond.Wait(listMutex); + } +} + +void cPlayManager::NoPlay(cSong *nono) +{ + // call with listMutex locked!! + while((nono && play==nono) || (!nono && play)) { + playNew=true; + fgCond.Wait(listMutex); + } +} + +bool cPlayManager::Next(void) +{ + cMutexLock lock(&listMutex); + int ni; + cSong *n; + if(shuffleMode) { + if(curr) { + ni=shuffle->Next(currIndex); + if(ni<0) { + if(loopMode || eol) { + shuffle->Shuffle(maxIndex+1,-1); + ni=shuffle->First(); + } + else eol=true; + } + } + else + ni=shuffle->First(); + n=(ni>=0) ? list.Get(ni) : 0; + } + else { + if(curr) { + n=list.cList::Next(curr); + if(!n) { + if(loopMode || eol) n=list.First(); + else eol=true; + } + } + else + n=list.First(); + ni=n ? n->Index() : -1; + } + if(n) { + curr=n; currIndex=ni; + playNew=true; eol=false; + + d(printf("music: mgr: Next(): maxIndex: %d , currIndex: %d , currindex: %d\n",maxIndex, currIndex, currindex)) + + tracksadded = false; + + return true; + } + + tracksadded = false; + return false; +} + +bool cPlayManager::Prev(void) +{ + cMutexLock lock(&listMutex); + int ni; + cSong *n; + if(shuffleMode) { + ni=shuffle->Prev(currIndex); + n=(ni>=0) ? list.Get(ni) : 0; + } + else { + n=list.cList::Prev(curr); + ni=n ? n->Index() : -1; + } + if(n) { + curr=n; currIndex=ni; + playNew=true; eol=false; + d(printf("music: mgr: prev Track-> %d , Playlistindex-> %d\n",currIndex+1, currIndex)) + return true; + } + + return false; +} + +void cPlayManager::Goto(int num) +{ + cMutexLock lock(&listMutex); + if(num>0 && num<=maxIndex+1) { + int idx=num-1; + if(shuffleMode) { + if(eol) { + shuffle->Shuffle(maxIndex+1,-1); + currIndex=shuffle->Goto(idx,-1); + } + else + currIndex=shuffle->Goto(idx,currIndex); + } + else + currIndex=idx; + + curr=(currIndex>=0) ? list.Get(currIndex) : 0; + + playNew=true; eol=false; + d(printf("music: mgr: goto Track-> %d , Playlistindex-> %d\n",currIndex + 1, currIndex)) + } +} + + +cSong *cPlayManager::Track(int index) +{ + cSong *s; + s =list.Get(index); + return s; +} + + +cSong *cPlayManager::Current(void) +{ + cMutexLock lock(&listMutex); + if(!play) { + NoScan(curr); + play=curr; + playNew=false; + + if(play){ + d(printf("music: mgr: playing %s\n",play->Name())) + } + else d(printf("music: mgr: nothing to play\n")) + + fgCond.Broadcast(); + } + return play; +} + +bool cPlayManager::NextCurrent(void) +{ + cMutexLock lock(&listMutex); + return (!eol && (playNew || Next() ) ); +} + +bool cPlayManager::NewCurrent(void) +{ + return playNew; +} + +bool cPlayManager::TracksAdded(void) +{ + return tracksadded; +} + +void cPlayManager::Release(void) +{ + cMutexLock lock(&listMutex); + play=0; + fgCond.Broadcast(); +} + + +// --- cOutput ----------------------------------------------------------------- + +struct FrameHeader { + unsigned int samplerate; + }; +#define FHS sizeof(struct FrameHeader) + +class cOutput { +protected: + cMP3Player *player; + cScale scale; +public: + cOutput(cMP3Player *Player); + virtual ~cOutput() {} + virtual void Init(void); + virtual unsigned int SampleRate(unsigned int PcmSampleRate)=0; + virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr)=0; + virtual int Output(const unsigned char *Data, int Len, bool SOF)=0; + virtual bool Poll(void)=0; + virtual void Play(void)=0; + virtual void Pause(void)=0; + +#ifdef DEBUG + virtual void Stats(void); +#endif + }; + +cOutput::cOutput(cMP3Player *Player) +{ + player=Player; +} + +void cOutput::Init(void) +{ + scale.Init(); +} + +#ifdef DEBUG +void cOutput::Stats(void) +{ + scale.Stats(); +} +#endif + +// --- cOutputDvb -------------------------------------------------------------- + +/* +struct LPCMHeader { int id:8; // id + int frame_count:8; // number of frames + int access_ptr:16; // first acces unit pointer, i.e. start of audio frame + bool emphasis:1; // audio emphasis on-off + bool mute:1; // audio mute on-off + bool reserved:1; // reserved + int frame_number:5; // audio frame number + int quant_wlen:2; // quantization word length + int sample_freq:2; // audio sampling frequency (48khz=0, 96khz=1, 44,1khz=2, 32khz=3) + bool reserved2:1; // reserved + int chan_count:3; // number of audio channels - 1 (e.g. stereo = 1) + int dyn_range_ctrl:8; // dynamic range control (0x80 if off) + }; +*/ + +#define FRAMESIZE 2048 // max. frame size allowed for DVB driver + +class cOutputDvb : public cOutput { +private: + cPoller poll; + unsigned int outSr; + bool only48khz; +public: + cOutputDvb(cMP3Player *Player); + virtual unsigned int SampleRate(unsigned int PcmSampleRate); + virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr); + virtual int Output(const unsigned char *Data, int Len, bool SOF); + virtual bool Poll(void); + virtual void Play(void); + virtual void Pause(void); + }; + +cOutputDvb::cOutputDvb(cMP3Player *Player) +:cOutput(Player) +{ + only48khz=MP3Setup.Only48kHz; + outSr=0; +#if APIVERSNUM == 10318 + cDevice::PrimaryDevice()->SetCurrentAudioTrack(ttDolbyFirst); +#elif APIVERSNUM >= 10319 + cDevice::PrimaryDevice()->SetCurrentAudioTrack(ttAudio); +#endif + d(printf("music: dvb: using DVB output\n")) +} + +unsigned int cOutputDvb::SampleRate(unsigned int PcmSampleRate) +{ + unsigned int samplerate=48000; + if(!only48khz) { + switch(PcmSampleRate) { // If one of the supported frequencies, do it without resampling. + case 96000: // Select a "even" upsampling frequency if possible, too. + samplerate=96000; + break; + //case 48000: // this is already the default ... + // samplerate=48000; + // break; + case 11025: + case 22050: + case 44100: + samplerate=44100; + break; + case 8000: + case 16000: + case 32000: + samplerate=32000; + break; + } + } + return samplerate; +} + + + +cFrame *cOutputDvb::MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr) +{ + static const unsigned char header[] = { + 0x00, // PES header + 0x00, + 0x01, + 0xBD, // private stream + 0x00, + 0x00, + 0x87, // mpeg2, aligned, copyright, original + 0x00, // no pts/dts + 0x00, // PES header data len + 0xA0, // aLPCM header + 0xFF, + 0x00, + 0x04, + 0x00, + 0x01, // 2-channel stereo (n-1) + 0x80 // neutral dynamic range + }; + cFrame *f=0; + unsigned char *buff=MALLOC(uchar,FRAMESIZE); + if(buff) { + struct FrameHeader *fh=(struct FrameHeader *)buff; + fh->samplerate=sr; + memcpy(buff+FHS,header,sizeof(header)); + int srMode; + switch(sr) { + default: + case 48000: srMode=0<<4; break; + case 96000: srMode=1<<4; break; + case 44100: srMode=2<<4; break; + case 32000: srMode=3<<4; break; + } + buff[14+FHS]|=srMode; + unsigned int outlen=scale.ScaleBlock(buff+sizeof(header)+FHS,FRAMESIZE-sizeof(header)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherBE:amRoundBE); + if(outlen) { + // lPCM has 600 fps which is 80 samples at 48kHz per channel + // Frame size = (sample_rate * quantization * channels)/4800 + buff[10+FHS]=outlen*(4800/16/2)/sr; + outlen+=(sizeof(header)-6); + buff[4+FHS]=outlen>>8; + buff[5+FHS]=outlen; + + // Spectrum Analyzer: Hand over the PCM16-data to SpAn + int offset = sizeof(header)+FHS; + Span_SetPcmData_1_0 SetPcmData; + cPlugin *Plugin = cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, NULL); + if (Plugin) + { + SetPcmData.length = (unsigned int)(outlen-offset); + // the timestamp (ms) of the frame(s) to be visualized: + SetPcmData.index = index; + // tell SpAn the ringbuffer's size for it's internal bookkeeping of the data to be visualized: + SetPcmData.bufferSize = MP3BUFSIZE; + SetPcmData.data = buff + offset + 1; // get rid of the header + SetPcmData.bigEndian = true; + cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, &SetPcmData); + } + + f=new cFrame(buff,-(outlen+6+FHS),ftUnknown,index); + } + if(!f) free(buff); + } + return f; +} + + + +#ifdef BROKEN_PCM +#include "player-mp3-sample.c" +#endif + +int cOutputDvb::Output(const unsigned char *Data, int Len, bool SOF) +{ + int n=0; + if(SOF) { +#ifdef BROKEN_PCM + struct FrameHeader *fh=(struct FrameHeader *)Data; + if(fh->samplerate!=outSr) { + if(outSr) { + // at this point we would need access to AUDIO_STOP/AUDIO_PLAY + // ioctl, but unfortunaly VDR's API doesn't provides this. + // So we have to do magic to make the driver switch samplerate. + const unsigned char *p=testAudio; + int pc=sizeof(testAudio); + int r; + do { +#if APIVERSNUM < 10318 + r=player->PlayVideo(p,pc); +#else + r=player->PlayPes(p,pc); +#endif + if(r>0) { p+=r; pc-=r; } + if(r==0) Poll(); + } while(r>=0 && pc>0); + } + outSr=fh->samplerate; + d(printf("music: dvb: output samplerate now %d\n",outSr)) + } +#endif + n=FHS; + Data+=n; Len-=n; + } +#if APIVERSNUM < 10318 + int r=player->PlayVideo(Data,Len); +#else + int r=player->PlayPes(Data,Len); +#endif + return (r>=0 ? r+n : -1); +} + +bool cOutputDvb::Poll(void) +{ + return player->DevicePoll(poll,500); +} + +void cOutputDvb::Play(void) +{ +#ifndef BROKEN_PCM + player->DevicePlay(); +#endif +} + +void cOutputDvb::Pause(void) +{ +#ifndef BROKEN_PCM + player->DeviceFreeze(); +#endif +} + +// --- cOutputOss -------------------------------------------------------------- + +const char *dspdevice="/dev/dsp"; + +class cOutputOss : public cOutput { +private: + int fd; + cPoller poll; + unsigned int outSr; + unsigned char buff[8192]; + // + bool Reset(unsigned int sr); +public: + cOutputOss(cMP3Player *Player); + virtual ~cOutputOss(); + virtual void Init(void); + virtual unsigned int SampleRate(unsigned int PcmSampleRate); + virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr); + virtual int Output(const unsigned char *Data, int Len, bool SOF); + virtual bool Poll(void); + virtual void Play(void); + virtual void Pause(void); + }; + +cOutputOss::cOutputOss(cMP3Player *Player) +:cOutput(Player) +{ + fd=-1; outSr=0; + d(printf("music: oss: using OSS output\n")) +} + +cOutputOss::~cOutputOss() +{ + close(fd); +} + +void cOutputOss::Init(void) +{ + if(fd<0) { + fd=open(dspdevice,O_WRONLY|O_NONBLOCK); + if(fd>=0) poll.Add(fd,true); + else esyslog("music: ERROR: Cannot open dsp device '%s': %s!",dspdevice,strerror(errno)); + } + cOutput::Init(); +} + +bool cOutputOss::Reset(unsigned int sr) +{ + if(fd>=0) { + CHECK(ioctl(fd,SNDCTL_DSP_SYNC,0)); + int format=AFMT_S16_LE; + CHECK(ioctl(fd,SNDCTL_DSP_SETFMT,&format)); + if(format==AFMT_S16_LE) { + int channels=2; + CHECK(ioctl(fd,SNDCTL_DSP_CHANNELS,&channels)); + if(channels==2) { + int real=sr; + CHECK(ioctl(fd,SNDCTL_DSP_SPEED,&real)); + d(printf("music: oss: DSP samplerate now %d\n",real)) + if(abs(real-sr)samplerate=sr; + cFrame *f=0; + unsigned int outlen=scale.ScaleBlock(buff+FHS,sizeof(buff)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherLE:amRoundLE); + if(outlen) + { +// Spectrum Analyzer: Hand over the PCM16-data to SpAn + int offset = FHS; + Span_SetPcmData_1_0 SetPcmData; + cPlugin *Plugin = cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, NULL); + if (Plugin) + { + SetPcmData.length = (unsigned int)(outlen-offset); + // the timestamp (ms) of the frame(s) to be visualized: + SetPcmData.index = index; + // tell SpAn the ringbuffer's size for it's internal bookkeeping of the data to be visualized: + SetPcmData.bufferSize = MP3BUFSIZE; + SetPcmData.data = buff + offset + 1; // get rid of the header + SetPcmData.bigEndian = false; + cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, &SetPcmData); + } + + f=new cFrame(buff,outlen+FHS,ftUnknown,index); + } + return f; +} + +int cOutputOss::Output(const unsigned char *Data, int Len, bool SOF) +{ + if(fd>=0) { + int n=0; + if(SOF) { + struct FrameHeader *fh=(struct FrameHeader *)Data; + if(fh->samplerate!=outSr) Reset(fh->samplerate); + n=FHS; + Data+=n; Len-=n; + } + int r=write(fd,Data,Len); + if(r<0 && !FATALERRNO) r=0; + if(r>=0) return n+r; + } + return -1; +} + +bool cOutputOss::Poll(void) +{ + return fd>=0 ? poll.Poll(500) : false; +} + +void cOutputOss::Play(void) +{ +} + +void cOutputOss::Pause(void) +{ + CHECK(ioctl(fd,SNDCTL_DSP_POST,0)); +} + + + +// --- ALSA OUTPUT ------------------------------------------------------------- +// --- cOutputAlsa ------------------------------------------------------------- + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API + +const char *alsadevice="default"; + +class cOutputAlsa : public cOutput { +private: + cPoller poll; + unsigned int outSr; + unsigned char buff[8192]; + + snd_pcm_t *sound_handle; + snd_output_t *errlog; + snd_pcm_stream_t stream; + int frag_size; + int frag_count; + int nr_channels; + unsigned int output_rate; + + int sample_size; + + int Xrun_recovery(snd_pcm_t *handle, int err); + bool Reset(unsigned int sr); + int Alsa_Set_Buffer(int *fragment_size, int *fragment_count, int *channels); + +public: + cOutputAlsa(cMP3Player *Player); + virtual ~cOutputAlsa(); + virtual void Init(void); + virtual unsigned int SampleRate(unsigned int PcmSampleRate); + virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr); + virtual int Output(const unsigned char *Data, int Len, bool SOF); + virtual bool Poll(void); + virtual void Play(void); + virtual void Pause(void); +}; + + + +cOutputAlsa::cOutputAlsa(cMP3Player *Player) +:cOutput(Player) +{ + sound_handle = NULL; + stream = SND_PCM_STREAM_PLAYBACK; + outSr=0; + frag_size = 2048; + frag_count = 16; + nr_channels = 2; + output_rate = 44100; + + d(printf("music: output: using ALSA output\n")) +} + +cOutputAlsa::~cOutputAlsa() +{ + if (sound_handle) { + snd_pcm_drain(sound_handle); + snd_pcm_close(sound_handle); + sound_handle = NULL; + } + if (errlog) + snd_output_close(errlog); +} + +void cOutputAlsa::Init(void) +{ + int err; + if (!sound_handle) + { + if ((err = snd_pcm_open (&sound_handle, alsadevice, stream, 0)) < 0) { + esyslog ("music: output: ERROR: cannot open audio device %s (%s)\n", + alsadevice, + snd_strerror (err)); + } + else { + if(fcntl(err, F_SETFL,0)!=0) { + poll.Add(err,true); + } + d(printf("music: output: Init(): opened device %s\n", alsadevice)) + + err = snd_output_stdio_attach(&errlog, stderr , 0); + if (err < 0) { + d(printf("music: output: Init(): ERROR: snd_output_stdio_attach: %s\n", snd_strerror(err))) + } + } + + } + cOutput::Init(); +} + + + +int cOutputAlsa::Xrun_recovery(snd_pcm_t *handle, int err) +{ + if (err == -EPIPE) { //underrun + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Cant recovery from underrun, prepare failed: %s\n", snd_strerror(err)); + return 0; + } + else if (err == -ESTRPIPE) { + while (( err = snd_pcm_resume(handle)) == -EAGAIN) + sleep(1); //wait until the suspend flag is released + if(err < 0) { + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Cant recovery from suspend , prepare failed: %s\n", snd_strerror(err)); + } + return 0; + } + return err; +} + + +unsigned int cOutputAlsa::SampleRate(unsigned int PcmSampleRate) +{ + return PcmSampleRate; +} + + + +cFrame *cOutputAlsa::MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr) +{ + struct FrameHeader *fh=(struct FrameHeader *)buff; + fh->samplerate=sr; + cFrame *f=0; + unsigned int outlen=scale.ScaleBlock(buff+FHS,sizeof(buff)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherLE:amRoundLE); + if(outlen) + { +// Spectrum Analyzer: Hand over the PCM16-data to SpAn + int offset = FHS; + Span_SetPcmData_1_0 SetPcmData; + cPlugin *Plugin = cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, NULL); + if (Plugin) + { + SetPcmData.length = (unsigned int)(outlen-offset); + // the timestamp (ms) of the frame(s) to be visualized: + SetPcmData.index = index; + // tell SpAn the ringbuffer's size for it's internal bookkeeping of the data to be visualized: + SetPcmData.bufferSize = MP3BUFSIZE; + SetPcmData.data = buff + offset + 1; // get rid of the header + SetPcmData.bigEndian = false; + cPluginManager::CallFirstService(SPAN_SET_PCM_DATA_ID, &SetPcmData); + } + + f=new cFrame(buff,outlen+FHS,ftUnknown,index); + } + return f; +} + + +bool cOutputAlsa::Reset(unsigned int sr) +{ + if (sound_handle) { + output_rate = sr; + Alsa_Set_Buffer(&frag_size, &frag_count, &nr_channels); + return true; + } + return false; +} + + +/* +int cOutputAlsa::Output(const unsigned char *Data, int Len, bool SOF ) +{ + snd_pcm_uframes_t fcount; + int err; + int n = 0; + + if(sound_handle) { + + if(SOF) { + struct FrameHeader *fh=(struct FrameHeader *)Data; + if(fh->samplerate!=outSr) Reset(fh->samplerate); + n=FHS; + Data+=n; + Len-=n; + } + + fcount = (snd_pcm_uframes_t) (Len / 4); + + err = snd_pcm_writei(sound_handle, Data, fcount); + if ( err < 0 ) { + if (Xrun_recovery(sound_handle, err) < 0) { + printf("music : player-mp3.c : alsa: xrun\n"); + return -1; + } + err = snd_pcm_writei(sound_handle, Data, fcount); + if (err < 0) { + if (Xrun_recovery(sound_handle, err) < 0) { + printf("music : player-mp3.c : alsa: xrun\n"); + return -1; + } + } + } + + return (err>=0 ? err*4+n : -1); + } + + return -1; +} + +*/ + +int cOutputAlsa::Output(const unsigned char *Data, int Len, bool SOF ) +{ + snd_pcm_uframes_t fcount; + int err; + int n = 0; + + if(sound_handle) { + + if(SOF) { + struct FrameHeader *fh=(struct FrameHeader *)Data; + if(fh->samplerate!=outSr) Reset(fh->samplerate); + n=FHS; + Data+=n; + Len-=n; + } + + + fcount = (snd_pcm_uframes_t) (Len / 4); + + unsigned int len = fcount; + + while (len >0) { + + + err = snd_pcm_writei(sound_handle, Data, fcount); + + if ( (err == -EAGAIN) || (err == 0)) usleep (1000); + + if ( err < 0 ) { + printf("music: player-mp3.c : error occured\n"); + // this might be an error or an exception + if (Xrun_recovery(sound_handle, err) < 0) { + printf("music : player-mp3.c : alsa: xrun\n"); + return -1; + } + err = snd_pcm_writei(sound_handle, Data, fcount); + if (err < 0) { + if (Xrun_recovery(sound_handle, err) < 0) { + printf("music : player-mp3.c : alsa: xrun\n"); + return -1; + } + } + } + + // decrement the sample counter + len -= err; + + // adjust the start pointer + Data += err * sample_size; + } + + return (err>0 ? err*4 : -1); + } + + return -1; +} + + + +int cOutputAlsa::Alsa_Set_Buffer(int *fragment_size, int *fragment_count, int *channels) +{ + int err; + unsigned int val; + + snd_pcm_uframes_t periodsize; + snd_pcm_hw_params_t *hwparams; + + snd_pcm_hw_params_t **noWarnPtr = &hwparams; + snd_pcm_hw_params_alloca(noWarnPtr); + + // Fill it in with default values. + snd_pcm_hw_params_any(sound_handle, hwparams); + + // Set the desired hardware parameters. + + // Interleaved mode + snd_pcm_hw_params_set_access(sound_handle, hwparams, + SND_PCM_ACCESS_RW_INTERLEAVED); + + // Signed 16-bit little-endian format + snd_pcm_hw_params_set_format(sound_handle, hwparams, + SND_PCM_FORMAT_S16_LE); + + sample_size = 16 * 2 / 8; + + // Sampling rate + val = output_rate; + err = snd_pcm_hw_params_set_rate_near(sound_handle, hwparams, &val, 0); + if (err < 0) { + // Try 48kHZ + printf("%d HZ not available , trying 48000 HZ\n", output_rate); + val = 48000; + err = snd_pcm_hw_params_set_rate_near(sound_handle, + hwparams, &val, 0); + printf("error on setting output_rate (%d)\n", output_rate); + } + output_rate = val; + + char msg[80]; + snprintf(msg, 80, "alsa: DSP samplerate now %d\n",output_rate); + d(printf(msg)) + + + // Two channels (stereo) + snd_pcm_hw_params_set_channels(sound_handle, hwparams, *channels); + + + periodsize = (*fragment_size) / 4; + err = snd_pcm_hw_params_set_period_size_near(sound_handle, hwparams, &periodsize, 0); + if (err < 0) { + printf("error on set_period_size (%d)\n", (int)periodsize); + } + + frag_size = periodsize << 2; + val = *fragment_count; + err = snd_pcm_hw_params_set_periods_near(sound_handle, hwparams, &val, 0); + if(err > 0) { + printf("error on set_periods (%d)\n", val); + } + + frag_count = val; + + // Write the parameters to the driver + err = snd_pcm_hw_params(sound_handle, hwparams); + if (err < 0) { + esyslog("music: output: unable to set hw parameters: %s\n", snd_strerror(err)); + snd_pcm_hw_params_dump (hwparams, errlog); + return 0; + } + +// bytes_per_frame = snd_pcm_frames_to_bytes(handle, 1); + + nr_channels = *channels; + *fragment_size = frag_size; + *fragment_count = frag_count; + outSr = output_rate; + d(printf("music: output: DSP(alsa) reset done\n")) + return 1; + +} + + + +bool cOutputAlsa::Poll(void) +{ + return (sound_handle) ? poll.Poll(500) : false; +} + +void cOutputAlsa::Play(void) +{ + if(sound_handle) snd_pcm_prepare(sound_handle); +} + +void cOutputAlsa::Pause(void) +{ + if (sound_handle) snd_pcm_drain(sound_handle); +} + + +// --- cMP3Player -------------------------------------------------------------- + +cMP3Player::cMP3Player() +:cPlayer(MP3Setup.BgrMode == 1 ? pmAudioOnly : pmAudioOnlyBlack) +{ + statusMode=0; + active=true; started=false; isStream=false; + ringBuffer=new cRingBufferFrame(MP3BUFSIZE); + rframe=0; pframe=0; decoder=0; output=0; + playMode=pmStartup; state=msStop; + playindex=total=0; + + file = ""; +} + +cMP3Player::~cMP3Player() +{ + Detach(); + delete ringBuffer; +} + +void cMP3Player::Activate(bool On) +{ + if(On) { + d(printf("music: player: player active true requested...\n")) + if(!started) { + playMode=pmStartup; Start(); started=true; + playModeMutex.Lock(); + WaitPlayMode(pmStartup,true); // wait for the decoder to become ready + playModeMutex.Unlock(); + Lock(); + Play(); + Unlock(); + } + d(printf("music: player: player active true done\n")) + } + else if(started && active) { + d(printf("music: player: player active false requested...\n")) + Lock(); + StopPlay(); + Unlock(); + active=false; + SetPlayMode(pmStartup); + Cancel(2); + d(printf("music: player: player active false done\n")) + } +} + +void cMP3Player::SetPlayMode(ePlayMode mode) +{ + if(mode==pmStopped) InStopMode=true; else InStopMode = false; + + playModeMutex.Lock(); + if(mode!=playMode) { + playMode=mode; + dm(printf("music: player: setting mode=%d (pid=%d)\n",mode,getpid())) + playModeCond.Broadcast(); + } + playModeMutex.Unlock(); +} + +void cMP3Player::WaitPlayMode(ePlayMode mode, bool inv) +{ + // must be called with playModeMutex LOCKED !!! + + while(active && ((!inv && mode!=playMode) || (inv && mode==playMode))) { + dm(printf("music: player: entering wait for mode%s%d with mode=%d (pid=%d)\n",inv?"!=":"==",mode,playMode,getpid())) + playModeCond.Wait(playModeMutex); + dm(printf("music: player: returning from wait with mode=%d (pid=%d)\n",playMode,getpid())) + } +} + +void cMP3Player::Action(void) +{ + + cSong *playing=0; + struct mad_pcm *pcm=0; + cResample resample[2]; + unsigned int nsamples[2]; + const mad_fixed_t *data[2]; + cLevel level; + cNormalize norm; + bool haslevel=false; + const unsigned char *p=0; + int pc=0, readindex=0; +#ifdef DEBUG + int beat=0; +#endif +#ifdef DEBUG_DELAY + int lastwrite=0; +#endif + bool frameIncomplete = true; + + dsyslog("music: player: player thread started (pid=%d)", getpid()); + state=msStop; + SetPlayMode(pmStopped); + + delete output; output=0; + + if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) output=new cOutputOss(this); + else + if(MP3Setup.AudioOutMode==AUDIOOUTMODE_ALSA) output=new cOutputAlsa(this); + else + output=new cOutputDvb(this); + + if(!output) { + d(printf("music: player: audiooutmode mismatch or no output driver\n")) + esyslog("music: player: ERROR: no audio output driver. balling out"); + goto abort; + } + + while(active) { +#ifdef DEBUG + { + int now=time(0); + if(now>=beat) { + int avail=ringBuffer->Available(); + printf("music: player: heartbeat buffer=%d now=%d\n",avail,now&4095); + //output->Stats(); if(haslevel) norm.Stats(); + beat=now+(avail>(MP3BUFSIZE*10/100) ? (avail<(MP3BUFSIZE*50/100) ? 2 : 20) : 1); + } + } +#endif + + Lock(); + +next: + bool SOF=false; + if(!pframe && playMode==pmPlay) { + pframe=ringBuffer->Get(); + if(pframe) { + playindex=pframe->Index(); + p=pframe->Data(); + pc=pframe->Count(); + SOF=true; + } + } + + if(pframe) { +#ifdef DEBUG_DELAY + { + int now=time_ms(); + if(lastwrite && lastwriteOutput(p,pc,SOF); + + if(w>0) { +// Spectrum Analyzer: Tell SpAn which timestamp is currently playing + if ( frameIncomplete ) { + Span_SetPlayindex_1_0 SetPlayindexData; + cPlugin *Plugin = cPluginManager::CallFirstService(SPAN_SET_PLAYINDEX_ID, NULL); + if (Plugin) { + SetPlayindexData.index = playindex; + cPluginManager::CallFirstService(SPAN_SET_PLAYINDEX_ID, &SetPlayindexData); + } + frameIncomplete = false; + } + + p+=w; pc-=w; + if(pc<=0) { + ringBuffer->Drop(pframe); + pframe=0; + frameIncomplete = true; + goto next; + } + } + else if(w<0 && FATALERRNO) { + LOG_ERROR; + d(printf("music: player: output failed: %s\n",strerror(errno))) + Unlock(); + goto abort; + } + } + + if(mgr->NewCurrent() && playMode==pmPlay && state!=msStart) { + Empty(); + state=msRestart; + d(printf("music: player: stale song change, restart.\n")) + } + + if(!rframe && playMode==pmPlay) { + switch(state) { + case msStart: + d(printf("music: player: starting play\n")) + mgr->Throttle(true); + playindex=readindex=total=0; + playing=mgr->Current(); + +// check for existing file + if(playing) { + if((decoder=playing->Decoder()) && decoder->Start()) { + strncpy(Songname,playing->Fullname(),sizeof(Songname)); + isStream=decoder->IsStream(); levelgood=!isStream; haslevel=false; + cSongInfo *si=playing->Info(true); + if(si) { + if(si->Level>0.0) { + d(printf("music: player: found song level=%f peak=%f\n",si->Level,si->Peak)) + haslevel=true; + norm.Init(si->Level,si->Peak); + } + if(si->HasInfo()) { + total=SecondsToFrames(si->Total); + } + } + d(printf("music: player: isStream=%d levelgood=%d haslevel=%d\n",isStream,levelgood,haslevel)) + output->Init(); + level.Init(); + state=msDecode; + mgr->currindex=mgr->currIndex; + MP3Setup.isWebstream=IsStream(); + statusMode=2; + break; + } + else { + esyslog("music: player: ERROR: playlist entry %s is not a valid file",playing->Name()); + } + } + else + d(printf("music: player: no current on start play\n")) + state=msEof; + break; + case msDecode: + { +#ifdef DEBUG_DELAY + int now=time_ms(); +#endif + struct Decode *ds=decoder->Decode(); +#ifdef DEBUG_DELAY + now=time_ms()-now; + if(now>DEBUG_DELAY) printf("music: player: decode delayed %d ms\n",now); +#endif + switch(ds->status) { + case dsPlay: + pcm=ds->pcm; + readindex=ds->index; + state=msNormalize; + break; + case dsSkip: + case dsSoftError: + // skipping, state unchanged, next decode + break; + case dsEof: + if(!haslevel && levelgood) { // save level & peak to infocache on eof + double l=level.GetLevel(); + if(l>0.0) { + cSongInfo *si=decoder->SongInfo(false); + cFileInfo *fi=decoder->FileInfo(); + if(si && fi) { + si->Level=l; + si->Peak=level.GetPeak(); + InfoCache.Cache(si,fi); + } + } + } + state=msEof; + break; + case dsOK: + case dsError: + state=msError; + break; + } + break; + } + case msNormalize: + if(!haslevel) { if(levelgood) level.GetPower(pcm); } + else norm.AddGain(pcm); + state=msResample; + break; + case msResample: +#ifdef DEBUG + { + static unsigned int oldrate=0; + if(oldrate!=pcm->samplerate) { + printf("music: player: new input sample rate %d\n",pcm->samplerate); + oldrate=pcm->samplerate; + } + } +#endif + nsamples[0]=nsamples[1]=pcm->length; + data[0]=pcm->samples[0]; + data[1]=pcm->channels>1 ? pcm->samples[1]:0; + + dvbSampleRate=output->SampleRate(pcm->samplerate); + if(dvbSampleRate!=pcm->samplerate) { + if(resample[0].SetInputRate(pcm->samplerate,dvbSampleRate)) { + nsamples[0]=resample[0].ResampleBlock(nsamples[0],data[0]); + data[0] =resample[0].Resampled(); + } + if(data[1] && resample[1].SetInputRate(pcm->samplerate,dvbSampleRate)) { + nsamples[1]=resample[1].ResampleBlock(nsamples[1],data[1]); + data[1] =resample[1].Resampled(); + } + } + state=msOutput; + break; + + case msOutput: + if(nsamples[0]>0) rframe=output->MakeFrame(nsamples[0],data,readindex,dvbSampleRate); + else state=msDecode; + break; + + case msError: + case msEof: + d(printf("music: player: eof or error\n")) + state=msWait; + d(printf("music: player: state=msEof\n")) + // fall through + + case msRestart: + case msStop: + d(printf("music: player: stopping play\n")) + if(decoder) { decoder->Stop(); decoder=0; } + mgr->Release(); playing=0; + levelgood=false; +#ifdef DEBUG + output->Stats(); if(haslevel) norm.Stats(); +#endif + d(printf("music: player: state=msStop\n")) + if(state==msStop) SetPlayMode(pmStopped); + if(state==msRestart) state=msStart; + break; + + case msWait: + if(ringBuffer->Available()==0) { + if(mgr->NextCurrent()) { + d(printf("music: player: playing next\n")) + state=msStart; + } + else { + d(printf("music: player: end of playlist\n")) + d(printf("music: player: player idle...\n")) + d(printf("music: player: state=msWait\n")) + SetPlayMode(pmStopped); + statusMode=1; + } + } + break; + + + } + } + + if(rframe && ringBuffer->Put(rframe)) rframe=0; + + Unlock(); + + if((rframe || state==msWait) && pframe) { + mgr->Throttle(false); + output->Poll(); + } + else if(playMode!=pmPlay) { + mgr->Throttle(false); + playModeMutex.Lock(); + if(playMode!=pmPlay) WaitPlayMode(playMode,true); + playModeMutex.Unlock(); +#ifdef DEBUG_DELAY + lastwrite=0; +#endif + } + else if(state!=msWait && ringBuffer->Available()<(MP3BUFSIZE*50/100)) { + mgr->Throttle(true); + } + } + +abort: + Lock(); + delete rframe; + delete output; output=0; + if(decoder) { decoder->Stop(); decoder=0; } + mgr->Release(); playing=0; + SetPlayMode(pmStopped); + Unlock(); + active=false; + + dsyslog("music: player: player thread ended (pid=%d)", getpid()); +} + +void cMP3Player::Empty(void) +{ + if(MP3Setup.AudioOutMode!=AUDIOOUTMODE_ALSA) Lock(); // need fix + delete rframe; + rframe=0; + pframe=0; + ringBuffer->Clear(); + DeviceClear(); + if(MP3Setup.AudioOutMode!=AUDIOOUTMODE_ALSA) Unlock(); // need fix +} + +void cMP3Player::StopPlay(void) // StopPlay() must be called in locked state!!! +{ + if(playMode!=pmStopped) { + Empty(); + state=msStop; + SetPlayMode(pmPlay); + Unlock(); // let the decode thread process the stop signal + playModeMutex.Lock(); + WaitPlayMode(pmStopped,false); + playModeMutex.Unlock(); + Lock(); + } +} + +void cMP3Player::Pause(void) +{ + Lock(); + if(playMode==pmPaused) Play(); + else if(playMode==pmPlay && !isStream) { + d(printf("music: player: pause\n")) + if(output) output->Pause(); + SetPlayMode(pmPaused); + statusMode=3; + } + Unlock(); +} + + +void cMP3Player::Play(void) +{ + Lock(); + if(playMode!=pmPlay) { + d(printf("music: player: play\n")) + if(playMode==pmStopped) state=msStart; + if(output) output->Play(); + SetPlayMode(pmPlay); + } + statusMode=2; + Unlock(); +} + + +void cMP3Player::DeleteTrack(bool All, int idx) +{ + std::string file(""); + int all=All; + + if (all) { + statusMode=1; + Lock(); + StopPlay(); + Unlock(); + mgr->Halt(); + mgr->Flush(); + total=0; playindex=0; + file = config; + file = file + "/themes/defaultcover/music-default-cover.png"; + strncpy(coverpicture, file.c_str(),sizeof(coverpicture)); + } + else { + if (idx == mgr->currIndex) { + Lock(); + StopPlay(); + Unlock(); + mgr->DeleteRecord(idx); + Play(); + } + else { + mgr->DeleteRecord(idx); + } + } +} + + +bool cMP3Player::PrevCheck(void) +{ + bool res=false; + Lock(); + if(playindex>=2000 && !isStream) { + state=msRestart; res=true; + Empty(); + d(printf("music: player: skip to start of song\n")) + } + Unlock(); + return res; +} + +void cMP3Player::SkipSeconds(int secs) +{ + if(playMode!=pmStopped && !isStream) { + + if(MP3Setup.AudioOutMode!=AUDIOOUTMODE_ALSA) Lock(); // need fix + + d(printf("music: player: skip secs %d\n",secs)) + if(playMode==pmPaused) SetPlayMode(pmPlay); + float bufsecs=(float)ringBuffer->Available() / (float)(dvbSampleRate*OUT_FACT); + d(printf("music: player: ringbuffer available %f secs\n",bufsecs)) + if(secs>0 && bufsecs>=(float)secs) { + // clear intermediate queue + if(pframe) { + ringBuffer->Drop(pframe); + pframe=0; + } + DeviceClear(); + // skip inside ringbuffer + int skipindex=playindex+secs*1000; + d(printf("music: player: skipping play=%d skip=%d ...\n",playindex,skipindex)) + cFrame *f; + + do { + f=ringBuffer->Get(); + if(f) { + playindex=f->Index(); + ringBuffer->Drop(f); + d(printf("*")) + } + } while(f && playindexSkip(secs,bufsecs)) levelgood=false; + + Empty(); + } + if(MP3Setup.AudioOutMode!=AUDIOOUTMODE_ALSA) Unlock(); // need fix + } +} + + +bool cMP3Player::Muted(void) +{ + bool res = false; + res = cDevice::PrimaryDevice()->IsMute(); + return res; +} + +int cMP3Player::CurrentVolume(void) +{ + return cDevice::PrimaryDevice()->CurrentVolume(); +} + + +bool cMP3Player::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + Current=SecondsToFrames(playindex/1000); Total=total; + return total>=0; +} + +bool cMP3Player::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + Play=(playMode==pmPlay); + Forward=true; + Speed=-1; + return true; +} + +//bool cMP3Player::ExistsLyrics(const char *songpath) +bool cMP3Player::ExistsLyrics(const char *songpath) +{ + bool LyricsFound = false; + + std::string::size_type pos; + std::string fullfilename; + std::string filename; + + fullfilename = songpath; + + pos = fullfilename.rfind("."); + if(pos!=std::string::npos) { + filename = fullfilename.substr(0, fullfilename.length() -(fullfilename.length() -pos)); + filename += ".lyrics"; +#ifdef DEBUG_COVER + printf("music: player: check for lyrics '%s'\n", filename.c_str()); +#endif + if( FILE *f = fopen(filename.c_str(), "r") ) { +#ifdef DEBUG_COVER + printf("music: player: found lyrics '%s'\n", filename.c_str()); +#endif + LyricsFound = true; + fclose(f); + } + else { +#ifdef DEBUG_COVER + printf("music: player: no lyrics found\n"); +#endif + LyricsFound = false; + } + } + + return LyricsFound; +} + diff -Nru vdr-plugin-music-0.9.9/player-mp3.c vdr-plugin-music-0.9.9/player-mp3.c --- vdr-plugin-music-0.9.9/player-mp3.c 2013-10-27 22:51:38.000000000 +0000 +++ vdr-plugin-music-0.9.9/player-mp3.c 2020-11-26 22:13:51.000000000 +0000 @@ -1727,10 +1727,10 @@ int channels=2; CHECK(ioctl(fd,SNDCTL_DSP_CHANNELS,&channels)); if(channels==2) { - int real=sr; + int real = (int) sr; CHECK(ioctl(fd,SNDCTL_DSP_SPEED,&real)); d(printf("music: oss: DSP samplerate now %d\n",real)) - if(abs(real-sr)