Fix displaying of notes in auto-created MIDI region when it's the first region in...
authorDavid Robillard <d@drobilla.net>
Sun, 14 Oct 2007 05:45:31 +0000 (05:45 +0000)
committerDavid Robillard <d@drobilla.net>
Sun, 14 Oct 2007 05:45:31 +0000 (05:45 +0000)
Fix crash after recording long phrases of MIDI.
Fix MIDI looping (kinda).
Add note-off exposure to MidiModel::iterator.
Fix first-note-is-stuck-note problem.
Fix resolving long notes while recording.
Fix several other things I forget now.  MIDI works pretty well.....

git-svn-id: svn://localhost/ardour2/trunk@2555 d708f5d6-7413-0410-9779-e7cbd77b26cf

29 files changed:
gtk2_ardour/ardour.bindings.in
gtk2_ardour/ardour.menus
gtk2_ardour/ardour2_ui_default.conf
gtk2_ardour/ardour_ui.cc
gtk2_ardour/canvas-hit.h
gtk2_ardour/canvas-midi-event.cc
gtk2_ardour/canvas-midi-event.h
gtk2_ardour/canvas-note.h
gtk2_ardour/editing_syms.h
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_mouse.cc
gtk2_ardour/main.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/midi_streamview.cc
gtk2_ardour/midi_time_axis.h
gtk2_ardour/public_editor.h
libs/ardour/ardour/midi_event.h
libs/ardour/ardour/midi_model.h
libs/ardour/midi_buffer.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_track.cc
libs/ardour/quantize.cc
libs/ardour/session.cc
libs/ardour/session_events.cc
libs/ardour/smf_source.cc
libs/ardour/source_factory.cc

index e8a918cb1fa3292b02e60becb5ebf577b559db73..c7ead238bbbae4de4d3be508958634e04791241a 100644 (file)
 ; (gtk_accel_path "<Actions>/Transport/TogglePunchOut" "")
 (gtk_accel_path "<Actions>/Editor/select-all-in-loop-range" "<Control>l")
 (gtk_accel_path "<Actions>/Editor/show-editor-mixer" "<Shift>e")
+(gtk_accel_path "<Actions>/Editor/show-editor-list" "<Shift>l")
 ; (gtk_accel_path "<Actions>/options/SoloInPlace" "")
 ; (gtk_accel_path "<Actions>/Main/Options" "")
 ; (gtk_accel_path "<Actions>/options/MeterFalloffMedium" "")
index a24041374bfbaad553861c3f688820c6d69aaf24..871aa15aee9c7171cc97ef99d2ed5dbab4fd8005 100644 (file)
                <menuitem action='ToggleMeasureVisibility'/>
               <separator/>
               <menuitem action='show-editor-mixer'/>
+              <menuitem action='show-editor-list'/>
               <menuitem action='SyncEditorAndMixerTrackOrder'/>
          </menu>
         <menu name='JACK' action='JACK'>
index 034dd75b0fd291c1ed89bdb66b7d9532c5c40968..721d8c31167ea0759752624961fbed43f3f68e31 100644 (file)
@@ -4,20 +4,20 @@
     <Option name="waveform" value="000000cc"/>
     <Option name="clipped waveform" value="ff0000e5"/>
     <Option name="region base" value="bfbfc1aa"/>
-    <Option name="selected region base" value="b591a8ff"/>
+    <Option name="selected region base" value="8888ffaa"/>
     <Option name="audio track base" value="c6d3d868"/>
     <Option name="audio bus base" value="dbd1ea68"/>
-    <Option name="midi track base" value="ff8f8f3d"/>
-    <Option name="midi bus base" value="ff0000ee"/>
+    <Option name="midi track base" value="c67e7e5f"/>
+       <Option name="midi bus base" value="ffceea40"/>
     <Option name="time-stretch-fill" value="e2b5b596"/>
     <Option name="time-stretch-outline" value="63636396"/>
     <Option name="automation line" value="44bc59ff"/>
     <Option name="processor automation line" value="7aa3f9ff"/>
-    <Option name="control point fill" value="000000ff"/>
-    <Option name="control point outline" value="000000ff"/>
+    <Option name="control point fill" value="ffffff66"/>
+    <Option name="control point outline" value="ffffffaa"/>
     <Option name="entered control point outline" value="ff0000ee"/>
     <Option name="entered control point selected" value="ff3535ff"/>
-    <Option name="entered control point" value="000000cc"/>
+    <Option name="entered control point" value="ffffffaa"/>
     <Option name="control point selected" value="00ff00ff"/>
     <Option name="control point" value="ff0000ff"/>
     <Option name="automation track fill" value="a0a0ce68"/>
@@ -40,7 +40,7 @@
     <Option name="location punch" value="7c3a3aff"/>
     <Option name="verbose canvas cursor" value="f4f214bc"/>
     <Option name="marker label" value="000000ff"/>
-    <Option name="marker bar separator" value="30303088"/>
+    <Option name="marker bar separator" value="aaaaaa77"/>
     <Option name="tempo bar" value="72727fff"/>
     <Option name="meterbar" value="666672ff"/>
     <Option name="markerbar" value="7f7f8cff"/>
@@ -60,8 +60,8 @@
     <Option name="EnteredMarker" value="dd6363ff"/>
     <Option name="MeterMarker" value="f2425bff"/>
     <Option name="TempoMarker" value="f2425bff"/>
-    <Option name="MeasureLineBeat" value="72727266"/>
-    <Option name="MeasureLineBar" value="8c8c988c"/>
+    <Option name="MeasureLineBeat" value="b5b5b576"/>
+    <Option name="MeasureLineBar" value="d9d9d99c"/>
     <Option name="GhostTrackBase" value="44007c7f"/>
     <Option name="GhostTrackWave" value="02fd004c"/>
     <Option name="GhostTrackWaveClip" value="ff000000"/>
@@ -74,8 +74,8 @@
     <Option name="RecordingRect" value="e5c6c6ff"/>
     <Option name="SelectionRect" value="e8f4d377"/>
     <Option name="Selection" value="636363b2"/>
-    <Option name="VestigialFrame" value="44007c0f"/>
-    <Option name="TimeAxisFrame" value="44007c0f"/>
+    <Option name="VestigialFrame" value="0000000f"/>
+    <Option name="TimeAxisFrame" value="0000000f"/>
     <Option name="NameHighlightFill" value="0000ffff"/>
     <Option name="NameHighlightOutline" value="7c00ff96"/>
     <Option name="FrameHandle" value="7c00ff96"/>
     <Option name="TrimHandle" value="1900ff44"/>
     <Option name="EditCursor" value="0000ffff"/>
     <Option name="PlayHead" value="ff0000ff"/>
+    <Option name="MidiSelectRectOutline" value="5555ffff"/>
+    <Option name="MidiSelectRectFill" value="8888ff88"/>
+    <Option name="MidiNoteOutlineMin" value="22ff22b0"/>
+    <Option name="MidiNoteOutlineMid" value="ffff22b0"/>
+    <Option name="MidiNoteOutlineMax" value="ff2222b0"/>
+    <Option name="MidiNoteFillMin" value="33ee338a"/>
+    <Option name="MidiNoteFillMid" value="eeee338a"/>
+    <Option name="MidiNoteFillMax" value="ee33338a"/>
+    <Option name="MidiNoteSelectedOutline" value="5566ffee"/>
   </Canvas>
 </Ardour>
 
index 962ada5035e787efcdb9ebdc4455aa6518b26e05..491939bd97663d86ac927d63c861acc565412e8b 100644 (file)
@@ -296,14 +296,14 @@ ARDOUR_UI::post_engine ()
        MIDI::Manager::instance()->set_api_data (engine->jack());
        setup_midi ();
 
-       check_memory_locking();
-
-               ActionManager::init ();
+       ActionManager::init ();
        _tooltips.enable();
 
        if (setup_windows ()) {
                throw failed_constructor ();
        }
+       
+       check_memory_locking();
 
        /* this is the first point at which all the keybindings are available */
 
