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...> - 2010-08-12 22:45:21
|
Module: performous Branch: master Commit: 395e40fc605c707dbcc2cb9bb28260c5c458028f Author: Tapio Vierros <tap...@gm...> Date: Thu Jul 22 18:31:24 2010 +0300 Merge branch 'master' into portaudio --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:18
|
Module: performous
Branch: master
Commit: b068521bce1700d3a5fdaedd142d64e89d344e4d
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 22:50:44 2010 +0300
Audio config cleanup (removed in= setting) and simple support for mic assignments.
---
data/schema.xml | 6 +++---
game/audio.cc | 33 ++++++++++++++++++---------------
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index 26ebb9f..1c293f8 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -179,9 +179,9 @@ to save the current settings to XML.
</locale>
</entry>
<entry name="audio/devices" type="string_list">
- <stringvalue>in=2 dev="default" mics="blue,red"</stringvalue><!-- SingStar mics -->
- <stringvalue>in=1 dev="Microphone"</stringvalue><!-- Rock Band branded Logitech mic -->
- <stringvalue>in=1</stringvalue><!-- Any other microphone -->
+ <stringvalue>dev="USBMIC" mics="blue,red"</stringvalue><!-- SingStar mics -->
+ <stringvalue>dev="Microphone" mics="*"</stringvalue><!-- Rock Band branded Logitech mic -->
+ <stringvalue>mics="blue"</stringvalue><!-- Any other microphone (only if blue is still free) -->
<stringvalue>out=2</stringvalue><!-- Any stereo output device -->
<locale name="C">
<short>Audio devices</short>
diff --git a/game/audio.cc b/game/audio.cc
index d29cebd..27c499a 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -298,16 +298,15 @@ struct Audio::Impl {
boost::ptr_vector<Analyzer> analyzers;
bool playback;
Impl(): playback() {
- int mic_count = 0;
// Parse audio devices from config
ConfigItem::StringList devs = config["audio/devices"].sl();
for (ConfigItem::StringList::const_iterator it = devs.begin(), end = devs.end(); it != end; ++it) {
try {
struct Params {
- int in, out;
+ int out;
unsigned int rate;
std::string dev;
- std::vector<int> mics;
+ std::vector<std::string> mics;
} params = Params();
params.rate = 48000;
// Break into tokens:
@@ -318,14 +317,11 @@ struct Audio::Impl {
std::string key = it2->first;
std::istringstream iss(it2->second);
if (key == "out") iss >> params.out;
- else if (key == "in") iss >> params.in;
else if (key == "rate") iss >> params.rate;
else if (key == "dev") std::getline(iss, params.dev);
else if (key == "mics") {
// Parse a comma-separated list of mics
- for (std::string mic; std::getline(iss, mic, ','); ) {
- params.mics.push_back(0); // TODO/FIXME: implement
- }
+ for (std::string mic; std::getline(iss, mic, ','); params.mics.push_back(mic)) {}
}
else throw std::runtime_error("Unknown device parameter " + key);
if (!iss.eof()) throw std::runtime_error("Syntax error parsing device parameter " + key);
@@ -333,7 +329,7 @@ struct Audio::Impl {
int count = Pa_GetDeviceCount();
int dev = -1;
// Handle empty device
- if (params.dev.empty()) dev = params.in ? Pa_GetDefaultInputDevice() : Pa_GetDefaultOutputDevice();
+ if (params.dev.empty()) dev = (params.out == 0 ? Pa_GetDefaultInputDevice() : Pa_GetDefaultOutputDevice());
// Try numeric value
if (dev < 0) {
std::istringstream iss(params.dev);
@@ -344,31 +340,38 @@ struct Audio::Impl {
bool found = false;
// Try exact match first, then partial
for (int match_partial = 0; match_partial < 2 && !skip_partial; ++match_partial) {
- // Loop through the devices and try everyting that matches the name
+ // Loop through the devices and try everything that matches the name
for (int i = -1; i < count && (dev < 0 || i == -1); ++i) {
if (dev > 0 && i == -1) i = dev;
else if (i == -1) continue;
PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
if (!info) continue;
- if (params.in && info->maxInputChannels == 0) continue;
- if (params.out && info->maxOutputChannels == 0) continue;
+ if (info->maxInputChannels < int(params.mics.size())) continue;
+ if (info->maxOutputChannels < params.out) continue;
if (!match_partial && info->name != params.dev) continue;
if (match_partial && std::string(info->name).find(params.dev) == std::string::npos) continue;
// Match found if we got here
bool device_init_threw = true;
try {
- devices.push_back(new Device(params.in, params.out, params.rate, i));
+ devices.push_back(new Device(params.mics.size(), params.out, params.rate, i));
Device& d = devices.back();
device_init_threw = false;
// Start capture/playback on this device
d.start();
- // Assign mics for all channels of the device (TODO: proper assignments)
+ // Assign mics for all channels of the device
for (unsigned int j = 0; j < d.in; ++j) {
- if (mic_count + 1 > 4) break; // Too many mics
+ if (analyzers.size() >= 4) break; // Too many mics
+ std::string const& m = params.mics[j];
+ if (m.empty()) continue; // Input channel not used
+ // TODO: allow assignment in any order (not sequentially like the following code does)
+ if (m == "blue" && analyzers.size() != 0) continue;
+ if (m == "red" && analyzers.size() != 1) continue;
+ if (m == "green" && analyzers.size() != 2) continue;
+ if (m == "orange" && analyzers.size() != 3) continue;
+ // Add the new analyzer
Analyzer* a = new Analyzer(d.rate);
analyzers.push_back(a);
d.mics[j] = a;
- mic_count++;
}
// Assign playback output for the first available stereo output
if (!playback && d.out == 2) { d.outptr = &output; playback = true; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:15
|
Module: performous
Branch: master
Commit: f17a382e841b283ce7bad5bc09aef1141abe17d3
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 20:43:16 2010 +0300
Device string matching moved to audio.cc, also try until working one is found.
---
game/audio.cc | 78 ++++++++++++++++++++++++--------
libs/libda/include/libda/portaudio.hpp | 39 ----------------
2 files changed, 59 insertions(+), 58 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 4c9ccd5..d29cebd 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -5,6 +5,7 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/thread/mutex.hpp>
+#include <boost/lexical_cast.hpp>
#include <libda/fft.hpp> // For M_PI
#include <libda/portaudio.hpp>
#include <cmath>
@@ -254,14 +255,14 @@ struct Device {
// Init
const unsigned int in, out;
const double rate;
- const std::string dev;
+ const unsigned int dev;
portaudio::Stream stream;
std::vector<Analyzer*> mics;
Output* outptr;
- Device(unsigned int in, unsigned int out, double rate, std::string dev):
+ Device(unsigned int in, unsigned int out, double rate, unsigned int dev):
in(in), out(out), rate(rate), dev(dev),
- stream(*this, in ? portaudio::Params().channelCount(in).device(dev, true) : (const PaStreamParameters*)NULL, (out ? portaudio::Params().channelCount(out).device(dev, false) : (const PaStreamParameters*)NULL), rate),
+ stream(*this, in ? portaudio::Params().channelCount(in).device(dev) : (const PaStreamParameters*)NULL, (out ? portaudio::Params().channelCount(out).device(dev) : (const PaStreamParameters*)NULL), rate),
outptr()
{
mics.resize(in);
@@ -269,7 +270,8 @@ struct Device {
void start() {
PaError err = Pa_StartStream(stream);
- if (err != paNoError) throw std::runtime_error("Cannot start PortAudio audio stream " + dev + ": " + Pa_GetErrorText(err));
+ if (err != paNoError) throw std::runtime_error("Cannot start PortAudio audio stream "
+ + boost::lexical_cast<std::string>(dev) + ": " + Pa_GetErrorText(err));
}
int operator()(void const* input, void* output, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags) try {
@@ -288,6 +290,7 @@ struct Device {
}
};
+
struct Audio::Impl {
Output output;
portaudio::Init init;
@@ -327,23 +330,60 @@ struct Audio::Impl {
else throw std::runtime_error("Unknown device parameter " + key);
if (!iss.eof()) throw std::runtime_error("Syntax error parsing device parameter " + key);
}
- devices.push_back(new Device(params.in, params.out, params.rate, params.dev));
- Device& d = devices.back();
- // Assign mics for all channels of the device (TODO: proper assignments)
- for (unsigned int i = 0; i < d.in; ++i) {
- if (mic_count + i + 1 > 4) break; // Too many mics
- Analyzer* a = new Analyzer(d.rate);
- analyzers.push_back(a);
- d.mics[i] = a;
+ int count = Pa_GetDeviceCount();
+ int dev = -1;
+ // Handle empty device
+ if (params.dev.empty()) dev = params.in ? Pa_GetDefaultInputDevice() : Pa_GetDefaultOutputDevice();
+ // Try numeric value
+ if (dev < 0) {
+ std::istringstream iss(params.dev);
+ int tmp;
+ if (iss >> tmp && iss.get() == EOF && tmp >= 0 && tmp < count) dev = tmp;
}
- // Assign playback output for the first available stereo output
- if (!playback && d.out == 2) {
- d.outptr = &output;
- playback = true;
+ bool skip_partial = false;
+ bool found = false;
+ // Try exact match first, then partial
+ for (int match_partial = 0; match_partial < 2 && !skip_partial; ++match_partial) {
+ // Loop through the devices and try everyting that matches the name
+ for (int i = -1; i < count && (dev < 0 || i == -1); ++i) {
+ if (dev > 0 && i == -1) i = dev;
+ else if (i == -1) continue;
+ PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
+ if (!info) continue;
+ if (params.in && info->maxInputChannels == 0) continue;
+ if (params.out && info->maxOutputChannels == 0) continue;
+ if (!match_partial && info->name != params.dev) continue;
+ if (match_partial && std::string(info->name).find(params.dev) == std::string::npos) continue;
+ // Match found if we got here
+ bool device_init_threw = true;
+ try {
+ devices.push_back(new Device(params.in, params.out, params.rate, i));
+ Device& d = devices.back();
+ device_init_threw = false;
+ // Start capture/playback on this device
+ d.start();
+ // Assign mics for all channels of the device (TODO: proper assignments)
+ for (unsigned int j = 0; j < d.in; ++j) {
+ if (mic_count + 1 > 4) break; // Too many mics
+ Analyzer* a = new Analyzer(d.rate);
+ analyzers.push_back(a);
+ d.mics[j] = a;
+ mic_count++;
+ }
+ // Assign playback output for the first available stereo output
+ if (!playback && d.out == 2) { d.outptr = &output; playback = true; }
+ } catch (...) {
+ if (!device_init_threw) devices.pop_back();
+ if (dev > 0) { skip_partial = true; break; } // Numeric, end search
+ continue;
+ }
+ skip_partial = true;
+ found = true;
+ break;
+ }
}
- // Start capture/playback on this device
- d.start();
- mic_count += d.in;
+ // Error handling
+ if (!found) throw std::runtime_error("Not found or already in use.");
} catch(std::runtime_error& e) {
std::cerr << "Audio device '" << *it << "': " << e.what() << std::endl;
}
diff --git a/libs/libda/include/libda/portaudio.hpp b/libs/libda/include/libda/portaudio.hpp
index cf0775f..fb2a575 100644
--- a/libs/libda/include/libda/portaudio.hpp
+++ b/libs/libda/include/libda/portaudio.hpp
@@ -48,45 +48,6 @@ namespace portaudio {
}
Params& channelCount(int val) { params.channelCount = val; return *this; }
Params& device(PaDeviceIndex val) { params.device = val; return *this; }
- Params& device(std::string const& name, bool inputDevice) {
- static std::vector<bool> used_devices(Pa_GetDeviceCount(), false);
- int count = Pa_GetDeviceCount();
- int val = -1;
- if (name.empty()) val = inputDevice ? Pa_GetDefaultInputDevice() : Pa_GetDefaultOutputDevice();
- if (val >= 0 && used_devices.at(val)) val = -1; // Don't use default device if it is already in use
- // Try numeric value
- if (val < 0) {
- std::istringstream iss(name);
- int tmp;
- if (iss >> tmp && iss.get() == EOF && tmp >= 0 && tmp < count && !used_devices.at(tmp)) val = tmp;
- }
- // Try matching exact name
- if (val < 0) for (int i = 0; i != count; ++i) {
- if (used_devices.at(i)) continue;
- PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
- if (!info) continue;
- if (inputDevice && info->maxInputChannels == 0) continue;
- if (!inputDevice && info->maxOutputChannels == 0) continue;
- if (info->name == name) { val = i; break; }
- }
- // Try matching partial name
- if (val < 0) for (int i = 0; i != count; ++i) {
- if (used_devices.at(i)) continue;
- PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
- if (!info) continue;
- if (inputDevice && info->maxInputChannels == 0) continue;
- if (!inputDevice && info->maxOutputChannels == 0) continue;
- if (std::string(info->name).find(name) != std::string::npos) { val = i; break; }
- }
- // Error handling
- std::string dir = inputDevice ? "input" : "output";
- if (val < 0) throw std::runtime_error(name.empty() ? "No PortAudio default " + dir + " device found" : "No matching PortAudio " + dir + " device (" + name + ") found");
- PaDeviceInfo const* info = Pa_GetDeviceInfo(val);
- if (!info) throw std::runtime_error("The specified " + dir + " device (" + name + ") does not exist."); // FIXME: When does this happen?
- if ((inputDevice ? info->maxInputChannels : info->maxOutputChannels) == 0) throw std::runtime_error("The PortAudio " + dir + " device specified (" + name + ") has no " + dir + " channels");
- // Set the device
- return device(val);
- }
Params& sampleFormat(PaSampleFormat val) { params.sampleFormat = val; return *this; }
Params& suggestedLatency(PaTime val) { params.suggestedLatency = val; return *this; }
Params& hostApiSpecificStreamInfo(void* val) { params.hostApiSpecificStreamInfo = val; return *this; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:12
|
Module: performous
Branch: master
Commit: 1bf5c55883193d8f6d1e573e7ba28cb45846006e
Author: Vincent Le Ligeour <yo...@us...>
Date: Sun Jul 18 18:38:25 2010 +0200
Disabled synth on stop and fade out
---
game/audio.cc | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 458ee35..4c9ccd5 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -395,11 +395,23 @@ void Audio::playMusic(std::string const& filename, bool preview, double fadeTime
void Audio::stopMusic() {
std::map<std::string,std::string> m;
playMusic(m, false, 0.0);
+ {
+ Output& o = self->output;
+ // stop synth when music is stopped
+ boost::mutex::scoped_lock l(o.synth_mutex);
+ o.synth.reset();
+ }
}
void Audio::fadeout(double fadeTime) {
std::map<std::string,std::string> m;
playMusic(m, false, fadeTime);
+ {
+ Output& o = self->output;
+ // stop synth when music is stopped
+ boost::mutex::scoped_lock l(o.synth_mutex);
+ o.synth.reset();
+ }
}
double Audio::getPosition() const {
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:11
|
Module: performous
Branch: master
Commit: e94fa6f85f83b4490ec5a6873e5a4d8d38277677
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 16:45:32 2010 +0300
Allow spaces before key start in key=value parser.
---
game/audio.cc | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 3d34946..b92264f 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -29,11 +29,11 @@ namespace {
continue;
}
// Space in key (bad)
- if (st[i] == ' ' && parsing_key)
- throw std::logic_error("Error: Space in key in string: " + st);
+ if (st[i] == ' ' && parsing_key && !key.empty())
+ throw std::logic_error("Space in key in string: " + st);
// Value start
if (st[i] == '=' && !inside_quotes) {
- if (key.empty()) throw std::logic_error("Error: Empty key in string: " + st);
+ if (key.empty()) throw std::logic_error("Empty key in string: " + st);
parsing_key = false;
continue;
}
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:10
|
Module: performous
Branch: master
Commit: 07e9e2fa72fc060cf47a0bfc4476b26052689e17
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 19:08:15 2010 +0300
Implement sample iterators and multichannel capture
---
game/audio.cc | 9 +++++----
libs/libda/include/libda/sample.hpp | 16 ++++++++++++++++
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index b92e325..458ee35 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -273,13 +273,14 @@ struct Device {
}
int operator()(void const* input, void* output, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags) try {
- float const* in = static_cast<float const*>(input);
- float* out = static_cast<float*>(output);
+ float const* inbuf = static_cast<float const*>(input);
+ float* outbuf = static_cast<float*>(output);
for (std::size_t i = 0; i < mics.size(); ++i) {
if (!mics[i]) continue; // No analyzer? -> Channel not used
- mics[i]->input(in, in + 1 * frames); // FIXME: needs libda iterators for multiple channel support
+ da::sample_const_iterator it = da::sample_const_iterator(inbuf + i, in);
+ mics[i]->input(it, it + frames);
}
- if (outptr) outptr->callback(out, out + 2 * frames);
+ if (outptr) outptr->callback(outbuf, outbuf + 2 * frames);
return paContinue;
} catch (std::exception& e) {
std::cerr << "Exception in audio callback: " << e.what() << std::endl;
diff --git a/libs/libda/include/libda/sample.hpp b/libs/libda/include/libda/sample.hpp
index 58502e0..29383e7 100644
--- a/libs/libda/include/libda/sample.hpp
+++ b/libs/libda/include/libda/sample.hpp
@@ -49,6 +49,22 @@ namespace da {
static inline int conv_to_s16_fast(sample_t s) { return static_cast<int>(s * max_s16); }
static inline int conv_to_s24_fast(sample_t s) { return static_cast<int>(s * max_s24); }
static inline int conv_to_s32_fast(sample_t s) { return static_cast<int>(s * max_s32); }
+
+ template <typename ValueType> class step_iterator: public std::iterator<std::random_access_iterator_tag, ValueType> {
+ ValueType* m_pos;
+ std::ptrdiff_t m_step;
+ public:
+ step_iterator(ValueType* pos, std::ptrdiff_t step): m_pos(pos), m_step(step) {}
+ ValueType& operator*() { return *m_pos; }
+ step_iterator operator+(std::ptrdiff_t rhs) { return step_iterator(m_pos + m_step * rhs, m_step); }
+ step_iterator& operator++() { m_pos += m_step; return *this; }
+ bool operator!=(step_iterator const& rhs) const { return m_pos != rhs.m_pos; }
+ std::ptrdiff_t operator-(step_iterator const& rhs) const { return (m_pos - rhs.m_pos) / m_step; }
+ // TODO: more operators
+ };
+
+ typedef step_iterator<sample_t> sample_iterator;
+ typedef step_iterator<sample_t const> sample_const_iterator;
}
#endif
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:09
|
Module: performous
Branch: master
Commit: 89d958378a472a339bf38db6c2ff6a81ec5c7451
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 17:05:09 2010 +0300
Audio device matching by name, first exact, then if not found, partial.
---
libs/libda/include/libda/portaudio.hpp | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/libs/libda/include/libda/portaudio.hpp b/libs/libda/include/libda/portaudio.hpp
index d6e33b1..c1ab993 100644
--- a/libs/libda/include/libda/portaudio.hpp
+++ b/libs/libda/include/libda/portaudio.hpp
@@ -58,14 +58,21 @@ namespace portaudio {
int tmp;
if (iss >> tmp && iss.get() == EOF && tmp >= 0 && tmp < count) val = tmp;
}
- // Try name matching
+ // Try matching exact name
if (val < 0) for (int i = 0; i != count; ++i) {
PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
if (!info) continue;
if (inputDevice && info->maxInputChannels == 0) continue;
if (!inputDevice && info->maxOutputChannels == 0) continue;
- val = i;
- break;
+ if (info->name == name) { val = i; break; }
+ }
+ // Try matching partial name
+ if (val < 0) for (int i = 0; i != count; ++i) {
+ PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
+ if (!info) continue;
+ if (inputDevice && info->maxInputChannels == 0) continue;
+ if (!inputDevice && info->maxOutputChannels == 0) continue;
+ if (std::string(info->name).find(name) != std::string::npos) { val = i; break; }
}
// Error handling
std::string dir = inputDevice ? "input" : "output";
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:09
|
Module: performous
Branch: master
Commit: 10510c64c4bed76a1b7c4a3c3cdb5087625c0164
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 16:42:05 2010 +0300
Parse quoted strings.
---
game/audio.cc | 64 +++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 3d85777..3d34946 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -9,6 +9,45 @@
#include <libda/portaudio.hpp>
#include <cmath>
#include <iostream>
+#include <map>
+
+namespace {
+ std::map<std::string, std::string> parseKeyValuePairs(const std::string& st) {
+ std::map<std::string, std::string> ret;
+ bool inside_quotes = false;
+ int parsing_key = true;
+ std::string key = "", value = "";
+ for (size_t i = 0; i < st.size(); ++i) {
+ // Quotes
+ if (st[i] == '"') { inside_quotes = !inside_quotes; continue; }
+ // Value end
+ if (st[i] == ' ' && !inside_quotes && !parsing_key) {
+ if (value.empty()) continue; // Skip whitespace after equals sign
+ ret[key] = value;
+ key = ""; value = "";
+ parsing_key = true;
+ continue;
+ }
+ // Space in key (bad)
+ if (st[i] == ' ' && parsing_key)
+ throw std::logic_error("Error: Space in key in string: " + st);
+ // Value start
+ if (st[i] == '=' && !inside_quotes) {
+ if (key.empty()) throw std::logic_error("Error: Empty key in string: " + st);
+ parsing_key = false;
+ continue;
+ }
+ // Key start
+ if (st[i] != ' ' && parsing_key) { key += st[i]; continue; }
+ // If we got here, it is value
+ value += st[i];
+ }
+ // Handle last key
+ if (!key.empty()) ret[key] = value;
+ return ret;
+ }
+}
+
class Music {
struct Track {
@@ -267,25 +306,24 @@ struct Audio::Impl {
} params = Params();
params.rate = 48000;
// Break into tokens:
- std::istringstream iss(*it);
- for (std::string token; std::getline(iss, token, ' '); ) {
- // Parse key=value
- std::istringstream iss2(token);
- std::string key;
- std::getline(iss2, key, '=');
- if (key == "out") iss2 >> params.out;
- else if (key == "in") iss2 >> params.in;
- else if (key == "rate") iss2 >> params.rate;
- else if (key == "dev") std::getline(iss2, params.dev);
+ std::map<std::string, std::string> keyvalues = parseKeyValuePairs(*it);
+ for (std::map<std::string, std::string>::const_iterator it2 = keyvalues.begin();
+ it2 != keyvalues.end(); ++it2) {
+ // Handle keys
+ std::string key = it2->first;
+ std::istringstream iss(it2->second);
+ if (key == "out") iss >> params.out;
+ else if (key == "in") iss >> params.in;
+ else if (key == "rate") iss >> params.rate;
+ else if (key == "dev") std::getline(iss, params.dev);
else if (key == "mics") {
// Parse a comma-separated list of mics
- for (std::string mic; std::getline(iss2, mic, ','); ) {
+ for (std::string mic; std::getline(iss, mic, ','); ) {
params.mics.push_back(0); // TODO/FIXME: implement
}
-
}
else throw std::runtime_error("Unknown device parameter " + key);
- if (!iss2.eof()) throw std::runtime_error("Syntax error parsing device parameter " + key);
+ if (!iss.eof()) throw std::runtime_error("Syntax error parsing device parameter " + key);
}
devices.push_back(new Device(params.in, params.out, params.rate, params.dev));
Device& d = devices.back();
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:09
|
Module: performous
Branch: master
Commit: 23c1b6546d236b08953cb504fa88233055c25c93
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 17:55:06 2010 +0300
Only match the same device once.
---
libs/libda/include/libda/portaudio.hpp | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/libs/libda/include/libda/portaudio.hpp b/libs/libda/include/libda/portaudio.hpp
index c1ab993..cf0775f 100644
--- a/libs/libda/include/libda/portaudio.hpp
+++ b/libs/libda/include/libda/portaudio.hpp
@@ -49,17 +49,20 @@ namespace portaudio {
Params& channelCount(int val) { params.channelCount = val; return *this; }
Params& device(PaDeviceIndex val) { params.device = val; return *this; }
Params& device(std::string const& name, bool inputDevice) {
+ static std::vector<bool> used_devices(Pa_GetDeviceCount(), false);
int count = Pa_GetDeviceCount();
int val = -1;
if (name.empty()) val = inputDevice ? Pa_GetDefaultInputDevice() : Pa_GetDefaultOutputDevice();
+ if (val >= 0 && used_devices.at(val)) val = -1; // Don't use default device if it is already in use
// Try numeric value
if (val < 0) {
std::istringstream iss(name);
int tmp;
- if (iss >> tmp && iss.get() == EOF && tmp >= 0 && tmp < count) val = tmp;
+ if (iss >> tmp && iss.get() == EOF && tmp >= 0 && tmp < count && !used_devices.at(tmp)) val = tmp;
}
// Try matching exact name
if (val < 0) for (int i = 0; i != count; ++i) {
+ if (used_devices.at(i)) continue;
PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
if (!info) continue;
if (inputDevice && info->maxInputChannels == 0) continue;
@@ -68,6 +71,7 @@ namespace portaudio {
}
// Try matching partial name
if (val < 0) for (int i = 0; i != count; ++i) {
+ if (used_devices.at(i)) continue;
PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
if (!info) continue;
if (inputDevice && info->maxInputChannels == 0) continue;
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:09
|
Module: performous
Branch: master
Commit: 05aaf1dc2011ac1756fe72bb90d07cad14b360d3
Author: Tapio Vierros <tap...@gm...>
Date: Sun Jul 18 17:14:53 2010 +0300
Limit the number of mics.
---
game/audio.cc | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index b92264f..b92e325 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -294,6 +294,7 @@ struct Audio::Impl {
boost::ptr_vector<Analyzer> analyzers;
bool playback;
Impl(): playback() {
+ int mic_count = 0;
// Parse audio devices from config
ConfigItem::StringList devs = config["audio/devices"].sl();
for (ConfigItem::StringList::const_iterator it = devs.begin(), end = devs.end(); it != end; ++it) {
@@ -327,8 +328,9 @@ struct Audio::Impl {
}
devices.push_back(new Device(params.in, params.out, params.rate, params.dev));
Device& d = devices.back();
- // Assign mics for all channels of the device (TODO: proper assignments and limit the number of mics)
+ // Assign mics for all channels of the device (TODO: proper assignments)
for (unsigned int i = 0; i < d.in; ++i) {
+ if (mic_count + i + 1 > 4) break; // Too many mics
Analyzer* a = new Analyzer(d.rate);
analyzers.push_back(a);
d.mics[i] = a;
@@ -340,6 +342,7 @@ struct Audio::Impl {
}
// Start capture/playback on this device
d.start();
+ mic_count += d.in;
} catch(std::runtime_error& e) {
std::cerr << "Audio device '" << *it << "': " << e.what() << std::endl;
}
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 2661a16adb2a245da582970940c8f30387b56783
Author: Lasse Karkkainen <tro...@tr...>
Date: Wed Jun 23 08:27:59 2010 +0300
Cleanup
---
game/audio.cc | 34 ++++++++++++++++++++--------------
game/audio.hh | 5 +++--
2 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 4cd5ae4..899615a 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -13,8 +13,8 @@
class Music {
struct Track {
FFmpeg mpeg;
- float volume;
- Track(std::string const& filename, unsigned int sr): mpeg(false, true, filename, sr), volume(1.0f) {}
+ float fadeLevel;
+ Track(std::string const& filename, unsigned int sr): mpeg(false, true, filename, sr), fadeLevel(1.0f) {}
};
typedef boost::ptr_map<std::string, Track> Tracks;
Tracks tracks; ///< Audio decoders
@@ -35,7 +35,7 @@ public:
std::vector<float> mixbuf(end - begin);
for (Tracks::iterator it = tracks.begin(), itend = tracks.end(); it != itend; ++it) {
Track& t = *it->second;
- if (t.mpeg.audioQueue(&*mixbuf.begin(), &*mixbuf.end(), m_pos, t.volume)) eof = false;
+ if (t.mpeg.audioQueue(&*mixbuf.begin(), &*mixbuf.end(), m_pos, t.fadeLevel)) eof = false;
}
m_pos += end - begin;
for (size_t i = 0, iend = mixbuf.size(); i != iend; ++i) {
@@ -66,10 +66,10 @@ public:
}
return ready;
}
- void trackLevel(std::string const& id, double level) {
- Tracks::iterator it = tracks.find(id);
+ void trackFade(std::string const& name, double fadeLevel) {
+ Tracks::iterator it = tracks.find(name);
if (it == tracks.end()) return;
- it->second->volume = level;
+ it->second->fadeLevel = fadeLevel;
}
};
@@ -103,7 +103,11 @@ struct SampleNew {
};
-typedef std::pair<std::string, double> Command; ///< <stream ID, volume level>
+struct Command {
+ enum { TRACK_FADE } type;
+ std::string track;
+ double fadeLevel;
+};
struct Audio::Impl {
boost::mutex mutex;
@@ -133,9 +137,12 @@ struct Audio::Impl {
}
// Process commands
for (size_t i = 0; i < commands.size(); ++i) {
- std::string id = commands[i].first;
- double level = commands[i].second;
- if (!playing.empty()) playing[0].trackLevel(id, level);
+ Command const& cmd = commands[i];
+ switch (cmd.type) {
+ case Command::TRACK_FADE:
+ if (!playing.empty()) playing[0].trackFade(cmd.track, cmd.fadeLevel);
+ break;
+ }
}
commands.clear();
}
@@ -184,7 +191,6 @@ bool Audio::isOpen() const {
}
void Audio::loadSample(std::string streamId, std::string filename) {
- std::cout << ">>> Loading sample \"" << streamId << "\"" << std::endl;
{
boost::mutex::scoped_lock l(self->mutex);
self->samples.insert(streamId, new SampleNew(filename, getSR()));
@@ -200,7 +206,6 @@ void Audio::playSample(std::string streamId) {
}
void Audio::unloadSample(std::string streamId) {
- std::cout << ">>> Unloading sample \"" << streamId << "\"" << std::endl;
{
boost::mutex::scoped_lock l(self->mutex);
self->samples.erase(streamId);
@@ -270,9 +275,10 @@ void Audio::pause(bool state) {
bool Audio::isPaused() const { return self->paused; }
-void Audio::streamFade(std::string stream_id, double level) {
+void Audio::streamFade(std::string track, double fadeLevel) {
boost::mutex::scoped_lock l(self->mutex);
- self->commands.push_back(Command(stream_id, level));
+ Command cmd = { Command::TRACK_FADE, track, fadeLevel };
+ self->commands.push_back(cmd);
}
boost::ptr_vector<Analyzer>& Audio::analyzers() { return self->analyzers; }
diff --git a/game/audio.hh b/game/audio.hh
index cab5e4f..53ce5b2 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -54,8 +54,9 @@ public:
void togglePause() { pause(!isPaused()); }
void pause(bool state = true);
bool isPaused() const;
- void toggleSynth(Notes const& notes) { /*m_notes = (m_notes ? NULL : ¬es); */} ///< toggles synth playback
- void streamFade(std::string stream_id, double level);
+ void toggleSynth(Notes const&) { /*m_notes = (m_notes ? NULL : ¬es); */} ///< toggles synth playback
+ /// Adjust volume level of a single track (used for muting incorrectly played instruments). Range 0.0 to 1.0.
+ void streamFade(std::string track, double volume);
double getSR() const { return 48000.0; }
};
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: cb9219b0dfb92e14d7a6798a5d887e5dac149413
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 10:18:40 2010 +0300
Fix init order bug that caused segfault on Alt+F4 from singing screen
---
game/audio.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 81eec71..3d85777 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -249,10 +249,10 @@ struct Device {
};
struct Audio::Impl {
+ Output output;
portaudio::Init init;
boost::ptr_vector<Device> devices;
boost::ptr_vector<Analyzer> analyzers;
- Output output;
bool playback;
Impl(): playback() {
// Parse audio devices from config
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous Branch: master Commit: a5e395fde064c89588a393d577ace04a50ea4f11 Author: Lasse Karkkainen <tro...@tr...> Date: Sun Jul 18 09:37:44 2010 +0300 Merge branch 'master' into portaudio Conflicts: game/main.cc game/screen_intro.hh game/screen_practice.cc game/screen_practice.hh --- |
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: d28fe6660eae95b465e5f58c35d3afde8129680c
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 09:22:36 2010 +0300
Audio device configuration implemented (mostly)
---
data/schema.xml | 2 +-
game/audio.cc | 74 ++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index c41c864..26ebb9f 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -178,7 +178,7 @@ to save the current settings to XML.
<long>Affects instruments and dancing only. The total of USB (guitar or dance pad) latency combined with audio output latency. Adjust so that you can hit the notes best when playing by ear (not looking on screen). Use Ctrl+F5/F6 to adjust while performing.</long>
</locale>
</entry>
- <entry name="audio/device" type="string_list">
+ <entry name="audio/devices" type="string_list">
<stringvalue>in=2 dev="default" mics="blue,red"</stringvalue><!-- SingStar mics -->
<stringvalue>in=1 dev="Microphone"</stringvalue><!-- Rock Band branded Logitech mic -->
<stringvalue>in=1</stringvalue><!-- Any other microphone -->
diff --git a/game/audio.cc b/game/audio.cc
index 2c6a3b4..7071e50 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -213,9 +213,9 @@ struct Output {
struct Device {
// Init
- unsigned int in, out;
- double rate;
- std::string dev;
+ const unsigned int in, out;
+ const double rate;
+ const std::string dev;
portaudio::Stream stream;
std::vector<Analyzer*> mics;
Output* outptr;
@@ -236,8 +236,8 @@ struct Device {
float const* in = static_cast<float const*>(input);
float* out = static_cast<float*>(output);
for (std::size_t i = 0; i < mics.size(); ++i) {
- if (!mics[i]) continue; // Channel not used
- mics[i]->input(in, in + 1 * frames);
+ if (!mics[i]) continue; // No analyzer? -> Channel not used
+ mics[i]->input(in, in + 1 * frames); // FIXME: needs libda iterators for multiple channel support
}
if (outptr) outptr->callback(out, out + 2 * frames);
return paContinue;
@@ -253,21 +253,57 @@ struct Audio::Impl {
boost::ptr_vector<Analyzer> analyzers;
Output output;
bool playback;
- Impl() {
- devices.push_back(new Device(1, 2, 48000.0, ""));
- // One analyzer for mono input (TODO: fix callbackInput to allow more)
- analyzers.push_back(new Analyzer(48000.0));
- devices[0].mics[0] = &analyzers[0];
- playback = false;
- for (size_t i = 0; i < devices.size(); ++i) {
- Device& d = devices[i];
- // Assign playback output for the first available stereo output
- if (!playback && d.out == 2) {
- d.outptr = &output;
- playback = true;
+ Impl(): playback() {
+ // Parse audio devices from config
+ ConfigItem::StringList devs = config["audio/devices"].sl();
+ for (ConfigItem::StringList::const_iterator it = devs.begin(), end = devs.end(); it != end; ++it) {
+ try {
+ struct Params {
+ int in, out;
+ unsigned int rate;
+ std::string dev;
+ std::vector<int> mics;
+ } params = Params();
+ params.rate = 48000;
+ // Break into tokens:
+ std::istringstream iss(*it);
+ for (std::string token; std::getline(iss, token, ' '); ) {
+ // Parse key=value
+ std::istringstream iss2(token);
+ std::string key;
+ std::getline(iss2, key, '=');
+ if (key == "out") iss2 >> params.out;
+ else if (key == "in") iss2 >> params.in;
+ else if (key == "rate") iss2 >> params.rate;
+ else if (key == "dev") std::getline(iss2, params.dev);
+ else if (key == "mics") {
+ // Parse a comma-separated list of mics
+ for (std::string mic; std::getline(iss2, mic, ','); ) {
+ params.mics.push_back(0); // TODO/FIXME: implement
+ }
+
+ }
+ else throw std::runtime_error("Unknown device parameter " + key);
+ if (!iss2.eof()) throw std::runtime_error("Syntax error parsing device parameter " + key);
+ }
+ devices.push_back(new Device(params.in, params.out, params.rate, params.dev));
+ Device& d = devices.back();
+ // Assign mics for all channels of the device (TODO: proper assignments and limit the number of mics)
+ for (unsigned int i = 0; i < d.in; ++i) {
+ Analyzer* a = new Analyzer(d.rate);
+ analyzers.push_back(a);
+ d.mics[i] = a;
+ }
+ // Assign playback output for the first available stereo output
+ if (!playback && d.out == 2) {
+ d.outptr = &output;
+ playback = true;
+ }
+ // Start capture/playback on this device
+ d.start();
+ } catch(std::runtime_error& e) {
+ std::cerr << "Audio device '" << *it << "': " << e.what() << std::endl;
}
- // Start capture/playback on this device
- d.start();
}
}
};
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: aa42591f3f8fa2dfc4f072e836205f24f6774215
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 00:51:55 2010 +0300
Replace mics/pdev command line options with --audio
---
game/main.cc | 11 +++--------
1 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/game/main.cc b/game/main.cc
index f466381..a297f0d 100644
--- a/game/main.cc
+++ b/game/main.cc
@@ -254,8 +254,7 @@ int main(int argc, char** argv) try {
std::ios::sync_with_stdio(false); // We do not use C stdio
std::srand(std::time(NULL));
// Parse commandline options
- std::vector<std::string> mics;
- std::vector<std::string> pdevs;
+ std::vector<std::string> devices;
std::vector<std::string> songdirs;
namespace po = boost::program_options;
po::options_description opt1("Generic options");
@@ -266,10 +265,7 @@ int main(int argc, char** argv) try {
("songlist", po::value<std::string>(&songlist), "save a list of songs in the specified folder");
po::options_description opt2("Configuration options");
opt2.add_options()
- ("mics", po::value<std::vector<std::string> >(&mics)->composing(), "specify the microphones to use")
- ("pdev", po::value<std::vector<std::string> >(&pdevs)->composing(), "specify the playback device")
- ("michelp", "detailed help and device list for --mics")
- ("pdevhelp", "detailed help and device list for --pdev")
+ ("audio", po::value<std::vector<std::string> >(&devices)->composing(), "specify an audio device to use")
("jstest", "utility to get joystick button mappings");
po::options_description opt3("Hidden options");
opt3.add_options()
@@ -312,8 +308,7 @@ int main(int argc, char** argv) try {
}
// Override XML config for options that were specified from commandline or performous.conf
confOverride(songdirs, "system/path_songs");
- confOverride(mics, "audio/capture");
- confOverride(pdevs, "audio/playback");
+ confOverride(devices, "audio/devices");
getPaths(); // Initialize paths before other threads start
if (vm.count("jstest")) { // Joystick test program
std::cout << std::endl << "Joystick utility - Touch your joystick to see buttons here" << std::endl
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 3e2ae0eeceb114895884c11851f818fead791188
Author: Vincent Le Ligeour <yo...@us...>
Date: Mon Jul 5 16:02:29 2010 +0200
Moved all samples loading to init
---
game/audio.cc | 4 ++--
game/guitargraph.cc | 31 +++++++++++++------------------
game/guitargraph.hh | 2 +-
game/main.cc | 14 ++++++++++++++
game/screen_practice.cc | 20 +++++++-------------
game/screen_practice.hh | 2 +-
libs/libda/include/libda/portaudio.hpp | 4 ++--
7 files changed, 40 insertions(+), 37 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 0d9b7a5..97feaaf 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -167,10 +167,10 @@ struct Device {
portaudio::Stream stream;
std::vector<Analyzer*> mics;
Output* outptr;
-
+
Device(unsigned int in, unsigned int out, double rate, std::string dev):
in(in), out(out), rate(rate), dev(dev),
- stream(*this, in ? portaudio::Params().channelCount(in).device(dev, true) : NULL, out ? portaudio::Params().channelCount(out).device(dev, false) : NULL, rate)
+ stream(*this, in ? portaudio::Params().channelCount(in).device(dev, true) : (const PaStreamParameters*)NULL, (out ? portaudio::Params().channelCount(out).device(dev, false) : (const PaStreamParameters*)NULL), rate)
{
mics.resize(in);
}
diff --git a/game/guitargraph.cc b/game/guitargraph.cc
index d9e3383..86b5e32 100644
--- a/game/guitargraph.cc
+++ b/game/guitargraph.cc
@@ -100,25 +100,20 @@ GuitarGraph::GuitarGraph(Audio& audio, Song const& song, bool drums, int number,
// Score calculator (TODO a better one)
m_scoreText.reset(new SvgTxtThemeSimple(getThemePath("sing_score_text.svg"), config["graphic/text_lod"].f()));
m_streakText.reset(new SvgTxtThemeSimple(getThemePath("sing_score_text.svg"), config["graphic/text_lod"].f()));
- // Load fail sounds
if (m_drums) {
- m_samples.push_back(std::make_pair("drum bass", getPath("sounds/drum_bass.ogg")));
- m_samples.push_back(std::make_pair("drum snare", getPath("sounds/drum_snare.ogg")));
- m_samples.push_back(std::make_pair("drum hi-hat", getPath("sounds/drum_hi-hat.ogg")));
- m_samples.push_back(std::make_pair("drum tom1", getPath("sounds/drum_tom1.ogg")));
- m_samples.push_back(std::make_pair("drum cymbal", getPath("sounds/drum_cymbal.ogg")));
- //m_samples.push_back(std::make_pair("drum tom2", getPath("sounds/drum_tom2.ogg")));
+ m_samples.push_back("drum bass");
+ m_samples.push_back("drum snare");
+ m_samples.push_back("drum hi-hat");
+ m_samples.push_back("drum tom1");
+ m_samples.push_back("drum cymbal");
+ //m_samples.push_back("drum tom2");
} else {
- m_samples.push_back(std::make_pair("guitar fail1", getPath("sounds/guitar_fail1.ogg")));
- m_samples.push_back(std::make_pair("guitar fail2", getPath("sounds/guitar_fail2.ogg")));
- m_samples.push_back(std::make_pair("guitar fail3", getPath("sounds/guitar_fail3.ogg")));
- m_samples.push_back(std::make_pair("guitar fail4", getPath("sounds/guitar_fail4.ogg")));
- m_samples.push_back(std::make_pair("guitar fail5", getPath("sounds/guitar_fail5.ogg")));
- m_samples.push_back(std::make_pair("guitar fail6", getPath("sounds/guitar_fail6.ogg")));
- }
- // Warning the sample are shared between Guitargraphs, do not unload them
- for(unsigned int i = 0 ; i < m_samples.size() ; i++) {
- m_audio.loadSample(m_samples[i].first, m_samples[i].second);
+ m_samples.push_back("guitar fail1");
+ m_samples.push_back("guitar fail2");
+ m_samples.push_back("guitar fail3");
+ m_samples.push_back("guitar fail4");
+ m_samples.push_back("guitar fail5");
+ m_samples.push_back("guitar fail6");
}
for (int i = 0; i < 6; ++i) m_pressed_anim[i].setRate(5.0);
for (int i = 0; i < 5; ++i) m_holds[i] = 0;
@@ -409,7 +404,7 @@ void GuitarGraph::fail(double time, int fret) {
// Reduce points and play fail sample only when GodMode is deactivated
m_events.push_back(Event(time, 0, fret));
if (fret < 0) fret = std::rand();
- m_audio.playSample(m_samples[unsigned(fret) % m_samples.size()].first);
+ m_audio.playSample(m_samples[unsigned(fret) % m_samples.size()]);
// remove equivalent of 1 perfect hit for every note
// kids tend to play a lot of extra notes just for the fun of it.
// need to make sure they don't end up with a score of zero
diff --git a/game/guitargraph.hh b/game/guitargraph.hh
index 9e53408..0a41db2 100644
--- a/game/guitargraph.hh
+++ b/game/guitargraph.hh
@@ -88,7 +88,7 @@ class GuitarGraph: public InstrumentGraph {
glutil::Color m_neckglowColor;
Object3d m_fretObj; /// 3d object for regular note
Object3d m_tappableObj; /// 3d object for the HOPO note cap
- std::vector<std::pair<std::string, std::string> > m_samples; /// sound effects
+ std::vector<std::string> m_samples; /// sound effects
boost::scoped_ptr<Texture> m_neck; /// necks
boost::scoped_ptr<SvgTxtThemeSimple> m_scoreText;
boost::scoped_ptr<SvgTxtThemeSimple> m_streakText;
diff --git a/game/main.cc b/game/main.cc
index fcc41ec..f466381 100644
--- a/game/main.cc
+++ b/game/main.cc
@@ -117,6 +117,20 @@ void mainLoop(std::string const& songlist) {
boost::scoped_ptr<input::MidiDrums> midiDrums;
// TODO: Proper error handling...
try { midiDrums.reset(new input::MidiDrums); } catch (std::runtime_error&) {}
+ // Load audio samples
+ audio.loadSample("drum bass", getPath("sounds/drum_bass.ogg"));
+ audio.loadSample("drum snare", getPath("sounds/drum_snare.ogg"));
+ audio.loadSample("drum hi-hat", getPath("sounds/drum_hi-hat.ogg"));
+ audio.loadSample("drum tom1", getPath("sounds/drum_tom1.ogg"));
+ audio.loadSample("drum cymbal", getPath("sounds/drum_cymbal.ogg"));
+ //audio.loadSample("drum tom2", getPath("sounds/drum_tom2.ogg"));
+ audio.loadSample("guitar fail1", getPath("sounds/guitar_fail1.ogg"));
+ audio.loadSample("guitar fail2", getPath("sounds/guitar_fail2.ogg"));
+ audio.loadSample("guitar fail3", getPath("sounds/guitar_fail3.ogg"));
+ audio.loadSample("guitar fail4", getPath("sounds/guitar_fail4.ogg"));
+ audio.loadSample("guitar fail5", getPath("sounds/guitar_fail5.ogg"));
+ audio.loadSample("guitar fail6", getPath("sounds/guitar_fail6.ogg"));
+ // Load screens
sm.addScreen(new ScreenIntro("Intro", audio));
sm.addScreen(new ScreenSongs("Songs", audio, songs, database));
sm.addScreen(new ScreenSing("Sing", audio, database, backgrounds));
diff --git a/game/screen_practice.cc b/game/screen_practice.cc
index d0b2896..d48afd1 100644
--- a/game/screen_practice.cc
+++ b/game/screen_practice.cc
@@ -18,21 +18,15 @@ void ScreenPractice::enter() {
m_vumeters.push_back(b = new ProgressBar(getThemePath("vumeter_bg.svg"), getThemePath("vumeter_fg.svg"), ProgressBar::VERTICAL, 0.136, 0.023));
b->dimensions.screenBottom().left(-0.4 + i * 0.2).fixedWidth(0.04);
}
- m_samples.push_back(std::make_pair("drum bass", getPath("sounds/drum_bass.ogg")));
- m_samples.push_back(std::make_pair("drum snare", getPath("sounds/drum_snare.ogg")));
- m_samples.push_back(std::make_pair("drum hi-hat", getPath("sounds/drum_hi-hat.ogg")));
- m_samples.push_back(std::make_pair("drum tom1", getPath("sounds/drum_tom1.ogg")));
- m_samples.push_back(std::make_pair("drum cymbal", getPath("sounds/drum_cymbal.ogg")));
- //m_samples.push_back(std::make_pair("drum tom2", getPath("sounds/drum_tom2.ogg")));
- for(unsigned int i = 0 ; i < m_samples.size() ; i++) {
- m_audio.loadSample(m_samples[i].first, m_samples[i].second);
- }
+ m_samples.push_back("drum bass");
+ m_samples.push_back("drum snare");
+ m_samples.push_back("drum hi-hat");
+ m_samples.push_back("drum tom1");
+ m_samples.push_back("drum cymbal");
+ //m_samples.push_back("drum tom2");
}
void ScreenPractice::exit() {
- for(unsigned int i = 0 ; i < m_samples.size() ; i++) {
- m_audio.unloadSample(m_samples[i].first);
- }
m_vumeters.clear();
m_samples.clear();
theme.reset();
@@ -47,7 +41,7 @@ void ScreenPractice::manageEvent(SDL_Event event) {
else if (event.type == SDL_JOYBUTTONDOWN // Play drum sounds here
&& input::detail::devices[event.jbutton.which].type_match(input::DRUMS)) {
int b = input::buttonFromSDL(input::detail::devices[event.jbutton.which].type(), event.jbutton.button);
- if (b != -1) m_audio.playSample(m_samples[unsigned(b) % m_samples.size()].first);
+ if (b != -1) m_audio.playSample(m_samples[unsigned(b) % m_samples.size()]);
}
}
diff --git a/game/screen_practice.hh b/game/screen_practice.hh
index 2d472d2..f8156f5 100644
--- a/game/screen_practice.hh
+++ b/game/screen_practice.hh
@@ -23,7 +23,7 @@ class ScreenPractice : public Screen {
private:
Audio& m_audio;
- std::vector<std::pair<std::string, std::string> > m_samples;
+ std::vector<std::string> m_samples;
boost::ptr_vector<ProgressBar> m_vumeters;
boost::scoped_ptr<ThemePractice> theme;
};
diff --git a/libs/libda/include/libda/portaudio.hpp b/libs/libda/include/libda/portaudio.hpp
index a7987b9..8add471 100644
--- a/libs/libda/include/libda/portaudio.hpp
+++ b/libs/libda/include/libda/portaudio.hpp
@@ -19,7 +19,7 @@ namespace portaudio {
PaError m_code;
char const* m_func;
};
-
+
namespace internal {
void check(PaError code, char const* func) { if (code != paNoError) throw Error(code, func); }
}
@@ -70,7 +70,7 @@ namespace portaudio {
Params& hostApiSpecificStreamInfo(void* val) { params.hostApiSpecificStreamInfo = val; return *this; }
operator PaStreamParameters const*() const { return ¶ms; }
};
-
+
template <typename Functor> int functorCallback(void const* input, void* output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData) {
return (*static_cast<Functor*>(userData))(input, output, frameCount, timeInfo, statusFlags);
}
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous Branch: master Commit: c98951d17e65b78b99834e8852e6f811d6f5822a Author: Lasse Karkkainen <tro...@tr...> Date: Thu Jun 24 03:44:34 2010 +0300 - Config schema for new audio device configuration - Audio code rewritten with multiple device support - Samples now take std::string const& instead of std::string * Must use std::auto_ptr for ptr_map insert (avoid leaks when key copycon throws) --- data/schema.xml | 25 +++------ game/audio.cc | 154 +++++++++++++++++++++++++++++++++--------------------- game/audio.hh | 6 +- 3 files changed, 105 insertions(+), 80 deletions(-) |
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 7bc30cc15ec978b178cca13be2892401ba7c868d
Author: Vincent Le Ligeour <yo...@us...>
Date: Mon Jul 5 19:08:46 2010 +0200
Fixed audio sample thread model
---
game/audio.cc | 45 ++++++++++++++++++++++++++++-----------------
1 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 97feaaf..67b1ec9 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -20,11 +20,12 @@ class Music {
Tracks tracks; ///< Audio decoders
double srate; ///< Sample rate
int64_t m_pos; ///< Current sample position
+ bool m_preview;
public:
double fadeLevel;
double fadeRate;
typedef std::map<std::string,std::string> Files;
- Music(Files const& filenames, unsigned int sr): srate(sr), m_pos(), fadeLevel(), fadeRate() {
+ Music(Files const& filenames, unsigned int sr, bool preview): srate(sr), m_pos(), m_preview(preview), fadeLevel(), fadeRate() {
for (Files::const_iterator it = filenames.begin(), end = filenames.end(); it != end; ++it) {
tracks.insert(it->first, std::auto_ptr<Track>(new Track(it->second, sr)));
}
@@ -73,15 +74,14 @@ public:
}
};
-// rename to Sample once totally implemented
-struct SampleNew {
+struct Sample {
private:
unsigned int srate;
double m_pos;
FFmpeg mpeg;
bool eof;
public:
- SampleNew(std::string const& filename, unsigned sr) : srate(sr), m_pos(), mpeg(false, true, filename, sr), eof(true) { }
+ Sample(std::string const& filename, unsigned sr) : srate(sr), m_pos(), mpeg(false, true, filename, sr), eof(true) { }
void operator()(float* begin, float* end) {
if(eof) {
// No more data to play in this sample
@@ -104,16 +104,17 @@ struct SampleNew {
struct Command {
- enum { TRACK_FADE } type;
+ enum { TRACK_FADE, SAMPLE_RESET } type;
std::string track;
double fadeLevel;
};
struct Output {
boost::mutex mutex;
+ boost::mutex samples_mutex;
std::auto_ptr<Music> preloading;
boost::ptr_vector<Music> playing, disposing;
- boost::ptr_map<std::string, SampleNew> samples;
+ boost::ptr_map<std::string, Sample> samples;
std::vector<Command> commands;
volatile bool paused;
Output(): paused(false) {}
@@ -132,6 +133,11 @@ struct Output {
case Command::TRACK_FADE:
if (!playing.empty()) playing[0].trackFade(cmd.track, cmd.fadeLevel);
break;
+ case Command::SAMPLE_RESET:
+ boost::ptr_map<std::string, Sample>::iterator it = samples.find(cmd.track);
+ if (it != samples.end())
+ it->second->reset();
+ break;
}
}
commands.clear();
@@ -152,9 +158,14 @@ struct Output {
++i;
}
// Mix in the samples currently playing
- for(boost::ptr_map<std::string, SampleNew>::iterator it = samples.begin() ; it != samples.end() ; ++it) {
- boost::mutex::scoped_try_lock l(mutex);
- (*it->second)(begin, end);
+ {
+ // samples should not be created/destroyed on the fly
+ boost::mutex::scoped_try_lock l(samples_mutex, boost::defer_lock);
+ if(l.try_lock()) {
+ for(boost::ptr_map<std::string, Sample>::iterator it = samples.begin() ; it != samples.end() ; ++it) {
+ (*it->second)(begin, end);
+ }
+ }
}
}
};
@@ -226,19 +237,19 @@ bool Audio::isOpen() const {
}
void Audio::loadSample(std::string const& streamId, std::string const& filename) {
- boost::mutex::scoped_lock l(self->output.mutex);
- self->output.samples.insert(streamId, std::auto_ptr<SampleNew>(new SampleNew(filename, getSR())));
+ boost::mutex::scoped_lock l(self->output.samples_mutex);
+ self->output.samples.insert(streamId, std::auto_ptr<Sample>(new Sample(filename, getSR())));
}
void Audio::playSample(std::string const& streamId) {
- boost::mutex::scoped_lock l(self->output.mutex);
- boost::ptr_map<std::string, SampleNew>::iterator it = self->output.samples.find(streamId);
- if (it == self->output.samples.end()) throw std::runtime_error("Cannot play sample : " + streamId);
- it->second->reset();
+ Output& o = self->output;
+ boost::mutex::scoped_lock l(o.mutex);
+ Command cmd = { Command::SAMPLE_RESET, streamId, 0.0 };
+ o.commands.push_back(cmd);
}
void Audio::unloadSample(std::string const& streamId) {
- boost::mutex::scoped_lock l(self->output.mutex);
+ boost::mutex::scoped_lock l(self->output.samples_mutex);
self->output.samples.erase(streamId);
}
@@ -246,7 +257,7 @@ void Audio::playMusic(std::map<std::string,std::string> const& filenames, bool p
Output& o = self->output;
boost::mutex::scoped_lock l(o.mutex);
o.disposing.clear(); // Delete disposed streams
- o.preloading.reset(new Music(filenames, getSR()));
+ o.preloading.reset(new Music(filenames, getSR(), preview));
Music& m = *o.preloading.get();
m.seek(startPos);
m.fadeRate = 1.0 / getSR() / fadeTime;
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 7b5d9e1559f236a44c38e8c82675f1d627423d94
Author: Vincent Le Ligeour <yo...@us...>
Date: Mon Jul 5 21:26:46 2010 +0200
Added note synth to audio code
---
game/audio.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++
game/audio.hh | 2 +-
2 files changed, 46 insertions(+), 1 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index ac93f15..1cb771a 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -102,6 +102,36 @@ struct Sample {
}
};
+struct Synth {
+ private:
+ Notes m_notes;
+ double srate; ///< Sample rate
+ public:
+ Synth(Notes const& notes, unsigned int sr) : m_notes(notes), srate(sr) {};
+ void operator()(float* begin, float* end, double position) {
+ static double phase = 0.0;
+ for (float *i = begin; i < end; ++i) *i *= 0.3; // Decrease music volume
+
+ std::vector<float> mixbuf(end - begin);
+ Notes::const_iterator it = m_notes.begin();
+
+ while (it != m_notes.end() && it->end < position) ++it;
+ if (it == m_notes.end() || it->type == Note::SLEEP || it->begin > position) { phase = 0.0; return; }
+ int note = it->note % 12;
+ double d = (note + 1) / 13.0;
+ double freq = MusicalScale().getNoteFreq(note + 12);
+ double value = 0.0;
+ // Synthesize tones
+ for (size_t i = 0, iend = mixbuf.size(); i != iend; ++i) {
+ if (i % 2 == 0) {
+ 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 / srate;
+ }
+ begin[i] += value;
+ }
+ }
+};
+
struct Command {
enum { TRACK_FADE, SAMPLE_RESET } type;
@@ -112,6 +142,8 @@ struct Command {
struct Output {
boost::mutex mutex;
boost::mutex samples_mutex;
+ boost::mutex synth_mutex;
+ std::auto_ptr<Synth> synth;
std::auto_ptr<Music> preloading;
boost::ptr_vector<Music> playing, disposing;
boost::ptr_map<std::string, Sample> samples;
@@ -167,6 +199,13 @@ struct Output {
}
}
}
+ // Mix synth if available (should be done at the end)
+ {
+ boost::mutex::scoped_try_lock l(synth_mutex, boost::defer_lock);
+ if(l.try_lock() && synth.get() && !playing.empty()) {
+ (*synth.get())(begin, end, playing[0].pos());
+ }
+ }
}
};
@@ -326,5 +365,11 @@ void Audio::streamFade(std::string track, double fadeLevel) {
o.commands.push_back(cmd);
}
+void Audio::toggleSynth(Notes const& notes) {
+ Output& o = self->output;
+ boost::mutex::scoped_lock l(o.synth_mutex);
+ o.synth.get() ? o.synth.reset() : o.synth.reset(new Synth(notes, getSR()));
+}
+
boost::ptr_vector<Analyzer>& Audio::analyzers() { return self->analyzers; }
diff --git a/game/audio.hh b/game/audio.hh
index 1087c8f..dab6770 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -54,7 +54,7 @@ public:
void togglePause() { pause(!isPaused()); }
void pause(bool state = true);
bool isPaused() const;
- void toggleSynth(Notes const&) { /*m_notes = (m_notes ? NULL : ¬es); */} ///< toggles synth playback
+ void toggleSynth(Notes const&); ///< toggles synth playback
/// Adjust volume level of a single track (used for muting incorrectly played instruments). Range 0.0 to 1.0.
void streamFade(std::string track, double volume);
double getSR() const { return 48000.0; }
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: c0db3b7c1d3a2bfd0245e335844e325cede35ab3
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 18 10:12:40 2010 +0300
Another way of struct initialization avoids GCC compile warnings.
---
tools/itg_pck.cc | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/itg_pck.cc b/tools/itg_pck.cc
index 0593e37..0dbe4cf 100644
--- a/tools/itg_pck.cc
+++ b/tools/itg_pck.cc
@@ -46,7 +46,7 @@ struct Extract {
std::string ext;
if (file.mode == 1) {
std::vector<char> buf2(file.size);
- z_stream strm = {};
+ z_stream strm = z_stream();
strm.avail_in = buffer.size();
strm.next_in = reinterpret_cast<Bytef*>(&buffer[0]);
strm.avail_out = buf2.size();
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 63476ceedd38feb0ff2c34328e8085c42bab56ad
Author: Tapio Vierros <tap...@gm...>
Date: Thu Jul 15 20:31:17 2010 +0300
Output PA devices to console.
---
game/audio.cc | 4 ++++
game/audio.hh | 13 +++++++------
libs/libda/include/libda/portaudio.hpp | 13 ++++++++++++-
3 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 1cb771a..2c6a3b4 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -150,6 +150,7 @@ struct Output {
std::vector<Command> commands;
volatile bool paused;
Output(): paused(false) {}
+
void callbackUpdate() {
boost::mutex::scoped_try_lock l(mutex);
if (!l.owns_lock()) return; // No update now, try again later (cannot stop and wait for mutex to be released)
@@ -174,6 +175,7 @@ struct Output {
}
commands.clear();
}
+
void callback(float* begin, float* end) {
callbackUpdate();
std::fill(begin, end, 0.0f);
@@ -224,10 +226,12 @@ struct Device {
{
mics.resize(in);
}
+
void start() {
PaError err = Pa_StartStream(stream);
if (err != paNoError) throw std::runtime_error("Cannot start PortAudio audio stream " + dev + ": " + Pa_GetErrorText(err));
}
+
int operator()(void const* input, void* output, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags) try {
float const* in = static_cast<float const*>(input);
float* out = static_cast<float*>(output);
diff --git a/game/audio.hh b/game/audio.hh
index dab6770..27018f8 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -27,15 +27,15 @@ public:
* @param startPos starting position
*/
void playMusic(std::string const& filename, bool preview = false, double fadeTime = 0.5, double startPos = 0.0);
- /// plays a list of songs
+ /** Plays a list of songs **/
void playMusic(std::map<std::string,std::string> const& filenames, bool preview = false, double fadeTime = 0.5, double startPos = 0.0);
- /// loads/plays/unloads a sample
+ /** Loads/plays/unloads a sample **/
void loadSample(std::string const& streamId, std::string const& filename);
void playSample(std::string const& streamId);
void unloadSample(std::string const& streamId);
- /// stops music
+ /** Stops music **/
void stopMusic();
- /// fades music out
+ /** Fades music out **/
void fadeout(double time = 1.0);
/** Get the length of the currently playing song, in seconds. **/
double getLength() const;
@@ -54,8 +54,9 @@ public:
void togglePause() { pause(!isPaused()); }
void pause(bool state = true);
bool isPaused() const;
- void toggleSynth(Notes const&); ///< toggles synth playback
- /// Adjust volume level of a single track (used for muting incorrectly played instruments). Range 0.0 to 1.0.
+ /** Toggle synth playback **/
+ void toggleSynth(Notes const&);
+ /** Adjust volume level of a single track (used for muting incorrectly played instruments). Range 0.0 to 1.0. **/
void streamFade(std::string track, double volume);
double getSR() const { return 48000.0; }
};
diff --git a/libs/libda/include/libda/portaudio.hpp b/libs/libda/include/libda/portaudio.hpp
index 8add471..d6e33b1 100644
--- a/libs/libda/include/libda/portaudio.hpp
+++ b/libs/libda/include/libda/portaudio.hpp
@@ -25,7 +25,18 @@ namespace portaudio {
}
struct Init {
- Init() { PORTAUDIO_CHECKED(Pa_Initialize, ()); }
+ Init()
+ {
+ PORTAUDIO_CHECKED(Pa_Initialize, ());
+ // Print the devices
+ std::cout << "PortAudio devices:\n";
+ for (int i = 0, end = Pa_GetDeviceCount(); i != end; ++i) {
+ PaDeviceInfo const* info = Pa_GetDeviceInfo(i);
+ if (!info) continue;
+ std::cout << " " << i << " " << info->name << " (" << info->maxInputChannels << " in, " << info->maxOutputChannels << " out)\n";
+ }
+ std::cout << std::endl;
+ }
~Init() { Pa_Terminate(); }
};
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:08
|
Module: performous
Branch: master
Commit: 34aaed0a09c83565b5481f6744cb3ba0f7c4c486
Author: Vincent Le Ligeour <yo...@us...>
Date: Mon Jul 5 19:58:53 2010 +0200
Implemented audio volume
---
game/audio.cc | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 67b1ec9..ac93f15 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -45,7 +45,7 @@ public:
if (fadeLevel <= 0.0) return false;
if (fadeLevel > 1.0) { fadeLevel = 1.0; fadeRate = 0.0; }
}
- begin[i] += mixbuf[i] * fadeLevel;
+ begin[i] += mixbuf[i] * fadeLevel * static_cast<float>(m_preview ? config["audio/preview_volume"].i() : config["audio/music_volume"].i())/100.0;
}
return !eof;
}
@@ -92,7 +92,7 @@ struct Sample {
eof = true;
}
for (size_t i = 0, iend = end - begin; i != iend; ++i) {
- begin[i] += mixbuf[i];
+ begin[i] += mixbuf[i] * static_cast<float>(config["audio/fail_volume"].i())/100.0;
}
m_pos += end - begin;
}
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:07
|
Module: performous
Branch: master
Commit: da7996816460ccd179e6a3244f76aaa196be7276
Author: Vincent Le Ligeour <yo...@us...>
Date: Sun Jun 20 21:16:30 2010 +0200
Added draft of sample playing
---
game/audio.cc | 75 +++++++++++++++++++++++++++++++++++++++++++++-
game/audio.hh | 7 ++++-
game/ffmpeg.hh | 2 +-
game/screen_practice.cc | 3 ++
4 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index b82be8d..fcdb3bc 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -68,10 +68,46 @@ public:
}
};
+#define MAX_SAMPLE_SIZE 2000000
+
+// rename to Sample once totally implemented
+struct SampleNew {
+ private:
+ std::vector<float> sample_buf;
+ unsigned int srate;
+ double m_pos;
+ public:
+ SampleNew(std::string filename, unsigned sr) : srate(sr), m_pos() {
+ FFmpeg mpeg(false, true, filename, sr);
+ // here transfer all the samples to sample_buf
+ //
+ sample_buf.resize(MAX_SAMPLE_SIZE);
+ }
+ bool operator()(float* begin, float* end) {
+ if( m_pos >= sample_buf.size()) {
+ // No more data to play in this sample
+ return false;
+ }
+ for (size_t i = 0, iend = end - begin; i != iend; ++i) {
+ if(m_pos + i > sample_buf.size()) {
+ // no more data to fill
+ break;
+ }
+ begin[i] += sample_buf[m_pos + i];
+ }
+ m_pos += end - begin;
+ }
+ void seek(double time) {
+ m_pos = time * srate * 2.0;
+ }
+};
+
+
struct Audio::Impl {
boost::mutex mutex;
std::auto_ptr<Music> preloading;
boost::ptr_vector<Music> playing, disposing;
+ boost::ptr_map<std::string, SampleNew> playing_samples, sleeping_samples;
portaudio::Init init;
boost::ptr_vector<portaudio::Stream> streams;
volatile bool paused;
@@ -101,6 +137,12 @@ struct Audio::Impl {
if (!l.owns_lock()) keep = true; // Cannot dispose without lock
if (keep) ++i; else disposing.transfer(disposing.end(), playing.begin() + i, playing);
}
+ for(boost::ptr_map<std::string, SampleNew>::iterator it = playing_samples.begin() ; it != playing_samples.end() ; ++it) {
+ boost::mutex::scoped_try_lock l(mutex);
+ if( (*it->second)(begin, end) == false && l.owns_lock()) {
+ sleeping_samples.transfer(sleeping_samples.end(), it, playing_samples);
+ }
+ }
}
int operator()(void const* input, void* output, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags) try {
float const* in = static_cast<float const*>(input);
@@ -123,8 +165,37 @@ bool Audio::isOpen() const {
boost::mutex::scoped_lock l(self->mutex);
return !self->streams.empty();
}
-
-void Audio::play(Sample const& s, std::string const& volumeSetting) {
+
+void Audio::loadSample(std::string streamId, std::string filename) {
+ std::cout << ">>> Loading sample \"" << streamId << "\"" << std::endl;
+ {
+ boost::mutex::scoped_lock l(self->mutex);
+ self->sleeping_samples.insert(streamId, new SampleNew(filename, getSR()));
+ }
+}
+void Audio::playSample(std::string streamId) {
+ boost::mutex::scoped_lock l(self->mutex);
+ boost::ptr_map<std::string, SampleNew>::iterator it = self->sleeping_samples.find(streamId);
+ if( it == self->sleeping_samples.end() ) {
+ boost::ptr_map<std::string, SampleNew>::iterator it = self->playing_samples.find(streamId);
+ if( it == self->playing_samples.end() ) {
+ throw std::runtime_error("Cannot play sample : " + streamId);
+ } else {
+ it->second->seek(0.0);
+ }
+ } else {
+ it->second->seek(0.0);
+ self->playing_samples.transfer(self->playing_samples.end(), it, self->sleeping_samples);
+ }
+}
+
+void Audio::unloadSample(std::string streamId) {
+ std::cout << ">>> Unloading sample \"" << streamId << "\"" << std::endl;
+ {
+ boost::mutex::scoped_lock l(self->mutex);
+ self->sleeping_samples.erase(streamId);
+ self->playing_samples.erase(streamId);
+ }
}
void Audio::playMusic(std::map<std::string,std::string> const& filenames, bool preview, double fadeTime, double startPos) {
diff --git a/game/audio.hh b/game/audio.hh
index ab310a8..8475e3d 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -11,10 +11,12 @@
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/scoped_ptr.hpp>
+// TODO: should be removed
struct Sample {
Sample(std::string, unsigned) {}
};
+
/** @short High level audio playback API **/
class Audio {
struct Impl;
@@ -34,7 +36,10 @@ public:
/// plays a list of songs
void playMusic(std::map<std::string,std::string> const& filenames, bool preview = false, double fadeTime = 0.5, double startPos = 0.0);
/// plays a sample
- void play(Sample const& s, std::string const& volumeSetting);
+ void loadSample(std::string streamId, std::string filename);
+ void playSample(std::string streamId);
+ void unloadSample(std::string streamId);
+ void play(Sample const& s, std::string const& volumeSetting) {};// TODO: remove
/// stops music
void stopMusic();
/// fades music out
diff --git a/game/ffmpeg.hh b/game/ffmpeg.hh
index 246f436..877b145 100644
--- a/game/ffmpeg.hh
+++ b/game/ffmpeg.hh
@@ -32,7 +32,7 @@ struct VideoFrame {
int width, ///< width of frame
height; ///< height of frame
/// data array
- std::vector<uint8_t> data;
+ std::vector<uint8_t> data;
/// constructor
VideoFrame(double ts, int w, int h): timestamp(ts), width(w), height(h) {}
VideoFrame(): timestamp(getInf()) {} // EOF marker
diff --git a/game/screen_practice.cc b/game/screen_practice.cc
index 3c18e3d..335650d 100644
--- a/game/screen_practice.cc
+++ b/game/screen_practice.cc
@@ -19,6 +19,7 @@ void ScreenPractice::enter() {
b->dimensions.screenBottom().left(-0.4 + i * 0.2).fixedWidth(0.04);
}
unsigned int sr = m_audio.getSR();
+ m_audio.loadSample("drum bass", getPath("sounds/drum_bass.ogg"));
m_samples.push_back(Sample(getPath("sounds/drum_bass.ogg"), sr));
m_samples.push_back(Sample(getPath("sounds/drum_snare.ogg"), sr));
m_samples.push_back(Sample(getPath("sounds/drum_hi-hat.ogg"), sr));
@@ -28,6 +29,7 @@ void ScreenPractice::enter() {
}
void ScreenPractice::exit() {
+ m_audio.unloadSample("drum bass");
m_vumeters.clear();
m_samples.clear();
theme.reset();
@@ -43,6 +45,7 @@ void ScreenPractice::manageEvent(SDL_Event event) {
&& input::detail::devices[event.jbutton.which].type_match(input::DRUMS)) {
int b = input::buttonFromSDL(input::detail::devices[event.jbutton.which].type(), event.jbutton.button);
if (b != -1) m_audio.play(m_samples[unsigned(b) % m_samples.size()], "audio/fail_volume");
+ m_audio.playSample("drum bass");
}
}
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:07
|
Module: performous
Branch: master
Commit: 8a47959c4e54a3c571bd1465a1ae96d763dd6c1a
Author: Lasse Karkkainen <tro...@tr...>
Date: Sat Jun 19 05:47:03 2010 +0300
A temporary fix for the Alt+F4 segfault problem, caused by screen_sing not being exited before destroying Audio, causing engine thread to sometimes access Audio::getPosition on a dead object...
---
game/main.cc | 3 +--
game/screen.hh | 1 +
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/game/main.cc b/game/main.cc
index 9b0b597..fcc41ec 100644
--- a/game/main.cc
+++ b/game/main.cc
@@ -107,10 +107,9 @@ static void checkEvents_SDL(ScreenManager& sm) {
void mainLoop(std::string const& songlist) {
Window window(config["graphic/window_width"].i(), config["graphic/window_height"].i(), config["graphic/fullscreen"].b());
+ Audio audio;
ScreenManager sm(window);
try {
- sm.flashMessage(_("Audio playback..."), 0.0f, 1.0f, 1.0f); window.blank(); sm.drawFlashMessage(); window.swap();
- Audio audio;
sm.flashMessage(_("Miscellaneous..."), 0.0f, 1.0f, 1.0f); window.blank(); sm.drawFlashMessage(); window.swap();
Backgrounds backgrounds;
Database database(getConfigDir() / "database.xml");
diff --git a/game/screen.hh b/game/screen.hh
index ba7da69..fb853af 100644
--- a/game/screen.hh
+++ b/game/screen.hh
@@ -37,6 +37,7 @@ class ScreenManager: public Singleton <ScreenManager> {
public:
/// constructor
ScreenManager(Window& window);
+ ~ScreenManager() { if (currentScreen) currentScreen->exit(); }
/// adds a screen to the manager
void addScreen(Screen* s) { std::string tmp = s->getName(); screens.insert(tmp, s); };
/// Switches active screen
|
|
From: Lasse Kärkkäi. <tr...@us...> - 2010-08-12 22:45:07
|
Module: performous
Branch: master
Commit: 62e1916e4be836cc53f4cf563874f618f34adcac
Author: Lasse Karkkainen <tro...@tr...>
Date: Wed Jun 23 07:33:33 2010 +0300
Implement capture (analyzer) for one channel. Improve code comments in audio.cc.
---
game/audio.cc | 31 +++++++++++++++++++++----------
game/audio.hh | 2 +-
game/engine.hh | 1 +
3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/game/audio.cc b/game/audio.cc
index 3a6c9e8..7c1779b 100644
--- a/game/audio.cc
+++ b/game/audio.cc
@@ -103,12 +103,15 @@ struct Audio::Impl {
std::auto_ptr<Music> preloading;
boost::ptr_vector<Music> playing, disposing;
boost::ptr_map<std::string, SampleNew> samples;
+ boost::ptr_vector<Analyzer> analyzers;
portaudio::Init init;
boost::ptr_vector<portaudio::Stream> streams;
volatile bool paused;
Impl(): paused(false) {
std::string dev;
- streams.push_back(new portaudio::Stream(*this, portaudio::Params().channelCount(2).device(dev, true), portaudio::Params().channelCount(2).device(dev, false), 48000));
+ streams.push_back(new portaudio::Stream(*this, portaudio::Params().channelCount(1).device(dev, true), portaudio::Params().channelCount(2).device(dev, false), 48000));
+ // One analyzer for mono input (TODO: fix callbackInput to allow more)
+ analyzers.push_back(new Analyzer(48000.0));
PaError err = Pa_StartStream(streams[0]);
if( err != paNoError ) throw std::runtime_error("Cannot start PortAudio audio stream " + dev + ": " + Pa_GetErrorText(err));
}
@@ -121,17 +124,24 @@ struct Audio::Impl {
playing.insert(playing.begin(), preloading);
}
}
- void callbackInput(float const* begin, float const* end) {}
+ void callbackInput(float const* begin, float const* end) {
+ analyzers[0].input(begin, end); // TODO: non-pointer sample iterators and support more analyzers
+ }
void callbackOutput(float* begin, float* end) {
std::fill(begin, end, 0.0f);
if (paused) return;
+ // Mix in from the streams currently playing
for (size_t i = 0; i < playing.size();) {
- bool keep = playing[i](begin, end);
- // Disposing hack
- boost::mutex::scoped_try_lock l(mutex);
- if (!l.owns_lock()) keep = true; // Cannot dispose without lock
- if (keep) ++i; else disposing.transfer(disposing.end(), playing.begin() + i, playing);
+ bool keep = playing[i](begin, end); // Do the actual mixing
+ boost::mutex::scoped_try_lock l(mutex, boost::defer_lock);
+ if (!keep && l.try_lock()) {
+ // Dispose streams no longer needed by moving them to another container (that will be cleared by another thread).
+ disposing.transfer(disposing.end(), playing.begin() + i, playing);
+ continue;
+ }
+ ++i;
}
+ // Mix in the samples currently playing
for(boost::ptr_map<std::string, SampleNew>::iterator it = samples.begin() ; it != samples.end() ; ++it) {
boost::mutex::scoped_try_lock l(mutex);
(*it->second)(begin, end);
@@ -140,10 +150,9 @@ struct Audio::Impl {
int operator()(void const* input, void* output, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags) try {
float const* in = static_cast<float const*>(input);
float* out = static_cast<float*>(output);
- size_t samples = 2 * frames;
- callbackInput(in, in + samples);
+ callbackInput(in, in + 1 * frames); // TODO: no hardcoded channel count
callbackUpdate();
- callbackOutput(out, out + samples);
+ callbackOutput(out, out + 2 * frames);
return paContinue;
} catch (std::exception& e) {
std::cerr << "Exception in audio callback: " << e.what() << std::endl;
@@ -248,3 +257,5 @@ bool Audio::isPaused() const { return self->paused; }
void Audio::streamFade(std::string stream_id, double level) {
}
+boost::ptr_vector<Analyzer>& Audio::analyzers() { return self->analyzers; }
+
diff --git a/game/audio.hh b/game/audio.hh
index 4f620ee..cab5e4f 100644
--- a/game/audio.hh
+++ b/game/audio.hh
@@ -18,7 +18,7 @@ class Audio {
public:
Audio();
~Audio();
- boost::ptr_vector<Analyzer>& analyzers() { static boost::ptr_vector<Analyzer> ana; return ana; }
+ boost::ptr_vector<Analyzer>& analyzers();
bool isOpen() const;
/** Play a song beginning at startPos (defaults to 0)
* @param filename the track filename
diff --git a/game/engine.hh b/game/engine.hh
index f1c7882..c2dad6d 100644
--- a/game/engine.hh
+++ b/game/engine.hh
@@ -65,6 +65,7 @@ class Engine {
std::for_each(m_database.cur.begin(), m_database.cur.end(), boost::bind(&Player::prepare, _1));
double t = m_audio.getPosition() - config["audio/round-trip"].f();
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_vocals.notes.begin(); it != m_vocals.notes.end(); ++it) it->power = 0.0f;
std::for_each(m_database.cur.begin(), m_database.cur.end(), boost::bind(&Player::update, _1));
|