Clean up some MIDI code.
This commit is contained in:
parent
9d8bbf4b9a
commit
8f8a4878f3
@ -25,15 +25,20 @@
|
|||||||
|
|
||||||
#include "ardour/ardour.h"
|
#include "ardour/ardour.h"
|
||||||
#include "ardour/playlist.h"
|
#include "ardour/playlist.h"
|
||||||
#include "ardour/midi_state_tracker.h"
|
|
||||||
#include "evoral/Parameter.hpp"
|
#include "evoral/Parameter.hpp"
|
||||||
|
|
||||||
|
namespace Evoral {
|
||||||
|
template<typename Time> class EventSink;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ARDOUR
|
namespace ARDOUR
|
||||||
{
|
{
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
class MidiRegion;
|
class MidiRegion;
|
||||||
class Source;
|
class Source;
|
||||||
|
class MidiStateTracker;
|
||||||
|
|
||||||
template<typename T> class MidiRingBuffer;
|
template<typename T> class MidiRingBuffer;
|
||||||
|
|
||||||
class LIBARDOUR_API MidiPlaylist : public ARDOUR::Playlist
|
class LIBARDOUR_API MidiPlaylist : public ARDOUR::Playlist
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
#include "ardour/midi_buffer.h"
|
#include "ardour/midi_buffer.h"
|
||||||
#include "ardour/midi_state_tracker.h"
|
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
@ -53,32 +53,29 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
|
|||||||
* \param newsrc MidiSource to which data will be written. Should be a
|
* \param newsrc MidiSource to which data will be written. Should be a
|
||||||
* new, empty source. If it already has contents, the results are
|
* new, empty source. If it already has contents, the results are
|
||||||
* undefined. Source must be writable.
|
* undefined. Source must be writable.
|
||||||
*
|
|
||||||
* \param begin time of earliest event that can be written.
|
* \param begin time of earliest event that can be written.
|
||||||
* \param end time of latest event that can be written.
|
* \param end time of latest event that can be written.
|
||||||
*
|
* \return zero on success, non-zero if the write failed for any reason.
|
||||||
* Returns zero on success, non-zero if the write failed for any
|
|
||||||
* reason.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
int write_to (boost::shared_ptr<MidiSource> newsrc,
|
int write_to (boost::shared_ptr<MidiSource> newsrc,
|
||||||
Evoral::MusicalTime begin = Evoral::MinMusicalTime,
|
Evoral::MusicalTime begin = Evoral::MinMusicalTime,
|
||||||
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
|
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
|
||||||
|
|
||||||
/** Read the data in a given time range from the MIDI source.
|
/** Read the data in a given time range from the MIDI source.
|
||||||
* All time stamps in parameters are in audio frames (even if the source has tempo time).
|
* All time stamps in parameters are in audio frames (even if the source has tempo time).
|
||||||
* \param dst Ring buffer where read events are written
|
* \param dst Ring buffer where read events are written.
|
||||||
* \param source_start Start position of the SOURCE in this read context
|
* \param source_start Start position of the SOURCE in this read context.
|
||||||
* \param start Start of range to be read
|
* \param start Start of range to be read.
|
||||||
* \param cnt Length of range to be read (in audio frames)
|
* \param cnt Length of range to be read (in audio frames).
|
||||||
* \param tracker an optional pointer to MidiStateTracker object, for note on/off tracking
|
* \param tracker an optional pointer to MidiStateTracker object, for note on/off tracking.
|
||||||
|
* \param filtered Parameters whose MIDI messages will not be returned.
|
||||||
*/
|
*/
|
||||||
virtual framecnt_t midi_read (Evoral::EventSink<framepos_t>& dst,
|
virtual framecnt_t midi_read (Evoral::EventSink<framepos_t>& dst,
|
||||||
framepos_t source_start,
|
framepos_t source_start,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker,
|
MidiStateTracker* tracker,
|
||||||
std::set<Evoral::Parameter> const &) const;
|
const std::set<Evoral::Parameter>& filtered) const;
|
||||||
|
|
||||||
/** Write data from a MidiRingBuffer to this source.
|
/** Write data from a MidiRingBuffer to this source.
|
||||||
* @param source Source to read from.
|
* @param source Source to read from.
|
||||||
|
@ -52,9 +52,24 @@ public:
|
|||||||
return _active_notes[(channel*128)+note] > 0;
|
return _active_notes[(channel*128)+note] > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
template<typename Time>
|
||||||
void track_note_onoffs(const Evoral::MIDIEvent<MidiBuffer::TimeType>& event);
|
void track (const Evoral::Event<Time>& ev) {
|
||||||
|
const uint8_t type = ev.buffer()[0] & 0xF0;
|
||||||
|
const uint8_t chan = ev.buffer()[0] & 0x0F;
|
||||||
|
switch (type) {
|
||||||
|
case MIDI_CTL_ALL_NOTES_OFF:
|
||||||
|
reset();
|
||||||
|
break;
|
||||||
|
case MIDI_CMD_NOTE_ON:
|
||||||
|
add(ev.buffer()[1], chan);
|
||||||
|
break;
|
||||||
|
case MIDI_CMD_NOTE_OFF:
|
||||||
|
remove(ev.buffer()[1], chan);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
uint8_t _active_notes[128*16];
|
uint8_t _active_notes[128*16];
|
||||||
uint16_t _on;
|
uint16_t _on;
|
||||||
};
|
};
|
||||||
|
@ -74,7 +74,6 @@ MidiSource::MidiSource (Session& s, const XMLNode& node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MidiSource::~MidiSource ()
|
MidiSource::~MidiSource ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -107,7 +106,6 @@ int
|
|||||||
MidiSource::set_state (const XMLNode& node, int /*version*/)
|
MidiSource::set_state (const XMLNode& node, int /*version*/)
|
||||||
{
|
{
|
||||||
const XMLProperty* prop;
|
const XMLProperty* prop;
|
||||||
|
|
||||||
if ((prop = node.property ("captured-for")) != 0) {
|
if ((prop = node.property ("captured-for")) != 0) {
|
||||||
_captured_for = prop->value();
|
_captured_for = prop->value();
|
||||||
}
|
}
|
||||||
@ -115,39 +113,31 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
|
|||||||
XMLNodeList children = node.children ();
|
XMLNodeList children = node.children ();
|
||||||
for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) {
|
for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) {
|
||||||
if ((*i)->name() == X_("InterpolationStyle")) {
|
if ((*i)->name() == X_("InterpolationStyle")) {
|
||||||
XMLProperty* prop;
|
|
||||||
|
|
||||||
if ((prop = (*i)->property (X_("parameter"))) == 0) {
|
if ((prop = (*i)->property (X_("parameter"))) == 0) {
|
||||||
error << _("Missing parameter property on InterpolationStyle") << endmsg;
|
error << _("Missing parameter property on InterpolationStyle") << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
|
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
|
||||||
|
|
||||||
if ((prop = (*i)->property (X_("style"))) == 0) {
|
if ((prop = (*i)->property (X_("style"))) == 0) {
|
||||||
error << _("Missing style property on InterpolationStyle") << endmsg;
|
error << _("Missing style property on InterpolationStyle") << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Evoral::ControlList::InterpolationStyle s = static_cast<Evoral::ControlList::InterpolationStyle>(
|
||||||
Evoral::ControlList::InterpolationStyle s = static_cast<Evoral::ControlList::InterpolationStyle> (string_2_enum (prop->value(), s));
|
string_2_enum (prop->value(), s));
|
||||||
set_interpolation_of (p, s);
|
set_interpolation_of (p, s);
|
||||||
|
|
||||||
} else if ((*i)->name() == X_("AutomationState")) {
|
} else if ((*i)->name() == X_("AutomationState")) {
|
||||||
|
|
||||||
XMLProperty* prop;
|
|
||||||
|
|
||||||
if ((prop = (*i)->property (X_("parameter"))) == 0) {
|
if ((prop = (*i)->property (X_("parameter"))) == 0) {
|
||||||
error << _("Missing parameter property on AutomationState") << endmsg;
|
error << _("Missing parameter property on AutomationState") << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
|
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
|
||||||
|
|
||||||
if ((prop = (*i)->property (X_("state"))) == 0) {
|
if ((prop = (*i)->property (X_("state"))) == 0) {
|
||||||
error << _("Missing state property on AutomationState") << endmsg;
|
error << _("Missing state property on AutomationState") << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoState s = static_cast<AutoState> (string_2_enum (prop->value(), s));
|
AutoState s = static_cast<AutoState> (string_2_enum (prop->value(), s));
|
||||||
set_automation_state_of (p, s);
|
set_automation_state_of (p, s);
|
||||||
}
|
}
|
||||||
@ -179,19 +169,21 @@ MidiSource::update_length (framecnt_t)
|
|||||||
// You're not the boss of me!
|
// You're not the boss of me!
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param filtered A set of parameters whose MIDI messages will not be returned */
|
|
||||||
framecnt_t
|
framecnt_t
|
||||||
MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst, framepos_t source_start,
|
MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst,
|
||||||
framepos_t start, framecnt_t cnt,
|
framepos_t source_start,
|
||||||
MidiStateTracker* tracker,
|
framepos_t start,
|
||||||
std::set<Evoral::Parameter> const & filtered) const
|
framecnt_t cnt,
|
||||||
|
MidiStateTracker* tracker,
|
||||||
|
const std::set<Evoral::Parameter>& filtered) const
|
||||||
{
|
{
|
||||||
Glib::Threads::Mutex::Lock lm (_lock);
|
Glib::Threads::Mutex::Lock lm (_lock);
|
||||||
|
|
||||||
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("MidiSource::midi-read() %5 sstart %1 start %2 cnt %3 tracker %4\n",
|
DEBUG_TRACE (DEBUG::MidiSourceIO,
|
||||||
source_start, start, cnt, tracker, name()));
|
string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n",
|
||||||
|
source_start, start, cnt, tracker, name()));
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
// Read events up to end
|
// Read events up to end
|
||||||
@ -201,26 +193,20 @@ MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst, framepos_t source_sta
|
|||||||
++i) {
|
++i) {
|
||||||
const framecnt_t time_frames = converter.to(i->time());
|
const framecnt_t time_frames = converter.to(i->time());
|
||||||
if (time_frames < start + cnt) {
|
if (time_frames < start + cnt) {
|
||||||
/* convert event times to session frames by adding on the source start position in session frames */
|
// Offset by source start to convert event time to session time
|
||||||
dst.write (time_frames + source_start, i->event_type(), i->size(), i->buffer());
|
dst.write (time_frames + source_start, i->event_type(), i->size(), i->buffer());
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("%1: add event @ %2 type %3 size = %4\n",
|
DEBUG_TRACE (DEBUG::MidiSourceIO,
|
||||||
_name, time_frames + source_start, i->event_type(), i->size()));
|
string_compose ("%1: add event @ %2 type %3 size %4\n",
|
||||||
|
_name, time_frames + source_start, i->event_type(), i->size()));
|
||||||
|
|
||||||
if (tracker) {
|
if (tracker) {
|
||||||
Evoral::MIDIEvent<Evoral::MusicalTime>& ev (*(reinterpret_cast<Evoral::MIDIEvent<Evoral::MusicalTime>*>
|
tracker->track (*i);
|
||||||
(const_cast<Evoral::Event<Evoral::MusicalTime>*> (&(*i)))));
|
|
||||||
if (ev.is_note_on()) {
|
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("\t%1 track note on %2 @ %3 velocity %4\n", _name, (int) ev.note(), time_frames, (int) ev.velocity()));
|
|
||||||
tracker->add (ev.note(), ev.channel());
|
|
||||||
} else if (ev.is_note_off()) {
|
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("\t%1 track note off %2 @ %3\n", _name, (int) ev.note(), time_frames));
|
|
||||||
tracker->remove (ev.note(), ev.channel());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("%1: reached end with event @ %2 vs. %3\n",
|
DEBUG_TRACE (DEBUG::MidiSourceIO,
|
||||||
_name, time_frames, start+cnt));
|
string_compose ("%1: reached end with event @ %2 vs. %3\n",
|
||||||
|
_name, time_frames, start+cnt));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +275,8 @@ MidiSource::mark_streaming_write_started ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption option, Evoral::MusicalTime end)
|
MidiSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption option,
|
||||||
|
Evoral::MusicalTime end)
|
||||||
{
|
{
|
||||||
if (_model) {
|
if (_model) {
|
||||||
_model->end_write (option, end);
|
_model->end_write (option, end);
|
||||||
@ -307,7 +294,7 @@ MidiSource::mark_streaming_write_completed ()
|
|||||||
int
|
int
|
||||||
MidiSource::write_to (boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end)
|
MidiSource::write_to (boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end)
|
||||||
{
|
{
|
||||||
newsrc->set_timeline_position(_timeline_position);
|
newsrc->set_timeline_position (_timeline_position);
|
||||||
newsrc->copy_interpolation_from (this);
|
newsrc->copy_interpolation_from (this);
|
||||||
newsrc->copy_automation_state_from (this);
|
newsrc->copy_automation_state_from (this);
|
||||||
|
|
||||||
@ -331,7 +318,7 @@ MidiSource::write_to (boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime
|
|||||||
} else {
|
} else {
|
||||||
newsrc->set_model (_model);
|
newsrc->set_model (_model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this file is not removable (but since it is MIDI, it is mutable) */
|
/* this file is not removable (but since it is MIDI, it is mutable) */
|
||||||
|
|
||||||
boost::dynamic_pointer_cast<FileSource> (newsrc)->prevent_deletion ();
|
boost::dynamic_pointer_cast<FileSource> (newsrc)->prevent_deletion ();
|
||||||
@ -347,25 +334,18 @@ MidiSource::session_saved()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (_model && _model->edited()) {
|
if (_model && _model->edited()) {
|
||||||
|
/* The model is edited, write its contents into the current source
|
||||||
// if the model is edited, write its contents into
|
file (overwiting previous contents). */
|
||||||
// the current source file (overwiting previous contents.
|
|
||||||
|
|
||||||
/* temporarily drop our reference to the model so that
|
|
||||||
as the model pushes its current state to us, we don't
|
|
||||||
try to update it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* Temporarily drop our reference to the model so that as the model
|
||||||
|
pushes its current state to us, we don't try to update it. */
|
||||||
boost::shared_ptr<MidiModel> mm = _model;
|
boost::shared_ptr<MidiModel> mm = _model;
|
||||||
_model.reset ();
|
_model.reset ();
|
||||||
|
|
||||||
/* flush model contents to disk
|
/* Flush model contents to disk. */
|
||||||
*/
|
|
||||||
|
|
||||||
mm->sync_to_source ();
|
mm->sync_to_source ();
|
||||||
|
|
||||||
/* reacquire model */
|
/* Reacquire model. */
|
||||||
|
|
||||||
_model = mm;
|
_model = mm;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +375,6 @@ MidiSource::set_model (boost::shared_ptr<MidiModel> m)
|
|||||||
ModelChanged (); /* EMIT SIGNAL */
|
ModelChanged (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Interpolation style that should be used for control parameter \a p */
|
|
||||||
Evoral::ControlList::InterpolationStyle
|
Evoral::ControlList::InterpolationStyle
|
||||||
MidiSource::interpolation_of (Evoral::Parameter p) const
|
MidiSource::interpolation_of (Evoral::Parameter p) const
|
||||||
{
|
{
|
||||||
|
@ -46,16 +46,6 @@ MidiStateTracker::reset ()
|
|||||||
_on = 0;
|
_on = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent<MidiBuffer::TimeType>& event)
|
|
||||||
{
|
|
||||||
if (event.is_note_on()) {
|
|
||||||
add (event.note(), event.channel());
|
|
||||||
} else if (event.is_note_off()){
|
|
||||||
remove (event.note(), event.channel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStateTracker::add (uint8_t note, uint8_t chn)
|
MidiStateTracker::add (uint8_t note, uint8_t chn)
|
||||||
{
|
{
|
||||||
@ -96,21 +86,8 @@ MidiStateTracker::remove (uint8_t note, uint8_t chn)
|
|||||||
void
|
void
|
||||||
MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to)
|
MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to)
|
||||||
{
|
{
|
||||||
// DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 track notes\n", this));
|
|
||||||
|
|
||||||
for (MidiBuffer::iterator i = from; i != to; ++i) {
|
for (MidiBuffer::iterator i = from; i != to; ++i) {
|
||||||
const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
|
track(*i);
|
||||||
|
|
||||||
/* catch AllNotesOff message and turn off all notes
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (ev.type() == MIDI_CTL_ALL_NOTES_OFF) {
|
|
||||||
cerr << "State tracker sees ALL_NOTES_OFF, silenceing " << sizeof (_active_notes) << endl;
|
|
||||||
memset (_active_notes, 0, sizeof (_active_notes));
|
|
||||||
_on = 0;
|
|
||||||
} else {
|
|
||||||
track_note_onoffs (ev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user