* added myself to about.cc

* created ArdourCanvas::CanvasFlag as a base class for flags
* removed obsolete cruft from midi_model
* made MidiTimeAxisView and MidiRegionView work together to display program changes as
  names by means of MidiPatchManager


git-svn-id: svn://localhost/ardour2/branches/3.0@4307 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Hans Baier 2008-12-11 08:06:27 +00:00
parent dfed4965b7
commit e009016b03
12 changed files with 272 additions and 96 deletions

View File

@ -131,6 +131,7 @@ axis_view.cc
bundle_manager.cc
canvas-note-event.cc
canvas-note.cc
canvas-flag.cc
canvas-program-change.cc
canvas-simpleline.c
canvas-simplerect.c

View File

@ -148,6 +148,7 @@ static const char* authors[] = {
N_("Christopher George"),
N_("Robert Jordens"),
N_("Dave Robillard"),
N_("Hans Baier"),
N_("Hans Fugal"),
N_("Brian Ahr"),
N_("Nimal Ratnayake"),

View File

@ -0,0 +1,41 @@
#include "canvas-flag.h"
#include <iostream>
#include "ardour_ui.h"
using namespace Gnome::Canvas;
using namespace std;
void
CanvasFlag::set_text(string a_text)
{
if (_text) {
delete _text;
}
_text = new Text(*this, 0.0, 0.0, a_text);
_text->property_justification() = Gtk::JUSTIFY_CENTER;
_text->property_fill_color_rgba() = _outline_color_rgba;
double flagwidth = _text->property_text_width() + 10.0;
double flagheight = _text->property_text_height() + 3.0;
_text->property_x() = flagwidth / 2.0;
_text->property_y() = flagheight / 2.0;
_text->show();
_line = new SimpleLine(*this, 0.0, 0.0, 0.0, _height);
_line->property_color_rgba() = _outline_color_rgba;
_rect = new SimpleRect(*this, 0.0, 0.0, flagwidth, flagheight);
_rect->property_outline_color_rgba() = _outline_color_rgba;
_rect->property_fill_color_rgba() = _fill_color_rgba;
_text->lower_to_bottom();
_text->raise(2);
}
CanvasFlag::~CanvasFlag()
{
delete _line;
delete _rect;
if(_text) {
delete _text;
}
}

58
gtk2_ardour/canvas-flag.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef CANVASFLAG_H_
#define CANVASFLAG_H_
#include <libgnomecanvasmm/group.h>
#include <libgnomecanvasmm/text.h>
#include <libgnomecanvasmm/widget.h>
#include <ardour/midi_model.h>
#include "simplerect.h"
#include "simpleline.h"
class MidiRegionView;
namespace Gnome {
namespace Canvas {
class CanvasFlag : public Group
{
public:
CanvasFlag(
MidiRegionView& region,
Group& parent,
double height,
guint outline_color_rgba = 0xc0c0c0ff,
guint fill_color_rgba = 0x07070707,
double x = 0.0,
double y = 0.0
) : Group(parent, x, y)
, _text(0)
, _height(height)
, _outline_color_rgba(outline_color_rgba)
, _fill_color_rgba(fill_color_rgba)
, _region(region)
, _line(0)
, _rect(0)
{}
virtual ~CanvasFlag();
void set_text(string a_text);
protected:
Text* _text;
double _height;
guint _outline_color_rgba;
guint _fill_color_rgba;
private:
MidiRegionView& _region;
SimpleLine* _line;
SimpleRect* _rect;
};
} // namespace Canvas
} // namespace Gnome
#endif /*CANVASFLAG_H_*/

View File

@ -8,40 +8,24 @@ using namespace std;
CanvasProgramChange::CanvasProgramChange(
MidiRegionView& region,
Group& parent,
boost::shared_ptr<Evoral::Event> event,
string text,
double height,
double x,
double y)
: Group(parent, x, y)
, _region(region)
, _event(event)
, _text(0)
, _line(0)
, _rect(0)
: CanvasFlag(
region,
parent,
height,
ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get(),
ARDOUR_UI::config()->canvasvar_MidiProgramChangeFill.get(),
x,
y
)
{
char pgm_str[4];
snprintf(pgm_str, 4, "%d", (int)(((Evoral::MIDIEvent*)event.get())->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;
double flagheight = _text->property_text_height() + 3.0;
_text->property_x() = flagwidth / 2.0;
_text->property_y() = flagheight / 2.0;
_text->show();
_line = new SimpleLine(*this, 0.0, 0.0, 0.0, height);
_line->property_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get();
_rect = new SimpleRect(*this, 0.0, 0.0, flagwidth, flagheight);
_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeOutline.get();
_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiProgramChangeFill.get();
_text->lower_to_bottom();
_text->raise(2);
set_text(text);
}
CanvasProgramChange::~CanvasProgramChange()
{
delete _line;
delete _rect;
delete _text;
}

View File

@ -1,25 +1,20 @@
#ifndef CANVASPROGRAMCHANGE_H_
#define CANVASPROGRAMCHANGE_H_
#include <libgnomecanvasmm/group.h>
#include "simplerect.h"
#include "simpleline.h"
#include <libgnomecanvasmm/text.h>
#include <libgnomecanvasmm/widget.h>
#include <ardour/midi_model.h>
#include "canvas-flag.h"
class MidiRegionView;
namespace Gnome {
namespace Canvas {
class CanvasProgramChange : public Group
class CanvasProgramChange : public CanvasFlag
{
public:
CanvasProgramChange(
MidiRegionView& region,
Group& parent,
boost::shared_ptr<Evoral::Event> event,
string text,
double height,
double x = 0.0,
double y = 0.0
@ -28,11 +23,6 @@ public:
virtual ~CanvasProgramChange();
private:
MidiRegionView& _region;
boost::shared_ptr<Evoral::Event> _event;
Text* _text;
SimpleLine* _line;
SimpleRect* _rect;
};
} // namespace Canvas

View File

@ -33,6 +33,10 @@
#include <ardour/midi_source.h>
#include <ardour/midi_diskstream.h>
#include <ardour/midi_model.h>
#include <ardour/midi_patch_manager.h>
#include <evoral/Parameter.hpp>
#include <evoral/Control.hpp>
#include "streamview.h"
#include "midi_region_view.h"
@ -67,6 +71,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
, _default_note_length(0.0)
, _current_range_min(0)
, _current_range_max(0)
, _model_name(string())
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
, _delta_command(NULL)
@ -81,6 +87,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
, _force_channel(-1)
, _last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _model_name(string())
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
, _delta_command(NULL)
@ -97,6 +105,8 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
, _force_channel(-1)
, _last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _model_name(string())
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
, _delta_command(NULL)
@ -117,6 +127,8 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
, _force_channel(-1)
, _last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _model_name(string())
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
, _delta_command(NULL)
@ -175,6 +187,9 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
midi_view()->signal_channel_mode_changed().connect(
mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
midi_view()->signal_midi_patch_settings_changed().connect(
mem_fun(this, &MidiRegionView::midi_patch_settings_changed));
}
bool
@ -546,7 +561,9 @@ MidiRegionView::redisplay_model()
clear_events();
_model->read_lock();
/*MidiModel::Notes notes = _model->notes();
MidiModel::Notes notes = _model->notes();
/*
cerr << endl << _model->midi_source()->name() << " : redisplaying " << notes.size() << " notes:" << endl;
for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
cerr << "NOTE time: " << (*i)->time()
@ -555,27 +572,14 @@ MidiRegionView::redisplay_model()
<< " end-time: " << (*i)->end_time()
<< " velocity: " << int((*i)->velocity())
<< endl;
}*/
for (size_t i = 0; i < _model->n_notes(); ++i)
add_note(_model->note_at(i));
// Draw program change 'flags'
for (Automatable::Controls::iterator control = _model->controls().begin();
control != _model->controls().end(); ++control) {
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) {
Evoral::ControlIterator iter(control->second->list(), (*event)->when, (*event)->value);
boost::shared_ptr<Evoral::Event> event(new Evoral::Event());
_model->control_to_midi_event(event, iter);
add_pgm_change(event);
}
break;
}
}
*/
for (size_t i = 0; i < _model->n_notes(); ++i) {
add_note(_model->note_at(i));
}
find_and_insert_program_chage_flags();
// Is this necessary?
/*for (Automatable::Controls::const_iterator i = _model->controls().begin();
@ -606,7 +610,6 @@ MidiRegionView::redisplay_model()
_automation_children.insert(std::make_pair(i->second->parameter(), arv));
}*/
_model->read_unlock();
} else {
@ -614,6 +617,74 @@ MidiRegionView::redisplay_model()
}
}
void
MidiRegionView::find_and_insert_program_change_flags()
{
// Draw program change 'flags'
for (Automatable::Controls::iterator control = _model->controls().begin();
control != _model->controls().end(); ++control) {
if (control->first.type() == MidiPgmChangeAutomation) {
Glib::Mutex::Lock list_lock (control->second->list()->lock());
uint8_t channel = control->first.channel();
for (AutomationList::const_iterator event = control->second->list()->begin();
event != control->second->list()->end(); ++event) {
double event_time = (*event)->when;
double program_number = (*event)->value;
//cerr << " got program change on channel " << int(channel) << " time: " << event_time << " number: " << program_number << endl;
// find bank select msb and lsb for the program change
Evoral::Parameter bank_select_msb(MidiCCAutomation, channel, MIDI_CTL_MSB_BANK);
Evoral::Parameter bank_select_lsb(MidiCCAutomation, channel, MIDI_CTL_LSB_BANK);
boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
boost::shared_ptr<MIDI::Name::MasterDeviceNames> master_device
= MIDI::Name::MidiPatchManager::instance().master_device_by_model(_model_name);
MIDI::Name::Patch patch;
if (master_device != 0 && _custom_device_mode != "") {
uint8_t msb = 0;
if (msb_control != 0) {
msb = uint8_t(msb_control->get_float(true, event_time));
}
uint8_t lsb = 0;
if (lsb_control != 0) {
lsb = uint8_t(lsb_control->get_float(true, event_time));
}
//cerr << " got msb " << int(msb) << " and lsb " << int(lsb) << endl;
patch = master_device->find_patch(
_custom_device_mode,
channel,
msb,
lsb,
uint8_t(program_number)
);
//cerr << " got patch with name " << patch.name() << " number " << patch.number() << endl;
}
if (patch.name() != "") {
add_pgm_change(event_time, patch.name());
} else {
char buf[4];
snprintf(buf, 4, "%d", int(program_number));
add_pgm_change(event_time, buf);
}
}
break;
} else if (control->first.type() == MidiCCAutomation) {
//cerr << " found CC Automation of channel " << int(control->first.channel()) << " and id " << control->first.id() << endl;
}
}
}
MidiRegionView::~MidiRegionView ()
{
@ -925,21 +996,21 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
}
void
MidiRegionView::add_pgm_change(boost::shared_ptr<Evoral::Event> event)
MidiRegionView::add_pgm_change(nframes_t time, string displaytext)
{
assert(event->time() >= 0);
assert(time >= 0);
// dont display notes beyond the region bounds
if (event->time() - _region->start() >= _region->length() || event->time() < _region->start())
if (time - _region->start() >= _region->length() || time < _region->start())
return;
ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
const double x = trackview.editor.frame_to_pixel((nframes64_t)event->time() - _region->start());
const double x = trackview.editor.frame_to_pixel((nframes64_t)time - _region->start());
double height = midi_stream_view()->contents_height();
_pgm_changes.push_back(
boost::shared_ptr<CanvasProgramChange>(
new CanvasProgramChange(*this, *group, event, height, x, 1.0)));
new CanvasProgramChange(*this, *group, displaytext, height, x, 1.0)));
}
void
@ -1438,3 +1509,11 @@ MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
_last_channel_selection = mask;
}
void
MidiRegionView::midi_patch_settings_changed(std::string model, std::string custom_device_mode)
{
_model_name = model;
_custom_device_mode = custom_device_mode;
redisplay_model();
}

