Fix time / positioning of PC flags (beat time).

Fix needless string copying in flag stuff.
Clean up.


git-svn-id: svn://localhost/ardour2/branches/3.0@4601 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2009-02-16 05:54:12 +00:00
parent de88640598
commit 31a6e0b254
6 changed files with 134 additions and 139 deletions

View File

@ -5,7 +5,6 @@
using namespace Gnome::Canvas;
using namespace std;
void
CanvasFlag::delete_allocated_objects()
{
@ -20,7 +19,7 @@ CanvasFlag::delete_allocated_objects()
}
void
CanvasFlag::set_text(string& a_text)
CanvasFlag::set_text(const string& a_text)
{
delete_allocated_objects();

View File

@ -1,6 +1,7 @@
#ifndef CANVASFLAG_H_
#define CANVASFLAG_H_
#include <string>
#include <libgnomecanvasmm/group.h>
#include <libgnomecanvasmm/widget.h>
@ -19,41 +20,41 @@ class CanvasFlag : public Group, public InteractiveItem
{
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)
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();
virtual bool on_event(GdkEvent* ev);
void set_text(string& a_text);
void set_text(const std::string& a_text);
protected:
InteractiveText* _text;
double _height;
guint _outline_color_rgba;
guint _fill_color_rgba;
MidiRegionView& _region;
InteractiveText* _text;
double _height;
guint _outline_color_rgba;
guint _fill_color_rgba;
MidiRegionView& _region;
private:
void delete_allocated_objects();
SimpleLine* _line;
InteractiveRect* _rect;
SimpleLine* _line;
InteractiveRect* _rect;
};

View File

