mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-11 15:29:28 -05:00
Added Soundboard
file.cpp: scan_root_files proc_audiotx.cpp: bandwidth setting ui_widget.cpp: button on_focus
This commit is contained in:
parent
5de6349199
commit
f7e0f36bd9
@ -165,7 +165,7 @@ set(CPPSRC
|
||||
ui_handwrite.cpp
|
||||
ui_afsksetup.cpp
|
||||
# ui_closecall.cpp
|
||||
# ui_soundboard.cpp
|
||||
ui_soundboard.cpp
|
||||
ui_rds.cpp
|
||||
ui_lcr.cpp
|
||||
ui_xylos.cpp
|
||||
|
@ -4062,6 +4062,30 @@ ui_setup.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_setup.cpp.s
|
||||
.PHONY : ui_setup.cpp.s
|
||||
|
||||
ui_soundboard.obj: ui_soundboard.cpp.obj
|
||||
.PHONY : ui_soundboard.obj
|
||||
|
||||
# target to build an object file
|
||||
ui_soundboard.cpp.obj:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_soundboard.cpp.obj
|
||||
.PHONY : ui_soundboard.cpp.obj
|
||||
|
||||
ui_soundboard.i: ui_soundboard.cpp.i
|
||||
.PHONY : ui_soundboard.i
|
||||
|
||||
# target to preprocess a source file
|
||||
ui_soundboard.cpp.i:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_soundboard.cpp.i
|
||||
.PHONY : ui_soundboard.cpp.i
|
||||
|
||||
ui_soundboard.s: ui_soundboard.cpp.s
|
||||
.PHONY : ui_soundboard.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
ui_soundboard.cpp.s:
|
||||
cd /home/furrtek/portapack-hackrf && $(MAKE) -f firmware/application/CMakeFiles/application.elf.dir/build.make firmware/application/CMakeFiles/application.elf.dir/ui_soundboard.cpp.s
|
||||
.PHONY : ui_soundboard.cpp.s
|
||||
|
||||
ui_spectrum.obj: ui_spectrum.cpp.obj
|
||||
.PHONY : ui_spectrum.obj
|
||||
|
||||
@ -4660,6 +4684,9 @@ help:
|
||||
@echo "... ui_setup.obj"
|
||||
@echo "... ui_setup.i"
|
||||
@echo "... ui_setup.s"
|
||||
@echo "... ui_soundboard.obj"
|
||||
@echo "... ui_soundboard.i"
|
||||
@echo "... ui_soundboard.s"
|
||||
@echo "... ui_spectrum.obj"
|
||||
@echo "... ui_spectrum.i"
|
||||
@echo "... ui_spectrum.s"
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@ -177,6 +178,28 @@ std::string next_filename_stem_matching_pattern(const std::string& filename_stem
|
||||
return filename_stem;
|
||||
}
|
||||
|
||||
std::vector<std::string> scan_root_files(const std::string& extension) {
|
||||
std::vector<std::string> file_list { };
|
||||
std::string fname;
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
static FILINFO fno;
|
||||
|
||||
res = f_opendir(&dir, "/");
|
||||
if (res == FR_OK) {
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res != FR_OK || fno.fname[0] == 0) break;
|
||||
fname.assign(fno.fname);
|
||||
if (fname.find(extension) != std::string::npos)
|
||||
file_list.push_back(fname);
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
return file_list;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
namespace filesystem {
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@ -32,8 +33,10 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern);
|
||||
std::vector<std::string> scan_root_files(const std::string& extension);
|
||||
|
||||
namespace std {
|
||||
namespace filesystem {
|
||||
|
@ -23,19 +23,21 @@
|
||||
// Bitmaps generated with:
|
||||
// Gimp image > indexed colors (16), then "xxd -i *.bmp"
|
||||
|
||||
//BUG: No audio in about when shown second time
|
||||
//BUG (fixed ?): No audio in about when shown second time
|
||||
//BUG: POCSAG RX sometimes misses the first codeword after SYNC
|
||||
|
||||
//TODO: Make frequency set button in afsksetup accept GHz frequencies (longer label buffer)
|
||||
//TODO: POCSAG 512 and 2400 (all 3 at the same time, or parameter ?)
|
||||
//TODO: Check AFSK transmit end, skips last bits ?
|
||||
//TODO: Check jammer bandwidths
|
||||
//TODO: Use msgpack for settings, lists... on sd card
|
||||
//TODO: Frequency manager
|
||||
//TODO: Morse coder
|
||||
//TODO: Replay
|
||||
|
||||
//Multimon-style stuff:
|
||||
//TODO: AFSK receiver
|
||||
//TODO: Xylos receiver
|
||||
//TODO: Xylos (CCIR) receiver
|
||||
|
||||
//TODO: Check jammer bandwidths
|
||||
//TODO: Closecall wide range fix
|
||||
//TODO: SD card wiper
|
||||
//TODO: GSM channel detector
|
||||
|
@ -41,18 +41,18 @@ namespace format {
|
||||
|
||||
static std::string bitrate_str(BitRate bitrate) {
|
||||
switch (bitrate) {
|
||||
case BitRate::FSK512: return "F512 ";
|
||||
case BitRate::FSK1200: return "F1200";
|
||||
case BitRate::FSK2400: return "F2400";
|
||||
default: return "F????";
|
||||
case BitRate::FSK512: return "512 ";
|
||||
case BitRate::FSK1200: return "1200";
|
||||
case BitRate::FSK2400: return "2400";
|
||||
default: return "????";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string flag_str(PacketFlag packetflag) {
|
||||
switch (packetflag) {
|
||||
case PacketFlag::NORMAL: return "NORMAL ";
|
||||
case PacketFlag::NORMAL: return "OK";
|
||||
case PacketFlag::TIMED_OUT: return "TIMED OUT";
|
||||
case PacketFlag::TOO_LONG: return "TOO LONG ";
|
||||
case PacketFlag::TOO_LONG: return "TOO LONG";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@ -208,12 +208,12 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage * message) {
|
||||
if (eom) {
|
||||
std::string console_info;
|
||||
|
||||
console_info = to_string_time(message->packet.timestamp());
|
||||
console_info = to_string_time(message->packet.timestamp()) + " ";
|
||||
|
||||
if (address || function) {
|
||||
console_info += pocsag::format::bitrate_str( message->packet.bitrate()) + " ";
|
||||
console_info += pocsag::format::flag_str(message->packet.flag()) + " ";
|
||||
console_info += " ADDR:" + to_string_dec_uint(address, 7) + " F:" + to_string_dec_uint(function);
|
||||
console_info += "ADDR:" + to_string_dec_uint(address) + " F:" + to_string_dec_uint(function);
|
||||
|
||||
console.writeln(console_info);
|
||||
|
||||
|
@ -59,9 +59,7 @@ void AboutView::on_show() {
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(
|
||||
0
|
||||
);
|
||||
baseband::set_audiotx_data(15);
|
||||
|
||||
//audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max);
|
||||
}
|
||||
@ -132,7 +130,7 @@ void AboutView::render_video() {
|
||||
|
||||
// Switch to next text
|
||||
if (anim_state == 0) {
|
||||
if (credits_index == 7)
|
||||
if (credits_index == 9)
|
||||
credits_index = 0;
|
||||
else
|
||||
credits_index++;
|
||||
@ -221,7 +219,7 @@ void AboutView::render_audio() {
|
||||
// Render 1024 music samples
|
||||
for (ym_render_cnt = 0; ym_render_cnt < 1024; ym_render_cnt++) {
|
||||
|
||||
// Taken at 48000/960 = 50Hz
|
||||
// Update registers at 48000/960 = 50Hz
|
||||
if (ym_sample_cnt == 0) {
|
||||
// "Decompress" on the fly and update YM registers
|
||||
for (i = 0; i < 14; i++) {
|
||||
@ -338,7 +336,7 @@ void AboutView::update() {
|
||||
}
|
||||
|
||||
// Slowly increase volume to avoid jumpscare
|
||||
if (headphone_vol < (70<<2)) {
|
||||
if (headphone_vol < (70 << 2)) {
|
||||
audio::headphone::set_volume(volume_t::decibel((headphone_vol/4) - 99) + audio::headphone::volume_range().max);
|
||||
headphone_vol++;
|
||||
}
|
||||
|
@ -56,12 +56,12 @@ private:
|
||||
bool same;
|
||||
} ymreg_t;
|
||||
|
||||
uint16_t headphone_vol = 5<<2;
|
||||
uint16_t headphone_vol = 5 << 2;
|
||||
|
||||
ymreg_t ym_regs[14];
|
||||
uint16_t ym_frames;
|
||||
uint16_t ym_frame;
|
||||
uint8_t drum;
|
||||
uint8_t drum = 0;
|
||||
uint16_t ym_osc_cnt[3];
|
||||
uint32_t ym_rng = 1;
|
||||
uint16_t ym_noise_cnt;
|
||||
@ -80,8 +80,8 @@ private:
|
||||
ui::Color paletteB[16];
|
||||
ui::Color * framebuffer;
|
||||
uint32_t phase = 0;
|
||||
uint8_t copperbars[5] = {0};
|
||||
uint8_t copperbuffer[72] = {0};
|
||||
uint8_t copperbars[5] = { 0 };
|
||||
uint8_t copperbuffer[72] = { 0 };
|
||||
|
||||
uint8_t anim_state = 0;
|
||||
uint8_t credits_index = 0;
|
||||
@ -98,12 +98,12 @@ private:
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
const uint8_t copperluma[16] = {8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8};
|
||||
const uint8_t coppercolor[5][3] = { {255,0,0},
|
||||
{0,255,0},
|
||||
{0,0,255},
|
||||
{255,0,255},
|
||||
{255,255,0} };
|
||||
const uint8_t copperluma[16] = { 8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8 };
|
||||
const uint8_t coppercolor[5][3] = { { 255,0,0 },
|
||||
{ 0,255,0 },
|
||||
{ 0,0,255 },
|
||||
{ 255,0,255 },
|
||||
{ 255,255,0 } };
|
||||
|
||||
typedef struct credits_t {
|
||||
char role[12];
|
||||
@ -112,10 +112,12 @@ private:
|
||||
} credits_t;
|
||||
|
||||
// 0123456789A 0123456789A
|
||||
const credits_t credits[8] = { {"GURUS", "J. BOONE", false},
|
||||
{"GURUS", "M. OSSMANN", true},
|
||||
const credits_t credits[10] = { {"GURUS", "J. BOONE", false},
|
||||
{"GURYS", "M. OSSMANN", true},
|
||||
{"BUGS", "FURRTEK", true},
|
||||
{"RDS TABLE", "C. JACQUET", true},
|
||||
{"RDS WAVE", "C. JACQUET", true},
|
||||
{"POCSAG RX", "T. SAILER", false},
|
||||
{"POCSAG RX", "E. OENAL", true},
|
||||
{"XYLOS DATA", "CLX", true},
|
||||
{"GREETS TO", "SIGMOUNTE", false},
|
||||
{"GREETS TO", "WINDYOONA", true},
|
||||
|
@ -266,7 +266,7 @@ void LCRView::start_tx(const bool scan) {
|
||||
portapack::persistent_memory::afsk_mark_freq() * 437 * 5, //(0x40000 * 256) / (153600 / 25),
|
||||
portapack::persistent_memory::afsk_space_freq() * 437 * 5, //(0x40000 * 256) / (153600 / 25),
|
||||
afsk_repeats,
|
||||
portapack::persistent_memory::afsk_bw() * 115, // See proc_fsk_lcr.cpp
|
||||
portapack::persistent_memory::afsk_bw() * 115, // See proc_afsk.cpp
|
||||
afsk_format
|
||||
);
|
||||
}
|
||||
|
@ -35,9 +35,9 @@
|
||||
#include "ui_setup.hpp"
|
||||
#include "ui_debug.hpp"
|
||||
|
||||
//#include "ui_soundboard.hpp" // DEBUG
|
||||
//#include "ui_closecall.hpp" // DEBUG
|
||||
#include "ui_freqman.hpp" // DEBUG
|
||||
//#include "ui_freqman.hpp" // DEBUG
|
||||
#include "ui_soundboard.hpp"
|
||||
|
||||
#include "ui_encoders.hpp"
|
||||
#include "ui_debug.hpp"
|
||||
@ -46,7 +46,7 @@
|
||||
#include "ui_epar.hpp"
|
||||
#include "ui_lcr.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "ui_audiotx.hpp" // DEBUG
|
||||
//#include "ui_audiotx.hpp" // DEBUG
|
||||
//#include "ui_jammer.hpp" // DEBUG
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
@ -246,9 +246,9 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
|
||||
{ "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } },
|
||||
{ "Capture RX", ui::Color::cyan(), [&nav](){ nav.push<CaptureAppView>(); } },
|
||||
//{ "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push<CloseCallView>(); } },
|
||||
{ "Numbers station TX", ui::Color::purple(), [&nav](){ nav.push<NotImplementedView>(); } }, //nav.push<NumbersStationView>();
|
||||
//{ "Numbers station TX", ui::Color::purple(), [&nav](){ nav.push<NotImplementedView>(); } }, //nav.push<NumbersStationView>();
|
||||
//{ "Pokemon GO Away TX", ui::Color::blue(), [&nav](){ nav.push<JammerView>(); } },
|
||||
//{ "Soundboard TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, SoundBoard); } },
|
||||
{ "Soundboard TX", ui::Color::yellow(), [&nav](){ nav.push<SoundBoardView>(); } },
|
||||
//{ "Audio TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, AudioTX); } },
|
||||
//{ "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } },
|
||||
//{ "EPAR TX", ui::Color::green(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, EPAR); } },
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@ -19,6 +20,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// To prepare samples: for f in ./*.wav; do sox "$f" -r 48000 -c 1 -b8 --norm "conv/$f"; done
|
||||
|
||||
#include "ui_soundboard.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
@ -35,28 +38,65 @@
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
uint16_t SoundBoardView::shitty_rand() {
|
||||
uint8_t bit;
|
||||
|
||||
void SoundBoardView::on_show() {
|
||||
/*
|
||||
// Just in case
|
||||
EventDispatcher::message_map().unregister_handler(Message::ID::DisplayFrameSync);
|
||||
bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
|
||||
|
||||
// "Vertical blank interrupt"
|
||||
EventDispatcher::message_map().register_handler(Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
pbar_test.set_value(testv/4);
|
||||
testv++;
|
||||
}
|
||||
);*/
|
||||
return lfsr = (lfsr >> 1) | (bit << 15);
|
||||
}
|
||||
|
||||
std::string SoundBoardView::title() const {
|
||||
return "Sound board";
|
||||
};
|
||||
void SoundBoardView::do_random() {
|
||||
uint16_t id;
|
||||
|
||||
chThdSleepMilliseconds(300); // 100ms
|
||||
|
||||
id = shitty_rand() % max_sound;
|
||||
|
||||
play_sound(id);
|
||||
|
||||
buttons[id % 21].focus();
|
||||
page = id / 21;
|
||||
|
||||
refresh_buttons(id);
|
||||
}
|
||||
|
||||
void SoundBoardView::prepare_audio() {
|
||||
|
||||
if (cnt >= sample_duration) {
|
||||
if (tx_mode == NORMAL) {
|
||||
if (!check_loop.value()) {
|
||||
pbar.set_value(0);
|
||||
transmitter_model.disable();
|
||||
return;
|
||||
} else {
|
||||
file.seek(44);
|
||||
cnt = 0;
|
||||
}
|
||||
} else {
|
||||
pbar.set_value(0);
|
||||
transmitter_model.disable();
|
||||
do_random();
|
||||
}
|
||||
}
|
||||
|
||||
pbar.set_value(cnt);
|
||||
|
||||
file.read(audio_buffer, 1024);
|
||||
|
||||
for (size_t n = 0; n < 1024; n++)
|
||||
audio_buffer[n] -= 0x80;
|
||||
|
||||
cnt += 1024;
|
||||
|
||||
baseband::set_fifo_data(audio_buffer);
|
||||
}
|
||||
|
||||
void SoundBoardView::focus() {
|
||||
buttons[0].focus();
|
||||
@ -66,72 +106,218 @@ void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
transmitter_model.set_tuning_frequency(f);
|
||||
}
|
||||
|
||||
void SoundBoardView::on_button(Button& button) {
|
||||
text_test.set(to_string_dec_uint(button.id));
|
||||
void SoundBoardView::play_sound(uint16_t id) {
|
||||
|
||||
auto error = file.open(sounds[id].filename);
|
||||
if (error.is_valid()) return;
|
||||
|
||||
sample_duration = sounds[id].sample_duration;
|
||||
|
||||
pbar.set_max(sample_duration);
|
||||
pbar.set_value(0);
|
||||
|
||||
cnt = 0;
|
||||
file.seek(44); // Skip header
|
||||
|
||||
prepare_audio();
|
||||
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 0,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
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();
|
||||
|
||||
baseband::set_audiotx_data(number_bw.value());
|
||||
}
|
||||
|
||||
void SoundBoardView::show_infos(uint16_t id) {
|
||||
uint32_t duration = sounds[id].ms_duration;
|
||||
|
||||
text_duration.set(to_string_dec_uint(duration / 1000) + "." + to_string_dec_uint((duration / 100) % 10) + "s");
|
||||
}
|
||||
|
||||
void SoundBoardView::refresh_buttons(uint16_t id) {
|
||||
size_t n = 0, n_sound;
|
||||
|
||||
text_page.set(to_string_dec_uint(page + 1) + "/" + to_string_dec_uint(max_page));
|
||||
|
||||
for (auto& button : buttons) {
|
||||
n_sound = (page * 21) + n;
|
||||
|
||||
button.id = n_sound;
|
||||
|
||||
if (n_sound < max_sound) {
|
||||
button.set_text(sounds[n_sound].shortname);
|
||||
button.set_style(styles[sounds[n_sound].shortname[0] & 3]);
|
||||
} else {
|
||||
button.set_text("- - -");
|
||||
button.set_style(styles[0]);
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
show_infos(id);
|
||||
}
|
||||
|
||||
void SoundBoardView::change_page(Button& button, const KeyEvent key) {
|
||||
|
||||
// Stupid way to find out if the button is on the sides
|
||||
if (button.screen_pos().x < 32) {
|
||||
if ((key == KeyEvent::Left) && (page > 0)) {
|
||||
page--;
|
||||
refresh_buttons(button.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (button.screen_pos().x > 120) {
|
||||
if ((key == KeyEvent::Right) && (page < max_page - 1)) {
|
||||
page++;
|
||||
refresh_buttons(button.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SoundBoardView::fb_to_uint16(const std::string& fb) {
|
||||
return (fb[1] << 8) + fb[0];
|
||||
}
|
||||
|
||||
uint32_t SoundBoardView::fb_to_uint32(const std::string& fb) {
|
||||
return (fb[3] << 24) + (fb[2] << 16) + (fb[1] << 8) + fb[0];
|
||||
}
|
||||
|
||||
SoundBoardView::SoundBoardView(
|
||||
NavigationView& nav
|
||||
)
|
||||
{
|
||||
size_t n;
|
||||
std::vector<std::string> file_list;
|
||||
std::string file_name;
|
||||
uint32_t size;
|
||||
uint8_t c;
|
||||
|
||||
for (n = 0; n < 12; n++) {
|
||||
sounds[n].filename = "";
|
||||
sounds[n].shortname = "Empty";
|
||||
sounds[n].min = 0;
|
||||
sounds[n].sec = 0;
|
||||
char file_buffer[32];
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
file_list = scan_root_files(".WAV");
|
||||
|
||||
c = 0;
|
||||
for (auto& file_name : file_list) {
|
||||
|
||||
auto error = file.open(file_name);
|
||||
|
||||
file.seek(40);
|
||||
file.read(file_buffer, 4);
|
||||
size = fb_to_uint32(file_buffer);
|
||||
sounds[c].size = size;
|
||||
|
||||
file.seek(22);
|
||||
file.read(file_buffer, 2);
|
||||
if (fb_to_uint16(file_buffer) > 1) {
|
||||
sounds[c].stereo = true;
|
||||
size /= 2;
|
||||
} else
|
||||
sounds[c].stereo = false;
|
||||
|
||||
file.seek(24);
|
||||
file.read(file_buffer, 4);
|
||||
sounds[c].sample_rate = fb_to_uint32(file_buffer);
|
||||
|
||||
file.seek(34);
|
||||
file.read(file_buffer, 2);
|
||||
if (fb_to_uint16(file_buffer) > 8) {
|
||||
sounds[c].sixteenbit = true;
|
||||
size /= 2;
|
||||
} else
|
||||
sounds[c].sixteenbit = false;
|
||||
|
||||
sounds[c].ms_duration = (size * 1000) / sounds[c].sample_rate;
|
||||
sounds[c].sample_duration = size;
|
||||
|
||||
sounds[c].filename = file_name;
|
||||
sounds[c].shortname = file_name.substr(0, file_name.find_last_of("."));
|
||||
|
||||
c++;
|
||||
if (c == 100) break;
|
||||
}
|
||||
|
||||
max_sound = c;
|
||||
max_page = max_sound / 21;
|
||||
|
||||
add_children({ {
|
||||
&text_test,
|
||||
&field_frequency,
|
||||
&number_bw,
|
||||
&pbar_test,
|
||||
&button_load,
|
||||
&text_kHz,
|
||||
&text_page,
|
||||
&text_duration,
|
||||
&pbar,
|
||||
&check_loop,
|
||||
&button_random,
|
||||
&button_exit
|
||||
} });
|
||||
|
||||
const auto button_fn = [this](Button& button) {
|
||||
this->on_button(button);
|
||||
tx_mode = NORMAL;
|
||||
this->play_sound(button.id);
|
||||
};
|
||||
|
||||
const auto button_focus = [this](Button& button) {
|
||||
this->show_infos(button.id);
|
||||
};
|
||||
|
||||
const auto button_dir = [this](Button& button, const KeyEvent key) {
|
||||
(void)button;
|
||||
|
||||
this->change_page(button, key);
|
||||
};
|
||||
|
||||
size_t n = 0;
|
||||
for(auto& button : buttons) {
|
||||
add_child(&button);
|
||||
button.id = n;
|
||||
button.on_select = button_fn;
|
||||
button.on_highlight = button_focus;
|
||||
button.on_dir = button_dir;
|
||||
button.set_parent_rect({
|
||||
static_cast<Coord>((n % 3) * 70 + 15),
|
||||
static_cast<Coord>((n / 3) * 50 + 30),
|
||||
70, 50
|
||||
static_cast<Coord>((n % 3) * 78 + 3),
|
||||
static_cast<Coord>((n / 3) * 28 + 26),
|
||||
78, 28
|
||||
});
|
||||
button.set_text(sounds[n].shortname);
|
||||
n++;
|
||||
}
|
||||
refresh_buttons(0);
|
||||
|
||||
check_loop.set_value(false);
|
||||
number_bw.set_value(15);
|
||||
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.set_step(10000);
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
/*button_transmit.on_select = [](Button&){
|
||||
transmitter_model.set_baseband_configuration({
|
||||
.mode = 1,
|
||||
.sampling_rate = 1536000,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
transmitter_model.set_rf_amp(true);
|
||||
transmitter_model.enable();
|
||||
};*/
|
||||
button_random.on_select = [this](Button&){
|
||||
if (tx_mode == NORMAL) {
|
||||
tx_mode = RANDOM;
|
||||
button_random.set_text("STOP");
|
||||
do_random();
|
||||
} else {
|
||||
tx_mode = NORMAL;
|
||||
button_random.set_text("Random");
|
||||
}
|
||||
};
|
||||
|
||||
button_exit.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
@ -140,6 +326,7 @@ SoundBoardView::SoundBoardView(
|
||||
|
||||
SoundBoardView::~SoundBoardView() {
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@ -19,19 +20,17 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UI_SOUNDBOARD_H__
|
||||
#define __UI_SOUNDBOARD_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_painter.hpp"
|
||||
#include "ui_menu.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "message.hpp"
|
||||
#include "rf_path.hpp"
|
||||
#include "max2837.hpp"
|
||||
#include "volume.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "transmitter_model.hpp"
|
||||
#include "message.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -40,27 +39,81 @@ public:
|
||||
SoundBoardView(NavigationView& nav);
|
||||
~SoundBoardView();
|
||||
|
||||
std::string title() const;
|
||||
void on_show() override;
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Soundboard"; };
|
||||
|
||||
private:
|
||||
enum tx_modes {
|
||||
NORMAL = 0,
|
||||
RANDOM
|
||||
};
|
||||
|
||||
tx_modes tx_mode = NORMAL;
|
||||
|
||||
struct sound {
|
||||
std::string filename;
|
||||
std::string shortname;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
bool stereo;
|
||||
bool sixteenbit;
|
||||
uint32_t sample_rate;
|
||||
uint32_t size;
|
||||
uint32_t sample_duration;
|
||||
uint32_t ms_duration;
|
||||
};
|
||||
|
||||
sound sounds[12];
|
||||
uint32_t cnt;
|
||||
uint32_t sample_duration;
|
||||
uint8_t page = 0;
|
||||
|
||||
File file;
|
||||
|
||||
uint16_t lfsr = 0x1337u;
|
||||
|
||||
sound sounds[100];
|
||||
uint8_t max_sound;
|
||||
uint8_t max_page;
|
||||
|
||||
std::array<Button, 12> buttons;
|
||||
void on_button(Button& button);
|
||||
int8_t audio_buffer[1024];
|
||||
|
||||
Style style_a {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = { 255, 51, 153 }
|
||||
};
|
||||
Style style_b {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = { 153, 204, 0 }
|
||||
};
|
||||
Style style_c {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = { 51, 204, 204 }
|
||||
};
|
||||
Style style_d {
|
||||
.font = font::fixed_8x16,
|
||||
.background = Color::black(),
|
||||
.foreground = { 153, 102, 255 }
|
||||
};
|
||||
|
||||
std::array<Button, 21> buttons;
|
||||
const Style * styles[4] = { &style_a, &style_b, &style_c, &style_d };
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
|
||||
Text text_test {
|
||||
{ 120, 4, 64, 16 }
|
||||
void do_random();
|
||||
uint16_t shitty_rand();
|
||||
void show_infos(uint16_t id);
|
||||
void change_page(Button& button, const KeyEvent key);
|
||||
void refresh_buttons(uint16_t id);
|
||||
void play_sound(uint16_t id);
|
||||
void prepare_audio();
|
||||
uint16_t fb_to_uint16(const std::string& fb);
|
||||
uint32_t fb_to_uint32(const std::string& fb);
|
||||
|
||||
Text text_duration {
|
||||
{ 16, 236, 5 * 8, 16 }
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
@ -68,26 +121,54 @@ private:
|
||||
};
|
||||
|
||||
NumberField number_bw {
|
||||
{ 16 * 8, 4 },
|
||||
5,
|
||||
{1000, 50000},
|
||||
500,
|
||||
{ 14 * 8, 4 },
|
||||
2,
|
||||
{1, 50},
|
||||
1,
|
||||
' '
|
||||
};
|
||||
|
||||
ProgressBar pbar_test {
|
||||
{ 45, 236, 150, 16 }
|
||||
Text text_kHz {
|
||||
{ 16 * 8, 4, 3 * 8, 16 },
|
||||
"kHz"
|
||||
};
|
||||
|
||||
Button button_load {
|
||||
{ 8, 270, 64, 32 },
|
||||
"Load"
|
||||
Text text_page {
|
||||
{ 22 * 8, 4, 3 * 8, 16 },
|
||||
"-/-"
|
||||
};
|
||||
|
||||
ProgressBar pbar {
|
||||
{ 72, 236, 150, 16 }
|
||||
};
|
||||
|
||||
Checkbox check_loop {
|
||||
{ 16, 274 },
|
||||
4,
|
||||
"Loop"
|
||||
};
|
||||
|
||||
Button button_random {
|
||||
{ 80, 270, 72, 32 },
|
||||
"Random"
|
||||
};
|
||||
|
||||
Button button_exit {
|
||||
{ 96, 270, 64, 32 },
|
||||
{ 160, 270, 64, 32 },
|
||||
"Exit"
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal {
|
||||
Message::ID::FIFOSignal,
|
||||
[this](const Message* const p) {
|
||||
const auto message = static_cast<const FIFOSignalMessage*>(p);
|
||||
if (message->signaltype == 1) {
|
||||
this->prepare_audio();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif/*__UI_SOUNDBOARD_H__*/
|
||||
|
@ -106,7 +106,8 @@ void AFSKProcessor::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
// FM
|
||||
// 1<<18 = 262144
|
||||
// m = (262144 * BW) / 2280000 (* 115, see ui_lcr afsk_bw setting)
|
||||
// m = (262144 * a) / 2280000
|
||||
// a = 262144 / 2280000 (*1000 = 115, see ui_lcr afsk_bw setting)
|
||||
frq = tone_sample * afsk_bw;
|
||||
|
||||
phase = (phase + frq);
|
||||
|
@ -38,8 +38,8 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
||||
for (size_t i = 0; i<buffer.count; i++) {
|
||||
|
||||
// Audio preview sample generation: 1536000/48000 = 32
|
||||
if (as >= 31) {
|
||||
as = 0;
|
||||
if (!as) {
|
||||
as = 32;
|
||||
audio_fifo.out(sample);
|
||||
//preview_audio_buffer.p[ai++] = sample << 8;
|
||||
|
||||
@ -50,11 +50,11 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
||||
asked = true;
|
||||
}
|
||||
} else {
|
||||
as++;
|
||||
as--;
|
||||
}
|
||||
|
||||
// FM
|
||||
frq = sample * 8000;
|
||||
frq = sample * bw;
|
||||
|
||||
phase = (phase + frq);
|
||||
sphase = phase + (64 << 18);
|
||||
@ -69,9 +69,17 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
||||
}
|
||||
|
||||
void AudioTXProcessor::on_message(const Message* const msg) {
|
||||
const auto message = static_cast<const AudioTXConfigMessage*>(msg);
|
||||
|
||||
switch(msg->id) {
|
||||
case Message::ID::AudioTXConfig:
|
||||
//const auto message = static_cast<const AudioTXConfigMessage*>(msg);
|
||||
|
||||
// 1<<18 = 262144
|
||||
// m = (262144 * a) / 1536000
|
||||
// a = 262144 / 1536000 (*1000 = 171)
|
||||
bw = 171 * (message->bw);
|
||||
as = 0;
|
||||
|
||||
configured = true;
|
||||
break;
|
||||
|
||||
|
@ -41,6 +41,7 @@ private:
|
||||
int8_t audio_fifo_data[2048];
|
||||
FIFO<int8_t> audio_fifo = { audio_fifo_data, 11 }; // 43ms @ 48000Hz
|
||||
|
||||
uint32_t bw;
|
||||
uint8_t as = 0, ai;
|
||||
int8_t re, im;
|
||||
int8_t sample;
|
||||
|
@ -94,7 +94,7 @@ void POCSAGProcessor::execute(const buffer_c8_t& buffer) {
|
||||
last_rx_data = rx_data;
|
||||
rx_state = SYNC;
|
||||
} else if (rx_data == POCSAG_IDLE) {
|
||||
//rx_state = WAITING;
|
||||
rx_state = WAITING;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -106,6 +106,7 @@ void POCSAGProcessor::execute(const buffer_c8_t& buffer) {
|
||||
if (msg_timeout < 600) {
|
||||
msg_timeout++;
|
||||
rx_bit++;
|
||||
|
||||
if (rx_bit >= 32) {
|
||||
rx_bit = 0;
|
||||
|
||||
|
@ -434,13 +434,13 @@ ProgressBar::ProgressBar(
|
||||
{
|
||||
}
|
||||
|
||||
void ProgressBar::set_max(const uint16_t max) {
|
||||
void ProgressBar::set_max(const uint32_t max) {
|
||||
_value = 0;
|
||||
_max = max;
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void ProgressBar::set_value(const uint16_t value) {
|
||||
void ProgressBar::set_value(const uint32_t value) {
|
||||
if (value > _max)
|
||||
_value = _max;
|
||||
else
|
||||
@ -689,6 +689,11 @@ void Button::paint(Painter& painter) {
|
||||
);
|
||||
}
|
||||
|
||||
void Button::on_focus() {
|
||||
if( on_highlight )
|
||||
on_highlight(*this);
|
||||
}
|
||||
|
||||
bool Button::on_key(const KeyEvent key) {
|
||||
if( key == KeyEvent::Select ) {
|
||||
if( on_select ) {
|
||||
|
@ -220,14 +220,14 @@ class ProgressBar : public Widget {
|
||||
public:
|
||||
ProgressBar(Rect parent_rect);
|
||||
|
||||
void set_max(const uint16_t max);
|
||||
void set_value(const uint16_t value);
|
||||
void set_max(const uint32_t max);
|
||||
void set_value(const uint32_t value);
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
private:
|
||||
uint16_t _value = 0;
|
||||
uint16_t _max = 100;
|
||||
uint32_t _value = 0;
|
||||
uint32_t _max = 100;
|
||||
};
|
||||
|
||||
class Console : public Widget {
|
||||
@ -282,6 +282,7 @@ class Button : public Widget {
|
||||
public:
|
||||
std::function<void(Button&)> on_select;
|
||||
std::function<void(Button&,KeyEvent)> on_dir;
|
||||
std::function<void(Button&)> on_highlight;
|
||||
|
||||
Button(Rect parent_rect, std::string text);
|
||||
|
||||
@ -295,6 +296,7 @@ public:
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void on_focus() override;
|
||||
bool on_key(const KeyEvent key) override;
|
||||
bool on_touch(const TouchEvent event) override;
|
||||
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user