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 
TEST(test_flowgraph,module_sinki16)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 
TEST(test_flowgraph,module_mono_to_stereo)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 
TEST(test_flowgraph,module_ramp_linear)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.
TEST(test_flowgraph,module_packed_24)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 
TEST(test_flowgraph,module_clip_to_range)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