diff --git a/src/MixerApi.cpp b/src/MixerApi.cpp index fc292b4..23b2c74 100644 --- a/src/MixerApi.cpp +++ b/src/MixerApi.cpp @@ -285,6 +285,10 @@ std::string MixerApi::getStateJson() const writer.write_member("label", cs.label); writer.write_member("hpEnabled", cs.hpEnabled); writer.write_member("hpFrequency", (double)cs.hpFrequency); + writer.write_member("vuLeft", (double)cs.vuLeft); + writer.write_member("vuRight", (double)cs.vuRight); + writer.write_member("gateOpen", cs.gateOpen); + writer.write_member("compressorReduction", (double)cs.compressorReduction); writer.end_object(); } writer.write_raw("]"); @@ -309,6 +313,8 @@ std::string MixerApi::getStateJson() const writer.write_member("type", typeStr); writer.write_member("volume", (double)bs.volume); writer.write_member("mute", bs.mute); + writer.write_member("vuLeft", (double)bs.vuLeft); + writer.write_member("vuRight", (double)bs.vuRight); writer.end_object(); } writer.write_raw("]"); @@ -346,6 +352,10 @@ std::string MixerApi::getStateJson() const } writer.write_raw("]"); + // Physical I/O info + writer.write_member("physicalInputCount", (int64_t)mixerEngine_->physicalInputCount()); + writer.write_member("physicalOutputCount", (int64_t)mixerEngine_->physicalOutputCount()); + writer.end_object(); return ss.str(); } diff --git a/src/MixerEngine.cpp b/src/MixerEngine.cpp index 682143c..6ee858e 100644 --- a/src/MixerEngine.cpp +++ b/src/MixerEngine.cpp @@ -499,6 +499,15 @@ MixerEngine::MixerSnapshot MixerEngine::captureSnapshot() const cs.label = channel->label(); cs.hpEnabled = channel->hpEnabled(); cs.hpFrequency = channel->hpFrequency(); + cs.vuLeft = channel->vuLeft(); + cs.vuRight = channel->vuRight(); + + // Gate detection: gate is "open" when signal exceeds approx -50dB threshold + // (mapped from actual gate state once a gate module is implemented) + cs.gateOpen = (cs.vuLeft > -50.0f || cs.vuRight > -50.0f); + + // Compressor gain reduction (placeholder — 0 dB when no compressor active) + cs.compressorReduction = 0.0f; for (size_t i = 0; i < channel->auxSendCount(); ++i) { cs.auxSendLevels.push_back(channel->auxSend(i).level); @@ -514,6 +523,8 @@ MixerEngine::MixerSnapshot MixerEngine::captureSnapshot() const bs.type = bus->type(); bs.volume = bus->volume(); bs.mute = bus->mute(); + bs.vuLeft = bus->vuLeft(); + bs.vuRight = bus->vuRight(); snap.buses.push_back(bs); } @@ -570,8 +581,12 @@ std::vector MixerEngine::findOutputRoutesForBus(i // --- Auto channel creation --- -void MixerEngine::autoCreateChannels(uint32_t inputChannelCount) +void MixerEngine::autoCreateChannels(uint32_t inputChannelCount, uint32_t outputChannelCount) { + // Store the physical I/O channel counts for later queries + physicalInputCount_ = inputChannelCount; + physicalOutputCount_ = outputChannelCount; + // Remove existing channels if any for (int i = (int)channels_.size() - 1; i >= 0; --i) { removeChannel(i); @@ -589,24 +604,18 @@ void MixerEngine::autoCreateChannels(uint32_t inputChannelCount) } // Set default output routes: - // For 1-2 channels: master bus → physical 1-2 (backward compatible) - // For 3+ channels: master bus → physical 1-2, then pair remaining channels - // in groups of 2 to physical 3-4, 5-6, etc. + // Always route master bus to physical 1-2 (the main monitor output) + // For multi-channel setups, individual channel routing is configured via the output routing UI. outputRoutes_.clear(); if (!masterBus_) return; - // Always route master bus to physical 1-2 MixerOutputRoute masterRoute; masterRoute.sourceBusId = masterBus_->id(); masterRoute.sourceStartChannel = 0; masterRoute.targetStartChannel = 0; masterRoute.channels = 2; outputRoutes_.push_back(masterRoute); - - // If more than 2 channels, don't auto-create additional output routes. - // The user should configure them via the output routing UI. - // (Aux buses, subgroups, etc. are not auto-routed) } void MixerEngine::applySnapshot(const MixerSnapshot& snapshot) diff --git a/src/MixerEngine.hpp b/src/MixerEngine.hpp index 9adb23c..2bc5fe3 100644 --- a/src/MixerEngine.hpp +++ b/src/MixerEngine.hpp @@ -74,7 +74,9 @@ public: /// Auto-create channels based on the number of detected input channels. /// Removes existing channels and creates one strip per input. /// Also sets up default output routes. - void autoCreateChannels(uint32_t inputChannelCount); + /// @param inputChannelCount Number of physical input channels detected + /// @param outputChannelCount Number of physical output channels detected + void autoCreateChannels(uint32_t inputChannelCount, uint32_t outputChannelCount = 2); /// Remove a channel by its channel index. void removeChannel(int channelIndex); @@ -148,6 +150,19 @@ public: /// Get all current routes. const std::vector& routes() const { return routes_; } + /// --- Physical I/O Info --- + + /// Number of physical input channels detected on the audio device. + uint32_t physicalInputCount() const { return physicalInputCount_; } + /// Number of physical output channels detected on the audio device. + uint32_t physicalOutputCount() const { return physicalOutputCount_; } + + /// Set the physical I/O channel counts (called by autoCreateChannels or externally). + void setPhysicalChannelCounts(uint32_t inputs, uint32_t outputs) { + physicalInputCount_ = inputs; + physicalOutputCount_ = outputs; + } + /// --- Audio Processing (real-time thread) --- /// Prepare all channels and allocate buffers. @@ -199,6 +214,10 @@ public: bool hpEnabled; float hpFrequency; std::vector auxSendLevels; // indexed by aux bus index + float vuLeft = -96.0f; // dB — peak VU level + float vuRight = -96.0f; // dB — peak VU level + bool gateOpen = true; // gate state (true = signal passing) + float compressorReduction = 0.0f; // dB of gain reduction (0 = no reduction) }; struct BusState { int64_t id; @@ -206,6 +225,8 @@ public: MixerBusType type; float volume; bool mute; + float vuLeft = -96.0f; // dB — peak VU level + float vuRight = -96.0f; // dB — peak VU level }; std::vector channels; std::vector buses; @@ -243,6 +264,10 @@ private: // Allocated once at prepare time std::vector> channelOutputBuffers_; + // Physical I/O channel counts (from audio device auto-detection) + uint32_t physicalInputCount_ = 0; + uint32_t physicalOutputCount_ = 0; + // Internal helper: accumulate a channel's output to all its routed buses void routeChannelOutput( MixerChannelStrip* channel,