#include "gui_thread.h"
#include "utils.h"
#include "simplerect.h"
+#include "simpleline.h"
using namespace std;
using namespace ARDOUR;
MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
: StreamView (tv)
- , _lowest_note(0)
- , _highest_note(127)
+ , _range(ContentsRange)
+ , _lowest_note(60)
+ , _highest_note(60)
{
if (tv.is_track())
stream_base_color = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
canvas_rect->property_fill_color_rgba() = stream_base_color;
canvas_rect->property_outline_color_rgba() = RGBA_BLACK;
- //use_rec_regions = tv.editor.show_waveforms_recording ();
- use_rec_regions = true;
+ use_rec_regions = tv.editor.show_waveforms_recording ();
+
+ _note_line_group = new ArdourCanvas::Group (*canvas_group);
+
+ for (uint8_t i=0; i < 127; ++i) {
+ _note_lines[i] = new ArdourCanvas::SimpleLine(*_note_line_group,
+ 0, note_to_y(i), 10, note_to_y(i));
+ _note_lines[i]->property_color_rgba() = 0xEEEEEE55;
+ }
}
MidiStreamView::~MidiStreamView ()
RegionView*
-MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves)
+MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd)
{
boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion> (r);
/* great. we already have a MidiRegionView for this Region. use it again. */
(*i)->set_valid (true);
- display_region(dynamic_cast<MidiRegionView*>(*i), false);
+ (*i)->enable_display(wfd);
+ display_region(dynamic_cast<MidiRegionView*>(*i), wfd);
return NULL;
}
}
- // can't we all just get along?
- assert(_trackview.midi_track()->mode() != Destructive);
-
region_view = new MidiRegionView (canvas_group, _trackview, region,
_samples_per_unit, region_color);
-
- region_view->init (region_color, wait_for_waves);
+
+ region_view->init (region_color, false);
region_views.push_front (region_view);
/* follow global waveform setting */
- // FIXME
- //region_view->set_waveform_visible(_trackview.editor.show_waveforms());
+ if (wfd) {
+ region_view->enable_display(true);
+ region_view->midi_region()->midi_source(0)->load_model();
+ }
/* display events and find note range */
- display_region(region_view, false);
+ display_region(region_view, wfd);
/* always display at least 1 octave range */
_highest_note = max(_highest_note, static_cast<uint8_t>(_lowest_note + 11));
}
void
-MidiStreamView::display_region(MidiRegionView* region_view, bool redisplay_events)
+MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
{
if ( ! region_view)
return;
- if (redisplay_events)
- region_view->begin_write();
-
boost::shared_ptr<MidiSource> source(region_view->midi_region()->midi_source(0));
- for (size_t i=0; i < source->model()->n_events(); ++i) {
- const MidiEvent& ev = source->model()->event_at(i);
-
- // Look at all note on events to find our note range
- if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
- _lowest_note = min(_lowest_note, ev.buffer[1]);
- _highest_note = max(_highest_note, ev.buffer[1]);
- }
+ if (load_model)
+ source->load_model();
- if (redisplay_events)
- region_view->add_event(ev);
+ if (source->model()) {
+ // Find our note range
+ for (size_t i=0; i < source->model()->n_notes(); ++i) {
+ const MidiModel::Note& note = source->model()->note_at(i);
+ update_bounds(note.note());
+ }
}
- if (redisplay_events)
- region_view->end_write();
+ // Display region contents
+ region_view->display_model(source->model());
+}
+
+void
+MidiStreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
+{
+ StreamView::display_diskstream(ds);
+ draw_note_separators();
}
// FIXME: code duplication with AudioStreamView
list<RegionView *>::iterator i, tmp;
for (i = region_views.begin(); i != region_views.end(); ++i) {
+ (*i)->enable_display(true); // FIXME: double display
(*i)->set_valid (false);
+
+ /* FIXME: slow. MidiRegionView needs a find_note_range method
+ * that finds the range without wasting time drawing the events */
+
+ // Load model if it isn't already, to get note range
+ MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
+ mrv->midi_region()->midi_source(0)->load_model();
}
- _lowest_note = 60; // middle C
- _highest_note = _lowest_note + 11;
+ //_lowest_note = 60; // middle C
+ //_highest_note = _lowest_note + 11;
if (_trackview.is_midi_track()) {
_trackview.get_diskstream()->playlist()->foreach_region (static_cast<StreamView*>(this), &StreamView::add_region_view);
}
+
+ /* Always display at least one octave */
+ if (_highest_note == 127) {
+ if (_lowest_note > (127 - 11))
+ _lowest_note = 127 - 11;
+ } else if (_highest_note < _lowest_note + 11) {
+ _highest_note = _lowest_note + 11;
+ }
for (i = region_views.begin(); i != region_views.end(); ) {
tmp = i;
delete *i;
region_views.erase (i);
} else {
+ (*i)->enable_display(true);
(*i)->set_y_position_and_height(0, height); // apply note range
}
i = tmp;
}
-
+
/* now fix layering */
for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
region_layered (*i);
}
+
+ draw_note_separators();
+}
+
+
+void
+MidiStreamView::update_contents_y_position_and_height ()
+{
+ StreamView::update_contents_y_position_and_height();
+ draw_note_separators();
+}
+
+void
+MidiStreamView::draw_note_separators()
+{
+ for (uint8_t i=0; i < 127; ++i) {
+ if (i >= _lowest_note-1 && i <= _highest_note) {
+ _note_lines[i]->property_x1() = 0;
+ _note_lines[i]->property_x2() = canvas_rect->property_x2() - 2;
+ _note_lines[i]->property_y1() = note_to_y(i);
+ _note_lines[i]->property_y2() = note_to_y(i);
+ _note_lines[i]->show();
+ } else {
+ _note_lines[i]->hide();
+ }
+ }
+}
+
+
+void
+MidiStreamView::set_note_range(VisibleNoteRange r)
+{
+ _range = r;
+ if (r == FullRange) {
+ _lowest_note = 0;
+ _highest_note = 127;
+ } else {
+ _lowest_note = 60;
+ _highest_note = 60;
+ }
+ redisplay_diskstream();
+}
+
+
+void
+MidiStreamView::update_bounds(uint8_t note_num)
+{
+ _lowest_note = min(_lowest_note, note_num);
+ _highest_note = max(_highest_note, note_num);
}
}
void
-MidiStreamView::update_rec_regions (boost::shared_ptr<MidiBuffer> data, nframes_t start, nframes_t dur)
+MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t start, nframes_t dur)
{
ENSURE_GUI_THREAD (bind (mem_fun (*this, &MidiStreamView::update_rec_regions), data, start, dur));
/* 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);
- mrv->extend_active_notes();
+ // FIXME: slow
+ for (size_t i=0; i < data->n_notes(); ++i) {
+ const MidiModel::Note& note = data->note_at(i);
+ if (note.time() > start + dur)
+ break;
+
+ if (note.time() >= start)
+ if (data->note_mode() == Percussive || note.duration() > 0)
+ mrv->add_note(note);
+ else
+ mrv->add_event(note.on_event());
+
+ if (note.duration() > 0 && note.end_time() >= start)
+ mrv->add_event(note.off_event());
+
}
+
+ mrv->extend_active_notes();
}
}
}
void
-MidiStreamView::rec_data_range_ready (boost::shared_ptr<MidiBuffer> data, jack_nframes_t start, jack_nframes_t dur, boost::weak_ptr<Source> weak_src)
+MidiStreamView::rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur, boost::weak_ptr<Source> weak_src)
{
// this is called from the butler thread for now
- ENSURE_GUI_THREAD(bind (mem_fun (*this, &MidiStreamView::rec_data_range_ready), data, start, dur, weak_src));
+ ENSURE_GUI_THREAD(bind (mem_fun (*this, &MidiStreamView::rec_data_range_ready), start, dur, weak_src));
boost::shared_ptr<SMFSource> src (boost::dynamic_pointer_cast<SMFSource>(weak_src.lock()));
//cerr << src.get() << " MIDI READY: " << start << " * " << dur
// << " -- " << data->size() << " events!" << endl;
- this->update_rec_regions (data, start, dur);
+ this->update_rec_regions (src->model(), start, dur);
}
void