Preliminary visible MIDI notes in MidiRegionView.

git-svn-id: svn://localhost/ardour2/trunk@1943 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2007-06-01 23:27:29 +00:00
parent b0685f4336
commit b32765571b
9 changed files with 227 additions and 20 deletions

View File

@ -28,6 +28,7 @@
#include <ardour/midi_region.h>
#include <ardour/midi_source.h>
#include <ardour/midi_diskstream.h>
#include <ardour/midi_events.h>
#include "streamview.h"
#include "midi_region_view.h"
@ -35,7 +36,6 @@
#include "simplerect.h"
#include "simpleline.h"
#include "public_editor.h"
//#include "midi_region_editor.h"
#include "ghostregion.h"
#include "midi_time_axis.h"
#include "utils.h"
@ -53,12 +53,14 @@ using namespace ArdourCanvas;
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu,
Gdk::Color& basic_color)
: RegionView (parent, tv, r, spu, basic_color)
, _active_notes(0)
{
}
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu,
Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
: RegionView (parent, tv, r, spu, basic_color, visibility)
, _active_notes(0)
{
}
@ -89,6 +91,7 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
MidiRegionView::~MidiRegionView ()
{
in_destructor = true;
end_write();
RegionViewGoingAway (this); /* EMIT_SIGNAL */
}
@ -113,3 +116,67 @@ MidiRegionView::add_ghost (AutomationTimeAxisView& atv)
return NULL;
}
/** Begin tracking note state for successive calls to add_event
*/
void
MidiRegionView::begin_write()
{
_active_notes = new ArdourCanvas::SimpleRect*[127];
}
/** Destroy note state for add_event
*/
void
MidiRegionView::end_write()
{
delete[] _active_notes;
_active_notes = NULL;
}
void
MidiRegionView::add_event (const MidiEvent& ev)
{
/*printf("Event, time = %u, size = %zu, data = ",
ev.time, ev.size);
for (size_t i=0; i < ev.size; ++i) {
printf("%X ", ev.buffer[i]);
}
printf("\n");*/
double y1 = trackview.height / 2.0;
if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
const Byte& note = ev.buffer[1];
y1 = (trackview.height / 127.0) * note;
ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect(
*(ArdourCanvas::Group*)get_canvas_group());
ev_rect->property_x1() = trackview.editor.frame_to_pixel (
ev.time);
ev_rect->property_y1() = y1;
ev_rect->property_x2() = trackview.editor.frame_to_pixel (
_region->length());
ev_rect->property_y2() = y1 + (trackview.height / 127.0);
ev_rect->property_outline_color_rgba() = 0xFFFFFFAA;
/* outline all but right edge */
ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8);
ev_rect->property_fill_color_rgba() = 0xFFFFFF66;
_events.push_back(ev_rect);
if (_active_notes)
_active_notes[note] = ev_rect;
} else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
const Byte& note = ev.buffer[1];
if (_active_notes && _active_notes[note]) {
_active_notes[note]->property_x2() = trackview.editor.frame_to_pixel(ev.time);
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
_active_notes[note] = NULL;
}
}
}

View File

@ -25,6 +25,7 @@
#include <libgnomecanvasmm/polygon.h>
#include <sigc++/signal.h>
#include <ardour/midi_region.h>
#include <ardour/types.h>
#include "region_view.h"
#include "route_time_axis.h"
@ -61,6 +62,11 @@ class MidiRegionView : public RegionView
GhostRegion* add_ghost (AutomationTimeAxisView&);
void add_event(const ARDOUR::MidiEvent& ev);
void begin_write();
void end_write();
protected:
/* this constructor allows derived types
@ -79,6 +85,11 @@ class MidiRegionView : public RegionView
void set_flags (XMLNode *);
void store_flags ();
private:
std::vector<ArdourCanvas::Item*> _events;
ArdourCanvas::SimpleRect** _active_notes;
};
#endif /* __gtk_ardour_midi_region_view_h__ */

View File

@ -45,6 +45,7 @@
#include "gui_thread.h"
#include "utils.h"
#include "color.h"
#include "simplerect.h"
using namespace std;
using namespace ARDOUR;
@ -107,8 +108,13 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait
// FIXME
//region_view->set_waveform_visible(_trackview.editor.show_waveforms());
/* catch regionview going away */
/* display events */
region_view->begin_write();
for (size_t i=0; i < region->midi_source(0)->model().n_events(); ++i)
region_view->add_event(region->midi_source(0)->model().event_at(i));
region_view->end_write();
/* catch regionview going away */
region->GoingAway.connect (bind (mem_fun (*this, &MidiStreamView::remove_region_view), region));
RegionViewAdded (region_view);
@ -337,12 +343,21 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiBuffer> data, nframes_
if (origlen == 1) {
/* our special initial length */
iter->second = add_region_view_internal (region, false);
((MidiRegionView*)iter->second)->begin_write();
}
/* also update rect */
ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle;
gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length());
rect->property_x2() = xend;
/* draw events */
MidiRegionView* mrv = (MidiRegionView*)iter->second;
for (size_t i = 0; i < data->size(); ++i) {
const MidiEvent& ev = (*data.get())[i];
mrv->add_event(ev);
}
}
}

View File

@ -57,6 +57,7 @@ midi_diskstream.cc
midi_playlist.cc
midi_track.cc
midi_region.cc
midi_model.cc
smf_source.cc
auditioner.cc
automation.cc

View File

