diff options
Diffstat (limited to 'libs/ardour/ardour/midi_ring_buffer.h')
-rw-r--r-- | libs/ardour/ardour/midi_ring_buffer.h | 156 |
1 files changed, 87 insertions, 69 deletions
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index 680e2a7b61..ea0013fe46 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -75,7 +75,7 @@ public: if (w > r) { return ((r - w + _size) % _size) - 1; - } else if(w < r) { + } else if (w < r) { return (r - w) - 1; } else { return _size - 1; @@ -101,15 +101,17 @@ public: size_t read(size_t size, T* dst); bool full_read(size_t size, T* dst); + + bool skip(size_t size); void write(size_t size, const T* src); protected: - mutable gint _write_ptr; - mutable gint _read_ptr; + mutable int _write_ptr; + mutable int _read_ptr; size_t _size; ///< Size (capacity) in bytes - T* _buf; ///< size, event, size, event... + T* _buf; ///< size, event, size, event... }; @@ -130,7 +132,7 @@ MidiRingBufferBase<T>::peek(size_t size, T* dst) : _size - priv_read_ptr; memcpy(dst, &_buf[priv_read_ptr], read_size); - + return read_size; } @@ -168,7 +170,7 @@ MidiRingBufferBase<T>::read(size_t size, T* dst) : _size - priv_read_ptr; memcpy(dst, &_buf[priv_read_ptr], read_size); - + g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size); return read_size; @@ -192,6 +194,23 @@ MidiRingBufferBase<T>::full_read(size_t size, T* dst) template<typename T> +bool +MidiRingBufferBase<T>::skip(size_t size) +{ + if (read_space() < size) { + std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl; + return false; + } + + const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr); + g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size); + + return true; +} + + + +template<typename T> inline void MidiRingBufferBase<T>::write(size_t size, const T* src) { @@ -199,14 +218,14 @@ MidiRingBufferBase<T>::write(size_t size, const T* src) if (priv_write_ptr + size <= _size) { memcpy(&_buf[priv_write_ptr], src, size); - g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size); + g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size); } else { const size_t this_size = _size - priv_write_ptr; assert(this_size < size); assert(priv_write_ptr + this_size <= _size); memcpy(&_buf[priv_write_ptr], src, this_size); memcpy(&_buf[0], src+this_size, size - this_size); - g_atomic_int_set(&_write_ptr, size - this_size); + g_atomic_int_set(&_write_ptr, size - this_size); } } @@ -223,11 +242,10 @@ MidiRingBufferBase<T>::write(size_t size, const T* src) */ class MidiRingBuffer : public MidiRingBufferBase<Byte> { public: - /** @param size Size in bytes. */ MidiRingBuffer(size_t size) - : MidiRingBufferBase<Byte>(size), _channel_mask(0xFFFF), _force_channel(-1) + : MidiRingBufferBase<Byte>(size), _channel_mask(0x0000FFFF) {} size_t write(double time, size_t size, const Byte* buf); @@ -238,21 +256,24 @@ public: size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0); - /** - * @param channel_mask each bit in channel_mask represents a midi channel: bit 0 = channel 0, - * bit 1 = channel 1 etc. the read and write methods will only allow - * events to pass, whose channel bit is 1. + /** 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 + * process events whose channel bit is 1. + * If mode is ForceChannel, mask is simply a channel number which all events will + * be forced to while reading. */ - void set_channel_mask(uint16_t channel_mask) { g_atomic_int_set(&_channel_mask, channel_mask); } - uint16_t get_channel_mask() { return g_atomic_int_get(&_channel_mask); } + void set_channel_mode(ChannelMode mode, uint16_t mask) { + g_atomic_int_set(&_channel_mask, ((uint16_t)mode << 16) | mask); + } + + ChannelMode get_channel_mode() const { + return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16); + } - /** - * @param channel if negative, forcing channels is deactivated and filtering channels - * is activated, if positive, the LSB of channel is the channel number - * of the channel all events are forced into and filtering is deactivated - */ - void set_force_channel(int8_t channel) { g_atomic_int_set(&_force_channel, channel); } - int8_t get_force_channel() { return g_atomic_int_get(&_force_channel); } + uint16_t get_channel_mask() const { + return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0x0000FFFF)); + } protected: inline bool is_channel_event(Byte event_type_byte) { @@ -263,8 +284,7 @@ protected: } private: - volatile uint16_t _channel_mask; - volatile int8_t _force_channel; + volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask }; @@ -308,17 +328,18 @@ MidiRingBuffer::read_contents(size_t size, Byte* buf) inline size_t MidiRingBuffer::write(double time, size_t size, const Byte* buf) { - //printf("MRB - write %#X %d %d with time %lf\n", - // buf[0], buf[1], buf[2], time); + /*fprintf(stderr, "MRB %p write (t = %f) ", this, time); + for (size_t i = 0; i < size; ++i) + fprintf(stderr, "%X", (char)buf[i]); + fprintf(stderr, "\n");*/ assert(size > 0); - if(is_channel_event(buf[0]) && (g_atomic_int_get(&_force_channel) < 0)) { - // filter events for channels - Byte channel_nr = buf[0] & 0x0F; - if( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) { + // Don't write event if it doesn't match channel filter + if (is_channel_event(buf[0]) && get_channel_mode() == FilterChannels) { + Byte channel = buf[0] & 0x0F; + if ( !(get_channel_mask() & (1L << channel)) ) return 0; - } } if (write_space() < (sizeof(double) + sizeof(size_t) + size)) { @@ -326,11 +347,11 @@ MidiRingBuffer::write(double time, size_t size, const Byte* buf) } else { MidiRingBufferBase<Byte>::write(sizeof(double), (Byte*)&time); MidiRingBufferBase<Byte>::write(sizeof(size_t), (Byte*)&size); - if(is_channel_event(buf[0]) && (g_atomic_int_get(&_force_channel) >= 0)) { + if (is_channel_event(buf[0]) && get_channel_mode() == ForceChannel) { assert(size == 3); Byte tmp_buf[3]; - //force event into channel - tmp_buf[0] = (buf[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F); + // Force event to channel + tmp_buf[0] = (buf[0] & 0xF0) | (get_channel_mask() & 0x0F); tmp_buf[1] = buf[1]; tmp_buf[2] = buf[2]; MidiRingBufferBase<Byte>::write(size, tmp_buf); @@ -354,22 +375,23 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t if (read_space() == 0) return 0; - MIDI::Event ev; + double ev_time; + uint32_t ev_size; size_t count = 0; - //printf("MRB - read %u .. %u + %u\n", start, end, offset); + //printf("---- MRB read %u .. %u + %u\n", start, end, offset); while (read_space() > sizeof(double) + sizeof(size_t)) { - full_peek(sizeof(double), (Byte*)&ev.time()); + full_peek(sizeof(double), (Byte*)&ev_time); - if (ev.time() > end) + if (ev_time > end) break; - bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev.time()); + bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev_time); if (success) { - success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev.size()); + success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev_size); } if (!success) { @@ -377,51 +399,47 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t continue; } - Byte first_event_byte; - if(success) { - success = full_peek(sizeof(Byte), &first_event_byte); - } - - // could this ever happen??? - if (!success) { - std::cerr << "MRB: PEEK ERROR (first event byte)" << std::endl; - continue; - } + Byte status; + success = full_peek(sizeof(Byte), &status); + assert(success); // If this failed, buffer is corrupt, all hope is lost - // filter events for channels - // filtering is only active, if forcing channels is not active - if(is_channel_event(first_event_byte) && (g_atomic_int_get(&_force_channel) < 0)) { - Byte channel_nr = first_event_byte & 0x0F; - if( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) { + // Ignore event if it doesn't match channel filter + if (is_channel_event(status) && get_channel_mode() == FilterChannels) { + const Byte channel = status & 0x0F; + if ( !(get_channel_mask() & (1L << channel)) ) { + skip(ev_size); // Advance read pointer to next event continue; } } - if (ev.time() >= start) { - ev.time() -= start; - // TODO: Right now there come MIDI Events with empty buffer - if(!ev.buffer()) { - std::cerr << "MidiRingBuffer::read WARNING: Skipping MIDI Event with NULL buffer pointer " - << " and length " << int(ev.size()) << std::endl; + 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; + + Byte* write_loc = dst.reserve(ev_time, ev_size); + if (write_loc == NULL) { + std::cerr << "MRB: Unable to reserve space in buffer, event skipped"; continue; } - Byte* write_loc = dst.reserve(ev.time(), ev.size()); - - success = MidiRingBufferBase<Byte>::full_read(ev.size(), write_loc); + success = MidiRingBufferBase<Byte>::full_read(ev_size, write_loc); if (success) { - if(is_channel_event(first_event_byte) && (g_atomic_int_get(&_force_channel) >= 0)) { - write_loc[0] = (write_loc[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F); + if (is_channel_event(status) && get_channel_mode() == ForceChannel) { + write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F); } ++count; - //printf("MRB - read event at time %lf\n", ev.time()); + //printf("MRB - read event at time %lf\n", ev_time); } else { std::cerr << "MRB: READ ERROR (data)" << std::endl; } } else { - printf("MRB - SKIPPING EVENT AT TIME %f\n", ev.time()); + printf("MRB (start %u) - Skipping event at (too early) time %f\n", start, ev_time); } } |