Example #1
0
UtlBoolean MpBridgeAlgLinear::doMix(MpBufPtr inBufs[], int inBufsSize,
                                    MpBufPtr outBufs[], int outBufsSize,
                                    int samplesPerFrame)
{
   int numActiveInputs = 0;
   const int numExtendedInputs = mExtendedInputs.getExtendedInputsNum();

   assert(inBufsSize == maxInputs());
   assert(outBufsSize == maxOutputs());

   //
   //  Build list of active inputs (stored in mpActiveInputsList).
   //
#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
   UtlString contributorDumpString("Contributors (inversed order): ");
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

   int extInput;
   for ( extInput=numExtendedInputs-1; extInput>=0; extInput-- )
   {
      if (mExtendedInputs.isNotMuted(extInput))
      {
         int origInput = mExtendedInputs.getOrigin(extInput);

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
         contributorDumpString.appendFormat("(%d)i:%dNM",extInput, origInput);
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

         if (inBufs[origInput].isValid())
         {

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
            contributorDumpString.append("V");
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

            MpAudioBufPtr pAudio = inBufs[origInput];
            if ((mMixSilence || isActiveAudio(pAudio->getSpeechType())) &&
                pAudio->getSpeechType() != MP_SPEECH_MUTED)
            {

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
               contributorDumpString.append("A");
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

               mpActiveInputsList[numActiveInputs] = extInput;
               numActiveInputs++;

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
               contributorDumpString.append("+");
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

            }
         }

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
         contributorDumpString.append(" ");
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

      }
   }

#ifdef TEST_PRINT_MIXING_CONTRIBUTORS // [
   contributorDumpString.append("\n");
   //printf(contributorDumpString.data());
   OsSysLog::add(FAC_MP, PRI_DEBUG, "%s", contributorDumpString.data());
   //printf("Total active inputs: %d\n", numActiveInputs);
   OsSysLog::add(FAC_MP, PRI_DEBUG, "Total active inputs: %d", numActiveInputs);
#endif // TEST_PRINT_MIXING_CONTRIBUTORS ]

   //
   //  Build mix actions stack.
   //

   // Prepare 0: Initialize temporary data structures.
   initMixActions();
   initMixDataInfoStack(numActiveInputs);
   // Prepare 1: Copy data from inputs to temporary mix data storage beginning.
   //   NOTE: Inputs data must be always first. This is used later for
   //         optimization!
   for (int input=0; input<numActiveInputs; input++)
   {
      int tmpInput=0;
      for (; tmpInput<input; tmpInput++)
      {
         mpMixDataInfoStackTop[tmpInput] = 0;
      }
      mpMixDataInfoStackTop[tmpInput] = 1;
      tmpInput++;
      for (; tmpInput<numActiveInputs; tmpInput++)
      {
         mpMixDataInfoStackTop[tmpInput] = 0;
      }

      // Commands to copy data from inputs will be queued after main loop.
      // ...

      // Advance stack pointers.
      mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = INT_MAX;
      PRINT_TOP_MIX_DATA();
      mMixDataInfoProcessedStackTop++;
      mpMixDataInfoStackTop += mMixDataInfoStackStep;
      assert(mpMixDataInfoStackTop<mpMixDataInfoStack+mMixDataInfoStackLength);
   }
   // Prepare 2: Append outputs data to temporary mix data storage.
   for (int output=0; output<maxOutputs(); output++)
   {
      int dataBitCounter = 0;

      // Generate data set for this output.
      for (int input=0; input<mMixDataInfoStackStep; input++)
      {
         const int origInput = mExtendedInputs.getOrigin(mpActiveInputsList[input]);
         mpMixDataInfoStackTop[input] =
            (mExtendedInputs.getExtendedInput(origInput, output) == mpActiveInputsList[input]) ? 1 : 0;
         dataBitCounter += mpMixDataInfoStackTop[input];
      }

      // Skip output if it is muted.
      if (dataBitCounter > 0)
      {
         // Check for uniqueness.
         int twinData;
         if (searchData(mpMixDataInfoStackTop, twinData))
         {
            // Stack already contain this data.

            // Request copy to output.
            pushMixActionCopyToOutput(twinData, output);
         }
         else
         {
            // Data is unique.

            // Request copy to output.
            pushMixActionCopyToOutput(mMixDataInfoProcessedStackTop, output);

            // Push output mask to mix data array.
            mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
            mMixDataInfoProcessedStackTop++;
            mpMixDataInfoStackTop += mMixDataInfoStackStep;
            assert(mpMixDataInfoStackTop<mpMixDataInfoStack+mMixDataInfoStackLength);
         }
      }
   }

   // Main loop: walk through data info stack, looking for the way to get
   //            requested data. New data is added on top of data info stack
   //            if needed.
   int *pDataInfoStackPtr = mpMixDataInfoStack;
   int  dataInfoStackPos  = 0;
   while (pDataInfoStackPtr<mpMixDataInfoStackTop)
   {
      // Do processing only if not processed already
      if (mpMixDataInfoProcessedStack[dataInfoStackPos]<0)
      {
         int *pClosestDataInfoStackPtr;
         int  closestDataInfoStackPos;
         if (searchClosestUnprocessedData(pDataInfoStackPtr,
                                          pDataInfoStackPtr, dataInfoStackPos,
                                          pClosestDataInfoStackPtr, closestDataInfoStackPos))
         {
            // Pair for this data found.

            int *pCommonDataPtr = mpMixDataInfoStackTop;
            int *pFirstDataDiffPtr  = mpMixDataInfoStackTop+mMixDataInfoStackStep;
            int *pSecondDataDiffPtr = mpMixDataInfoStackTop+2*mMixDataInfoStackStep;
            mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
            mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop+1] = -1;
            mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop+2] = -1;
            int  commonDataBitCounter = 0;
            int  firstDataDiffBitCounter  = 0;
            int  secondDataDiffBitCounter = 0;

            assert(pSecondDataDiffPtr+mMixDataInfoStackStep<mpMixDataInfoStack+mMixDataInfoStackLength);

            // Calculate common part, first only part and second only part.
            for (int i=0; i<mMixDataInfoStackStep; i++)
            {
               pCommonDataPtr[i]     =  pDataInfoStackPtr[i] &  pClosestDataInfoStackPtr[i];
               pFirstDataDiffPtr[i]  =  pDataInfoStackPtr[i] & !pClosestDataInfoStackPtr[i];
               pSecondDataDiffPtr[i] = !pDataInfoStackPtr[i] &  pClosestDataInfoStackPtr[i];
               commonDataBitCounter     += pCommonDataPtr[i];
               firstDataDiffBitCounter  += pFirstDataDiffPtr[i];
               secondDataDiffBitCounter += pSecondDataDiffPtr[i];
            }
            // Data sets must have common part!
            assert(commonDataBitCounter > 0);
            // Data sets must be different!
            assert(firstDataDiffBitCounter > 0 || secondDataDiffBitCounter > 0);

            int commonDataPos;
            int firstDataDiffPos;
            int secondDataDiffPos;

            // Look is this data is already in our stack.
            // Note, that data we're searching for is always in array,
            // because we've stored it temporarily there, so search function
            // always succeed.
            // Note also, that if firstDataBitCounter or secondDataBitCounter
            // is zero, then common part is equal to first or second data.
            if (firstDataDiffBitCounter > 0)
            {
               searchExistingUnprocessedData(pFirstDataDiffPtr, firstDataDiffPos,
                                             numActiveInputs);
               if (secondDataDiffBitCounter > 0)
               {
                  searchExistingUnprocessedData(pCommonDataPtr, commonDataPos,
                                                numActiveInputs);
               }
            }
            if (secondDataDiffBitCounter > 0)
            {
               searchExistingUnprocessedData(pSecondDataDiffPtr, secondDataDiffPos,
                                             numActiveInputs);
               if (firstDataDiffBitCounter == 0)
               {
                  // Common data is equal to first data.
                  commonDataPos = dataInfoStackPos;
               }
            }
            else
            {
               // Common data is equal to second data.
               commonDataPos = closestDataInfoStackPos;
            }

            // Remove unused data from our stack.
            if ((firstDataDiffBitCounter == 0) ||
                (secondDataDiffBitCounter == 0) ||
                (commonDataPos < mMixDataInfoProcessedStackTop))
            {
               // Common data is not needed, so move other data to its place.
               if ((firstDataDiffBitCounter > 0) &&
                   (firstDataDiffPos > mMixDataInfoProcessedStackTop))
               {
                  // First data is needed. Move it and advance stack pointer.
                  if (commonDataPos >= firstDataDiffPos)
                  {
                     commonDataPos--;
                  }
                  firstDataDiffPos--;
                  memcpy(pCommonDataPtr, pFirstDataDiffPtr,
                         mMixDataInfoStackStep*sizeof(int));
                  mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                  PRINT_TOP_MIX_DATA();
                  mpMixDataInfoStackTop += mMixDataInfoStackStep;
                  mMixDataInfoProcessedStackTop++;

                  if ((secondDataDiffBitCounter > 0) &&
                      (secondDataDiffPos >= mMixDataInfoProcessedStackTop))
                  {
                     // Second data is needed. Move it and advance stack pointer.
                     if (commonDataPos == secondDataDiffPos)
                     {
                        commonDataPos--;
                     }
                     secondDataDiffPos--;
                     memcpy(pFirstDataDiffPtr, pSecondDataDiffPtr,
                            mMixDataInfoStackStep*sizeof(int));
                     mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                     PRINT_TOP_MIX_DATA();
                     mpMixDataInfoStackTop += mMixDataInfoStackStep;
                     mMixDataInfoProcessedStackTop++;
                  }
               }
               else
               {
                  if ((secondDataDiffBitCounter > 0) &&
                      (secondDataDiffPos >= mMixDataInfoProcessedStackTop))
                  {
                     // Second data is needed. Move it and advance stack pointer.
                     if (commonDataPos == secondDataDiffPos)
                     {
                        commonDataPos -= 2;
                     }
                     secondDataDiffPos -= 2;
                     memcpy(pCommonDataPtr, pSecondDataDiffPtr,
                            mMixDataInfoStackStep*sizeof(int));
                     mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                     PRINT_TOP_MIX_DATA();
                     mpMixDataInfoStackTop += mMixDataInfoStackStep;
                     mMixDataInfoProcessedStackTop++;
                  }
               }
            }
            else
            {
               // Common data is new. Advance stack pointer.
               mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
               PRINT_TOP_MIX_DATA();
               mpMixDataInfoStackTop += mMixDataInfoStackStep;
               mMixDataInfoProcessedStackTop++;

               if ((firstDataDiffBitCounter > 0) &&
                   (firstDataDiffPos >= mMixDataInfoProcessedStackTop))
               {
                  // First data is needed. Advance stack pointer.
                  mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                  PRINT_TOP_MIX_DATA();
                  mpMixDataInfoStackTop += mMixDataInfoStackStep;
                  mMixDataInfoProcessedStackTop++;

                  if ((secondDataDiffBitCounter > 0) &&
                      (secondDataDiffPos >= mMixDataInfoProcessedStackTop))
                  {
                     // Second data is needed. Advance stack pointer.
                     mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                     PRINT_TOP_MIX_DATA();
                     mpMixDataInfoStackTop += mMixDataInfoStackStep;
                     mMixDataInfoProcessedStackTop++;
                  }
               }
               else
               {
                  if ((secondDataDiffBitCounter > 0) &&
                      (secondDataDiffPos >= mMixDataInfoProcessedStackTop))
                  {
                     // Second data is needed. Move it and advance stack pointer.
                     mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
                     secondDataDiffPos--;
                     memcpy(pFirstDataDiffPtr, pSecondDataDiffPtr,
                            mMixDataInfoStackStep*sizeof(int));
                     PRINT_TOP_MIX_DATA();
                     mpMixDataInfoStackTop += mMixDataInfoStackStep;
                     mMixDataInfoProcessedStackTop++;
                  }
               }
            }
            assert(mpMixDataInfoStackTop<mpMixDataInfoStack+mMixDataInfoStackLength);

            if (firstDataDiffBitCounter > 0)
            {
               // Queue command to generate first data and mark it as processed
               // if it is not a subset of second data. In later case leave it
               // unprocessed for later processing.
               pushMixActionMix(commonDataPos, firstDataDiffPos, dataInfoStackPos);
//               moveDataUp(numActiveInputs, firstDataDiffPos);
            }

            if (secondDataDiffBitCounter > 0)
            {
               // Queue command to generate second data and mark it as processed
               // if it is not a subset of first data. In later case leave it
               // unprocessed for later processing.
               pushMixActionMix(commonDataPos, secondDataDiffPos, closestDataInfoStackPos);
//               moveDataUp(numActiveInputs, secondDataDiffPos);
            }

//            moveDataUp(numActiveInputs, commonDataPos);
         }
         else
         {
            // No pair for this data found. Cut one input from it and continue.
            // Note, that data must have more then one "1", because it is
            // not just an input.

            // Copy data to the top of stack, and remove first "1" from it.
            memcpy(mpMixDataInfoStackTop, pDataInfoStackPtr,
                   sizeof(int)*mMixDataInfoStackStep);
            mpMixDataInfoProcessedStack[mMixDataInfoProcessedStackTop] = -1;
            int extInput;
            for (extInput=0; extInput<mMixDataInfoStackStep; extInput++)
            {
               if (mpMixDataInfoStackTop[extInput] == 1)
               {
                  mpMixDataInfoStackTop[extInput] = 0;
                  break;
               }
            }
            assert(extInput<numActiveInputs);

            int newDataPos;
            searchExistingUnprocessedData(mpMixDataInfoStackTop, newDataPos,
                                          numActiveInputs);
            if (newDataPos >= mMixDataInfoProcessedStackTop)
            {
               // Advance stack pointer.
               PRINT_TOP_MIX_DATA();
               mpMixDataInfoStackTop += mMixDataInfoStackStep;
               mMixDataInfoProcessedStackTop++;
            }

            // Queue command to generate data.
            // Here we use knowledge, that inputs are located at the end of
            // data stack.
            pushMixActionMix(extInput, newDataPos, dataInfoStackPos);
//            moveDataUp(numActiveInputs, newDataPos);
         }

         if (mpMixDataInfoProcessedStack[dataInfoStackPos]>=0)
         {
            // Step to next data if we've processed this one.
            pDataInfoStackPtr += mMixDataInfoStackStep;
            dataInfoStackPos++;
         }
      }
      else
      {
         // Step to next data info.
         pDataInfoStackPtr += mMixDataInfoStackStep;
         dataInfoStackPos++;
      }
   }

   // Finalization: request copying of input data to temporary storage
   for (extInput=0; extInput<numActiveInputs; extInput++)
   {
      pushMixActionCopyFromInput(mpActiveInputsList[extInput], extInput);
   }

   //
   //  Apply mix actions from stack.
   //
   initMixDataStack();

   // Initialize amplitudes if they haven't been initialized yet.
   for (int i=0; i<inBufsSize; i++)
   {
      if (mpPrevAmplitudes[i] < 0 && inBufs[i].isValid())
      {
         MpAudioBufPtr pAudioBuf = inBufs[i];
         MpAudioSample amplitude = pAudioBuf->getAmplitude();
         mpPrevAmplitudes[i] = amplitude == 0 ? 1 : amplitude;
      }
   }