@ -14,7 +14,7 @@ using namespace std;
CanvasProgramChange::CanvasProgramChange(
MidiRegionView& region,
Group& parent,
string& text,
const string& text,
double height,
double x,
double y,

View File

@ -20,7 +20,7 @@ public:
CanvasProgramChange(
MidiRegionView& region,
Group& parent,
string& text,
const string& text,
double height,
double x,
double y,

View File

@ -609,8 +609,7 @@ MidiRegionView::display_program_change_flags()
MIDI::Name::MidiPatchManager::instance().find_patch(
_model_name, _custom_device_mode, channel, patch_key);
ControlEvent program_change(beats_to_frames(event_time),
uint8_t(program_number), channel);
PCEvent program_change(event_time, uint8_t(program_number), channel);
if (patch != 0) {
add_pgm_change(program_change, patch->name());
@ -753,7 +752,7 @@ MidiRegionView::add_ghost (TimeAxisView& tv)
if (mtv && mtv->midi_view()) {
/* if ghost is inserted into midi track, use a dedicated midi ghost canvas group
to allow having midi notes on top of note lines and waveforms under it.
to allow having midi notes on top of note lines and waveforms.
*/
ghost = new MidiGhostRegion (*mtv->midi_view(), trackview, unit_position);
} else {
@ -921,10 +920,7 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note)
if (_active_notes[note->note()]) {
CanvasNote* const old_rect = _active_notes[note->note()];
boost::shared_ptr<NoteType> old_note = old_rect->note();
cerr << "MidiModel: WARNING: Note has length 0: chan " << old_note->channel()
<< "note " << (int)old_note->note() << " @ " << old_note->time() << endl;
/* FIXME: How large to make it? Make it a diamond? */
old_rect->property_x2() = old_rect->property_x1() + 2.0;
old_rect->property_x2() = x;
old_rect->property_outline_what() = (guint32) 0xF;
}
_active_notes[note->note()] = ev_rect;
@ -971,16 +967,12 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note)
}
void
MidiRegionView::add_pgm_change(ControlEvent& program, string displaytext)
MidiRegionView::add_pgm_change(PCEvent& program, const string& displaytext)
{
assert(program.time >= 0);
// dont display program changes beyond the region bounds
if (program.time - _region->start() >= _region->length() || program.time < _region->start())
return;
ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
const double x = trackview.editor().frame_to_pixel((nframes64_t)program.time - _region->start());
const double x = trackview.editor().frame_to_pixel(beats_to_frames(program.time));
double height = midi_stream_view()->contents_height();
@ -993,6 +985,13 @@ MidiRegionView::add_pgm_change(ControlEvent& program, string displaytext)
_custom_device_mode,
program.time, program.channel, program.value));
// Show unless program change is beyond the region bounds
if (program.time - _region->start() >= _region->length() || program.time < _region->start()) {
pgm_change->hide();
} else {
pgm_change->show();
}
_pgm_changes.push_back(pgm_change);
}
@ -1001,7 +1000,7 @@ MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::Patch
{
cerr << "getting patch key at " << time << " for channel " << channel << endl;
Evoral::Parameter bank_select_msb(MidiCCAutomation, channel, MIDI_CTL_MSB_BANK);
boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
float msb = -1.0;
if (msb_control != 0) {
msb = int(msb_control->get_float(true, time));
@ -1009,7 +1008,7 @@ MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::Patch
}
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> lsb_control = _model->control(bank_select_lsb);
float lsb = -1.0;
if (lsb_control != 0) {
lsb = lsb_control->get_float(true, time);
@ -1017,7 +1016,7 @@ MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::Patch
}
Evoral::Parameter program_change(MidiPgmChangeAutomation, channel, 0);
boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
float program_number = -1.0;
if (program_control != 0) {
program_number = program_control->get_float(true, time);
@ -1032,24 +1031,24 @@ MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::Patch
void
MidiRegionView::alter_program_change(ControlEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch)
MidiRegionView::alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch)
{
// TODO: Get the real event here and alter them at the original times
Evoral::Parameter bank_select_msb(MidiCCAutomation, old_program.channel, MIDI_CTL_MSB_BANK);
boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
boost::shared_ptr<Evoral::Control> msb_control = _model->control(bank_select_msb);
if (msb_control != 0) {
msb_control->set_float(float(new_patch.msb), true, old_program.time);
}
// TODO: Get the real event here and alter them at the original times
Evoral::Parameter bank_select_lsb(MidiCCAutomation, old_program.channel, MIDI_CTL_LSB_BANK);
boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
boost::shared_ptr<Evoral::Control> lsb_control = _model->control(bank_select_lsb);
if (lsb_control != 0) {
lsb_control->set_float(float(new_patch.lsb), true, old_program.time);
}
Evoral::Parameter program_change(MidiPgmChangeAutomation, old_program.channel, 0);
boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
boost::shared_ptr<Evoral::Control> program_control = _model->control(program_change);
assert(program_control != 0);
program_control->set_float(float(new_patch.program_number), true, old_program.time);
@ -1060,7 +1059,7 @@ MidiRegionView::alter_program_change(ControlEvent& old_program, const MIDI::Name
void
MidiRegionView::program_selected(CanvasProgramChange& program, const MIDI::Name::PatchPrimaryKey& new_patch)
{
ControlEvent program_change_event(program.event_time(), program.program(), program.channel());
PCEvent program_change_event(program.event_time(), program.program(), program.channel());
alter_program_change(program_change_event, new_patch);
}
@ -1077,7 +1076,7 @@ MidiRegionView::previous_program(CanvasProgramChange& program)
program.channel(),
key);
ControlEvent program_change_event(program.event_time(), program.program(), program.channel());
PCEvent program_change_event(program.event_time(), program.program(), program.channel());
if (patch) {
alter_program_change(program_change_event, patch->patch_primary_key());
}
@ -1095,7 +1094,8 @@ MidiRegionView::next_program(CanvasProgramChange& program)
_custom_device_mode,
program.channel(),
key);
ControlEvent program_change_event(program.event_time(), program.program(), program.channel());
PCEvent program_change_event(program.event_time(), program.program(), program.channel());
if (patch) {
alter_program_change(program_change_event, patch->patch_primary_key());
}
@ -1246,81 +1246,83 @@ void
MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
{
// TODO: This would be faster/nicer with a MoveCommand that doesn't need to copy...
if (_selection.find(ev) != _selection.end()) {
uint8_t lowest_note_in_selection = midi_stream_view()->lowest_note();
uint8_t highest_note_in_selection = midi_stream_view()->highest_note();
uint8_t highest_note_difference = 0;
if (_selection.find(ev) == _selection.end()) {
return;
}
// find highest and lowest notes first
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
uint8_t pitch = (*i)->note()->note();
lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
highest_note_in_selection = std::max(highest_note_in_selection, pitch);
uint8_t lowest_note_in_selection = midi_stream_view()->lowest_note();
uint8_t highest_note_in_selection = midi_stream_view()->highest_note();
uint8_t highest_note_difference = 0;
// find highest and lowest notes first
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
uint8_t pitch = (*i)->note()->note();
lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
highest_note_in_selection = std::max(highest_note_in_selection, pitch);
}
/*
cerr << "dnote: " << (int) dnote << endl;
cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
<< " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
<< int(highest_note_in_selection) << endl;
cerr << "selection size: " << _selection.size() << endl;
cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
*/
// Make sure the note pitch does not exceed the MIDI standard range
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
highest_note_difference = highest_note_in_selection - 127;
}
start_delta_command(_("move notes"));
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
Selection::iterator next = i;
++next;
const boost::shared_ptr<NoteType> copy(new NoteType(*(*i)->note().get()));
// we need to snap here again in nframes64_t in order to be sample accurate
double start_frames = snap_to_frame(beats_to_frames((*i)->note()->time()) + dt);
// keep notes inside region if dragged beyond left region bound
if (start_frames < _region->start()) {
start_frames = _region->start();
}
/*
cerr << "dnote: " << (int) dnote << endl;
cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
<< " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
<< int(highest_note_in_selection) << endl;
cerr << "selection size: " << _selection.size() << endl;
cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
*/
copy->set_time(frames_to_beats(start_frames));
uint8_t original_pitch = (*i)->note()->note();
uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
// Make sure the note pitch does not exceed the MIDI standard range
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
highest_note_difference = highest_note_in_selection - 127;
}
// keep notes in standard midi range
clamp_to_0_127(new_pitch);
start_delta_command(_("move notes"));
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
Selection::iterator next = i;
++next;
const boost::shared_ptr<NoteType> copy(new NoteType(*(*i)->note().get()));
// we need to snap here again in nframes64_t in order to be sample accurate
double start_frames = snap_to_frame(beats_to_frames((*i)->note()->time()) + dt);
// keep notes inside region if dragged beyond left region bound
if (start_frames < _region->start()) {
start_frames = _region->start();
}
copy->set_time(frames_to_beats(start_frames));
uint8_t original_pitch = (*i)->note()->note();
uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
// keep notes in standard midi range
clamp_to_0_127(new_pitch);
// keep original pitch if note is dragged outside valid midi range
if ((original_pitch != 0 && new_pitch == 0)
|| (original_pitch != 127 && new_pitch == 127)) {
new_pitch = original_pitch;
}
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
copy->set_note(new_pitch);
command_remove_note(*i);
command_add_note(copy, (*i)->selected());
i = next;
// keep original pitch if note is dragged outside valid midi range
if ((original_pitch != 0 && new_pitch == 0)
|| (original_pitch != 127 && new_pitch == 127)) {
new_pitch = original_pitch;
}
apply_command();
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
copy->set_note(new_pitch);
// care about notes being moved beyond the upper/lower bounds on the canvas
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
highest_note_in_selection > midi_stream_view()->highest_note()) {
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
}
command_remove_note(*i);
command_add_note(copy, (*i)->selected());
i = next;
}
apply_command();
// care about notes being moved beyond the upper/lower bounds on the canvas
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
highest_note_in_selection > midi_stream_view()->highest_note()) {
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
}
}

