Remove pointless Byte typedef that didn't really match any other typedef in ardour...
[ardour.git] / libs / ardour / ardour / midi_ring_buffer.h
index c6cde666a3eecf61d503a31c5a3eb3c5572f0c61..ff0be5c9978b5927168cdf9761a3628e3529f0a7 100644 (file)
@@ -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;
 }
 
@@ -139,13 +141,15 @@ template<typename T>
 bool
 MidiRingBufferBase<T>::full_peek(size_t size, T* dst)
 {
-       if (read_space() < size)
+       if (read_space() < size) {
                return false;
+       }
 
        const size_t read_size = peek(size, dst);
        
-       if (read_size < size)
+       if (read_size < size) {
                peek(size - read_size, dst + read_size);
+       }
 
        return true;
 }
@@ -179,13 +183,31 @@ template<typename T>
 bool
 MidiRingBufferBase<T>::full_read(size_t size, T* dst)
 {
-       if (read_space() < size)
+       if (read_space() < size) {
                return false;
+       }
 
        const size_t read_size = read(size, dst);
        
-       if (read_size < size)
+       if (read_size < size) {
                read(size - read_size, dst + read_size);
+       }
+
+       return true;
+}
+
+
+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;
 }
@@ -199,14 +221,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);
        }
 }
 
@@ -221,41 +243,43 @@ MidiRingBufferBase<T>::write(size_t size, const T* src)
  *
  * [timestamp][size][size bytes of raw MIDI][timestamp][size][etc..]
  */
-class MidiRingBuffer : public MidiRingBufferBase<Byte> {
+class MidiRingBuffer : public MidiRingBufferBase<uint8_t> {
 public:
-
        /** @param size Size in bytes.
         */
        MidiRingBuffer(size_t size)
-               : MidiRingBufferBase<Byte>(size), _channel_mask(0xFFFF), _force_channel(-1)
+               : MidiRingBufferBase<uint8_t>(size), _channel_mask(0x0000FFFF)
        {}
 
-       size_t write(double time, size_t size, const Byte* buf);
-       bool   read(double* time, size_t* size, Byte* buf);
+       size_t write(double time, size_t size, const uint8_t* buf);
+       bool   read(double* time, size_t* size, uint8_t* buf);
 
        bool   read_prefix(double* time, size_t* size);
-       bool   read_contents(size_t size, Byte* buf);
+       bool   read_contents(size_t size, uint8_t* buf);
 
        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) {
+       inline bool is_channel_event(uint8_t event_type_byte) {
                // mask out channel information
                event_type_byte &= 0xF0;
                // midi channel events range from 0x80 to 0xE0
@@ -263,20 +287,22 @@ protected:
        }
        
 private:
-       volatile uint16_t _channel_mask;
-       volatile int8_t   _force_channel;
+       volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
 };
 
 
 inline bool
-MidiRingBuffer::read(double* time, size_t* size, Byte* buf)
+MidiRingBuffer::read(double* time, size_t* size, uint8_t* buf)
 {
-       bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)time);
-       if (success)
-               success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)size);
-       if (success)
-               success = MidiRingBufferBase<Byte>::full_read(*size, buf);
-
+       bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)time);
+       
+       if (success) {
+               success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)size);
+       }
+       if (success) {
+               success = MidiRingBufferBase<uint8_t>::full_read(*size, buf);
+       }
+       
        return success;
 }
 
@@ -287,9 +313,10 @@ MidiRingBuffer::read(double* time, size_t* size, Byte* buf)
 inline bool
 MidiRingBuffer::read_prefix(double* time, size_t* size)
 {
-       bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)time);
-       if (success)
-               success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)size);
+       bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)time);
+       if (success) {
+               success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)size);
+       }
 
        return success;
 }
@@ -299,24 +326,26 @@ MidiRingBuffer::read_prefix(double* time, size_t* size)
  * by a call to read_prefix (or the returned even will be garabage).
  */
 inline bool
-MidiRingBuffer::read_contents(size_t size, Byte* buf)
+MidiRingBuffer::read_contents(size_t size, uint8_t* buf)
 {
-       return MidiRingBufferBase<Byte>::full_read(size, buf);
+       return MidiRingBufferBase<uint8_t>::full_read(size, buf);
 }
 
 
 inline size_t
-MidiRingBuffer::write(double time, size_t size, const Byte* buf)
+MidiRingBuffer::write(double time, size_t size, const uint8_t* 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) {
+               uint8_t channel = buf[0] & 0x0F;
+               if ( !(get_channel_mask() & (1L << channel)) ) {
                        return 0;
                }
        }
@@ -324,18 +353,20 @@ MidiRingBuffer::write(double time, size_t size, const Byte* buf)
        if (write_space() < (sizeof(double) + sizeof(size_t) + size)) {
                return 0;
        } 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)) {
-                       assert(size == 3);
-                       Byte tmp_buf[3];
-                       //force event into channel
-                       tmp_buf[0] = (buf[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F);
+               MidiRingBufferBase<uint8_t>::write(sizeof(double), (uint8_t*)&time);
+               MidiRingBufferBase<uint8_t>::write(sizeof(size_t), (uint8_t*)&size);
+               if (is_channel_event(buf[0]) && get_channel_mode() == ForceChannel) {
+                       assert(size == 2 || size == 3);
+                       uint8_t tmp_buf[3];
+                       // 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);
+                       if (size == 3) {
+                               tmp_buf[2] = buf[2];
+                       }
+                       MidiRingBufferBase<uint8_t>::write(size, tmp_buf);
                } else {
-                       MidiRingBufferBase<Byte>::write(size, buf);
+                       MidiRingBufferBase<uint8_t>::write(size, buf);
                }
                return size;
        }
@@ -354,64 +385,72 @@ 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), (uint8_t*)&ev_time);
        
-               if (ev.time() > end)
+               if (ev_time > end) {
                        break;
+               }
                
-               bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev.time());
-               if (success)
-                       success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev.size());
+               bool success = MidiRingBufferBase<uint8_t>::full_read(sizeof(double), (uint8_t*)&ev_time);
+               if (success) {
+                       success = MidiRingBufferBase<uint8_t>::full_read(sizeof(size_t), (uint8_t*)&ev_size);
+               }
 
                if (!success) {
                        std::cerr << "MRB: READ ERROR (time/size)" << std::endl;
                        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;
-               }
+               uint8_t status;
+               success = full_peek(sizeof(uint8_t), &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)) )  {
-                               return 0;
+               // 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)) ) {
+                               skip(ev_size); // Advance read pointer to next event
+                               continue;
                        }
                }
 
-               if (ev.time() >= start) {
-                       ev.time() -= start;
-                       Byte* write_loc = dst.reserve(ev.time(), ev.size());
-                       success = MidiRingBufferBase<Byte>::full_read(ev.size(), write_loc);
+               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 = MidiRingBufferBase<uint8_t>::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);
                }
        }