#ifdef TEST_PRINT_MIXING // [
   printf("-----------------------------------\n");
#endif // TEST_PRINT_MIXING ]
#ifdef DEBUG_AGC
   static int debugCounter = 0;
   bool debugFlag = false;
   debugCounter++;
   if (debugCounter % 50 == 0)
   {
      debugFlag = true;
   }
   if (debugFlag)
   {
      printf("\nInput:  ");
   }
#endif

   for (int action=mMixActionsStackTop-1; action>=0; action--)
   {
      switch (mpMixActionsStack[action].mType)
      {
      case MixAction::DO_MIX:
         {
            const MixAction &mixAction = mpMixActionsStack[action];
            MpDspUtils::add(&mpMixDataStack[mMixDataStackStep * mixAction.mSrc1],
                            &mpMixDataStack[mMixDataStackStep * mixAction.mSrc2],
                            &mpMixDataStack[mMixDataStackStep * mixAction.mDst],
                            mMixDataStackStep);
            mpMixDataSpeechType[mixAction.mDst] =
               mixSpeechTypes(mpMixDataSpeechType[mixAction.mSrc1],
                              mpMixDataSpeechType[mixAction.mSrc2]);
            mpMixDataAmplitude[mixAction.mDst] =
               mpMixDataAmplitude[mixAction.mSrc1] + mpMixDataAmplitude[mixAction.mSrc2];
         }
#ifdef TEST_PRINT_MIXING // [
         OsSysLog::add(FAC_MP, PRI_DEBUG, "DO_MIX:     %2d + %2d -> %2d [0x%08X + 0x%08X -> 0x%08X]\n",
                mpMixActionsStack[action].mSrc1,
                mpMixActionsStack[action].mSrc2,
                mpMixActionsStack[action].mDst,
                mpMixDataStack[mMixDataStackStep * mpMixActionsStack[action].mSrc1],
                mpMixDataStack[mMixDataStackStep * mpMixActionsStack[action].mSrc2],
                mpMixDataStack[mMixDataStackStep * mpMixActionsStack[action].mDst]);
#endif // TEST_PRINT_MIXING ]
         break;
      case MixAction::COPY_TO_OUTPUT:
         {
            const int src = mpMixActionsStack[action].mSrc1;

            // Need to look at the input gain for this particular output
            if (src < numActiveInputs &&
                mExtendedInputs.getGain(mpActiveInputsList[src]) == MP_BRIDGE_GAIN_PASSTHROUGH)
            {
               // This is direct input to output copy.
               const int origInput = mExtendedInputs.getOrigin(mpActiveInputsList[src]);
               outBufs[mpMixActionsStack[action].mDst] = inBufs[origInput];

#ifdef TEST_PRINT_MIXING // [
               OsSysLog::add(FAC_MP, PRI_DEBUG, "src: %d mpActiveInputsList[src]: %d origInput: %d",
                      src, mpActiveInputsList[src], origInput);
               OsSysLog::add(FAC_MP, PRI_DEBUG, "mExtendedInputs.getGain(src): %d mExtendedInputs.getGain(mpActiveInputsList[src]): %d",
                      mExtendedInputs.getGain(src), mExtendedInputs.getGain(mpActiveInputsList[src]));
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_TO_OUTPUT*: %2d -> %2d\n",
                      mpMixActionsStack[action].mSrc1,
                      mpMixActionsStack[action].mDst);
#endif // TEST_PRINT_MIXING ]
            } 
            else
            {
               // This is mixed data. Convert it and copy to buffer.

               // Get buffer for output data.
               MpAudioBufPtr pOutBuf = MpMisc.RawAudioPool->getBuffer();
               assert(pOutBuf.isValid());
               pOutBuf->setSamplesNumber(samplesPerFrame);
               pOutBuf->setSpeechType(mpMixDataSpeechType[src]);
               pOutBuf->setEnergy(-1);
               pOutBuf->setAmplitude(MPF_SATURATE16(mpMixDataAmplitude[src]));
               if (mpMixDataAmplitude[src] >= MpSpeechParams::MAX_AMPLITUDE)
               {
                  // This can be a wrong decision. We need better clipping
                  // handling here. Probably we should track clipping flag
                  // down to original inputs through all scaling and then
                  // use logical OR to determine final clipping flag.
                  pOutBuf->setClipping(TRUE);
               }

               MpDspUtils::convert_Att(&mpMixDataStack[mMixDataStackStep * src],
                                       pOutBuf->getSamplesWritePtr(),
                                       mMixDataStackStep, MP_BRIDGE_FRAC_LENGTH);

   #ifdef TEST_PRINT_MIXING // [
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_TO_OUTPUT:  %2d -> %2d [0x%08X -> 0x%08X]\n",
                      mpMixActionsStack[action].mSrc1,
                      mpMixActionsStack[action].mDst,
                      mpMixDataStack[mMixDataStackStep * mpMixActionsStack[action].mSrc1],
                      *pOutBuf->getSamplesPtr());
   #endif // TEST_PRINT_MIXING ]

               outBufs[mpMixActionsStack[action].mDst].swap(pOutBuf);
            }
         }
         break;
      case MixAction::COPY_FROM_INPUT:
         {
            const int extInput = mpMixActionsStack[action].mSrc1;
            const int extOutput = mpMixActionsStack[action].mDst;
            const int origInput = mExtendedInputs.getOrigin(extInput);
            const MpAudioBufPtr pInBuf(inBufs[origInput]);
            MpAudioSample prevAmplitude = mpPrevAmplitudes[origInput];
            MpAudioSample curAmplitude = pInBuf->getAmplitude();
            if (curAmplitude == 0)
            {
               curAmplitude = 1;
            }

            mpMixDataSpeechType[extOutput] = pInBuf->getSpeechType();
            if (  mExtendedInputs.getGain(extInput) == MP_BRIDGE_GAIN_PASSTHROUGH
               && prevAmplitude == MpSpeechParams::MAX_AMPLITUDE
               && curAmplitude == MpSpeechParams::MAX_AMPLITUDE)
            {
               MpDspUtils::convert_Gain(pInBuf->getSamplesPtr(),
                                        &mpMixDataStack[mMixDataStackStep * extOutput],
                                        mMixDataStackStep, MP_BRIDGE_FRAC_LENGTH);
               // Update output amplitude value.
               mpMixDataAmplitude[extOutput] = MpSpeechParams::MAX_AMPLITUDE;
#ifdef DEBUG_AGC
               if ( debugFlag && (origInput==0 || origInput==3) )
               {
                  printf("P ");
               }
#endif
#ifdef TEST_PRINT_MIXING // [
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_FROM_INPUT: %2d <- %2d [0x%08X <- 0x%08X <<%d]\n",
                      extOutput,
                      extInput,
                      mpMixDataStack[mMixDataStackStep * extOutput],
                      *pInBuf->getSamplesPtr(),
                      MP_BRIDGE_FRAC_LENGTH);
#endif // TEST_PRINT_MIXING ]
            }
            else if (curAmplitude == prevAmplitude)
            {
               // Calculate gain taking into account input amplitude.
               MpBridgeGain scaledGain = (MpBridgeGain)
                  ((mExtendedInputs.getGain(extInput)*MAX_AMPLITUDE_ROUND)/curAmplitude);

               MpDspUtils::mul(pInBuf->getSamplesPtr(),
                               scaledGain,
                               &mpMixDataStack[mMixDataStackStep * extOutput],
                               mMixDataStackStep);
               // Update output amplitude value.
               mpMixDataAmplitude[extOutput] = (curAmplitude*scaledGain)>>MP_BRIDGE_FRAC_LENGTH;
#ifdef DEBUG_AGC
               if ( debugFlag && (origInput==0 || origInput==3) )
               {
                  printf("F %d ", scaledGain);
               }
#endif
#ifdef TEST_PRINT_MIXING // [
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_FROM_INPUT: scaledGain(%d) = %d * %d / %d",
                      (int) scaledGain, mExtendedInputs.getGain(extInput), MAX_AMPLITUDE_ROUND, curAmplitude);
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_FROM_INPUT: %2d <- %2d [0x%08X <- 0x%08X *%d ( %d)]",
                      extOutput,
                      extInput,
                      mpMixDataStack[mMixDataStackStep * extOutput],
                      *pInBuf->getSamplesPtr(),
                      mExtendedInputs.getGain(extInput),
                      (int) scaledGain);
