You can subscribe to this list here.
| 2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(25) |
Jul
(288) |
Aug
(119) |
Sep
(31) |
Oct
(59) |
Nov
(458) |
Dec
(359) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 |
Jan
(268) |
Feb
(26) |
Mar
(36) |
Apr
(48) |
May
(119) |
Jun
(37) |
Jul
(173) |
Aug
(429) |
Sep
(137) |
Oct
(156) |
Nov
(59) |
Dec
(45) |
| 2011 |
Jan
(398) |
Feb
(257) |
Mar
(49) |
Apr
(5) |
May
(34) |
Jun
(11) |
Jul
(38) |
Aug
(12) |
Sep
(1) |
Oct
(49) |
Nov
(5) |
Dec
(10) |
| 2012 |
Jan
(21) |
Feb
(32) |
Mar
(20) |
Apr
(1) |
May
(2) |
Jun
|
Jul
(173) |
Aug
|
Sep
(25) |
Oct
(6) |
Nov
(44) |
Dec
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2012-02-11 07:01:55
|
Author: Lasse Karkkainen <tro...@tr...>
Date: Sat Feb 11 08:51:26 2012 +0200
Make Songs::currentPtr return NULL instead of segfaulting if there are no songs.
---
game/songs.hh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/songs.hh b/game/songs.hh
index d403139..70b5a2a 100644
--- a/game/songs.hh
+++ b/game/songs.hh
@@ -46,7 +46,7 @@ class Songs: boost::noncopyable {
/// sets margins for animation
void setAnimMargins(double left, double right) { math_cover.setMargins(left, right); }
/// @return current song
- boost::shared_ptr<Song> currentPtr() { return m_filtered[math_cover.getTarget()]; }
+ boost::shared_ptr<Song> currentPtr() { return m_filtered.empty() ? boost::shared_ptr<Song>() : m_filtered[math_cover.getTarget()]; }
/// @return current song
Song& current() { return *m_filtered[math_cover.getTarget()]; }
/// @return current Song
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2012-02-11 07:01:52
|
Author: Lasse Karkkainen <tro...@tr...>
Date: Sat Feb 11 08:37:27 2012 +0200
Major cleanup of screen songs with some bugfixes.
- Update logic separated from drawing functions
- Browser would hang due to auto-advance when all the songs displayed had the same music files
- Only update songlist when idle (allows for smooth browsing during song loading)
- Various other small things and almost certainly new bugs...
---
game/screen_songs.cc | 76 +++++++++++++++++++++++++------------------------
game/screen_songs.hh | 16 ++--------
game/song.hh | 3 +-
3 files changed, 44 insertions(+), 51 deletions(-)
diff --git a/game/screen_songs.cc b/game/screen_songs.cc
index bf8fa63..7dc98e8 100644
--- a/game/screen_songs.cc
+++ b/game/screen_songs.cc
@@ -17,7 +17,7 @@ ScreenSongs::ScreenSongs(std::string const& name, Audio& audio, Songs& songs, Da
Screen(name), m_audio(audio), m_songs(songs), m_database(database), m_covers(20), m_jukebox(), show_hiscores(), hiscore_start_pos()
{
m_songs.setAnimMargins(5.0, 5.0);
- m_playTimer.setTarget(getInf()); // Using this as a simple timer counting seconds
+ m_idleTimer.setTarget(getInf()); // Using this as a simple timer counting seconds
}
void ScreenSongs::enter() {
@@ -53,7 +53,6 @@ void ScreenSongs::exit() {
m_songbg_default.reset();
m_songbg_ground.reset();
m_playing.clear();
- m_playReq.clear();
}
/**Add actions here which should effect both the
@@ -77,6 +76,7 @@ void ScreenSongs::manageEvent(SDL_Event event) {
input::NavButton nav(input::getNav(event));
// Handle basic navigational input that is possible also with instruments
if (nav != input::NONE) {
+ m_idleTimer.setValue(0.0); // Reset idle timer
if (m_jukebox) {
if (nav == input::CANCEL || m_songs.empty()) m_jukebox = false;
else if (nav == input::UP) m_audio.seek(5);
@@ -128,6 +128,42 @@ void ScreenSongs::manageEvent(SDL_Event event) {
sm->showLogo(!m_jukebox);
}
+void ScreenSongs::update() {
+ if (m_idleTimer.get() < 0.3) return; // Only update when the user gives us a break
+ m_songs.update(); // Poll for new songs
+ bool songChange = false; // Do we need to switch songs?
+ // Automatic song browsing
+ if (!m_audio.isPaused() && m_idleTimer.get() > 1.0) {
+ // If playback has ended or hasn't started
+ if (!m_audio.isPlaying() || m_audio.getPosition() > m_audio.getLength()) {
+ songChange = true; // Force reload even if the music happens to stay the same
+ }
+ // If the above, or if in regular mode and idle too long, advance to next song
+ if (songChange || (!m_jukebox && m_idleTimer.get() > IDLE_TIMEOUT)) {
+ m_songs.advance(1);
+ m_idleTimer.setValue(0.0);
+ }
+ }
+ // Check out if the music has changed
+ boost::shared_ptr<Song> song = m_songs.currentPtr();
+ Song::Music music;
+ if (song) music = song->music;
+ if (m_playing != music) songChange = true;
+ // Switch songs if needed, only when the user is not browsing for a moment
+ if (!songChange) return;
+ m_playing = music;
+ // Clear the old content and load new content if available
+ m_songbg.reset(); m_video.reset();
+ double pstart = (!m_jukebox && song ? song->preview_start : 0.0);
+ m_audio.playMusic(music, true, 2.0, pstart);
+ if (song) {
+ std::string background = song->path + song->background;
+ std::string video = song->path + song->video;
+ if (!background.empty()) try { m_songbg.reset(new Surface(background)); } catch (std::exception const&) {}
+ if (!video.empty() && config["graphic/video"].b()) m_video.reset(new Video(video, song->videoGap));
+ }
+}
+
void ScreenSongs::drawJukebox() {
double pos = m_audio.getPosition();
double len = m_audio.getLength();
@@ -166,27 +202,6 @@ void ScreenSongs::drawMultimedia() {
}
}
-void ScreenSongs::updateMultimedia(Song& song, ScreenSharedInfo& info) {
- if (!song.music.empty()) info.music = song.music; // TODO it is always empty?
- if (!song.background.empty()) info.songbg = song.path + song.background;
- if (!song.video.empty()) { info.video = song.path + song.video; info.videoGap = song.videoGap; }
-}
-
-void ScreenSongs::stopMultimedia(ScreenSharedInfo& info) {
- // Schedule playback change if the chosen song has changed
- if (info.music != m_playReq) { m_playReq = info.music; m_playTimer.setValue(0.0); }
- // Play/stop preview playback (if it is the time)
- if (info.music != m_playing && m_playTimer.get() > 0.3) {
- m_songbg.reset(); m_video.reset();
- double pstart = 0.0; // Playback starting time
- if (!m_songs.empty() && !m_jukebox) pstart = m_songs.current().preview_start; // In regular mode
- if (info.music.empty()) m_audio.fadeout(1.0); else m_audio.playMusic(info.music, true, 2.0, pstart);
- if (!info.songbg.empty()) try { m_songbg.reset(new Surface(info.songbg)); } catch (std::exception const&) {}
- if (!info.video.empty() && config["graphic/video"].b()) m_video.reset(new Video(info.video, info.videoGap));
- m_playing = info.music;
- }
-}
-
namespace {
float getIconTex(int i) {
static int iconcount = 8;
@@ -195,10 +210,7 @@ namespace {
}
void ScreenSongs::draw() {
- m_songs.update(); // Poll for new songs
- ScreenSharedInfo info;
- info.videoGap = 0.0;
-
+ update();
drawMultimedia();
std::ostringstream oss_song, oss_order, oss_has_hiscore;
// Test if there are no songs
@@ -226,7 +238,6 @@ void ScreenSongs::draw() {
// Get hiscores from database
m_database.queryPerSongHiscore_HiscoreDisplay(oss_order, m_songs.currentPtr(), hiscore_start_pos, 5);
}
- updateMultimedia(song, info);
}
if (m_jukebox) drawJukebox();
else {
@@ -238,15 +249,6 @@ void ScreenSongs::draw() {
} else theme->hiscores.draw(oss_order.str());
if (!show_hiscores) drawInstruments(Dimensions(m_instrumentList->ar()).fixedHeight(0.03).center(-0.04));
}
- stopMultimedia(info);
- if (m_jukebox) {
- // Switch if at song end
- if (!m_audio.isPlaying() || m_audio.getPosition() + 1.3 > m_audio.getLength()) {
- m_songs.advance(1);
- // Force reload of data
- m_playing.clear();
- }
- } else if (!m_audio.isPaused() && m_playTimer.get() > IDLE_TIMEOUT) m_songs.advance(1); // Switch if song hasn't changed for IDLE_TIMEOUT seconds
}
void ScreenSongs::drawCovers() {
diff --git a/game/screen_songs.hh b/game/screen_songs.hh
index 4fd16ff..a04d18e 100644
--- a/game/screen_songs.hh
+++ b/game/screen_songs.hh
@@ -15,14 +15,6 @@ class Song;
class Audio;
class Songs;
-struct ScreenSharedInfo
-{
- std::map<std::string,std::string> music;
- std::string songbg;
- std::string video;
- double videoGap;
-};
-
/// song chooser screen
class ScreenSongs : public Screen {
public:
@@ -41,8 +33,7 @@ public:
protected:
void drawInstruments(Dimensions const& dim, float alpha = 1.0f) const;
void drawMultimedia();
- void updateMultimedia(Song& song, ScreenSharedInfo& info);
- void stopMultimedia(ScreenSharedInfo& info);
+ void update();
Audio& m_audio;
Songs& m_songs;
@@ -50,9 +41,8 @@ protected:
boost::scoped_ptr<Surface> m_songbg, m_songbg_ground, m_songbg_default;
boost::scoped_ptr<Video> m_video;
boost::scoped_ptr<ThemeSongs> theme;
- std::map<std::string,std::string> m_playing;
- std::map<std::string,std::string> m_playReq;
- AnimValue m_playTimer;
+ Song::Music m_playing;
+ AnimValue m_idleTimer;
TextInput m_search;
boost::scoped_ptr<Surface> m_singCover;
boost::scoped_ptr<Surface> m_instrumentCover;
diff --git a/game/song.hh b/game/song.hh
index 726c0ca..a2b1b73 100644
--- a/game/song.hh
+++ b/game/song.hh
@@ -104,7 +104,8 @@ class Song: boost::noncopyable {
std::string text; ///< songtext
std::string creator; ///< creator
std::string language; ///< language
- std::map<std::string,std::string> music; ///< music files (background, guitar, rhythm/bass, drums, vocals)
+ typedef std::map<std::string,std::string> Music;
+ Music music; ///< music files (background, guitar, rhythm/bass, drums, vocals)
std::string cover; ///< cd cover
std::string background; ///< background image
std::string video; ///< video
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2012-02-11 07:01:49
|
Author: Lasse Karkkainen <tro...@tr...>
Date: Sat Feb 11 05:52:08 2012 +0200
Cleanup: determine preview times in song parser rather than in song browser.
---
game/screen_songs.cc | 9 ++-------
game/songparser.cc | 2 ++
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/game/screen_songs.cc b/game/screen_songs.cc
index fc0c86e..bf8fa63 100644
--- a/game/screen_songs.cc
+++ b/game/screen_songs.cc
@@ -178,13 +178,8 @@ void ScreenSongs::stopMultimedia(ScreenSharedInfo& info) {
// Play/stop preview playback (if it is the time)
if (info.music != m_playing && m_playTimer.get() > 0.3) {
m_songbg.reset(); m_video.reset();
- double pstart = 0;
- if (!m_songs.empty() && !m_jukebox) {
- pstart = m_songs.current().preview_start;
- if (pstart != pstart) pstart = 100; // true if NaN, 100 is caught in the next min
- // 5.0s is for performance (don't make it higher unless you implement better seeking method in songs)
- pstart = std::min(pstart, (info.music.size() == 1 ? 30.0 : 5.0)); // we can seek further in 1-track songs
- }
+ double pstart = 0.0; // Playback starting time
+ if (!m_songs.empty() && !m_jukebox) pstart = m_songs.current().preview_start; // In regular mode
if (info.music.empty()) m_audio.fadeout(1.0); else m_audio.playMusic(info.music, true, 2.0, pstart);
if (!info.songbg.empty()) try { m_songbg.reset(new Surface(info.songbg)); } catch (std::exception const&) {}
if (!info.video.empty() && config["graphic/video"].b()) m_video.reset(new Video(info.video, info.videoGap));
diff --git a/game/songparser.cc b/game/songparser.cc
index 7c63d39..d698b15 100644
--- a/game/songparser.cc
+++ b/game/songparser.cc
@@ -85,6 +85,8 @@ SongParser::SongParser(Song& s):
else if (type == INI) iniParseHeader();
else if (type == XML) xmlParseHeader();
else if (type == SM) { smParseHeader(); s.dropNotes(); } // Hack: drop notes here
+ // Default for preview position if none was specified in header
+ if (s.preview_start != s.preview_start) s.preview_start = (type == INI ? 5.0 : 30.0); // 5 s for band mode, 30 s for others
} catch (std::runtime_error& e) {
throw SongParserException(e.what(), m_linenum);
}
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:55
|
Author: Tapio Vierros <tap...@gm...> Date: Tue Jan 31 13:39:59 2012 +0200 Configuration_bg.svg not used anymore. --- themes/default/configuration_bg.svg | 480 ----------------------------------- 1 files changed, 0 insertions(+), 480 deletions(-) |
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:50
|
Author: Tapio Vierros <tap...@gm...> Date: Tue Jan 31 13:39:59 2012 +0200 Configuration_bg.svg not used anymore. --- themes/default/configuration_bg.svg | 480 ----------------------------------- 1 files changed, 0 insertions(+), 480 deletions(-) |
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:44
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:18:44 2012 +0200
Apparantly boost nowadays prints quotes to paths by itself.
---
game/configuration.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/configuration.cc b/game/configuration.cc
index ec747db..1b59858 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -283,7 +283,7 @@ void writeConfig(bool system) {
if (exists(conf)) remove(conf);
if (dirty) {
rename(tmp, conf);
- std::cerr << "Saved configuration to \"" << conf << "\"" << std::endl;
+ std::cerr << "Saved configuration to " << conf << std::endl;
} else {
std::cerr << "Using default settings, no configuration file needed." << std::endl;
}
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:37
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:14:36 2012 +0200
GUI theme switcher.
* Screen switching is currently needed to apply the new theme
* Uses enum config type
--> So might pick wrong saved theme when they are added or deleted
* Needs more testing
---
data/schema.xml | 7 ++++---
game/cache.cc | 2 +-
game/configuration.cc | 17 +++++++++++++++++
game/configuration.hh | 1 +
game/fs.cc | 31 +++++++++++++++++++++++++++++--
game/fs.hh | 3 +++
6 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index 3c8faa0..a98b8c3 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -42,10 +42,11 @@ to save the current settings to XML.
<short>Pitch waves</short>
<long>Enable singing pitch display (when not in karaoke mode).</long>
</entry>
- <entry name="game/theme" type="string">
- <stringvalue>default</stringvalue>
+ <entry name="game/theme" type="int" value="-1">
+ <limits min="-1" max="-1" step="0" />
+ <!-- Enum options added dynamically by scanning theme folders -->
<short>Theme</short>
- <long>Name of the theme to use or absolute path to theme folder.</long>
+ <long>Name of the theme to use.</long>
</entry>
<entry name="game/keyboard_guitar" type="bool" value="true">
<short>Keyboard as guitar</short>
diff --git a/game/cache.cc b/game/cache.cc
index 0f1edd0..5fd637f 100644
--- a/game/cache.cc
+++ b/game/cache.cc
@@ -16,7 +16,7 @@ namespace cache {
#endif
if (isThemeResource(svgfilename)) {
- std::string const theme_name = (config["game/theme"].s().empty() ? "default" : config["game/theme"].s());
+ std::string const theme_name = (config["game/theme"].getEnumName().empty() ? "default" : config["game/theme"].getEnumName());
cache_filename = getCacheDir() / "themes" / theme_name / cache_basename;
} else {
// We use the full path under cache to avoid name collisions
diff --git a/game/configuration.cc b/game/configuration.cc
index de92d67..ec747db 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -152,6 +152,12 @@ void ConfigItem::addEnum(std::string name) {
m_step = 1;
}
+std::string ConfigItem::getEnumName() {
+ int val = i();
+ if (val >= 0 && val < m_enums.size()) return m_enums[val];
+ return "";
+}
+
template <typename T> void ConfigItem::updateNumeric(xmlpp::Element& elem, int mode) {
xmlpp::NodeSet ns = elem.find("limits");
if (!ns.empty()) setLimits<T>(dynamic_cast<xmlpp::Element&>(*ns[0]), m_min, m_max, m_step);
@@ -367,4 +373,15 @@ void readConfig() {
readConfigXML(schemafile, 0); // Read schema and defaults
readConfigXML(systemConfFile, 1); // Update defaults with system config
readConfigXML(userConfFile, 2); // Read user settings
+ { // Populate themes
+ ConfigItem& ci = config["game/theme"];
+ std::vector<std::string> themes = getThemes();
+ bool useDefaultTheme = (ci.i() == -1);
+ for (int i = 0; i < themes.size(); ++i) {
+ ci.addEnum(themes[i]);
+ // Select the default theme is no other is selected
+ if (useDefaultTheme && themes[i] == "default")
+ ci.i() = i;
+ }
+ }
}
diff --git a/game/configuration.hh b/game/configuration.hh
index 93278f8..3122ddd 100644
--- a/game/configuration.hh
+++ b/game/configuration.hh
@@ -38,6 +38,7 @@ class ConfigItem {
std::string const& getShortDesc() const { return m_shortDesc; } ///< get the short description for this ConfigItem
std::string const& getLongDesc() const { return m_longDesc; } ///< get the long description for this ConfigItem
void addEnum(std::string name); ///< Dynamically adds an enum to all values
+ std::string getEnumName(); ///< Returns the selected enum option's text
private:
template <typename T> void updateNumeric(xmlpp::Element& elem, int mode); ///< Used internally for loading XML
diff --git a/game/fs.cc b/game/fs.cc
index 545206e..cb59487 100644
--- a/game/fs.cc
+++ b/game/fs.cc
@@ -98,7 +98,7 @@ fs::path getCacheDir() {
}
fs::path getThemeDir() {
- std::string theme = config["game/theme"].s();
+ std::string theme = config["game/theme"].getEnumName();
static const std::string defaultTheme = "default";
if (theme.empty()) theme = defaultTheme;
return getDataDir() / "themes" / theme;
@@ -117,7 +117,7 @@ fs::path pathMangle(fs::path const& dir) {
}
std::string getThemePath(std::string const& filename) {
- std::string theme = config["game/theme"].s();
+ std::string theme = config["game/theme"].getEnumName();
static const std::string defaultTheme = "default";
if (theme.empty()) theme = defaultTheme;
// Try current theme and if that fails, try default theme and finally data dir
@@ -126,6 +126,33 @@ std::string getThemePath(std::string const& filename) {
return getPath(filename);
}
+std::vector<std::string> getThemes() {
+ std::vector<std::string> themes;
+ // Search all paths for themes folders and add them
+ Paths const& paths = getPaths();
+ for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) {
+ fs::path p = *it;
+ p /= fs::path("themes");
+ if (fs::is_directory(p)) {
+ // Gather the themes in this folder
+ for (fs::directory_iterator dirIt(p), dirEnd; dirIt != dirEnd; ++dirIt) {
+ fs::path p2 = dirIt->path();
+ if (fs::is_directory(p2)) {
+ #if BOOST_FILESYSTEM_VERSION < 3
+ themes.push_back(p2.leaf());
+ #else
+ themes.push_back(p2.filename().string());
+ #endif
+ }
+ }
+ }
+ }
+ // No duplicates allowed
+ std::sort(themes.begin(), themes.end());
+ std::unique(themes.begin(), themes.end());
+ return themes;
+}
+
bool isThemeResource(fs::path filename){
try {
#if BOOST_FILESYSTEM_VERSION < 3
diff --git a/game/fs.hh b/game/fs.hh
index 2743425..a77265a 100644
--- a/game/fs.hh
+++ b/game/fs.hh
@@ -33,6 +33,9 @@ fs::path pathMangle(fs::path const& dir);
/** Get full path to a file from the current theme **/
std::string getThemePath(std::string const& filename);
+/** Get available theme names **/
+std::vector<std::string> getThemes();
+
/** Get full path to a share file **/
std::string getPath(fs::path const& filename);
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:29
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:00:11 2012 +0200
Fixed a bug in getThemePath.
---
game/fs.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/fs.cc b/game/fs.cc
index 767a7ab..545206e 100644
--- a/game/fs.cc
+++ b/game/fs.cc
@@ -122,7 +122,7 @@ std::string getThemePath(std::string const& filename) {
if (theme.empty()) theme = defaultTheme;
// Try current theme and if that fails, try default theme and finally data dir
try { return getPath(fs::path("themes") / theme / filename); } catch (std::runtime_error&) {}
- if (theme == defaultTheme) try { return getPath(fs::path("themes") / defaultTheme / filename); } catch (std::runtime_error&) {}
+ if (theme != defaultTheme) try { return getPath(fs::path("themes") / defaultTheme / filename); } catch (std::runtime_error&) {}
return getPath(filename);
}
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:23
|
Author: Tapio Vierros <tap...@gm...>
Date: Thu Dec 15 19:22:32 2011 +0200
Instrument forcing in UI.
* Dynamically populate the config items with available controller presets.
* Use the config values when evaluating instrument forcing.
---
game/joystick.cc | 23 ++++++++++++++++++++++-
1 files changed, 22 insertions(+), 1 deletions(-)
diff --git a/game/joystick.cc b/game/joystick.cc
index 29432ed..21285e1 100644
--- a/game/joystick.cc
+++ b/game/joystick.cc
@@ -333,8 +333,29 @@ void input::SDL::init() {
readControllers(g_instruments, getDefaultConfig(fs::path("/config/controllers.xml")));
readControllers(g_instruments, getConfigDir() / "controllers.xml");
std::map<unsigned int, input::Instrument> forced_type;
+ ConfigItem::StringList instruments = config["game/instruments"].sl();
+
+ // Populate controller forcing config items
+ ConfigItem& ci0 = config["game/instrument0"];
+ ConfigItem& ci1 = config["game/instrument1"];
+ ConfigItem& ci2 = config["game/instrument2"];
+ ConfigItem& ci3 = config["game/instrument3"];
+ int i = 0;
+ for (input::Instruments::const_iterator it = g_instruments.begin(); it != g_instruments.end(); ++it, ++i) {
+ // Add the enum
+ std::string title = it->second.description;
+ ci0.addEnum(title);
+ ci1.addEnum(title);
+ ci2.addEnum(title);
+ ci3.addEnum(title);
+ // Check for active items
+ if (i == ci0.i()-1) instruments.push_back("0:" + it->first);
+ if (i == ci1.i()-1) instruments.push_back("1:" + it->first);
+ if (i == ci2.i()-1) instruments.push_back("2:" + it->first);
+ if (i == ci3.i()-1) instruments.push_back("3:" + it->first);
+ }
- ConfigItem::StringList const& instruments = config["game/instruments"].sl();
+ // Check all forced instruments
for (ConfigItem::StringList::const_iterator it = instruments.begin(); it != instruments.end(); ++it) {
std::istringstream iss(*it);
unsigned sdl_id;
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:16
|
Author: Tapio Vierros <tap...@gm...>
Date: Thu Dec 15 18:54:48 2011 +0200
Added individual instrument forcing thingys to schema.
---
data/schema.xml | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index 205eff3..3c8faa0 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -63,6 +63,38 @@ to save the current settings to XML.
<short>Keyboard as keyboard</short>
<long>Enable keyboard as keyboard.</long>
</entry>
+ <entry name="game/instrument0" type="int" value="0">
+ <limits>
+ <enum>Auto</enum>
+ <!-- Options added dynamically from controllers.xml -->
+ </limits>
+ <short>Force controller A's type</short>
+ <long>Override autodetection and force the first controller to the given type.</long>
+ </entry>
+ <entry name="game/instrument1" type="int" value="0">
+ <limits>
+ <enum>Auto</enum>
+ <!-- Options added dynamically from controllers.xml -->
+ </limits>
+ <short>Force controller B's type</short>
+ <long>Override autodetection and force the second controller to the given type.</long>
+ </entry>
+ <entry name="game/instrument2" type="int" value="0">
+ <limits>
+ <enum>Auto</enum>
+ <!-- Options added dynamically from controllers.xml -->
+ </limits>
+ <short>Force controller C's type</short>
+ <long>Override autodetection and force the third controller to the given type.</long>
+ </entry>
+ <entry name="game/instrument3" type="int" value="0">
+ <limits>
+ <enum>Auto</enum>
+ <!-- Options added dynamically from controllers.xml -->
+ </limits>
+ <short>Force controller D's type</short>
+ <long>Override autodetection and force the fourth controller to the given type.</long>
+ </entry>
<entry name="game/instruments" type="string_list">
<!-- Should be SDL_ID:{GUITAR_GUITARHERO|GUITAR_GUITARHERO_XPLORER|GUITAR_ROCKBAND_PS3|GUITAR_ROCKBAND_XB360|DRUMS_GUITARHERO|DRUMS_ROCKBAND_PS3|DRUMS_ROCKBAND_XB360|DRUMS_MIDI|DANCEPAD_GENERIC|DANCEPAD_TIGERGAME|DANCEPAD_2TECH}
example:
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:46:08
|
Author: Tapio Vierros <tap...@gm...>
Date: Thu Dec 15 18:54:08 2011 +0200
Added a function to dynamically add enums to a ConfigItem.
---
game/configuration.cc | 8 ++++++++
game/configuration.hh | 1 +
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/game/configuration.cc b/game/configuration.cc
index 3f6144d..de92d67 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -144,6 +144,14 @@ namespace {
}
}
+void ConfigItem::addEnum(std::string name) {
+ verifyType("int");
+ m_enums.push_back(name);
+ m_min = 0;
+ m_max = int(m_enums.size() - 1);
+ m_step = 1;
+}
+
template <typename T> void ConfigItem::updateNumeric(xmlpp::Element& elem, int mode) {
xmlpp::NodeSet ns = elem.find("limits");
if (!ns.empty()) setLimits<T>(dynamic_cast<xmlpp::Element&>(*ns[0]), m_min, m_max, m_step);
diff --git a/game/configuration.hh b/game/configuration.hh
index 82f2e6e..93278f8 100644
--- a/game/configuration.hh
+++ b/game/configuration.hh
@@ -37,6 +37,7 @@ class ConfigItem {
std::string getValue() const; ///< Get a human-readable representation of the current value
std::string const& getShortDesc() const { return m_shortDesc; } ///< get the short description for this ConfigItem
std::string const& getLongDesc() const { return m_longDesc; } ///< get the long description for this ConfigItem
+ void addEnum(std::string name); ///< Dynamically adds an enum to all values
private:
template <typename T> void updateNumeric(xmlpp::Element& elem, int mode); ///< Used internally for loading XML
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:19:29
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:18:44 2012 +0200
Apparantly boost nowadays prints quotes to paths by itself.
---
game/configuration.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/configuration.cc b/game/configuration.cc
index ec747db..1b59858 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -283,7 +283,7 @@ void writeConfig(bool system) {
if (exists(conf)) remove(conf);
if (dirty) {
rename(tmp, conf);
- std::cerr << "Saved configuration to \"" << conf << "\"" << std::endl;
+ std::cerr << "Saved configuration to " << conf << std::endl;
} else {
std::cerr << "Using default settings, no configuration file needed." << std::endl;
}
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:17:48
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:14:36 2012 +0200
GUI theme switcher.
* Screen switching is currently needed to apply the new theme
* Uses enum config type
--> So might pick wrong saved theme when they are added or deleted
* Needs more testing
---
data/schema.xml | 7 ++++---
game/cache.cc | 2 +-
game/configuration.cc | 17 +++++++++++++++++
game/configuration.hh | 1 +
game/fs.cc | 31 +++++++++++++++++++++++++++++--
game/fs.hh | 3 +++
6 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index 29b420c..a51b769 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -42,10 +42,11 @@ to save the current settings to XML.
<short>Pitch waves</short>
<long>Enable singing pitch display (when not in karaoke mode).</long>
</entry>
- <entry name="game/theme" type="string">
- <stringvalue>default</stringvalue>
+ <entry name="game/theme" type="int" value="-1">
+ <limits min="-1" max="-1" step="0" />
+ <!-- Enum options added dynamically by scanning theme folders -->
<short>Theme</short>
- <long>Name of the theme to use or absolute path to theme folder.</long>
+ <long>Name of the theme to use.</long>
</entry>
<entry name="game/keyboard_guitar" type="bool" value="true">
<short>Keyboard as guitar</short>
diff --git a/game/cache.cc b/game/cache.cc
index 0f1edd0..5fd637f 100644
--- a/game/cache.cc
+++ b/game/cache.cc
@@ -16,7 +16,7 @@ namespace cache {
#endif
if (isThemeResource(svgfilename)) {
- std::string const theme_name = (config["game/theme"].s().empty() ? "default" : config["game/theme"].s());
+ std::string const theme_name = (config["game/theme"].getEnumName().empty() ? "default" : config["game/theme"].getEnumName());
cache_filename = getCacheDir() / "themes" / theme_name / cache_basename;
} else {
// We use the full path under cache to avoid name collisions
diff --git a/game/configuration.cc b/game/configuration.cc
index de92d67..ec747db 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -152,6 +152,12 @@ void ConfigItem::addEnum(std::string name) {
m_step = 1;
}
+std::string ConfigItem::getEnumName() {
+ int val = i();
+ if (val >= 0 && val < m_enums.size()) return m_enums[val];
+ return "";
+}
+
template <typename T> void ConfigItem::updateNumeric(xmlpp::Element& elem, int mode) {
xmlpp::NodeSet ns = elem.find("limits");
if (!ns.empty()) setLimits<T>(dynamic_cast<xmlpp::Element&>(*ns[0]), m_min, m_max, m_step);
@@ -367,4 +373,15 @@ void readConfig() {
readConfigXML(schemafile, 0); // Read schema and defaults
readConfigXML(systemConfFile, 1); // Update defaults with system config
readConfigXML(userConfFile, 2); // Read user settings
+ { // Populate themes
+ ConfigItem& ci = config["game/theme"];
+ std::vector<std::string> themes = getThemes();
+ bool useDefaultTheme = (ci.i() == -1);
+ for (int i = 0; i < themes.size(); ++i) {
+ ci.addEnum(themes[i]);
+ // Select the default theme is no other is selected
+ if (useDefaultTheme && themes[i] == "default")
+ ci.i() = i;
+ }
+ }
}
diff --git a/game/configuration.hh b/game/configuration.hh
index 93278f8..3122ddd 100644
--- a/game/configuration.hh
+++ b/game/configuration.hh
@@ -38,6 +38,7 @@ class ConfigItem {
std::string const& getShortDesc() const { return m_shortDesc; } ///< get the short description for this ConfigItem
std::string const& getLongDesc() const { return m_longDesc; } ///< get the long description for this ConfigItem
void addEnum(std::string name); ///< Dynamically adds an enum to all values
+ std::string getEnumName(); ///< Returns the selected enum option's text
private:
template <typename T> void updateNumeric(xmlpp::Element& elem, int mode); ///< Used internally for loading XML
diff --git a/game/fs.cc b/game/fs.cc
index 545206e..cb59487 100644
--- a/game/fs.cc
+++ b/game/fs.cc
@@ -98,7 +98,7 @@ fs::path getCacheDir() {
}
fs::path getThemeDir() {
- std::string theme = config["game/theme"].s();
+ std::string theme = config["game/theme"].getEnumName();
static const std::string defaultTheme = "default";
if (theme.empty()) theme = defaultTheme;
return getDataDir() / "themes" / theme;
@@ -117,7 +117,7 @@ fs::path pathMangle(fs::path const& dir) {
}
std::string getThemePath(std::string const& filename) {
- std::string theme = config["game/theme"].s();
+ std::string theme = config["game/theme"].getEnumName();
static const std::string defaultTheme = "default";
if (theme.empty()) theme = defaultTheme;
// Try current theme and if that fails, try default theme and finally data dir
@@ -126,6 +126,33 @@ std::string getThemePath(std::string const& filename) {
return getPath(filename);
}
+std::vector<std::string> getThemes() {
+ std::vector<std::string> themes;
+ // Search all paths for themes folders and add them
+ Paths const& paths = getPaths();
+ for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) {
+ fs::path p = *it;
+ p /= fs::path("themes");
+ if (fs::is_directory(p)) {
+ // Gather the themes in this folder
+ for (fs::directory_iterator dirIt(p), dirEnd; dirIt != dirEnd; ++dirIt) {
+ fs::path p2 = dirIt->path();
+ if (fs::is_directory(p2)) {
+ #if BOOST_FILESYSTEM_VERSION < 3
+ themes.push_back(p2.leaf());
+ #else
+ themes.push_back(p2.filename().string());
+ #endif
+ }
+ }
+ }
+ }
+ // No duplicates allowed
+ std::sort(themes.begin(), themes.end());
+ std::unique(themes.begin(), themes.end());
+ return themes;
+}
+
bool isThemeResource(fs::path filename){
try {
#if BOOST_FILESYSTEM_VERSION < 3
diff --git a/game/fs.hh b/game/fs.hh
index 2743425..a77265a 100644
--- a/game/fs.hh
+++ b/game/fs.hh
@@ -33,6 +33,9 @@ fs::path pathMangle(fs::path const& dir);
/** Get full path to a file from the current theme **/
std::string getThemePath(std::string const& filename);
+/** Get available theme names **/
+std::vector<std::string> getThemes();
+
/** Get full path to a share file **/
std::string getPath(fs::path const& filename);
|
|
From: Tapio V. <aa...@us...> - 2012-01-31 11:17:41
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 31 13:00:11 2012 +0200
Fixed a bug in getThemePath.
---
game/fs.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/fs.cc b/game/fs.cc
index 767a7ab..545206e 100644
--- a/game/fs.cc
+++ b/game/fs.cc
@@ -122,7 +122,7 @@ std::string getThemePath(std::string const& filename) {
if (theme.empty()) theme = defaultTheme;
// Try current theme and if that fails, try default theme and finally data dir
try { return getPath(fs::path("themes") / theme / filename); } catch (std::runtime_error&) {}
- if (theme == defaultTheme) try { return getPath(fs::path("themes") / defaultTheme / filename); } catch (std::runtime_error&) {}
+ if (theme != defaultTheme) try { return getPath(fs::path("themes") / defaultTheme / filename); } catch (std::runtime_error&) {}
return getPath(filename);
}
|
|
From: Yoda-JM <yo...@us...> - 2012-01-29 10:20:20
|
Author: Lasse Kärkkäinen <tronic+ndrm at trn.iki.fi> Date: Mon Sep 19 12:49:38 2011 +0300 libpng voidp API change --- game/image.hh | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/game/image.hh b/game/image.hh index 58a63a3..d50b1ae 100644 --- a/game/image.hh +++ b/game/image.hh @@ -26,7 +26,7 @@ namespace { } void loadPNG_internal(png_structp pngPtr, png_infop infoPtr, std::ifstream& file, std::vector<unsigned char>& image, std::vector<png_bytep>& rows, unsigned& w, unsigned& h) { if (setjmp(png_jmpbuf(pngPtr))) throw std::runtime_error("Reading PNG failed"); - png_set_read_fn(pngPtr,(voidp)&file, readPngHelper); + png_set_read_fn(pngPtr,(png_voidp)&file, readPngHelper); png_read_info(pngPtr, infoPtr); png_set_expand(pngPtr); // Expand everything to RGB(A) png_set_strip_16(pngPtr); // Strip everything down to 8 bit/component |
|
From: Tapio V. <aa...@us...> - 2012-01-23 18:16:14
|
Author: Tapio Vierros <tap...@gm...>
Date: Mon Jan 23 20:15:15 2012 +0200
Started implementing more robust US txt multiplayer parser, with P3 support.
---
game/song.hh | 6 ++++-
game/songparser-txt.cc | 51 +++++++++++++++++++++++++++++++++++------------
game/songparser.hh | 3 +-
3 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/game/song.hh b/game/song.hh
index 74c813a..726c0ca 100644
--- a/game/song.hh
+++ b/game/song.hh
@@ -60,9 +60,12 @@ class Song: boost::noncopyable {
Status status(double time);
int randomIdx; ///< sorting index used for random order
void insertVocalTrack(std::string vocalTrack, VocalTrack track) {
- vocalTracks.erase(vocalTrack);
+ eraseVocalTrack(vocalTrack);
vocalTracks.insert(std::make_pair<std::string, VocalTrack>(vocalTrack, track));
}
+ void eraseVocalTrack(std::string vocalTrack = TrackName::LEAD_VOCAL) {
+ vocalTracks.erase(vocalTrack);
+ }
// Get a selected track, or LEAD_VOCAL if not found or the first one if not found
VocalTrack& getVocalTrack(std::string vocalTrack = TrackName::LEAD_VOCAL) {
VocalTracks::iterator it = vocalTracks.find(vocalTrack);
@@ -82,6 +85,7 @@ class Song: boost::noncopyable {
}
return result;
}
+
InstrumentTracks instrumentTracks; ///< guitar etc. notes for this song
DanceTracks danceTracks; ///< dance tracks
bool hasDance() const { return !danceTracks.empty(); }
diff --git a/game/songparser-txt.cc b/game/songparser-txt.cc
index 665b9da..abaceaf 100644
--- a/game/songparser-txt.cc
+++ b/game/songparser-txt.cc
@@ -10,6 +10,10 @@
using namespace SongParserUtil;
+namespace {
+ const std::string DUET_P2 = "Duet singer"; // FIXME
+}
+
/// 'Magick' to check if this file looks like correct format
bool SongParser::txtCheck(std::vector<char> const& data) const {
return data[0] == '#' && data[1] >= 'A' && data[1] <= 'Z';
@@ -28,14 +32,28 @@ void SongParser::txtParseHeader() {
/// Parse notes
void SongParser::txtParse() {
std::string line;
- VocalTrack vocal(TrackName::LEAD_VOCAL);
+ m_curSinger = P1;
+ m_song.insertVocalTrack(TrackName::LEAD_VOCAL, VocalTrack(TrackName::LEAD_VOCAL));
+ m_song.insertVocalTrack(DUET_P2, VocalTrack(DUET_P2));
while (getline(line) && txtParseField(line)) {} // Parse the header again
resetNoteParsingState();
- while (txtParseNote(line, vocal) && getline(line)) {} // Parse notes
- // Workaround for the terminating : 1 0 0 line, written by some converters
- if (!vocal.notes.empty() && vocal.notes.back().type != Note::SLEEP
- && vocal.notes.back().begin == vocal.notes.back().end) vocal.notes.pop_back();
- m_song.insertVocalTrack(vocal.name, vocal);
+ while (txtParseNote(line) && getline(line)) {} // Parse notes
+
+ {
+ // Workaround for the terminating : 1 0 0 line, written by some converters
+ VocalTrack& vocal = m_song.getVocalTrack(TrackName::LEAD_VOCAL);
+ if (!vocal.notes.empty() && vocal.notes.back().type != Note::SLEEP
+ && vocal.notes.back().begin == vocal.notes.back().end) vocal.notes.pop_back();
+ }{
+ // Workaround for the terminating : 1 0 0 line, written by some converters
+ VocalTrack& vocal = m_song.getVocalTrack(DUET_P2);
+ if (!vocal.notes.empty() && vocal.notes.back().type != Note::SLEEP
+ && vocal.notes.back().begin == vocal.notes.back().end) vocal.notes.pop_back();
+ // Erase if empty
+ else if (vocal.notes.empty())
+ m_song.eraseVocalTrack(vocal.name);
+ }
+
}
bool SongParser::txtParseField(std::string const& line) {
@@ -66,7 +84,7 @@ bool SongParser::txtParseField(std::string const& line) {
return true;
}
-bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
+bool SongParser::txtParseNote(std::string line) {
if (line.empty() || line == "\r") return true;
if (line[0] == '#') throw std::runtime_error("Key found in the middle of notes");
if (line[line.size() - 1] == '\r') line.erase(line.size() - 1);
@@ -81,13 +99,14 @@ bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
return true;
}
if (line[0] == 'P') {
+ if (m_relative) // FIXME?
+ throw std::runtime_error("Relative note timing not supported with multiple singers");
if (line.size() < 2) throw std::runtime_error("Invalid player info line");
- if (line[1] == '1') return true;
- else if (line[1] == '2') {
- m_song.insertVocalTrack(vocal.name, vocal);
- vocal = VocalTrack("Singer 2"); // FIXME
- resetNoteParsingState();
- }
+ if (line[1] == '1') m_curSinger = P1;
+ else if (line[1] == '2') m_curSinger = P2;
+ else if (line[1] == '3') m_curSinger = BOTH;
+ else throw std::runtime_error("Invalid player info line");
+ resetNoteParsingState();
return true;
}
Note n;
@@ -121,9 +140,13 @@ bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
default: throw std::runtime_error("Unknown note type");
}
n.begin = tsTime(ts);
+ VocalTrack& vocal = (m_curSinger & P1)
+ ? m_song.getVocalTrack(TrackName::LEAD_VOCAL)
+ : m_song.getVocalTrack(DUET_P2);
Notes& notes = vocal.notes;
if (m_relative && notes.empty()) m_relativeShift = ts;
m_prevts = ts;
+ // FIXME: These work-arounds don't work for P3 (both singers) case
if (n.begin < m_prevtime) {
// Oh no, overlapping notes (b0rked file)
// Can't do this because too many songs are b0rked: throw std::runtime_error("Note overlaps with previous note");
@@ -157,6 +180,8 @@ bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
n.begin = n.end = prevtime; // Normalize sleep notes
}
notes.push_back(n);
+ if (m_curSinger == BOTH)
+ m_song.getVocalTrack(DUET_P2).notes.push_back(n);
return true;
}
diff --git a/game/songparser.hh b/game/songparser.hh
index 7962d8f..4cecd29 100644
--- a/game/songparser.hh
+++ b/game/songparser.hh
@@ -36,7 +36,7 @@ class SongParser {
void txtParseHeader();
void txtParse();
bool txtParseField(std::string const& line);
- bool txtParseNote(std::string line, VocalTrack &vocal);
+ bool txtParseNote(std::string line);
bool iniCheck(std::vector<char> const& data) const;
void iniParseHeader();
void iniParse();
@@ -55,6 +55,7 @@ class SongParser {
double m_prevtime;
unsigned int m_prevts;
unsigned int m_relativeShift;
+ enum CurrentSinger { P1 = 1, P2 = 2, BOTH = P1 | P2 } m_curSinger;
struct BPM {
BPM(double _begin, double _ts, double bpm): begin(_begin), step(0.25 * 60.0 / bpm), ts(_ts) {}
double begin; // Time in seconds
|
|
From: Tapio V. <aa...@us...> - 2012-01-23 18:16:12
|
Author: Tapio Vierros <tap...@gm...>
Date: Mon Jan 23 19:36:31 2012 +0200
Optimize getVocalTrack.
---
game/song.hh | 22 +++++++++-------------
1 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/game/song.hh b/game/song.hh
index 16d3e16..74c813a 100644
--- a/game/song.hh
+++ b/game/song.hh
@@ -62,23 +62,19 @@ class Song: boost::noncopyable {
void insertVocalTrack(std::string vocalTrack, VocalTrack track) {
vocalTracks.erase(vocalTrack);
vocalTracks.insert(std::make_pair<std::string, VocalTrack>(vocalTrack, track));
- };
+ }
// Get a selected track, or LEAD_VOCAL if not found or the first one if not found
VocalTrack& getVocalTrack(std::string vocalTrack = TrackName::LEAD_VOCAL) {
- if(vocalTracks.find(vocalTrack) != vocalTracks.end()) {
- return vocalTracks.find(vocalTrack)->second;
+ VocalTracks::iterator it = vocalTracks.find(vocalTrack);
+ if (it != vocalTracks.end()) {
+ return it->second;
} else {
- if(vocalTracks.find(TrackName::LEAD_VOCAL) != vocalTracks.end()) {
- return vocalTracks.find(TrackName::LEAD_VOCAL)->second;
- } else {
- if(!vocalTracks.empty()) {
- return vocalTracks.begin()->second;
- } else {
- return dummyVocal;
- }
- }
+ it = vocalTracks.find(TrackName::LEAD_VOCAL);
+ if (it != vocalTracks.end()) return it->second;
+ else if (!vocalTracks.empty()) return vocalTracks.begin()->second;
+ else return dummyVocal;
}
- };
+ }
std::vector<std::string> getVocalTrackNames() {
std::vector<std::string> result;
BOOST_FOREACH(VocalTracks::value_type &it, vocalTracks) {
|
|
From: Yoda-JM <yo...@us...> - 2012-01-23 00:40:42
|
Author: Vincent Le Ligeour <yo...@us...>
Date: Mon Jan 23 01:40:29 2012 +0100
Removed harmonic track from header (it's FretsOfFire format only)
---
game/song.hh | 3 ---
game/songparser-mid.cc | 16 ++++++++++------
game/songparser-txt.cc | 2 +-
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/game/song.hh b/game/song.hh
index 82c4113..16d3e16 100644
--- a/game/song.hh
+++ b/game/song.hh
@@ -29,9 +29,6 @@ namespace TrackName {
const std::string KEYBOARD = "Keyboard";
const std::string DRUMS = "Drums";
const std::string LEAD_VOCAL = "Vocals";
- const std::string HARMONIC_1 = "Harmonic 1";
- const std::string HARMONIC_2 = "Harmonic 2";
- const std::string HARMONIC_3 = "Harmonic 3";
#if 0 // Here is some dummy gettext calls to populate the dictionary
_("Guitar") _("Coop guitar") _("Rhythm guitar") _("Bass") _("Drums") _("Vocals") _("Harmonic 1") _("Harmonic 2") _("Harmonic 3")
#endif
diff --git a/game/songparser-mid.cc b/game/songparser-mid.cc
index e944968..5068f49 100644
--- a/game/songparser-mid.cc
+++ b/game/songparser-mid.cc
@@ -11,6 +11,10 @@
using namespace SongParserUtil;
+const std::string HARMONIC_1 = "Harmonic 1";
+const std::string HARMONIC_2 = "Harmonic 2";
+const std::string HARMONIC_3 = "Harmonic 3";
+
namespace {
void testAndAdd(Song& s, std::string const& trackid, std::string const& filename) {
std::string f = s.path + filename;
@@ -18,9 +22,9 @@ namespace {
}
bool isVocalTrack(std::string name) {
if(name == TrackName::LEAD_VOCAL) return true;
- else if(name == TrackName::HARMONIC_1) return true;
- else if(name == TrackName::HARMONIC_2) return true;
- else if(name == TrackName::HARMONIC_3) return true;
+ else if(name == HARMONIC_1) return true;
+ else if(name == HARMONIC_2) return true;
+ else if(name == HARMONIC_3) return true;
return false;
}
/// Change the MIDI track name to Performous track name
@@ -39,9 +43,9 @@ namespace {
else if (name == "KEYS") return false; // TODO: RB3 5 lane keyboard track
else if (name == "GUITAR") name = TrackName::GUITAR;
else if (name == "VOCALS") name = TrackName::LEAD_VOCAL;
- else if (name == "HARM1") name = TrackName::HARMONIC_1;
- else if (name == "HARM2") name = TrackName::HARMONIC_2;
- else if (name == "HARM3") name = TrackName::HARMONIC_3;
+ else if (name == "HARM1") name = HARMONIC_1;
+ else if (name == "HARM2") name = HARMONIC_2;
+ else if (name == "HARM3") name = HARMONIC_3;
// expert stuffs
else if (name == "REAL_KEYS_X") return false; // TODO: RB3 pro keyboard expert track
else if (name == "REAL_KEYS_H") return false; // TODO: RB3 pro keyboard hard track
diff --git a/game/songparser-txt.cc b/game/songparser-txt.cc
index 6744eaf..665b9da 100644
--- a/game/songparser-txt.cc
+++ b/game/songparser-txt.cc
@@ -85,7 +85,7 @@ bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
if (line[1] == '1') return true;
else if (line[1] == '2') {
m_song.insertVocalTrack(vocal.name, vocal);
- vocal = VocalTrack(TrackName::HARMONIC_1);
+ vocal = VocalTrack("Singer 2"); // FIXME
resetNoteParsingState();
}
return true;
|
|
From: Yoda-JM <yo...@us...> - 2012-01-23 00:33:40
|
Author: Vincent Le Ligeour <yo...@us...> Date: Mon Jan 23 01:33:18 2012 +0100 Added SingStar XML format parsing --- game/songparser-xml.cc | 321 ++++++++++++++++++++++++++++++++++++++++++++++++ game/songparser.cc | 5 +- game/songparser.hh | 3 + game/songs.cc | 2 +- 4 files changed, 329 insertions(+), 2 deletions(-) |
|
From: Tapio V. <aa...@us...> - 2012-01-17 21:34:53
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 17 23:33:42 2012 +0200
Support for UltraStar TXT multiplayer duet note parsing.
Needs more testing.
---
game/songparser-txt.cc | 15 ++++++++++++---
game/songparser.cc | 9 +++++++++
game/songparser.hh | 1 +
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/game/songparser-txt.cc b/game/songparser-txt.cc
index 06221b3..6744eaf 100644
--- a/game/songparser-txt.cc
+++ b/game/songparser-txt.cc
@@ -30,12 +30,12 @@ void SongParser::txtParse() {
std::string line;
VocalTrack vocal(TrackName::LEAD_VOCAL);
while (getline(line) && txtParseField(line)) {} // Parse the header again
- if (m_bpm != 0.0) addBPM(0, m_bpm);
+ resetNoteParsingState();
while (txtParseNote(line, vocal) && getline(line)) {} // Parse notes
// Workaround for the terminating : 1 0 0 line, written by some converters
if (!vocal.notes.empty() && vocal.notes.back().type != Note::SLEEP
&& vocal.notes.back().begin == vocal.notes.back().end) vocal.notes.pop_back();
- m_song.insertVocalTrack(TrackName::LEAD_VOCAL, vocal);
+ m_song.insertVocalTrack(vocal.name, vocal);
}
bool SongParser::txtParseField(std::string const& line) {
@@ -80,7 +80,16 @@ bool SongParser::txtParseNote(std::string line, VocalTrack &vocal) {
addBPM(ts, bpm);
return true;
}
- if (line[0] == 'P') return true; //We ignore player information for now (multiplayer hack)
+ if (line[0] == 'P') {
+ if (line.size() < 2) throw std::runtime_error("Invalid player info line");
+ if (line[1] == '1') return true;
+ else if (line[1] == '2') {
+ m_song.insertVocalTrack(vocal.name, vocal);
+ vocal = VocalTrack(TrackName::HARMONIC_1);
+ resetNoteParsingState();
+ }
+ return true;
+ }
Note n;
n.type = Note::Type(iss.get());
unsigned int ts = m_prevts;
diff --git a/game/songparser.cc b/game/songparser.cc
index ac9f3f6..f3a2862 100644
--- a/game/songparser.cc
+++ b/game/songparser.cc
@@ -117,6 +117,15 @@ SongParser::SongParser(Song& s):
s.loadStatus = Song::HEADER;
}
+void SongParser::resetNoteParsingState() {
+ m_prevtime = 0;
+ m_prevts = 0;
+ m_relativeShift = 0;
+ m_tsPerBeat = 0;
+ m_tsEnd = 0;
+ m_bpms.clear();
+ if (m_bpm != 0.0) addBPM(0, m_bpm);
+}
void SongParser::finalize() {
std::vector<std::string> tracks = m_song.getVocalTrackNames();
diff --git a/game/songparser.hh b/game/songparser.hh
index 7355a33..0347559 100644
--- a/game/songparser.hh
+++ b/game/songparser.hh
@@ -48,6 +48,7 @@ class SongParser {
void smParse();
bool smParseField(std::string line);
Notes smParseNotes(std::string line);
+ void resetNoteParsingState();
double m_prevtime;
unsigned int m_prevts;
unsigned int m_relativeShift;
|
|
From: Tapio V. <aa...@us...> - 2012-01-17 19:43:12
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 17 21:42:29 2012 +0200
Full screen singer layout if only one mic available.
---
game/screen_sing.cc | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/game/screen_sing.cc b/game/screen_sing.cc
index eeb8240..dfb7a9e 100644
--- a/game/screen_sing.cc
+++ b/game/screen_sing.cc
@@ -60,10 +60,11 @@ void ScreenSing::enter() {
selectedTracks.push_back(&m_song->getVocalTrack(m_selectedTrack));
m_layout_singer.clear();
m_layout_singer.push_back(new LayoutSinger(*selectedTracks.back(), m_database, theme));
- // Find out if we have multiple vocal tracks and create layouts for them, up to a total of 2
+ // Do we have a second vocal track and a singer for it?
std::vector<std::string> tracks = m_song->getVocalTrackNames();
- for (size_t i = 1; i < std::min((int)tracks.size(), 2); ++i) {
- selectedTracks.push_back(&m_song->getVocalTrack(tracks[i]));
+ if (tracks.size() > 1 && analyzers.size() > 1) {
+ // TODO: Maybe should check that tracks[1] is not LEAD_VOCALS
+ selectedTracks.push_back(&m_song->getVocalTrack(tracks[1]));
m_layout_singer.push_back(new LayoutSinger(*selectedTracks.back(), m_database, theme));
}
// Load instrument and dance tracks
|
|
From: Tapio V. <aa...@us...> - 2012-01-17 19:29:25
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 17 21:28:10 2012 +0200
Draw player scores etc only in their corresponding singer layout.
---
game/layout_singer.cc | 28 +++++++++++++++-------------
1 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/game/layout_singer.cc b/game/layout_singer.cc
index 4f0645c..9d52d7c 100644
--- a/game/layout_singer.cc
+++ b/game/layout_singer.cc
@@ -29,8 +29,9 @@ void LayoutSinger::reset() {
}
void LayoutSinger::drawScore(PositionMode position) {
- unsigned int i = 0;
+ unsigned int i = 0, j = 0;
for (std::list<Player>::const_iterator p = m_database.cur.begin(); p != m_database.cur.end(); ++p, ++i) {
+ if (p->m_vocal.name != m_vocal.name) continue;
float act = p->activity();
if (act == 0.0f) continue;
float r = p->m_color.r;
@@ -39,21 +40,21 @@ void LayoutSinger::drawScore(PositionMode position) {
m_score_text[i%4]->render((boost::format("%04d") % p->getScore()).str());
switch(position) {
case LayoutSinger::FULL:
- m_player_icon->dimensions.left(-0.5 + 0.01 + 0.25 * i).fixedWidth(0.075).screenTop(0.055);
- m_score_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * i).fixedHeight(0.075).screenTop(0.055);
+ m_player_icon->dimensions.left(-0.5 + 0.01 + 0.25 * j).fixedWidth(0.075).screenTop(0.055);
+ m_score_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * j).fixedHeight(0.075).screenTop(0.055);
break;
case LayoutSinger::TOP:
- m_player_icon->dimensions.right(0.35).fixedHeight(0.050).screenTop(0.025 + 0.050 * i);
- m_score_text[i%4]->dimensions().right(0.45).fixedHeight(0.050).screenTop(0.025 + 0.050 * i);
+ m_player_icon->dimensions.right(0.35).fixedHeight(0.050).screenTop(0.025 + 0.050 * j);
+ m_score_text[i%4]->dimensions().right(0.45).fixedHeight(0.050).screenTop(0.025 + 0.050 * j);
break;
case LayoutSinger::BOTTOM:
- m_player_icon->dimensions.right(0.35).fixedHeight(0.050).center(0.025 + 0.050 * i);
- m_score_text[i%4]->dimensions().right(0.45).fixedHeight(0.050).center(0.025 + 0.050 * i);
+ m_player_icon->dimensions.right(0.35).fixedHeight(0.050).center(0.025 + 0.050 * j);
+ m_score_text[i%4]->dimensions().right(0.45).fixedHeight(0.050).center(0.025 + 0.050 * j);
break;
case LayoutSinger::LEFT:
case LayoutSinger::RIGHT:
- m_player_icon->dimensions.left(-0.5 + 0.01 + 0.25 * i).fixedWidth(0.075).screenTop(0.055);
- m_score_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * i).fixedHeight(0.075).screenTop(0.055);
+ m_player_icon->dimensions.left(-0.5 + 0.01 + 0.25 * j).fixedWidth(0.075).screenTop(0.055);
+ m_score_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * j).fixedHeight(0.075).screenTop(0.055);
break;
}
{
@@ -74,17 +75,17 @@ void LayoutSinger::drawScore(PositionMode position) {
m_line_rank_text[i%4]->render(prevLineRank);
switch(position) {
case LayoutSinger::FULL:
- m_line_rank_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * i).fixedHeight(0.055*fzoom).screenTop(0.11);
+ m_line_rank_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * j).fixedHeight(0.055*fzoom).screenTop(0.11);
break;
case LayoutSinger::TOP:
- m_line_rank_text[i%4]->dimensions().right(0.30).fixedHeight(0.05*fzoom).screenTop(0.025 + 0.050 * i);
+ m_line_rank_text[i%4]->dimensions().right(0.30).fixedHeight(0.05*fzoom).screenTop(0.025 + 0.050 * j);
break;
case LayoutSinger::BOTTOM:
- m_line_rank_text[i%4]->dimensions().right(0.30).fixedHeight(0.05*fzoom).center(0.025 + 0.050 * i);
+ m_line_rank_text[i%4]->dimensions().right(0.30).fixedHeight(0.05*fzoom).center(0.025 + 0.050 * j);
break;
case LayoutSinger::LEFT:
case LayoutSinger::RIGHT:
- m_line_rank_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * i).fixedHeight(0.055*fzoom).screenTop(0.11);
+ m_line_rank_text[i%4]->dimensions().middle(-0.350 + 0.01 + 0.25 * j).fixedHeight(0.055*fzoom).screenTop(0.11);
break;
}
{
@@ -92,6 +93,7 @@ void LayoutSinger::drawScore(PositionMode position) {
m_line_rank_text[i%4]->draw();
}
}
+ ++j;
}
}
|
|
From: Tapio V. <aa...@us...> - 2012-01-17 19:29:16
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 17 21:27:35 2012 +0200
Draw pitch waves only in their correct notegraph.
---
game/notegraph.cc | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/game/notegraph.cc b/game/notegraph.cc
index c8ce4c6..e70fe5c 100644
--- a/game/notegraph.cc
+++ b/game/notegraph.cc
@@ -197,6 +197,8 @@ void NoteGraph::drawWaves(Database const& database) {
UseTexture tblock(m_wave);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
for (std::list<Player>::const_iterator p = database.cur.begin(); p != database.cur.end(); ++p) {
+ if (p->m_vocal.name != m_vocal.name)
+ continue;
float const texOffset = 2.0 * m_time; // Offset for animating the wave texture
Player::pitch_t const& pitch = p->m_pitch;
size_t const beginIdx = std::max(0.0, m_time - 0.5 / pixUnit) / Engine::TIMESTEP; // At which pitch idx to start displaying the wave
|
|
From: Tapio V. <aa...@us...> - 2012-01-17 19:14:50
|
Author: Tapio Vierros <tap...@gm...>
Date: Tue Jan 17 21:12:57 2012 +0200
Engine work for duet: now different tracks are analyzed.
Contains some FIXMEs though.
---
game/engine.hh | 26 +++++++++++++++++---------
game/screen_sing.cc | 14 +++++++++-----
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/game/engine.hh b/game/engine.hh
index 7fed62d..7ebeeb6 100644
--- a/game/engine.hh
+++ b/game/engine.hh
@@ -12,13 +12,13 @@
/// performous engine
class Engine {
Audio& m_audio;
- VocalTrack& m_vocal;
size_t m_time;
volatile bool m_quit;
Database& m_database;
boost::scoped_ptr<boost::thread> m_thread;
public:
+ typedef std::vector<VocalTrack*> VocalTrackPtrs;
/// timestepping constant
static const double TIMESTEP;
/** Construct a new Engine with the players that go with it.
@@ -28,17 +28,24 @@ class Engine {
* @param anEnd Analyzers to use (ending iterator)
* @param vocal Song to play
**/
- template <typename FwdIt> Engine(Audio& audio, VocalTrack& vocal, FwdIt anBegin, FwdIt anEnd, Database& database):
- m_audio(audio), m_vocal(vocal), m_time(), m_quit(), m_database(database)
+ template <typename FwdIt> Engine(Audio& audio, VocalTrackPtrs vocals, FwdIt anBegin, FwdIt anEnd, Database& database):
+ m_audio(audio), m_time(), m_quit(), m_database(database)
{
- // clear old player information
+ if (vocals.empty())
+ throw std::runtime_error("Engine needs at least one vocal track");
+ // Remove unsensibly long tracks
+ for (VocalTrackPtrs::iterator it = vocals.begin(); it != vocals.end(); )
+ if (!(*it) || (*it)->endTime > 10000.0) it = vocals.erase(it);
+ else ++it;
+ // Clear old player information
m_database.cur.clear();
m_database.scores.clear();
- // Only add players if the vocal track has sensible length (not NaN or extremely long)
- if (vocal.endTime < 10000.0) {
+ size_t i = 0;
+ while (anBegin != anEnd && !vocals.empty()) {
// Calculate the space required for pitch frames
- size_t frames = vocal.endTime / Engine::TIMESTEP;
- while (anBegin != anEnd) m_database.cur.push_back(Player(vocal, *anBegin++, frames));
+ size_t frames = vocals[i]->endTime / Engine::TIMESTEP;
+ m_database.cur.push_back(Player(*vocals[i], *anBegin++, frames));
+ i = (i+1) % vocals.size();
}
m_thread.reset(new boost::thread(boost::ref(*this)));
}
@@ -53,7 +60,8 @@ class Engine {
double timeLeft = m_time * TIMESTEP - t;
if (timeLeft != timeLeft || timeLeft > 1.0) timeLeft = 1.0; // FIXME: Workaround for NaN values and other weirdness (should fix the weirdness instead)
if (timeLeft > 0.0) { boost::thread::sleep(now() + std::min(TIMESTEP, timeLeft)); continue; }
- for (Notes::const_iterator it = m_vocal.notes.begin(); it != m_vocal.notes.end(); ++it) it->power = 0.0f;
+ // FIXME: Implement
+ //for (Notes::const_iterator it = m_vocal.notes.begin(); it != m_vocal.notes.end(); ++it) it->power = 0.0f;
std::for_each(m_database.cur.begin(), m_database.cur.end(), boost::bind(&Player::update, _1));
++m_time;
}
diff --git a/game/screen_sing.cc b/game/screen_sing.cc
index 31ab59c..eeb8240 100644
--- a/game/screen_sing.cc
+++ b/game/screen_sing.cc
@@ -56,12 +56,15 @@ void ScreenSing::enter() {
boost::ptr_vector<Analyzer>& analyzers = m_audio.analyzers();
reloadGL();
// Add a singer layout
+ Engine::VocalTrackPtrs selectedTracks;
+ selectedTracks.push_back(&m_song->getVocalTrack(m_selectedTrack));
m_layout_singer.clear();
- m_layout_singer.push_back(new LayoutSinger(m_song->getVocalTrack(m_selectedTrack), m_database, theme));
+ m_layout_singer.push_back(new LayoutSinger(*selectedTracks.back(), m_database, theme));
// Find out if we have multiple vocal tracks and create layouts for them, up to a total of 2
std::vector<std::string> tracks = m_song->getVocalTrackNames();
for (size_t i = 1; i < std::min((int)tracks.size(), 2); ++i) {
- m_layout_singer.push_back(new LayoutSinger(m_song->getVocalTrack(tracks[i]), m_database, theme));
+ selectedTracks.push_back(&m_song->getVocalTrack(tracks[i]));
+ m_layout_singer.push_back(new LayoutSinger(*selectedTracks.back(), m_database, theme));
}
// Load instrument and dance tracks
sm->loading(_("Loading instruments..."), 0.8);
@@ -100,12 +103,13 @@ void ScreenSing::enter() {
opts.push_back(*it);
}
m_vocalTrackOpts = ConfigItem(opts); // Create a ConfigItem from the option list
- if (opts.size() > 1) { // Vocal track changer only if there is options
+ // FIXME: Add a duet option without breaking track selector
+ /*if (opts.size() > 1) { // Vocal track changer only if there is options
m_vocalTrackOpts.select(cur); // Set the selection to current track
m_menu.add(MenuOption("", _("Change vocal track\n(restart required)"), &m_vocalTrackOpts));
m_selectedTrackLocalized = _(m_selectedTrack.c_str());
m_menu.back().setDynamicName(m_selectedTrackLocalized); // Set the title to be dynamic
- }
+ }*/
}
m_menu.add(MenuOption(_("Quit"), _("Exit to song browser"), "Songs"));
m_menu.close();
@@ -113,7 +117,7 @@ void ScreenSing::enter() {
double setup_delay = (m_instruments.empty() && m_dancers.empty() ? -1.0 : -5.0);
sm->loading(_("Finalizing..."), 0.95);
m_audio.playMusic(m_song->music, false, 0.0, setup_delay);
- m_engine.reset(new Engine(m_audio, m_song->getVocalTrack(m_selectedTrack), analyzers.begin(), analyzers.end(), m_database));
+ m_engine.reset(new Engine(m_audio, selectedTracks, analyzers.begin(), analyzers.end(), m_database));
// Notify about broken tracks
if (m_song->b0rkedTracks) ScreenManager::getSingletonPtr()->dialog(_("Song contains broken tracks!"));
sm->showLogo(false);
|
|
From: Tapio V. <aa...@us...> - 2011-12-18 17:40:49
|
Author: Tapio Vierros <tap...@gm...>
Date: Sun Dec 18 19:37:53 2011 +0200
Disable joining with keyboard starpower since CTRL is used for e.g. seeking.
---
game/guitargraph.cc | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/game/guitargraph.cc b/game/guitargraph.cc
index aeb9d30..20883b3 100644
--- a/game/guitargraph.cc
+++ b/game/guitargraph.cc
@@ -316,9 +316,10 @@ void GuitarGraph::engine() {
bool difficulty_changed = false;
// Handle all events
for (input::Event ev; m_input.tryPoll(ev);) {
- // This hack disallows joining with Enter-key for skipping instrumental
- // breaks to be usable with FoF songs.
- if (dead() && m_input.isKeyboard() && ev.type == input::Event::PICK) continue;
+ // This hack disallows joining with Enter and CTRL-key
+ // since they cause issues due to also being used in other places
+ if (dead() && m_input.isKeyboard()
+ && (ev.type == input::Event::PICK || ev.button == input::GODMODE_BUTTON)) continue;
m_dead = 0; // Keep alive
// Handle joining
if (m_jointime != m_jointime) {
|