super-basic working MIDI triggering for TriggerBox
This commit is contained in:
@@ -42,10 +42,14 @@ class TriggerBox;
|
||||
|
||||
class LIBARDOUR_API Trigger {
|
||||
public:
|
||||
Trigger() {}
|
||||
Trigger() : _running (false) {}
|
||||
virtual ~Trigger() {}
|
||||
|
||||
virtual void bang (TriggerBox&, Temporal::Beats const &, samplepos_t) = 0;
|
||||
bool running() const { return _running; }
|
||||
|
||||
protected:
|
||||
bool _running;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
@@ -58,9 +62,8 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
|
||||
private:
|
||||
boost::shared_ptr<AudioRegion> region;
|
||||
bool running;
|
||||
std::vector<Sample*> data;
|
||||
samplecnt_t read_index;
|
||||
std::vector<samplecnt_t> read_index;
|
||||
samplecnt_t length;
|
||||
};
|
||||
|
||||
@@ -72,6 +75,7 @@ class LIBARDOUR_API TriggerBox : public Processor
|
||||
|
||||
void run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required);
|
||||
bool can_support_io_configuration (const ChanCount& in, ChanCount& out);
|
||||
bool configure_io (ChanCount in, ChanCount out);
|
||||
|
||||
bool queue_trigger (Trigger*);
|
||||
void add_trigger (Trigger*);
|
||||
|
||||
@@ -19,7 +19,7 @@ TriggerBox::TriggerBox (Session& s)
|
||||
{
|
||||
PropertyList plist;
|
||||
|
||||
the_source.reset (new SndFileSource (_session, "/usr/share/sounds/alsa/Front_Center.wav", 0, Source::Flag (0)));
|
||||
the_source.reset (new SndFileSource (_session, "/music/misc/La_Voz_Del_Rio.wav", 0, Source::Flag (0)));
|
||||
|
||||
plist.add (Properties::start, 0);
|
||||
plist.add (Properties::length, the_source->length ());
|
||||
@@ -30,8 +30,6 @@ TriggerBox::TriggerBox (Session& s)
|
||||
boost::shared_ptr<Region> r = RegionFactory::create (the_source, plist, false);
|
||||
the_region = boost::dynamic_pointer_cast<AudioRegion> (r);
|
||||
|
||||
cerr << "Trigger track has region " << the_region->name() << " length = " << the_region->length() << endl;
|
||||
|
||||
/* XXX the_region/trigger will be looked up in a
|
||||
std::map<MIDI::byte,Trigger>
|
||||
*/
|
||||
@@ -50,24 +48,16 @@ TriggerBox::can_support_io_configuration (const ChanCount& in, ChanCount& out)
|
||||
return false;
|
||||
}
|
||||
|
||||
out = ChanCount::max (out, ChanCount (DataType::AUDIO, 2));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TriggerBox::note_on (int note_number, int velocity)
|
||||
{
|
||||
if (velocity == 0) {
|
||||
note_off (note_number, velocity);
|
||||
return;
|
||||
}
|
||||
|
||||
queue_trigger (the_trigger);
|
||||
}
|
||||
|
||||
void
|
||||
TriggerBox::note_off (int note_number, int velocity)
|
||||
bool
|
||||
TriggerBox::configure_io (ChanCount in, ChanCount out)
|
||||
{
|
||||
cerr << "TB: " << in << " / " << out << endl;
|
||||
return Processor::configure_io (in, out);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -87,6 +77,9 @@ TriggerBox::queue_trigger (Trigger* trigger)
|
||||
void
|
||||
TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required)
|
||||
{
|
||||
samplepos_t next_beat = 0;
|
||||
Temporal::Beats beats_now;
|
||||
|
||||
/* check MIDI port input buffers for triggers */
|
||||
|
||||
for (BufferSet::midi_iterator mi = bufs.midi_begin(); mi != bufs.midi_end(); ++mi) {
|
||||
@@ -94,8 +87,12 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
|
||||
for (MidiBuffer::iterator ev = mb.begin(); ev != mb.end(); ++ev) {
|
||||
if ((*ev).is_note_on()) {
|
||||
cerr << "Trigger => NOTE ON!\n";
|
||||
note_on ((*ev).note(), (*ev).velocity());
|
||||
|
||||
if (!the_trigger->running()) {
|
||||
active_triggers.push_back (the_trigger);
|
||||
}
|
||||
|
||||
the_trigger->bang (*this, beats_now, start_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,9 +102,6 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
/* find offset to next bar * and beat start
|
||||
*/
|
||||
|
||||
samplepos_t next_beat = 0;
|
||||
Temporal::Beats beats_now;
|
||||
|
||||
/* if next beat occurs in this process cycle, see if we have any triggers waiting
|
||||
*/
|
||||
|
||||
@@ -118,7 +112,7 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
//run_beats = true;
|
||||
//}
|
||||
|
||||
/* if there are any triggers queued, run them.
|
||||
/* if there are any triggers queued, make them active
|
||||
*/
|
||||
|
||||
RingBuffer<Trigger*>::rw_vector vec;
|
||||
@@ -128,25 +122,26 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
Trigger* t = vec.buf[0][n];
|
||||
t->bang (*this, beats_now, start_sample);
|
||||
active_triggers.push_back (t);
|
||||
cerr << "Trigger goes bang at " << start_sample << endl;
|
||||
}
|
||||
|
||||
for (uint32_t n = 0; n < vec.len[1]; ++n) {
|
||||
Trigger* t = vec.buf[1][n];
|
||||
t->bang (*this, beats_now, start_sample);
|
||||
active_triggers.push_back (t);
|
||||
cerr << "Trigger goes bang at " << start_sample << endl;
|
||||
}
|
||||
|
||||
_trigger_queue.increment_read_idx (vec.len[0] + vec.len[1]);
|
||||
|
||||
bool err = false;
|
||||
size_t chan = 0;
|
||||
const size_t nchans = bufs.count().get (DataType::AUDIO);
|
||||
const size_t nchans = the_region->n_channels ();
|
||||
bool need_butler = false;
|
||||
|
||||
for (Triggers::iterator t = active_triggers.begin(); !err && t != active_triggers.end(); ) {
|
||||
for (uint32_t chan = 0; chan < nchans; ++chan) {
|
||||
AudioBuffer& buf = bufs.get_audio (chan);
|
||||
buf.silence (nframes, 0);
|
||||
}
|
||||
|
||||
for (Triggers::iterator t = active_triggers.begin(); !err && t != active_triggers.end(); ++t) {
|
||||
|
||||
AudioTrigger* at = dynamic_cast<AudioTrigger*> (*t);
|
||||
|
||||
@@ -159,22 +154,30 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
AudioBuffer& buf = bufs.get_audio (chan);
|
||||
|
||||
pframes_t to_copy = nframes;
|
||||
|
||||
Sample* data = at->run (chan, to_copy, start_sample, end_sample, need_butler);
|
||||
|
||||
if (!data) {
|
||||
/* XXX need to delete the trigger/put it back in the pool */
|
||||
cerr << "trigger complete\n";
|
||||
t = active_triggers.erase (t);
|
||||
err = true;
|
||||
} else {
|
||||
if (t == active_triggers.begin()) {
|
||||
buf.read_from (data, to_copy);
|
||||
if (to_copy < nframes) {
|
||||
buf.silence (nframes - to_copy, to_copy);
|
||||
}
|
||||
} else {
|
||||
buf.accumulate_from (data, to_copy);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ChanCount cc (DataType::AUDIO, nchans);
|
||||
cc.set_midi (bufs.count().n_midi());
|
||||
bufs.set_count (cc);
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
@@ -194,24 +197,20 @@ TriggerBox::set_state (const XMLNode&, int version)
|
||||
|
||||
AudioTrigger::AudioTrigger (boost::shared_ptr<AudioRegion> r)
|
||||
: region (r)
|
||||
, running (false)
|
||||
, data (0)
|
||||
, read_index (0)
|
||||
, length (0)
|
||||
{
|
||||
/* XXX catch region going away */
|
||||
|
||||
const uint32_t nchans = region->n_channels();
|
||||
|
||||
cerr << "Trigger needs " << nchans << " channels of " << region->length() << " each\n";
|
||||
|
||||
length = region->length_samples();
|
||||
|
||||
for (uint32_t n = 0; n < nchans; ++n) {
|
||||
data.push_back (new Sample (length));;
|
||||
// region->read (data[n], 0, length, n);
|
||||
data.push_back (new Sample[length]);;
|
||||
read_index.push_back (0);
|
||||
region->read (data[n], 0, length, n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AudioTrigger::~AudioTrigger ()
|
||||
@@ -228,30 +227,28 @@ AudioTrigger::bang (TriggerBox& /*proc*/, Temporal::Beats const &, samplepos_t)
|
||||
* run()
|
||||
*/
|
||||
|
||||
read_index = 0;
|
||||
running = true;
|
||||
for (std::vector<samplecnt_t>::iterator ri = read_index.begin(); ri != read_index.end(); ++ri) {
|
||||
(*ri) = 0;
|
||||
}
|
||||
|
||||
_running = true;
|
||||
}
|
||||
|
||||
Sample*
|
||||
AudioTrigger::run (uint32_t channel, pframes_t& nframes, samplepos_t start_sample, samplepos_t end_sample, bool& need_butler)
|
||||
AudioTrigger::run (uint32_t channel, pframes_t& nframes, samplepos_t /*start_sample*/, samplepos_t /*end_sample*/, bool& /* need_butler */)
|
||||
{
|
||||
if (!running) {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_index >= length) {
|
||||
if (read_index[channel] >= length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (channel >= data.size()) {
|
||||
return 0;
|
||||
}
|
||||
channel %= data.size();
|
||||
|
||||
nframes = (pframes_t) std::min ((samplecnt_t) nframes, (length - read_index));
|
||||
nframes = (pframes_t) std::min ((samplecnt_t) nframes, (length - read_index[channel]));
|
||||
read_index[channel] += nframes;
|
||||
|
||||
Sample* ret = data[channel] + read_index;
|
||||
|
||||
read_index += nframes;
|
||||
|
||||
return ret;
|
||||
return data[channel] + read_index[channel];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user