|  | // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // Refer to the accompanying README.md file for detailed API documentation | 
|  | // (functions, structs and constants). | 
|  |  | 
|  | #ifndef EXAMPLES_MEDIA_AUDIO_EFFECTS_DFX_RECHANNEL_H_ | 
|  | #define EXAMPLES_MEDIA_AUDIO_EFFECTS_DFX_RECHANNEL_H_ | 
|  |  | 
|  | #include <lib/media/audio_dfx/cpp/audio_device_fx.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "examples/media/audio/effects/dfx_base.h" | 
|  |  | 
|  | namespace media::audio_dfx_test { | 
|  |  | 
|  | // DfxRechannel: an example of non-in-place effect with no controls. Being non- | 
|  | // inplace, it has channel restrictions: specifically it must take in six | 
|  | // channels and produce two channels. It does so while adding no latency. | 
|  | class DfxRechannel : public DfxBase { | 
|  | public: | 
|  | static constexpr uint16_t kNumControls = 0; | 
|  | static constexpr uint16_t kNumChannelsIn = 6; | 
|  | static constexpr uint16_t kNumChannelsOut = 2; | 
|  | static constexpr uint32_t kLatencyFrames = 0; | 
|  |  | 
|  | static bool GetInfo(fuchsia_audio_dfx_description* dfx_desc) { | 
|  | std::strcpy(dfx_desc->name, "5.1 to Stereo"); | 
|  | dfx_desc->num_controls = kNumControls; | 
|  | dfx_desc->incoming_channels = kNumChannelsIn; | 
|  | dfx_desc->outgoing_channels = kNumChannelsOut; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool GetControlInfo(uint16_t, fuchsia_audio_dfx_control_description*) { return false; } | 
|  |  | 
|  | static DfxRechannel* Create(uint32_t frame_rate, uint16_t channels_in, uint16_t channels_out) { | 
|  | return (channels_in == kNumChannelsIn && channels_out == kNumChannelsOut | 
|  | ? new DfxRechannel(frame_rate) | 
|  | : nullptr); | 
|  | } | 
|  |  | 
|  | DfxRechannel(uint32_t frame_rate) | 
|  | : DfxBase(Effect::Rechannel, kNumControls, frame_rate, kNumChannelsIn, kNumChannelsOut, | 
|  | kLatencyFrames, kLatencyFrames) {} | 
|  |  | 
|  | // Effect converts a 5.1 mix into stereo. | 
|  | // Left  = FL + FC*sqr(.5) + BL  -and-  Right = FR + FC*sqr(.5) + BR | 
|  | // To normalize: div by (1+.7071+1) or *= .36939806251812928 | 
|  | // Note: LFE is omitted (common practice in stereo downmixes). | 
|  | // Or, with dpl encoding: | 
|  | // Left  = FL + FC*sqr(.5) + BL*sqr(.75) + BR*sqr(.25) | 
|  | // Right = FR + FC*sqr(.5) - BL*sqr(.25) - BR*sqr(.75) | 
|  | // To normalize: div by (1+.7071+.8660+.5) or *= .32540090689572506 | 
|  | bool Process(uint32_t num_frames, const float* buff_in, float* buff_out) { | 
|  | for (uint32_t frame = 0; frame < num_frames; ++frame) { | 
|  | uint32_t out = frame * channels_out_; | 
|  | uint32_t in = frame * channels_in_; | 
|  | if (!encode_) { | 
|  | buff_out[out] = | 
|  | (buff_in[in] + (0.707106781f * buff_in[in + 2]) + buff_in[in + 4]) * 0.369398062f; | 
|  | buff_out[out + 1] = | 
|  | (buff_in[in + 1] + (0.707106781f * buff_in[in + 2]) + buff_in[in + 5]) * 0.369398062f; | 
|  | } else { | 
|  | buff_out[out] = (buff_in[in] + (0.707106781f * buff_in[in + 2]) + | 
|  | (0.866025403f * buff_in[in + 4]) + (0.5f * buff_in[in + 5])) * | 
|  | 0.325400906f; | 
|  | buff_out[out + 1] = (buff_in[in + 1] + (0.707106781f * buff_in[in + 2]) - | 
|  | (0.5f * buff_in[in + 4]) - (0.866025403f * buff_in[in + 5])) * | 
|  | 0.325400906f; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | bool encode_ = false; | 
|  | }; | 
|  |  | 
|  | }  // namespace media::audio_dfx_test | 
|  |  | 
|  | #endif  // EXAMPLES_MEDIA_AUDIO_EFFECTS_DFX_RECHANNEL_H_ |