Soundboard: Arbitrary samplerate support for wave files
Screenshots
@ -99,8 +99,9 @@ void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phas
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_audiotx_data(const uint32_t bw) {
|
||||
void set_audiotx_data(const uint32_t divider, const uint32_t bw) {
|
||||
const AudioTXConfigMessage message {
|
||||
divider,
|
||||
bw
|
||||
};
|
||||
send_message(&message);
|
||||
|
@ -53,7 +53,7 @@ struct WFMConfig {
|
||||
};
|
||||
|
||||
void set_ccir_data( const uint32_t samples_per_tone, const uint16_t tone_count);
|
||||
void set_audiotx_data(const uint32_t bw);
|
||||
void set_audiotx_data(const uint32_t divider, const uint32_t bw);
|
||||
void set_fifo_data(const int8_t * data);
|
||||
void set_pwmrssi(int32_t avg, bool enabled);
|
||||
void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space,
|
||||
|
@ -138,7 +138,7 @@ static std::string find_last_file_matching_pattern(const std::string& pattern) {
|
||||
return last_match;
|
||||
}
|
||||
|
||||
static std::string remove_filename_extension(const std::string& filename) {
|
||||
std::string remove_filename_extension(const std::string& filename) {
|
||||
const auto extension_index = filename.find_last_of('.');
|
||||
return filename.substr(0, extension_index);
|
||||
}
|
||||
@ -178,14 +178,14 @@ 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> scan_root_files(const std::string& directory, const std::string& extension) {
|
||||
std::vector<std::string> file_list { };
|
||||
std::string fname;
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
static FILINFO fno;
|
||||
|
||||
res = f_opendir(&dir, "/");
|
||||
res = f_opendir(&dir, directory.c_str());
|
||||
if (res == FR_OK) {
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno);
|
||||
|
@ -35,8 +35,9 @@
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
std::string remove_filename_extension(const std::string& filename);
|
||||
std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern);
|
||||
std::vector<std::string> scan_root_files(const std::string& extension);
|
||||
std::vector<std::string> scan_root_files(const std::string& directory, const std::string& extension);
|
||||
|
||||
namespace std {
|
||||
namespace filesystem {
|
||||
|
@ -59,7 +59,7 @@ void AboutView::on_show() {
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(15);
|
||||
baseband::set_audiotx_data(32, 15);
|
||||
|
||||
//audio::headphone::set_volume(volume_t::decibel(0 - 99) + audio::headphone::volume_range().max);
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ private:
|
||||
|
||||
// 0123456789A 0123456789A
|
||||
const credits_t credits[10] = { {"GURUS", "J. BOONE", false},
|
||||
{"GURYS", "M. OSSMANN", true},
|
||||
{"GURUS", "M. OSSMANN", true},
|
||||
{"BUGS", "FURRTEK", true},
|
||||
{"RDS WAVE", "C. JACQUET", true},
|
||||
{"POCSAG RX", "T. SAILER", false},
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ui_soundboard.hpp"
|
||||
|
||||
#include "ch.h"
|
||||
#include "file.hpp"
|
||||
|
||||
#include "ui_alphanum.hpp"
|
||||
#include "ff.h"
|
||||
@ -108,7 +109,9 @@ void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
|
||||
void SoundBoardView::play_sound(uint16_t id) {
|
||||
|
||||
auto error = file.open(sounds[id].filename);
|
||||
if (sounds[id].size == 0) return;
|
||||
|
||||
auto error = file.open("/wav/" + sounds[id].filename);
|
||||
if (error.is_valid()) return;
|
||||
|
||||
sample_duration = sounds[id].sample_duration;
|
||||
@ -132,7 +135,7 @@ void SoundBoardView::play_sound(uint16_t id) {
|
||||
transmitter_model.set_baseband_bandwidth(1750000);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_audiotx_data(number_bw.value());
|
||||
baseband::set_audiotx_data(1536000 / sounds[id].sample_rate, number_bw.value());
|
||||
}
|
||||
|
||||
void SoundBoardView::show_infos(uint16_t id) {
|
||||
@ -174,7 +177,6 @@ void SoundBoardView::change_page(Button& button, const KeyEvent key) {
|
||||
refresh_buttons(button.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (button.screen_pos().x > 120) {
|
||||
if ((key == KeyEvent::Right) && (page < max_page - 1)) {
|
||||
page++;
|
||||
@ -204,12 +206,12 @@ SoundBoardView::SoundBoardView(
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||
|
||||
file_list = scan_root_files(".WAV");
|
||||
file_list = scan_root_files("/wav", ".WAV");
|
||||
|
||||
c = 0;
|
||||
for (auto& file_name : file_list) {
|
||||
|
||||
auto error = file.open(file_name);
|
||||
auto error = file.open("/wav/" + file_name);
|
||||
|
||||
file.seek(40);
|
||||
file.read(file_buffer, 4);
|
||||
@ -240,7 +242,7 @@ SoundBoardView::SoundBoardView(
|
||||
sounds[c].sample_duration = size;
|
||||
|
||||
sounds[c].filename = file_name;
|
||||
sounds[c].shortname = file_name.substr(0, file_name.find_last_of("."));
|
||||
sounds[c].shortname = remove_filename_extension(file_name);
|
||||
|
||||
c++;
|
||||
if (c == 100) break;
|
||||
@ -271,8 +273,6 @@ SoundBoardView::SoundBoardView(
|
||||
};
|
||||
|
||||
const auto button_dir = [this](Button& button, const KeyEvent key) {
|
||||
(void)button;
|
||||
|
||||
this->change_page(button, key);
|
||||
};
|
||||
|
||||
|
@ -52,14 +52,14 @@ private:
|
||||
tx_modes tx_mode = NORMAL;
|
||||
|
||||
struct sound {
|
||||
std::string filename;
|
||||
std::string shortname;
|
||||
bool stereo;
|
||||
bool sixteenbit;
|
||||
uint32_t sample_rate;
|
||||
uint32_t size;
|
||||
uint32_t sample_duration;
|
||||
uint32_t ms_duration;
|
||||
std::string filename = "";
|
||||
std::string shortname = "";
|
||||
bool stereo = false;
|
||||
bool sixteenbit = false;
|
||||
uint32_t sample_rate = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t sample_duration = 0;
|
||||
uint32_t ms_duration = 0;
|
||||
};
|
||||
|
||||
uint32_t cnt;
|
||||
|
@ -34,12 +34,12 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){
|
||||
|
||||
if (!configured) return;
|
||||
|
||||
ai = 0;
|
||||
//ai = 0;
|
||||
for (size_t i = 0; i<buffer.count; i++) {
|
||||
|
||||
// Audio preview sample generation: 1536000/48000 = 32
|
||||
// Audio preview sample generation: 1536000/divider = samplerate
|
||||
if (!as) {
|
||||
as = 32;
|
||||
as = divider;
|
||||
audio_fifo.out(sample);
|
||||
//preview_audio_buffer.p[ai++] = sample << 8;
|
||||
|
||||
@ -78,6 +78,7 @@ void AudioTXProcessor::on_message(const Message* const msg) {
|
||||
// m = (262144 * a) / 1536000
|
||||
// a = 262144 / 1536000 (*1000 = 171)
|
||||
bw = 171 * (message->bw);
|
||||
divider = message->divider;
|
||||
as = 0;
|
||||
|
||||
configured = true;
|
||||
|
@ -42,7 +42,9 @@ private:
|
||||
FIFO<int8_t> audio_fifo = { audio_fifo_data, 11 }; // 43ms @ 48000Hz
|
||||
|
||||
uint32_t bw;
|
||||
uint8_t as = 0, ai;
|
||||
uint32_t divider;
|
||||
uint8_t as = 0;
|
||||
|
||||
int8_t re, im;
|
||||
int8_t sample;
|
||||
|
||||
|
@ -561,12 +561,15 @@ public:
|
||||
class AudioTXConfigMessage : public Message {
|
||||
public:
|
||||
constexpr AudioTXConfigMessage(
|
||||
const uint32_t divider,
|
||||
const uint32_t bw
|
||||
) : Message { ID::AudioTXConfig },
|
||||
divider(divider),
|
||||
bw(bw)
|
||||
{
|
||||
}
|
||||
|
||||
const uint32_t divider;
|
||||
const uint32_t bw;
|
||||
};
|
||||
|
||||
|
BIN
pictures/about.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pictures/afsk.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pictures/config.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pictures/lcr.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
pictures/ook_enc.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pictures/pocsag.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
pictures/rds.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
pictures/soundboard.png
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
pictures/xylos.png
Normal file
After Width: | Height: | Size: 5.1 KiB |