#endif // TEST_PRINT_MIXING ]
            }
            else
            {
               // Calculate gain start and end taking into account previous
               // and current input amplitudes.
               MpBridgeGain origGain = mExtendedInputs.getGain(extInput);
               MpBridgeGain scaledGainStart = (MpBridgeGain)
                  ((origGain*MAX_AMPLITUDE_ROUND)/prevAmplitude);
               MpBridgeGain scaledGainEnd = (MpBridgeGain)
                  ((origGain*MAX_AMPLITUDE_ROUND)/curAmplitude);

               MpDspUtils::mulLinear(pInBuf->getSamplesPtr(),
                                     scaledGainStart,
                                     scaledGainEnd,
                                     &mpMixDataStack[mMixDataStackStep * extOutput],
                                     mMixDataStackStep);
               MpBridgeGain scaledGainMax = MpDspUtils::maximum(scaledGainStart, scaledGainEnd);
               mpMixDataAmplitude[extOutput] = (curAmplitude*scaledGainMax) >> MP_BRIDGE_FRAC_LENGTH;
#ifdef DEBUG_AGC
               if ( debugFlag && (origInput==0 || origInput==3) )
               {
                  printf("V %d %d ", scaledGainStart, scaledGainEnd);
               }
#endif
#ifdef TEST_PRINT_MIXING // [
               OsSysLog::add(FAC_MP, PRI_DEBUG, "COPY_FROM_INPUT: %2d <- %2d [0x%08X <- 0x%08X *%d/(%d->%d)]\n",
                      extOutput,
                      extInput,
                      mpMixDataStack[mMixDataStackStep * extOutput],
                      *pInBuf->getSamplesPtr(),
                      origGain,
                      prevAmplitude,
                      curAmplitude);
#endif // TEST_PRINT_MIXING ]
            }
         }
         break;
      case MixAction::NO_OPERATION:
         break;
      }
