mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-12 17:46:34 +01:00
* removed old implementation for Program Changes from MidiModel
* Added Automation based implementation for Program Changes, Pitch Bender and Channel Aftertouch git-svn-id: svn://localhost/ardour2/branches/3.0@3304 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
da45f489dd
commit
0e394fb66b
8 changed files with 131 additions and 95 deletions
|
|
@ -477,12 +477,11 @@ MidiRegionView::redisplay_model()
|
||||||
add_note(_model->note_at(i));
|
add_note(_model->note_at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiModel::PgmChanges& pgm_changes = _model->pgm_changes();
|
// TODO: Add program changes here
|
||||||
for_each(pgm_changes.begin(), pgm_changes.end(),
|
|
||||||
sigc::mem_fun(this, &MidiRegionView::add_pgm_change));
|
|
||||||
|
|
||||||
end_write();
|
end_write();
|
||||||
|
|
||||||
|
// Is this necessary ??????????
|
||||||
/*for (Automatable::Controls::const_iterator i = _model->controls().begin();
|
/*for (Automatable::Controls::const_iterator i = _model->controls().begin();
|
||||||
i != _model->controls().end(); ++i) {
|
i != _model->controls().end(); ++i) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,12 @@ MidiTimeAxisView::add_controller_track()
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::create_automation_child (Parameter param, bool show)
|
MidiTimeAxisView::create_automation_child (Parameter param, bool show)
|
||||||
{
|
{
|
||||||
if (param.type() == MidiCCAutomation) {
|
if (
|
||||||
|
param.type() == MidiCCAutomation ||
|
||||||
|
param.type() == MidiPgmChangeAutomation ||
|
||||||
|
param.type() == MidiPitchBenderAutomation ||
|
||||||
|
param.type() == MidiChannelAftertouchAutomation
|
||||||
|
) {
|
||||||
|
|
||||||
/* FIXME: don't create AutomationList for track itself
|
/* FIXME: don't create AutomationList for track itself
|
||||||
* (not actually needed or used, since the automation is region-ey) */
|
* (not actually needed or used, since the automation is region-ey) */
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@
|
||||||
#include <ardour/midi_ring_buffer.h>
|
#include <ardour/midi_ring_buffer.h>
|
||||||
#include <ardour/automatable.h>
|
#include <ardour/automatable.h>
|
||||||
#include <ardour/note.h>
|
#include <ardour/note.h>
|
||||||
|
#include <ardour/types.h>
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
class MidiSource;
|
class MidiSource;
|
||||||
|
|
||||||
// x , y
|
|
||||||
class MidiControlIterator {
|
class MidiControlIterator {
|
||||||
public:
|
public:
|
||||||
boost::shared_ptr<const AutomationList> automation_list;
|
boost::shared_ptr<const AutomationList> automation_list;
|
||||||
|
|
@ -110,10 +110,6 @@ public:
|
||||||
inline Notes& notes() { return _notes; }
|
inline Notes& notes() { return _notes; }
|
||||||
inline const Notes& notes() const { return _notes; }
|
inline const Notes& notes() const { return _notes; }
|
||||||
|
|
||||||
typedef std::vector< boost::shared_ptr<MIDI::Event> > PgmChanges;
|
|
||||||
inline PgmChanges& pgm_changes() { return _pgm_changes; }
|
|
||||||
inline const PgmChanges& pgm_changes() const { return _pgm_changes; }
|
|
||||||
|
|
||||||
/** Add/Remove notes.
|
/** Add/Remove notes.
|
||||||
* Technically all operations can be implemented as one of these.
|
* Technically all operations can be implemented as one of these.
|
||||||
*/
|
*/
|
||||||
|
|
@ -195,7 +191,6 @@ public:
|
||||||
Notes::const_iterator _note_iter;
|
Notes::const_iterator _note_iter;
|
||||||
std::vector<MidiControlIterator> _control_iters;
|
std::vector<MidiControlIterator> _control_iters;
|
||||||
std::vector<MidiControlIterator>::iterator _control_iter;
|
std::vector<MidiControlIterator>::iterator _control_iter;
|
||||||
PgmChanges::const_iterator _pgm_change_iter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(*this, 0); }
|
const_iterator begin() const { return const_iterator(*this, 0); }
|
||||||
|
|
@ -218,13 +213,12 @@ private:
|
||||||
|
|
||||||
void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
|
void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
|
||||||
void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
|
void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
|
||||||
void append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value);
|
void append_automation_event_unlocked(AutomationType type, uint8_t chan, double time, uint8_t first_byte, uint8_t second_byte);
|
||||||
void append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number);
|
void append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number);
|
||||||
|
|
||||||
mutable Glib::RWLock _lock;
|
mutable Glib::RWLock _lock;
|
||||||
|
|
||||||
Notes _notes;
|
Notes _notes;
|
||||||
PgmChanges _pgm_changes;
|
|
||||||
|
|
||||||
NoteMode _note_mode;
|
NoteMode _note_mode;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,21 +80,34 @@ public:
|
||||||
* should be moved here */
|
* should be moved here */
|
||||||
|
|
||||||
inline double min() const {
|
inline double min() const {
|
||||||
if (_type == MidiCCAutomation)
|
switch(_type) {
|
||||||
|
case MidiCCAutomation:
|
||||||
|
case MidiPgmChangeAutomation:
|
||||||
|
case MidiPitchBenderAutomation:
|
||||||
|
case MidiChannelAftertouchAutomation:
|
||||||
return 0.0;
|
return 0.0;
|
||||||
else
|
|
||||||
|
default:
|
||||||
return DBL_MIN;
|
return DBL_MIN;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline double max() const {
|
inline double max() const {
|
||||||
if (_type == MidiCCAutomation)
|
switch(_type) {
|
||||||
|
case MidiCCAutomation:
|
||||||
|
case MidiPgmChangeAutomation:
|
||||||
|
case MidiChannelAftertouchAutomation:
|
||||||
return 127.0;
|
return 127.0;
|
||||||
else
|
case MidiPitchBenderAutomation:
|
||||||
|
return 16383.0;
|
||||||
|
|
||||||
|
default:
|
||||||
return DBL_MAX;
|
return DBL_MAX;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool is_integer() const {
|
inline bool is_integer() const {
|
||||||
return (_type == MidiCCAutomation);
|
return (_type >= MidiCCAutomation && _type <= MidiChannelAftertouchAutomation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,9 @@ namespace ARDOUR {
|
||||||
SoloAutomation = 0x8,
|
SoloAutomation = 0x8,
|
||||||
MuteAutomation = 0x10,
|
MuteAutomation = 0x10,
|
||||||
MidiCCAutomation = 0x20,
|
MidiCCAutomation = 0x20,
|
||||||
|
MidiPgmChangeAutomation = 0x21,
|
||||||
|
MidiPitchBenderAutomation = 0x22,
|
||||||
|
MidiChannelAftertouchAutomation = 0x23,
|
||||||
FadeInAutomation = 0x40,
|
FadeInAutomation = 0x40,
|
||||||
FadeOutAutomation = 0x80,
|
FadeOutAutomation = 0x80,
|
||||||
EnvelopeAutomation = 0x100
|
EnvelopeAutomation = 0x100
|
||||||
|
|
|
||||||
|
|
@ -87,14 +87,18 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Disabled for stablility reasons
|
|
||||||
MidiControlIterator earliest_control(boost::shared_ptr<AutomationList>(), DBL_MAX, 0.0);
|
MidiControlIterator earliest_control(boost::shared_ptr<AutomationList>(), DBL_MAX, 0.0);
|
||||||
|
|
||||||
_control_iters.reserve(model.controls().size());
|
_control_iters.reserve(model.controls().size());
|
||||||
for (Automatable::Controls::const_iterator i = model.controls().begin();
|
for (Automatable::Controls::const_iterator i = model.controls().begin();
|
||||||
i != model.controls().end(); ++i) {
|
i != model.controls().end(); ++i) {
|
||||||
|
|
||||||
assert(i->first.type() == MidiCCAutomation);
|
assert(
|
||||||
|
i->first.type() == MidiCCAutomation ||
|
||||||
|
i->first.type() == MidiPgmChangeAutomation ||
|
||||||
|
i->first.type() == MidiPitchBenderAutomation ||
|
||||||
|
i->first.type() == MidiChannelAftertouchAutomation
|
||||||
|
);
|
||||||
|
|
||||||
double x, y;
|
double x, y;
|
||||||
bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
|
bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
|
||||||
|
|
@ -119,8 +123,6 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
--_control_iter;
|
--_control_iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
if (_note_iter != model.notes().end()) {
|
if (_note_iter != model.notes().end()) {
|
||||||
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
||||||
|
|
@ -129,27 +131,10 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
++_note_iter;
|
++_note_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO: Disabled for stability reasons
|
|
||||||
if (earliest_control.automation_list && earliest_control.x < _event.time())
|
if (earliest_control.automation_list && earliest_control.x < _event.time())
|
||||||
model.control_to_midi_event(_event, earliest_control);
|
model.control_to_midi_event(_event, earliest_control);
|
||||||
else
|
else
|
||||||
_control_iter = _control_iters.end();
|
_control_iter = _control_iters.end();
|
||||||
*/
|
|
||||||
|
|
||||||
_pgm_change_iter = model.pgm_changes().end();
|
|
||||||
// find first program change which begins after t
|
|
||||||
for (PgmChanges::const_iterator i = model.pgm_changes().begin(); i != model.pgm_changes().end(); ++i) {
|
|
||||||
if ((*i)->time() >= t) {
|
|
||||||
_pgm_change_iter = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_pgm_change_iter != model.pgm_changes().end()) {
|
|
||||||
if((*_pgm_change_iter)->time() <= _event.time()) {
|
|
||||||
_event = MIDI::Event(*(*_pgm_change_iter), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_event.size() == 0) {
|
if (_event.size() == 0) {
|
||||||
//cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
|
//cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
|
||||||
|
|
@ -183,14 +168,12 @@ MidiModel::const_iterator::operator++()
|
||||||
<< " buffer: 0x" << int(_event.buffer()[0]) << " 0x" << int(_event.buffer()[1])
|
<< " buffer: 0x" << int(_event.buffer()[0]) << " 0x" << int(_event.buffer()[1])
|
||||||
<< " 0x" << int(_event.buffer()[2]) << endl;
|
<< " 0x" << int(_event.buffer()[2]) << endl;
|
||||||
|
|
||||||
if(! (_event.is_note() || _event.is_cc() || _event.is_pgm_change())) {
|
if(! (_event.is_note() || _event.is_cc() || _event.is_pgm_change() || _event.is_pitch_bender() || _event.is_channel_aftertouch()) ) {
|
||||||
cerr << "FAILED pgm change vector size: " << _model->pgm_changes().size() << endl;
|
|
||||||
cerr << "FAILED event buffer: " << hex << int(_event.buffer()[0]) << int(_event.buffer()[1]) << int(_event.buffer()[2]) << endl;
|
cerr << "FAILED event buffer: " << hex << int(_event.buffer()[0]) << int(_event.buffer()[1]) << int(_event.buffer()[2]) << endl;
|
||||||
}
|
}
|
||||||
assert(_event.is_note() || _event.is_cc() || _event.is_pgm_change());
|
assert((_event.is_note() || _event.is_cc() || _event.is_pgm_change() || _event.is_pitch_bender() || _event.is_channel_aftertouch()));
|
||||||
|
|
||||||
// TODO: This code crashes at the marked section
|
// TODO: This code crashes at the marked section
|
||||||
/*
|
|
||||||
// Increment past current control event
|
// Increment past current control event
|
||||||
if (_control_iter != _control_iters.end() && _control_iter->automation_list && _event.is_cc()) {
|
if (_control_iter != _control_iters.end() && _control_iter->automation_list && _event.is_cc()) {
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|
@ -222,9 +205,7 @@ MidiModel::const_iterator::operator++()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
enum Type { NIL, NOTE_ON, NOTE_OFF, AUTOMATION };
|
||||||
|
|
||||||
enum Type { NIL, NOTE_ON, NOTE_OFF, CC, PGM_CHANGE, PITCH_BENDER };
|
|
||||||
|
|
||||||
Type type = NIL;
|
Type type = NIL;
|
||||||
double t = 0;
|
double t = 0;
|
||||||
|
|
@ -243,21 +224,10 @@ MidiModel::const_iterator::operator++()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disabled for above mentioned reason, this loops endlessly otherwise
|
|
||||||
// Use the next earliest controller iff it's earlier than the note event
|
// Use the next earliest controller iff it's earlier than the note event
|
||||||
if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX)
|
if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX)
|
||||||
if (type == NIL || _control_iter->x < t)
|
if (type == NIL || _control_iter->x < t)
|
||||||
type = CC;
|
type = AUTOMATION;
|
||||||
*/
|
|
||||||
if(_pgm_change_iter != _model->pgm_changes().end()) {
|
|
||||||
if((*_pgm_change_iter)->time() <= t) {
|
|
||||||
type = PGM_CHANGE;
|
|
||||||
t = (*_pgm_change_iter)->time();
|
|
||||||
cerr << "operator++ got PGM CHANGE with time " << t << " and type " << hex
|
|
||||||
<< int((*_pgm_change_iter)->type()) << " and channel " << int((*_pgm_change_iter)->channel())
|
|
||||||
<< " and program " << int((*_pgm_change_iter)->pgm_number()) << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == NOTE_ON) {
|
if (type == NOTE_ON) {
|
||||||
cerr << "********** MIDI Iterator = note on" << endl;
|
cerr << "********** MIDI Iterator = note on" << endl;
|
||||||
|
|
@ -268,13 +238,9 @@ MidiModel::const_iterator::operator++()
|
||||||
cerr << "********** MIDI Iterator = note off" << endl;
|
cerr << "********** MIDI Iterator = note off" << endl;
|
||||||
_event = MIDI::Event(_active_notes.top()->off_event(), false);
|
_event = MIDI::Event(_active_notes.top()->off_event(), false);
|
||||||
_active_notes.pop();
|
_active_notes.pop();
|
||||||
} else if (type == CC) {
|
} else if (type == AUTOMATION) {
|
||||||
cerr << "********** MIDI Iterator = CC" << endl;
|
cerr << "********** MIDI Iterator = AUTOMATION" << endl;
|
||||||
_model->control_to_midi_event(_event, *_control_iter);
|
_model->control_to_midi_event(_event, *_control_iter);
|
||||||
} else if (type == PGM_CHANGE) {
|
|
||||||
cerr << "********** MIDI Iterator = program change" << endl;
|
|
||||||
_event = MIDI::Event(*(*_pgm_change_iter), false);
|
|
||||||
++_pgm_change_iter;
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "********** MIDI Iterator = END" << endl;
|
cerr << "********** MIDI Iterator = END" << endl;
|
||||||
_is_end = true;
|
_is_end = true;
|
||||||
|
|
@ -312,7 +278,6 @@ MidiModel::const_iterator::operator=(const const_iterator& other)
|
||||||
_note_iter = other._note_iter;
|
_note_iter = other._note_iter;
|
||||||
_control_iters = other._control_iters;
|
_control_iters = other._control_iters;
|
||||||
_control_iter = other._control_iter;
|
_control_iter = other._control_iter;
|
||||||
_pgm_change_iter = other._pgm_change_iter;
|
|
||||||
|
|
||||||
assert( ! _event.owns_buffer());
|
assert( ! _event.owns_buffer());
|
||||||
|
|
||||||
|
|
@ -381,7 +346,8 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes
|
||||||
bool
|
bool
|
||||||
MidiModel::control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const
|
MidiModel::control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& iter) const
|
||||||
{
|
{
|
||||||
if (iter.automation_list->parameter().type() == MidiCCAutomation) {
|
switch(iter.automation_list->parameter().type()) {
|
||||||
|
case MidiCCAutomation:
|
||||||
if (ev.size() < 3)
|
if (ev.size() < 3)
|
||||||
ev.set_buffer((Byte*)malloc(3), true);
|
ev.set_buffer((Byte*)malloc(3), true);
|
||||||
|
|
||||||
|
|
@ -395,7 +361,53 @@ MidiModel::control_to_midi_event(MIDI::Event& ev, const MidiControlIterator& ite
|
||||||
ev.time() = iter.x;
|
ev.time() = iter.x;
|
||||||
ev.size() = 3;
|
ev.size() = 3;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
|
case MidiPgmChangeAutomation:
|
||||||
|
if (ev.size() < 3)
|
||||||
|
ev.set_buffer((Byte*)malloc(3), true);
|
||||||
|
|
||||||
|
assert(iter.automation_list);
|
||||||
|
assert(iter.automation_list->parameter().channel() < 16);
|
||||||
|
assert(iter.automation_list->parameter().id() <= INT8_MAX);
|
||||||
|
assert(iter.y <= INT8_MAX);
|
||||||
|
ev.buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.automation_list->parameter().channel();
|
||||||
|
ev.buffer()[1] = (Byte)iter.y;
|
||||||
|
ev.buffer()[2] = 0;
|
||||||
|
ev.time() = iter.x;
|
||||||
|
ev.size() = 3;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MidiPitchBenderAutomation:
|
||||||
|
if (ev.size() < 3)
|
||||||
|
ev.set_buffer((Byte*)malloc(3), true);
|
||||||
|
|
||||||
|
assert(iter.automation_list);
|
||||||
|
assert(iter.automation_list->parameter().channel() < 16);
|
||||||
|
assert(iter.automation_list->parameter().id() <= INT8_MAX);
|
||||||
|
assert(iter.y <= INT8_MAX);
|
||||||
|
ev.buffer()[0] = MIDI_CMD_BENDER + iter.automation_list->parameter().channel();
|
||||||
|
ev.buffer()[1] = ((Byte)iter.y) & 0x7F; // LSB
|
||||||
|
ev.buffer()[2] = (((Byte)iter.y) >> 7) & 0x7F; // MSB
|
||||||
|
ev.time() = iter.x;
|
||||||
|
ev.size() = 3;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MidiChannelAftertouchAutomation:
|
||||||
|
if (ev.size() < 3)
|
||||||
|
ev.set_buffer((Byte*)malloc(3), true);
|
||||||
|
|
||||||
|
assert(iter.automation_list);
|
||||||
|
assert(iter.automation_list->parameter().channel() < 16);
|
||||||
|
assert(iter.automation_list->parameter().id() <= INT8_MAX);
|
||||||
|
assert(iter.y <= INT8_MAX);
|
||||||
|
ev.buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.automation_list->parameter().channel();
|
||||||
|
ev.buffer()[1] = (Byte)iter.y;
|
||||||
|
ev.buffer()[2] = 0;
|
||||||
|
ev.time() = iter.x;
|
||||||
|
ev.size() = 3;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -483,9 +495,13 @@ MidiModel::append(const MIDI::Event& ev)
|
||||||
} else if (ev.is_note_off()) {
|
} else if (ev.is_note_off()) {
|
||||||
append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
|
append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
|
||||||
} else if (ev.is_cc()) {
|
} else if (ev.is_cc()) {
|
||||||
append_cc_unlocked(ev.channel(), ev.time(), ev.cc_number(), ev.cc_value());
|
append_automation_event_unlocked(MidiCCAutomation, ev.channel(), ev.time(), ev.cc_number(), ev.cc_value());
|
||||||
} else if (ev.is_pgm_change()) {
|
} else if (ev.is_pgm_change()) {
|
||||||
append_pgm_change_unlocked(ev.channel(), ev.time(), ev.pgm_number());
|
append_automation_event_unlocked(MidiPgmChangeAutomation, ev.channel(), ev.time(), ev.pgm_number(), 0);
|
||||||
|
} else if (ev.is_pitch_bender()) {
|
||||||
|
append_automation_event_unlocked(MidiPitchBenderAutomation, ev.channel(), ev.time(), ev.pitch_bender_lsb(), ev.pitch_bender_msb());
|
||||||
|
} else if (ev.is_channel_aftertouch()) {
|
||||||
|
append_automation_event_unlocked(MidiChannelAftertouchAutomation, ev.channel(), ev.time(), ev.channel_aftertouch(), 0);
|
||||||
} else {
|
} else {
|
||||||
printf("MM Unknown event type %X\n", ev.type());
|
printf("MM Unknown event type %X\n", ev.type());
|
||||||
}
|
}
|
||||||
|
|
@ -556,35 +572,39 @@ MidiModel::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiModel::append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value)
|
MidiModel::append_automation_event_unlocked(AutomationType type, uint8_t chan, double time, uint8_t first_byte, uint8_t second_byte)
|
||||||
{
|
{
|
||||||
//cerr << "MidiModel " << this << " chan " << (int)chan <<
|
//cerr << "MidiModel " << this << " chan " << (int)chan <<
|
||||||
// " CC " << (int)number << " = " << (int)value << " @ " << time << endl;
|
// " CC " << (int)number << " = " << (int)value << " @ " << time << endl;
|
||||||
|
|
||||||
assert(chan < 16);
|
assert(chan < 16);
|
||||||
assert(_writing);
|
assert(_writing);
|
||||||
/** TODO: disabled for now until debugged....
|
|
||||||
_edited = true;
|
_edited = true;
|
||||||
|
double value;
|
||||||
|
|
||||||
Parameter param(MidiCCAutomation, number, chan);
|
uint32_t id = 0;
|
||||||
boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
|
|
||||||
control->list()->fast_simple_add(time, (double)value);
|
switch(type) {
|
||||||
*/
|
case MidiCCAutomation:
|
||||||
|
id = first_byte;
|
||||||
|
value = double(second_byte);
|
||||||
|
break;
|
||||||
|
case MidiChannelAftertouchAutomation:
|
||||||
|
case MidiPgmChangeAutomation:
|
||||||
|
id = 0;
|
||||||
|
value = double(first_byte);
|
||||||
|
break;
|
||||||
|
case MidiPitchBenderAutomation:
|
||||||
|
id = 0;
|
||||||
|
value = double((0x7F & second_byte) << 7 | (0x7F & first_byte));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Parameter param(type, id, chan);
|
||||||
MidiModel::append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number)
|
boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
|
||||||
{
|
control->list()->fast_simple_add(time, value);
|
||||||
//cerr << "MidiModel::append_pgm_change_unlocked: channel " << int(chan) << " time: " << time << " program number: " << int(number) <<endl;
|
|
||||||
assert(chan < 16);
|
|
||||||
assert(_writing);
|
|
||||||
_edited = true;
|
|
||||||
|
|
||||||
boost::shared_ptr<MIDI::Event> event_ptr(new MIDI::Event(time, 3, 0, true));
|
|
||||||
event_ptr->set_type(MIDI_CMD_PGM_CHANGE);
|
|
||||||
event_ptr->set_channel(chan);
|
|
||||||
event_ptr->set_pgm_number(number);
|
|
||||||
_pgm_changes.push_back(event_ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -933,11 +953,6 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
|
||||||
active_notes.pop();
|
active_notes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//write program changes
|
|
||||||
for (PgmChanges::const_iterator p = _pgm_changes.begin(); p != _pgm_changes.end(); ++p) {
|
|
||||||
events.push((*p).get());
|
|
||||||
}
|
|
||||||
|
|
||||||
while(!events.empty()) {
|
while(!events.empty()) {
|
||||||
source->append_event_unlocked(Frames, *events.top());
|
source->append_event_unlocked(Frames, *events.top());
|
||||||
cerr << "MidiModel::write_to appending event with time:" << dec << int(events.top()->time()) << hex
|
cerr << "MidiModel::write_to appending event with time:" << dec << int(events.top()->time()) << hex
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,13 @@ Parameter::to_string() const
|
||||||
return string_compose("parameter-%1", _id);
|
return string_compose("parameter-%1", _id);
|
||||||
} else if (_type == MidiCCAutomation) {
|
} else if (_type == MidiCCAutomation) {
|
||||||
return string_compose("midicc-%1-%2", _channel, _id);
|
return string_compose("midicc-%1-%2", _channel, _id);
|
||||||
|
} else if (_type == MidiPgmChangeAutomation) {
|
||||||
|
return string_compose("midi_pgm_change-%1", _channel);
|
||||||
|
} else if (_type == MidiPitchBenderAutomation) {
|
||||||
|
return string_compose("midi_pitch_bender-%1", _channel);
|
||||||
|
} else if (_type == MidiChannelAftertouchAutomation) {
|
||||||
|
return string_compose("midi_channel_aftertouch-%1", _channel);
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
|
||||||
PBD::warning << "Uninitialized Parameter to_string() called." << endmsg;
|
PBD::warning << "Uninitialized Parameter to_string() called." << endmsg;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,9 @@ struct Event {
|
||||||
inline uint8_t velocity() const { return (_buffer[2]); }
|
inline uint8_t velocity() const { return (_buffer[2]); }
|
||||||
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 uint16_t pitch_bender_value() const { return ((_buffer[1] << 8) | _buffer[2]); }
|
inline uint16_t pitch_bender_value() const { return (((0x7F & _buffer[1]) << 7) | (0x7F & _buffer[2])); }
|
||||||
|
inline uint8_t pitch_bender_lsb() const { return (_buffer[1]); }
|
||||||
|
inline uint8_t pitch_bender_msb() const { return (_buffer[2]); }
|
||||||
inline uint8_t pgm_number() const { return (_buffer[1]); }
|
inline uint8_t pgm_number() const { return (_buffer[1]); }
|
||||||
inline void set_pgm_number(uint8_t number){ _buffer[1] = number; }
|
inline void set_pgm_number(uint8_t number){ _buffer[1] = number; }
|
||||||
inline uint8_t aftertouch() const { return (_buffer[1]); }
|
inline uint8_t aftertouch() const { return (_buffer[1]); }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue