|
From: knittl <kn...@us...> - 2009-08-03 08:41:23
|
Module: performous
Branch: master
Commit: b79176c8812ce93764b8178dc57e1057be33db2c
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Aug 2 21:45:05 2009 +0300
Fade out streams when played incorrectly.
---
data/performous.xml | 10 +++++++++-
game/audio.cc | 5 +++++
game/audio.hh | 16 +++++++++++++---
game/guitargraph.cc | 29 ++++++++++++++++++-----------
game/guitargraph.hh | 7 +++++--
game/screen_sing.cc | 17 ++++++++++++++++-
6 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/data/performous.xml b/data/performous.xml
index 2911139..05721b9 100644
--- a/data/performous.xml
+++ b/data/performous.xml
@@ -132,7 +132,15 @@
<limits min="-0.5" max="0.5" step="0.02" />
<locale name="C">
<short>Audio/video latency</short>
- <long>Use negative value if your display input lag is greater than the sound card output latency, positive values in opposite case and zero if they are equal. F5/F6 to adjust this in singing screen.</long>
+ <long>Use negative value if your display input lag is greater than the sound card output latency, positive values in the opposite case and zero if they are equal. F5/F6 to adjust this in singing screen.</long>
+ </locale>
+ </entry>
+ <entry name="audio/controller_delay" type="float" value="0.00">
+ <ui unit=" ms" multiplier="1000" />
+ <limits min="-0.5" max="0.5" step="0.02" />
+ <locale name="C">
+ <short>Audio/controller latency</short>
+ <long>Use negative value if your controller lag is greater than the sound card output latency, positive values in the opposite case and zero if they are equal.</long>
</locale>
</entry>
<entry name="audio/round-trip" type="float" value="0.08">
diff --git a/game/audio.cc b/game/audio.cc
index fbb2d21..72fd294 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -133,3 +133,8 @@ void Audio::pause(bool state) {
m_mixer.pause(m_paused);
}
+void Audio::streamFade(unsigned num, double level) {
+ da::lock_holder l = m_mixer.lock();
+ m_streams.at(num)->fade = level;
+}
+
diff --git a/game/audio.hh b/game/audio.hh
index 74d0c6a..db8e027 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -23,10 +23,19 @@ struct Stream {
double srate;
/// constructor
Stream(std::string const& filename, unsigned int sr):
- mpeg(false, true, filename, sr), srate(sr), m_pos() {}
+ mpeg(false, true, filename, sr), srate(sr), m_pos(), fade(1.0) {}
/// crossfades songs
bool operator()(da::pcm_data& data) {
- mpeg.audioQueue(data, m_pos);
+ if (fade == 1.0) {
+ mpeg.audioQueue(data, m_pos);
+ } else {
+ std::vector<da::sample_t> tmp(data.samples());
+ da::pcm_data dtmp(&tmp[0], data.frames, data.channels, data.rate);
+ mpeg.audioQueue(dtmp, m_pos);
+ for (std::size_t i = 0, s = data.samples(); i < s; ++i) {
+ data[i] += dtmp[i] * fade;
+ }
+ }
return !eof();
}
void seek(double time) { m_pos = time * srate * 2.0; }
@@ -34,6 +43,7 @@ struct Stream {
double duration() const { return mpeg.audioQueue.duration(); }
bool eof() const { return mpeg.audioQueue.eof(m_pos); }
int64_t m_pos;
+ double fade;
};
/** @short High level audio playback API **/
@@ -81,7 +91,7 @@ class Audio {
void pause(bool state = true);
/// toggles synth playback (F4)
void toggleSynth(Notes const& notes) { m_notes = (m_notes ? NULL : ¬es); }
-
+ void streamFade(unsigned num, double level);
private:
bool m_paused;
Notes const* volatile m_notes;
diff --git a/game/guitargraph.cc b/game/guitargraph.cc
index c5aa978..3c5b123 100644
--- a/game/guitargraph.cc
+++ b/game/guitargraph.cc
@@ -42,10 +42,11 @@ GuitarGraph::GuitarGraph(Song const& song, bool drums, unsigned track):
m_cx(0.0, 0.2),
m_width(0.5, 0.4),
m_track(track),
+ m_stream(),
m_level(),
m_dead(-1),
m_text(getThemePath("sing_timetxt.svg"), config["graphic/text_lod"].f()),
- m_hammerReady(0.0, 2.0),
+ m_correctness(0.0, 2.0),
m_score()
{
for (Tracks::const_iterator it = m_song.tracks.begin(); it != m_song.tracks.end(); ++it) {
@@ -60,7 +61,9 @@ GuitarGraph::GuitarGraph(Song const& song, bool drums, unsigned track):
difficultyAuto();
}
-void GuitarGraph::engine(double time) {
+void GuitarGraph::engine(Audio& audio) {
+ double time = audio.getPosition();
+ time -= config["audio/controller_delay"].f();
// Handle holds
if (!m_drums) {
for (int i = 0; i < 5; ++i) {
@@ -98,10 +101,11 @@ void GuitarGraph::engine(double time) {
}
// Skip missed notes
while (m_chordIt != m_chords.end() && m_chordIt->begin + maxTolerance < time) {
- if (m_chordIt->status < m_chordIt->polyphony) m_hammerReady.setTarget(0.0);
+ if (m_chordIt->status < m_chordIt->polyphony) m_correctness.setTarget(0.0);
++m_chordIt;
++m_dead;
}
+ if (m_chordIt != m_chords.end() && m_chordIt->end < time) m_correctness.setTarget(1.0);
}
void GuitarGraph::drumHit(double time, int fret) {
@@ -120,11 +124,11 @@ void GuitarGraph::drumHit(double time, int fret) {
if (best == m_chords.end()) {
std::cout << "MISS" << std::endl;
m_score -= 50;
- m_hammerReady.setTarget(0.0, true); // Instantly go to zero
+ m_correctness.setTarget(0.0, true); // Instantly go to zero
} else {
while (best != m_chordIt) {
if (m_chordIt->status == m_chordIt->polyphony) continue;
- m_hammerReady.setTarget(0.0);
+ m_correctness.setTarget(0.0);
std::cout << "SKIPPED, ";
++m_chordIt;
}
@@ -148,8 +152,7 @@ void GuitarGraph::drumHit(double time, int fret) {
void GuitarGraph::guitarPlay(double time, input::Event const& ev) {
bool picked = (ev.type == input::Event::PICK);
bool const* frets = ev.pressed; // Kinda b0rked, FIXME
- if (!picked && m_hammerReady.get() < 0.5) return; // Hammering not possible at the moment
- m_hammerReady.setTarget(0.0);
+ if (!picked && m_correctness.get() < 0.5) return; // Hammering not possible at the moment
// Find any suitable note within the tolerance
double tolerance = maxTolerance;
Chords::iterator best = m_chords.end();
@@ -173,7 +176,7 @@ void GuitarGraph::guitarPlay(double time, input::Event const& ev) {
std::cout << "MISS" << std::endl;
if (picked) {
m_score -= 50;
- m_hammerReady.setTarget(0.0, true); // Instantly go to zero
+ m_correctness.setTarget(0.0, true); // Instantly go to zero
}
} else {
m_chordIt = best;
@@ -185,7 +188,7 @@ void GuitarGraph::guitarPlay(double time, input::Event const& ev) {
std::cout << ", new score = " << score << std::endl;
m_chordIt->status = 1 + picked;
m_score += score;
- m_hammerReady.setTarget(1.0, true); // Instantly go to one
+ m_correctness.setTarget(1.0, true); // Instantly go to one
}
}
@@ -197,6 +200,11 @@ void GuitarGraph::difficultyAuto() {
bool GuitarGraph::difficulty(Difficulty level) {
m_track %= m_tracks.size();
Track const& track = *m_tracks[m_track];
+ // Find the stream number
+ for (m_stream = 0; m_stream < m_song.tracks.size(); ++m_stream) {
+ if (&track == &m_song.tracks[m_stream]) break;
+ }
+ // Check if the difficulty level is available
uint8_t basepitch = diffv[level].basepitch;
NoteMap const& nm = track.nm;
int fail = 0;
@@ -224,7 +232,6 @@ glutil::Color const& GuitarGraph::color(int fret) const {
}
void GuitarGraph::draw(double time) {
- engine(time);
Dimensions dimensions(1.0); // FIXME: bogus aspect ratio (is this fixable?)
dimensions.screenBottom().middle(m_cx.get()).fixedWidth(m_width.get());
glutil::PushMatrixMode pmm(GL_PROJECTION);
@@ -298,7 +305,7 @@ void GuitarGraph::draw(double time) {
m_button.dimensions.center(time2y(tBeg)).middle(x);
m_button.draw();
if (it->tappable) {
- float l = std::max(0.5, m_hammerReady.get());
+ float l = std::max(0.5, m_correctness.get());
glColor3f(l, l, l);
m_tap.dimensions = m_button.dimensions;
m_tap.draw();
diff --git a/game/guitargraph.hh b/game/guitargraph.hh
index 6a8082e..67924a5 100644
--- a/game/guitargraph.hh
+++ b/game/guitargraph.hh
@@ -52,9 +52,11 @@ class GuitarGraph {
* @param time at which time to draw
*/
void draw(double time);
- void engine(double time);
+ void engine(Audio& audio);
void position(double cx, double width) { m_cx.setTarget(cx); m_width.setTarget(width); }
double dead(double time) const { return time > -0.5 && m_dead > 10; }
+ unsigned stream() const { return m_stream; }
+ double correctness() const { return m_correctness.get(); }
private:
input::InputDev m_input;
Song const& m_song;
@@ -65,6 +67,7 @@ class GuitarGraph {
bool m_drums;
AnimValue m_cx, m_width;
unsigned m_track;
+ std::size_t m_stream;
std::vector<Track const*> m_tracks;
void drumHit(double time, int pad);
void guitarPlay(double time, input::Event const& ev);
@@ -87,7 +90,7 @@ class GuitarGraph {
Chords::iterator m_chordIt;
typedef std::map<Duration const*, int> NoteStatus;
NoteStatus m_notes;
- AnimValue m_hammerReady;
+ AnimValue m_correctness;
int m_score;
};
diff --git a/game/screen_sing.cc b/game/screen_sing.cc
index ad4444f..17956e8 100644
--- a/game/screen_sing.cc
+++ b/game/screen_sing.cc
@@ -51,7 +51,22 @@ void ScreenSing::instrumentLayout(double time) {
for (Instruments::size_type i = 0, s = m_instruments.size(); i < s; ++i) {
m_instruments[i].position((0.5 + i - 0.5 * s) * iw, iw);
}
- for (Instruments::iterator it = m_instruments.begin(); it != m_instruments.end(); ++it) it->draw(time);
+ typedef std::pair<unsigned, double> CountSum;
+ std::map<unsigned, CountSum> volume; // stream number to (count, sum)
+ for (Instruments::iterator it = m_instruments.begin(); it != m_instruments.end(); ++it) {
+ it->engine(m_audio);
+ CountSum& cs = volume[it->stream() + 1];
+ cs.first++;
+ cs.second += it->correctness();
+ it->draw(time);
+ }
+ // Set volume levels (averages of all instruments playing that track)
+ for (std::size_t i = 0, s = m_song->music.size(); i < s; ++i) {
+ double level = 1.0;
+ CountSum cs = volume[i];
+ if (cs.first > 0) level = cs.second / cs.first;
+ m_audio.streamFade(i, level); // +1 because 0 is bg
+ }
}
void ScreenSing::exit() {
|