index b924f981bb687f97e084dae4bbee9015819a367c..9a65f8067a7b26bdf1b3fb5da32b718b81ce0d5a 100644 (file)
@@ -29,8 +29,15 @@ namespace Canvas {
 
 class CanvasHit : public Diamond, public CanvasMidiEvent {
 public:
-       CanvasHit(MidiRegionView& region, Group& group, double size, const ARDOUR::Note* note=NULL)
-               : Diamond(group, size), CanvasMidiEvent(region, this, note) {}
+       CanvasHit(
+                       MidiRegionView&                       region,
+                       Group&                                group,
+                       double                                size,
+                       const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>())
+
+               : Diamond(group, size), CanvasMidiEvent(region, this, note)
+       {
+       }
        
        // FIXME
        double x1() { return 0.0; }
index 5981e7b78e3e7993b7f5bcac211857b57eb3e5fe..298743509085c871066360a00f4491253d2c7552 100644 (file)
@@ -31,24 +31,17 @@ namespace Gnome {
 namespace Canvas {
 
 
-CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note, bool copy_note)
+CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item,
+               const boost::shared_ptr<ARDOUR::Note> note)
        : _region(region)
        , _item(item)
        , _state(None)
-       , _note((copy_note && note) ? new ARDOUR::Note(*note) : note)
-       , _own_note(copy_note)
+       , _note(note)
        , _selected(false)
 {      
 }
 
 
-CanvasMidiEvent::~CanvasMidiEvent()
-{
-       if (_own_note)
-               delete _note;
-}
-
-       
 void
 CanvasMidiEvent::selected(bool yn)
 {
index d7b83bc2122b891621243db2f33bbbbb083e733e..3fa009ed33104d9754007fa2a17d58e8a3cd316e 100644 (file)
@@ -43,8 +43,12 @@ namespace Canvas {
  */
 class CanvasMidiEvent {
 public:
-       CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note=NULL, bool copy_note=false);
-       virtual ~CanvasMidiEvent();
+       CanvasMidiEvent(
+                       MidiRegionView&                       region,
+                       Item*                                 item,
+                       const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>());
+
+       virtual ~CanvasMidiEvent() {}
 
        bool on_event(GdkEvent* ev);
 
@@ -62,17 +66,17 @@ public:
        const Item* item() const { return _item; }
        Item*       item()       { return _item; }
 
-       const ARDOUR::Note* note() { return _note; }
+       const boost::shared_ptr<ARDOUR::Note> note() { return _note; }
 
 protected:
        enum State { None, Pressed, Dragging };
 
-       MidiRegionView&     _region;
-       Item* const         _item;
-       State               _state;
-       const ARDOUR::Note* _note;
-       bool                _own_note;
-       bool                _selected;
+       MidiRegionView&                       _region;
+       Item* const                           _item;
+       State                                 _state;
+       const boost::shared_ptr<ARDOUR::Note> _note;
+       bool                                  _own_note;
+       bool                                  _selected;
 };
 
 } // namespace Gnome
index 4fde2281ca5f32d2f983a5b956186f100a75d78c..3948765d66028d39204609757476e19ff4efaa00 100644 (file)
@@ -30,8 +30,12 @@ namespace Canvas {
 
 class CanvasNote : public SimpleRect, public CanvasMidiEvent {
 public:
-       CanvasNote(MidiRegionView& region, Group& group, const ARDOUR::Note* note=NULL, bool copy_note=false)
-               : SimpleRect(group), CanvasMidiEvent(region, this, note, copy_note)
+       CanvasNote(
+                       MidiRegionView&                       region,
+                       Group&                                group,
+                       const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>())
+
+               : SimpleRect(group), CanvasMidiEvent(region, this, note)
        {
        }
        
index a520b0d318a3414f291b1991574997f334a8edeb..f731d33efe7057f8ad9ddac8e9567dc694ae7683 100644 (file)
@@ -62,8 +62,8 @@ MOUSEMODE(MouseZoom)
 MOUSEMODE(MouseAudition)
 MOUSEMODE(MouseNote)
 
-MIDIEDITMODE(MidiEditSelect)
 MIDIEDITMODE(MidiEditPencil)
+MIDIEDITMODE(MidiEditSelect)
 MIDIEDITMODE(MidiEditErase)
 
 /* Changing this order will break the menu */
index f0a2bfa809c67a099271afccfb600719e4202c24..3a7009e7b73f2d034268fe73b35647fc23169f3e 100644 (file)
@@ -158,8 +158,8 @@ Gdk::Cursor* Editor::zoom_cursor = 0;
 Gdk::Cursor* Editor::time_fx_cursor = 0;
 Gdk::Cursor* Editor::fader_cursor = 0;
 Gdk::Cursor* Editor::speaker_cursor = 0;
-Gdk::Cursor* Editor::midi_select_cursor = 0;
 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
+Gdk::Cursor* Editor::midi_select_cursor = 0;
 Gdk::Cursor* Editor::midi_erase_cursor = 0;
 Gdk::Cursor* Editor::wait_cursor = 0;
 Gdk::Cursor* Editor::timebar_cursor = 0;
@@ -349,7 +349,7 @@ Editor::Editor ()
        range_marker_drag_rect = 0;
        marker_drag_line = 0;
        
-       set_midi_edit_mode (MidiEditSelect, true);
+       set_midi_edit_mode (MidiEditPencil, true);
        set_mouse_mode (MouseObject, true);
 
        frames_per_unit = 2048; /* too early to use reset_zoom () */
@@ -1310,8 +1310,8 @@ Editor::build_cursors ()
        time_fx_cursor = new Gdk::Cursor (SIZING);
        wait_cursor = new Gdk::Cursor  (WATCH);
        timebar_cursor = new Gdk::Cursor(LEFT_PTR);
-       midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
        midi_pencil_cursor = new Gdk::Cursor (PENCIL);
+       midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
        midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
 }
 
@@ -1666,12 +1666,14 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
        if (have_selected_audio_region) {
 
                Menu* envelopes_menu = manage (new Menu);
-               MenuList& envelopes_items = envelopes_menu->items();
+
                envelopes_menu->set_name ("ArdourContextMenu");
 
 #if FIXUP_REGION_MENU
 
    XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE                
+               
+               MenuList& envelopes_items = envelopes_menu->items();
 
                RegionView* rv = sv->find_view (ar);
                AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
@@ -2751,44 +2753,44 @@ Editor::setup_midi_toolbar ()
 
        vector<ToggleButton *> midi_tool_buttons;
 
-       midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
-       midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
-       midi_tool_buttons.push_back (&midi_tool_select_button);
        midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
        midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
        midi_tool_buttons.push_back (&midi_tool_pencil_button);
+       midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
+       midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
+       midi_tool_buttons.push_back (&midi_tool_select_button);
        midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
        midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
        midi_tool_buttons.push_back (&midi_tool_erase_button);
 
-       midi_tool_select_button.set_active(true);
+       midi_tool_pencil_button.set_active(true);
        
        midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
 
        midi_tool_button_box.set_border_width (2);
        midi_tool_button_box.set_spacing(4);
        midi_tool_button_box.set_spacing(1);
-       midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
        midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
+       midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
        midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
        midi_tool_button_box.set_homogeneous(true);
 
-       midi_tool_select_button.set_name ("MouseModeButton");
        midi_tool_pencil_button.set_name ("MouseModeButton");
+       midi_tool_select_button.set_name ("MouseModeButton");
        midi_tool_erase_button.set_name ("MouseModeButton");
 
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
        ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
+       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
        ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
 
-       midi_tool_select_button.unset_flags (CAN_FOCUS);
        midi_tool_pencil_button.unset_flags (CAN_FOCUS);
+       midi_tool_select_button.unset_flags (CAN_FOCUS);
        midi_tool_erase_button.unset_flags (CAN_FOCUS);
        
-       midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
-                               &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
        midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
                                &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
+       midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
+                               &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
        midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
                                &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
        
index 63cbc042ac359c7a06464e3c315479a8bd2f39ea..7e96f9c9c551823545750994e93b30451fdce588 100644 (file)
@@ -833,8 +833,8 @@ class Editor : public PublicEditor
        static Gdk::Cursor* time_fx_cursor;
        static Gdk::Cursor* fader_cursor;
        static Gdk::Cursor* speaker_cursor;
-       static Gdk::Cursor* midi_select_cursor;
        static Gdk::Cursor* midi_pencil_cursor;
+       static Gdk::Cursor* midi_select_cursor;
        static Gdk::Cursor* midi_erase_cursor;
        static Gdk::Cursor* wait_cursor;
        static Gdk::Cursor* timebar_cursor;
@@ -1137,6 +1137,8 @@ class Editor : public PublicEditor
        std::set<boost::shared_ptr<ARDOUR::Playlist> > motion_frozen_playlists;
        void region_drag_motion_callback (ArdourCanvas::Item*, GdkEvent*);
        void region_drag_finished_callback (ArdourCanvas::Item*, GdkEvent*);
+       void create_region_drag_motion_callback (ArdourCanvas::Item*, GdkEvent*);
+       void create_region_drag_finished_callback (ArdourCanvas::Item*, GdkEvent*);
 
        bool _dragging_playhead;
 
@@ -1157,6 +1159,7 @@ class Editor : public PublicEditor
        gint mouse_rename_region (ArdourCanvas::Item*, GdkEvent*);
 
        void start_region_grab (ArdourCanvas::Item*, GdkEvent*);
+       void start_create_region_grab (ArdourCanvas::Item*, GdkEvent*);
        void start_region_copy_grab (ArdourCanvas::Item*, GdkEvent*);
        void start_region_brush_grab (ArdourCanvas::Item*, GdkEvent*);
        void start_selection_grab (ArdourCanvas::Item*, GdkEvent*);
@@ -1439,8 +1442,8 @@ class Editor : public PublicEditor
 
        Gtk::HBox                midi_tool_button_box;
        Gtkmm2ext::TearOff*      midi_tool_tearoff;
-       Gtk::ToggleButton        midi_tool_select_button;
        Gtk::ToggleButton        midi_tool_pencil_button;
+       Gtk::ToggleButton        midi_tool_select_button;
        Gtk::ToggleButton        midi_tool_erase_button;
        GroupedButtons          *midi_tool_button_set;
        void                     midi_edit_mode_toggled (Editing::MidiEditMode m);
index da95d50d95949e8088db8361d67a6d1850879f80..c6bbf5ca5fe1eee741d2c9f897acf0edfad275c7 100644 (file)
@@ -28,6 +28,7 @@
 #include <pbd/error.h>
 #include <gtkmm2ext/utils.h>
 #include <pbd/memento_command.h>
+#include <pbd/basename.h>
 
 #include "ardour_ui.h"
 #include "editor.h"
@@ -52,6 +53,7 @@
 #include <ardour/route.h>
 #include <ardour/audio_track.h>
 #include <ardour/audio_diskstream.h>
+#include <ardour/midi_diskstream.h>
 #include <ardour/playlist.h>
 #include <ardour/audioplaylist.h>
 #include <ardour/audioregion.h>
@@ -59,6 +61,7 @@
 #include <ardour/dB.h>
 #include <ardour/utils.h>
 #include <ardour/region_factory.h>
+#include <ardour/source_factory.h>
 
 #include <bitset>
 
@@ -318,22 +321,19 @@ Editor::midi_edit_mode_toggled (MidiEditMode m)
        }
 
        switch (m) {
-       case MidiEditSelect:
-               if (midi_tool_select_button.get_active()) {
+       case MidiEditPencil:
+               if (midi_tool_pencil_button.get_active())
                        set_midi_edit_mode (m);
-               }
                break;
-       
-       case MidiEditPencil:
-               if (midi_tool_pencil_button.get_active()) {
+
+       case MidiEditSelect:
+               if (midi_tool_select_button.get_active())
                        set_midi_edit_mode (m);
-               }
                break;
-       
+
        case MidiEditErase:
-               if (midi_tool_erase_button.get_active()) {
+               if (midi_tool_erase_button.get_active())
                        set_midi_edit_mode (m);
-               }
                break;
 
        default:
@@ -362,14 +362,14 @@ Editor::set_midi_edit_mode (MidiEditMode m, bool force)
        ignore_midi_edit_mode_toggle = true;
 
        switch (midi_edit_mode) {
-       case MidiEditSelect:
-               midi_tool_select_button.set_active (true);
-               break;
-       
        case MidiEditPencil:
                midi_tool_pencil_button.set_active (true);
                break;
-       
+
+       case MidiEditSelect:
+               midi_tool_select_button.set_active (true);
+               break;
+
        case MidiEditErase:
                midi_tool_erase_button.set_active (true);
                break;
@@ -388,12 +388,14 @@ void
 Editor::set_midi_edit_cursor (MidiEditMode m)
 {
        switch (midi_edit_mode) {
-       case MidiEditSelect:
-               current_canvas_cursor = midi_select_cursor;
-               break;
        case MidiEditPencil:
                current_canvas_cursor = midi_pencil_cursor;
                break;
+
+       case MidiEditSelect:
+               current_canvas_cursor = midi_select_cursor;
+               break;
+
        case MidiEditErase:
                current_canvas_cursor = midi_erase_cursor;
                break;
@@ -777,6 +779,10 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        /* rest handled in motion & release */
                        break;
 
+               case MouseNote:
+                       start_create_region_grab (item, event);
+                       break;
+               
                default:
                        break;
                }
@@ -1117,7 +1123,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                session->request_transport_speed (0.0);
                        }
                        break;
-
+                       
                default:
                        break;
 
@@ -1621,6 +1627,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        case MouseRange:
        case MouseZoom:
        case MouseTimeFX:
+       case MouseNote:
                if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
                                       (event->motion.state & GDK_BUTTON2_MASK))) {
                        if (!from_autoscroll) {
@@ -2792,6 +2799,19 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
        begin_reversible_command (_("move region(s)"));
 }
 
+void
+Editor::start_create_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
+{
+       drag_info.copy = false;
+       drag_info.item = item;
+       drag_info.data = clicked_axisview;
+       drag_info.last_trackview = clicked_axisview;
+       drag_info.motion_callback = &Editor::create_region_drag_motion_callback;
+       drag_info.finished_callback = &Editor::create_region_drag_finished_callback;
+
+       start_grab (event);
+}
+
 void
 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
@@ -3605,6 +3625,59 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        }
 }
 
+       
+void
+Editor::create_region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+       if (drag_info.move_threshold_passed) {
+               if (drag_info.first_move) {
+                       // TODO: create region-create-drag region view here
+                       drag_info.first_move = false;
+               }
+
+               // TODO: resize region-create-drag region view here
+       }
+} 
+
+void
+Editor::create_region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+       MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (drag_info.last_trackview);
+       if (!mtv)
+               return;
+
+       const boost::shared_ptr<MidiDiskstream> diskstream =
+               boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream());
+       
+       if (!diskstream) {
+               warning << "Cannot create non-MIDI region" << endl;
+               return;
+       }
+
+       if (drag_info.first_move) {
+               begin_reversible_command (_("create region"));
+               XMLNode &before = mtv->playlist()->get_state();
+
+               nframes_t start = drag_info.grab_frame;
+               snap_to (start, -1);
+               const Meter& m = session->tempo_map().meter_at(start);
+               const Tempo& t = session->tempo_map().tempo_at(start);
+               double length = m.frames_per_bar(t, session->frame_rate());
+
+               boost::shared_ptr<Source> src = session->create_midi_source_for_session(*diskstream.get());
+                               
+               mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>(RegionFactory::create(
+                               src, 0, length, PBD::basename_nosuffix(src->name()))), start);
+               XMLNode &after = mtv->playlist()->get_state();
+               session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
+               commit_reversible_command();
+
+       } else {
+               create_region_drag_motion_callback (item, event);
+               // TODO: create region-create-drag region here
+       }
+}
+
 void
 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
 {
index 1e9b27d8a7eac1178f3c829120529cf131b7e719..5203346d57ba77b9ed08b1b1146d416e1328ea81 100644 (file)
@@ -57,7 +57,7 @@ TextReceiver text_receiver ("ardour");
 extern int curvetest (string);
 
 static ARDOUR_UI  *ui = 0;
-static char* localedir = LOCALEDIR;
+static const char* localedir = LOCALEDIR;
 
 gint
 show_ui_callback (void *arg)
index 7dcba64baea63a42d53b5bfbb678563f3418117a..ec326f1e2ea23f733c7ffff409ab7418daaddef4 100644 (file)
@@ -302,7 +302,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                                clear_selection();
                                break;
                        case MidiEditPencil:
-                               trackview.editor.snap_to(event_frame);
+                               trackview.editor.snap_to(event_frame, -1);
                                event_x = trackview.editor.frame_to_pixel(event_frame);
                                create_note_at(event_x, event_y, _default_note_length);
                        default:
@@ -359,9 +359,9 @@ MidiRegionView::create_note_at(double x, double y, double dur)
        //double dur = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar();
 
        // Add a 1 beat long note (for now)
-       const Note new_note(stamp, dur, (uint8_t)note, 0x40);
+       const boost::shared_ptr<Note> new_note(new Note(stamp, dur, (uint8_t)note, 0x40));
        
-       view->update_bounds(new_note.note());
+       view->update_bounds(new_note->note());
 
        MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
        cmd->add(new_note);
@@ -406,7 +406,7 @@ MidiRegionView::redisplay_model()
                _model->read_lock();
 
                for (size_t i=0; i < _model->n_notes(); ++i)
-                       add_note(_model->note_at(i), false);
+                       add_note(_model->note_at(i));
 
                end_write();
 
@@ -596,30 +596,34 @@ MidiRegionView::extend_active_notes()
  * event arrives, to properly display the note.
  */
 void
-MidiRegionView::add_note(const Note& note, bool copy_note)
+MidiRegionView::add_note(const boost::shared_ptr<Note> note)
 {
-       assert(note.time() >= 0);
-       //assert(note.time() < _region->length());
+       assert(note->time() >= 0);
+       //assert(note->time() < _region->length());
 
        ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
        
        if (midi_view()->note_mode() == Sustained) {
-               const double y1 = midi_stream_view()->note_to_y(note.note());
+       
+               //cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time()
+               //      << " .. " << note->end_time() << endl;
+
+               const double y1 = midi_stream_view()->note_to_y(note->note());
 
-               CanvasNote* ev_rect = new CanvasNote(*this, *group, &note, copy_note);
-               ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note.time());
+               CanvasNote* ev_rect = new CanvasNote(*this, *group, note);
+               ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note->time());
                ev_rect->property_y1() = y1;
-               if (note.duration() > 0)
-                       ev_rect->property_x2() = trackview.editor.frame_to_pixel((nframes_t)(note.end_time()));
+               if (note->duration() > 0)
+                       ev_rect->property_x2() = trackview.editor.frame_to_pixel((nframes_t)(note->end_time()));
                else
                        ev_rect->property_x2() = trackview.editor.frame_to_pixel(_region->length());
                ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height());
 
