Eliminate excessive allocation (for every event) during MidiModel iteration.
authorDavid Robillard <d@drobilla.net>
Thu, 15 May 2008 05:00:28 +0000 (05:00 +0000)
committerDavid Robillard <d@drobilla.net>
Thu, 15 May 2008 05:00:28 +0000 (05:00 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@3351 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/canvas-program-change.cc
gtk2_ardour/canvas-program-change.h
gtk2_ardour/midi_region_view.cc
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/note.h
libs/ardour/midi_buffer.cc
libs/ardour/midi_model.cc
libs/midi++2/midi++/event.h

index ccaf333ef5e39762171e96e546dde23616421d9c..6f7182e2cda6f9f91e1c64c4602169cc80c0b74d 100644 (file)
@@ -12,19 +12,16 @@ CanvasProgramChange::CanvasProgramChange(
                double                                height,
                double                                x,
                double                                y)
-       : Group(parent, x, y),
-         _region(region),
-         _event(event),
-         _text(0),
-         _line(0),
-         _rect(0),
-         _widget(0)
+       : Group(parent, x, y)
+       , _region(region)
+       , _event(event)
+       , _text(0)
+       , _line(0)
+       , _rect(0)
 {
-       _text = new Text(*this);
-       assert(_text);
-       ostringstream pgm(ios::ate);
-       pgm << int(event->pgm_number());
-       _text->property_text() = pgm.str();
+       char pgm_str[4];
+       snprintf(pgm_str, 4, "%d", (int)event->pgm_number());
+       _text = new Text(*this, 0.0, 0.0, pgm_str);
        _text->property_justification() = Gtk::JUSTIFY_CENTER;
        _text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get();
        double flagwidth  = _text->property_text_width()  + 10.0;
@@ -39,22 +36,12 @@ CanvasProgramChange::CanvasProgramChange(
        _rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeFill.get();
        _text->lower_to_bottom();
        _text->raise(2);
-       assert(_widget == 0);
-       assert(_text != 0);
-       assert(_line != 0);
-       assert(_rect != 0);
 }
 
 CanvasProgramChange::~CanvasProgramChange()
 {
-       if(_line)
-               delete _line;
-       if(_rect)
-               delete _rect;
-       if(_text)
-               delete _text;
-       if(_widget)
-               delete _widget;
+       delete _line;
+       delete _rect;
+       delete _text;
 }
 
-
index 37dc0cc8dae0227edf88e65525a50908b188f956..3ac9b103838321958207e7b911060846600ebc77 100644 (file)
@@ -33,7 +33,6 @@ private:
        Text*                             _text;
        SimpleLine*                       _line;
        SimpleRect*                       _rect;
-       Widget*                           _widget;
 };
 
 } // namespace Canvas
index b70e1c7b083e3336616b810b3ca4af63e1bfa7cd..b9af0a81a2b5278d4ba26c75f29992e5e0603c95 100644 (file)
@@ -466,29 +466,28 @@ MidiRegionView::redisplay_model()
                             << "  velocity: " << int((*i)->velocity()) 
                             << endl;
                }*/
-
                
-               for (size_t i = 0; i < _model->n_notes(); ++i) {
+               for (size_t i = 0; i < _model->n_notes(); ++i)
                        add_note(_model->note_at(i));
-               }
 
