From a5de06a050d8ba6a391b9241c61fef9a0992a77e Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 22 Jan 2014 15:25:39 +0100 Subject: backend for auditioning midi-files: * "downgrade" auditioner from AudioTrack to Track. * add relevant methods from both AudioTrack and MidiTrack. --- libs/ardour/ardour/audio_diskstream.h | 4 +- libs/ardour/ardour/auditioner.h | 57 ++++++- libs/ardour/ardour/midi_diskstream.h | 5 +- libs/ardour/auditioner.cc | 295 ++++++++++++++++++++++++++++------ 4 files changed, 302 insertions(+), 59 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 5a856e9b36..3a5dc2ad91 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -146,10 +146,8 @@ class AudioDiskstream : public Diskstream protected: friend class Auditioner; - int seek (framepos_t which_sample, bool complete_refill = false); - - protected: friend class AudioTrack; + int seek (framepos_t which_sample, bool complete_refill = false); int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal); frameoffset_t calculate_playback_distance (pframes_t nframes); diff --git a/libs/ardour/ardour/auditioner.h b/libs/ardour/ardour/auditioner.h index 7e772fe194..696dd1fb8e 100644 --- a/libs/ardour/ardour/auditioner.h +++ b/libs/ardour/ardour/auditioner.h @@ -26,6 +26,10 @@ #include "ardour/ardour.h" #include "ardour/audio_track.h" +#include "ardour/midi_region.h" + +#include "ardour/audio_diskstream.h" +#include "ardour/midi_diskstream.h" namespace ARDOUR { @@ -33,14 +37,14 @@ class Session; class AudioRegion; class AudioPlaylist; -class Auditioner : public AudioTrack +class Auditioner : public Track { public: Auditioner (Session&); ~Auditioner (); int init (); - int connect (); + int connect (); void audition_region (boost::shared_ptr); @@ -63,11 +67,52 @@ class Auditioner : public AudioTrack virtual ChanCount input_streams () const; frameoffset_t seek_frame() const { return _seeking ? _seek_frame : -1;} - void seek_response(frameoffset_t pos) { _seek_complete = true; if (_seeking) { current_frame = pos; _seek_complete = true;} } + void seek_response(frameoffset_t pos) { + _seek_complete = true; + if (_seeking) { current_frame = pos; _seek_complete = true;} + } + PBD::Signal2 AuditionProgress; + /* Track */ + int roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler); + DataType data_type () const; + + int roll_audio (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler); + int roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler); + + boost::shared_ptr create_diskstream (); + void set_diskstream (boost::shared_ptr ds); + + /* fake track */ + void set_state_part_two () {} + int set_state (const XMLNode&, int) { return 0; } + bool bounceable (boost::shared_ptr, bool) const { return false; } + void freeze_me (InterThreadInfo&) {} + void unfreeze () {} + + boost::shared_ptr bounce (InterThreadInfo&) + { return boost::shared_ptr (); } + + boost::shared_ptr bounce_range (framepos_t, framepos_t, InterThreadInfo&, boost::shared_ptr, bool) + { return boost::shared_ptr (); } + + int export_stuff (BufferSet&, framepos_t, framecnt_t, boost::shared_ptr, bool, bool) + { return -1; } + + boost::shared_ptr diskstream_factory (XMLNode const &) + { return boost::shared_ptr (); } + + boost::shared_ptr audio_diskstream() const + { return boost::dynamic_pointer_cast (_diskstream); } + + boost::shared_ptr midi_diskstream() const + { return boost::dynamic_pointer_cast (_diskstream); } + + private: boost::shared_ptr the_region; + boost::shared_ptr midi_region; framepos_t current_frame; mutable gint _auditioning; Glib::Threads::Mutex lock; @@ -76,6 +121,12 @@ class Auditioner : public AudioTrack bool _seeking; bool _seek_complete; bool via_monitor; + bool _midi_audition; + bool _synth_added; + + boost::shared_ptr _diskstream_audio; + boost::shared_ptr _diskstream_midi; + boost::shared_ptr asynth; void drop_ports (); static void *_drop_ports (void *); diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index b1c126b339..c2c3f5801f 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -118,11 +118,10 @@ class MidiDiskstream : public Diskstream static void set_readahead_frames (framecnt_t frames_ahead) { midi_readahead = frames_ahead; } - protected: - int seek (framepos_t which_sample, bool complete_refill = false); - protected: friend class MidiTrack; + friend class Auditioner; + int seek (framepos_t which_sample, bool complete_refill = false); int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream); frameoffset_t calculate_playback_distance (pframes_t nframes); diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index 75a40f142d..a0789b3034 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -21,17 +21,18 @@ #include "pbd/error.h" -#include "ardour/audio_diskstream.h" +#include "ardour/amp.h" #include "ardour/audioregion.h" #include "ardour/audioengine.h" -#include "ardour/delivery.h" -#include "ardour/route.h" -#include "ardour/session.h" -#include "ardour/auditioner.h" #include "ardour/audioplaylist.h" +#include "ardour/auditioner.h" #include "ardour/audio_port.h" #include "ardour/data_type.h" +#include "ardour/delivery.h" +#include "ardour/plugin.h" #include "ardour/region_factory.h" +#include "ardour/route.h" +#include "ardour/session.h" using namespace std; using namespace ARDOUR; @@ -40,31 +41,38 @@ using namespace PBD; #include "i18n.h" Auditioner::Auditioner (Session& s) - : AudioTrack (s, "auditioner", Route::Auditioner) - , current_frame (0) - , _auditioning (0) - , length (0) - , _seek_frame (-1) - , _seeking (false) - , _seek_complete (false) - , via_monitor (false) + : Track (s, "auditioner", Route::Auditioner) + , current_frame (0) + , _auditioning (0) + , length (0) + , _seek_frame (-1) + , _seeking (false) + , _seek_complete (false) + , via_monitor (false) + , _midi_audition (false) + , _synth_added (false) { } int Auditioner::init () { - if (Track::init ()) { - return -1; - } - + if (Track::init ()) { + return -1; + } + if (connect ()) { return -1; } + _output->add_port ("Midiaudition", this, DataType::MIDI); + boost::shared_ptr p = find_plugin (_session, "https://community.ardour.org/node/7596", ARDOUR::LV2); + assert(p); + asynth = boost::shared_ptr (new PluginInsert (_session, p)); + _output->changed.connect_same_thread (*this, boost::bind (&Auditioner::output_changed, this, _1, _2)); - return 0; + return 0; } Auditioner::~Auditioner () @@ -149,9 +157,138 @@ Auditioner::connect () return 0; } + +DataType +Auditioner::data_type () const { + if (_midi_audition) { + return DataType::MIDI; + } else { + return DataType::AUDIO; + } +} + +boost::shared_ptr +Auditioner::create_diskstream () { + + { + AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0); + dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Hidden); + _diskstream_audio = boost::shared_ptr (new AudioDiskstream (_session, name(), dflags)); + } + + { + MidiDiskstream::Flag dflags = MidiDiskstream::Flag (0); + dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Hidden); + _diskstream_midi = boost::shared_ptr (new MidiDiskstream (_session, name(), dflags)); + _diskstream_midi->do_refill_with_alloc (); + _diskstream_midi->playlist()->set_orig_track_id (id()); + } + + return _diskstream_audio; +} + +int +Auditioner::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler) { + if (_midi_audition) { + return roll_midi(nframes, start_frame, end_frame, declick, need_butler); + } else { + return roll_audio(nframes, start_frame, end_frame, declick, need_butler); + } +} + +int +Auditioner::roll_midi (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler) +{ + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); + if (!lm.locked()) { + return 0; + } + + assert(_active); + + framecnt_t playback_distance = nframes; + boost::shared_ptr diskstream = midi_diskstream(); + BufferSet& bufs = _session.get_route_buffers (n_process_buffers()); + + _silent = false; + MidiBuffer& mbuf (bufs.get_midi (0)); + diskstream->get_playback (mbuf, nframes); + + ChanCount cnt (DataType::MIDI, 1); + cnt.set (DataType::AUDIO, bufs.count().n_audio()); + bufs.set_count (cnt); + + process_output_buffers (bufs, start_frame, end_frame, nframes, + declick, (!diskstream->record_enabled() && !_session.transport_stopped())); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr d = boost::dynamic_pointer_cast (*i); + if (d) { + d->flush_buffers (nframes); + } + } + + need_butler = diskstream->commit (playback_distance); + return 0; +} + + +int +Auditioner::roll_audio (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler) { + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); + if (!lm.locked()) { + return 0; + } + + assert(n_outputs().n_total() > 0); + assert(_active); + + int dret; + framecnt_t playback_distance; + framepos_t transport_frame = _session.transport_frame(); + boost::shared_ptr diskstream = audio_diskstream(); + BufferSet& bufs = _session.get_route_buffers (n_process_buffers ()); + + _silent = false; + _amp->apply_gain_automation(false); + + if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) { + need_butler = diskstream->commit (playback_distance); + silence (nframes); + return dret; + } + + process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling())); + need_butler = diskstream->commit (playback_distance); + return 0; +} + +void +Auditioner::set_diskstream (boost::shared_ptr ds) +{ + Track::set_diskstream (ds); + + _diskstream->set_track (this); + _diskstream->set_destructive (_mode == Destructive); + _diskstream->set_non_layered (_mode == NonLayered); + _diskstream->set_record_enabled (false); + _diskstream->request_input_monitoring (false); + + DiskstreamChanged (); /* EMIT SIGNAL */ +} + AudioPlaylist& Auditioner::prepare_playlist () { + // used by CrossfadeEditor::audition() + + _midi_audition = false; + set_diskstream(_diskstream_audio); + if (_synth_added) { + remove_processor(asynth); + _synth_added = false; + } + // FIXME auditioner is still audio-only boost::shared_ptr apl = boost::dynamic_pointer_cast(_diskstream->playlist()); assert(apl); @@ -170,48 +307,100 @@ Auditioner::audition_region (boost::shared_ptr region) cancel_audition (); } - if (boost::dynamic_pointer_cast(region) == 0) { - error << _("Auditioning of non-audio regions not yet supported") << endmsg; - return; - } - Glib::Threads::Mutex::Lock lm (lock); - /* copy it */ + if (boost::dynamic_pointer_cast(region) != 0) { - boost::shared_ptr the_region (boost::dynamic_pointer_cast (RegionFactory::create (region))); - the_region->set_position (0); + _midi_audition = false; + set_diskstream(_diskstream_audio); + if (_synth_added) { + remove_processor(asynth); + _synth_added = false; + } + midi_region.reset(); - _diskstream->playlist()->drop_regions (); - _diskstream->playlist()->add_region (the_region, 0, 1); + /* copy it */ + the_region = boost::dynamic_pointer_cast (RegionFactory::create (region)); + the_region->set_position (0); - if (_diskstream->n_channels().n_audio() < the_region->n_channels()) { - audio_diskstream()->add_channel (the_region->n_channels() - _diskstream->n_channels().n_audio()); - } else if (_diskstream->n_channels().n_audio() > the_region->n_channels()) { - audio_diskstream()->remove_channel (_diskstream->n_channels().n_audio() - the_region->n_channels()); - } + _diskstream->playlist()->drop_regions (); + _diskstream->playlist()->add_region (the_region, 0, 1); - ProcessorStreams ps; - { - Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + if (_diskstream->n_channels().n_audio() < the_region->n_channels()) { + audio_diskstream()->add_channel (the_region->n_channels() - _diskstream->n_channels().n_audio()); + } else if (_diskstream->n_channels().n_audio() > the_region->n_channels()) { + audio_diskstream()->remove_channel (_diskstream->n_channels().n_audio() - the_region->n_channels()); + } + + ProcessorStreams ps; + { + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - if (configure_processors (&ps)) { - error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"), - _diskstream->n_channels()) << endmsg; - return; + if (configure_processors (&ps)) { + error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"), + _diskstream->n_channels()) << endmsg; + return; + } } + + } else if (boost::dynamic_pointer_cast(region)) { + _midi_audition = true; + set_diskstream(_diskstream_midi); + the_region.reset(); + + /* copy it */ + midi_region = (boost::dynamic_pointer_cast (RegionFactory::create (region))); + midi_region->set_position (0); + + _diskstream->playlist()->drop_regions (); + _diskstream->playlist()->add_region (midi_region, 0, 1); + midi_diskstream()->reset_tracker(); + + ProcessorStreams ps; + + if (!_synth_added) { + int rv = add_processor_by_index(asynth, PreFader, &ps, true); + if (rv) { + error << _("Failed to load synth for MIDI-Audition.") << endmsg; + } else { + _synth_added = true; + } + } else { + // TODO -- queue midi-panic // reset synth -> all notes off + // here or in first cycle.. + } + + { + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + + if (configure_processors (&ps)) { + error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"), + _diskstream->n_channels()) << endmsg; + return; + } + } + + } else { + error << _("Auditioning of regions other than Audio or Midi is not supported.") << endmsg; + return; } /* force a panner reset now that we have all channels */ - _main_outs->reset_panner(); _seek_frame = -1; _seeking = false; - length = the_region->length(); int dir; - framecnt_t offset = the_region->sync_offset (dir); + framecnt_t offset; + + if (_midi_audition) { + length = midi_region->length(); + offset = midi_region->sync_offset (dir); + } else { + length = the_region->length(); + offset = the_region->sync_offset (dir); + } /* can't audition from a negative sync point */ @@ -249,6 +438,7 @@ Auditioner::play_audition (framecnt_t nframes) _seek_complete = false; _seeking = false; _seek_frame = -1; + midi_diskstream()->reset_tracker(); } if(!_seeking) { @@ -270,6 +460,7 @@ Auditioner::play_audition (framecnt_t nframes) _seek_complete = false; _seeking = true; need_butler = true; + // TODO -- send midi-panic. -> all notes off } if (!_seeking) { @@ -325,15 +516,19 @@ Auditioner::output_changed (IOChange change, void* /*src*/) ChanCount Auditioner::input_streams () const { - /* auditioner never has any inputs - its channel configuration - depends solely on the region we are auditioning. - */ + /* auditioner never has any inputs - its channel configuration + depends solely on the region we are auditioning. + */ - if (audio_diskstream()) { - return audio_diskstream()->n_channels(); - } + if (!_midi_audition && audio_diskstream()) { + return audio_diskstream()->n_channels(); + } + if (_midi_audition && midi_diskstream()) { + ChanCount cnt (DataType::MIDI, 1); + return cnt; + } - return ChanCount (); + return ChanCount (); } MonitorState -- cgit v1.2.3