-               ev_rect->property_fill_color_rgba() = note_fill_color(note.velocity());
-               ev_rect->property_outline_color_rgba() = note_outline_color(note.velocity());
+               ev_rect->property_fill_color_rgba() = note_fill_color(note->velocity());
+               ev_rect->property_outline_color_rgba() = note_outline_color(note->velocity());
 
-               if (note.duration() == 0) {
-                       _active_notes[note.note()] = ev_rect;
+               if (note->duration() == 0) {
+                       _active_notes[note->note()] = ev_rect;
                        /* outline all but right edge */
                        ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8);
                } else {
@@ -631,15 +635,18 @@ MidiRegionView::add_note(const Note& note, bool copy_note)
                _events.push_back(ev_rect);
 
        } else if (midi_view()->note_mode() == Percussive) {
+               
+               //cerr << "MRV::add_note percussive " << note->note() << " @ " << note->time() << endl;
+               
                const double diamond_size = midi_stream_view()->note_height() / 2.0;
-               const double x = trackview.editor.frame_to_pixel((nframes_t)note.time());
-               const double y = midi_stream_view()->note_to_y(note.note()) + ((diamond_size-2) / 4.0);
+               const double x = trackview.editor.frame_to_pixel((nframes_t)note->time());
+               const double y = midi_stream_view()->note_to_y(note->note()) + ((diamond_size-2) / 4.0);
 
                CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size);
                ev_diamond->move(x, y);
                ev_diamond->show();
