| Index: third_party/WebKit/Source/platform/audio/AudioBus.cpp
 | 
| diff --git a/third_party/WebKit/Source/platform/audio/AudioBus.cpp b/third_party/WebKit/Source/platform/audio/AudioBus.cpp
 | 
| index 2b29e70916b8184cddcae076ec3fde3595e0316c..677b3d7227dd4e032a8f139f8c89c1ec1be0ff7d 100644
 | 
| --- a/third_party/WebKit/Source/platform/audio/AudioBus.cpp
 | 
| +++ b/third_party/WebKit/Source/platform/audio/AudioBus.cpp
 | 
| @@ -216,24 +216,9 @@ void AudioBus::copyFrom(const AudioBus& sourceBus, ChannelInterpretation channel
 | 
|      if (&sourceBus == this)
 | 
|          return;
 | 
|  
 | 
| -    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
| -    unsigned numberOfDestinationChannels = numberOfChannels();
 | 
| -
 | 
| -    if (numberOfDestinationChannels == numberOfSourceChannels) {
 | 
| -        for (unsigned i = 0; i < numberOfSourceChannels; ++i)
 | 
| -            channel(i)->copyFrom(sourceBus.channel(i));
 | 
| -    } else {
 | 
| -        switch (channelInterpretation) {
 | 
| -        case Speakers:
 | 
| -            speakersCopyFrom(sourceBus);
 | 
| -            break;
 | 
| -        case Discrete:
 | 
| -            discreteCopyFrom(sourceBus);
 | 
| -            break;
 | 
| -        default:
 | 
| -            ASSERT_NOT_REACHED();
 | 
| -        }
 | 
| -    }
 | 
| +    // Copying bus is equivalent to zeroing and then summing.
 | 
| +    zero();
 | 
| +    sumFrom(sourceBus, channelInterpretation);
 | 
|  }
 | 
|  
 | 
|  void AudioBus::sumFrom(const AudioBus& sourceBus, ChannelInterpretation channelInterpretation)
 | 
