Merge pull request #329 from aldude999/next

AM/SSB/DSB Microphone Functionality
This commit is contained in:
Erwin Ried 2021-04-14 09:26:09 +02:00 committed by GitHub
commit e21fbbf234
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 675 additions and 16 deletions

View File

@ -110,7 +110,11 @@ void SoundBoardView::start_tx(const uint32_t id) {
1536000 / 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
TONES_F2D(tone_key_frequency(tone_key_index), 1536000) TONES_F2D(tone_key_frequency(tone_key_index), 1536000),
0, //AM
0, //DSB
0, //USB
0 //LSB
); );
baseband::set_sample_rate(sample_rate); baseband::set_sample_rate(sample_rate);

View File

@ -65,8 +65,13 @@ void MicTXView::configure_baseband() {
sampling_rate / 20, // Update vu-meter at 20Hz sampling_rate / 20, // Update vu-meter at 20Hz
transmitting ? transmitter_model.channel_bandwidth() : 0, transmitting ? transmitter_model.channel_bandwidth() : 0,
mic_gain, mic_gain,
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate) TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
enable_am,
enable_dsb,
enable_usb,
enable_lsb
); );
} }
void MicTXView::set_tx(bool enable) { void MicTXView::set_tx(bool enable) {
@ -143,8 +148,20 @@ void MicTXView::rxaudio(bool is_on) {
if (is_on) { if (is_on) {
audio::input::stop(); audio::input::stop();
baseband::shutdown(); baseband::shutdown();
if (enable_am || enable_usb || enable_lsb || enable_dsb) {
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
if (options_mode.selected_index() < 4)
receiver_model.set_am_configuration(options_mode.selected_index() - 1);
else
receiver_model.set_am_configuration(0);
}
else {
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
}
receiver_model.set_sampling_rate(3072000); receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000); receiver_model.set_baseband_bandwidth(1750000);
// receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out. // receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
@ -155,15 +172,15 @@ void MicTXView::rxaudio(bool is_on) {
receiver_model.enable(); receiver_model.enable();
audio::output::start(); audio::output::start();
} else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX. } else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); //This fixes something with AM RX...
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
baseband::run_image(portapack::spi_flash::image_tag_mic_tx); baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
audio::output::stop();
audio::input::start(); audio::input::start();
// transmitter_model.enable();
portapack::pin_i2s0_rx_sda.mode(3); portapack::pin_i2s0_rx_sda.mode(3);
// transmitting = false;
configure_baseband(); configure_baseband();
// transmitter_model.disable();
} }
} }
@ -198,11 +215,13 @@ MicTXView::MicTXView(
&field_bw, &field_bw,
&field_rfgain, &field_rfgain,
&field_rfamp, &field_rfamp,
&options_mode,
&field_frequency, &field_frequency,
&options_tone_key, &options_tone_key,
&check_rogerbeep, &check_rogerbeep,
&check_rxactive, &check_rxactive,
&field_volume, &field_volume,
&field_rxbw,
&field_squelch, &field_squelch,
&field_rxfrequency, &field_rxfrequency,
&field_rxlna, &field_rxlna,
@ -262,6 +281,42 @@ MicTXView::MicTXView(
}; };
field_rfamp.set_value(rf_amp ? 14 : 0); field_rfamp.set_value(rf_amp ? 14 : 0);
options_mode.on_change = [this](size_t, int32_t v) {
enable_am = false;
enable_usb = false;
enable_lsb = false;
enable_dsb = false;
switch(v) {
case 0:
enable_am = false;
enable_usb = false;
enable_lsb = false;
enable_dsb = false;
field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
//if (rx_enabled)
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 1:
enable_am = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 2:
enable_usb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 3:
enable_lsb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 4:
enable_dsb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
}
//configure_baseband();
};
/* /*
check_va.on_select = [this](Checkbox&, bool v) { check_va.on_select = [this](Checkbox&, bool v) {
va_enabled = v; va_enabled = v;
@ -331,6 +386,21 @@ MicTXView::MicTXView(
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
field_rxbw.on_change = [this](size_t, int32_t v) {
switch(v) {
case 0:
receiver_model.set_nbfm_configuration(0);
break;
case 1:
receiver_model.set_nbfm_configuration(1);
break;
case 2:
receiver_model.set_nbfm_configuration(2);
break;
}
};
field_rxbw.set_selected_index(2);
field_squelch.on_change = [this](int32_t v) { field_squelch.on_change = [this](int32_t v) {
receiver_model.set_squelch_level(100 - v); receiver_model.set_squelch_level(100 - v);
}; };

View File

@ -99,19 +99,27 @@ private:
int32_t focused_ui { 2 }; int32_t focused_ui { 2 };
bool button_touch { false }; bool button_touch { false };
//AM TX Stuff
bool enable_am { false };
bool enable_dsb { false };
bool enable_usb { false };
bool enable_lsb { false };
Labels labels { Labels labels {
{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() }, { { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
{ { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() },
{ { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() }, { { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() },
{ { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
{ {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() }, { {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() },
{ { 18 * 8, (5 * 8) }, "Mode:", Color::light_grey() },
{ { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() }, { { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() },
{ { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() }, { { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() },
{ {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() }, { {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() },
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() }, { {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() }, { { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
{ { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() }, { { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() },
{ {17 * 8, 23 * 8 }, "FM RXBW:", Color::light_grey() },
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() }, { {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() }, { { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()}, { { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
@ -162,6 +170,18 @@ private:
14, 14,
' ' ' '
}; };
OptionsField options_mode {
{ 24 * 8, 5 * 8 },
3,
{
{ "FM", 0 },
{ "AM", 1 },
{ "USB", 2 },
{ "LSB", 3 },
{ "DSB", 4 }
}
};
/* /*
Checkbox check_va { Checkbox check_va {
{ 3 * 8, (10 * 8) - 4 }, { 3 * 8, (10 * 8) - 4 },
@ -231,6 +251,16 @@ private:
' ', ' ',
}; };
OptionsField field_rxbw {
{ 25 * 8, 23 * 8},
3,
{
{"8k5", 0},
{"11k", 1},
{"16k", 2}
}
};
NumberField field_squelch { NumberField field_squelch {
{ 20 * 8, 25 * 8 }, { 20 * 8, 25 * 8 },
2, 2,

View File

@ -176,13 +176,18 @@ void kill_afsk() {
} }
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
const uint32_t tone_key_delta) { const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled,
const bool usb_enabled, const bool lsb_enabled) {
const AudioTXConfigMessage message { const AudioTXConfigMessage message {
divider, divider,
deviation_hz, deviation_hz,
audio_gain, audio_gain,
tone_key_delta, tone_key_delta,
(float)persistent_memory::tone_mix() / 100.0f (float)persistent_memory::tone_mix() / 100.0f,
am_enabled,
dsb_enabled,
usb_enabled,
lsb_enabled
}; };
send_message(&message); send_message(&message);
} }

View File

@ -61,7 +61,8 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1
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, void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
const uint32_t tone_key_delta); 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, 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,

View File

@ -113,6 +113,8 @@ set(CPPSRC
baseband_stats_collector.cpp baseband_stats_collector.cpp
dsp_decimate.cpp dsp_decimate.cpp
dsp_demodulate.cpp dsp_demodulate.cpp
dsp_hilbert.cpp
dsp_modulate.cpp
dsp_goertzel.cpp dsp_goertzel.cpp
matched_filter.cpp matched_filter.cpp
spectrum_collector.cpp spectrum_collector.cpp
@ -125,6 +127,7 @@ set(CPPSRC
${COMMON}/dsp_fft.cpp ${COMMON}/dsp_fft.cpp
${COMMON}/dsp_fir_taps.cpp ${COMMON}/dsp_fir_taps.cpp
${COMMON}/dsp_iir.cpp ${COMMON}/dsp_iir.cpp
${COMMON}/dsp_sos.cpp
fxpt_atan2.cpp fxpt_atan2.cpp
rssi.cpp rssi.cpp
rssi_dma.cpp rssi_dma.cpp

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_hilbert.hpp"
#include "dsp_sos_config.hpp"
namespace dsp {
HilbertTransform::HilbertTransform() {
n = 0;
sos_i.configure(half_band_lpf_config);
sos_q.configure(half_band_lpf_config);
}
void HilbertTransform::execute(float in, float &out_i, float &out_q) {
float a = 0, b = 0;
switch (n) {
case 0: a = in; b = 0; break;
case 1: a = 0; b = -in; break;
case 2: a = -in; b = 0; break;
case 3: a = 0; b = in; break;
}
float i = sos_i.execute(a) * 2.0f;
float q = sos_q.execute(b) * 2.0f;
switch (n) {
case 0: out_i = i; out_q = q; break;
case 1: out_i = -q; out_q = i; break;
case 2: out_i = -i; out_q = -q; break;
case 3: out_i = q; out_q = -i; break;
}
n = (n + 1) % 4;
}
} /* namespace dsp */

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_HILBERT_H__
#define __DSP_HILBERT_H__
#include "dsp_sos.hpp"
#include "dsp_types.hpp"
namespace dsp {
class HilbertTransform {
public:
HilbertTransform();
void execute(float in, float &out_i, float &out_q);
private:
uint8_t n = 0;
SOSFilter<5> sos_i;
SOSFilter<5> sos_q;
};
} /* namespace dsp */
#endif/*__DSP_HILBERT_H__*/