-               ev_diamond->property_fill_color_rgba() = note_fill_color(note.velocity());
-               ev_diamond->property_outline_color_rgba() = note_outline_color(note.velocity());
+               ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity());
+               ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity());
                _events.push_back(ev_diamond);
        }
 }
@@ -651,7 +658,7 @@ MidiRegionView::delete_selection()
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i)
                if ((*i)->selected())
-                       _delta_command->remove(*(*i)->note());
+                       _delta_command->remove((*i)->note());
 
        _selection.clear();
 }
@@ -755,10 +762,10 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
 
                for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                        command_remove_note(*i);
-                       Note copy(*(*i)->note()); 
+                       const boost::shared_ptr<Note> copy(new Note(*(*i)->note().get())); 
 
-                       copy.set_time((*i)->note()->time() + dt);
-                       copy.set_note((*i)->note()->note() + dnote);
+                       copy->set_time((*i)->note()->time() + dt);
+                       copy->set_note((*i)->note()->note() + dnote);
 
                        command_add_note(copy);
                }
@@ -773,7 +780,7 @@ MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
        if (ev->note() && _mouse_state == EraseTouchDragging) {
                start_delta_command();
                ev->selected(true);
-               _delta_command->remove(*ev->note());
+               _delta_command->remove(ev->note());
        } else if (_mouse_state == SelectTouchDragging) {
                note_selected(ev, true);
        }
index 6b0dcd18047cad06a57464f5b322f0c8c0bf72e6..20c7671f5bbc0377a3836ba9d304c452d4e510ff 100644 (file)
@@ -76,7 +76,7 @@ class MidiRegionView : public RegionView
 
     GhostRegion* add_ghost (AutomationTimeAxisView&);
 
-       void add_note(const ARDOUR::Note& note, bool copy_note);
+       void add_note(const boost::shared_ptr<ARDOUR::Note> note);
        void resolve_note(uint8_t note_num, double end_time);
 
        void begin_write();
@@ -99,14 +99,14 @@ class MidiRegionView : public RegionView
                        _delta_command = _model->new_delta_command();
        }
        
-       void command_add_note(ARDOUR::Note& note) {
+       void command_add_note(const boost::shared_ptr<ARDOUR::Note> note) {
                if (_delta_command)
                        _delta_command->add(note);
        }
 
        void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
                if (_delta_command && ev->note()) {
-                       _delta_command->remove(*ev->note());
+                       _delta_command->remove(ev->note());
                        ev->selected(true);
                }
        }
index a2b4229650eb6f835b085f4036e7783c7c03c9b2..9e0f9f368f2156c0b0bdf3235fd26846eb19d269 100644 (file)
@@ -146,13 +146,10 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
        if (load_model)
                source->load_model();
 
-       if (source->model()) {
-               // Find our note range
-               for (size_t i=0; i < source->model()->n_notes(); ++i) {
-                       const Note& note = source->model()->note_at(i);
-                       update_bounds(note.note());
-               }
-       }
+       // Find our note range
+       if (source->model())
+               for (size_t i=0; i < source->model()->n_notes(); ++i)
+                       update_bounds(source->model()->note_at(i)->note());
        
        // Display region contents
        region_view->display_model(source->model());