| @@ -244,164 +229,208 @@ void AudioBus::sumFrom(const AudioBus& sourceBus, ChannelInterpretation channelI
 | 
|      unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
|      unsigned numberOfDestinationChannels = numberOfChannels();
 | 
|  
 | 
| -    if (numberOfDestinationChannels == numberOfSourceChannels) {
 | 
| +    // If the channel numbers are equal, perform channels-wise summing.
 | 
| +    if (numberOfSourceChannels == numberOfDestinationChannels) {
 | 
|          for (unsigned i = 0; i < numberOfSourceChannels; ++i)
 | 
|              channel(i)->sumFrom(sourceBus.channel(i));
 | 
| -    } else {
 | 
| -        switch (channelInterpretation) {
 | 
| -        case Speakers:
 | 
| -            speakersSumFrom(sourceBus);
 | 
| -            break;
 | 
| -        case Discrete:
 | 
| -            discreteSumFrom(sourceBus);
 | 
| -            break;
 | 
| -        default:
 | 
| -            ASSERT_NOT_REACHED();
 | 
| -        }
 | 
| +
 | 
| +        return;
 | 
| +    }
 | 
| +
 | 
| +    // Otherwise perform up/down-mix or the discrete transfer based on the
 | 
| +    // number of channels and the channel interpretation.
 | 
| +    switch (channelInterpretation) {
 | 
| +    case Speakers:
 | 
| +        if (numberOfSourceChannels < numberOfDestinationChannels)
 | 
| +            sumFromByUpMixing(sourceBus);
 | 
| +        else
 | 
| +            sumFromByDownMixing(sourceBus);
 | 
| +        break;
 | 
| +    case Discrete:
 | 
| +        discreteSumFrom(sourceBus);
 | 
| +        break;
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void AudioBus::speakersCopyFrom(const AudioBus& sourceBus)
 | 
| +void AudioBus::discreteSumFrom(const AudioBus& sourceBus)
 | 
|  {
 | 
| -    // FIXME: Implement down mixing 5.1 to stereo.
 | 
| -    // https://bugs.webkit.org/show_bug.cgi?id=79192
 | 
| -
 | 
|      unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
|      unsigned numberOfDestinationChannels = numberOfChannels();
 | 
|  
 | 
| -    if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) {
 | 
| -        // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
 | 
| -        // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
 | 
| -        const AudioChannel* sourceChannel = sourceBus.channel(0);
 | 
| -        channel(0)->copyFrom(sourceChannel);
 | 
| -        channel(1)->copyFrom(sourceChannel);
 | 
| -    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
 | 
| -        // Handle stereo -> mono case. output = 0.5 * (input.L + input.R).
 | 
| -        AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
 | 
| -
 | 
| -        const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
 | 
| -        const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data();
 | 
| -
 | 
| -        float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| -        vadd(sourceL, 1, sourceR, 1, destination, 1, length());
 | 
| -        float scale = 0.5;
 | 
| -        vsmul(destination, 1, &scale, destination, 1, length());
 | 
| -    } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) {
 | 
| -        // Handle mono -> 5.1 case, copy mono channel to center.
 | 
| -        channel(2)->copyFrom(sourceBus.channel(0));
 | 
| -        channel(0)->zero();
 | 
| -        channel(1)->zero();
 | 
| -        channel(3)->zero();
 | 
| -        channel(4)->zero();
 | 
| -        channel(5)->zero();
 | 
| -    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) {
 | 
| -        // Handle 5.1 -> mono case.
 | 
| -        zero();
 | 
| -        speakersSumFrom5_1_ToMono(sourceBus);
 | 
| -    } else {
 | 
| -        // Fallback for unknown combinations.
 | 
| -        discreteCopyFrom(sourceBus);
 | 
| +    if (numberOfDestinationChannels < numberOfSourceChannels) {
 | 
| +        // Down-mix by summing channels and dropping the remaining.
 | 
| +        for (unsigned i = 0; i < numberOfDestinationChannels; ++i)
 | 
| +            channel(i)->sumFrom(sourceBus.channel(i));
 | 
| +    } else if (numberOfDestinationChannels > numberOfSourceChannels) {
 | 
| +        // Up-mix by summing as many channels as we have.
 | 
| +        for (unsigned i = 0; i < numberOfSourceChannels; ++i)
 | 
| +            channel(i)->sumFrom(sourceBus.channel(i));
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void AudioBus::speakersSumFrom(const AudioBus& sourceBus)
 | 
| +void AudioBus::sumFromByUpMixing(const AudioBus& sourceBus)
 | 
|  {
 | 
| -    // FIXME: Implement down mixing 5.1 to stereo.
 | 
| -    // https://bugs.webkit.org/show_bug.cgi?id=79192
 | 
| -
 | 
|      unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
|      unsigned numberOfDestinationChannels = numberOfChannels();
 | 
|  
 | 
| -    if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) {
 | 
| -        // Handle mono -> stereo case (summing mono channel into both left and right).
 | 
| -        const AudioChannel* sourceChannel = sourceBus.channel(0);
 | 
| -        channel(0)->sumFrom(sourceChannel);
 | 
| -        channel(1)->sumFrom(sourceChannel);
 | 
| -    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
 | 
| -        // Handle stereo -> mono case. output += 0.5 * (input.L + input.R).
 | 
| -        AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
 | 
| -
 | 
| -        const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
 | 
| -        const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data();
 | 
| -
 | 
| -        float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| -        float scale = 0.5;
 | 
| -        vsma(sourceL, 1, &scale, destination, 1, length());
 | 
| -        vsma(sourceR, 1, &scale, destination, 1, length());
 | 
| -    } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) {
 | 
| -        // Handle mono -> 5.1 case, sum mono channel into center.
 | 
| -        channel(2)->sumFrom(sourceBus.channel(0));
 | 
| -    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) {
 | 
| -        // Handle 5.1 -> mono case.
 | 
| -        speakersSumFrom5_1_ToMono(sourceBus);
 | 
| +    if ((numberOfSourceChannels == 1 && numberOfDestinationChannels == 2) || (numberOfSourceChannels == 1 && numberOfDestinationChannels == 4)) {
 | 
| +        // Up-mixing: 1 -> 2, 1 -> 4
 | 
| +        //   output.L = input
 | 
| +        //   output.R = input
 | 
| +        //   output.SL = 0 (in the case of 1 -> 4)
 | 
| +        //   output.SR = 0 (in the case of 1 -> 4)
 | 
| +        const AudioChannel* sourceL = sourceBus.channelByType(ChannelLeft);
 | 
| +        channelByType(ChannelLeft)->sumFrom(sourceL);
 | 
| +        channelByType(ChannelRight)->sumFrom(sourceL);
 | 
| +    } else if (numberOfSourceChannels == 1 && numberOfDestinationChannels == 6) {
 | 
| +        // Up-mixing: 1 -> 5.1
 | 
| +        //   output.L = 0
 | 
| +        //   output.R = 0
 | 
| +        //   output.C = input (put in center channel)
 | 
| +        //   output.LFE = 0
 | 
| +        //   output.SL = 0
 | 
| +        //   output.SR = 0
 | 
| +        channelByType(ChannelCenter)->sumFrom(sourceBus.channelByType(ChannelLeft));
 | 
| +    } else if ((numberOfSourceChannels == 2 && numberOfDestinationChannels == 4) || (numberOfSourceChannels == 2 && numberOfDestinationChannels == 6)) {
 | 
| +        // Up-mixing: 2 -> 4, 2 -> 5.1
 | 
| +        //   output.L = input.L
 | 
| +        //   output.R = input.R
 | 
| +        //   output.C = 0 (in the case of 2 -> 5.1)
 | 
| +        //   output.LFE = 0 (in the case of 2 -> 5.1)
 | 
| +        //   output.SL = 0
 | 
| +        //   output.SR = 0
 | 
| +        channelByType(ChannelLeft)->sumFrom(sourceBus.channelByType(ChannelLeft));
 | 
| +        channelByType(ChannelRight)->sumFrom(sourceBus.channelByType(ChannelRight));
 | 
| +    } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 6) {
 | 
| +        // Up-mixing: 4 -> 5.1
 | 
| +        //   output.L = input.L
 | 
| +        //   output.R = input.R
 | 
| +        //   output.C = 0
 | 
| +        //   output.LFE = 0
 | 
| +        //   output.SL = input.SL
 | 
| +        //   output.SR = input.SR
 | 
| +        channelByType(ChannelLeft)->sumFrom(sourceBus.channelByType(ChannelLeft));
 | 
| +        channelByType(ChannelRight)->sumFrom(sourceBus.channelByType(ChannelRight));
 | 
| +        channelByType(ChannelSurroundLeft)->sumFrom(sourceBus.channelByType(ChannelSurroundLeft));
 | 
| +        channelByType(ChannelSurroundRight)->sumFrom(sourceBus.channelByType(ChannelSurroundRight));
 | 
|      } else {
 | 
| -        // Fallback for unknown combinations.
 | 
| +        // All other cases, fall back to the discrete sum. This will silence the
 | 
| +        // excessive channels.
 | 
|          discreteSumFrom(sourceBus);
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void AudioBus::speakersSumFrom5_1_ToMono(const AudioBus& sourceBus)
 | 
| +void AudioBus::sumFromByDownMixing(const AudioBus& sourceBus)
 | 
|  {
 | 
| -    AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
 | 
| -
 | 
| -    const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
 | 
| -    const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data();
 | 
| -    const float* sourceC = sourceBusSafe.channelByType(ChannelCenter)->data();
 | 
| -    const float* sourceSL = sourceBusSafe.channelByType(ChannelSurroundLeft)->data();
 | 
| -    const float* sourceSR = sourceBusSafe.channelByType(ChannelSurroundRight)->data();
 | 
| -
 | 
| -    float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| -
 | 
| -    AudioFloatArray temp(length());
 | 
| -    float* tempData = temp.data();
 | 
| -
 | 
| -    // Sum in L and R.
 | 
| -    vadd(sourceL, 1, sourceR, 1, tempData, 1, length());
 | 
| -    float scale = 0.7071;
 | 
| -    vsmul(tempData, 1, &scale, tempData, 1, length());
 | 
| -    vadd(tempData, 1, destination, 1, destination, 1, length());
 | 
| +    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
| +    unsigned numberOfDestinationChannels = numberOfChannels();
 | 
|  
 | 
| -    // Sum in SL and SR.
 | 
| -    vadd(sourceSL, 1, sourceSR, 1, tempData, 1, length());
 | 
| -    scale = 0.5;
 | 
| -    vsmul(tempData, 1, &scale, tempData, 1, length());
 | 
| -    vadd(tempData, 1, destination, 1, destination, 1, length());
 | 
| +    if (numberOfSourceChannels == 2 && numberOfDestinationChannels == 1) {
 | 
| +        // Down-mixing: 2 -> 1
 | 
| +        //   output = 0.5 * (input.L + input.R)
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
|  
 | 
| -    // Sum in center.
 | 
| -    vadd(sourceC, 1, destination, 1, destination, 1, length());
 | 
| -}
 | 
| +        float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| +        float scale = 0.5;
 | 
|  
 | 
| -void AudioBus::discreteCopyFrom(const AudioBus& sourceBus)
 | 
| -{
 | 
| -    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
| -    unsigned numberOfDestinationChannels = numberOfChannels();
 | 
| +        vsma(sourceL, 1, &scale, destination, 1, length());
 | 
| +        vsma(sourceR, 1, &scale, destination, 1, length());
 | 
| +    } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 1) {
 | 
| +        // Down-mixing: 4 -> 1
 | 
| +        //   output = 0.25 * (input.L + input.R + input.SL + input.SR)
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
| +        const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data();
 | 
| +        const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data();
 | 
|  
 | 
| -    if (numberOfDestinationChannels < numberOfSourceChannels) {
 | 
| -        // Down-mix by copying channels and dropping the remaining.
 | 
| -        for (unsigned i = 0; i < numberOfDestinationChannels; ++i)
 | 
| -            channel(i)->copyFrom(sourceBus.channel(i));
 | 
| -    } else if (numberOfDestinationChannels > numberOfSourceChannels) {
 | 
| -        // Up-mix by copying as many channels as we have, then zeroing remaining channels.
 | 
| -        for (unsigned i = 0; i < numberOfSourceChannels; ++i)
 | 
| -            channel(i)->copyFrom(sourceBus.channel(i));
 | 
| -        for (unsigned i = numberOfSourceChannels; i < numberOfDestinationChannels; ++i)
 | 
| -            channel(i)->zero();
 | 
| -    }
 | 
| -}
 | 
| +        float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| +        float scale = 0.25;
 | 
|  
 | 
| -void AudioBus::discreteSumFrom(const AudioBus& sourceBus)
 | 
| -{
 | 
| -    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
 | 
| -    unsigned numberOfDestinationChannels = numberOfChannels();
 | 
| +        vsma(sourceL, 1, &scale, destination, 1, length());
 | 
| +        vsma(sourceR, 1, &scale, destination, 1, length());
 | 
| +        vsma(sourceSL, 1, &scale, destination, 1, length());
 | 
| +        vsma(sourceSR, 1, &scale, destination, 1, length());
 | 
| +    } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 1) {
 | 
| +        // Down-mixing: 5.1 -> 1
 | 
| +        //   output = sqrt(1/2) * (input.L + input.R) + input.C
 | 
| +        //            + 0.5 * (input.SL + input.SR)
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
| +        const float* sourceC = sourceBus.channelByType(ChannelCenter)->data();
 | 
| +        const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data();
 | 
| +        const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data();
 | 
|  
 | 
| -    if (numberOfDestinationChannels < numberOfSourceChannels) {
 | 
| -        // Down-mix by summing channels and dropping the remaining.
 | 
| -        for (unsigned i = 0; i < numberOfDestinationChannels; ++i)
 | 
| -            channel(i)->sumFrom(sourceBus.channel(i));
 | 
| -    } else if (numberOfDestinationChannels > numberOfSourceChannels) {
 | 
| -        // Up-mix by summing as many channels as we have.
 | 
| -        for (unsigned i = 0; i < numberOfSourceChannels; ++i)
 | 
| -            channel(i)->sumFrom(sourceBus.channel(i));
 | 
| +        float* destination = channelByType(ChannelLeft)->mutableData();
 | 
| +        float scaleSqrtHalf = sqrtf(0.5);
 | 
| +        float scaleHalf = 0.5;
 | 
| +
 | 
| +        vsma(sourceL, 1, &scaleSqrtHalf, destination, 1, length());
 | 
| +        vsma(sourceR, 1, &scaleSqrtHalf, destination, 1, length());
 | 
| +        vadd(sourceC, 1, destination, 1, destination, 1, length());
 | 
| +        vsma(sourceSL, 1, &scaleHalf, destination, 1, length());
 | 
| +        vsma(sourceSR, 1, &scaleHalf, destination, 1, length());
 | 
| +    } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 2) {
 | 
| +        // Down-mixing: 4 -> 2
 | 
| +        //   output.L = 0.5 * (input.L + input.SL)
 | 
| +        //   output.R = 0.5 * (input.R + input.SR)
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
| +        const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data();
 | 
| +        const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data();
 | 
| +
 | 
| +        float* destinationL = channelByType(ChannelLeft)->mutableData();
 | 
| +        float* destinationR = channelByType(ChannelRight)->mutableData();
 | 
| +        float scaleHalf = 0.5;
 | 
| +
 | 
| +        vsma(sourceL, 1, &scaleHalf, destinationL, 1, length());
 | 
| +        vsma(sourceSL, 1, &scaleHalf, destinationL, 1, length());
 | 
| +        vsma(sourceR, 1, &scaleHalf, destinationR, 1, length());
 | 
| +        vsma(sourceSR, 1, &scaleHalf, destinationR, 1, length());
 | 
| +    } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 2) {
 | 
| +        // Down-mixing: 5.1 -> 2
 | 
| +        //   output.L = input.L + sqrt(1/2) * (input.C + input.SL)
 | 
| +        //   output.R = input.R + sqrt(1/2) * (input.C + input.SR)
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
| +        const float* sourceC = sourceBus.channelByType(ChannelCenter)->data();
 | 
| +        const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data();
 | 
| +        const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data();
 | 
| +
 | 
| +        float* destinationL = channelByType(ChannelLeft)->mutableData();
 | 
| +        float* destinationR = channelByType(ChannelRight)->mutableData();
 | 
| +        float scaleSqrtHalf = sqrtf(0.5);
 | 
| +
 | 
| +        vadd(sourceL, 1, destinationL, 1, destinationL, 1, length());
 | 
| +        vsma(sourceC, 1, &scaleSqrtHalf, destinationL, 1, length());
 | 
| +        vsma(sourceSL, 1, &scaleSqrtHalf, destinationL, 1, length());
 | 
| +        vadd(sourceR, 1, destinationR, 1, destinationR, 1, length());
 | 
| +        vsma(sourceC, 1, &scaleSqrtHalf, destinationR, 1, length());
 | 
| +        vsma(sourceSR, 1, &scaleSqrtHalf, destinationR, 1, length());
 | 
| +    } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 4) {
 | 
| +        // Down-mixing: 5.1 -> 4
 | 
| +        //   output.L = input.L + sqrt(1/2) * input.C
 | 
| +        //   output.R = input.R + sqrt(1/2) * input.C
 | 
| +        //   output.SL = input.SL
 | 
| +        //   output.SR = input.SR
 | 
| +        const float* sourceL = sourceBus.channelByType(ChannelLeft)->data();
 | 
| +        const float* sourceR = sourceBus.channelByType(ChannelRight)->data();
 | 
| +        const float* sourceC = sourceBus.channelByType(ChannelCenter)->data();
 | 
| +
 | 
| +        float* destinationL = channelByType(ChannelLeft)->mutableData();
 | 
| +        float* destinationR = channelByType(ChannelRight)->mutableData();
 | 
| +        float scaleSqrtHalf = sqrtf(0.5);
 | 
| +
 | 
| +        vadd(sourceL, 1, destinationL, 1, destinationL, 1, length());
 | 
| +        vsma(sourceC, 1, &scaleSqrtHalf, destinationL, 1, length());
 | 
| +        vadd(sourceR, 1, destinationR, 1, destinationR, 1, length());
 | 
| +        vsma(sourceC, 1, &scaleSqrtHalf, destinationR, 1, length());
 | 
| +        channel(2)->sumFrom(sourceBus.channel(4));
 | 
| +        channel(3)->sumFrom(sourceBus.channel(5));
 | 
| +    } else {
 | 
| +        // All other cases, fall back to the discrete sum. This will perform
 | 
| +        // channel-wise sum until the destination channels run out.
 | 
| +        discreteSumFrom(sourceBus);
 | 
|      }
 | 
|  }
 | 
|  
 | 
| 
 |