mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-15 03:47:42 +00:00
Finally found what was eating all the RAM :D
Re-enabled the tone key selector in Soundboard Soundboard now uses OutputStream, like Replay Constexpr'd a bunch of consts which were going to BSS section Exiting an app now goes back to main menu Cleaned up Message array
This commit is contained in:
@@ -142,7 +142,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
|
||||
std::string alphanum_text = "";
|
||||
|
||||
if (message->packet.flag() != NORMAL)
|
||||
console.writeln("\n\x1B\x0CRX ERROR: " + pocsag::flag_str(message->packet.flag()));
|
||||
console.writeln("\n\x1B\x0CRC ERROR: " + pocsag::flag_str(message->packet.flag()));
|
||||
else {
|
||||
pocsag_decode_batch(message->packet, &pocsag_state);
|
||||
|
||||
|
@@ -161,6 +161,8 @@ void ReplayAppView::stop(const bool do_loop) {
|
||||
radio::disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
|
@@ -62,10 +62,11 @@ void CreditsWidget::on_hide() {
|
||||
void CreditsWidget::new_row(
|
||||
const std::array<Color, 240>& pixel_row
|
||||
) {
|
||||
// Glitch be here (see comment in main.cpp)
|
||||
const auto draw_y = display.scroll(-1);
|
||||
|
||||
display.draw_pixels(
|
||||
{ { 0, draw_y }, { 240, 1 } },
|
||||
{ { 0, draw_y - 1 }, { 240, 1 } },
|
||||
pixel_row
|
||||
);
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@ void EncodersConfigView::on_type_change(size_t index) {
|
||||
symfield_word.set_length(word_length);
|
||||
size_t n = 0, i = 0;
|
||||
while (n < word_length) {
|
||||
symbol_type = encoder_def->word_format.at(i++);
|
||||
symbol_type = encoder_def->word_format[i++];
|
||||
if (symbol_type == 'A') {
|
||||
symfield_word.set_symbol_list(n++, encoder_def->address_symbols);
|
||||
format_string += 'A';
|
||||
|
@@ -51,11 +51,11 @@ void MicTXView::on_tx_progress(const bool done) {
|
||||
}
|
||||
|
||||
void MicTXView::configure_baseband() {
|
||||
baseband::set_audiotx_data(
|
||||
baseband::set_audiotx_config(
|
||||
sampling_rate / 20, // Update vu-meter at 20Hz
|
||||
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
||||
mic_gain,
|
||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
||||
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
|
||||
0.2 // 20% mix
|
||||
);
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
// To prepare samples: for f in ./*.wav; do sox "$f" -r 48000 -c 1 -b8 --norm "conv/$f"; done
|
||||
|
||||
#include "ui_soundboard.hpp"
|
||||
|
||||
#include "lfsr_random.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "tonesets.hpp"
|
||||
@@ -33,6 +32,7 @@ using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
// TODO: Use Sharebrained's PRNG
|
||||
void SoundBoardView::do_random() {
|
||||
uint32_t id;
|
||||
|
||||
@@ -43,45 +43,42 @@ void SoundBoardView::do_random() {
|
||||
|
||||
play_sound(id);
|
||||
|
||||
buttons[id % 18].focus();
|
||||
page = id / 18;
|
||||
buttons[id % 15].focus();
|
||||
page = id / 15;
|
||||
|
||||
refresh_buttons(id);
|
||||
}
|
||||
|
||||
void SoundBoardView::prepare_audio() {
|
||||
bool SoundBoardView::is_active() const {
|
||||
return (bool)replay_thread;
|
||||
}
|
||||
|
||||
void SoundBoardView::stop(const bool do_loop) {
|
||||
if( is_active() )
|
||||
replay_thread.reset();
|
||||
|
||||
if (sample_counter >= sample_duration) {
|
||||
if (tx_mode == NORMAL) {
|
||||
if (!check_loop.value()) {
|
||||
pbar.set_value(0);
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
} else {
|
||||
reader->rewind();
|
||||
sample_counter = 0;
|
||||
}
|
||||
} else {
|
||||
pbar.set_value(0);
|
||||
transmitter_model.disable();
|
||||
if (check_loop.value())
|
||||
do_random();
|
||||
}
|
||||
if (do_loop && check_loop.value()) {
|
||||
play_sound(playing_id);
|
||||
} else {
|
||||
radio::disable();
|
||||
//button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
ready_signal = false;
|
||||
}
|
||||
|
||||
void SoundBoardView::handle_replay_thread_done(const uint32_t return_code) {
|
||||
if (return_code == ReplayThread::END_OF_FILE) {
|
||||
stop(true);
|
||||
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||
stop(false);
|
||||
file_error();
|
||||
}
|
||||
|
||||
pbar.set_value(sample_counter);
|
||||
progressbar.set_value(0);
|
||||
}
|
||||
|
||||
auto bytes_read = reader->read(audio_buffer, 512).value();
|
||||
|
||||
// Unsigned to signed, pretty stupid :/
|
||||
for (size_t n = 0; n < bytes_read; n++)
|
||||
audio_buffer[n] -= 0x80;
|
||||
for (size_t n = bytes_read; n < 512; n++)
|
||||
audio_buffer[n] = 0;
|
||||
|
||||
sample_counter += 512;
|
||||
|
||||
baseband::set_fifo_data(audio_buffer);
|
||||
void SoundBoardView::set_ready() {
|
||||
ready_signal = true;
|
||||
}
|
||||
|
||||
void SoundBoardView::focus() {
|
||||
@@ -95,41 +92,60 @@ void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
transmitter_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
void SoundBoardView::file_error() {
|
||||
nav_.display_modal("Error", "File read error.");
|
||||
}
|
||||
|
||||
void SoundBoardView::play_sound(uint16_t id) {
|
||||
uint32_t tone_key_index;
|
||||
uint32_t divider;
|
||||
uint32_t sample_rate = 0;
|
||||
|
||||
auto reader = std::make_unique<WAVFileReader>();
|
||||
uint32_t tone_key_index = options_tone_key.selected_index();
|
||||
|
||||
stop(false);
|
||||
|
||||
if (sounds[id].size == 0) return;
|
||||
|
||||
if (!reader->open(sounds[id].path)) return;
|
||||
if(!reader->open(sounds[id].path)) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
|
||||
sample_duration = sounds[id].sample_duration;
|
||||
playing_id = id;
|
||||
|
||||
pbar.set_max(sample_duration);
|
||||
pbar.set_value(0);
|
||||
progressbar.set_max(reader->sample_count());
|
||||
sample_rate = reader->sample_rate() * 32;
|
||||
|
||||
sample_counter = 0;
|
||||
if( reader ) {
|
||||
//button_play.set_bitmap(&bitmap_stop);
|
||||
baseband::set_sample_rate(sample_rate);
|
||||
|
||||
replay_thread = std::make_unique<ReplayThread>(
|
||||
std::move(reader),
|
||||
read_size, buffer_count,
|
||||
&ready_signal,
|
||||
[](uint32_t return_code) {
|
||||
ReplayThreadDoneMessage message { return_code };
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
prepare_audio();
|
||||
|
||||
transmitter_model.set_sampling_rate(1536000U);
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.set_lna(40);
|
||||
transmitter_model.set_vga(40);
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
tone_key_index = 0; //options_tone_key.selected_index();
|
||||
|
||||
divider = (1536000 / sounds[id].sample_rate) - 1;
|
||||
|
||||
baseband::set_audiotx_data(
|
||||
divider,
|
||||
baseband::set_audiotx_config(
|
||||
0,
|
||||
number_bw.value() * 1000,
|
||||
10,
|
||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
||||
TONES_F2D(tone_key_frequency(tone_key_index), sample_rate),
|
||||
0.2 // 20% mix
|
||||
);
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
sample_rate,
|
||||
1750000,
|
||||
rf::Direction::Transmit,
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
}
|
||||
|
||||
void SoundBoardView::show_infos(uint16_t id) {
|
||||
@@ -144,7 +160,7 @@ void SoundBoardView::refresh_buttons(uint16_t id) {
|
||||
text_page.set("Page " + to_string_dec_uint(page + 1) + "/" + to_string_dec_uint(max_page));
|
||||
|
||||
for (auto& button : buttons) {
|
||||
n_sound = (page * 18) + n;
|
||||
n_sound = (page * 15) + n;
|
||||
|
||||
button.id = n_sound;
|
||||
|
||||
@@ -180,64 +196,57 @@ bool SoundBoardView::change_page(Button& button, const KeyEvent key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoundBoardView::on_tx_progress(const uint32_t progress) {
|
||||
progressbar.set_value(progress);
|
||||
}
|
||||
|
||||
SoundBoardView::SoundBoardView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
std::vector<std::filesystem::path> file_list;
|
||||
std::string title;
|
||||
uint8_t c;
|
||||
auto reader = std::make_unique<WAVFileReader>();
|
||||
uint8_t c = 0;
|
||||
|
||||
reader = std::make_unique<WAVFileReader>();
|
||||
|
||||
file_list = scan_root_files(u"WAV", u"*.WAV");
|
||||
|
||||
c = 0;
|
||||
for (auto& path : file_list) {
|
||||
if (reader->open(u"WAV/" + path.native())) {
|
||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
||||
sounds[c].size = reader->data_size();
|
||||
sounds[c].sample_duration = reader->data_size(); // / (reader->bits_per_sample() / 8);
|
||||
sounds[c].sample_rate = reader->sample_rate();
|
||||
//if (reader->bits_per_sample() > 8)
|
||||
// sounds[c].sixteenbit = true;
|
||||
//else
|
||||
// sounds[c].sixteenbit = false;
|
||||
sounds[c].ms_duration = reader->ms_duration();
|
||||
sounds[c].path = u"WAV/" + path.native();
|
||||
title = reader->title().substr(0, 20);
|
||||
if (title != "")
|
||||
sounds[c].title = title;
|
||||
else
|
||||
sounds[c].title = "-";
|
||||
c++;
|
||||
if (c == 54) break; // Limit to 54 files (3 pages)
|
||||
for(const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*.WAV")) {
|
||||
if( std::filesystem::is_regular_file(entry.status()) ) {
|
||||
if (reader->open(u"WAV/" + entry.path().native())) {
|
||||
if ((reader->channels() == 1) && (reader->bits_per_sample() == 8)) {
|
||||
sounds[c].ms_duration = reader->ms_duration();
|
||||
sounds[c].path = u"WAV/" + entry.path().native();
|
||||
std::string title = reader->title().substr(0, 20);
|
||||
if (title != "")
|
||||
sounds[c].title = title;
|
||||
else
|
||||
sounds[c].title = "-";
|
||||
c++;
|
||||
if (c == 60) break; // Limit to 60 files (4 pages)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
|
||||
max_sound = c;
|
||||
max_page = (max_sound + 18 - 1) / 18; // 3 * 6 = 18 buttons per page
|
||||
max_page = (max_sound + 15 - 1) / 15; // 3 * 5 = 15 buttons per page
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&field_frequency,
|
||||
&number_bw,
|
||||
//&options_tone_key,
|
||||
&options_tone_key,
|
||||
&text_title,
|
||||
&text_page,
|
||||
&text_duration,
|
||||
&pbar,
|
||||
&progressbar,
|
||||
&check_loop,
|
||||
&button_random,
|
||||
&button_exit
|
||||
});
|
||||
|
||||
//tone_keys_populate(options_tone_key);
|
||||
//options_tone_key.set_selected_index(0);
|
||||
|
||||
|
||||
tone_keys_populate(options_tone_key);
|
||||
options_tone_key.set_selected_index(0);
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
tx_mode = NORMAL;
|
||||
this->play_sound(button.id);
|
||||
@@ -250,7 +259,7 @@ SoundBoardView::SoundBoardView(
|
||||
const auto button_dir = [this](Button& button, const KeyEvent key) {
|
||||
return change_page(button, key);
|
||||
};
|
||||
|
||||
|
||||
// Generate buttons
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
@@ -260,8 +269,8 @@ SoundBoardView::SoundBoardView(
|
||||
button.on_dir = button_dir;
|
||||
button.set_parent_rect({
|
||||
static_cast<Coord>((n % 3) * 78 + 3),
|
||||
static_cast<Coord>((n / 3) * 30 + 24),
|
||||
78, 30
|
||||
static_cast<Coord>((n / 3) * 38 + 24),
|
||||
78, 38
|
||||
});
|
||||
n++;
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "replay_thread.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "io_wave.hpp"
|
||||
@@ -59,10 +60,6 @@ private:
|
||||
|
||||
struct sound {
|
||||
std::filesystem::path path { };
|
||||
bool sixteenbit = false;
|
||||
uint32_t sample_rate = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t sample_duration = 0;
|
||||
uint32_t ms_duration = 0;
|
||||
std::string title { };
|
||||
};
|
||||
@@ -73,13 +70,15 @@ private:
|
||||
|
||||
uint32_t lfsr_v = 0x13377331;
|
||||
|
||||
std::unique_ptr<WAVFileReader> reader { };
|
||||
|
||||
sound sounds[54]; // 3 pages * 18 buttons
|
||||
sound sounds[60]; // 5 pages * 12 buttons
|
||||
uint32_t max_sound { };
|
||||
uint8_t max_page { };
|
||||
uint32_t playing_id { };
|
||||
|
||||
int8_t audio_buffer[512];
|
||||
const size_t read_size { 2048 }; // Less ?
|
||||
const size_t buffer_count { 3 };
|
||||
std::unique_ptr<ReplayThread> replay_thread { };
|
||||
bool ready_signal { false };
|
||||
|
||||
Style style_a {
|
||||
.font = font::fixed_8x16,
|
||||
@@ -102,7 +101,7 @@ private:
|
||||
.foreground = { 153, 102, 255 }
|
||||
};
|
||||
|
||||
std::array<Button, 18> buttons { };
|
||||
std::array<Button, 15> buttons { };
|
||||
const Style * styles[4] = { &style_a, &style_b, &style_c, &style_d };
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
@@ -112,8 +111,13 @@ private:
|
||||
bool change_page(Button& button, const KeyEvent key);
|
||||
void refresh_buttons(uint16_t id);
|
||||
void play_sound(uint16_t id);
|
||||
void prepare_audio();
|
||||
void on_ctcss_changed(uint32_t v);
|
||||
void stop(const bool do_loop);
|
||||
bool is_active() const;
|
||||
void set_ready();
|
||||
void handle_replay_thread_done(const uint32_t return_code);
|
||||
void file_error();
|
||||
void on_tx_progress(const uint32_t progress);
|
||||
|
||||
Labels labels {
|
||||
{ { 10 * 8, 4 }, "BW: kHz", Color::light_grey() }
|
||||
@@ -138,21 +142,21 @@ private:
|
||||
};
|
||||
|
||||
Text text_title {
|
||||
{ 1 * 8, 26 * 8, 20 * 8, 16 },
|
||||
{ 1 * 8, 28 * 8, 20 * 8, 16 },
|
||||
"-"
|
||||
};
|
||||
|
||||
Text text_page {
|
||||
{ 22 * 8 - 4, 26 * 8, 8 * 8, 16 },
|
||||
{ 22 * 8 - 4, 28 * 8, 8 * 8, 16 },
|
||||
"Page -/-"
|
||||
};
|
||||
|
||||
Text text_duration {
|
||||
{ 1 * 8, 30 * 8, 5 * 8, 16 }
|
||||
{ 1 * 8, 31 * 8, 5 * 8, 16 }
|
||||
};
|
||||
|
||||
ProgressBar pbar {
|
||||
{ 9 * 8, 30 * 8, 20 * 8, 16 }
|
||||
ProgressBar progressbar {
|
||||
{ 9 * 8, 31 * 8, 20 * 8, 16 }
|
||||
};
|
||||
|
||||
Checkbox check_loop {
|
||||
@@ -171,15 +175,31 @@ private:
|
||||
"Exit"
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||
Message::ID::ReplayThreadDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||
this->handle_replay_thread_done(message.return_code);
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal {
|
||||
Message::ID::RequestSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const RequestSignalMessage*>(p);
|
||||
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||
this->prepare_audio();
|
||||
this->set_ready();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_tx_progress {
|
||||
Message::ID::TXProgress,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||
this->on_tx_progress(message.progress);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
@@ -45,7 +45,10 @@ ToneSearchView::ToneSearchView(
|
||||
//baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
add_children({
|
||||
&labels
|
||||
&labels,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_rf_amp,
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,19 @@ private:
|
||||
NavigationView& nav_;
|
||||
|
||||
Labels labels {
|
||||
{ { 1 * 8, 0 }, "Min: Max: LNA VGA", Color::light_grey() }
|
||||
{ { 0 * 8, 0 * 8 }, "LNA: VGA: AMP:", Color::light_grey() }
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 4 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 11 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user