Call ARDOUR::cleanup at the end of libardour tests (from
[ardour.git] / libs / ardour / midi_track.cc
index e835008e67689800ddc1396f5e192ad3117dc38a..64e61e79f9f6406d2af8f7ed9cef628884a87c41 100644 (file)
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "pbd/error.h"
-
 #include "pbd/enumwriter.h"
 #include "pbd/convert.h"
-#include "midi++/events.h"
 #include "evoral/midi_util.h"
 
-#include "ardour/amp.h"
 #include "ardour/buffer_set.h"
 #include "ardour/debug.h"
 #include "ardour/delivery.h"
-#include "ardour/io_processor.h"
 #include "ardour/meter.h"
 #include "ardour/midi_diskstream.h"
 #include "ardour/midi_playlist.h"
 #include "ardour/midi_port.h"
-#include "ardour/midi_region.h"
-#include "ardour/midi_source.h"
 #include "ardour/midi_track.h"
-#include "ardour/panner.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
-#include "ardour/route_group_specialized.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
 #include "ardour/utils.h"
 
 #include "i18n.h"
 
+namespace ARDOUR {
+class InterThreadInfo;
+class MidiSource;
+class Region;
+class SMFSource;
+}
+
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
@@ -107,16 +105,21 @@ MidiTrack::set_record_enabled (bool yn, void *src)
 void
 MidiTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
 {
+       /* We have to do this here, as Track::set_diskstream will cause a buffer refill,
+          and the diskstream must be set up to fill its buffers using the correct _note_mode.
+       */
+       boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds);
+       mds->set_note_mode (_note_mode);
+       
        Track::set_diskstream (ds);
 
+       mds->reset_tracker ();  
+
        _diskstream->set_track (this);
        _diskstream->set_destructive (_mode == Destructive);
-
        _diskstream->set_record_enabled (false);
-       //_diskstream->monitor_input (false);
 
        _diskstream_data_recorded_connection.disconnect ();
-       boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds);
        mds->DataRecorded.connect_same_thread (
                _diskstream_data_recorded_connection,
                boost::bind (&MidiTrack::diskstream_data_recorded, this, _1));
@@ -135,6 +138,16 @@ MidiTrack::set_state (const XMLNode& node, int version)
 {
        const XMLProperty *prop;
 
+       /* This must happen before Track::set_state(), as there will be a buffer
+          fill during that call, and we must fill buffers using the correct
+          _note_mode.
+       */
+       if ((prop = node.property (X_("note-mode"))) != 0) {
+               _note_mode = NoteMode (string_2_enum (prop->value(), _note_mode));
+       } else {
+               _note_mode = Sustained;
+       }
+
        if (Track::set_state (node, version)) {
                return -1;
        }
@@ -142,12 +155,6 @@ MidiTrack::set_state (const XMLNode& node, int version)
        // No destructive MIDI tracks (yet?)
        _mode = Normal;
 
-       if ((prop = node.property (X_("note-mode"))) != 0) {
-               _note_mode = NoteMode (string_2_enum (prop->value(), _note_mode));
-       } else {
-               _note_mode = Sustained;
-       }
-
        if ((prop = node.property ("midi-thru")) != 0) {
                set_midi_thru (string_is_affirmative (prop->value()));
        }
@@ -269,6 +276,9 @@ MidiTrack::set_state_part_two ()
        return;
 }
 
+/** @param need_butler to be set to true if this track now needs the butler, otherwise it can be left alone
+ *  or set to false.
+ */
 int
 MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler)
 {
@@ -366,7 +376,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
                if (d) {
-                       d->flush_buffers (nframes, end_frame - start_frame - 1);
+                       d->flush_buffers (nframes);
                }
        }
 
@@ -391,6 +401,7 @@ void
 MidiTrack::realtime_locate ()
 {
        Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+
        if (!lm.locked ()) {
                return;
        }
@@ -398,12 +409,15 @@ MidiTrack::realtime_locate ()
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->realtime_locate ();
        }
+
+       midi_diskstream()->reset_tracker ();
 }
 
 void
 MidiTrack::realtime_handle_transport_stopped ()
 {
        Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+
        if (!lm.locked ()) {
                return;
        }
@@ -471,7 +485,8 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framep
 }
 
 int