View File

@ -19,6 +19,7 @@
#ifndef __gtk_ardour_midi_region_view_h__
#define __gtk_ardour_midi_region_view_h__
#include <string>
#include <vector>
#include <libgnomecanvasmm.h>
@ -96,28 +97,20 @@ class MidiRegionView : public RegionView
void add_note(const boost::shared_ptr<NoteType> note);
void resolve_note(uint8_t note_num, double end_time);
struct ControlEvent
{
nframes_t time;
uint8_t value;
uint8_t channel;
ControlEvent(nframes_t a_time, uint8_t a_value, uint8_t a_channel)
struct PCEvent {
PCEvent(double a_time, uint8_t a_value, uint8_t a_channel)
: time(a_time), value(a_value), channel(a_channel) {}
ControlEvent& operator=(const ControlEvent& other) {
time = other.time;
value = other.value;
channel = other.channel;
return *this;
}
double time;
uint8_t value;
uint8_t channel;
};
/** Add a new program change flag to the canvas.
* @param program the MidiRegionView::ControlEvent to add
* @param program the MidiRegionView::PCEvent to add
* @param the text to display in the flag
*/
void add_pgm_change(ControlEvent& program, string displaytext);
void add_pgm_change(PCEvent& program, const std::string& displaytext);
/** Look up the given time and channel in the 'automation' and set keys accordingly.
* @param time the time of the program change event
@ -128,10 +121,10 @@ class MidiRegionView : public RegionView
void get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
/** Change the 'automation' data of old_program to new values which correspond to new_patch.
* @param old_program identifies the program change event which is to be altered
* @param new_patch defines the new lsb, msb and program number which are to be set in the automation list data
* @param old_program the program change event which is to be altered
* @param new_patch the new lsb, msb and program number which are to be set
*/
void alter_program_change(ControlEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch);
void alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch);
/** Alter a given program to the new given one.
* (Called on context menu select on CanvasProgramChange)
@ -160,7 +153,7 @@ class MidiRegionView : public RegionView
void display_model(boost::shared_ptr<ARDOUR::MidiModel> model);
void start_delta_command(string name = "midi edit");
void start_delta_command(std::string name = "midi edit");
void command_add_note(const boost::shared_ptr<NoteType> note, bool selected);
void command_remove_note(ArdourCanvas::CanvasNoteEvent* ev);
@ -308,10 +301,10 @@ class MidiRegionView : public RegionView
uint8_t _current_range_max;
/// MIDNAM information of the current track: Model name of MIDNAM file
string _model_name;
std::string _model_name;
/// MIDNAM information of the current track: CustomDeviceMode
string _custom_device_mode;
std::string _custom_device_mode;
typedef std::vector<ArdourCanvas::CanvasNoteEvent*> Events;
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > PgmChanges;