@ -22,6 +22,7 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <boost/utility.hpp>
#include <ardour/types.h>
#include <ardour/data_type.h>
#include <ardour/runtime_functions.h>
@ -38,7 +39,7 @@ namespace ARDOUR {
*
* To actually read/write buffer contents, use the appropriate derived class.
*/
class Buffer
class Buffer : public boost::noncopyable
{
public:
virtual ~Buffer() {}
@ -76,11 +77,6 @@ protected:
size_t _capacity;
size_t _size;
bool _silent;
private:
// Prevent copies (undefined)
Buffer(const Buffer& copy);
void operator=(const Buffer& other);
};
@ -175,10 +171,6 @@ public:
{ assert(offset + nframes <= _capacity); return _data + offset; }
private:
// These are undefined (prevent copies)
AudioBuffer(const AudioBuffer& copy);
AudioBuffer& operator=(const AudioBuffer& copy);
bool _owns_data;
Sample* _data; ///< Actual buffer contents
};
@ -197,7 +189,7 @@ public:
void read_from(const Buffer& src, nframes_t nframes, nframes_t offset);
bool push_back(const MidiEvent& event);
bool push_back(const ARDOUR::MidiEvent& event);
Byte* reserve(nframes_t time, size_t size);
const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
@ -206,10 +198,6 @@ public:
static size_t max_event_size() { return MAX_EVENT_SIZE; }
private:
// These are undefined (prevent copies)
MidiBuffer(const MidiBuffer& copy);
MidiBuffer& operator=(const MidiBuffer& copy);
// FIXME: Jack needs to tell us this
static const size_t MAX_EVENT_SIZE = 4; // bytes

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2006 Paul Davis
Written by Dave Robillard, 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_midi_model_h__
#define __ardour_midi_model_h__
#include <boost/utility.hpp>
#include <ardour/types.h>
#include <ardour/buffer.h>
namespace ARDOUR {
/** A dynamically resizable collection of MIDI events, sorted by time
*/
class MidiModel : public boost::noncopyable {
public:
MidiModel(size_t size=0);
~MidiModel();
/** Resizes vector if necessary (NOT realtime safe) */
void append(const MidiBuffer& data);
inline const MidiEvent& event_at(unsigned i) const { return _events[i]; }
inline size_t n_events() const { return _events.size(); }
private:
std::vector<MidiEvent> _events;
};
} /* namespace ARDOUR */
#endif /* __ardour_midi_model_h__ */

View File

@ -31,6 +31,7 @@
#include <ardour/source.h>
#include <ardour/ardour.h>
#include <ardour/buffer.h>
#include <ardour/midi_model.h>
#include <pbd/stateful.h>
#include <pbd/xml++.h>
@ -62,12 +63,14 @@ class MidiSource : public Source
static sigc::signal<void,MidiSource*> MidiSourceCreated;
// The MIDI equivalent to "peaks"
// The MIDI equivalent to "peaks" (but complete data)
mutable sigc::signal<void,boost::shared_ptr<MidiBuffer>,nframes_t,nframes_t> ViewDataRangeReady;
XMLNode& get_state ();
int set_state (const XMLNode&);
MidiModel& model() { return _model; }
protected:
virtual nframes_t read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const = 0;
virtual nframes_t write_unlocked (MidiRingBuffer& dst, nframes_t cnt) = 0;
@ -77,6 +80,8 @@ class MidiSource : public Source
mutable uint32_t _read_data_count; ///< modified in read()
mutable uint32_t _write_data_count; ///< modified in write()
MidiModel _model;
private:
bool file_changed (string path);
};

65
libs/ardour/midi_model.cc Normal file
View File

@ -0,0 +1,65 @@
/*
Copyright (C) 2006 Paul Davis
Written by Dave Robillard, 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include <ardour/midi_model.h>
#include <ardour/types.h>
using namespace std;
using namespace ARDOUR;
MidiModel::MidiModel(size_t size)
: _events(size)
{
}
MidiModel::~MidiModel()
{
for (size_t i=0; i < _events.size(); ++i)
delete _events[i].buffer;
}
/** Append contents of \a buf to model. NOT (even remotely) realtime safe.
*
* Timestamps of events in \a buf are expected to be relative to
* the start of this model (t=0) and MUST be monotonically increasing
* and MUST be >= the latest event currently in the model.
*
* Events in buf are deep copied.
*/
void
MidiModel::append(const MidiBuffer& buf)
{
for (size_t i=0; i < buf.size(); ++i) {
const MidiEvent& buf_event = buf[i];
assert(buf_event.time >= _events.back().time);
_events.push_back(buf_event);
MidiEvent& my_event = _events.back();
assert(my_event.time == buf_event.time);
assert(my_event.size == buf_event.size);
my_event.buffer = new Byte[my_event.size];
memcpy(my_event.buffer, buf_event.buffer, my_event.size);
}
}

View File

@ -352,9 +352,10 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
// FIXME: start of source time?
for (size_t i=0; i < buf.size(); ++i) {
const MidiEvent& ev = buf[i];
MidiEvent& ev = buf[i];
assert(ev.time >= _timeline_position);
uint32_t delta_time = (ev.time - _timeline_position) - _last_ev_time;
ev.time -= _timeline_position;
uint32_t delta_time = ev.time - _last_ev_time;
/*printf("SMF - writing event, delta = %u, size = %zu, data = ",
delta_time, ev.size);
@ -376,6 +377,8 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
const nframes_t oldlen = _length;
update_length(oldlen, cnt);
_model.append(buf);
ViewDataRangeReady (buf_ptr, oldlen, cnt); /* EMIT SIGNAL */
return cnt;