-MidiTrack::export_stuff (BufferSet& /*bufs*/, framecnt_t /*nframes*/, framepos_t /*end_frame*/)
+MidiTrack::export_stuff (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framecnt_t /*nframes*/, 
+                        boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/, bool /*forexport*/)
 {
        return -1;
 }
@@ -485,7 +500,8 @@ MidiTrack::bounce (InterThreadInfo& /*itt*/)
 
 
 boost::shared_ptr<Region>
-MidiTrack::bounce_range (framepos_t /*start*/, framepos_t /*end*/, InterThreadInfo& /*itt*/, bool /*enable_processing*/)
+MidiTrack::bounce_range (framepos_t /*start*/, framepos_t /*end*/, InterThreadInfo& /*itt*/,
+                        boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/)
 {
        std::cerr << "MIDI bounce range currently unsupported" << std::endl;
        return boost::shared_ptr<Region> ();
@@ -516,7 +532,7 @@ MidiTrack::midi_panic()
 {
        DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers panic data\n", name()));
        for (uint8_t channel = 0; channel <= 0xF; channel++) {
-               uint8_t ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
+               uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), ((uint8_t) MIDI_CTL_SUSTAIN), 0 };
                write_immediate_event(3, ev);
                ev[1] = MIDI_CTL_ALL_NOTES_OFF;
                write_immediate_event(3, ev);
@@ -542,9 +558,9 @@ void
 MidiTrack::MidiControl::set_value(double val)
 {
        bool valid = false;
-       if (isinf(val)) {
+       if (std::isinf(val)) {
                cerr << "MIDIControl value is infinity" << endl;
-       } else if (isnan(val)) {
+       } else if (std::isnan(val)) {
                cerr << "MIDIControl value is NaN" << endl;
        } else if (val < _list->parameter().min()) {
                cerr << "MIDIControl value is < " << _list->parameter().min() << endl;
@@ -561,7 +577,7 @@ MidiTrack::MidiControl::set_value(double val)
        assert(val <= _list->parameter().max());
        if ( ! automation_playback()) {
                size_t size = 3;
-               uint8_t ev[3] = { _list->parameter().channel(), int(val), 0 };
+               uint8_t ev[3] = { _list->parameter().channel(), uint8_t (val), 0 };
                switch(_list->parameter().type()) {
                case MidiCCAutomation:
                        ev[0] += MIDI_CMD_CONTROL;
@@ -651,18 +667,6 @@ MidiTrack::diskstream_data_recorded (boost::weak_ptr<MidiSource> src)
        DataRecorded (src); /* EMIT SIGNAL */
 }
 
-bool
-MidiTrack::should_monitor () const
-{
-       return true;
-}
-
-bool
-MidiTrack::send_silence () const
-{
-       return false;
-}
-
 bool
 MidiTrack::input_active () const
 {
@@ -736,7 +740,7 @@ MidiTrack::act_on_mute ()
                        if ((1<<channel) & mask) {
 
                                DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers mute message to channel %2\n", name(), channel+1));
-                               uint8_t ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
+                               uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
                                write_immediate_event (3, ev);
                                ev[1] = MIDI_CTL_ALL_NOTES_OFF;
                                write_immediate_event (3, ev);
@@ -745,3 +749,40 @@ MidiTrack::act_on_mute ()
        }
 }
        
+void
+MidiTrack::set_monitoring (MonitorChoice mc)
+{
+       Track::set_monitoring (mc);
+
+       boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
+
+       if (md) {
+               md->reset_tracker ();
+       }
+}
+
+MonitorState
+MidiTrack::monitoring_state () const
+{
+       /* Explicit requests */
+       
+       if (_monitoring & MonitorInput) {
+               return MonitoringInput;
+       }
+               
+       if (_monitoring & MonitorDisk) {
+               return MonitoringDisk;
+       }
+
+       if (_session.transport_rolling()) {
+               return MonitoringDisk;
+       } 
+
+       /* the return value here doesn't mean that we're actually monitoring
+        * input, let alone input *audio*. but it means that we are NOT 
+        * monitoring silence. this allows us to still hear any audio generated
+        * by using internal generation techniques
+        */
+
+       return MonitoringInput;
+}