return;
}
- if (_selection.erase (cne) > 0) {
- cerr << "Erased a CNE from selection\n";
- }
+ _selection.erase (cne);
}
void
#include <iostream>
#include <algorithm>
+
+#include "evoral/EventRingBuffer.hpp"
+
#include "ardour/types.h"
#include "ardour/buffer.h"
-#include "evoral/EventRingBuffer.hpp"
+#include "ardour/midi_state_tracker.h"
namespace ARDOUR {
return (0x80 <= event_type_byte) && (event_type_byte <= 0xE0);
}
+ inline bool is_note_on(uint8_t event_type_byte) {
+ // mask out channel information
+ return (event_type_byte & 0xF0) == MIDI_CMD_NOTE_ON;
+ }
+
+ inline bool is_note_off(uint8_t event_type_byte) {
+ // mask out channel information
+ return (event_type_byte & 0xF0) == MIDI_CMD_NOTE_OFF;
+ }
+
private:
volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
+ MidiStateTracker _tracker;
};
CONFIG_VARIABLE (bool, show_group_tabs, "show-group-tabs", true)
CONFIG_VARIABLE (bool, external_sync, "external-sync", false)
CONFIG_VARIABLE (SyncSource, sync_source, "sync-source", JACK)
-CONFIG_VARIABLE (InsertMergePolicy, insert_merge_policy, "insert-merge-policy", InsertMergeReject)
+CONFIG_VARIABLE (InsertMergePolicy, insert_merge_policy, "insert-merge-policy", InsertMergeRelax)
CONFIG_VARIABLE (framecnt_t, timecode_offset, "timecode-offset", 0)
CONFIG_VARIABLE (bool, timecode_offset_negative, "timecode-offset-negative", true)
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
- "%1 MDS pre-read read from %2 write to %3\n", _name,
- _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr()));
+ "%1 MDS pre-read read %4..%5 from %2 write to %3\n", _name,
+ _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), start, end));
// cerr << "================\n";
// _playback_buf->dump (cerr);
// cerr << "----------------\n";
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
}
- /* lets see if we are going to be able to write this event into dst.
- */
-
assert(ev_time >= start);
ev_time -= start;
ev_time += offset;
- // write the timestamp to address (write_loc - 1)
- uint8_t* write_loc = dst.reserve(ev_time, ev_size);
- if (write_loc == NULL) {
+ // This event marks a loop end (i.e. the next event's timestamp
+ // will be non-monotonic). Don't write it into the buffer - the
+ // significance of this event ends here.
+
+ if (ev_type == LoopEventType) {
+ assert (ev_size == sizeof (framepos_t));
+ framepos_t loop_start;
+ read_contents (ev_size, (uint8_t *) &loop_start);
+ loop_offset = ev_time - loop_start;
+ _tracker.resolve_notes (dst, ev_time);
+ continue;
+ }
+
+ /* lets see if we are going to be able to write this event into dst.
+ */
+ uint8_t* write_loc = dst.reserve (ev_time, ev_size);
+ if (write_loc == 0) {
if (stop_on_overflow_in_dst) {
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events\n", count));
break;
/* we're good to go ahead and read the data now but since we
* have the prefix data already, just skip over that
*/
-
this->increment_read_ptr (prefix_size);
-
- // This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
- if (ev_type == LoopEventType) {
- assert (ev_size == sizeof (framepos_t));
- framepos_t loop_start;
- read_contents (ev_size, (uint8_t *) &loop_start);
-
- loop_offset = ev_time - loop_start;
- continue;
- }
-
ev_time += loop_offset;
uint8_t status;
#endif
if (success) {
+
+ if (is_note_on(write_loc[0]) ) {
+ _tracker.add (write_loc[1], write_loc[0] & 0xf);
+ } else if (is_note_off(write_loc[0])) {
+ _tracker.remove (write_loc[1], write_loc[0] & 0xf);
+ }
+
if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
}
inline PatchChanges& patch_changes () { return _patch_changes; }
inline const PatchChanges& patch_changes () const { return _patch_changes; }
+ void dump (std::ostream&) const;
+
private:
typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
public:
} // namespace Evoral
+// template<typename Time> std::ostream& operator<<(std::ostream& o, const Evoral::Sequence<Time>& s) { s.dump (o); return o; }
+
#endif // EVORAL_SEQUENCE_HPP
#ifndef EVORAL_MIDI_UTIL_H
#define EVORAL_MIDI_UTIL_H
+#include <iostream>
+
#include <stdint.h>
#include <stdbool.h>
#include <string>
return 1;
case MIDI_CMD_COMMON_SYSEX:
+ std::cerr << "event size called for sysex\n";
return -1;
}
+ std::cerr << "event size called for unknown status byte " << std::hex << (int) status << "\n";
return -1;
}
_edited = true;
- return true;
+ return true;
}
template<typename Time>
}
if (!erased) {
- cerr << "Unable to find note to erase" << endl;
+ cerr << "Unable to find note to erase matching " << *note.get() << endl;
}
}
template class Sequence<Evoral::MusicalTime>;
+template<typename Time>
+void
+Sequence<Time>::dump (ostream& str) const
+{
+ Sequence<Time>::const_iterator i;
+ str << "+++ dump\n";
+ for (i = begin(); i != end(); ++i) {
+ str << *i << endl;
+ }
+ str << "--- dump\n";
+}
+
} // namespace Evoral