LCOV - code coverage report
Current view: top level - src/audio/utils - spsc_queue.h (source / functions) Coverage Total Hit
Test: merged.info Lines: 100.0 % 35 35
Test Date: 2026-06-01 11:15:25 Functions: 100.0 % 27 27

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include <atomic>
       4              : #include <cstddef>
       5              : #include <type_traits>
       6              : #include <vector>
       7              : 
       8              : namespace Amplitron {
       9              : 
      10              : // Lock-free Single-Producer Single-Consumer ring buffer.
      11              : // Producer: GUI thread pushes parameter changes.
      12              : // Consumer: Audio thread drains at the start of each callback.
      13              : template <typename T, size_t Capacity>
      14              : class SPSCQueue {
      15              :     static_assert(Capacity > 0 && (Capacity & (Capacity - 1)) == 0,
      16              :                   "Capacity must be a power of two");
      17              :     static_assert(std::is_trivially_copyable<T>::value,
      18              :                   "T must be trivially copyable");
      19              : 
      20              : public:
      21        49086 :     SPSCQueue() : head_(0), tail_(0) {}
      22              : 
      23              :     // Called from the producer (GUI) thread.
      24              :     // Returns false if the queue is full (message dropped by caller).
      25          666 :     bool try_push(const T& item) {
      26          666 :         const size_t h = head_.load(std::memory_order_relaxed);
      27          666 :         const size_t next = (h + 1) & kMask;
      28          888 :         if (next == tail_.load(std::memory_order_acquire)) {
      29            2 :             return false;  // full
      30              :         }
      31          663 :         buf_[h] = item;
      32          663 :         head_.store(next, std::memory_order_release);
      33          663 :         return true;
      34          222 :     }
      35              : 
      36              :     // Called from the consumer (audio) thread.
      37              :     // Returns false if the queue is empty.
      38         4973 :     bool try_pop(T& item) {
      39         4973 :         const size_t t = tail_.load(std::memory_order_relaxed);
      40         6190 :         if (t == head_.load(std::memory_order_acquire)) {
      41         3658 :             return false;  // empty
      42              :         }
      43          147 :         item = buf_[t];
      44          147 :         tail_.store((t + 1) & kMask, std::memory_order_release);
      45          147 :         return true;
      46         2539 :     }
      47              : 
      48              :     // Inspect the front item without consuming it (consumer thread only).
      49              :     // Returns false if the queue is empty.
      50         4820 :     bool try_peek(T& item) const {
      51         4820 :         const size_t t = tail_.load(std::memory_order_relaxed);
      52         5986 :         if (t == head_.load(std::memory_order_acquire)) {
      53         3612 :             return false;  // empty
      54              :         }
      55           63 :         item = buf_[t];
      56           63 :         return true;
      57         2488 :     }
      58              : 
      59            6 :     size_t try_pop_all(std::vector<T>& out_vec) {
      60            6 :         size_t count = 0;
      61              :         T item;
      62           15 :         while (try_pop(item)) {
      63            9 :             out_vec.push_back(item);
      64            9 :             ++count;
      65              :         }
      66            6 :         return count;
      67              :     }
      68              : 
      69           12 :     size_t size() const {
      70           20 :         return (head_.load(std::memory_order_acquire) - tail_.load(std::memory_order_acquire)) & kMask;
      71              :     }
      72              : 
      73            2 :     size_t capacity() const {
      74            2 :         return Capacity - 1;
      75              :     }
      76              : 
      77              : private:
      78              :     static constexpr size_t kMask = Capacity - 1;
      79              : 
      80              :     // Pad to avoid false sharing between producer and consumer cache lines
      81              :     alignas(64) std::atomic<size_t> head_;
      82              :     alignas(64) std::atomic<size_t> tail_;
      83              :     T buf_[Capacity];
      84              : };
      85              : 
      86              : // A command that the GUI thread sends to the audio thread.
      87              : struct AudioCommand {
      88              :     enum Type : uint8_t {
      89              :         SetEffectParam,      // Change an effect parameter value
      90              :         SetEffectEnabled,    // Enable/disable an effect
      91              :         SetEffectMix,        // Change effect wet/dry mix
      92              :         SetMixerGain,        // Change mixer input gain dynamically
      93              :         SetInputGain,        // Change master input gain
      94              :         SetOutputGain,       // Change master output gain
      95              :         AddEffect,           // Signal that effect list changed (swap pointer)
      96              :         RemoveEffect,        // Signal that effect list changed
      97              :         MoveEffect,          // Signal that effect list changed
      98              :     };
      99              : 
     100              :     Type type;
     101              :     int effect_index;     // Which effect in the chain
     102              :     int param_index;      // Which parameter within the effect
     103              :     float value;          // The new value
     104              : };
     105              : 
     106              : } // namespace Amplitron
        

Generated by: LCOV version 2.0-1