@@ -467,24 +464,26 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
                                                MidiRegionView* mrv = (MidiRegionView*)iter->second;
                                                for (size_t i=0; i < data->n_notes(); ++i) {
 
-                                                       const Note& note = data->note_at(i);
+                                                       // FIXME: slooooooooow!
 
-                                                       if (note.time() + region->position() < start)
+                                                       const boost::shared_ptr<Note> note = data->note_at(i);
+                                                       
+                                                       if (note->duration() > 0 && note->end_time() + region->position() > start)
+                                                               mrv->resolve_note(note->note(), note->end_time());
+
+                                                       if (note->time() + region->position() < start)
                                                                continue;
 
-                                                       if (note.time() + region->position() > start + dur)
+                                                       if (note->time() + region->position() > start + dur)
                                                                break;
 
-                                                       mrv->add_note(note, true);
-                                                       
-                                                       if (note.duration() > 0 && note.end_time() >= start)
-                                                               mrv->resolve_note(note.note(), note.end_time());
+                                                       mrv->add_note(note);
 
-                                                       if (note.note() < _lowest_note) {
-                                                               _lowest_note = note.note();
+                                                       if (note->note() < _lowest_note) {
+                                                               _lowest_note = note->note();
                                                                update_range = true;
-                                                       } else if (note.note() > _highest_note) {
-                                                               _highest_note = note.note();
+                                                       } else if (note->note() > _highest_note) {
+                                                               _highest_note = note->note();
                                                                update_range = true;
                                                        }
                                                }
index a35a332e01922be83c9a3412f5fbc55db1715ddb..f7ec164edc24f5da9e3ec4b3fa0aa13f9f93780e 100644 (file)
@@ -42,7 +42,6 @@
 
 namespace ARDOUR {
        class Session;
-       class MidiDiskstream;
        class RouteGroup;
        class Processor;
        class Location;
index 871ec0fb9c19ee18b1fa614e393a0df46be06e5f..03d5897c1a4dbc9bf33cd52ea6b8680cdbec0aa2 100644 (file)
@@ -146,7 +146,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
         */
        virtual Editing::MouseMode current_mouse_mode () const = 0;
        
-       /** Set the midi edit mode (select, pencil, eraser, etc.)
+       /** Set the midi edit mode (pencil, select, eraser, etc.)
         * @param m Midi edit mode (defined in editing_syms.h)
         * @param force Perform the effects of the change even if no change is required
         * (ie even if the current midi edit mode is equal to \ref m)
index c430c708b7f336d13f589d95aa2c54d9282b24a1..ee6ea7b749c49fccd4a96fcf3c7dae8f2c2be400 100644 (file)
@@ -83,16 +83,19 @@ struct MidiEvent {
 
        inline const MidiEvent& operator=(const MidiEvent& copy) {
                _time = copy._time;
-               if (!_owns_buffer) {
-                       _buffer = copy._buffer;
-               } else if (copy._buffer) {
-                       if (!_buffer || _size < copy._size)
-                               _buffer = (Byte*)realloc(_buffer, copy._size);
-                       memcpy(_buffer, copy._buffer, copy._size);
+               if (_owns_buffer) {
+                       if (copy._buffer) {
+                               if (!_buffer || _size < copy._size)
+                                       _buffer = (Byte*)realloc(_buffer, copy._size);
+                               memcpy(_buffer, copy._buffer, copy._size);
+                       } else {
+                               free(_buffer);
+                               _buffer = NULL;
+                       }
                } else {
-                       free(_buffer);
-                       _buffer = NULL;
+                       _buffer = copy._buffer;
                }
+
                _size = copy._size;
                return *this;
        }
index 28a747683c3643bfdc04a63859edf72c7b415710..8e7d7867225546f10f77b0dae92c3d50c6906115 100644 (file)
@@ -22,6 +22,7 @@
 #define __ardour_midi_model_h__
 
 #include <queue>
+#include <deque>
 #include <utility>
 #include <boost/utility.hpp>
 #include <glibmm/thread.h>
@@ -72,20 +73,24 @@ public:
        /** Resizes vector if necessary (NOT realtime safe) */
        void append(const MidiEvent& ev);
        
-       inline const Note& note_at(unsigned i) const { return _notes[i]; }
+       inline const boost::shared_ptr<const Note> note_at(unsigned i) const { return _notes[i]; }
+       inline const boost::shared_ptr<Note>       note_at(unsigned i)       { return _notes[i]; }
 
        inline size_t n_notes() const { return _notes.size(); }
        inline bool   empty()   const { return _notes.size() == 0 && _controls.size() == 0; }
 
-       typedef std::vector<Note> Notes;
+       /* FIXME: use better data structure */
+       typedef std::vector< boost::shared_ptr<Note> > Notes;
        
-       inline static bool note_time_comparator (const Note& a, const Note& b) { 
-               return a.time() < b.time();
+       inline static bool note_time_comparator (const boost::shared_ptr<const Note> a,
+                                                const boost::shared_ptr<const Note> b) { 
+               return a->time() < b->time();
        }
 
        struct LaterNoteEndComparator {
                typedef const Note* value_type;
-               inline bool operator()(const Note* const a, const Note* const b) { 
+               inline bool operator()(const boost::shared_ptr<const Note> a,
+                                      const boost::shared_ptr<const Note> b) const { 
                        return a->end_time() > b->end_time();
                }
        };
@@ -111,14 +116,14 @@ public:
                /*int set_state (const XMLNode&);
                XMLNode& get_state ();*/
 
-               void add(const Note& note);
-               void remove(const Note& note);
+               void add(const boost::shared_ptr<Note> note);
+               void remove(const boost::shared_ptr<Note> note);
 
        private:
-               MidiModel&      _model;
-               std::string     _name;
-               std::list<Note> _added_notes;
-               std::list<Note> _removed_notes;
+               MidiModel&                           _model;
+               const std::string                    _name;
+               std::list< boost::shared_ptr<Note> > _added_notes;
+               std::list< boost::shared_ptr<Note> > _removed_notes;
        };
 
        MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
@@ -140,19 +145,28 @@ public:
                const_iterator(const MidiModel& model, double t);
                ~const_iterator();
 
+               inline bool locked() const { return _locked; }
+
                const MidiEvent& operator*()  const { return _event; }
                const MidiEvent* operator->() const { return &_event; }
 
                const const_iterator& operator++(); // prefix only
                bool operator==(const const_iterator& other) const;
                bool operator!=(const const_iterator& other) const { return ! operator==(other); }
+               
+               const_iterator& operator=(const const_iterator& other);
 
        private:
+               friend class MidiModel;
+
                const MidiModel* _model;
                MidiEvent        _event;
 
-               typedef std::priority_queue<const Note*,std::vector<const Note*>, LaterNoteEndComparator>
-                               ActiveNotes;
+               typedef std::priority_queue<
+                               boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
+                               LaterNoteEndComparator>
+                       ActiveNotes;
+               
                mutable ActiveNotes _active_notes;
 
                bool                                       _is_end;
@@ -167,8 +181,8 @@ public:
        
 private:
        friend class DeltaCommand;
-       void add_note_unlocked(const Note& note);
-       void remove_note_unlocked(const Note& note);
+       void add_note_unlocked(const boost::shared_ptr<Note> note);
+       void remove_note_unlocked(const boost::shared_ptr<const Note> note);
 
        friend class const_iterator;
        bool control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) const;
@@ -193,16 +207,13 @@ private:
 
        const const_iterator _end_iter;
 
-       mutable nframes_t     _next_read;
+       mutable nframes_t      _next_read;
        mutable const_iterator _read_iter;
 
-       // note state for read():
-       // (TODO: Remove and replace with iterator)
-       
-       typedef std::priority_queue<const Note*,std::vector<const Note*>,
-                       LaterNoteEndComparator> ActiveNotes;
-
-       //mutable ActiveNotes _active_notes;
+       typedef std::priority_queue<
+                       boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
+                       LaterNoteEndComparator>
+               ActiveNotes;
 };
 
 } /* namespace ARDOUR */
index 2b476899117b28433799de866c7ec243c3caf910..e971e9ae8ff1cae71f8a7ba920c94b18a742bbc9 100644 (file)
@@ -193,8 +193,8 @@ void
 MidiBuffer::silence(nframes_t dur, nframes_t offset)
 {
        // FIXME use parameters
-       assert(offset == 0);
-       //assert(dur == _capacity);
+       if (offset != 0)
+               cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
 
        memset(_events, 0, sizeof(MidiEvent) * _capacity);
        memset(_data, 0, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
index 2b8f70a307c6e1b6d9437e87ac1e08f4c076b3ef..3a2842be7a91fcbd23be6381667dce46d389c2e8 100644 (file)
@@ -141,7 +141,10 @@ MidiDiskstream::~MidiDiskstream ()
 void
 MidiDiskstream::non_realtime_locate (nframes_t position)
 {
+       //cerr << "MDS: non_realtime_locate: " << position << endl;
+       assert(_write_source);
        _write_source->set_timeline_position (position);
+       seek(position, true); // correct?
 }
 
 
@@ -204,25 +207,7 @@ MidiDiskstream::get_input_sources ()
 
        _source_port = _io->midi_input(0);
 
-       /* I don't get it....
-       const char **connections = _io->input(0)->get_connections ();
-
-       if (connections == 0 || connections[0] == 0) {
-
-               if (_source_port) {
-                       // _source_port->disable_metering ();
-               }
-
-               _source_port = 0;
-
-       } else {
-               _source_port = dynamic_cast<MidiPort*>(
-                       _session.engine().get_port_by_name (connections[0]) );
-       }
-
-       if (connections) {
-               free (connections);
-       }*/
+       // do... stuff?
 }              
 
 int
@@ -685,6 +670,7 @@ MidiDiskstream::set_pending_overwrite (bool yn)
 int
 MidiDiskstream::overwrite_existing_buffers ()
 {
+       cerr << "MDS: overwrite_existing_buffers() (does nothing)" << endl;
        return 0;
 }
 
@@ -693,6 +679,8 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
 {
        Glib::Mutex::Lock lm (state_lock);
        int ret = -1;
+       
+       //cerr << "MDS: seek: " << frame << endl;
 
        _playback_buf->reset();
        _capture_buf->reset();
@@ -722,6 +710,8 @@ MidiDiskstream::can_internal_playback_seek (nframes_t distance)
 int
 MidiDiskstream::internal_playback_seek (nframes_t distance)
 {
+       cerr << "MDS: internal_playback_seek " << distance << endl;
+
        first_recordable_frame += distance;
        playback_sample += distance;
 
@@ -1203,6 +1193,10 @@ MidiDiskstream::engage_record_enable ()
                _source_port->request_monitor_input (!(Config->get_auto_input() && rolling));
        }
 
+       // FIXME: Why is this necessary?  Isn't needed for AudioDiskstream...
+       if (!_write_source)
+               use_new_write_source();
+
        _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
 
        RecordEnableChanged (); /* EMIT SIGNAL */
@@ -1405,6 +1399,7 @@ MidiDiskstream::reset_write_sources (bool mark_write_complete, bool force)
        if (_write_source && mark_write_complete) {
                _write_source->mark_streaming_write_completed ();
        }
+
        use_new_write_source (0);
                        
        if (record_enabled()) {
index d7167ed2ecfb8e43a57463213fec9aebf16f1816..9a87e89ab8c3fdd4143748eb1aeb71843785889e 100644 (file)
@@ -42,7 +42,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        , _is_end( (t == DBL_MAX) || model.empty())
        , _locked( ! _is_end)
 {
-       //cerr << "Created MIDI iterator @ " << t << "(is end: " << _is_end << ")" << endl;
+       //cerr << "Created MIDI iterator @ " << t << " (is end: " << _is_end << ")" << endl;
        
        if (_is_end)
                return;
@@ -52,7 +52,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        _note_iter = model.notes().end();
 
        for (MidiModel::Notes::const_iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
-               if ((*i).time() >= t) {
+               if ((*i)->time() >= t) {
                        _note_iter = i;
                        break;
                }
@@ -70,8 +70,8 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
                double x, y;
                bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
                if (!ret) {
-                       cerr << "MIDI Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
-                               << ") has no events past " << t << endl;
+                       /*cerr << "MIDI Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
+                               << ") has no events past " << t << endl;*/
                        continue;
                } 
 
@@ -92,7 +92,8 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        }
 
        if (_note_iter != model.notes().end()) {
-               _event = MidiEvent(_note_iter->on_event(), false);
+               _event = MidiEvent((*_note_iter)->on_event(), false);
+               _active_notes.push(*_note_iter);
                ++_note_iter;
        }
 
@@ -106,9 +107,9 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
                _is_end = true;
                _model->read_unlock();
                _locked = false;
-       //} else {
-       //      printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
-       }
+       } /*else {
+               printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
+       }*/
 }
 
 
@@ -155,30 +156,51 @@ MidiModel::const_iterator::operator++()
                }
        }
        
