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:
@@ -143,7 +143,7 @@ set(CPPSRC
|
||||
${COMMON}/portapack_persistent_memory.cpp
|
||||
${COMMON}/portapack_shared_memory.cpp
|
||||
${COMMON}/sonde_packet.cpp
|
||||
${COMMON}/test_packet.cpp
|
||||
# ${COMMON}/test_packet.cpp
|
||||
${COMMON}/tpms_packet.cpp
|
||||
${COMMON}/ui.cpp
|
||||
${COMMON}/ui_focus.cpp
|
||||
@@ -239,7 +239,7 @@ set(CPPSRC
|
||||
apps/ui_sonde.cpp
|
||||
apps/ui_soundboard.cpp
|
||||
apps/ui_sstvtx.cpp
|
||||
apps/ui_test.cpp
|
||||
# apps/ui_test.cpp
|
||||
apps/ui_tone_search.cpp
|
||||
apps/ui_touch_calibration.cpp
|
||||
apps/ui_touchtunes.cpp
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -100,10 +101,8 @@ AnalogAudioView::AnalogAudioView(
|
||||
&field_volume,
|
||||
&text_ctcss,
|
||||
&record_view,
|
||||
&waterfall,
|
||||
&waterfall
|
||||
});
|
||||
|
||||
//exit_on_squelch = eos;
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
@@ -177,7 +176,7 @@ void AnalogAudioView::on_hide() {
|
||||
|
||||
void AnalogAudioView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
|
||||
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
waterfall.set_parent_rect(waterfall_rect);
|
||||
}
|
||||
@@ -208,9 +207,9 @@ void AnalogAudioView::remove_options_widget() {
|
||||
remove_child(options_widget.get());
|
||||
options_widget.reset();
|
||||
}
|
||||
|
||||
|
||||
text_ctcss.hidden(true);
|
||||
|
||||
|
||||
field_lna.set_style(nullptr);
|
||||
options_modulation.set_style(nullptr);
|
||||
field_frequency.set_style(nullptr);
|
||||
@@ -258,12 +257,23 @@ void AnalogAudioView::on_show_options_modulation() {
|
||||
switch(modulation) {
|
||||
case ReceiverModel::Mode::AMAudio:
|
||||
widget = std::make_unique<AMOptionsView>(options_view_rect, &style_options_group);
|
||||
waterfall.set_fft_widget(false);
|
||||
break;
|
||||
|
||||
case ReceiverModel::Mode::NarrowbandFMAudio:
|
||||
widget = std::make_unique<NBFMOptionsView>(nbfm_view_rect, &style_options_group);
|
||||
waterfall.set_fft_widget(false);
|
||||
break;
|
||||
|
||||
|
||||
case ReceiverModel::Mode::WidebandFMAudio:
|
||||
waterfall.set_fft_widget(true);
|
||||
waterfall.on_show();
|
||||
break;
|
||||
|
||||
case ReceiverModel::Mode::SpectrumAnalysis:
|
||||
waterfall.set_fft_widget(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -341,6 +351,7 @@ void AnalogAudioView::handle_coded_squelch(const uint32_t value) {
|
||||
size_t min_idx { 0 };
|
||||
size_t c;
|
||||
|
||||
// Find nearest match
|
||||
for (c = 0; c < tone_keys.size(); c++) {
|
||||
diff = abs(((float)value / 100.0) - tone_keys[c].second);
|
||||
if (diff < min_diff) {
|
||||
@@ -349,6 +360,7 @@ void AnalogAudioView::handle_coded_squelch(const uint32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary confidence threshold
|
||||
if (min_diff < 40)
|
||||
text_ctcss.set("CTCSS " + tone_keys[min_idx].first);
|
||||
else
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@@ -27,6 +27,10 @@
|
||||
// Check what ends up in the BSS section by looking at the map files !
|
||||
// Use constexpr where possible or make sure const are in .cpp files, not headers !
|
||||
|
||||
// Note about messages:
|
||||
// There can only be one message handler for one kind of message at once
|
||||
// If an attempt is made to register a second handler, there's a chDbgPanic
|
||||
|
||||
//TEST: Goertzel tone detect
|
||||
//TEST: Menuview refresh, seems to blink a lot
|
||||
//TEST: Check AFSK transmit end, skips last bits ?
|
||||
@@ -36,7 +40,11 @@
|
||||
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
|
||||
//BUG: SCANNER Multiple slices
|
||||
//GLITCH: The about view scroller sometimes misses lines because of a race condition between the display scrolling and drawing the line
|
||||
//GLITCH: Start of tx using ReplayThread plays a small bit of previous transmission (content of 1 buffer ?)
|
||||
// See fifo.reset_in() ?
|
||||
|
||||
//TODO: DCS decoder
|
||||
//TODO: Make CTCSS display only when squelch is opened
|
||||
//TODO: Make play button larger in Replay
|
||||
//TODO: Put LNA and VGA controls in Soundboard
|
||||
//TODO: Add default headphones volume setting in Audio settings
|
||||
|
@@ -255,7 +255,7 @@ WaterfallWidget::WaterfallWidget(const bool cursor) {
|
||||
|
||||
add_children({
|
||||
&waterfall_view,
|
||||
&frequency_scale,
|
||||
&frequency_scale
|
||||
});
|
||||
}
|
||||
|
||||
@@ -311,16 +311,51 @@ bool WaterfallWidget::on_key(const KeyEvent key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WaterfallWidget::on_audio_spectrum(const AudioSpectrum& spectrum) {
|
||||
if (fft_widget) {
|
||||
for (size_t i = 0; i < spectrum.db.size(); i++)
|
||||
audio_spectrum[i] = ((int16_t)spectrum.db[i] - 127) * 256;
|
||||
fft_widget->set_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallWidget::set_fft_widget(const bool show) {
|
||||
if (fft_widget) {
|
||||
audio_fifo = nullptr;
|
||||
remove_child(fft_widget.get());
|
||||
fft_widget.reset();
|
||||
}
|
||||
|
||||
if (show) {
|
||||
waterfall_view.set_parent_rect(waterfall_reduced_rect);
|
||||
waterfall_view.on_show();
|
||||
fft_widget = std::make_unique<Waveform>(
|
||||
fft_widget_rect,
|
||||
audio_spectrum,
|
||||
128,
|
||||
0,
|
||||
false,
|
||||
Color::white());
|
||||
add_child(fft_widget.get());
|
||||
} else {
|
||||
waterfall_view.set_parent_rect(waterfall_normal_rect);
|
||||
waterfall_view.on_show();
|
||||
}
|
||||
}
|
||||
|
||||
void WaterfallWidget::set_parent_rect(const Rect new_parent_rect) {
|
||||
constexpr Dim scale_height = 20;
|
||||
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
|
||||
waterfall_normal_rect = { 0, scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height};
|
||||
waterfall_reduced_rect = { 0, scale_height, new_parent_rect.width(), new_parent_rect.height() - scale_height - audio_spectrum_height };
|
||||
|
||||
frequency_scale.set_parent_rect({ 0, 0, new_parent_rect.width(), scale_height });
|
||||
waterfall_view.set_parent_rect({
|
||||
0, scale_height,
|
||||
new_parent_rect.width(),
|
||||
new_parent_rect.height() - scale_height
|
||||
});
|
||||
waterfall_view.set_parent_rect(waterfall_normal_rect);
|
||||
waterfall_view.on_show();
|
||||
|
||||
fft_widget_rect = { 0, new_parent_rect.height() - audio_spectrum_height, new_parent_rect.width(), audio_spectrum_height };
|
||||
}
|
||||
|
||||
void WaterfallWidget::paint(Painter& painter) {
|
||||
|
@@ -97,41 +97,67 @@ public:
|
||||
bool on_key(const KeyEvent key) override;
|
||||
|
||||
void set_parent_rect(const Rect new_parent_rect) override;
|
||||
|
||||
void set_fft_widget(const bool show);
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
void on_tick_second();
|
||||
|
||||
static constexpr ui::Dim audio_spectrum_height = 2 * 16;
|
||||
|
||||
WaterfallView waterfall_view { };
|
||||
FrequencyScale frequency_scale { };
|
||||
ChannelSpectrumFIFO* fifo { nullptr };
|
||||
|
||||
ChannelSpectrumFIFO* channel_fifo { nullptr };
|
||||
AudioSpectrumFIFO* audio_fifo { nullptr };
|
||||
|
||||
std::unique_ptr<Widget> fft_widget { };
|
||||
bool _blink { false };
|
||||
int sampling_rate { 0 };
|
||||
int32_t cursor_position { 0 };
|
||||
SignalToken signal_token_tick_second { };
|
||||
int16_t audio_spectrum[128] { 0 };
|
||||
ui::Rect waterfall_normal_rect { };
|
||||
ui::Rect waterfall_reduced_rect { };
|
||||
ui::Rect fft_widget_rect { };
|
||||
|
||||
MessageHandlerRegistration message_handler_spectrum_config {
|
||||
MessageHandlerRegistration message_handler_channel_spectrum_config {
|
||||
Message::ID::ChannelSpectrumConfig,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ChannelSpectrumConfigMessage*>(p);
|
||||
this->fifo = message.fifo;
|
||||
this->channel_fifo = message.fifo;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistration message_handler_audio_spectrum_config {
|
||||
Message::ID::AudioSpectrumConfig,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const AudioSpectrumConfigMessage*>(p);
|
||||
this->audio_fifo = message.fifo;
|
||||
}
|
||||
};
|
||||
MessageHandlerRegistration message_handler_frame_sync {
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
if( this->fifo ) {
|
||||
if( this->channel_fifo ) {
|
||||
ChannelSpectrum channel_spectrum;
|
||||
while( fifo->out(channel_spectrum) ) {
|
||||
while( channel_fifo->out(channel_spectrum) ) {
|
||||
this->on_channel_spectrum(channel_spectrum);
|
||||
}
|
||||
}
|
||||
if( this->audio_fifo ) {
|
||||
AudioSpectrum audio_spectrum;
|
||||
while( audio_fifo->out(audio_spectrum) ) {
|
||||
// Unstack everything until and only use last buffer (should only be one max. ready per frame)
|
||||
}
|
||||
this->on_audio_spectrum(audio_spectrum);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void on_channel_spectrum(const ChannelSpectrum& spectrum);
|
||||
void on_audio_spectrum(const AudioSpectrum& spectrum);
|
||||
};
|
||||
|
||||
} /* namespace spectrum */
|
||||
|
@@ -60,7 +60,7 @@
|
||||
#include "ui_sonde.hpp"
|
||||
#include "ui_soundboard.hpp"
|
||||
#include "ui_sstvtx.hpp"
|
||||
#include "ui_test.hpp"
|
||||
//#include "ui_test.hpp"
|
||||
#include "ui_tone_search.hpp"
|
||||
#include "ui_touchtunes.hpp"
|
||||
#include "ui_view_wav.hpp"
|
||||
|
Reference in New Issue
Block a user