Example #2
0
UtlBoolean MpBridgeAlgSimple::doMix(MpBufPtr inBufs[], int inBufsSize,
                                    MpBufPtr outBufs[], int outBufsSize,
                                    int samplesPerFrame)
{
   // Initialize amplitudes if they haven't been initialized yet.
   for (int i=0; i<inBufsSize; i++)
   {
      if (mpPrevAmplitudes[i] < 0 && inBufs[i].isValid())
      {
         MpAudioBufPtr pAudioBuf = inBufs[i];
         MpAudioSample amplitude = pAudioBuf->getAmplitude();
         mpPrevAmplitudes[i] = amplitude == 0 ? 1 : amplitude;
      }
   }

#ifdef DEBUG_AGC
   static int debugCounter = 0;
   bool debugFlag = false;
   debugCounter++;
   if (debugCounter % 50 == 0)
   {
      debugFlag = true;
   }
   if (debugFlag)
   {
      printf("\nInput:  ");
      for (int inputNum=0; inputNum<inBufsSize; inputNum++)
      {
         if (inBufs[inputNum].isValid())
         {
            MpAudioBufPtr pFrame = inBufs[inputNum];
            printf("%d ", pFrame->getAmplitude());
         }
         else
         {
            printf("- ");
         }
      }
      printf("\n");
      printf("Output: ");
   }
#endif

   // Loop over all outputs and mix
   for (int outputNum=0; outputNum<outBufsSize; outputNum++)
   {
      MpBridgeGain *pInputGains = &mpGainMatrix[outputNum*maxInputs()];
      int32_t amplitude = 0;

      // Initialize accumulator
      for (int i=0; i<samplesPerFrame; i++)
      {
         mpMixAccumulator[i] = MPF_BRIDGE_FLOAT(0.0f);
      }

      // Get buffer for output data.
      MpAudioBufPtr pOutBuf = MpMisc.RawAudioPool->getBuffer();
      assert(pOutBuf.isValid());
      pOutBuf->setSamplesNumber(samplesPerFrame);
      pOutBuf->setSpeechType(MP_SPEECH_SILENT);
      pOutBuf->setEnergy(-1);

      // Mix input data to accumulator
      for (int inputNum=0; inputNum<inBufsSize; inputNum++)
      {
         if (inBufs[inputNum].isValid() &&
             pInputGains[inputNum] != MP_BRIDGE_GAIN_MUTED)
         {
            MpAudioBufPtr pFrame = inBufs[inputNum];
            assert((int)(pFrame->getSamplesNumber()) == samplesPerFrame);

            // Do not mix muted audio.
            if (pFrame->getSpeechType() == MP_SPEECH_MUTED)
            {
               continue;
            }

            MpAudioSample prevAmplitude = mpPrevAmplitudes[inputNum];
            MpAudioSample curAmplitude = pFrame->getAmplitude();
            if (curAmplitude == 0)
            {
               curAmplitude = 1;
            }

            if (  pInputGains[inputNum] == MP_BRIDGE_GAIN_PASSTHROUGH
               && prevAmplitude == MpSpeechParams::MAX_AMPLITUDE
               && curAmplitude == MpSpeechParams::MAX_AMPLITUDE)
            {
               MpDspUtils::add_IGain(pFrame->getSamplesPtr(), mpMixAccumulator,
                                     samplesPerFrame, MP_BRIDGE_FRAC_LENGTH);

               // Update output amplitude value.
               amplitude += MpSpeechParams::MAX_AMPLITUDE;
#ifdef DEBUG_AGC
               if ( debugFlag && (outputNum==0 || outputNum==3) )
               {
                  printf("P");
               }
#endif
            }
            else if (curAmplitude == prevAmplitude)
            {
               // Calculate gain taking into account input amplitude.
               MpBridgeGain scaledGain = (MpBridgeGain)
                  ((pInputGains[inputNum]*MAX_AMPLITUDE_ROUND)/curAmplitude);

               MpDspUtils::addMul_I(pFrame->getSamplesPtr(),
                                    scaledGain,
                                    mpMixAccumulator,
                                    samplesPerFrame);

               // Update output amplitude value.
               amplitude += ((int)(curAmplitude*scaledGain))>>MP_BRIDGE_FRAC_LENGTH;
#ifdef DEBUG_AGC
               if ( debugFlag && (outputNum==0 || outputNum==3) )
               {
                  printf("F %d", scaledGain);
               }
#endif
            }
            else
            {
               // Calculate gain start and end taking into account previous
               // and current input amplitudes.
               MpBridgeGain scaledGainStart = (MpBridgeGain)
                  ((pInputGains[inputNum]*MAX_AMPLITUDE_ROUND)/prevAmplitude);
               MpBridgeGain scaledGainEnd = (MpBridgeGain)
                  ((pInputGains[inputNum]*MAX_AMPLITUDE_ROUND)/curAmplitude);

               MpDspUtils::addMulLinear_I(pFrame->getSamplesPtr(),
                                          scaledGainStart,
                                          scaledGainEnd,
                                          mpMixAccumulator,
                                          samplesPerFrame);

               // Update output amplitude value.
               MpBridgeGain scaledGainMax = MpDspUtils::maximum(scaledGainStart, scaledGainEnd);
               amplitude += ((int)(curAmplitude*scaledGainMax)) >> MP_BRIDGE_FRAC_LENGTH;
#ifdef DEBUG_AGC
               if ( debugFlag && (outputNum==0 || outputNum==3) )
               {
                  printf("V %d %d", scaledGainStart, scaledGainEnd);
               }
#endif
            }

            // Update output frame speech type.
            pOutBuf->setSpeechType(mixSpeechTypes(pOutBuf->getSpeechType(),
                                                  pFrame->getSpeechType()));
         }