|
From: Lasse Kärkkäi. <tr...@us...> - 2010-01-15 00:45:59
|
Module: performous
Branch: master
Commit: 0d4d24e28073498b2fd59b77b2899d279a53fdb9
Author: Lasse Karkkainen <tro...@tr...>
Date: Fri Jan 15 02:45:48 2010 +0200
Rewritten singing note power handling (fixes flashing notes issue) and score calculation (cleanup)
---
docs/TODO.txt | 2 ++
game/notes.cc | 21 ++++++++-------------
game/notes.hh | 10 ++++++----
game/player.cc | 11 ++++++++---
4 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/docs/TODO.txt b/docs/TODO.txt
index dd2933b..acb923e 100644
--- a/docs/TODO.txt
+++ b/docs/TODO.txt
@@ -70,3 +70,5 @@ Bugs:
* Different images may also stop at the exact same pixel
=> out of memory condition or something?
+- Instrument data files + catch
+
diff --git a/game/notes.cc b/game/notes.cc
index 0b78c10..3ee1845 100644
--- a/game/notes.cc
+++ b/game/notes.cc
@@ -55,25 +55,20 @@ double MusicalScale::getNoteOffset(double freq) const {
Note::Note(): begin(getNaN()), end(getNaN()), phase(getNaN()), power(getNaN()), type(NORMAL), note(), notePrev() {}
double Note::diff(double note, double n) { return remainder(n - note, 12.0); }
-double Note::maxScore() const { return scoreMultiplier(0.0) * (end - begin); }
+double Note::maxScore() const { return scoreMultiplier() * (end - begin); }
double Note::score(double n, double b, double e) const {
double len = std::min(e, end) - std::max(b, begin);
if (len <= 0.0 || !(n > 0.0)) return 0.0;
- return scoreMultiplier(std::abs(diff(n))) * len;
+ return scoreMultiplier() * powerFactor(n) * len;
}
-double Note::scoreMultiplier(double error) const {
- double max = 0.0;
- switch (type) {
- case FREESTYLE: power += 1.0; return 1.0;
- case NORMAL: case SLIDE: max = 1.0; break;
- case GOLDEN: max = 2.0; break;
- case SLEEP: case TAP: case HOLDBEGIN: case HOLDEND: case ROLL: case MINE: case LIFT: break;
- }
- double accuracy = clamp(1.5 - error, 0.0, 1.0);
- power += accuracy;
- return accuracy * max;
+double Note::scoreMultiplier() const { return type == GOLDEN ? 2.0 : 1.0; }
+
+double Note::powerFactor(double note) const {
+ if (type == FREESTYLE) return 1.0;
+ double error = std::abs(diff(note));
+ return clamp(1.5 - error, 0.0, 1.0);
}
Duration::Duration(): begin(getNaN()), end(getNaN()) {}
diff --git a/game/notes.hh b/game/notes.hh
index ae1694e..fdb0b09 100644
--- a/game/notes.hh
+++ b/game/notes.hh
@@ -71,10 +71,10 @@ struct Note {
double begin, ///< begin time
end; ///< end time
double phase; /// Position within a measure, [0, 1)
- /// power of note
+ /// power of note (how well it is being hit right now)
mutable double power;
/// how well the note was sung [0,1] (used for drawing a star)
- mutable float accuracy;
+ mutable double accuracy;
/// note type
enum Type { FREESTYLE = 'F', NORMAL = ':', GOLDEN = '*', SLIDE = '+', SLEEP = '-',
TAP = '1', HOLDBEGIN = '2', HOLDEND = '3', ROLL = '4', MINE = 'M', LIFT = 'L'} type;
@@ -88,14 +88,16 @@ struct Note {
static double diff(double note, double n);
/// maximum score
double maxScore() const;
- /// score when singing
+ /// score when singing over time period (a, b), which needs not to be entirely within the note
double score(double freq, double b, double e) const;
+ /// How precisely the note is hit (always 1.0 for freestyle, 0..1 for others)
+ double powerFactor(double note) const;
/// compares begin of two notes
static bool ltBegin(Note const& a, Note const& b) { return a.begin < b.begin; }
/// compares end of two notes
static bool ltEnd(Note const& a, Note const& b) { return a.end < b.end; }
private:
- double scoreMultiplier(double error) const;
+ double scoreMultiplier() const;
};
typedef std::vector<Note> Notes;
diff --git a/game/player.cc b/game/player.cc
index 3e43d95..8b8c7f5 100644
--- a/game/player.cc
+++ b/game/player.cc
@@ -13,6 +13,7 @@ Player::Player(Song& song, Analyzer& analyzer, size_t frames):
void Player::update() {
if (m_pos == m_pitch.size()) return; // End of song already
double beginTime = Engine::TIMESTEP * m_pos;
+ // Get the currently sung tone and store it in player's pitch data (also control inactivity timer)
Tone const* t = m_analyzer.findTone();
if (t) {
m_activitytimer = 1000;
@@ -22,13 +23,18 @@ void Player::update() {
m_pitch[m_pos++] = std::make_pair(getNaN(), -getInf());
}
double endTime = Engine::TIMESTEP * m_pos;
+ // Iterate over all the notes that are considered for this timestep
while (m_scoreIt != m_song.notes.end()) {
+ // If tone was detected, calculate score
if (t) {
+ double note = m_song.scale.getNote(t->freq);
// Add score
- double score_addition = m_song.m_scoreFactor * m_scoreIt->score(m_song.scale.getNote(t->freq), beginTime, endTime);
+ double score_addition = m_song.m_scoreFactor * m_scoreIt->score(note, beginTime, endTime);
m_score += score_addition;
m_noteScore += score_addition;
m_lineScore += score_addition;
+ // Add power
+ m_scoreIt->power = std::max(m_scoreIt->power, m_scoreIt->powerFactor(note));
}
// If a row of lyrics ends, calculate how well it went
if (m_scoreIt->type == Note::SLEEP) {
@@ -38,8 +44,7 @@ void Player::update() {
}
if (endTime < m_scoreIt->end) break;
// Set accuracy
- m_scoreIt->accuracy = std::max(m_scoreIt->accuracy,
- float(m_noteScore / m_song.m_scoreFactor / m_scoreIt->maxScore()));
+ m_scoreIt->accuracy = std::max(m_scoreIt->accuracy, m_noteScore / m_song.m_scoreFactor / m_scoreIt->maxScore());
m_noteScore = 0; // Reset noteScore as we are moving on to the next one
++m_scoreIt;
}
|