#include #include #include #include #include #include "audio_effect_helper.h" #define MAX_AUDIO_VAULE 0xffff // unsigned 16bit pcm audio max value BarHelper::BarHelper() { m_datafmt.sample_fmt = 16; m_datafmt.channel = 1; QLinearGradient gradient(QPointF(50, 200), QPointF(50, 0)); gradient.setColorAt(0.0, Qt::white); gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39)); m_background = QBrush(QColor(64, 32, 64)); m_brush = QBrush(gradient); m_pen = QPen(Qt::green, 2); // QPen(Qt::black); m_textPen = QPen(Qt::white); m_textFont.setPixelSize(50); } void BarHelper::draw_data_bar(QPainter* painter, std::vector& data, int n, int w, int h, int h_inter) { assert(data.size() == n); auto w_step = (w - (n - 1) * h_inter) * 1.0 / n; for (int i = 0; i < n; ++i) { auto top = data[i]; // rand() % height; QRectF rt(i * (w_step + h_inter), h - top, w_step, top); painter->drawRect(rt); } } void BarHelper::draw_data_line(QPainter* painter, std::vector& data, int n, int w, int h, int h_inter) { painter->setPen(m_pen); auto w_step = (w - (n - 1) * h_inter) * 1.0 / n; for (size_t i = 0; i < n - 1; ++i) { qreal x1 = i * (w_step + h_inter); qreal y1 = h - data[i]; qreal x2 = x1 + (w_step + h_inter); qreal y2 = h - data[i + 1]; // painter->drawRect(rt); QLine line = QLine(QPoint(x1, y1), QPoint(x2, y2)); painter->drawLine(line); } } void BarHelper::draw_data_arc(QPainter* painter, std::vector& data, int n, int w, int h) { assert(data.size() == n); const qreal s_radius = 50.0; QPointF center(w * 1.0 / 2, h * 1.0 / 2); painter->translate(center); painter->setBrush(QBrush(Qt::red)); const int spanAngle = 360 / n * 16; for (int i = 0; i < n; ++i) { qreal radius = data[i] + s_radius; QRect bounds(-radius, -radius, 2 * radius, 2 * radius); int startAngle = 360 * i / n * 16; painter->drawArc(bounds, startAngle, spanAngle); } } void BarHelper::draw_data_polygon(QPainter* painter, std::vector& data, int n, int w, int h, int r_offset) { assert(data.size() == n); QPointF center(w * 1.0 / 2, h * 1.0 / 2); painter->translate(center); const int pt_size = 4; const int inter_a = 0; const qreal s_radius = r_offset; QPointF points[pt_size] = {}; for (int i = 0; i < n; ++i) { qreal radius = data[i] + s_radius; float startAngle = 360 * i / n; float stopAngle = 360 * (i + 1) / n - inter_a; float start_d = qDegreesToRadians(startAngle); float stop_d = qDegreesToRadians(stopAngle); points[0] = QPointF(qCos(start_d) * s_radius, qSin(start_d) * s_radius); points[1] = QPointF(qCos(start_d) * radius, qSin(start_d) * radius); points[2] = QPointF(qCos(stop_d) * radius, qSin(stop_d) * radius); points[3] = QPointF(qCos(stop_d) * s_radius, qSin(stop_d) * s_radius); painter->drawPolygon(points, 4); } } void BarHelper::draw_data_style(QPainter* painter, const QRect& rt, const AudioData& data) { int width = rt.width(); int height = rt.height(); int h_inter = 2; assert(data.len <= BUFFER_LEN); std::vector v_data; get_data(data, v_data); if (v_data.size() == 0) return; int n = 128; normal_overzero(v_data); if (m_visualFmt.vType == e_VtSampleing) { data_sample(v_data, n); normal_audio_to_size(v_data, height); } else { data_frequency(v_data, n); } if (m_visualFmt.gType == e_GtBar) { draw_data_bar(painter, v_data, n, width, height, h_inter); } else if (m_visualFmt.gType == e_GtLine) { draw_data_line(painter, v_data, n, width, height, h_inter); } else if (m_visualFmt.gType == e_GtPie) { int r_offset = 30; normal_to_size(v_data, qMin(width / 2 - r_offset, height / 2 - r_offset)); draw_data_polygon(painter, v_data, n, width, height, r_offset); } else { qDebug() << "Not handled yet.\n"; } } void BarHelper::paint(QPainter* painter, QPaintEvent* event, const AudioData& data) { auto rt = event->rect(); painter->fillRect(rt, m_background); // painter->translate(0, -1 * rt.height() / 2); painter->save(); painter->setBrush(m_brush); draw_data_style(painter, rt, data); painter->restore(); } void BarHelper::get_data(const AudioData& data, std::vector& v, bool left) const { v.clear(); // unsigned 16bit const int16_t* p = (int16_t*)data.buffer; uint32_t len = data.len / sizeof(int16_t); int start = left ? 0 : 1; for (uint32_t i = start; i < len; i += 2) v.push_back(*(p + i)); // qDebug() << "data size: " << v.size(); } /* v data samples to num*/ void BarHelper::data_sample_old(std::vector& v, const uint32_t num) { auto size = v.size(); if (num <= 0 || size < num) { v.insert(v.end(), num - size, 0); return; } auto numItems = size / num; if (numItems <= 1) { v.erase(v.begin() + num, v.end()); return; } for (size_t i = 0; i < num; i++) { auto& value = v[i]; value = v[i * numItems]; /*for (int j = 1; j < numItems; j++) { value += v[i * numItems + j]; }*/ } v.erase(v.begin() + num, v.end()); } void BarHelper::data_sample(std::vector& v, const uint32_t num) { auto size = v.size(); if (num <= 0 || size < num) { v.insert(v.end(), num - size, 0); return; } auto numItems = size / num; if (numItems <= 1) { v.erase(v.begin() + num, v.end()); return; } while (v.size() / num >= 2) { binary_data(v); } v.erase(v.begin() + num, v.end()); } void BarHelper::binary_data(std::vector& v) { auto j = 0; for (size_t i = 0; i < v.size(); i += 2) v[j++] = v[i]; v.erase(v.begin() + j, v.end()); } void BarHelper::normal_overzero(std::vector& v) { int min = *std::min_element(v.begin(), v.end()); // int max = *std::max_element(v.begin(), v.end()); // qDebug() << "before size: " << v.size() << ",Max value: " << max << ",Min // value: " << min; if (min < 0) { min *= -1; for (int& x : v) x += min; } } void BarHelper::normal_audio_to_size(std::vector& v, const int size) { if (size <= 0) return; #if 0 static int maxValue = 0xff; int max = *std::max_element(v.begin(), v.end()); if (maxValue < max) maxValue = max; #else int maxValue = MAX_AUDIO_VAULE; #endif for (auto& x : v) { x = (x > maxValue) ? maxValue : x; x = (x * size) / maxValue; } } void BarHelper::normal_to_size(std::vector& v, const int size) { if (size <= 0) return; int maxValue = *std::max_element(v.begin(), v.end()); if (size >= maxValue) return; for (auto& x : v) { x = (x > size) ? size : x; x = (x * size) / maxValue; } } void BarHelper::normal_data(std::vector& v, const int height) { normal_overzero(v); normal_audio_to_size(v, height); } void BarHelper::data_frequency(std::vector& v, const uint32_t num) { auto size = v.size(); if (num <= 0 || size < num) { v.insert(v.end(), num - size, 0); return; } std::vector res(num, 0); #if 0 static uint32_t maxValue = 0xff; int max = *std::max_element(v.begin(), v.end()); if (maxValue < max) maxValue = max; #else int maxValue = MAX_AUDIO_VAULE; #endif const uint16_t step = ceil((maxValue + 1) * 1.0 / num); for (const auto& i : v) { uint32_t index = (i % maxValue) / step; assert(index < num); res[index % num]++; } v = res; }