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-07 15:51:50 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, "T must be trivially copyable");
      18              : 
      19              :    public:
      20        50130 :     SPSCQueue() : head_(0), tail_(0) {}
      21              : 
      22              :     // Called from the producer (GUI) thread.
      23              :     // Returns false if the queue is full (message dropped by caller).
      24          666 :     bool try_push(const T& item) {
      25          666 :         const size_t h = head_.load(std::memory_order_relaxed);
      26          666 :         const size_t next = (h + 1) & kMask;
      27          888 :         if (next == tail_.load(std::memory_order_acquire)) {
      28            2 :             return false;  // full
      29              :         }
      30          663 :         buf_[h] = item;
      31          663 :         head_.store(next, std::memory_order_release);
      32          663 :         return true;
      33          222 :     }
      34              : 
      35              :     // Called from the consumer (audio) thread.
      36              :     // Returns false if the queue is empty.
      37         4828 :     bool try_pop(T& item) {
      38         4828 :         const size_t t = tail_.load(std::memory_order_relaxed);
      39         6045 :         if (t == head_.load(std::memory_order_acquire)) {
      40         3513 :             return false;  // empty
      41              :         }
      42          147 :         item = buf_[t];
      43          147 :         tail_.store((t + 1) & kMask, std::memory_order_release);
      44          147 :         return true;
      45         2394 :     }
      46              : 
      47              :     // Inspect the front item without consuming it (consumer thread only).
      48              :     // Returns false if the queue is empty.
      49         4682 :     bool try_peek(T& item) const {
      50         4682 :         const size_t t = tail_.load(std::memory_order_relaxed);
      51         5848 :         if (t == head_.load(std::memory_order_acquire)) {
      52         3474 :             return false;  // empty
      53              :         }
      54           63 :         item = buf_[t];
      55           63 :         return true;
      56         2350 :     }
      57              : 
      58            6 :     size_t try_pop_all(std::vector<T>& out_vec) {
      59            6 :         size_t count = 0;
      60              :         T item;
      61           15 :         while (try_pop(item)) {
      62            9 :             out_vec.push_back(item);
      63            9 :             ++count;
      64              :         }
      65            6 :         return count;
      66              :     }
      67              : 
      68           12 :     size_t size() const {
      69           16 :         return (head_.load(std::memory_order_acquire) - tail_.load(std::memory_order_acquire)) &
      70            8 :                kMask;
      71              :     }
      72              : 
      73            2 :     size_t capacity() const { return Capacity - 1; }
      74              : 
      75              :    private:
      76              :     static constexpr size_t kMask = Capacity - 1;
      77              : 
      78              :     // Pad to avoid false sharing between producer and consumer cache lines
      79              :     alignas(64) std::atomic<size_t> head_;
      80              :     alignas(64) std::atomic<size_t> tail_;
      81              :     T buf_[Capacity];
      82              : };
      83              : 
      84              : // A command that the GUI thread sends to the audio thread.
      85              : struct AudioCommand {
      86              :     enum Type : uint8_t {
      87              :         SetEffectParam,    // Change an effect parameter value
      88              :         SetEffectEnabled,  // Enable/disable an effect
      89              :         SetEffectMix,      // Change effect wet/dry mix
      90              :         SetMixerGain,      // Change mixer input gain dynamically
      91              :         SetInputGain,      // Change master input gain
      92              :         SetOutputGain,     // Change master output gain
      93              :         AddEffect,         // Signal that effect list changed (swap pointer)
      94              :         RemoveEffect,      // Signal that effect list changed
      95              :         MoveEffect,        // Signal that effect list changed
      96              :     };
      97              : 
      98              :     Type type;
      99              :     int effect_index;  // Which effect in the chain
     100              :     int param_index;   // Which parameter within the effect
     101              :     float value;       // The new value
     102              : };
     103              : 
     104              : }  // namespace Amplitron
        

Generated by: LCOV version 2.0-1