Merge the two separate 'add notes to midi region' interfaces (note and midievent).

Update note range dynamically while recording to fit incoming notes.


git-svn-id: svn://localhost/ardour2/trunk@2512 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2007-10-04 05:15:28 +00:00
parent 9bcd3f1d16
commit 79db28b0b8
8 changed files with 79 additions and 82 deletions

View file

@ -31,15 +31,24 @@ namespace Gnome {
namespace Canvas { namespace Canvas {
CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note) CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note, bool copy_note)
: _region(region) : _region(region)
, _item(item) , _item(item)
, _state(None) , _state(None)
, _note(note) , _note((copy_note && note) ? new ARDOUR::Note(*note) : note)
, _own_note(copy_note)
, _selected(false) , _selected(false)
{ {
} }
CanvasMidiEvent::~CanvasMidiEvent()
{
if (_own_note)
delete _note;
}
void void
CanvasMidiEvent::selected(bool yn) CanvasMidiEvent::selected(bool yn)
{ {

View file

@ -43,8 +43,8 @@ namespace Canvas {
*/ */
class CanvasMidiEvent { class CanvasMidiEvent {
public: public:
CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note = NULL); CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOUR::Note* note=NULL, bool copy_note=false);
virtual ~CanvasMidiEvent() {} virtual ~CanvasMidiEvent();
bool on_event(GdkEvent* ev); bool on_event(GdkEvent* ev);
@ -71,6 +71,7 @@ protected:
Item* const _item; Item* const _item;
State _state; State _state;
const ARDOUR::Note* _note; const ARDOUR::Note* _note;
bool _own_note;
bool _selected; bool _selected;
}; };

View file

@ -30,8 +30,8 @@ namespace Canvas {
class CanvasNote : public SimpleRect, public CanvasMidiEvent { class CanvasNote : public SimpleRect, public CanvasMidiEvent {
public: public:
CanvasNote(MidiRegionView& region, Group& group, const ARDOUR::Note* note=NULL) CanvasNote(MidiRegionView& region, Group& group, const ARDOUR::Note* note=NULL, bool copy_note=false)
: SimpleRect(group), CanvasMidiEvent(region, this, note) : SimpleRect(group), CanvasMidiEvent(region, this, note, copy_note)
{ {
} }

View file

@ -406,7 +406,7 @@ MidiRegionView::redisplay_model()
_model->read_lock(); _model->read_lock();
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)); add_note(_model->note_at(i), false);
end_write(); end_write();
@ -495,8 +495,23 @@ MidiRegionView::set_y_position_and_height (double y, double h)
{ {
RegionView::set_y_position_and_height(y, h - 1); RegionView::set_y_position_and_height(y, h - 1);
if (_enable_display) if (_enable_display) {
redisplay_model();
_model->read_lock();
for (std::vector<CanvasMidiEvent*>::const_iterator i = _events.begin(); i != _events.end(); ++i) {
CanvasNote* note = dynamic_cast<CanvasNote*>(*i);
if (note && note->note()) {
const double y1 = midi_stream_view()->note_to_y(note->note()->note());
const double y2 = y1 + floor(midi_stream_view()->note_height());
note->property_y1() = y1;
note->property_y2() = y2;
}
}
_model->read_unlock();
}
if (name_text) { if (name_text) {
name_text->raise_to_top(); name_text->raise_to_top();
@ -544,68 +559,18 @@ MidiRegionView::end_write()
} }
/** Add a MIDI event. /** Resolve an active MIDI note (while recording).
*
* This is used while recording, and handles displaying still-unresolved notes.
* Displaying an existing model is simpler, and done with add_note.
*/ */
void void
MidiRegionView::add_event (const MidiEvent& ev) MidiRegionView::resolve_note(uint8_t note, double end_time)
{ {
/*printf("MRV add Event, time = %f, size = %u, data = ", ev.time(), ev.size()); if (midi_view()->note_mode() != Sustained)
for (size_t i=0; i < ev.size(); ++i) { return;
printf("%X ", ev.buffer()[i]);
}
printf("\n\n");*/
//ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); if (_active_notes && _active_notes[note]) {
ArdourCanvas::Group* const group = _note_group; _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)end_time);
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
if (midi_view()->note_mode() == Sustained) { _active_notes[note] = NULL;
if ((ev.buffer()[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
const Byte& note = ev.buffer()[1];
const double y1 = midi_stream_view()->note_to_y(note);
CanvasNote* ev_rect = new CanvasNote(*this, *group);
ev_rect->property_x1() = trackview.editor.frame_to_pixel (
(nframes_t)ev.time());
ev_rect->property_y1() = y1;
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(ev.velocity());
ev_rect->property_outline_color_rgba() = note_outline_color(ev.velocity());
/* outline all but right edge */
ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8);
ev_rect->raise_to_top();
_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((nframes_t)ev.time());
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
_active_notes[note] = NULL;
}
}
} else if (midi_view()->note_mode() == Percussive) {
const Byte& note = ev.buffer()[1];
const double diamond_size = midi_stream_view()->note_height() / 2.0;
const double x = trackview.editor.frame_to_pixel((nframes_t)ev.time());
const double y = midi_stream_view()->note_to_y(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(ev.velocity());
ev_diamond->property_outline_color_rgba() = note_outline_color(ev.velocity());
_events.push_back(ev_diamond);
} }
} }
@ -626,11 +591,12 @@ MidiRegionView::extend_active_notes()
/** Add a MIDI note to the view (with duration). /** Add a MIDI note to the view (with duration).
* *
* This does no 'realtime' note resolution, notes from a MidiModel have a * If in sustained mode, notes with duration 0 will be considered active
* duration so they can be drawn in full immediately. * notes, and resolve_note should be called when the corresponding note off
* event arrives, to properly display the note.
*/ */
void void
MidiRegionView::add_note (const Note& note) MidiRegionView::add_note (const Note& note, bool copy_note)
{ {
assert(note.time() >= 0); assert(note.time() >= 0);
//assert(note.time() < _region->length()); //assert(note.time() < _region->length());
@ -640,15 +606,26 @@ MidiRegionView::add_note (const Note& note)
if (midi_view()->note_mode() == Sustained) { if (midi_view()->note_mode() == Sustained) {
const double y1 = midi_stream_view()->note_to_y(note.note()); const double y1 = midi_stream_view()->note_to_y(note.note());
CanvasNote* ev_rect = new CanvasNote(*this, *group, &note); CanvasNote* ev_rect = new CanvasNote(*this, *group, &note, copy_note);
ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note.time()); ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note.time());
ev_rect->property_y1() = y1; ev_rect->property_y1() = y1;
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_y2() = y1 + floor(midi_stream_view()->note_height());
ev_rect->property_fill_color_rgba() = note_fill_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()); ev_rect->property_outline_color_rgba() = note_outline_color(note.velocity());
ev_rect->property_outline_what() = (guint32) 0xF; // all edges
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 {
/* outline all edges */
ev_rect->property_outline_what() = (guint32) 0xF;
}
ev_rect->show(); ev_rect->show();
_events.push_back(ev_rect); _events.push_back(ev_rect);

View file

@ -76,8 +76,8 @@ class MidiRegionView : public RegionView
GhostRegion* add_ghost (AutomationTimeAxisView&); GhostRegion* add_ghost (AutomationTimeAxisView&);
void add_event(const ARDOUR::MidiEvent& ev); void add_note(const ARDOUR::Note& note, bool copy_note);
void add_note(const ARDOUR::Note& note); void resolve_note(uint8_t note_num, double end_time);
void begin_write(); void begin_write();
void end_write(); void end_write();

View file

@ -417,6 +417,7 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
if (use_rec_regions) { if (use_rec_regions) {
uint32_t n = 0; uint32_t n = 0;
bool update_range = false;
for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) { for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
@ -474,14 +475,18 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
break; break;
if (note.time() >= start) if (note.time() >= start)
if (data->note_mode() == Percussive || note.duration() > 0) mrv->add_note(note, true);
mrv->add_note(note);
else
mrv->add_event(note.on_event());
if (note.duration() > 0 && note.end_time() >= start) if (note.duration() > 0 && note.end_time() >= start)
mrv->add_event(note.off_event()); mrv->resolve_note(note.note(), note.end_time());
if (note.note() < _lowest_note) {
_lowest_note = note.note();
update_range = true;
} else if (note.note() > _highest_note) {
_highest_note = note.note();
update_range = true;
}
} }
mrv->extend_active_notes(); mrv->extend_active_notes();
@ -517,6 +522,9 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
iter = tmp; iter = tmp;
} }
if (update_range)
update_contents_y_position_and_height();
} }
} }

View file

@ -148,7 +148,7 @@ struct MidiEvent {
inline uint8_t cc_number() const { return (_buffer[1]); } inline uint8_t cc_number() const { return (_buffer[1]); }
inline uint8_t cc_value() const { return (_buffer[2]); } inline uint8_t cc_value() const { return (_buffer[2]); }
inline const Byte* buffer() const { return _buffer; } inline const Byte* buffer() const { return _buffer; }
inline Byte*& buffer() { return _buffer; } inline Byte*& buffer() { return _buffer; }
private: private:
double _time; /**< Sample index (or beat time) at which event is valid */ double _time; /**< Sample index (or beat time) at which event is valid */

View file

@ -45,6 +45,8 @@ Note::Note(const Note& copy)
: _on_event(copy._on_event, true) : _on_event(copy._on_event, true)
, _off_event(copy._off_event, true) , _off_event(copy._off_event, true)
{ {
assert(_on_event.buffer());
assert(_off_event.buffer());
/* /*
assert(copy._on_event.size == 3); assert(copy._on_event.size == 3);
_on_event.buffer = _on_event_buffer; _on_event.buffer = _on_event_buffer;