#include <sstream>
#include <stdint.h>
#include <unistd.h>
+#include <vector>
#include <audio_utils/clock.h>
+#include <audio_utils/LogPlot.h>
#include <audio_utils/power.h>
#include <audio_utils/PowerLog.h>
if (nonzeros == 0) {
ss << prefix << "Signal power history: (none)\n";
} else {
+ // First value is power, second value is whether value is start of
+ // a new time stamp.
+ std::vector<std::pair<float, bool>> plotEntries;
ss << prefix << "Signal power history:\n";
size_t column = 0;
if (energy == 0.f) {
if (!first) {
ss << " ] sum(" << audio_utils_power_from_energy(cumulative) << ")";
+ // Add an entry to denote the start of a new time stamp series.
+ if (!plotEntries.empty()) {
+ // First value should be between min and max of all graph entries
+ // so that it doesn't mess with y-axis scaling.
+ plotEntries.emplace_back(plotEntries.back().first, true);
+ }
}
cumulative = 0.f;
column = 0;
audio_utils_power_from_energy(energy / (mChannelCount * mFramesPerEntry));
ss << std::setw(6) << power;
ALOGV("state: %d %lld %f", state, (long long)time, power);
+ // Add an entry to the ASCII art power log graph.
+ // false indicates the value doesn't have a new series time stamp.
+ plotEntries.emplace_back(power, false);
}
+ ss << "\n" << audio_utils_log_plot(plotEntries.begin(), plotEntries.end());
ss << "\n";
}
return ss.str();
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_PLOT_H
+#define LOG_PLOT_H
+
+#include <algorithm>
+#include <cmath>
+#include <iomanip> // setw
+#include <iostream>
+#include <sstream>
+#include <string>
+
+// TODO Make a class called LogPlot and put this functionality in it.
+/**
+ * \brief Creates a std::string graph representation of equally-spaced time-series data points.
+ *
+ * \param first RandomAccessIterator iterator to initial position of sequence.
+ * Iterator shall point to a pair<float, bool>, where the float is the data value
+ * and the bool is whether the data value is the start of a new data point in time
+ * (i.e. a break in time continuity).
+ * \param last RandomAccessIterator iterator to final position of sequence.
+ * \return the std::string of the graph.
+ *
+ */
+template <class RandomAccessIterator>
+std::string audio_utils_log_plot(RandomAccessIterator first, RandomAccessIterator last)
+{
+ using T = decltype((*first).first);
+
+ constexpr int HEIGHT = 14; // Character height of the plot
+ // Leave 20% display space before min and after max data points
+ constexpr float RANGE_BUFFER_ROOM = 0.2f;
+ // Minimum range of lowest and highest y-axis value to display
+ constexpr int RANGE_MIN = 14;
+ constexpr unsigned int WIDTH_MAX = 200U; // Max character width of plot
+ const size_t size = last - first;
+
+ if (size <= 0) {
+ return "";
+ }
+
+ // Find min and max element in the vector.
+ const auto result = std::minmax_element(first, last);
+ const T minVal = (*result.first).first;
+ const T maxVal = (*result.second).first;
+
+ const T range = maxVal - minVal;
+ T graphMin, graphMax;
+ if (range < RANGE_MIN) {
+ T avg = (maxVal + minVal) / 2;
+ graphMin = avg - RANGE_MIN / 2;
+ graphMax = avg + RANGE_MIN / 2;
+ } else {
+ graphMin = minVal - range * RANGE_BUFFER_ROOM;
+ graphMax = maxVal + range * RANGE_BUFFER_ROOM;
+ }
+
+ // Value of one character height increase on the graph
+ const T increment = (graphMax - graphMin) / HEIGHT;
+ // Something went wrong if we reached this statement..
+ if (increment <= 0.0f) {
+ return "";
+ }
+
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(1);
+
+ // Start storing the graph into string.
+ // TODO store everything into a preallocated string rather than use stringstream.
+ // This may make the code easier to maintain.
+ ss << "\n";
+ for (int height = HEIGHT - 1; height >= 0; height--) {
+ int spaces = 1; // Amount of spaces before the data point
+ ss << std::setw(9) << graphMin + increment * height;
+ ss << std::setw(3) << "-|";
+ auto it = size <= WIDTH_MAX ? first : first + size - WIDTH_MAX;
+ for (; it < last; ++it) {
+ const T power = it->first;
+ const bool start = it->second;
+ // TODO explicitly do type conversion for parameter passed to round()?
+ int px = (int)round((power - graphMin) / increment);
+ // The it != last - 1 is a temporary workaround to prevent vertical bar
+ // separators after the last data point entry.
+ if ((start || px == height) && it != last - 1) {
+ ss << std::setw(spaces) << (start ? "|" : "*");
+ spaces = 1;
+ } else {
+ spaces++;
+ }
+ }
+ ss << "\n";
+ }
+ ss << std::setw(12) << "|";
+ ss << std::string(std::min(size - (size_t)1, (size_t)WIDTH_MAX), '_') << "\n\n";
+
+ return ss.str();
+}
+
+#endif // !LOG_PLOT_H
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <vector>
+
+// FIXME couldn't get <audio_utils/LogPlot.h> to work yet.
+#include "LogPlot.h"
+
+// TODO Make more rigorous unit tests.
+int main(int argc, char **argv)
+{
+ static const float data[] = {-61.4, -61.7, -56.2, -54.5, -47.7, -51.1, -49.7, -47.2,
+ -47.8, -42.3, -38.9, -40.5, -39.4, -33.9, -26.3, -20.9};
+ size_t data_size = sizeof(data) / sizeof(*data);
+ std::vector<std::pair<float, bool>> vdata;
+ for (int i = 0; i < data_size; i++) {
+ vdata.push_back(std::make_pair(data[i], (i + 1) % 10 == 0));
+ }
+
+ std::string graphstr = audio_utils_log_plot(vdata.begin(), vdata.end());
+ std::cout << graphstr << std::endl;
+
+ return EXIT_SUCCESS;
+}