1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Test FlowGraph 19 */ 20 21 #include <iostream> 22 23 #include <gtest/gtest.h> 24 25 #include "flowgraph/ClipToRange.h" 26 #include "flowgraph/MonoToMultiConverter.h" 27 #include "flowgraph/SourceFloat.h" 28 #include "flowgraph/RampLinear.h" 29 #include "flowgraph/SinkFloat.h" 30 #include "flowgraph/SinkI16.h" 31 #include "flowgraph/SinkI24.h" 32 #include "flowgraph/SourceI16.h" 33 #include "flowgraph/SourceI24.h" 34 35 using namespace flowgraph; 36 37 constexpr int kBytesPerI24Packed = 3; 38 39 TEST(test_flowgraph, module_sinki16) { 40 static const float input[] = {1.0f, 0.5f, -0.25f, -1.0f, 0.0f, 53.9f, -87.2f}; 41 static const int16_t expected[] = {32767, 16384, -8192, -32768, 0, 32767, -32768}; 42 int16_t output[20]; 43 SourceFloat sourceFloat{1}; 44 SinkI16 sinkI16{1}; 45 46 int numInputFrames = sizeof(input) / sizeof(input[0]); 47 sourceFloat.setData(input, numInputFrames); 48 sourceFloat.output.connect(&sinkI16.input); 49 50 int numOutputFrames = sizeof(output) / sizeof(int16_t); 51 int32_t numRead = sinkI16.read(output, numOutputFrames); 52 ASSERT_EQ(numInputFrames, numRead); 53 for (int i = 0; i < numRead; i++) { 54 EXPECT_EQ(expected[i], output[i]); 55 } 56 } 57 58 TEST(test_flowgraph, module_mono_to_stereo) { 59 static const float input[] = {1.0f, 2.0f, 3.0f}; 60 float output[100] = {}; 61 SourceFloat sourceFloat{1}; 62 MonoToMultiConverter monoToStereo{2}; 63 SinkFloat sinkFloat{2}; 64 65 sourceFloat.setData(input, 3); 66 67 sourceFloat.output.connect(&monoToStereo.input); 68 monoToStereo.output.connect(&sinkFloat.input); 69 70 int32_t numRead = sinkFloat.read(output, 8); 71 ASSERT_EQ(3, numRead); 72 EXPECT_EQ(input[0], output[0]); 73 EXPECT_EQ(input[0], output[1]); 74 EXPECT_EQ(input[1], output[2]); 75 EXPECT_EQ(input[1], output[3]); 76 } 77 78 TEST(test_flowgraph, module_ramp_linear) { 79 constexpr int rampSize = 5; 80 constexpr int numOutput = 100; 81 constexpr float value = 1.0f; 82 constexpr float target = 100.0f; 83 float output[numOutput] = {}; 84 RampLinear rampLinear{1}; 85 SinkFloat sinkFloat{1}; 86 87 rampLinear.input.setValue(value); 88 rampLinear.setLengthInFrames(rampSize); 89 rampLinear.setTarget(target); 90 rampLinear.forceCurrent(0.0f); 91 92 rampLinear.output.connect(&sinkFloat.input); 93 94 int32_t numRead = sinkFloat.read(output, numOutput); 95 ASSERT_EQ(numOutput, numRead); 96 constexpr float tolerance = 0.0001f; // arbitrary 97 int i = 0; 98 for (; i < rampSize; i++) { 99 float expected = i * value * target / rampSize; 100 EXPECT_NEAR(expected, output[i], tolerance); 101 } 102 for (; i < numOutput; i++) { 103 float expected = value * target; 104 EXPECT_NEAR(expected, output[i], tolerance); 105 } 106 } 107 108 // It is easiest to represent packed 24-bit data as a byte array. 109 // This test will read from input, convert to float, then write 110 // back to output as bytes. 111 TEST(test_flowgraph, module_packed_24) { 112 static const uint8_t input[] = {0x01, 0x23, 0x45, 113 0x67, 0x89, 0xAB, 114 0xCD, 0xEF, 0x5A}; 115 uint8_t output[99] = {}; 116 SourceI24 sourceI24{1}; 117 SinkI24 sinkI24{1}; 118 119 int numInputFrames = sizeof(input) / kBytesPerI24Packed; 120 sourceI24.setData(input, numInputFrames); 121 sourceI24.output.connect(&sinkI24.input); 122 123 int32_t numRead = sinkI24.read(output, sizeof(output) / kBytesPerI24Packed); 124 ASSERT_EQ(numInputFrames, numRead); 125 for (size_t i = 0; i < sizeof(input); i++) { 126 EXPECT_EQ(input[i], output[i]); 127 } 128 } 129 130 TEST(test_flowgraph, module_clip_to_range) { 131 constexpr float myMin = -2.0f; 132 constexpr float myMax = 1.5f; 133 134 static const float input[] = {-9.7, 0.5f, -0.25, 1.0f, 12.3}; 135 static const float expected[] = {myMin, 0.5f, -0.25, 1.0f, myMax}; 136 float output[100]; 137 SourceFloat sourceFloat{1}; 138 ClipToRange clipper{1}; 139 SinkFloat sinkFloat{1}; 140 141 int numInputFrames = sizeof(input) / sizeof(input[0]); 142 sourceFloat.setData(input, numInputFrames); 143 144 clipper.setMinimum(myMin); 145 clipper.setMaximum(myMax); 146 147 sourceFloat.output.connect(&clipper.input); 148 clipper.output.connect(&sinkFloat.input); 149 150 int numOutputFrames = sizeof(output) / sizeof(output[0]); 151 int32_t numRead = sinkFloat.read(output, numOutputFrames); 152 ASSERT_EQ(numInputFrames, numRead); 153 constexpr float tolerance = 0.000001f; // arbitrary 154 for (int i = 0; i < numRead; i++) { 155 EXPECT_NEAR(expected[i], output[i], tolerance); 156 } 157 } 158