aboutsummaryrefslogtreecommitdiffstats
path: root/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'src/base')
-rw-r--r--src/base/song.cpp115
-rw-r--r--src/base/song.hpp17
-rw-r--r--src/base/songloading/songloader.cpp4
-rw-r--r--src/base/songloading/songloader.hpp4
-rw-r--r--src/base/songloading/songloading_strategy.hpp3
-rw-r--r--src/base/songloading/songloading_strategy_txt.cpp137
-rw-r--r--src/base/songloading/songloading_strategy_txt.hpp27
-rw-r--r--src/base/songloading/songloading_strategy_xml.cpp7
-rw-r--r--src/base/songloading/songloading_strategy_xml.hpp3
9 files changed, 305 insertions, 12 deletions
diff --git a/src/base/song.cpp b/src/base/song.cpp
new file mode 100644
index 00000000..fe93d781
--- /dev/null
+++ b/src/base/song.cpp
@@ -0,0 +1,115 @@
+/*
+ * UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 program 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "song.hpp"
+
+namespace usdx
+{
+ log4cxx::LoggerPtr Song::log =
+ log4cxx::Logger::getLogger("usdx.base.Song");
+
+ const std::string& Song::get_filename(void)
+ {
+ return filename;
+ }
+
+ Song::Song(const std::string& filename, const std::map<std::string, std::string>& header) :
+ filename(filename), custom_header_tags(header)
+ {
+ std::map<std::string, std::string>::iterator it;
+
+ title = get_header_tag("TITLE", true);
+ artist = get_header_tag("ARTIST", true);
+ mp3 = get_header_tag("MP3", true);
+ bpm = get_header_tag("BPM", true);
+
+ // TODO: float
+ // gap = get_header_tag("GAP");
+ cover = get_header_tag("COVER");
+ background = get_header_tag("BACKGROUND");
+
+ video = get_header_tag("VIDEO");
+ // TODO
+ // EncFile := DecodeFilename(Value);
+ // if (self.Path.Append(EncFile).IsFile) then
+ // self.Video := EncFile
+ // else
+ // Log.LogError('Can''t find video file in song: ' +
+ // Fulfilling);
+
+ // TODO: float
+ // videogap = get_header_tag("VIDEOGAP");
+
+ genre = get_header_tag("GENRE");
+ edition = get_header_tag("EDITION");
+ creator = get_header_tag("CREATOR");
+ language = get_header_tag("LANGUAGE");
+
+ // TODO: int
+ // year = get_header_tag("YEAR");
+
+ // TODO: float
+ // start = get_header_tag("START");
+
+ // TODO: int
+ // end = get_header_tag("END");
+ // resolution = get_header_tag("RESOLUTION");
+ // notesgap = get_header_tag("NOTESGAP");
+
+ // TODO: bool
+ // relative = get_header_tag("RELATIVE");
+
+ // TODO
+ // encoding = get_header_tag("ENCODING");
+ }
+
+ std::string Song::get_header_tag(const std::string& tag, const bool required)
+ {
+ std::map<std::string, std::string>::iterator it;
+ std::string result = "";
+
+ if ((it = custom_header_tags.find(tag)) != custom_header_tags.end()) {
+ result = it->second;
+ custom_header_tags.erase(it);
+ }
+ else if (required) {
+ LOG4CXX_ERROR(log, "Incomplete Song! Missing '" << tag << "' Tag in: '" << get_filename() << "'");
+ throw "Incomplete Song! Missing Tag.";
+ }
+
+ return result;
+ }
+
+ const std::string& Song::get_title(void)
+ {
+ return title;
+ }
+
+ const std::string& Song::get_artist(void)
+ {
+ return artist;
+ }
+};
diff --git a/src/base/song.hpp b/src/base/song.hpp
index 90226932..ae9c3f24 100644
--- a/src/base/song.hpp
+++ b/src/base/song.hpp
@@ -28,12 +28,18 @@
#define SONG_HPP
#include <string>
+#include <map>
+#include <log4cxx/logger.h>
namespace usdx
{
class Song
{
private:
+ static log4cxx::LoggerPtr log;
+
+ std::string filename;
+
std::string title;
std::string artist;
@@ -62,12 +68,21 @@ namespace usdx
bool relative;
int resolution;
// TODO: bpm: array of TBPM
+ std::string bpm;
// TODO: list of LyricLines
// TODO: Encoding: TEncoding;
- // TODO: CustomTags: array of TCustomHeaderTag;
+ std::map<std::string, std::string> custom_header_tags;
+
+ std::string get_header_tag(const std::string& tag, const bool required = false);
public:
+ const std::string& get_filename(void);
+
+ Song(const std::string& filename, const std::map<std::string, std::string>& header);
+
+ const std::string& get_title(void);
+ const std::string& get_artist(void);
};
};
diff --git a/src/base/songloading/songloader.cpp b/src/base/songloading/songloader.cpp
index c4d1054d..8bffa607 100644
--- a/src/base/songloading/songloader.cpp
+++ b/src/base/songloading/songloader.cpp
@@ -56,7 +56,7 @@ namespace usdx
return instance;
}
- Song *Songloader::load(std::string filename)
+ Song *Songloader::load_header(std::string filename)
{
std::string extension = "";
@@ -71,6 +71,6 @@ namespace usdx
throw "Unknown file format.";
}
- return it->second->loadSong(filename);
+ return it->second->load_header(filename);
}
};
diff --git a/src/base/songloading/songloader.hpp b/src/base/songloading/songloader.hpp
index 3c0b8e6f..8a5cbe03 100644
--- a/src/base/songloading/songloader.hpp
+++ b/src/base/songloading/songloader.hpp
@@ -49,11 +49,11 @@ namespace usdx
static Songloader *instance;
public:
- Songloader *get_instance(void);
+ static Songloader *get_instance(void);
virtual ~Songloader(void);
- Song *load(std::string filename);
+ Song *load_header(std::string filename);
};
};
diff --git a/src/base/songloading/songloading_strategy.hpp b/src/base/songloading/songloading_strategy.hpp
index 4f5edd0f..5cded02d 100644
--- a/src/base/songloading/songloading_strategy.hpp
+++ b/src/base/songloading/songloading_strategy.hpp
@@ -40,7 +40,8 @@ namespace usdx
public:
virtual ~SongloadingStrategy() {};
- virtual Song* loadSong(std::string filename) = 0;
+ virtual Song* load_song(Song* song) = 0;
+ virtual Song* load_header(const std::string& filename) = 0;
};
};
diff --git a/src/base/songloading/songloading_strategy_txt.cpp b/src/base/songloading/songloading_strategy_txt.cpp
index e8238f4a..31604191 100644
--- a/src/base/songloading/songloading_strategy_txt.cpp
+++ b/src/base/songloading/songloading_strategy_txt.cpp
@@ -24,10 +24,17 @@
* $Id$
*/
+#include <string>
+#include <algorithm>
#include "songloading_strategy_txt.hpp"
+#include "utils/file.hpp"
namespace usdx
{
+ log4cxx::LoggerPtr SongloadingStrategyTxt::log =
+ log4cxx::Logger::getLogger(
+ "usdx.base.songloading.SongloadingStrategyTxt");
+
SongloadingStrategyTxt::SongloadingStrategyTxt(void)
{
}
@@ -36,9 +43,133 @@ namespace usdx
{
}
- Song* SongloadingStrategyTxt::loadSong(std::string filename)
+ std::pair<std::string, std::string> SongloadingStrategyTxt::split_header_field(std::string &line)
+ {
+ std::size_t pos = line.find(':');
+
+ if (line[0] != '#' || pos == std::string::npos) {
+ LOG4CXX_DEBUG(log, "Tried to parse invalid header line: '" << line << "'");
+ throw "Invalid header!";
+ }
+
+ std::pair<std::string, std::string> result;
+
+ // copy the substring to : without # to result.first and
+ // transform to upper case
+ result.first.resize(pos - 1);
+ std::transform(line.begin() + 1, line.begin() + pos,
+ result.first.begin(), toupper);
+
+ // line is already ltrimmed
+ rtrim(result.first);
+
+ result.second = line.substr(pos + 1);
+
+ // line is already rtrimmed
+ ltrim(result.second);
+
+ LOG4CXX_DEBUG(log, "Found header: '" << result.first << "' with value '" << result.second << "'");
+
+ return result;
+ }
+
+ std::string& SongloadingStrategyTxt::ltrim(std::string& line)
+ {
+ std::size_t found = line.find_first_not_of(" \t\n\r");
+ if (found != std::string::npos && found >= 1) {
+ line.erase(0, found - 1);
+ }
+
+ return line;
+ }
+
+ std::string& SongloadingStrategyTxt::rtrim(std::string& line)
+ {
+ std::size_t found = line.find_last_not_of(" \t\n\r");
+ if (found != std::string::npos) {
+ line.erase(found + 1);
+ }
+
+ return line;
+ }
+
+ std::string& SongloadingStrategyTxt::trim(std::string& line)
{
- // TODO
- return NULL;
+ return ltrim(rtrim(line));
+ }
+
+ Song* SongloadingStrategyTxt::load_song(Song *song)
+ {
+ File file(song->get_filename());
+ std::string line;
+
+ while (file.stream().good()) {
+ file.stream() >> line;
+
+ // do not remove spaces at line ending, that are maybe
+ // spaces in lyrics
+ ltrim(line);
+
+ if (line[0] == '#') {
+ // ignore, header already read
+ }
+ else if (line[0] == 'E') {
+ // song end
+ break;
+ }
+ else if (line[0] == '-') {
+ // line break
+ }
+ else if (line[0] == 'B') {
+ // new bpm
+ }
+ else {
+ // normal line
+ }
+ }
+
+ // fill song
+
+ return song;
+ }
+
+ Song* SongloadingStrategyTxt::load_header(const std::string& filename)
+ {
+ File file(filename);
+ std::string line;
+ std::map<std::string, std::string> header_fields;
+
+ bool header = true, notes_found = false;
+ while (file.stream().good()) {
+ std::getline(file.stream(), line);
+
+ trim(line);
+ LOG4CXX_DEBUG(log, "Line: " << line);
+
+ if (header && line[0] == '#') {
+
+ // header
+ header_fields.insert(split_header_field(line));
+ }
+ else {
+ if (header) {
+ // end of header
+ header = false;
+ }
+
+ if (line[0] == ':' || line[0] == '*' || line[0] == 'F') {
+ notes_found = true;
+ break;
+ }
+ }
+ }
+
+ if (! notes_found) {
+ LOG4CXX_WARN(log, "Song: '" << filename << "' has no notes. Ignoring!");
+ throw "No notes.";
+ }
+
+ // fill song
+ return new Song(filename, header_fields);
}
};
diff --git a/src/base/songloading/songloading_strategy_txt.hpp b/src/base/songloading/songloading_strategy_txt.hpp
index 7a298e41..31a9815a 100644
--- a/src/base/songloading/songloading_strategy_txt.hpp
+++ b/src/base/songloading/songloading_strategy_txt.hpp
@@ -28,17 +28,42 @@
#define SONGLOADING_STRATEGY_TXT_HPP
#include <string>
+#include <log4cxx/logger.h>
#include "songloading_strategy.hpp"
namespace usdx
{
class SongloadingStrategyTxt : public SongloadingStrategy
{
+ private:
+ static log4cxx::LoggerPtr log;
+
+ /**
+ * Split the header field in name and value.
+ */
+ std::pair<std::string, std::string> split_header_field(std::string &line);
+
+ /**
+ * Removes whitespaces in front of the string.
+ */
+ std::string& ltrim(std::string& line);
+
+ /**
+ * Removes whitespaces in behind the string.
+ */
+ std::string& rtrim(std::string& line);
+
+ /**
+ * Removes whitespaces in front of the string and behind it.
+ */
+ std::string& trim(std::string& line);
+
public:
SongloadingStrategyTxt();
virtual ~SongloadingStrategyTxt();
- virtual Song* loadSong(std::string filename);
+ virtual Song* load_song(Song* song);
+ virtual Song* load_header(const std::string& filename);
};
};
diff --git a/src/base/songloading/songloading_strategy_xml.cpp b/src/base/songloading/songloading_strategy_xml.cpp
index 52d1f7cf..f7fea886 100644
--- a/src/base/songloading/songloading_strategy_xml.cpp
+++ b/src/base/songloading/songloading_strategy_xml.cpp
@@ -36,9 +36,14 @@ namespace usdx
{
}
- Song* SongloadingStrategyXml::loadSong(std::string filename)
+ Song* SongloadingStrategyXml::load_song(Song *song)
{
// TODO
+ return song;
+ }
+
+ Song* SongloadingStrategyXml::load_header(const std::string& filename)
+ {
return NULL;
}
};
diff --git a/src/base/songloading/songloading_strategy_xml.hpp b/src/base/songloading/songloading_strategy_xml.hpp
index b656fe9a..a01f9c11 100644
--- a/src/base/songloading/songloading_strategy_xml.hpp
+++ b/src/base/songloading/songloading_strategy_xml.hpp
@@ -37,7 +37,8 @@ namespace usdx
SongloadingStrategyXml(void);
virtual ~SongloadingStrategyXml(void);
- virtual Song* loadSong(std::string filename);
+ virtual Song* load_song(Song* song);
+ virtual Song* load_header(const std::string& filename);
};
};