+string
+get_required_string (multimap<string, string> const & kv, string k)
+{
+ if (kv.count (k) > 1) {
+ throw StringError (N_("unexpected multiple keys in key-value set"));
+ }
+
+ multimap<string, string>::const_iterator i = kv.find (k);
+
+ if (i == kv.end ()) {
+ throw StringError (String::compose (_("missing key %1 in key-value set"), k));
+ }
+
+ return i->second;
+}
+
+int
+get_required_int (multimap<string, string> const & kv, string k)
+{
+ string const v = get_required_string (kv, k);
+ return lexical_cast<int> (v);
+}
+
+float
+get_required_float (multimap<string, string> const & kv, string k)
+{
+ string const v = get_required_string (kv, k);
+ return lexical_cast<float> (v);
+}
+
+string
+get_optional_string (multimap<string, string> const & kv, string k)
+{
+ if (kv.count (k) > 1) {
+ throw StringError (N_("unexpected multiple keys in key-value set"));
+ }
+
+ multimap<string, string>::const_iterator i = kv.find (k);
+ if (i == kv.end ()) {
+ return N_("");
+ }
+
+ return i->second;
+}
+
+int
+get_optional_int (multimap<string, string> const & kv, string k)
+{
+ if (kv.count (k) > 1) {
+ throw StringError (N_("unexpected multiple keys in key-value set"));
+ }
+
+ multimap<string, string>::const_iterator i = kv.find (k);
+ if (i == kv.end ()) {
+ return 0;
+ }
+
+ return lexical_cast<int> (i->second);
+}
+
+/** Construct an AudioBuffers. Audio data is undefined after this constructor.
+ * @param channels Number of channels.
+ * @param frames Number of frames to reserve space for.
+ */
+AudioBuffers::AudioBuffers (int channels, int frames)
+ : _channels (channels)
+ , _frames (frames)
+ , _allocated_frames (frames)
+{
+ _data = new float*[_channels];
+ for (int i = 0; i < _channels; ++i) {
+ _data[i] = new float[frames];
+ }
+}
+
+/** Copy constructor.
+ * @param other Other AudioBuffers; data is copied.
+ */
+AudioBuffers::AudioBuffers (AudioBuffers const & other)
+ : _channels (other._channels)
+ , _frames (other._frames)
+ , _allocated_frames (other._frames)
+{
+ _data = new float*[_channels];
+ for (int i = 0; i < _channels; ++i) {
+ _data[i] = new float[_frames];
+ memcpy (_data[i], other._data[i], _frames * sizeof (float));
+ }
+}
+
+/* XXX: it's a shame that this is a copy-and-paste of the above;
+ probably fixable with c++0x.
+*/
+AudioBuffers::AudioBuffers (boost::shared_ptr<const AudioBuffers> other)
+ : _channels (other->_channels)
+ , _frames (other->_frames)
+ , _allocated_frames (other->_frames)
+{
+ _data = new float*[_channels];
+ for (int i = 0; i < _channels; ++i) {
+ _data[i] = new float[_frames];
+ memcpy (_data[i], other->_data[i], _frames * sizeof (float));
+ }
+}
+
+/** AudioBuffers destructor */
+AudioBuffers::~AudioBuffers ()
+{
+ for (int i = 0; i < _channels; ++i) {
+ delete[] _data[i];
+ }
+
+ delete[] _data;
+}
+
+/** @param c Channel index.
+ * @return Buffer for this channel.
+ */
+float*
+AudioBuffers::data (int c) const
+{
+ assert (c >= 0 && c < _channels);
+ return _data[c];
+}
+
+/** Set the number of frames that these AudioBuffers will report themselves
+ * as having.
+ * @param f Frames; must be less than or equal to the number of allocated frames.
+ */
+void
+AudioBuffers::set_frames (int f)
+{
+ assert (f <= _allocated_frames);
+ _frames = f;
+}
+
+/** Make all samples on all channels silent */
+void
+AudioBuffers::make_silent ()
+{
+ for (int i = 0; i < _channels; ++i) {
+ make_silent (i);
+ }
+}
+
+/** Make all samples on a given channel silent.
+ * @param c Channel.