mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Added cursors in waveform widget
Auto unit string format function
This commit is contained in:
parent
d47f292d3a
commit
90b76f00d9
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
//TODO: Cap Wav viewer position
|
//TODO: Cap Wav viewer position
|
||||||
//TODO: Adapt wav viewer position step
|
//TODO: Adapt wav viewer position step
|
||||||
//TODO: Optimize wav viewer refresh
|
//TODO: Use unit_auto_scale
|
||||||
//TODO: Remove make_bistream from encoders.cpp, too complex, stinks. bitstream_append should be enough.
|
//TODO: Remove make_bistream from encoders.cpp, too complex, stinks. bitstream_append should be enough.
|
||||||
//TODO: Continue work on proc_afskrx_corr, see python script (it works !)
|
//TODO: Continue work on proc_afskrx_corr, see python script (it works !)
|
||||||
//TODO: Super simple text file viewer
|
//TODO: Super simple text file viewer
|
||||||
@ -59,10 +59,7 @@ Continuous (Fox-oring)
|
|||||||
60s transmit, 240s space (Classic 1/5 min)
|
60s transmit, 240s space (Classic 1/5 min)
|
||||||
60s transmit, 360s space (Classic 1/7 min)
|
60s transmit, 360s space (Classic 1/7 min)
|
||||||
*/
|
*/
|
||||||
//TODO: Use TransmitterView in TEDI/LCR, Numbers, ...
|
|
||||||
//TODO: FreqMan: Remove and rename categories
|
//TODO: FreqMan: Remove and rename categories
|
||||||
//TODO: Wav visualizer
|
|
||||||
//TODO: File browser view ?
|
|
||||||
//TODO: Mousejack ?
|
//TODO: Mousejack ?
|
||||||
//TODO: Move frequencykeypad from ui_receiver to ui_widget (used everywhere)
|
//TODO: Move frequencykeypad from ui_receiver to ui_widget (used everywhere)
|
||||||
//TODO: ADS-B draw trajectory + GPS coordinates + scale, and playback
|
//TODO: ADS-B draw trajectory + GPS coordinates + scale, and playback
|
||||||
|
@ -170,3 +170,31 @@ std::string to_string_timestamp(const rtc::RTC& value) {
|
|||||||
to_string_dec_uint(value.minute(), 2, '0') +
|
to_string_dec_uint(value.minute(), 2, '0') +
|
||||||
to_string_dec_uint(value.second(), 2, '0');
|
to_string_dec_uint(value.second(), 2, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision) {
|
||||||
|
const uint32_t powers_of_ten[5] = { 1, 10, 100, 1000, 10000 };
|
||||||
|
std::string string { "" };
|
||||||
|
uint32_t prefix_index = base_nano;
|
||||||
|
double integer_part;
|
||||||
|
double fractional_part;
|
||||||
|
|
||||||
|
precision = std::min((uint32_t)4, precision);
|
||||||
|
|
||||||
|
while (n > 1000) {
|
||||||
|
n /= 1000.0;
|
||||||
|
prefix_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fractional_part = modf(n, &integer_part) * powers_of_ten[precision];
|
||||||
|
if (fractional_part < 0)
|
||||||
|
fractional_part = -fractional_part;
|
||||||
|
|
||||||
|
string = to_string_dec_int(integer_part);
|
||||||
|
if (precision)
|
||||||
|
string += '.' + to_string_dec_uint(fractional_part, precision, '0');
|
||||||
|
|
||||||
|
if (prefix_index != 3)
|
||||||
|
string += unit_prefix[prefix_index];
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
@ -35,6 +35,8 @@ enum TimeFormat {
|
|||||||
HM = 2
|
HM = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char unit_prefix[7] { 'n', 'u', 'm', 0, 'k', 'M', 'G' };
|
||||||
|
|
||||||
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
// TODO: Allow l=0 to not fill/justify? Already using this way in ui_spectrum.hpp...
|
||||||
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
||||||
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = 0);
|
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = 0);
|
||||||
@ -47,4 +49,6 @@ std::string to_string_short_freq(const uint64_t f);
|
|||||||
std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS);
|
std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS);
|
||||||
std::string to_string_timestamp(const rtc::RTC& value);
|
std::string to_string_timestamp(const rtc::RTC& value);
|
||||||
|
|
||||||
|
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision);
|
||||||
|
|
||||||
#endif/*__STRING_FORMAT_H__*/
|
#endif/*__STRING_FORMAT_H__*/
|
||||||
|
@ -128,12 +128,8 @@ void EncodersConfigView::on_show() {
|
|||||||
void EncodersConfigView::draw_waveform() {
|
void EncodersConfigView::draw_waveform() {
|
||||||
size_t length = frame_fragments.length();
|
size_t length = frame_fragments.length();
|
||||||
|
|
||||||
for (size_t n = 0; n < length; n++) {
|
for (size_t n = 0; n < length; n++)
|
||||||
if (frame_fragments[n] == '0')
|
waveform_buffer[n] = (frame_fragments[n] == '0') ? 0 : 1;
|
||||||
waveform_buffer[n] = 0;
|
|
||||||
else
|
|
||||||
waveform_buffer[n] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
waveform.set_length(length);
|
waveform.set_length(length);
|
||||||
waveform.set_dirty();
|
waveform.set_dirty();
|
||||||
|
@ -55,7 +55,7 @@ private:
|
|||||||
//uint8_t scan_count;
|
//uint8_t scan_count;
|
||||||
//double scan_progress;
|
//double scan_progress;
|
||||||
//unsigned int scan_index;
|
//unsigned int scan_index;
|
||||||
int8_t waveform_buffer[512];
|
int16_t waveform_buffer[512];
|
||||||
const encoder_def_t * encoder_def { };
|
const encoder_def_t * encoder_def { };
|
||||||
//uint8_t enc_type = 0;
|
//uint8_t enc_type = 0;
|
||||||
|
|
||||||
|
@ -32,29 +32,34 @@ namespace ui {
|
|||||||
void ViewWavView::update_scale(int32_t new_scale) {
|
void ViewWavView::update_scale(int32_t new_scale) {
|
||||||
scale = new_scale;
|
scale = new_scale;
|
||||||
ns_per_pixel = (1000000000UL / wav_reader->sample_rate()) * scale;
|
ns_per_pixel = (1000000000UL / wav_reader->sample_rate()) * scale;
|
||||||
field_pos_samples.set_step(scale);
|
|
||||||
refresh_waveform();
|
refresh_waveform();
|
||||||
|
refresh_measurements();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWavView::refresh_waveform() {
|
void ViewWavView::refresh_waveform() {
|
||||||
int16_t sample;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 240; i++) {
|
for (size_t i = 0; i < 240; i++) {
|
||||||
wav_reader->data_seek(position + (i * scale));
|
wav_reader->data_seek(position + (i * scale));
|
||||||
wav_reader->read(&sample, 2);
|
wav_reader->read(&waveform_buffer[i], sizeof(int16_t));
|
||||||
|
|
||||||
waveform_buffer[i] = sample >> 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waveform.set_dirty();
|
||||||
|
|
||||||
|
// Window
|
||||||
|
uint64_t w_start = (position * 240) / wav_reader->sample_count();
|
||||||
|
uint64_t w_width = (scale * 240) / (wav_reader->sample_count() / 240);
|
||||||
|
display.fill_rectangle({ 0, 10 * 16 + 1, 240, 16 }, Color::black());
|
||||||
|
display.fill_rectangle({ (Coord)w_start, 21 * 8, (Dim)w_width + 1, 8 }, Color::white());
|
||||||
|
display.draw_line({ 0, 10 * 16 + 1 }, { (Coord)w_start, 21 * 8 }, Color::white());
|
||||||
|
display.draw_line({ 239, 10 * 16 + 1 }, { (Coord)(w_start + w_width), 21 * 8 }, Color::white());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::refresh_measurements() {
|
||||||
uint64_t span_ns = ns_per_pixel * abs(field_cursor_b.value() - field_cursor_a.value());
|
uint64_t span_ns = ns_per_pixel * abs(field_cursor_b.value() - field_cursor_a.value());
|
||||||
|
|
||||||
if (span_ns)
|
if (span_ns)
|
||||||
text_delta.set(to_string_dec_uint(span_ns / 1000) + "us (" + to_string_dec_uint(1000000000UL / span_ns) + "Hz)");
|
text_delta.set(unit_auto_scale(span_ns, 0, 3) + "s (" + to_string_dec_uint(1000000000UL / span_ns) + "Hz)");
|
||||||
else
|
else
|
||||||
text_delta.set("0us ?Hz");
|
text_delta.set("0us ?Hz");
|
||||||
|
|
||||||
//waveform.set_dirty();
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWavView::paint(Painter& painter) {
|
void ViewWavView::paint(Painter& painter) {
|
||||||
@ -62,22 +67,9 @@ void ViewWavView::paint(Painter& painter) {
|
|||||||
painter.draw_hline({ 0, 6 * 16 - 1 }, 240, Color::grey());
|
painter.draw_hline({ 0, 6 * 16 - 1 }, 240, Color::grey());
|
||||||
painter.draw_hline({ 0, 10 * 16 }, 240, Color::grey());
|
painter.draw_hline({ 0, 10 * 16 }, 240, Color::grey());
|
||||||
|
|
||||||
// 0~127 to 0~15 color index
|
// Overall amplitude view, 0~127 to 0~255 color index
|
||||||
for (size_t i = 0; i < 240; i++)
|
for (size_t i = 0; i < 240; i++)
|
||||||
painter.draw_vline({ (Coord)i, 11 * 16 }, 8, amplitude_colors[amplitude_buffer[i] >> 3]);
|
painter.draw_vline({ (Coord)i, 11 * 16 }, 8, spectrum_rgb2_lut[amplitude_buffer[i] << 1]);
|
||||||
|
|
||||||
// Window
|
|
||||||
uint64_t w_start = (position * 240) / wav_reader->sample_count();
|
|
||||||
uint64_t w_width = (scale * 240) / (wav_reader->sample_count() / 240);
|
|
||||||
painter.fill_rectangle({ 0, 10 * 16 + 1, 240, 16 }, Color::black());
|
|
||||||
painter.fill_rectangle({ (Coord)w_start, 21 * 8, (Dim)w_width + 1, 8 }, Color::white());
|
|
||||||
display.draw_line({ 0, 10 * 16 + 1 }, { (Coord)w_start, 21 * 8 }, Color::white());
|
|
||||||
display.draw_line({ 239, 10 * 16 + 1 }, { (Coord)(w_start + w_width), 21 * 8 }, Color::white());
|
|
||||||
|
|
||||||
// Cursors
|
|
||||||
painter.fill_rectangle({ 0, 6 * 16 - 8, 240, 7 }, Color::black());
|
|
||||||
painter.draw_vline({ (Coord)field_cursor_a.value(), 11 * 8 }, 7, Color::cyan());
|
|
||||||
painter.draw_vline({ (Coord)field_cursor_b.value(), 11 * 8 }, 7, Color::magenta());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWavView::on_pos_changed() {
|
void ViewWavView::on_pos_changed() {
|
||||||
@ -101,7 +93,7 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
|||||||
|
|
||||||
text_filename.set(file_path.filename().string());
|
text_filename.set(file_path.filename().string());
|
||||||
auto ms_duration = wav_reader->ms_duration();
|
auto ms_duration = wav_reader->ms_duration();
|
||||||
text_duration.set(to_string_dec_uint(ms_duration / 1000) + "s" + to_string_dec_uint(ms_duration % 1000) + "ms");
|
text_duration.set(unit_auto_scale(ms_duration, 2, 3) + "s");
|
||||||
|
|
||||||
wav_reader->rewind();
|
wav_reader->rewind();
|
||||||
|
|
||||||
@ -117,13 +109,7 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
|||||||
for (size_t s = 0; s < subsampling_factor; s++) {
|
for (size_t s = 0; s < subsampling_factor; s++) {
|
||||||
wav_reader->data_seek(((i * subsampling_factor) + s) * skip);
|
wav_reader->data_seek(((i * subsampling_factor) + s) * skip);
|
||||||
wav_reader->read(&sample, 2);
|
wav_reader->read(&sample, 2);
|
||||||
|
average += (abs(sample) >> 8);
|
||||||
if (sample < 0)
|
|
||||||
sample = -sample;
|
|
||||||
|
|
||||||
sample >>= 8;
|
|
||||||
|
|
||||||
average += sample;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
amplitude_buffer[i] = average / subsampling_factor;
|
amplitude_buffer[i] = average / subsampling_factor;
|
||||||
@ -135,18 +121,10 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
|||||||
|
|
||||||
void ViewWavView::reset_controls() {
|
void ViewWavView::reset_controls() {
|
||||||
field_scale.set_value(1);
|
field_scale.set_value(1);
|
||||||
field_scale.on_change = [this](int32_t value) {
|
|
||||||
update_scale(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
field_pos_seconds.set_value(0);
|
field_pos_seconds.set_value(0);
|
||||||
field_pos_seconds.on_change = [this](int32_t) {
|
|
||||||
on_pos_changed();
|
|
||||||
};
|
|
||||||
field_pos_samples.set_value(0);
|
field_pos_samples.set_value(0);
|
||||||
field_pos_samples.on_change = [this](int32_t) {
|
field_cursor_a.set_value(0);
|
||||||
on_pos_changed();
|
field_cursor_b.set_value(0);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewWavView::ViewWavView(
|
ViewWavView::ViewWavView(
|
||||||
@ -175,19 +153,30 @@ ViewWavView::ViewWavView(
|
|||||||
auto open_view = nav.push<FileLoadView>();
|
auto open_view = nav.push<FileLoadView>();
|
||||||
open_view->on_changed = [this](std::filesystem::path file_path) {
|
open_view->on_changed = [this](std::filesystem::path file_path) {
|
||||||
load_wav(file_path);
|
load_wav(file_path);
|
||||||
|
field_pos_seconds.focus();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
field_scale.on_change = [this](int32_t value) {
|
||||||
|
update_scale(value);
|
||||||
|
};
|
||||||
|
field_pos_seconds.on_change = [this](int32_t) {
|
||||||
|
on_pos_changed();
|
||||||
|
};
|
||||||
|
field_pos_samples.on_change = [this](int32_t) {
|
||||||
|
on_pos_changed();
|
||||||
|
};
|
||||||
|
|
||||||
|
field_cursor_a.on_change = [this](int32_t v) {
|
||||||
|
waveform.set_cursor(0, v);
|
||||||
|
refresh_measurements();
|
||||||
|
};
|
||||||
|
field_cursor_b.on_change = [this](int32_t v) {
|
||||||
|
waveform.set_cursor(1, v);
|
||||||
|
refresh_measurements();
|
||||||
|
};
|
||||||
|
|
||||||
reset_controls();
|
reset_controls();
|
||||||
|
|
||||||
field_cursor_a.set_value(0);
|
|
||||||
field_cursor_a.on_change = [this](int32_t) {
|
|
||||||
refresh_waveform();
|
|
||||||
};
|
|
||||||
field_cursor_b.set_value(0);
|
|
||||||
field_cursor_b.on_change = [this](int32_t) {
|
|
||||||
refresh_waveform();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWavView::focus() {
|
void ViewWavView::focus() {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "io_wave.hpp"
|
#include "io_wave.hpp"
|
||||||
|
#include "spectrum_color_lut.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
@ -41,32 +42,14 @@ private:
|
|||||||
|
|
||||||
void update_scale(int32_t new_scale);
|
void update_scale(int32_t new_scale);
|
||||||
void refresh_waveform();
|
void refresh_waveform();
|
||||||
|
void refresh_measurements();
|
||||||
void on_pos_changed();
|
void on_pos_changed();
|
||||||
void load_wav(std::filesystem::path file_path);
|
void load_wav(std::filesystem::path file_path);
|
||||||
void reset_controls();
|
void reset_controls();
|
||||||
|
|
||||||
const Color amplitude_colors[16] = {
|
|
||||||
{ 0x00, 0x3F, 0xB0 },
|
|
||||||
{ 0x00, 0x6D, 0xB5 },
|
|
||||||
{ 0x00, 0x9C, 0xBA },
|
|
||||||
{ 0x00, 0xBF, 0xB0 },
|
|
||||||
{ 0x00, 0xC5, 0x86 },
|
|
||||||
{ 0x00, 0xCA, 0x5A },
|
|
||||||
{ 0x00, 0xCF, 0x2A },
|
|
||||||
{ 0x06, 0xD4, 0x00 },
|
|
||||||
{ 0x3A, 0xDA, 0x00 },
|
|
||||||
{ 0x71, 0xDF, 0x00 },
|
|
||||||
{ 0xAA, 0xE4, 0x00 },
|
|
||||||
{ 0xE6, 0xE9, 0x00 },
|
|
||||||
{ 0xEF, 0xB9, 0x00 },
|
|
||||||
{ 0xF4, 0x83, 0x00 },
|
|
||||||
{ 0xF9, 0x4B, 0x00 },
|
|
||||||
{ 0xFF, 0x0F, 0x00 }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<WAVFileReader> wav_reader { };
|
std::unique_ptr<WAVFileReader> wav_reader { };
|
||||||
|
|
||||||
int8_t waveform_buffer[240] { };
|
int16_t waveform_buffer[240] { };
|
||||||
uint8_t amplitude_buffer[240] { };
|
uint8_t amplitude_buffer[240] { };
|
||||||
int32_t scale { 1 };
|
int32_t scale { 1 };
|
||||||
uint64_t ns_per_pixel { };
|
uint64_t ns_per_pixel { };
|
||||||
|
Loading…
Reference in New Issue
Block a user