-       enum Type { NIL, NOTE, CC };
-       Type type = NIL;
+       enum Type { NIL, NOTE_ON, NOTE_OFF, CC };
+       
+       Type   type = NIL;
+       double t    = 0;
 
-       if (_note_iter != _model->notes().end())
-               type = NOTE;
+       // Next earliest note on
+       if (_note_iter != _model->notes().end()) {
+               type = NOTE_ON;
+               t = (*_note_iter)->time();
+       }
        
+       // Use the next earliest note off iff it's earlier than the note on
+       if (_model->note_mode() == Sustained && (! _active_notes.empty())) {
+               if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
+                       type = NOTE_OFF;
+                       t = _active_notes.top()->end_time();
+               }
+       }
+       
+       // Use the next earliest controller iff it's earlier than the note event
        if (_control_iter != _control_iters.end() && _control_iter->second.first != DBL_MAX)
-               if (_note_iter == _model->notes().end() || _control_iter->second.first < _note_iter->time())
+               if (type == NIL || _control_iter->second.first < t)
                        type = CC;
 
-       if (type == NOTE) {
-               //cerr << "MIDI Iterator = note" << endl;
-               _event = MidiEvent(_note_iter->on_event(), false);
+       if (type == NOTE_ON) {
+               //cerr << "********** MIDI Iterator = note on" << endl;
+               _event = MidiEvent((*_note_iter)->on_event(), false);
+               _active_notes.push(*_note_iter);
                ++_note_iter;
+       } else if (type == NOTE_OFF) {
+               //cerr << "********** MIDI Iterator = note off" << endl;
+               _event = MidiEvent(_active_notes.top()->off_event(), false);
+               _active_notes.pop();
        } else if (type == CC) {
-               //cerr << "MIDI Iterator = CC" << endl;
+               //cerr << "********** MIDI Iterator = CC" << endl;
                _model->control_to_midi_event(_event, *_control_iter);
        } else {
-               //cerr << "MIDI Iterator = NIL" << endl;
+               //cerr << "********** MIDI Iterator = END" << endl;
                _is_end = true;
                _model->read_unlock();
                _locked = false;
        }
 
+       assert(_is_end || _event.size() > 0);
+
        return *this;
 }
                
@@ -186,14 +208,36 @@ MidiModel::const_iterator::operator++()
 bool
 MidiModel::const_iterator::operator==(const const_iterator& other) const
 {
-       if (_is_end)
-               if (other._is_end)
-                       return true;
-               else
-                       return false;
+       if (_is_end || other._is_end)
+               return (_is_end == other._is_end);
        else
                return (_event == other._event);
 }
+               
+
+MidiModel::const_iterator&
+MidiModel::const_iterator::operator=(const const_iterator& other)
+{
+       if (_locked && _model != other._model)
+               _model->read_unlock();
+
+       assert( ! other._event.owns_buffer());
+
+       _model = other._model;
+       _event = other._event;
+       _is_end = other._is_end;
+       _locked = other._locked;
+       _note_iter = other._note_iter;
+       _control_iters = other._control_iters;
+       _control_iter = other._control_iter;
+       
+       assert( ! _event.owns_buffer());
+       
+       if (_locked)
+               _model->read_lock();
+
+       return *this;
+}
 
        
 // MidiModel
@@ -204,11 +248,12 @@ MidiModel::MidiModel(Session& s, size_t size)
        , _note_mode(Sustained)
        , _writing(false)
        , _edited(false)
-       //, _active_notes(LaterNoteEndComparator())
        , _end_iter(*this, DBL_MAX)
        , _next_read(UINT32_MAX)
        , _read_iter(*this, DBL_MAX)
 {
+       assert(_end_iter._is_end);
+       assert( ! _end_iter._locked);
 }
 
 
@@ -219,84 +264,34 @@ MidiModel::MidiModel(Session& s, size_t size)
 size_t
 MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const
 {
+       //cerr << this << " MM::read @ " << start << " * " << nframes << " + " << stamp_offset << endl;
+       //cerr << this << " MM # notes: " << n_notes() << endl;
+
        size_t read_events = 0;
 
        if (start != _next_read) {
                _read_iter = const_iterator(*this, (double)start);
-       //      cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
-       //} else {
-       //      cerr << "Using cached iterator at " << _next_read << endl;
+               //cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
+       } else {
+               //cerr << "Using cached iterator at " << _next_read << endl;
+       }
+
+       if (_read_iter == end()) {
+               //cerr << this << " MM::read: at end @ " << _read_iter->time() << endl;
+       } else {
+               //cerr << this << " MM::read: at " << _read_iter->time() << endl;
        }
 
        _next_read = start + nframes;
 
        while (_read_iter != end() && _read_iter->time() < start + nframes) {
+               assert(_read_iter->size() > 0);
                dst.write(_read_iter->time() + stamp_offset, _read_iter->size(), _read_iter->buffer());
+               //cerr << this << " MM::read event @ " << _read_iter->time() << endl;
                ++_read_iter;
                ++read_events;
        }
 
-#if 0
-       /* FIXME: cache last lookup value to avoid O(n) search every time */
-
-       if (_note_mode == Sustained) {
-
-               for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
-
-                       while ( ! _active_notes.empty() ) {
-                               const Note* const earliest_off = _active_notes.top();
-                               const MidiEvent&  off_ev       = earliest_off->off_event();
-                               if (off_ev.time() < start + nframes && off_ev.time() <= n->time()) {
-                                       dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer());
-                                       _active_notes.pop();
-                                       ++read_events;
-                               } else {
-                                       break;
-                               }
-                       }
-
-                       if (n->time() >= start + nframes)
-                               break;
-
-                       // Note on
-                       if (n->time() >= start) {
-                               const MidiEvent& on_ev = n->on_event();
-                               dst.write(on_ev.time() + stamp_offset, on_ev.size(), on_ev.buffer());
-                               _active_notes.push(&(*n));
-                               ++read_events;
-                       }
-
-               }
-                       
-               // Write any trailing note offs
-               while ( ! _active_notes.empty() ) {
-                       const Note* const earliest_off = _active_notes.top();
-                       const MidiEvent&  off_ev       = earliest_off->off_event();
-                       if (off_ev.time() < start + nframes) {
-                               dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer());
-                               _active_notes.pop();
-                               ++read_events;
-                       } else {
-                               break;
-                       }
-               }
-
-       // Percussive
-       } else {
-               for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
-                       // Note on
-                       if (n->time() >= start) {
-                               if (n->time() < start + nframes) {
-                                       const MidiEvent& ev = n->on_event();
-                                       dst.write(ev.time() + stamp_offset, ev.size(), ev.buffer());
-                                       ++read_events;
-                               } else {
-                                       break;
-                               }
-                       }
-               }
-       }
-#endif
        return read_events;
 }
        
