|
From: Lasse Kärkkäi. <tr...@us...> - 2009-07-21 14:30:24
|
Module: performous
Branch: master
Commit: 59208e93b7036b21e0b99bac873cdf3db6c02bb8
Author: Lasse Karkkainen <tro...@tr...>
Date: Tue Jul 21 03:52:09 2009 +0300
Adding mixer interface to libda.
Broke compatibility with older versions because callbacks now return bool instead of void. Return true to keep the old behavior.
---
game/audio.cc | 15 +++---
game/audio.hh | 4 +-
game/record.hh | 3 +-
libs/libda/include/libda/audio.hpp | 16 ++++---
libs/libda/include/libda/mixer.hpp | 93 ++++++++++++++++++++++++++++++++++++
5 files changed, 114 insertions(+), 17 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index b49e06f..8c830e2 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -27,11 +27,11 @@ void Audio::open(std::string const& pdev, std::size_t rate, std::size_t frames)
m_playback.reset(new da::playback(m_rs));
}
-void Audio::operator()(da::pcm_data& areas, da::settings const&) {
+bool Audio::operator()(da::pcm_data& areas, da::settings const&) {
boost::recursive_mutex::scoped_lock l(m_mutex);
std::size_t samples = areas.channels * areas.frames;
static double phase = 0.0;
- std::fill(areas.m_buf, areas.m_buf + samples, 0.0f);
+ std::fill(areas.rawbuf, areas.rawbuf + samples, 0.0f);
if (!m_paused) {
if(m_need_resync) {
std::cout << "Audio need to be synched here" << std::endl;
@@ -61,13 +61,13 @@ void Audio::operator()(da::pcm_data& areas, da::settings const&) {
m_need_resync = false;
}
for (Streams::iterator it = m_streams.begin(); it != m_streams.end();) {
- it->playmix(areas.m_buf, samples);
+ it->playmix(areas.rawbuf, samples);
if (it->fade <= 0.0) { it = m_streams.erase(it); continue; }
++it;
}
}
for (boost::ptr_map<std::string, AudioSample>::iterator it = m_samples.begin(); it != m_samples.end();++it) {
- it->second->playmix(areas.m_buf, samples);
+ it->second->playmix(areas.rawbuf, samples);
}
// Synthesize tones
Notes const* n = m_notes;
@@ -75,8 +75,8 @@ void Audio::operator()(da::pcm_data& areas, da::settings const&) {
double t = getPosition();
Notes::const_iterator it = n->begin();
while (it != n->end() && it->end < t) ++it;
- for (size_t i = 0; i < samples; ++i) areas.m_buf[i] *= 0.3; // Decrease music volume
- if (it == n->end() || it->type == Note::SLEEP || it->begin > t) { phase = 0.0; return; }
+ for (size_t i = 0; i < samples; ++i) areas.rawbuf[i] *= 0.3; // Decrease music volume
+ if (it == n->end() || it->type == Note::SLEEP || it->begin > t) { phase = 0.0; return true; }
int n = it->note % 12;
double d = (n + 1) / 13.0;
double freq = MusicalScale().getNoteFreq(n + 12);
@@ -87,9 +87,10 @@ void Audio::operator()(da::pcm_data& areas, da::settings const&) {
value = d * 0.2 * std::sin(phase) + 0.2 * std::sin(2 * phase) + (1.0 - d) * 0.2 * std::sin(4 * phase);
phase += 2.0 * M_PI * freq / m_rs.rate();
}
- areas.m_buf[i] += value;
+ areas.rawbuf[i] += value;
}
}
+ return true;
}
void Audio::playMusic(std::vector<std::string> const& filenames, bool preview, double fadeTime, double startPos) {
diff --git a/game/audio.hh b/game/audio.hh
index 93d5917..76fc877 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -9,7 +9,7 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/recursive_mutex.hpp>
-#include <libda/audio.hpp>
+#include <libda/mixer.hpp>
using boost::int16_t;
@@ -162,7 +162,7 @@ class Audio {
double getPosition() const;
void operator()(); ///< Thread runs here, don't call directly
/// callback for the audio backend (libda)
- void operator()(da::pcm_data& areas, da::settings const&);
+ bool operator()(da::pcm_data& areas, da::settings const&);
/// pauses and unpauses playback
void togglePause() { m_paused = !m_paused; }
/// toggles synth playback (F4)
diff --git a/game/record.hh b/game/record.hh
index fe72f14..bc2f6dd 100644
--- a/game/record.hh
+++ b/game/record.hh
@@ -22,10 +22,11 @@ class Capture {
if (c.m_analyzers.size() < 4) c.m_analyzers.push_back(m_channels[ch] = new Analyzer(m_settings.rate()));
}
}
- void operator()(da::pcm_data& areas, da::settings const&) {
+ bool operator()(da::pcm_data& areas, da::settings const&) {
for(std::size_t ch = 0; ch < m_channels.size(); ++ch) {
if (m_channels[ch]) m_channels[ch]->input(areas.begin(ch), areas.end(ch));
}
+ return true;
}
}; // Device
boost::ptr_vector<Analyzer> m_analyzers; // This must come before the devices for correct destruction order
diff --git a/libs/libda/include/libda/audio.hpp b/libs/libda/include/libda/audio.hpp
index 52f3c4a..782ca8a 100644
--- a/libs/libda/include/libda/audio.hpp
+++ b/libs/libda/include/libda/audio.hpp
@@ -41,12 +41,12 @@ namespace da {
/** Provides various access iterators to a multich interleaved sample buffer. **/
class pcm_data {
public:
- sample_t* m_buf;
+ sample_t* rawbuf;
const std::size_t frames;
const std::size_t channels;
- pcm_data(sample_t* buf, std::size_t _frames, std::size_t _channels): m_buf(buf), frames(_frames), channels(_channels) {}
- sample_t& operator()(std::size_t frame, std::size_t channel) { return m_buf[frame * channels + channel]; }
- sample_t& operator[](std::size_t idx) { return m_buf[idx]; }
+ pcm_data(sample_t* buf, std::size_t _frames, std::size_t _channels): rawbuf(buf), frames(_frames), channels(_channels) {}
+ sample_t& operator()(std::size_t frame, std::size_t channel) { return rawbuf[frame * channels + channel]; }
+ sample_t& operator[](std::size_t idx) { return rawbuf[idx]; }
class iter_by_ch: public std::iterator<std::random_access_iterator_tag, sample_t> {
sample_t* m_buf;
std::size_t m_pos;
@@ -60,13 +60,15 @@ namespace da {
std::ptrdiff_t operator-(iter_by_ch const& rhs) const { return (m_pos - rhs.m_pos) / m_channels; }
// TODO: more operators
};
- iter_by_ch begin(std::size_t ch) { return iter_by_ch(m_buf, ch, channels); }
- iter_by_ch end(std::size_t ch) { return iter_by_ch(m_buf, ch, channels) + frames; }
+ iter_by_ch begin(std::size_t ch) { return iter_by_ch(rawbuf, ch, channels); }
+ iter_by_ch end(std::size_t ch) { return iter_by_ch(rawbuf, ch, channels) + frames; }
};
struct settings;
class pcm_data;
- typedef boost::function<void (pcm_data& it, settings const&)> callback_t;
+
+ /** The callback functor typedef. If the function returns false, it will be removed from the processing chain. **/
+ typedef boost::function<bool (pcm_data& it, settings const&)> callback_t;
struct settings {
static const std::size_t low;
diff --git a/libs/libda/include/libda/mixer.hpp b/libs/libda/include/libda/mixer.hpp
new file mode 100644
index 0000000..d502a7e
--- /dev/null
+++ b/libs/libda/include/libda/mixer.hpp
@@ -0,0 +1,93 @@
+#ifndef LIBDA_MIXER_HPP_INCLUDED
+#define LIBDA_MIXER_HPP_INCLUDED
+
+/**
+@file mixer.hpp LibDA mixer interface.
+
+Link with libda when you use this.
+**/
+
+#include "audio.hpp"
+#include <boost/scoped_ptr.hpp>
+#include <algorithm>
+
+namespace da {
+
+ template <typename T> class shared_reference_wrapper {
+ public:
+ explicit shared_reference_wrapper(boost::shared_ptr<T>& ptr): m_ptr(ptr) {}
+ operator T&() const { return *m_ptr; }
+ private:
+ boost::shared_ptr<T> m_ptr;
+ };
+
+ template <typename T> shared_reference_wrapper<T> shared_ref(boost::shared_ptr<T>& ptr) {
+ return shared_reference_wrapper<T>(ptr);
+ }
+
+ class chain {
+ public:
+ chain() {}
+ chain(callback_t const& cb): streams(1, cb) {}
+ typedef std::vector<callback_t> streams_t;
+ streams_t streams;
+ bool operator()(pcm_data& data, settings const& s) {
+ streams_t::iterator wr = streams.begin();
+ for (streams_t::iterator it = wr; it != streams.end(); ++it) {
+ if ((*it)(data, s)) *wr++ = *it;
+ }
+ streams.erase(wr);
+ return !streams.empty();
+ }
+ private:
+ };
+
+ namespace {
+ bool zero(pcm_data& data, settings const&) {
+ std::fill(data.rawbuf, data.rawbuf + (data.channels * data.frames), 0.0f);
+ return true;
+ }
+ }
+
+ class buffer {
+ public:
+ explicit buffer(size_t s): m_data(s) {}
+ sample_t* begin() { return &m_data[0]; }
+ sample_t* end() { return begin() + m_data.size(); }
+ private:
+ std::vector<sample_t> m_data;
+ };
+
+ class stream {
+ public:
+ bool operator()(pcm_data& data, settings const&) {
+ sample_t* b = m_buffer->begin();
+ sample_t* e = m_buffer->end();
+ size_t size = std::min(data.frames * data.channels, e - b - m_bufferpos);
+ for (size_t i = 0; i < size; ++i) {
+ data.rawbuf[i] = b[m_bufferpos++];
+ }
+ return true;
+ }
+ private:
+ uint64_t m_streampos;
+ boost::shared_ptr<buffer> m_buffer;
+ size_t m_bufferpos;
+ };
+
+ class mixer {
+ public:
+ mixer(settings s = settings()):
+ m_chain(zero),
+ m_settings(s.set_callback(m_chain)),
+ m_playback(m_settings)
+ {}
+ private:
+ chain m_chain;
+ settings m_settings;
+ playback m_playback;
+ };
+}
+
+#endif
+
|