View File

@ -86,7 +86,8 @@ class MidiRegionView : public RegionView
void add_note(const boost::shared_ptr<Evoral::Note> note);
void resolve_note(uint8_t note_num, double end_time);
void add_pgm_change(boost::shared_ptr<Evoral::Event> event);
void add_pgm_change(nframes_t time, string displaytext);
void find_and_insert_program_change_flags();
void begin_write();
void end_write();
@ -219,6 +220,7 @@ class MidiRegionView : public RegionView
bool note_canvas_event(GdkEvent* ev);
void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
void midi_patch_settings_changed(std::string model, std::string custom_device_mode);
void clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev);
void clear_selection() { clear_selection_except(NULL); }
@ -229,6 +231,9 @@ class MidiRegionView : public RegionView
double _default_note_length;
uint8_t _current_range_min;
uint8_t _current_range_max;
string _model_name;
string _custom_device_mode;
typedef std::vector<ArdourCanvas::CanvasNoteEvent*> Events;
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > PgmChanges;

View File

@ -141,36 +141,28 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shar
}
HBox* midi_controls_hbox = manage(new HBox());
// Instrument patch selector
ComboBoxText* model_selector = manage(new ComboBoxText());
ComboBoxText* custom_device_mode_selector = manage(new ComboBoxText());
MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
for (MIDI::Name::MasterDeviceNames::Models::const_iterator model = patch_manager.all_models().begin();
model != patch_manager.all_models().end();
++model) {
model_selector->append_text(model->c_str());
_model_selector.append_text(model->c_str());
}
_model_selector.signal_changed().connect(mem_fun(*this, &MidiTimeAxisView::model_changed));
_custom_device_mode_selector.signal_changed().connect(
mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
// TODO: persist the choice
model_selector->set_active(0);
std::list<std::string> device_modes = patch_manager.custom_device_mode_names_by_model(model_selector->get_active_text());
for (std::list<std::string>::const_iterator i = device_modes.begin(); i != device_modes.end(); ++i) {
cerr << "found custom device mode " << *i << endl;
custom_device_mode_selector->append_text(*i);
}
// this initializes the comboboxes and sends out the signal
_model_selector.set_active(0);
// TODO: persist the choice
custom_device_mode_selector->set_active(0);
midi_controls_hbox->pack_start(_channel_selector, true, false);
if (!patch_manager.all_models().empty()) {
_midi_controls_box.pack_start(*model_selector, true, false);
_midi_controls_box.pack_start(*custom_device_mode_selector, true, false);
_midi_controls_box.pack_start(_model_selector, true, false);
_midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
}
_midi_controls_box.pack_start(*midi_controls_hbox, true, true);
@ -195,6 +187,26 @@ MidiTimeAxisView::~MidiTimeAxisView ()
_range_scroomer = 0;
}
void MidiTimeAxisView::model_changed()
{
std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
.custom_device_mode_names_by_model(_model_selector.get_active_text());
_custom_device_mode_selector.clear_items();
for (std::list<std::string>::const_iterator i = device_modes.begin(); i != device_modes.end(); ++i) {
cerr << "found custom device mode " << *i << endl;
_custom_device_mode_selector.append_text(*i);
}
_custom_device_mode_selector.set_active(0);
}
void MidiTimeAxisView::custom_device_mode_changed()
{
_midi_patch_settings_changed.emit(_model_selector.get_active_text(), _custom_device_mode_selector.get_active_text());
}
MidiStreamView*
MidiTimeAxisView::midi_view()
{

View File

@ -77,10 +77,19 @@ class MidiTimeAxisView : public RouteTimeAxisView
void update_range();
sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed()
{ return _channel_selector.mode_changed; }
sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed() {
return _channel_selector.mode_changed;
}
sigc::signal<void, string, string>& signal_midi_patch_settings_changed() {
return _midi_patch_settings_changed;
}
private:
sigc::signal<void, string, string> _midi_patch_settings_changed;
void model_changed();
void custom_device_mode_changed();
void append_extra_display_menu_items ();
void build_automation_action_menu ();
@ -102,6 +111,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
Gtk::RadioMenuItem* _percussion_mode_item;
Gtk::VBox _midi_controls_box;
MidiMultipleChannelSelector _channel_selector;
Gtk::ComboBoxText _model_selector;
Gtk::ComboBoxText _custom_device_mode_selector;
};
#endif /* __ardour_midi_time_axis_h__ */

View File

@ -278,13 +278,6 @@ XMLNode& MidiModel::DeltaCommand::get_state()
return *delta_command;
}
struct EventTimeComparator {
typedef const Evoral::Event* value_type;
inline bool operator()(const Evoral::Event& a, const Evoral::Event& b) const {
return a.time() >= b.time();
}
};
/** Write the model to a MidiSource (i.e. save the model).
* This is different from manually using read to write to a source in that
* note off events are written regardless of the track mode. This is so the

View File

@ -147,6 +147,7 @@ public:
Patch& find_patch(uint8_t msb, uint8_t lsb, uint8_t program_number) {
PatchPrimaryKey key(msb, lsb, program_number);
assert(key.is_sane());
return _patch_map[key];
}