@@ -323,83 +318,6 @@ MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter)
 }
 
        
-/** Return the earliest MIDI event in the given range.
- *
- * \return true if \a output has been set to the earliest event in the given range.
- */
-#if 0
-bool
-MidiModel::earliest_note_event(MidiEvent& output, nframes_t start, nframes_t nframes) const
-{
-       /* FIXME: cache last lookup value to avoid O(n) search every time */
-               
-       const Note*      const earliest_on  = NULL;
-       const Note*      const earliest_off = NULL;
-       const MidiEvent* const earliest_cc = NULL;
-
-       /* Notes */
-
-       if (_note_mode == Sustained) {
-                               
-               for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
-
-                       if ( ! _active_notes.empty() ) {
-                               const Note* const earliest_off = _active_notes.top();
-                               const MidiEvent&  off_ev       = earliest_off->off_event();
-                               if (off_ev.time() < start + nframes && off_ev.time() <= n->time()) {
-                                       output = off_ev;
-                                       //dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer());
-                                       _active_notes.pop();
-                                       return true;
-                               }
-                       }
-
-                       if (n->time() >= start + nframes)
-                               break;
-
-                       // Note on
-                       if (n->time() >= start) {
-                               earliest_on = &n->on_event();
-                               //dst.write(on_ev.time() + stamp_offset, on_ev.size(), on_ev.buffer());
-                               _active_notes.push(&(*n));
-                               return true;
-                       }
-
-               }
-                       
-               // Write any trailing note offs
-               while ( ! _active_notes.empty() ) {
-                       const Note* const earliest_off = _active_notes.top();
-                       const MidiEvent&  off_ev       = earliest_off->off_event();
-                       if (off_ev.time() < start + nframes) {
-                               dst.write(off_ev.time() + stamp_offset, off_ev.size(), off_ev.buffer());
-                               _active_notes.pop();
-                               ++read_events;
-                       } else {
-                               break;
-                       }
-               }
-
-       // Percussive
-       } else {
-               for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
-                       // Note on
-                       if (n->time() >= start) {
-                               if (n->time() < start + nframes) {
-                                       const MidiEvent& ev = n->on_event();
-                                       dst.write(ev.time() + stamp_offset, ev.size(), ev.buffer());
-                                       ++read_events;
-                               } else {
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       return read_events;
-}
-#endif
-
 /** Begin a write of events to the model.
  *
  * If \a mode is Sustained, complete notes with duration are constructed as note
@@ -435,8 +353,8 @@ MidiModel::end_write(bool delete_stuck)
 
        if (_note_mode == Sustained && delete_stuck) {
                for (Notes::iterator n = _notes.begin(); n != _notes.end() ; ) {
-                       if (n->duration() == 0) {
-                               cerr << "WARNING: Stuck note lost: " << n->note() << endl;
+                       if ((*n)->duration() == 0) {
+                               cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
                                n = _notes.erase(n);
                        } else {
                                ++n;
@@ -461,7 +379,7 @@ MidiModel::append(const MidiEvent& ev)
 {
        write_lock();
 
-       assert(_notes.empty() || ev.time() >= _notes.back().time());
+       assert(_notes.empty() || ev.time() >= _notes.back()->time());
        assert(_writing);
 
        if (ev.is_note_on())
@@ -483,7 +401,7 @@ MidiModel::append_note_on_unlocked(double time, uint8_t note_num, uint8_t veloci
        //cerr << "MidiModel " << this << " note " << (int)note_num << " on @ " << time << endl;
 
        assert(_writing);
-       _notes.push_back(Note(time, 0, note_num, velocity));
+       _notes.push_back(boost::shared_ptr<Note>(new Note(time, 0, note_num, velocity)));
        if (_note_mode == Sustained) {
                //cerr << "MM Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl;
                _write_notes.push_back(_notes.size() - 1);
@@ -512,7 +430,7 @@ MidiModel::append_note_off_unlocked(double time, uint8_t note_num)
         * keys that send it */
 
        for (WriteNotes::iterator n = _write_notes.begin(); n != _write_notes.end(); ++n) {
-               Note& note = _notes[*n];
+               Note& note = *_notes[*n].get();
                //cerr << (unsigned)(uint8_t)note.note() << " ? " << (unsigned)note_num << endl;
                if (note.note() == note_num) {
                        assert(time > note.time());
@@ -538,7 +456,7 @@ MidiModel::append_cc_unlocked(double time, uint8_t number, uint8_t value)
 
 
 void
-MidiModel::add_note_unlocked(const Note& note)
+MidiModel::add_note_unlocked(const boost::shared_ptr<Note> note)
 {
        //cerr << "MidiModel " << this << " add note " << (int)note.note() << " @ " << note.time() << endl;
        Notes::iterator i = upper_bound(_notes.begin(), _notes.end(), note, note_time_comparator);
@@ -547,7 +465,7 @@ MidiModel::add_note_unlocked(const Note& note)
 
 
 void
-MidiModel::remove_note_unlocked(const Note& note)
+MidiModel::remove_note_unlocked(const boost::shared_ptr<const Note> note)
 {
        //cerr << "MidiModel " << this << " remove note " << (int)note.note() << " @ " << note.time() << endl;
        Notes::iterator n = find(_notes.begin(), _notes.end(), note);
@@ -562,10 +480,10 @@ MidiModel::is_sorted() const
 {
        bool t = 0;
        for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n)
-               if (n->time() < t)
+               if ((*n)->time() < t)
                        return false;
                else
-                       t = n->time();
+                       t = (*n)->time();
 
        return true;
 }
@@ -605,7 +523,7 @@ MidiModel::apply_command(Command* cmd)
 
 
 void
-MidiModel::DeltaCommand::add(const Note& note)
+MidiModel::DeltaCommand::add(const boost::shared_ptr<Note> note)
 {
        //cerr << "MEC: apply" << endl;
 
@@ -615,7 +533,7 @@ MidiModel::DeltaCommand::add(const Note& note)
 
 
 void
-MidiModel::DeltaCommand::remove(const Note& note)
+MidiModel::DeltaCommand::remove(const boost::shared_ptr<Note> note)
 {
        //cerr << "MEC: remove" << endl;
 
@@ -630,15 +548,27 @@ MidiModel::DeltaCommand::operator()()
        // This could be made much faster by using a priority_queue for added and
        // removed notes (or sort here), and doing a single iteration over _model
        
+       // Need to reset iterator to drop the read lock it holds, or we'll deadlock
+       const bool   reset_iter = (_model._read_iter.locked());
+       const double iter_time  = _model._read_iter->time();
+
+       if (reset_iter)
+               _model._read_iter = _model.end(); // drop read lock
+
+       assert( ! _model._read_iter.locked());
+
        _model.write_lock();
        
-       for (std::list<Note>::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
+       for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
                _model.add_note_unlocked(*i);
        
-       for (std::list<Note>::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
+       for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
                _model.remove_note_unlocked(*i);
        
        _model.write_unlock();
+
+       if (reset_iter)
+               _model._read_iter = const_iterator(_model, iter_time);
        
        _model.ContentsChanged(); /* EMIT SIGNAL */
 }
@@ -650,16 +580,28 @@ MidiModel::DeltaCommand::undo()
        // This could be made much faster by using a priority_queue for added and
        // removed notes (or sort here), and doing a single iteration over _model
        
+       // Need to reset iterator to drop the read lock it holds, or we'll deadlock
+       const bool   reset_iter = (_model._read_iter.locked());
+       const double iter_time  = _model._read_iter->time();
+
+       if (reset_iter)
+               _model._read_iter = _model.end(); // drop read lock
+       
+       assert( ! _model._read_iter.locked());
+
        _model.write_lock();
 
-       for (std::list<Note>::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
+       for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
                _model.remove_note_unlocked(*i);
        
-       for (std::list<Note>::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
+       for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
                _model.add_note_unlocked(*i);
        
        _model.write_unlock();
        
+       if (reset_iter)
+               _model._read_iter = const_iterator(_model, iter_time);
+       
        _model.ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -697,9 +639,9 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
 
                // Write any pending note offs earlier than this note on
                while ( ! active_notes.empty() ) {
-                       const Note* const earliest_off = active_notes.top();
-                       const MidiEvent&  off_ev       = earliest_off->off_event();
-                       if (off_ev.time() <= n->time()) {
+                       const boost::shared_ptr<const Note> earliest_off = active_notes.top();
+                       const MidiEvent& off_ev = earliest_off->off_event();
+                       if (off_ev.time() <= (*n)->time()) {
                                source->append_event_unlocked(off_ev);
                                active_notes.pop();
                        } else {
@@ -708,9 +650,9 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
                }
 
                // Write this note on
-               source->append_event_unlocked(n->on_event());
-               if (n->duration() > 0)
-                       active_notes.push(&(*n));
+               source->append_event_unlocked((*n)->on_event());
+               if ((*n)->duration() > 0)
+                       active_notes.push(*n);
        }
                
        // Write any trailing note offs
index 3b62fb0f84c47a332e0491a8890d982359cd58e0..d81f1f2cefd063b3a56385bf7fed00a68b62d1f7 100644 (file)
@@ -354,13 +354,11 @@ MidiTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_fram
                     bool session_state_changing, bool can_record, bool rec_monitors_input)
 {
        if (n_outputs().n_midi() == 0) {
-               //return 0;
-               throw; // FIXME
+               return 0;
        }
 
        if (!_active) {
                silence (nframes, offset);
-               //return 0; // FIXME
        }
 
        if (session_state_changing) {
index 5da30e846656eae50f652a33986f26a8fe2b98ba..c29144996c1d618c9c599ff865251d1fc61d736a 100644 (file)
@@ -70,13 +70,13 @@ Quantize::run (boost::shared_ptr<Region> r)
        double q_frames = _q * (m.frames_per_bar(t, session.frame_rate()) / (double)m.beats_per_bar());
 
        for (MidiModel::Notes::iterator i = model->notes().begin(); i != model->notes().end(); ++i) {
-               const double new_time = lrint(i->time() / q_frames) * q_frames;
-               const double new_dur = ((i->time() != 0 && new_dur < (q_frames * 1.5))
+               const double new_time = lrint((*i)->time() / q_frames) * q_frames;
+               const double new_dur = (((*i)->time() != 0 && new_dur < (q_frames * 1.5))
                        ? q_frames
-                       : lrint(i->duration() / q_frames) * q_frames);
+                       : lrint((*i)->duration() / q_frames) * q_frames);
                
-               i->set_time(new_time);
-               i->set_duration(new_dur);
+               (*i)->set_time(new_time);
+               (*i)->set_duration(new_dur);
        }
 
        model->set_edited(true);
index 2473490f5b88b1e7383d5d4ea6fd53a0fc0513bc..abd8a0abba9258f972e017b980556a3588951346 100644 (file)
@@ -1482,11 +1482,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
        char track_name[32];
        uint32_t track_id = 0;
        uint32_t n = 0;
-       uint32_t channels_used = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
+       //uint32_t control_id;
 
+       // FIXME: need physical I/O and autoconnect stuff for MIDI
+       
        /* count existing midi tracks */
 
        {
@@ -1496,18 +1498,29 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
                        if (dynamic_cast<MidiTrack*>((*i).get()) != 0) {
                                if (!(*i)->is_hidden()) {
                                        n++;
-                                       channels_used += (*i)->n_inputs().n_midi();
+                                       //channels_used += (*i)->n_inputs().n_midi();
                                }
                        }
                }
        }
 
+       /*
+       vector<string> physinputs;
+       vector<string> physoutputs;
+       uint32_t nphysical_in;
+       uint32_t nphysical_out;
+
+       _engine.get_physical_outputs (physoutputs);
+       _engine.get_physical_inputs (physinputs);
+       control_id = ntracks() + nbusses() + 1;
+       */
+
        while (how_many) {
 
                /* check for duplicate route names, since we might have pre-existing
-                  routes with this name (e.g. create Midi1, Midi2, delete Midi1,
+                  routes with this name (e.g. create Audio1, Audio2, delete Audio1,
                   save, close,restart,add new route - first named route is now
-                  Midi2)
+                  Audio2)
                */
                
 
@@ -1522,17 +1535,71 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
                        
                } while (track_id < (UINT_MAX-1));
 
+               /*
+               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
+                       nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
+               } else {
+                       nphysical_in = 0;
+               }
+               
+               if (Config->get_output_auto_connect() & AutoConnectPhysical) {
+                       nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
+               } else {
+                       nphysical_out = 0;
+               }
+               */
+
+               shared_ptr<MidiTrack> track;
+               
                try {
-                       shared_ptr<MidiTrack> track (new MidiTrack (*this, track_name, Route::Flag (0), mode));
+                       track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
                        
-                       if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::MIDI, 1), false, this)) {
+                       if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) {
                                error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+                               goto failed;
+                       }
+
+                       /*
+                       if (nphysical_in) {
+                               for (uint32_t x = 0; x < track->n_inputs().n_midi() && x < nphysical_in; ++x) {
+                                       
+                                       port = "";
+                                       
+                                       if (Config->get_input_auto_connect() & AutoConnectPhysical) {
+                                               port = physinputs[(channels_used+x)%nphysical_in];
+                                       } 
+                                       
+                                       if (port.length() && track->connect_input (track->input (x), port, this)) {
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
+                               
+                               port = "";
+                               
+                               if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
+                                       port = physoutputs[(channels_used+x)%nphysical_out];
+                               } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
+                                       if (_master_out) {
+                                               port = _master_out->input (x%_master_out->n_inputs().n_midi())->name();
+                                       }
+                               }
+                               
+                               if (port.length() && track->connect_output (track->output (x), port, this)) {
+                                       break;
+                               }
                        }
                        
                        channels_used += track->n_inputs ().n_midi();
 
+                       */
+
+                       track->midi_diskstream()->non_realtime_input_change();
+                       
                        track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
-                       track->set_remote_control_id (ntracks());
+                       //track->set_remote_control_id (control_id);
 
                        new_routes.push_back (track);
                        ret.push_back (track);
@@ -1540,14 +1607,43 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
 
                catch (failed_constructor &err) {
                        error << _("Session: could not create new midi track.") << endmsg;
-                       // XXX should we delete the tracks already created? 
-                       ret.clear ();
-                       return ret;
+
+                       if (track) {
+                               /* we need to get rid of this, since the track failed to be created */
+                               /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
+
+                               { 
+                                       RCUWriter<DiskstreamList> writer (diskstreams);
+                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+                                       ds->remove (track->midi_diskstream());
+                               }
+                       }
+
+                       goto failed;
                }
-               
+
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+
+                       error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+
+                       if (track) {
+                               /* we need to get rid of this, since the track failed to be created */
+                               /* XXX arguably, MidiTrack::MidiTrack should not do the Session::add_diskstream() */
+
+                               { 
+                                       RCUWriter<DiskstreamList> writer (diskstreams);
+                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+                                       ds->remove (track->midi_diskstream());
+                               }
+                       }
+
+                       goto failed;
+               }
+
                --how_many;
        }
 
+  failed:
        if (!new_routes.empty()) {
                add_routes (new_routes, false);
                save_state (_current_snapshot_name);
@@ -2732,8 +2828,6 @@ Session::source_by_id (const PBD::ID& id)
                source = i->second;
        }
 
-       /* XXX search MIDI or other searches here */
-       
        return source;
 }
 
index aa5a1b87d4e5f6fab7302cdb800539715ddbc8a7..bf1d9f1a09f3f80310cefc5db329928b6a0e2274 100644 (file)
@@ -397,7 +397,7 @@ Session::process_event (Event* ev)
                break;
 
        case Event::Overwrite:
-               overwrite_some_buffers (static_cast<AudioDiskstream*>(ev->ptr));
+               overwrite_some_buffers (static_cast<Diskstream*>(ev->ptr));
                break;
 
        case Event::SetDiskstreamSpeed:
index 3bc53cb5382b9d07b5f3f1d101917071354f1f54..b8d82bdb9d7caa96280cdbbe48f56fc35c6edec8 100644 (file)
@@ -326,7 +326,7 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
 nframes_t
 SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
 {
-       //cerr << "SMF - read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
+       //cerr << "SMF " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
 
        // 64 bits ought to be enough for anybody
        uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
index d07b9d6d690a96b1aa6c7910447326d9811f9d4c..3a657bc0e2fdf1b2eb23fcbf4b52c3c3928b756a 100644 (file)
@@ -169,8 +169,10 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
 #endif
        
        } else if (type == DataType::MIDI) {
-
-               boost::shared_ptr<Source> ret (new SMFSource (s, node));
+                  boost::shared_ptr<Source> ret (new SMFSource (s, node));
+                      
+                  SourceCreated (ret);
+                  return ret;
        }
 
        return boost::shared_ptr<Source>();