mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-02-18 13:44:14 -05:00
Add audio playback ability to WAV Viewer app (#1829)
This commit is contained in:
parent
8068517808
commit
125184f300
@ -113,6 +113,7 @@ bool save_settings(std::string_view store_name, const SettingBindings& bindings)
|
|||||||
namespace app_settings {
|
namespace app_settings {
|
||||||
|
|
||||||
enum class Mode : uint8_t {
|
enum class Mode : uint8_t {
|
||||||
|
NO_RF = 0x00,
|
||||||
RX = 0x01,
|
RX = 0x01,
|
||||||
TX = 0x02,
|
TX = 0x02,
|
||||||
RX_TX = 0x03, // Both TX/RX
|
RX_TX = 0x03, // Both TX/RX
|
||||||
|
@ -116,15 +116,16 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
|||||||
|
|
||||||
// TODO: Delete all this and use tx model.
|
// TODO: Delete all this and use tx model.
|
||||||
baseband::set_audiotx_config(
|
baseband::set_audiotx_config(
|
||||||
TONES_SAMPLERATE / 20, // Update vu-meter at 20Hz
|
1536000 / 20, // Update vu-meter at 20Hz
|
||||||
transmitter_model.channel_bandwidth(),
|
transmitter_model.channel_bandwidth(),
|
||||||
0, // Gain is unused
|
0, // Gain is unused
|
||||||
8, // shift_bits_s16, default 8 bits, but also unused
|
8, // shift_bits_s16, default 8 bits, but also unused
|
||||||
|
8, // bits per sample
|
||||||
TONES_F2D(tone_key_frequency(tone_key_index), TONES_SAMPLERATE),
|
TONES_F2D(tone_key_frequency(tone_key_index), TONES_SAMPLERATE),
|
||||||
0, // AM
|
false, // AM
|
||||||
0, // DSB
|
false, // DSB
|
||||||
0, // USB
|
false, // USB
|
||||||
0 // LSB
|
false // LSB
|
||||||
);
|
);
|
||||||
baseband::set_sample_rate(sample_rate);
|
baseband::set_sample_rate(sample_rate);
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ void MicTXView::configure_baseband() {
|
|||||||
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
||||||
mic_gain_x10 / 10.0,
|
mic_gain_x10 / 10.0,
|
||||||
shift_bits(), // to be used in dsp_modulate
|
shift_bits(), // to be used in dsp_modulate
|
||||||
|
8, // bits per sample
|
||||||
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
|
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
|
||||||
(mic_mod_index == MIC_MOD_AM),
|
(mic_mod_index == MIC_MOD_AM),
|
||||||
(mic_mod_index == MIC_MOD_DSB),
|
(mic_mod_index == MIC_MOD_DSB),
|
||||||
|
@ -22,11 +22,12 @@
|
|||||||
|
|
||||||
#include "ui_view_wav.hpp"
|
#include "ui_view_wav.hpp"
|
||||||
#include "ui_fileman.hpp"
|
#include "ui_fileman.hpp"
|
||||||
|
#include "audio.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
#include "string_format.hpp"
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
void ViewWavView::update_scale(int32_t new_scale) {
|
void ViewWavView::update_scale(int32_t new_scale) {
|
||||||
@ -81,6 +82,8 @@ void ViewWavView::load_wav(std::filesystem::path file_path) {
|
|||||||
int16_t sample;
|
int16_t sample;
|
||||||
uint32_t average;
|
uint32_t average;
|
||||||
|
|
||||||
|
wav_file_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(unit_auto_scale(ms_duration, 2, 3) + "s");
|
text_duration.set(unit_auto_scale(ms_duration, 2, 3) + "s");
|
||||||
@ -117,9 +120,90 @@ void ViewWavView::reset_controls() {
|
|||||||
field_cursor_b.set_value(0);
|
field_cursor_b.set_value(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViewWavView::is_active() {
|
||||||
|
return (bool)replay_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::stop() {
|
||||||
|
if (is_active())
|
||||||
|
replay_thread.reset();
|
||||||
|
|
||||||
|
audio::output::stop();
|
||||||
|
|
||||||
|
button_play.set_bitmap(&bitmap_play);
|
||||||
|
ready_signal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::handle_replay_thread_done(const uint32_t return_code) {
|
||||||
|
(void)return_code;
|
||||||
|
|
||||||
|
stop();
|
||||||
|
progressbar.set_value(0);
|
||||||
|
|
||||||
|
if (return_code == ReplayThread::READ_ERROR)
|
||||||
|
file_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::set_ready() {
|
||||||
|
ready_signal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::file_error() {
|
||||||
|
nav_.display_modal("Error", "File read error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::start_playback() {
|
||||||
|
uint32_t sample_rate;
|
||||||
|
|
||||||
|
auto reader = std::make_unique<WAVFileReader>();
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (!reader->open(wav_file_path)) {
|
||||||
|
file_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
button_play.set_bitmap(&bitmap_stop);
|
||||||
|
|
||||||
|
sample_rate = reader->sample_rate();
|
||||||
|
|
||||||
|
progressbar.set_max(reader->sample_count());
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
baseband::set_audiotx_config(
|
||||||
|
1536000 / 20, // Rate of sending progress updates
|
||||||
|
0, // Transmit BW = 0 = not transmitting
|
||||||
|
0, // Gain - unused
|
||||||
|
8, // shift_bits_s16, default 8 bits - unused
|
||||||
|
16, // bits per sample
|
||||||
|
0, // tone key disabled
|
||||||
|
false, // AM
|
||||||
|
false, // DSB
|
||||||
|
false, // USB
|
||||||
|
false // LSB
|
||||||
|
);
|
||||||
|
baseband::set_sample_rate(sample_rate);
|
||||||
|
|
||||||
|
audio::output::start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::on_playback_progress(const uint32_t progress) {
|
||||||
|
progressbar.set_value(progress);
|
||||||
|
}
|
||||||
|
|
||||||
ViewWavView::ViewWavView(
|
ViewWavView::ViewWavView(
|
||||||
NavigationView& nav)
|
NavigationView& nav)
|
||||||
: nav_(nav) {
|
: nav_(nav) {
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_audio_tx);
|
||||||
wav_reader = std::make_unique<WAVFileReader>();
|
wav_reader = std::make_unique<WAVFileReader>();
|
||||||
|
|
||||||
add_children({&labels,
|
add_children({&labels,
|
||||||
@ -128,21 +212,26 @@ ViewWavView::ViewWavView(
|
|||||||
&text_title,
|
&text_title,
|
||||||
&text_duration,
|
&text_duration,
|
||||||
&button_open,
|
&button_open,
|
||||||
|
&button_play,
|
||||||
&waveform,
|
&waveform,
|
||||||
|
&progressbar,
|
||||||
&field_pos_seconds,
|
&field_pos_seconds,
|
||||||
&field_pos_samples,
|
&field_pos_samples,
|
||||||
&field_scale,
|
&field_scale,
|
||||||
&field_cursor_a,
|
&field_cursor_a,
|
||||||
&field_cursor_b,
|
&field_cursor_b,
|
||||||
&text_delta});
|
&text_delta,
|
||||||
|
&field_volume});
|
||||||
|
|
||||||
reset_controls();
|
reset_controls();
|
||||||
|
|
||||||
button_open.on_select = [this, &nav](Button&) {
|
button_open.on_select = [this, &nav](Button&) {
|
||||||
auto open_view = nav.push<FileLoadView>(".WAV");
|
auto open_view = nav.push<FileLoadView>(".WAV");
|
||||||
open_view->on_changed = [this, &nav](std::filesystem::path file_path) {
|
open_view->on_changed = [this, &nav](std::filesystem::path file_path) {
|
||||||
// Can't show new dialogs in an on_changed handler, so use continuation.
|
// Can't show new dialogs in an on_changed handler, so use continuation.
|
||||||
nav.set_on_pop([this, &nav, file_path]() {
|
nav.set_on_pop([this, &nav, file_path]() {
|
||||||
if (!wav_reader->open(file_path)) {
|
if (!wav_reader->open(file_path)) {
|
||||||
nav_.display_modal("Error", "Couldn't open file.");
|
file_error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
||||||
@ -155,6 +244,15 @@ ViewWavView::ViewWavView(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
field_volume.set_value(field_volume.value());
|
||||||
|
|
||||||
|
button_play.on_select = [this, &nav](ImageButton&) {
|
||||||
|
if (this->is_active())
|
||||||
|
stop();
|
||||||
|
else
|
||||||
|
start_playback();
|
||||||
|
};
|
||||||
|
|
||||||
field_scale.on_change = [this](int32_t value) {
|
field_scale.on_change = [this](int32_t value) {
|
||||||
update_scale(value);
|
update_scale(value);
|
||||||
};
|
};
|
||||||
@ -179,4 +277,9 @@ void ViewWavView::focus() {
|
|||||||
button_open.focus();
|
button_open.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewWavView::~ViewWavView() {
|
||||||
|
stop();
|
||||||
|
baseband::shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -24,12 +24,15 @@
|
|||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "io_wave.hpp"
|
#include "io_wave.hpp"
|
||||||
#include "spectrum_color_lut.hpp"
|
#include "spectrum_color_lut.hpp"
|
||||||
|
#include "ui_receiver.hpp"
|
||||||
|
#include "replay_thread.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class ViewWavView : public View {
|
class ViewWavView : public View {
|
||||||
public:
|
public:
|
||||||
ViewWavView(NavigationView& nav);
|
ViewWavView(NavigationView& nav);
|
||||||
|
~ViewWavView();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
void paint(Painter&) override;
|
void paint(Painter&) override;
|
||||||
@ -37,6 +40,9 @@ class ViewWavView : public View {
|
|||||||
std::string title() const override { return "WAV viewer"; };
|
std::string title() const override { return "WAV viewer"; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
app_settings::SettingsManager settings_{
|
||||||
|
"wav_viewer", app_settings::Mode::NO_RF};
|
||||||
|
|
||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
static constexpr uint32_t subsampling_factor = 8;
|
static constexpr uint32_t subsampling_factor = 8;
|
||||||
|
|
||||||
@ -46,6 +52,20 @@ class ViewWavView : public View {
|
|||||||
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();
|
||||||
|
bool is_active();
|
||||||
|
void stop();
|
||||||
|
void handle_replay_thread_done(const uint32_t return_code);
|
||||||
|
void set_ready();
|
||||||
|
void file_error();
|
||||||
|
void start_playback();
|
||||||
|
void on_playback_progress(const uint32_t progress);
|
||||||
|
|
||||||
|
std::filesystem::path wav_file_path{};
|
||||||
|
std::unique_ptr<ReplayThread> replay_thread{};
|
||||||
|
bool ready_signal{false};
|
||||||
|
const size_t read_size{2048};
|
||||||
|
const size_t buffer_count{3};
|
||||||
|
const uint32_t progress_interval_samples{1536000 / 20};
|
||||||
|
|
||||||
std::unique_ptr<WAVFileReader> wav_reader{};
|
std::unique_ptr<WAVFileReader> wav_reader{};
|
||||||
|
|
||||||
@ -60,10 +80,11 @@ class ViewWavView : public View {
|
|||||||
{{0 * 8, 1 * 16}, "Samplerate:", Color::light_grey()},
|
{{0 * 8, 1 * 16}, "Samplerate:", Color::light_grey()},
|
||||||
{{0 * 8, 2 * 16}, "Title:", Color::light_grey()},
|
{{0 * 8, 2 * 16}, "Title:", Color::light_grey()},
|
||||||
{{0 * 8, 3 * 16}, "Duration:", Color::light_grey()},
|
{{0 * 8, 3 * 16}, "Duration:", Color::light_grey()},
|
||||||
{{0 * 8, 11 * 16}, "Position: s Scale:", Color::light_grey()},
|
{{0 * 8, 12 * 16}, "Position: s Scale:", Color::light_grey()},
|
||||||
{{0 * 8, 12 * 16}, "Cursor A:", Color::dark_cyan()},
|
{{0 * 8, 13 * 16}, "Cursor A:", Color::dark_cyan()},
|
||||||
{{0 * 8, 13 * 16}, "Cursor B:", Color::dark_magenta()},
|
{{0 * 8, 14 * 16}, "Cursor B:", Color::dark_magenta()},
|
||||||
{{0 * 8, 14 * 16}, "Delta:", Color::light_grey()}};
|
{{0 * 8, 15 * 16}, "Delta:", Color::light_grey()},
|
||||||
|
{{24 * 8, 18 * 16}, "Vol:", Color::light_grey()}};
|
||||||
|
|
||||||
Text text_filename{
|
Text text_filename{
|
||||||
{5 * 8, 0 * 16, 12 * 8, 16},
|
{5 * 8, 0 * 16, 12 * 8, 16},
|
||||||
@ -80,6 +101,13 @@ class ViewWavView : public View {
|
|||||||
Button button_open{
|
Button button_open{
|
||||||
{24 * 8, 8, 6 * 8, 2 * 16},
|
{24 * 8, 8, 6 * 8, 2 * 16},
|
||||||
"Open"};
|
"Open"};
|
||||||
|
ImageButton button_play{
|
||||||
|
{24 * 8, 17 * 16, 2 * 8, 1 * 16},
|
||||||
|
&bitmap_play,
|
||||||
|
Color::green(),
|
||||||
|
Color::black()};
|
||||||
|
AudioVolumeField field_volume{
|
||||||
|
{28 * 8, 18 * 16}};
|
||||||
|
|
||||||
Waveform waveform{
|
Waveform waveform{
|
||||||
{0, 5 * 16, 240, 64},
|
{0, 5 * 16, 240, 64},
|
||||||
@ -89,34 +117,29 @@ class ViewWavView : public View {
|
|||||||
false,
|
false,
|
||||||
Color::white()};
|
Color::white()};
|
||||||
|
|
||||||
|
ProgressBar progressbar{
|
||||||
|
{0 * 8, 11 * 16, 30 * 8, 8}};
|
||||||
|
|
||||||
NumberField field_pos_seconds{
|
NumberField field_pos_seconds{
|
||||||
{9 * 8, 11 * 16},
|
{9 * 8, 12 * 16},
|
||||||
3,
|
3,
|
||||||
{0, 999},
|
{0, 999},
|
||||||
1,
|
1,
|
||||||
' '};
|
' '};
|
||||||
NumberField field_pos_samples{
|
NumberField field_pos_samples{
|
||||||
{14 * 8, 11 * 16},
|
{14 * 8, 12 * 16},
|
||||||
6,
|
6,
|
||||||
{0, 999999},
|
{0, 999999},
|
||||||
1,
|
1,
|
||||||
'0'};
|
'0'};
|
||||||
NumberField field_scale{
|
NumberField field_scale{
|
||||||
{28 * 8, 11 * 16},
|
{28 * 8, 12 * 16},
|
||||||
2,
|
2,
|
||||||
{1, 40},
|
{1, 40},
|
||||||
1,
|
1,
|
||||||
' '};
|
' '};
|
||||||
|
|
||||||
NumberField field_cursor_a{
|
NumberField field_cursor_a{
|
||||||
{9 * 8, 12 * 16},
|
|
||||||
3,
|
|
||||||
{0, 239},
|
|
||||||
1,
|
|
||||||
' ',
|
|
||||||
true};
|
|
||||||
|
|
||||||
NumberField field_cursor_b{
|
|
||||||
{9 * 8, 13 * 16},
|
{9 * 8, 13 * 16},
|
||||||
3,
|
3,
|
||||||
{0, 239},
|
{0, 239},
|
||||||
@ -124,9 +147,40 @@ class ViewWavView : public View {
|
|||||||
' ',
|
' ',
|
||||||
true};
|
true};
|
||||||
|
|
||||||
|
NumberField field_cursor_b{
|
||||||
|
{9 * 8, 14 * 16},
|
||||||
|
3,
|
||||||
|
{0, 239},
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
true};
|
||||||
|
|
||||||
Text text_delta{
|
Text text_delta{
|
||||||
{6 * 8, 14 * 16, 30 * 8, 16},
|
{7 * 8, 15 * 16, 30 * 8, 16},
|
||||||
"-"};
|
"-"};
|
||||||
|
|
||||||
|
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->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_playback_progress(message.progress);
|
||||||
|
}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -211,6 +211,7 @@ void set_audiotx_config(
|
|||||||
const float deviation_hz,
|
const float deviation_hz,
|
||||||
const float audio_gain,
|
const float audio_gain,
|
||||||
uint8_t audio_shift_bits_s16,
|
uint8_t audio_shift_bits_s16,
|
||||||
|
uint8_t bits_per_sample,
|
||||||
const uint32_t tone_key_delta,
|
const uint32_t tone_key_delta,
|
||||||
const bool am_enabled,
|
const bool am_enabled,
|
||||||
const bool dsb_enabled,
|
const bool dsb_enabled,
|
||||||
@ -221,6 +222,7 @@ void set_audiotx_config(
|
|||||||
deviation_hz,
|
deviation_hz,
|
||||||
audio_gain,
|
audio_gain,
|
||||||
audio_shift_bits_s16,
|
audio_shift_bits_s16,
|
||||||
|
bits_per_sample,
|
||||||
tone_key_delta,
|
tone_key_delta,
|
||||||
(float)persistent_memory::tone_mix() / 100.0f,
|
(float)persistent_memory::tone_mix() / 100.0f,
|
||||||
am_enabled,
|
am_enabled,
|
||||||
|
@ -63,7 +63,7 @@ void set_tone(const uint32_t index, const uint32_t delta, const uint32_t duratio
|
|||||||
void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out);
|
void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint16_t tone_count, const bool dual_tone, const bool audio_out);
|
||||||
void kill_tone();
|
void kill_tone();
|
||||||
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
|
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
|
||||||
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, uint8_t audio_shift_bits_s16, const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, const bool usb_enabled, const bool lsb_enabled);
|
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, uint8_t audio_shift_bits_s16, uint8_t bits_per_sample, const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, const bool usb_enabled, const bool lsb_enabled);
|
||||||
void set_fifo_data(const int8_t* data);
|
void set_fifo_data(const int8_t* data);
|
||||||
void set_pitch_rssi(int32_t avg, bool enabled);
|
void set_pitch_rssi(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, const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
|
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, const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
|
||||||
|
@ -30,23 +30,31 @@
|
|||||||
void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
|
void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
|
||||||
if (!configured) return;
|
if (!configured) return;
|
||||||
|
|
||||||
|
int32_t audio_sample_m;
|
||||||
|
|
||||||
// Zero-order hold (poop)
|
// Zero-order hold (poop)
|
||||||
for (size_t i = 0; i < buffer.count; i++) {
|
for (size_t i = 0; i < buffer.count; i++) {
|
||||||
resample_acc += resample_inc;
|
resample_acc += resample_inc;
|
||||||
if (resample_acc >= 0x10000) {
|
if (resample_acc >= 0x10000) {
|
||||||
resample_acc -= 0x10000;
|
resample_acc -= 0x10000;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
stream->read(&audio_sample, 1);
|
audio_sample = 0;
|
||||||
bytes_read++;
|
stream->read(&audio_sample, bytes_per_sample); // assumes little endian when reading 1 byte
|
||||||
|
samples_read++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = audio_sample - 0x80;
|
if (bytes_per_sample == 1) {
|
||||||
|
sample = audio_sample - 0x80;
|
||||||
|
audio_sample_m = sample * 256;
|
||||||
|
} else {
|
||||||
|
audio_sample_m = audio_sample;
|
||||||
|
}
|
||||||
|
|
||||||
// Output to speaker too
|
// Output to speaker too
|
||||||
if (!tone_key_enabled) {
|
if (!tone_key_enabled) {
|
||||||
uint32_t imod32 = i & (AUDIO_OUTPUT_BUFFER_SIZE - 1);
|
uint32_t imod32 = i & (AUDIO_OUTPUT_BUFFER_SIZE - 1);
|
||||||
audio_data[imod32] = sample * 256;
|
audio_data[imod32] = audio_sample_m;
|
||||||
if (imod32 == (AUDIO_OUTPUT_BUFFER_SIZE - 1))
|
if (imod32 == (AUDIO_OUTPUT_BUFFER_SIZE - 1))
|
||||||
audio_output.write_unprocessed(audio_buffer);
|
audio_output.write_unprocessed(audio_buffer);
|
||||||
}
|
}
|
||||||
@ -69,7 +77,7 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
|
|||||||
if (progress_samples >= progress_interval_samples) {
|
if (progress_samples >= progress_interval_samples) {
|
||||||
progress_samples -= progress_interval_samples;
|
progress_samples -= progress_interval_samples;
|
||||||
|
|
||||||
txprogress_message.progress = bytes_read; // Inform UI about progress
|
txprogress_message.progress = samples_read; // Inform UI about progress
|
||||||
txprogress_message.done = false;
|
txprogress_message.done = false;
|
||||||
shared_memory.application_queue.push(txprogress_message);
|
shared_memory.application_queue.push(txprogress_message);
|
||||||
}
|
}
|
||||||
@ -83,7 +91,7 @@ void AudioTXProcessor::on_message(const Message* const message) {
|
|||||||
|
|
||||||
case Message::ID::ReplayConfig:
|
case Message::ID::ReplayConfig:
|
||||||
configured = false;
|
configured = false;
|
||||||
bytes_read = 0;
|
samples_read = 0;
|
||||||
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
|
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -105,6 +113,7 @@ void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
|
|||||||
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
||||||
progress_interval_samples = message.divider;
|
progress_interval_samples = message.divider;
|
||||||
resample_acc = 0;
|
resample_acc = 0;
|
||||||
|
bytes_per_sample = message.bits_per_sample / 8;
|
||||||
audio_output.configure(false);
|
audio_output.configure(false);
|
||||||
|
|
||||||
tone_key_enabled = (message.tone_key_delta != 0);
|
tone_key_enabled = (message.tone_key_delta != 0);
|
||||||
|
@ -48,9 +48,11 @@ class AudioTXProcessor : public BasebandProcessor {
|
|||||||
uint32_t resample_inc{}, resample_acc{};
|
uint32_t resample_inc{}, resample_acc{};
|
||||||
uint32_t fm_delta{0};
|
uint32_t fm_delta{0};
|
||||||
uint32_t phase{0}, sphase{0};
|
uint32_t phase{0}, sphase{0};
|
||||||
uint8_t audio_sample{};
|
uint32_t audio_sample{};
|
||||||
int32_t sample{0}, delta{};
|
int32_t sample{0}, delta{};
|
||||||
int8_t re{0}, im{0};
|
int8_t re{0}, im{0};
|
||||||
|
int8_t bytes_per_sample{1};
|
||||||
|
int16_t audio_sample_s16{};
|
||||||
|
|
||||||
int16_t audio_data[AUDIO_OUTPUT_BUFFER_SIZE];
|
int16_t audio_data[AUDIO_OUTPUT_BUFFER_SIZE];
|
||||||
buffer_s16_t audio_buffer{audio_data, AUDIO_OUTPUT_BUFFER_SIZE, 48000};
|
buffer_s16_t audio_buffer{audio_data, AUDIO_OUTPUT_BUFFER_SIZE, 48000};
|
||||||
@ -59,7 +61,7 @@ class AudioTXProcessor : public BasebandProcessor {
|
|||||||
size_t progress_interval_samples = 0, progress_samples = 0;
|
size_t progress_interval_samples = 0, progress_samples = 0;
|
||||||
|
|
||||||
bool configured{false};
|
bool configured{false};
|
||||||
uint32_t bytes_read{0};
|
uint32_t samples_read{0};
|
||||||
bool tone_key_enabled{false};
|
bool tone_key_enabled{false};
|
||||||
|
|
||||||
void sample_rate_config(const SampleRateConfigMessage& message);
|
void sample_rate_config(const SampleRateConfigMessage& message);
|
||||||
|
@ -931,6 +931,7 @@ class AudioTXConfigMessage : public Message {
|
|||||||
const float deviation_hz,
|
const float deviation_hz,
|
||||||
const float audio_gain,
|
const float audio_gain,
|
||||||
const uint8_t audio_shift_bits_s16,
|
const uint8_t audio_shift_bits_s16,
|
||||||
|
const uint8_t bits_per_sample,
|
||||||
const uint32_t tone_key_delta,
|
const uint32_t tone_key_delta,
|
||||||
const float tone_key_mix_weight,
|
const float tone_key_mix_weight,
|
||||||
const bool am_enabled,
|
const bool am_enabled,
|
||||||
@ -942,6 +943,7 @@ class AudioTXConfigMessage : public Message {
|
|||||||
deviation_hz(deviation_hz),
|
deviation_hz(deviation_hz),
|
||||||
audio_gain(audio_gain),
|
audio_gain(audio_gain),
|
||||||
audio_shift_bits_s16(audio_shift_bits_s16),
|
audio_shift_bits_s16(audio_shift_bits_s16),
|
||||||
|
bits_per_sample(bits_per_sample),
|
||||||
tone_key_delta(tone_key_delta),
|
tone_key_delta(tone_key_delta),
|
||||||
tone_key_mix_weight(tone_key_mix_weight),
|
tone_key_mix_weight(tone_key_mix_weight),
|
||||||
am_enabled(am_enabled),
|
am_enabled(am_enabled),
|
||||||
@ -954,6 +956,7 @@ class AudioTXConfigMessage : public Message {
|
|||||||
const float deviation_hz;
|
const float deviation_hz;
|
||||||
const float audio_gain;
|
const float audio_gain;
|
||||||
const uint8_t audio_shift_bits_s16;
|
const uint8_t audio_shift_bits_s16;
|
||||||
|
const uint8_t bits_per_sample;
|
||||||
const uint32_t tone_key_delta;
|
const uint32_t tone_key_delta;
|
||||||
const float tone_key_mix_weight;
|
const float tone_key_mix_weight;
|
||||||
const bool am_enabled;
|
const bool am_enabled;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user