mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-25 15:37:49 +00:00
Added an audio FFT view in Wideband FM receive
Tried speeding up fill_rectangle for clearing the waveform widget
This commit is contained in:
@@ -100,25 +100,26 @@ void fft_swap_in_place(std::array<T, N>& data) {
|
||||
/* http://www.drdobbs.com/cpp/a-simple-and-efficient-fft-implementatio/199500857?pgno=3 */
|
||||
|
||||
template<typename T, size_t N>
|
||||
void fft_c_preswapped(std::array<T, N>& data) {
|
||||
void fft_c_preswapped(std::array<T, N>& data, const size_t from, const size_t to) {
|
||||
static_assert(power_of_two(N), "only defined for N == power of two");
|
||||
constexpr auto K = log_2(N);
|
||||
if ((to > K) || (from > K)) return;
|
||||
|
||||
constexpr size_t K_max = 8;
|
||||
static_assert(K <= K_max, "No FFT twiddle factors for K > 8");
|
||||
static constexpr std::array<std::complex<float>, K_max> wp_table { {
|
||||
{ -2.0f, 0.0f },
|
||||
{ -1.0f, -1.0f },
|
||||
{ -0.2928932188134524756f, -0.7071067811865475244f },
|
||||
{ -0.076120467488713243872f, -0.38268343236508977173f },
|
||||
{ -0.019214719596769550874f, -0.19509032201612826785f },
|
||||
{ -0.0048152733278031137552f, -0.098017140329560601994f },
|
||||
{ -0.0012045437948276072852f, -0.049067674327418014255f },
|
||||
{ -0.00030118130379577988423f, -0.024541228522912288032f },
|
||||
{ -2.0f, 0.0f }, // 2
|
||||
{ -1.0f, -1.0f }, // 4
|
||||
{ -0.2928932188134524756f, -0.7071067811865475244f }, // 8
|
||||
{ -0.076120467488713243872f, -0.38268343236508977173f }, // 16
|
||||
{ -0.019214719596769550874f, -0.19509032201612826785f }, // 32
|
||||
{ -0.0048152733278031137552f, -0.098017140329560601994f }, // 64
|
||||
{ -0.0012045437948276072852f, -0.049067674327418014255f }, // 128
|
||||
{ -0.00030118130379577988423f, -0.024541228522912288032f }, // 256
|
||||
} };
|
||||
|
||||
/* Provide data to this function, pre-swapped. */
|
||||
for(size_t k = 0; k < log_2(N); k++) {
|
||||
for(size_t k = from; k < to; k++) {
|
||||
const size_t mmax = 1 << k;
|
||||
const auto wp = wp_table[k];
|
||||
T w { 1.0f, 0.0f };
|
||||
|
@@ -297,6 +297,15 @@ void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) {
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9341::fill_rectangle_unrolled8(ui::Rect r, const ui::Color c) {
|
||||
const auto r_clipped = r.intersect(screen_rect());
|
||||
if( !r_clipped.is_empty() ) {
|
||||
lcd_start_ram_write(r_clipped);
|
||||
size_t count = r_clipped.width() * r_clipped.height();
|
||||
io.lcd_write_pixels_unrolled8(c, count);
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9341::render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer) {
|
||||
lcd_start_ram_write(p, { count, 1 });
|
||||
io.lcd_write_pixels(line_buffer, count);
|
||||
|
@@ -49,6 +49,7 @@ public:
|
||||
void wake();
|
||||
|
||||
void fill_rectangle(ui::Rect r, const ui::Color c);
|
||||
void fill_rectangle_unrolled8(ui::Rect r, const ui::Color c);
|
||||
void draw_line(const ui::Point start, const ui::Point end, const ui::Color color);
|
||||
void fill_circle(
|
||||
const ui::Point center,
|
||||
|
@@ -106,6 +106,7 @@ public:
|
||||
|
||||
AudioLevelReport = 51,
|
||||
CodedSquelch = 52,
|
||||
AudioSpectrumConfig = 53,
|
||||
MAX
|
||||
};
|
||||
|
||||
@@ -273,6 +274,27 @@ public:
|
||||
size_t trigger { 0 };
|
||||
};
|
||||
|
||||
struct AudioSpectrum {
|
||||
std::array<uint8_t, 128> db { { 0 } };
|
||||
//uint32_t sampling_rate { 0 };
|
||||
};
|
||||
|
||||
using AudioSpectrumFIFO = FIFO<AudioSpectrum>;
|
||||
|
||||
class AudioSpectrumConfigMessage : public Message {
|
||||
public:
|
||||
static constexpr size_t fifo_k = 2;
|
||||
|
||||
constexpr AudioSpectrumConfigMessage(
|
||||
AudioSpectrumFIFO* fifo
|
||||
) : Message { ID::AudioSpectrumConfig },
|
||||
fifo { fifo }
|
||||
{
|
||||
}
|
||||
|
||||
AudioSpectrumFIFO* fifo { nullptr };
|
||||
};
|
||||
|
||||
struct ChannelSpectrum {
|
||||
std::array<uint8_t, 256> db { { 0 } };
|
||||
uint32_t sampling_rate { 0 };
|
||||
|
@@ -158,6 +158,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_write_pixels_unrolled8(const ui::Color pixel, size_t n) {
|
||||
auto v = pixel.v;
|
||||
n >>= 3;
|
||||
while(n--) {
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
lcd_write_data(v);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_write_pixels(const ui::Color* const pixels, size_t n) {
|
||||
for(size_t i=0; i<n; i++) {
|
||||
lcd_write_pixel(pixels[i]);
|
||||
|
@@ -98,6 +98,10 @@ void Painter::fill_rectangle(const Rect r, const Color c) {
|
||||
display.fill_rectangle(r, c);
|
||||
}
|
||||
|
||||
void Painter::fill_rectangle_unrolled8(const Rect r, const Color c) {
|
||||
display.fill_rectangle_unrolled8(r, c);
|
||||
}
|
||||
|
||||
void Painter::paint_widget_tree(Widget* const w) {
|
||||
if( ui::is_dirty() ) {
|
||||
paint_widget(w);
|
||||
|
@@ -56,6 +56,7 @@ public:
|
||||
|
||||
void draw_rectangle(const Rect r, const Color c);
|
||||
void fill_rectangle(const Rect r, const Color c);
|
||||
void fill_rectangle_unrolled8(const Rect r, const Color c);
|
||||
|
||||
void paint_widget_tree(Widget* const w);
|
||||
|
||||
|
@@ -1493,6 +1493,7 @@ Waveform::Waveform(
|
||||
color_ { color }
|
||||
{
|
||||
//set_focusable(false);
|
||||
//previous_data.resize(length_, 0);
|
||||
}
|
||||
|
||||
void Waveform::set_cursor(const uint32_t i, const int16_t position) {
|
||||
@@ -1522,19 +1523,31 @@ void Waveform::set_length(const uint32_t new_length) {
|
||||
void Waveform::paint(Painter& painter) {
|
||||
size_t n;
|
||||
Coord y, y_offset = screen_rect().location().y();
|
||||
Coord prev_x = screen_rect().location().x(), prev_y;
|
||||
Coord prev_x, prev_y;
|
||||
float x, x_inc;
|
||||
Dim h = screen_rect().size().height();
|
||||
const float y_scale = (float)(h - 1) / 65536.0;
|
||||
int16_t * data_start = data_ + offset_;
|
||||
|
||||
// Clear
|
||||
painter.fill_rectangle(screen_rect(), Color::black());
|
||||
|
||||
if (!length_) return;
|
||||
|
||||
x_inc = (float)screen_rect().size().width() / length_;
|
||||
|
||||
// Clear
|
||||
painter.fill_rectangle_unrolled8(screen_rect(), Color::black());
|
||||
/*prev_x = screen_rect().location().x();
|
||||
prev_y = previous_data[0];
|
||||
x = prev_x + x_inc;
|
||||
for (n = 1; n < length_; n++) {
|
||||
y = previous_data[n];
|
||||
display.draw_line( {prev_x, prev_y}, {(Coord)x, y}, Color::black());
|
||||
|
||||
prev_x = x;
|
||||
prev_y = y;
|
||||
x += x_inc;
|
||||
}*/
|
||||
prev_x = screen_rect().location().x();
|
||||
|
||||
if (digital_) {
|
||||
// Digital waveform: each value is an horizontal line
|
||||
x = 0;
|
||||
@@ -1557,8 +1570,10 @@ void Waveform::paint(Painter& painter) {
|
||||
x = prev_x + x_inc;
|
||||
h /= 2;
|
||||
prev_y = y_offset + h - (*(data_start++) * y_scale);
|
||||
//previous_data[0] = prev_y;
|
||||
for (n = 1; n < length_; n++) {
|
||||
y = y_offset + h - (*(data_start++) * y_scale);
|
||||
//previous_data[n] = y;
|
||||
display.draw_line( {prev_x, prev_y}, {(Coord)x, y}, color_);
|
||||
|
||||
prev_x = x;
|
||||
|
@@ -617,6 +617,7 @@ private:
|
||||
const Color cursor_colors[2] = { Color::cyan(), Color::magenta() };
|
||||
|
||||
int16_t * data_;
|
||||
//std::vector<int16_t> previous_data { };
|
||||
uint32_t length_;
|
||||
uint32_t offset_;
|
||||
bool digital_ { false };
|
||||
|
Reference in New Issue
Block a user