View File

@ -0,0 +1,137 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_modulate.hpp"
#include "sine_table_int8.hpp"
namespace dsp {
namespace modulate {
Modulator::~Modulator() {
}
Mode Modulator::get_mode() {
return mode;
}
void Modulator::set_mode(Mode new_mode) {
mode = new_mode;
}
void Modulator::set_over(uint32_t new_over) {
over = new_over;
}
///
SSB::SSB() : hilbert() {
mode = Mode::LSB;
}
void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re = 0, im = 0;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % 128 == 0) {
float i = 0.0, q = 0.0;
sample = audio.p[counter / over] >> 2;
//switch (mode) {
//case Mode::LSB:
hilbert.execute(sample / 32768.0f, i, q);
//case Mode::USB: hilbert.execute(sample / 32768.0f, q, i);
//default: break;
//}
i *= 64.0f;
q *= 64.0f;
switch (mode) {
case Mode::LSB: re = q; im = i; break;
case Mode::USB: re = i; im = q; break;
default: re = 0; im = 0; break;
}
//re = q;
//im = i;
//break;
}
buffer.p[counter] = { re, im };
}
}
///
FM::FM() {
mode = Mode::FM;
}
void FM::set_fm_delta(uint32_t new_delta) {
fm_delta = new_delta;
}
void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re, im;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % over == 0) {
sample = audio.p[counter / over] >> 8;
delta = sample * fm_delta;
}
phase += delta;
sphase = phase >> 24;
re = (sine_table_i8[(sphase + 64) & 255]);
im = (sine_table_i8[sphase]);
buffer.p[counter] = { re, im };
}
}
AM::AM() {
mode = Mode::AM;
}
void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re, im;
float q = 0.0;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % 128 == 0) {
sample = audio.p[counter / over] >> 2;
}
q = sample / 32768.0f;
q *= 64.0f;
switch (mode) {
case Mode::AM: re = q + 20; im = q + 20;
case Mode::DSB: re = q; im = q;
default: break;
}
buffer.p[counter] = { re, im };
}
}
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_MODULATE_H__
#define __DSP_MODULATE_H__
#include "dsp_types.hpp"
#include "dsp_hilbert.hpp"
namespace dsp {
namespace modulate {
enum class Mode {
None,
AM,
DSB,
LSB,
USB,
FM
};
///
class Modulator {
public:
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) = 0;
virtual ~Modulator();
Mode get_mode();
void set_mode(Mode new_mode);
void set_over(uint32_t new_over);
protected:
uint32_t over = 1;
Mode mode = Mode::None;
};
///
class SSB : public Modulator {
public:
SSB();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
private:
dsp::HilbertTransform hilbert;
};
///
class FM : public Modulator {
public:
FM();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
void set_fm_delta(uint32_t new_delta);
///
private:
uint32_t fm_delta { 0 };
uint32_t phase { 0 }, sphase { 0 };
int32_t sample { 0 }, delta { };
};
class AM : public Modulator {
public:
AM();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
};
} /* namespace modulate */
} /* namespace dsp */
#endif/*__DSP_MODULATE_H__*/

