|
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
|