-               for (Automatable::Controls::iterator 
-                    control = _model->controls().begin();
+               // Draw program change 'flags'
+               for (Automatable::Controls::iterator control = _model->controls().begin();
                                control != _model->controls().end(); ++control) {
-
-                       if ( control->first.type() == MidiPgmChangeAutomation ) {
+                       if (control->first.type() == MidiPgmChangeAutomation) {
                                Glib::Mutex::Lock list_lock (control->second->list()->lock());
                                
                                for (AutomationList::const_iterator event = control->second->list()->begin();
-                               event != control->second->list()->end(); ++event) {
+                                               event != control->second->list()->end(); ++event) {
                                        MidiControlIterator iter(control->second->list(), (*event)->when, (*event)->value);
-                                       add_pgm_change(_model->control_to_midi_event(iter));
+                                       boost::shared_ptr<MIDI::Event> event(new MIDI::Event());
+                                       _model->control_to_midi_event(event, iter);
+                                       add_pgm_change(event);
                                }
                                break;
                        }
                }
 
-               // Is this necessary ??????????
+               // Is this necessary?
                /*for (Automatable::Controls::const_iterator i = _model->controls().begin();
                                i != _model->controls().end(); ++i) {
 
@@ -821,12 +820,8 @@ MidiRegionView::add_pgm_change(boost::shared_ptr<MIDI::Event> event)
        assert(event->time() >= 0);
        
        // dont display notes beyond the region bounds
-       if (
-                       event->time() - _region->start() >= _region->length() ||
-                       event->time() <  _region->start() 
-         ) {
+       if (event->time() - _region->start() >= _region->length() || event->time() <  _region->start()) 
                return;
-       }
        
        ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
        const double x = trackview.editor.frame_to_pixel((nframes_t)event->time() - _region->start());
index 98e159002a35c63b72453378e40a27a44f882a85..a49a8783716b1cac44e3623cebe8fd78c21635e0 100644 (file)
@@ -200,7 +200,7 @@ public:
        
        const MidiSource* midi_source() const { return _midi_source; }
        void set_midi_source(MidiSource* source) { _midi_source = source; } 
-       boost::shared_ptr<MIDI::Event> control_to_midi_event(const MidiControlIterator& iter) const;
+       bool control_to_midi_event(boost::shared_ptr<MIDI::Event> ev, const MidiControlIterator& iter) const;
        
 private:
        friend class DeltaCommand;
index f32a2e75f9a9b3fd4f676b689163884e30a57e02..0f649b337096730366a9d8cfac530c3ab1014ffe 100644 (file)
@@ -62,7 +62,7 @@ public:
        inline void set_note(uint8_t n)     { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; }
        inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; }
        inline void set_duration(double d)  { _off_event.time() = _on_event.time() + d; }
-       inline void set_channel(uint8_t channel)  { _on_event.set_channel(channel);  _off_event.set_channel(channel); }
+       inline void set_channel(uint8_t c)  { _on_event.set_channel(c);  _off_event.set_channel(c); }
 
        inline MIDI::Event& on_event()  { return _on_event; }
        inline MIDI::Event& off_event() { return _off_event; }
index 4628de4a6a45e6732d0c3d45f4e0740491ae7048..9c82397142bfa50ae6dac71e730a28336484f57d 100644 (file)
@@ -145,7 +145,7 @@ MidiBuffer::push_back(const MIDI::Event& ev)
 
        memcpy(write_loc, ev.buffer(), ev.size());
        _events[_size] = ev;
-       _events[_size].set_buffer(write_loc, false);
+       _events[_size].set_buffer(ev.size(), write_loc, false);
        ++_size;
 
        //cerr << "MidiBuffer: pushed, size = " << _size << endl;
@@ -173,8 +173,7 @@ MidiBuffer::push_back(const jack_midi_event_t& ev)
 
        memcpy(write_loc, ev.buffer, ev.size);
        _events[_size].time() = (double)ev.time;
-       _events[_size].size() = ev.size;
-       _events[_size].set_buffer(write_loc, false);
+       _events[_size].set_buffer(ev.size, write_loc, false);
        ++_size;
 
        //cerr << "MidiBuffer: pushed, size = " << _size << endl;
@@ -206,8 +205,7 @@ MidiBuffer::reserve(double time, size_t size)
        Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
 
        _events[_size].time() = time;
-       _events[_size].size() = size;
-       _events[_size].set_buffer(write_loc, false);
+       _events[_size].set_buffer(size, write_loc, false);
        ++_size;
 
        //cerr << "MidiBuffer: reserved, size = " << _size << endl;
index fc5a9f41251a43767d9aaeb4cc6eab31f72cad0b..d9d1632590c2bf86f40e19a4d87d3be4b3aa1e21 100644 (file)
@@ -59,6 +59,7 @@ void MidiModel::read_unlock() const {
 
 MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        : _model(&model)
+       , _event(new MIDI::Event(0.0, 4, NULL, true))
        , _is_end( (t == DBL_MAX) || model.empty())
        , _locked( !_is_end)
 {
@@ -120,9 +121,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        }
 
        if (_note_iter != model.notes().end()) {
-               MIDI::Event *new_event = new MIDI::Event((*_note_iter)->on_event(), true);
-               assert(new_event);
-               _event = boost::shared_ptr<MIDI::Event>(new_event);
+               *_event = (*_note_iter)->on_event();
        }
 
        double time = DBL_MAX;
@@ -138,7 +137,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
        
        // <=, because we probably would want to send control events first 
        if (earliest_control.automation_list.get() && earliest_control.x <= time) {
-               _event = model.control_to_midi_event(earliest_control);
+               model.control_to_midi_event(_event, earliest_control);
        } else {
                _control_iter = _control_iters.end();
        }
@@ -238,20 +237,16 @@ const MidiModel::const_iterator& MidiModel::const_iterator::operator++()
 
        if (type == NOTE_ON) {
                //cerr << "********** MIDI Iterator = note on" << endl;
-               MIDI::Event *new_event = new MIDI::Event((*_note_iter)->on_event(), true);
-               assert(new_event);
-               _event = boost::shared_ptr<MIDI::Event>(new_event);
+               *_event = (*_note_iter)->on_event();
                _active_notes.push(*_note_iter);
                ++_note_iter;
        } else if (type == NOTE_OFF) {
                //cerr << "********** MIDI Iterator = note off" << endl;
-               MIDI::Event *new_event = new MIDI::Event(_active_notes.top()->off_event(), true);
-               assert(new_event);
-               _event = boost::shared_ptr<MIDI::Event>(new_event);
+               *_event = (*_note_iter)->off_event();
                _active_notes.pop();
        } else if (type == AUTOMATION) {
                //cerr << "********** MIDI Iterator = Automation" << endl;
-               _event = _model->control_to_midi_event(*_control_iter);
+               _model->control_to_midi_event(_event, *_control_iter);
        } else {
                //cerr << "********** MIDI Iterator = End" << endl;
                _is_end = true;
@@ -278,7 +273,7 @@ MidiModel::const_iterator& MidiModel::const_iterator::operator=(const const_iter
        }
 
        _model         = other._model;
-       _event         = other._event;
+       _event         = boost::shared_ptr<MIDI::Event>(new MIDI::Event(*other._event, true));
        _active_notes  = other._active_notes;
        _is_end        = other._is_end;
        _locked        = other._locked;
@@ -349,15 +344,14 @@ size_t MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes,
 }
 
 /** Write the controller event pointed to by \a iter to \a ev.
- * Ev will have a newly allocated buffer containing the event.
+ * The buffer of \a ev will be allocated or resized as necessary.
+ * \return true on success
  */
-boost::shared_ptr<MIDI::Event> 
-MidiModel::control_to_midi_event(const MidiControlIterator& iter) const
+bool
+MidiModel::control_to_midi_event(boost::shared_ptr<MIDI::Event> ev, const MidiControlIterator& iter) const
 {
        assert(iter.automation_list.get());
        
-       boost::shared_ptr<MIDI::Event> ev;
-       
        switch (iter.automation_list->parameter().type()) {
        case MidiCCAutomation:
                assert(iter.automation_list.get());
@@ -365,7 +359,8 @@ MidiModel::control_to_midi_event(const MidiControlIterator& iter) const
                assert(iter.automation_list->parameter().id() <= INT8_MAX);
                assert(iter.y <= INT8_MAX);
                
-               ev = boost::shared_ptr<MIDI::Event>(new MIDI::Event(iter.x, 3, (uint8_t *)malloc(3), true));
+               ev->time() = iter.x;
+               ev->realloc(3);
                ev->buffer()[0] = MIDI_CMD_CONTROL + iter.automation_list->parameter().channel();
                ev->buffer()[1] = (Byte)iter.automation_list->parameter().id();
                ev->buffer()[2] = (Byte)iter.y;
@@ -377,7 +372,8 @@ MidiModel::control_to_midi_event(const MidiControlIterator& iter) const
                assert(iter.automation_list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
                
-               ev = boost::shared_ptr<MIDI::Event>(new MIDI::Event(iter.x, 2, (uint8_t *)malloc(2), true));
+               ev->time() = iter.x;
+               ev->realloc(2);
                ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.automation_list->parameter().channel();
                ev->buffer()[1] = (Byte)iter.y;
                break;
@@ -388,7 +384,8 @@ MidiModel::control_to_midi_event(const MidiControlIterator& iter) const
                assert(iter.automation_list->parameter().id() == 0);
                assert(iter.y < (1<<14));
                
-               ev = boost::shared_ptr<MIDI::Event>(new MIDI::Event(iter.x, 3, (uint8_t *)malloc(3), true));
+               ev->time() = iter.x;
+               ev->realloc(3);
                ev->buffer()[0] = MIDI_CMD_BENDER + iter.automation_list->parameter().channel();
                ev->buffer()[1] = ((Byte)iter.y) & 0x7F; // LSB
                ev->buffer()[2] = (((Byte)iter.y) >> 7) & 0x7F; // MSB
@@ -400,18 +397,18 @@ MidiModel::control_to_midi_event(const MidiControlIterator& iter) const
                assert(iter.automation_list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
 
-               ev = boost::shared_ptr<MIDI::Event>(new MIDI::Event(iter.x, 2, (uint8_t *)malloc(2), true));
+               ev->time() = iter.x;
+               ev->realloc(2);
                ev->buffer()[0]
                                = MIDI_CMD_CHANNEL_PRESSURE + iter.automation_list->parameter().channel();
                ev->buffer()[1] = (Byte)iter.y;
                break;
 
        default:
-               break;
+               return false;
        }
-       
-       assert(ev.get());
-       return ev;
+
+       return true;
 }
 
 
index fed5c5dd4466c656b2bd17c30d13aab0c111a7bb..5734c1228cb651d9cbfcc85539b404fc87470891 100644 (file)
@@ -93,9 +93,8 @@ struct Event {
                _time = copy._time;
                if (_owns_buffer) {
                        if (copy._buffer) {
-                               if (!_buffer || _size < copy._size) {
+                               if (copy._size > _size)
                                        _buffer = (uint8_t*)::realloc(_buffer, copy._size);
-                               }
                                memcpy(_buffer, copy._buffer, copy._size);
                        } else {
                                free(_buffer);
@@ -108,19 +107,31 @@ struct Event {
                _size = copy._size;
                return *this;
        }
+
+       inline void shallow_copy(const Event& copy) {
+               if (_owns_buffer) {
+                       free(_buffer);
+                       _buffer = false;
+                       _owns_buffer = false;
+               }
+
+               _time = copy._time;
+               _size = copy._size;
+               _buffer = copy._buffer;
+       }
        
-       inline void set (uint8_t* msg, size_t msglen, timestamp_t t) {
+       inline void set(uint8_t* buf, size_t size, double t) {
                if (_owns_buffer) {
-                       if (_size < msglen) {
-                               free (_buffer);
-                               _buffer = (uint8_t*) malloc (msglen);
+                       if (_size < size) {
+                               _buffer = (uint8_t*) ::realloc(_buffer, size);
                        }
                } else {
-                       _buffer = (uint8_t*) malloc (msglen);
+                       _buffer = (uint8_t*) malloc(size);
                        _owns_buffer = true;
                }
 
-               memcpy (_buffer, msg, msglen);
+               _size = size;
+               memcpy (_buffer, buf, size);
                _time = t;
        }
 
@@ -145,18 +156,20 @@ struct Event {
 
        inline bool owns_buffer() const { return _owns_buffer; }
        
-       inline void set_buffer(uint8_t* buf, bool own) {
+       inline void set_buffer(size_t size, uint8_t* buf, bool own) {
                if (_owns_buffer) {
                        free(_buffer);
                        _buffer = NULL;
                }
+               _size = size;
                _buffer = buf;
                _owns_buffer = own;
        }
 
        inline void realloc(size_t size) {
                if (_owns_buffer) {
-                       _buffer = (uint8_t*) ::realloc(_buffer, size);
+                       if (size > _size)
+                               _buffer = (uint8_t*) ::realloc(_buffer, size);
                } else {
                        _buffer = (uint8_t*) ::malloc(size);
                        _owns_buffer = true;
@@ -176,7 +189,7 @@ struct Event {
        inline uint32_t    size()                  const { return _size; }
        inline uint32_t&   size()                        { return _size; }
        inline uint8_t     type()                  const { return (_buffer[0] & 0xF0); }
-       inline void        set_type(uint8_t type     )   { _buffer[0] = (0x0F & _buffer[0]) | (0xF0 & type); }
+       inline void        set_type(uint8_t type)        { _buffer[0] = (0x0F & _buffer[0]) | (0xF0 & type); }
        inline uint8_t     channel()               const { return (_buffer[0] & 0x0F); }
        inline void        set_channel(uint8_t channel)  { _buffer[0] = (0xF0 & _buffer[0]) | (0x0F & channel); }
        inline bool        is_note_on()            const { return (type() == MIDI_CMD_NOTE_ON); }