View File

@ -35,6 +35,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
if (!configured) return; if (!configured) return;
audio_input.read_audio_buffer(audio_buffer); audio_input.read_audio_buffer(audio_buffer);
modulator->execute(audio_buffer, buffer);
for (size_t i = 0; i < buffer.count; i++) { for (size_t i = 0; i < buffer.count; i++) {
@ -70,6 +71,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
sample = beep_gen.process(0); sample = beep_gen.process(0);
} }
/*
sample = tone_gen.process(sample); sample = tone_gen.process(sample);
// FM // FM
@ -87,6 +89,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
} }
buffer.p[i] = { re, im }; buffer.p[i] = { re, im };
*/
} }
} }
@ -96,7 +99,40 @@ void MicTXProcessor::on_message(const Message* const msg) {
switch(msg->id) { switch(msg->id) {
case Message::ID::AudioTXConfig: case Message::ID::AudioTXConfig:
fm_delta = config_message.deviation_hz * (0xFFFFFFUL / baseband_fs); if (fm_enabled) {
dsp::modulate::FM *fm = new dsp::modulate::FM();
fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs));
modulator = fm;
}
if (usb_enabled) {
modulator = new dsp::modulate::SSB();
modulator->set_mode(dsp::modulate::Mode::USB);
}
if (lsb_enabled) {
modulator = new dsp::modulate::SSB();
modulator->set_mode(dsp::modulate::Mode::LSB);
}
if (am_enabled) {
modulator = new dsp::modulate::AM();
modulator->set_mode(dsp::modulate::Mode::AM);
}
if (dsb_enabled) {
modulator = new dsp::modulate::AM();
modulator->set_mode(dsp::modulate::Mode::DSB);
}
modulator->set_over(baseband_fs / 24000);
am_enabled = config_message.am_enabled;
usb_enabled = config_message.usb_enabled;
lsb_enabled = config_message.lsb_enabled;
dsb_enabled = config_message.dsb_enabled;
if (!am_enabled || !usb_enabled || !lsb_enabled || !dsb_enabled) {
fm_enabled = true;
}
audio_gain = config_message.audio_gain; audio_gain = config_message.audio_gain;
divider = config_message.divider; divider = config_message.divider;

View File

@ -27,6 +27,7 @@
#include "baseband_thread.hpp" #include "baseband_thread.hpp"
#include "audio_input.hpp" #include "audio_input.hpp"
#include "tone_gen.hpp" #include "tone_gen.hpp"
#include "dsp_modulate.hpp"
class MicTXProcessor : public BasebandProcessor { class MicTXProcessor : public BasebandProcessor {
public: public:
@ -50,6 +51,13 @@ private:
AudioInput audio_input { }; AudioInput audio_input { };
ToneGen tone_gen { }; ToneGen tone_gen { };
ToneGen beep_gen { }; ToneGen beep_gen { };
dsp::modulate::Modulator *modulator;
bool am_enabled { false };
bool fm_enabled { true };
bool usb_enabled { false };
bool lsb_enabled { false };
bool dsb_enabled { false };
uint32_t divider { }; uint32_t divider { };
float audio_gain { }; float audio_gain { };

View File

@ -55,3 +55,29 @@ void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t&
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) { void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
execute(buffer, buffer); execute(buffer, buffer);
} }
void IIRBiquadDF2Filter::configure(const iir_biquad_df2_config_t& config) {
b0 = config[0] / config[3];
b1 = config[1] / config[3];
b2 = config[2] / config[3];
a1 = config[4] / config[3];
a2 = config[5] / config[3];
}
// scipy.signal.sosfilt
//
// x_n = x[i, n] # make a temporary copy
// # Use direct II transposed structure:
// x[i, n] = b[s, 0] * x_n + zi[i, s, 0]
// zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1])
// zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n])
float IIRBiquadDF2Filter::execute(float x) {
float y;
y = b0 * x + z0;
z0 = b1 * x - a1 * y + z1;
z1 = b2 * x - a2 * y;
return y;
}

View File

@ -31,6 +31,9 @@ struct iir_biquad_config_t {
std::array<float, 3> a; std::array<float, 3> a;
}; };
// 0..2 - b, 3..5 - a
typedef std::array<float, 6> iir_biquad_df2_config_t;
constexpr iir_biquad_config_t iir_config_passthrough { constexpr iir_biquad_config_t iir_config_passthrough {
{ { 1.0f, 0.0f, 0.0f } }, { { 1.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } }, { { 0.0f, 0.0f, 0.0f } },
@ -67,4 +70,21 @@ private:
std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } }; std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
}; };
class IIRBiquadDF2Filter {
public:
void configure(const iir_biquad_df2_config_t& config);
float execute(float z);
private:
float b0 = 0;
float b1 = 0;
float b2 = 0;
float a1 = 0;
float a2 = 0;
float z0 = 0;
float z1 = 0;
};
#endif/*__DSP_IIR_H__*/ #endif/*__DSP_IIR_H__*/

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_sos.hpp"

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SOS_H__
#define __DSP_SOS_H__
#include "dsp_iir.hpp"
#include <cstdint>
#include <cstddef>
template <size_t N>
class SOSFilter {
public:
void configure(const iir_biquad_df2_config_t config[N]) {
for (size_t i = 0; i < N; i++)
filters[i].configure(config[i]);
}
float execute(float value) {
for (auto &filter : filters)
value = filter.execute(value);
return value;
}
private:
IIRBiquadDF2Filter filters[N];
};
#endif/*__DSP_SOS_H__*/

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SOS_CONFIG_H__
#define __DSP_SOS_CONFIG_H__
#include "dsp_iir.hpp"
// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.5, btype = 'lowpass', output="sos")
constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = {
{ 0.02339042f, 0.0411599f, 0.02339042f, 1.0f, -0.95317621f, 0.33446485f },
{ 1.0f, 0.82196114f, 1.0f, 1.0f, -0.50327735f, 0.63611027f },
{ 1.0f, 0.32515305f, 1.0f, 1.0f, -0.18144446f, 0.85269598f },
{ 1.0f, 0.14394122f, 1.0f, 1.0f, -0.04368236f, 0.94798064f },
{ 1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f }
};
#endif/*__DSP_SOS_CONFIG_H__*/

View File

@ -856,13 +856,21 @@ public:
const float deviation_hz, const float deviation_hz,
const float audio_gain, const float audio_gain,
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 dsb_enabled,
const bool usb_enabled,
const bool lsb_enabled
) : Message { ID::AudioTXConfig }, ) : Message { ID::AudioTXConfig },
divider(divider), divider(divider),
deviation_hz(deviation_hz), deviation_hz(deviation_hz),
audio_gain(audio_gain), audio_gain(audio_gain),
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),
dsb_enabled(dsb_enabled),
usb_enabled(usb_enabled),
lsb_enabled(lsb_enabled)
{ {
} }
@ -871,6 +879,10 @@ public:
const float audio_gain; const float audio_gain;
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 dsb_enabled;
const bool usb_enabled;
const bool lsb_enabled;
}; };
class SigGenConfigMessage : public Message { class SigGenConfigMessage : public Message {