diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index d53e7c796..65b3bdf34 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -191,6 +191,7 @@ set(CPPSRC clock_manager.cpp core_control.cpp database.cpp + gradient.cpp rfm69.cpp event_m0.cpp file_reader.cpp diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index 90deb0f20..9a69df852 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -21,7 +21,6 @@ * Boston, MA 02110-1301, USA. */ -#include "ble_rx_app.hpp" #include "ble_rx_app.hpp" #include "ui_modemsetup.hpp" diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 12e118a38..ec4e949ac 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -419,6 +419,17 @@ void FileManBaseView::reload_current(bool reset_pagination) { refresh_list(); } +void FileManBaseView::copy_waterfall(std::filesystem::path path) { + nav_.push( + "Install", " Use this gradient file\n for all waterfalls?", YESNO, + [this, path](bool choice) { + if (choice) { + delete_file(default_gradient_file); + copy_file(path, default_gradient_file); + } + }); +} + const FileManBaseView::file_assoc_t& FileManBaseView::get_assoc( const fs::path& ext) const { size_t index = 0; @@ -685,7 +696,11 @@ bool FileManagerView::handle_file_open() { auto ext = path.extension(); if (path_iequal(txt_ext, ext)) { - nav_.push(path); + if (path_iequal(current_path, u"/" + waterfalls_dir)) { + copy_waterfall(path); + } else { + nav_.push(path); + } return true; } else if (is_cxx_capture_file(path) || path_iequal(ppl_ext, ext)) { // TODO: Enough memory to push? diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index e044e53ec..3a4e8da07 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -96,6 +96,7 @@ class FileManBaseView : public View { void load_directory_contents(const std::filesystem::path& dir_path); void load_directory_contents_unordered(const std::filesystem::path& dir_path, size_t file_cnt); const file_assoc_t& get_assoc(const std::filesystem::path& ext) const; + void copy_waterfall(std::filesystem::path path); NavigationView& nav_; diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 5e412c420..2603560a7 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -126,7 +126,7 @@ void GlassView::reset_live_view() { } void GlassView::add_spectrum_pixel(uint8_t power) { - spectrum_row[pixel_index] = spectrum_rgb3_lut[power]; // row of colors + spectrum_row[pixel_index] = gradient.lut[power]; // row of colors spectrum_data[pixel_index] = (live_frequency_integrate * spectrum_data[pixel_index] + power) / (live_frequency_integrate + 1); // smoothing pixel_index++; @@ -359,6 +359,10 @@ GlassView::GlassView( : nav_(nav) { baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum); + if (!gradient.load_file(default_gradient_file)) { + gradient.set_default(); + } + add_children({&labels, &field_frequency_min, &field_frequency_max, diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index d02803b9e..42d13164b 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -35,7 +35,7 @@ #include "ui_receiver.hpp" #include "string_format.hpp" #include "analog_audio_app.hpp" -#include "spectrum_color_lut.hpp" +#include "gradient.hpp" namespace ui { @@ -74,6 +74,7 @@ class GlassView : public View { private: NavigationView& nav_; + Gradient gradient{}; RxRadioState radio_state_{ReceiverModel::Mode::SpectrumAnalysis}; // Settings rf::Frequency f_min = 260 * MHZ_DIV; // Default to 315/433 remote range. diff --git a/firmware/application/apps/ui_search.cpp b/firmware/application/apps/ui_search.cpp index 73fb5737f..86e041ac1 100644 --- a/firmware/application/apps/ui_search.cpp +++ b/firmware/application/apps/ui_search.cpp @@ -56,6 +56,10 @@ SearchView::SearchView( : nav_(nav) { baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum); + if (!gradient.load_file(default_gradient_file)) { + gradient.set_default(); + } + add_children({&labels, &field_frequency_min, &field_frequency_max, @@ -290,7 +294,7 @@ void SearchView::on_channel_spectrum(const ChannelSpectrum& spectrum) { power = spectrum.db[bin - 128]; } - add_spectrum_pixel(spectrum_rgb3_lut[power]); + add_spectrum_pixel(gradient.lut[power]); mean_acc += power; if (power > max_power) { diff --git a/firmware/application/apps/ui_search.hpp b/firmware/application/apps/ui_search.hpp index c7663e28a..6d7c3afd1 100644 --- a/firmware/application/apps/ui_search.hpp +++ b/firmware/application/apps/ui_search.hpp @@ -24,7 +24,7 @@ #include "receiver_model.hpp" #include "recent_entries.hpp" #include "radio_state.hpp" -#include "spectrum_color_lut.hpp" +#include "gradient.hpp" #include "ui_receiver.hpp" namespace ui { @@ -88,6 +88,7 @@ class SearchView : public View { private: NavigationView& nav_; + Gradient gradient{}; RxRadioState radio_state_{ 100'000'000 /* frequency */, 2500000 /* bandwidth */, diff --git a/firmware/application/external/gfxeq/ui_gfxeq.cpp b/firmware/application/external/gfxeq/ui_gfxeq.cpp index deba295a1..9a903e461 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.cpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.cpp @@ -112,49 +112,44 @@ void gfxEQView::update_audio_spectrum(const AudioSpectrum& spectrum) { float total_energy = 0; int bin_count = 0; - // Apply standard EQ frequency response curve (inverted V shape) for (int bin = start_bin; bin <= end_bin; bin++) { - float weight = 1.0f; - float normalized_bin = bin / 127.0f; // 0.0 to 1.0 - - // Boosting mid frequencies per standard graphic EQ curve - if (normalized_bin >= 0.2f && normalized_bin <= 0.7f) { - // Create an inverted V shape with peak at 0.45 (middle frequencies) - float distance_from_mid = fabs(normalized_bin - 0.45f); - weight = 2.2f - (distance_from_mid * 2.0f); // Max 2.2x boost at center - } - - // Add extra low-frequency sensitivity - if (bar < 5) { - weight *= (1.8f - (bar * 0.15f)); - } - - total_energy += spectrum.db[bin] * weight; + total_energy += spectrum.db[bin]; bin_count++; } - uint8_t avg_db = bin_count > 0 ? (total_energy / bin_count) : 0; + float avg_db = bin_count > 0 ? (total_energy / bin_count) : 0; - // Scale all bands to reasonable levels - float band_scale = 0.85f; + // Manually boost highs for better visual balance + float treble_boost = 1.0f; + if (bar == 10) + treble_boost = 1.7f; + else if (bar >= 9) + treble_boost = 1.3f; + else if (bar >= 7) + treble_boost = 1.3f; - // Get the height in display units - int target_height = (avg_db * RENDER_HEIGHT * band_scale) / 255; + // Mid emphasis for a V-shape effect + float mid_boost = 1.0f; + if (bar == 4 || bar == 5 || bar == 6) mid_boost = 1.2f; + + float amplified_db = avg_db * treble_boost * mid_boost; + + if (amplified_db > 255) amplified_db = 255; + + float band_scale = 1.0f; + int target_height = (amplified_db * RENDER_HEIGHT * band_scale) / 255; - // Cap maximum height to prevent overshoot if (target_height > RENDER_HEIGHT) { target_height = RENDER_HEIGHT; } - // Apply different speeds for rise and fall - float rise_speed = 0.7f; - float fall_speed = 0.12f; + // Adjusted to look nice to my eyes + float rise_speed = 0.8f; + float fall_speed = 1.0f; if (target_height > bar_heights[bar]) { - // Fast rise response bar_heights[bar] = bar_heights[bar] * (1.0f - rise_speed) + target_height * rise_speed; } else { - // Slow fall response bar_heights[bar] = bar_heights[bar] * (1.0f - fall_speed) + target_height * fall_speed; } } diff --git a/firmware/application/external/gfxeq/ui_gfxeq.hpp b/firmware/application/external/gfxeq/ui_gfxeq.hpp index df2029e29..f2fd0d1fe 100644 --- a/firmware/application/external/gfxeq/ui_gfxeq.hpp +++ b/firmware/application/external/gfxeq/ui_gfxeq.hpp @@ -43,15 +43,26 @@ class gfxEQView : public View { static constexpr int SCREEN_WIDTH = 240; static constexpr int SCREEN_HEIGHT = 320; static constexpr int RENDER_HEIGHT = 288; - static constexpr int NUM_BARS = 14; + static constexpr int NUM_BARS = 11; static constexpr int BAR_SPACING = 2; static constexpr int BAR_WIDTH = (SCREEN_WIDTH - (BAR_SPACING * (NUM_BARS - 1))) / NUM_BARS; static constexpr int HORIZONTAL_OFFSET = 2; static constexpr int SEGMENT_HEIGHT = 10; static constexpr std::array FREQUENCY_BANDS = { - 20, 40, 80, 160, 320, 640, 1000, 1600, 2500, 4000, - 6000, 9000, 12000, 16000, 24000}; + 375, // Bass warmth and low rumble (e.g., deep basslines, kick drum body) + 750, // Upper bass punch (e.g., bass guitar punch, kick drum attack) + 1500, // Lower midrange fullness (e.g., warmth in vocals, guitar body) + 2250, // Midrange clarity (e.g., vocal presence, snare crack) + 3375, // Upper midrange bite (e.g., instrument definition, vocal articulation) + 4875, // Presence and edge (e.g., guitar bite, vocal sibilance start) + 6750, // Lower brilliance (e.g., cymbal shimmer, vocal clarity) + 9375, // Brilliance and air (e.g., hi-hat crispness, breathy vocals) + 13125, // High treble sparkle (e.g., subtle overtones, synth shimmer) + 16875, // Upper treble airiness (e.g., faint harmonics, room ambiance) + 20625, // Top-end sheen (e.g., ultra-high harmonics, noise floor) + 24375 // Extreme treble limit (e.g., inaudible overtones, signal cutoff, static) + }; struct ColorTheme { Color base_color; diff --git a/firmware/application/file_path.cpp b/firmware/application/file_path.cpp index cea226ec3..f95e7b5b1 100644 --- a/firmware/application/file_path.cpp +++ b/firmware/application/file_path.cpp @@ -51,3 +51,4 @@ const std::filesystem::path whipcalc_dir = u"WHIPCALC"; const std::filesystem::path ook_editor_dir = u"OOKFILES"; const std::filesystem::path hopper_dir = u"HOPPER"; const std::filesystem::path subghz_dir = u"SUBGHZ"; +const std::filesystem::path waterfalls_dir = u"WATERFALLS"; diff --git a/firmware/application/file_path.hpp b/firmware/application/file_path.hpp index d260268af..4c64a86a1 100644 --- a/firmware/application/file_path.hpp +++ b/firmware/application/file_path.hpp @@ -53,5 +53,6 @@ extern const std::filesystem::path whipcalc_dir; extern const std::filesystem::path ook_editor_dir; extern const std::filesystem::path hopper_dir; extern const std::filesystem::path subghz_dir; +extern const std::filesystem::path waterfalls_dir; #endif /* __FILE_PATH_H__ */ diff --git a/firmware/application/gradient.cpp b/firmware/application/gradient.cpp new file mode 100644 index 000000000..2ca27e6bb --- /dev/null +++ b/firmware/application/gradient.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2025 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "gradient.hpp" + +#include "convert.hpp" +#include "file_reader.hpp" +namespace fs = std::filesystem; + +const std::filesystem::path default_gradient_file = u"waterfall.txt"; + +Gradient::Gradient() { + prev_index = 0; + prev_r = 0; + prev_g = 0; + prev_b = 0; +} + +void Gradient::set_default() { + step(86, 0, 0, 255); + step(171, 0, 255, 0); + step(255, 255, 0, 0); +} + +bool Gradient::load_file(const std::filesystem::path& file_path) { + File gradient_file; + auto error = gradient_file.open(file_path.string()); + + if (error) + return false; + + auto reader = FileLineReader(gradient_file); + for (const auto& line : reader) { + if (line.length() == 0 || line[0] == '#') + continue; // Empty or comment line. + + auto cols = split_string(line, ','); + + if (cols.size() == 4) { + int16_t index, r, g, b; + + if (!parse_int(cols[0], index) || index < 0 || index > 255) + continue; + + if (!parse_int(cols[1], r) || r < 0 || r > 255) + continue; + + if (!parse_int(cols[2], g) || g < 0 || g > 255) + continue; + + if (!parse_int(cols[3], b) || b < 0 || b > 255) + continue; + + step(index, r, g, b); + } + } + + return true; +} + +void Gradient::step(int16_t index, int16_t r, int16_t g, int16_t b) { + for (int16_t i = prev_index; i <= index; i++) { + float x = (float)(i - prev_index) / (index - prev_index); + float y = 1.0f - x; + + int16_t new_r = prev_r * y + r * x; + int16_t new_g = prev_g * y + g * x; + int16_t new_b = prev_b * y + b * x; + + lut[i] = ui::Color(new_r, new_g, new_b); + } + + prev_index = index; + prev_r = r; + prev_g = g; + prev_b = b; +} diff --git a/firmware/application/gradient.hpp b/firmware/application/gradient.hpp new file mode 100644 index 000000000..d32d58e59 --- /dev/null +++ b/firmware/application/gradient.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 Belousov Oleg + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GRADIENT_H__ +#define __GRADIENT_H__ + +#include "ui.hpp" +#include "file.hpp" + +#include +#include + +extern const std::filesystem::path default_gradient_file; + +class Gradient { + public: + std::array lut{}; + + Gradient(); + + void set_default(); + bool load_file(const std::filesystem::path& file_path); + + private: + int16_t prev_index = 0; + int16_t prev_r = 0; + int16_t prev_g = 0; + int16_t prev_b = 0; + + void step(int16_t index, int16_t r, int16_t g, int16_t b); +}; + +#endif /* __GRADIENT_H__ */ diff --git a/firmware/application/spectrum_color_lut.cpp b/firmware/application/spectrum_color_lut.cpp index a2877542e..832fa9756 100644 --- a/firmware/application/spectrum_color_lut.cpp +++ b/firmware/application/spectrum_color_lut.cpp @@ -280,265 +280,6 @@ const std::array spectrum_rgb2_lut{{ {132, 0, 0}, }}; -const std::array spectrum_rgb3_lut{{ - {0, 0, 0}, - {0, 0, 3}, - {0, 0, 6}, - {0, 0, 9}, - {0, 0, 12}, - {0, 0, 15}, - {0, 0, 18}, - {0, 0, 21}, - {0, 0, 24}, - {0, 0, 27}, - {0, 0, 30}, - {0, 0, 33}, - {0, 0, 36}, - {0, 0, 39}, - {0, 0, 42}, - {0, 0, 45}, - {0, 0, 48}, - {0, 0, 51}, - {0, 0, 54}, - {0, 0, 57}, - {0, 0, 60}, - {0, 0, 63}, - {0, 0, 66}, - {0, 0, 69}, - {0, 0, 72}, - {0, 0, 75}, - {0, 0, 78}, - {0, 0, 81}, - {0, 0, 84}, - {0, 0, 87}, - {0, 0, 90}, - {0, 0, 93}, - {0, 0, 96}, - {0, 0, 99}, - {0, 0, 102}, - {0, 0, 105}, - {0, 0, 108}, - {0, 0, 111}, - {0, 0, 114}, - {0, 0, 117}, - {0, 0, 120}, - {0, 0, 123}, - {0, 0, 126}, - {0, 0, 129}, - {0, 0, 132}, - {0, 0, 135}, - {0, 0, 138}, - {0, 0, 141}, - {0, 0, 144}, - {0, 0, 147}, - {0, 0, 150}, - {0, 0, 153}, - {0, 0, 156}, - {0, 0, 159}, - {0, 0, 162}, - {0, 0, 165}, - {0, 0, 168}, - {0, 0, 171}, - {0, 0, 174}, - {0, 0, 177}, - {0, 0, 180}, - {0, 0, 183}, - {0, 0, 186}, - {0, 0, 189}, - {0, 0, 192}, - {0, 0, 195}, - {0, 0, 198}, - {0, 0, 201}, - {0, 0, 204}, - {0, 0, 207}, - {0, 0, 210}, - {0, 0, 213}, - {0, 0, 216}, - {0, 0, 219}, - {0, 0, 222}, - {0, 0, 225}, - {0, 0, 228}, - {0, 0, 231}, - {0, 0, 234}, - {0, 0, 237}, - {0, 0, 240}, - {0, 0, 243}, - {0, 0, 246}, - {0, 0, 249}, - {0, 0, 252}, - {0, 0, 255}, - {0, 3, 252}, - {0, 6, 249}, - {0, 9, 246}, - {0, 12, 243}, - {0, 15, 240}, - {0, 18, 237}, - {0, 21, 234}, - {0, 24, 231}, - {0, 27, 228}, - {0, 30, 225}, - {0, 33, 222}, - {0, 36, 219}, - {0, 39, 216}, - {0, 42, 213}, - {0, 45, 210}, - {0, 48, 207}, - {0, 51, 204}, - {0, 54, 201}, - {0, 57, 198}, - {0, 60, 195}, - {0, 63, 192}, - {0, 66, 189}, - {0, 69, 186}, - {0, 72, 183}, - {0, 75, 180}, - {0, 78, 177}, - {0, 81, 174}, - {0, 84, 171}, - {0, 87, 168}, - {0, 90, 165}, - {0, 93, 162}, - {0, 96, 159}, - {0, 99, 156}, - {0, 102, 153}, - {0, 105, 150}, - {0, 108, 147}, - {0, 111, 144}, - {0, 114, 141}, - {0, 117, 138}, - {0, 120, 135}, - {0, 123, 132}, - {0, 126, 129}, - {0, 129, 126}, - {0, 132, 123}, - {0, 135, 120}, - {0, 138, 117}, - {0, 141, 114}, - {0, 144, 111}, - {0, 147, 108}, - {0, 150, 105}, - {0, 153, 102}, - {0, 156, 99}, - {0, 159, 96}, - {0, 162, 93}, - {0, 165, 90}, - {0, 168, 87}, - {0, 171, 84}, - {0, 174, 81}, - {0, 177, 78}, - {0, 180, 75}, - {0, 183, 72}, - {0, 186, 69}, - {0, 189, 66}, - {0, 192, 63}, - {0, 195, 60}, - {0, 198, 57}, - {0, 201, 54}, - {0, 204, 51}, - {0, 207, 48}, - {0, 210, 45}, - {0, 213, 42}, - {0, 216, 39}, - {0, 219, 36}, - {0, 222, 33}, - {0, 225, 30}, - {0, 228, 27}, - {0, 231, 24}, - {0, 234, 21}, - {0, 237, 18}, - {0, 240, 15}, - {0, 243, 12}, - {0, 246, 9}, - {0, 249, 6}, - {0, 252, 3}, - {0, 255, 0}, - {3, 252, 0}, - {6, 249, 0}, - {9, 246, 0}, - {12, 243, 0}, - {15, 240, 0}, - {18, 237, 0}, - {21, 234, 0}, - {24, 231, 0}, - {27, 228, 0}, - {30, 225, 0}, - {33, 222, 0}, - {36, 219, 0}, - {39, 216, 0}, - {42, 213, 0}, - {45, 210, 0}, - {48, 207, 0}, - {51, 204, 0}, - {54, 201, 0}, - {57, 198, 0}, - {60, 195, 0}, - {63, 192, 0}, - {66, 189, 0}, - {69, 186, 0}, - {72, 183, 0}, - {75, 180, 0}, - {78, 177, 0}, - {81, 174, 0}, - {84, 171, 0}, - {87, 168, 0}, - {90, 165, 0}, - {93, 162, 0}, - {96, 159, 0}, - {99, 156, 0}, - {102, 153, 0}, - {105, 150, 0}, - {108, 147, 0}, - {111, 144, 0}, - {114, 141, 0}, - {117, 138, 0}, - {120, 135, 0}, - {123, 132, 0}, - {126, 129, 0}, - {129, 126, 0}, - {132, 123, 0}, - {135, 120, 0}, - {138, 117, 0}, - {141, 114, 0}, - {144, 111, 0}, - {147, 108, 0}, - {150, 105, 0}, - {153, 102, 0}, - {156, 99, 0}, - {159, 96, 0}, - {162, 93, 0}, - {165, 90, 0}, - {168, 87, 0}, - {171, 84, 0}, - {174, 81, 0}, - {177, 78, 0}, - {180, 75, 0}, - {183, 72, 0}, - {186, 69, 0}, - {189, 66, 0}, - {192, 63, 0}, - {195, 60, 0}, - {198, 57, 0}, - {201, 54, 0}, - {204, 51, 0}, - {207, 48, 0}, - {210, 45, 0}, - {213, 42, 0}, - {216, 39, 0}, - {219, 36, 0}, - {222, 33, 0}, - {225, 30, 0}, - {228, 27, 0}, - {231, 24, 0}, - {234, 21, 0}, - {237, 18, 0}, - {240, 15, 0}, - {243, 12, 0}, - {246, 9, 0}, - {249, 6, 0}, - {252, 3, 0}, - {255, 0, 0}, -}}; - const std::array spectrum_rgb4_lut{{ {0, 0, 0}, {1, 1, 1}, diff --git a/firmware/application/spectrum_color_lut.hpp b/firmware/application/spectrum_color_lut.hpp index 1516ae3b1..0e748c33d 100644 --- a/firmware/application/spectrum_color_lut.hpp +++ b/firmware/application/spectrum_color_lut.hpp @@ -27,7 +27,6 @@ #include extern const std::array spectrum_rgb2_lut; -extern const std::array spectrum_rgb3_lut; extern const std::array spectrum_rgb4_lut; #endif /*__SPECTRUM_COLOR_LUT_H__*/ diff --git a/firmware/application/ui/ui_spectrum.cpp b/firmware/application/ui/ui_spectrum.cpp index 19e7ae47d..7c6a69286 100644 --- a/firmware/application/ui/ui_spectrum.cpp +++ b/firmware/application/ui/ui_spectrum.cpp @@ -21,8 +21,6 @@ #include "ui_spectrum.hpp" -#include "spectrum_color_lut.hpp" - #include "portapack.hpp" using namespace portapack; @@ -289,12 +287,12 @@ void WaterfallWidget::on_channel_spectrum( std::array pixel_row; for (size_t i = 0; i < 120; i++) { - const auto pixel_color = spectrum_rgb3_lut[spectrum.db[256 - 120 + i]]; + const auto pixel_color = gradient.lut[spectrum.db[256 - 120 + i]]; pixel_row[i] = pixel_color; } for (size_t i = 120; i < 240; i++) { - const auto pixel_color = spectrum_rgb3_lut[spectrum.db[i - 120]]; + const auto pixel_color = gradient.lut[spectrum.db[i - 120]]; pixel_row[i] = pixel_color; } @@ -333,7 +331,6 @@ WaterfallView::WaterfallView(const bool cursor) { if (on_select) on_select(offset); }; - // Add touch event handler for waterfall widget waterfall_widget.on_touch_select = [this](int32_t x) { if (sampling_rate) { // screen x to frequency scale x, NB we need two widgets aligh @@ -341,6 +338,10 @@ WaterfallView::WaterfallView(const bool cursor) { frequency_scale.set_cursor_position(cursor_position); } }; + + if (!waterfall_widget.gradient.load_file(default_gradient_file)) { + waterfall_widget.gradient.set_default(); + } } void WaterfallView::on_show() { diff --git a/firmware/application/ui/ui_spectrum.hpp b/firmware/application/ui/ui_spectrum.hpp index c8be71b74..984ad31e5 100644 --- a/firmware/application/ui/ui_spectrum.hpp +++ b/firmware/application/ui/ui_spectrum.hpp @@ -24,6 +24,7 @@ #include "ui.hpp" #include "ui_widget.hpp" +#include "gradient.hpp" #include "event_m0.hpp" @@ -115,6 +116,8 @@ class WaterfallWidget : public Widget { public: std::function on_touch_select{}; + Gradient gradient{}; + void on_show() override; void on_hide() override; void paint(Painter&) override {} diff --git a/sdcard/WATERFALLS/aurora.txt b/sdcard/WATERFALLS/aurora.txt new file mode 100644 index 000000000..f564ebf8e --- /dev/null +++ b/sdcard/WATERFALLS/aurora.txt @@ -0,0 +1,14 @@ +# 0% black +0,0,0,0 + +# 25% blue +64,0,0,255 + +# 50% magenta +128,255,0,255 + +# 75% green +192,0,255,0 + +# 100% white +255,255,255,255 diff --git a/sdcard/WATERFALLS/default.txt b/sdcard/WATERFALLS/default.txt new file mode 100644 index 000000000..a076dfbf6 --- /dev/null +++ b/sdcard/WATERFALLS/default.txt @@ -0,0 +1,12 @@ +#lines are index,r,g,b +#if index 0 is not set, it's starting at 0,0,0,0 +#all values are ranging from 0 to 255 + +#pure blue +86,0,0,255 + +#bright green +171,0,255,0 + +#pure red +255,255,0,0 diff --git a/sdcard/WATERFALLS/flame.txt b/sdcard/WATERFALLS/flame.txt new file mode 100644 index 000000000..83bdbcc3f --- /dev/null +++ b/sdcard/WATERFALLS/flame.txt @@ -0,0 +1,11 @@ +# 0% black +0,0,0,0 + +# 33% red +84,255,0,0 + +# 66% yellow +168,255,255,0 + +# 100% white +255,255,255,255 diff --git a/sdcard/WATERFALLS/matrix.txt b/sdcard/WATERFALLS/matrix.txt new file mode 100644 index 000000000..726ad89d1 --- /dev/null +++ b/sdcard/WATERFALLS/matrix.txt @@ -0,0 +1,8 @@ +# 0% black +0,0,0,0 + +# 50% green +128,0,255,0 + +# 100% white +255,255,255,255 diff --git a/sdcard/WATERFALLS/sunset.txt b/sdcard/WATERFALLS/sunset.txt new file mode 100644 index 000000000..aeae107d7 --- /dev/null +++ b/sdcard/WATERFALLS/sunset.txt @@ -0,0 +1,14 @@ +# 0% black +0,0,0,0 + +# 25% blue +64,0,0,255 + +# 50% red +128,255,0,0 + +# 75% yellow +192,255,255,0 + +# 100% white +255,255,255,255