void EngineMaster::processChannels(unsigned int* busChannelConnectionFlags, unsigned int* headphoneOutput, int iBufferSize) { ScopedTimer timer("EngineMaster::processChannels"); QList<ChannelInfo*>::iterator it = m_channels.begin(); QList<ChannelInfo*>::iterator master_it = NULL; // Clear talkover compressor for the next round of gain calculation. m_pTalkoverDucking->clearKeys(); // Find the Sync Master and process it first then process all the slaves // (and skip the master). EngineChannel* pMasterChannel = m_pMasterSync->getMaster(); if (pMasterChannel != NULL) { for (unsigned int channel_number = 0; it != m_channels.end(); ++it, ++channel_number) { ChannelInfo* pChannelInfo = *it; EngineChannel* pChannel = pChannelInfo->m_pChannel; if (!pChannel || !pChannel->isActive()) { continue; } if (pMasterChannel == pChannel) { master_it = it; // Proceed with the processing as below. bool needsProcessing = false; if (pChannel->isMaster()) { busChannelConnectionFlags[pChannel->getOrientation()] |= (1 << channel_number); needsProcessing = true; } // If the channel is enabled for previewing in headphones, copy it // over to the headphone buffer if (pChannel->isPFL()) { *headphoneOutput |= (1 << channel_number); needsProcessing = true; } // Process the buffer if necessary, which it damn well better be if (needsProcessing) { pChannel->process(pChannelInfo->m_pBuffer, iBufferSize); if (m_pTalkoverDucking->getMode() != EngineTalkoverDucking::OFF && pChannel->isTalkover()) { m_pTalkoverDucking->processKey(pChannelInfo->m_pBuffer, iBufferSize); } } break; } } } it = m_channels.begin(); for (unsigned int channel_number = 0; it != m_channels.end(); ++it, ++channel_number) { ChannelInfo* pChannelInfo = *it; EngineChannel* pChannel = pChannelInfo->m_pChannel; // Skip the master since we already processed it. if (it == master_it) { continue; } // Skip inactive channels. if (!pChannel || !pChannel->isActive()) { continue; } bool needsProcessing = false; if (pChannel->isMaster()) { busChannelConnectionFlags[pChannel->getOrientation()] |= (1 << channel_number); needsProcessing = true; } // If the channel is enabled for previewing in headphones, copy it // over to the headphone buffer if (pChannel->isPFL()) { *headphoneOutput |= (1 << channel_number); needsProcessing = true; } // Process the buffer if necessary if (needsProcessing) { pChannel->process(pChannelInfo->m_pBuffer, iBufferSize); if (m_pTalkoverDucking->getMode() != EngineTalkoverDucking::OFF && pChannel->isTalkover()) { m_pTalkoverDucking->processKey(pChannelInfo->m_pBuffer, iBufferSize); } } } }
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); } // 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); } }