void EngineMaster::processChannels(int iBufferSize) { m_activeBusChannels[EngineChannel::LEFT].clear(); m_activeBusChannels[EngineChannel::CENTER].clear(); m_activeBusChannels[EngineChannel::RIGHT].clear(); m_activeHeadphoneChannels.clear(); m_activeTalkoverChannels.clear(); m_activeChannels.clear(); ScopedTimer timer("EngineMaster::processChannels"); EngineChannel* pMasterChannel = m_pMasterSync->getMaster(); // Reserve the first place for the master channel which // should be processed first m_activeChannels.append(NULL); int activeChannelsStartIndex = 1; // Nothing at 0 yet for (int i = 0; i < m_channels.size(); ++i) { ChannelInfo* pChannelInfo = m_channels[i]; EngineChannel* pChannel = pChannelInfo->m_pChannel; // Skip inactive channels. if (!pChannel || !pChannel->isActive()) { continue; } if (pChannel->isTalkoverEnabled()) { // talkover is an exclusive channel // once talkover is enabled it is not used in // xFader-Mix m_activeTalkoverChannels.append(pChannelInfo); // Check if we need to fade out the master channel GainCache& gainCache = m_channelMasterGainCache[i]; if (gainCache.m_gain) { gainCache.m_fadeout = true; m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo); } } else { // Check if we need to fade out the channel GainCache& gainCache = m_channelTalkoverGainCache[i]; if (gainCache.m_gain) { gainCache.m_fadeout = true; m_activeTalkoverChannels.append(pChannelInfo); } if (pChannel->isMasterEnabled() && !pChannelInfo->m_pMuteControl->toBool()) { // the xFader-Mix m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo); } else { // Check if we need to fade out the channel GainCache& gainCache = m_channelMasterGainCache[i]; if (gainCache.m_gain) { gainCache.m_fadeout = true; m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo); } } } // If the channel is enabled for previewing in headphones, copy it // over to the headphone buffer if (pChannel->isPflEnabled()) { m_activeHeadphoneChannels.append(pChannelInfo); } else { // Check if we need to fade out the channel GainCache& gainCache = m_channelHeadphoneGainCache[i]; if (gainCache.m_gain) { m_channelHeadphoneGainCache[i].m_fadeout = true; m_activeHeadphoneChannels.append(pChannelInfo); } } // If necessary, add the channel to the list of buffers to process. if (pChannel == pMasterChannel) { // If this is the sync master, it should be processed first. m_activeChannels.replace(0, pChannelInfo); activeChannelsStartIndex = 0; } else { m_activeChannels.append(pChannelInfo); } } // Now that the list is built and ordered, do the processing. for (int i = activeChannelsStartIndex; i < m_activeChannels.size(); ++i) { ChannelInfo* pChannelInfo = m_activeChannels[i]; EngineChannel* pChannel = pChannelInfo->m_pChannel; pChannel->process(pChannelInfo->m_pBuffer, iBufferSize); // Collect metadata for effects if (m_pEngineEffectsManager) { GroupFeatureState features; pChannel->collectFeatures(&features); pChannelInfo->m_features = features; } } // After all the engines have been processed, trigger post-processing // which ensures that all channels are updating certain values at the // same point in time. This prevents sync from failing depending on // if the sync target was processed before or after the sync origin. for (int i = activeChannelsStartIndex; i < m_activeChannels.size(); ++i) { m_activeChannels[i]->m_pChannel->postProcess(iBufferSize); } }