X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Fmidi_ring_buffer.h;h=4b352b3c4dcf074d2271f090845f4529b600b479;hb=5558b3cf06b98060438d1e68c8d5d2f4a9c2f8f6;hp=ae82dc14ab5f0ed7f44f55f52fa764aa403ccd49;hpb=a2d2f738cb63dbf0fb89e0a00c424ce883fb7888;p=ardour.git diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index ae82dc14ab..4b352b3c4d 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2006 Paul Davis + Copyright (C) 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,13 +21,16 @@ #include #include -#include -#include -#include -#include + +#include "evoral/EventRingBuffer.hpp" + +#include "ardour/types.h" +#include "ardour/buffer.h" +#include "ardour/midi_state_tracker.h" namespace ARDOUR { +class MidiBuffer; /** A RingBuffer for (MIDI) events. * @@ -37,20 +40,22 @@ namespace ARDOUR { * * [timestamp][type][size][size bytes of raw MIDI][timestamp][type][size](etc...) */ -class MidiRingBuffer : public Evoral::EventRingBuffer { +template +class MidiRingBuffer : public Evoral::EventRingBuffer { public: /** @param size Size in bytes. */ MidiRingBuffer(size_t size) - : Evoral::EventRingBuffer(size) + : Evoral::EventRingBuffer(size) , _channel_mask(0x0000FFFF) {} - inline bool read_prefix(EventTime* time, EventType* type, uint32_t* size); + inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size); inline bool read_contents(uint32_t size, uint8_t* buf); - size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0); - + size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false); + void dump(std::ostream& dst); + /** Set the channel filtering mode. * @param mask If mode is FilterChannels, each bit represents a midi channel: * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only @@ -59,16 +64,18 @@ public: * be forced to while reading. */ void set_channel_mode(ChannelMode mode, uint16_t mask) { - g_atomic_int_set(&_channel_mask, ((uint16_t)mode << 16) | mask); + g_atomic_int_set(&_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask)); } ChannelMode get_channel_mode() const { return static_cast((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16); } - + uint16_t get_channel_mask() const { - return static_cast((g_atomic_int_get(&_channel_mask) & 0x0000FFFF)); + return g_atomic_int_get(&_channel_mask) & 0x0000FFFF; } + + void reset_tracker (); protected: inline bool is_channel_event(uint8_t event_type_byte) { @@ -77,122 +84,54 @@ protected: // midi channel events range from 0x80 to 0xE0 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; }; /** Read the time and size of an event. This call MUST be immediately proceeded - * by a call to read_contents (or the read pointer will be garabage). + * by a call to read_contents (or the read pointer will be garbage). */ +template inline bool -MidiRingBuffer::read_prefix(EventTime* time, EventType* type, uint32_t* size) +MidiRingBuffer::read_prefix(T* time, Evoral::EventType* type, uint32_t* size) { - bool success = Evoral::EventRingBuffer::full_read(sizeof(EventTime), (uint8_t*)time); - if (success) - success = Evoral::EventRingBuffer::full_read(sizeof(EventType), (uint8_t*)type); - if (success) - success = Evoral::EventRingBuffer::full_read(sizeof(uint32_t), (uint8_t*)size); + if (PBD::RingBufferNPT::read((uint8_t*)time, sizeof(T)) != sizeof (T)) { + return false; + } - return success; -} + if (PBD::RingBufferNPT::read((uint8_t*)type, sizeof(Evoral::EventType)) != sizeof (Evoral::EventType)) { + return false; + } + if (PBD::RingBufferNPT::read((uint8_t*)size, sizeof(uint32_t)) != sizeof (uint32_t)) { + return false; + } -/** Read the contenst of an event. This call MUST be immediately preceeded - * by a call to read_prefix (or the returned even will be garabage). - */ -inline bool -MidiRingBuffer::read_contents(uint32_t size, uint8_t* buf) -{ - return Evoral::EventRingBuffer::full_read(size, buf); + return true; } -/** Read a block of MIDI events from buffer. - * - * Timestamps of events returned are relative to start (ie event with stamp 0 - * occurred at start), with offset added. +/** Read the content of an event. This call MUST be immediately preceded + * by a call to read_prefix (or the returned even will be garbage). */ -inline size_t -MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset) +template +inline bool +MidiRingBuffer::read_contents(uint32_t size, uint8_t* buf) { - if (read_space() == 0) { - //std::cerr << "MRB: NO READ SPACE" << std::endl; - return 0; - } - - EventTime ev_time; - EventType ev_type; - uint32_t ev_size; - - size_t count = 0; - - //std::cerr << "MRB read " << start << " .. " << end << " + " << offset << std::endl; - - while (read_space() > sizeof(EventTime) + sizeof(EventType) + sizeof(uint32_t)) { - - full_peek(sizeof(EventTime), (uint8_t*)&ev_time); - - if (ev_time > end) { - //std::cerr << "MRB: PAST END (" << ev_time << " : " << end << ")" << std::endl; - break; - } - - bool success = read_prefix(&ev_time, &ev_type, &ev_size); - if (!success) { - //std::cerr << "MRB: READ ERROR (time/type/size)" << std::endl; - continue; - } - - uint8_t status; - success = full_peek(sizeof(uint8_t), &status); - assert(success); // If this failed, buffer is corrupt, all hope is lost - - // Ignore event if it doesn't match channel filter - if (is_channel_event(status) && get_channel_mode() == FilterChannels) { - const uint8_t channel = status & 0x0F; - if ( !(get_channel_mask() & (1L << channel)) ) { - //std::cerr << "MRB skipping event due to channel mask" << std::endl; - skip(ev_size); // Advance read pointer to next event - continue; - } - } - - if (ev_time >= start) { - - //std::cerr << "MRB " << this << " - Reading event, time = " - // << ev_time << " - " << start << " => " << ev_time - start - // << ", size = " << ev_size << std::endl; - - ev_time -= start; - - uint8_t* write_loc = dst.reserve(ev_time, ev_size); - if (write_loc == NULL) { - //std::cerr << "MRB: Unable to reserve space in buffer, event skipped"; - continue; - } - - success = Evoral::EventRingBuffer::full_read(ev_size, write_loc); - - if (success) { - if (is_channel_event(status) && get_channel_mode() == ForceChannel) { - write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F); - } - ++count; - //std::cerr << "MRB - read event at time " << ev_time << std::endl; - } else { - //std::cerr << "MRB: READ ERROR (data)" << std::endl; - } - - } else { - //std::cerr << "MRB (start " << start << ") - Skipping event at (too early) time " << ev_time << std::endl; - } - } - - //std::cerr << "MTB read space: " << read_space() << std::endl; - - return count; + return PBD::RingBufferNPT::read(buf, size) == size; }