/*
This file is part of Ingen.
Copyright 2007-2012 David Robillard
Ingen is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or any later version.
Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
You should have received a copy of the GNU Affero General Public License
along with Ingen. If not, see .
*/
#include "lv2/lv2plug.in/ns/ext/atom/util.h"
#include "ingen/shared/URIs.hpp"
#include "raul/log.hpp"
#include "AudioBuffer.hpp"
#include "Buffer.hpp"
#include "Context.hpp"
namespace Ingen {
namespace Server {
static inline void
audio_accumulate(Context& context, AudioBuffer* dst, const AudioBuffer* src)
{
Sample* const dst_buf = dst->data();
const Sample* const src_buf = src->data();
if (dst->is_control()) {
if (src->is_control()) { // control => control
dst_buf[0] += src_buf[0];
} else { // audio => control
dst_buf[0] += src_buf[context.offset()];
}
} else {
const SampleCount end = context.offset() + context.nframes();
if (src->is_control()) { // control => audio
for (SampleCount i = context.offset(); i < end; ++i) {
dst_buf[i] += src_buf[0];
}
} else { // audio => audio
for (SampleCount i = context.offset(); i < end; ++i) {
dst_buf[i] += src_buf[i];
}
}
}
}
static inline bool
is_audio(Shared::URIs& uris, LV2_URID type)
{
return type == uris.atom_Float || type == uris.atom_Sound;
}
static inline bool
is_end(const Buffer* buf, LV2_Atom_Event* ev)
{
return lv2_atom_sequence_is_end(
(LV2_Atom_Sequence_Body*)LV2_ATOM_BODY(buf->atom()),
buf->atom()->size,
ev);
}
void
mix(Context& context,
Shared::URIs& uris,
Buffer* dst,
const Buffer*const* srcs,
uint32_t num_srcs)
{
if (num_srcs == 1) {
dst->copy(context, srcs[0]);
} else if (is_audio(uris, dst->type())) {
// Copy the first source
dst->copy(context, srcs[0]);
// Mix in the rest
for (uint32_t i = 1; i < num_srcs; ++i) {
assert(is_audio(uris, srcs[i]->type()));
audio_accumulate(context,
(AudioBuffer*)dst,
(const AudioBuffer*)srcs[i]);
}
} else {
assert(dst->type() == uris.atom_Sequence);
LV2_Atom_Event* iters[num_srcs];
for (uint32_t i = 0; i < num_srcs; ++i) {
assert(srcs[i]->type() == uris.atom_Sequence);
iters[i] = lv2_atom_sequence_begin(
(LV2_Atom_Sequence_Body*)LV2_ATOM_BODY(srcs[i]->atom()));
if (is_end(srcs[i], iters[i])) {
iters[i] = NULL;
}
}
while (true) {
const LV2_Atom_Event* first = NULL;
uint32_t first_i = 0;
for (uint32_t i = 0; i < num_srcs; ++i) {
const LV2_Atom_Event* const ev = iters[i];
if (!first || (ev && ev->time.frames < first->time.frames)) {
first = ev;
first_i = i;
}
}
if (first) {
dst->append_event(
first->time.frames, first->body.size, first->body.type,
(const uint8_t*)LV2_ATOM_BODY(&first->body));
iters[first_i] = lv2_atom_sequence_next(first);
if (is_end(srcs[first_i], iters[first_i])) {
iters[first_i] = NULL;
}
} else {
break;
}
}
}
}
} // namespace Server
} // namespace Ingen