diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 8d08d31c..d8867d8d 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -153,13 +153,13 @@ void kill_afsk() { } void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t gain_x10, - const bool ctcss_enabled, const uint32_t ctcss_phase_inc) { + const uint32_t tone_key_delta, const float tone_key_mix_weight) { const AudioTXConfigMessage message { divider, bw, gain_x10, - ctcss_phase_inc, - ctcss_enabled + tone_key_delta, + tone_key_mix_weight }; send_message(&message); } diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 274af133..78b93950 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -61,7 +61,7 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1 void kill_tone(); void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration); void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t gain_x10, - const bool ctcss_enabled, const uint32_t ctcss_phase_inc); + const uint32_t tone_key_delta, const float tone_key_mix_weight); 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, diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 19d1bf28..3307cecb 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -217,7 +217,7 @@ std::string filesystem_error::what() const { case FR_OK: return "ok"; case FR_DISK_ERR: return "disk error"; case FR_INT_ERR: return "insanity detected"; - case FR_NOT_READY: return "not ready"; + case FR_NOT_READY: return "SD card not ready"; case FR_NO_FILE: return "no file"; case FR_NO_PATH: return "no path"; case FR_INVALID_NAME: return "invalid name"; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index ded06ac9..3bfc3dc8 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -33,7 +33,6 @@ //BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one //BUG: SCANNER Multiple slices -//TODO: Make tone generator class for baseband (with freq, samplerate and mixing ratio parameters) //TODO: Cap Wav viewer position //TODO: Adapt wav viewer position step //TODO: Use unit_auto_scale diff --git a/firmware/application/tone_key.cpp b/firmware/application/tone_key.cpp index c34c1853..044e8e26 100644 --- a/firmware/application/tone_key.cpp +++ b/firmware/application/tone_key.cpp @@ -26,6 +26,7 @@ namespace tonekey { const tone_key_t tone_keys[] = { + { "None", 0.0 }, { "0 XZ", 67.000 }, { "1 WZ", 69.400 }, { "2 XA", 71.900 }, @@ -88,9 +89,8 @@ void tone_keys_populate(OptionsField& field) { options_t tone_key_options; std::string tone_name; - tone_key_options.emplace_back(std::make_pair("None", 0)); for (size_t c = 0; c < KEY_TONES_NB; c++) { - if (c < 50) + if (c && (c < 51)) tone_name = "CTCSS " + tone_keys[c].first; else tone_name = tone_keys[c].first; diff --git a/firmware/application/ui_mictx.cpp b/firmware/application/ui_mictx.cpp index 5b231434..f0d41808 100644 --- a/firmware/application/ui_mictx.cpp +++ b/firmware/application/ui_mictx.cpp @@ -59,8 +59,8 @@ void MicTXView::configure_baseband() { sampling_rate / 20, // Update vu-meter at 20Hz transmitting ? transmitter_model.channel_bandwidth() : 0, mic_gain_x10, - transmitting ? tone_key_enabled : false, - TONES_F2D(tone_keys[tone_key_index].second) + TONES_F2D(tone_keys[tone_key_index].second), + 0.2 // 20% mix ); } @@ -150,12 +150,6 @@ MicTXView::MicTXView( tone_keys_populate(options_tone_key); options_tone_key.on_change = [this](size_t i, int32_t) { tone_key_index = i; - - if (tone_key_index) { - tone_key_enabled = true; - tone_key_index--; - } else - tone_key_enabled = false; }; options_tone_key.set_selected_index(0); diff --git a/firmware/application/ui_mictx.hpp b/firmware/application/ui_mictx.hpp index 50c3f9f9..7663d5dc 100644 --- a/firmware/application/ui_mictx.hpp +++ b/firmware/application/ui_mictx.hpp @@ -73,7 +73,6 @@ private: bool va_enabled { }; bool rogerbeep_enabled { }; uint32_t tone_key_index { }; - bool tone_key_enabled { }; uint32_t mic_gain_x10 { 10 }; uint32_t audio_level { 0 }; uint32_t va_level { }; diff --git a/firmware/application/ui_soundboard.cpp b/firmware/application/ui_soundboard.cpp index d48234a2..d4adfd65 100644 --- a/firmware/application/ui_soundboard.cpp +++ b/firmware/application/ui_soundboard.cpp @@ -26,6 +26,7 @@ #include "lfsr_random.hpp" #include "string_format.hpp" +#include "tonesets.hpp" using namespace tonekey; using namespace portapack; @@ -96,7 +97,6 @@ void SoundBoardView::on_tuning_frequency_changed(rf::Frequency f) { void SoundBoardView::play_sound(uint16_t id) { uint32_t tone_key_index; - bool tone_key_enabled; uint32_t divider; if (sounds[id].size == 0) return; @@ -121,20 +121,14 @@ void SoundBoardView::play_sound(uint16_t id) { tone_key_index = options_tone_key.selected_index(); - if (tone_key_index) { - tone_key_enabled = true; - tone_key_index--; - } else - tone_key_enabled = false; - divider = (1536000 / sounds[id].sample_rate) - 1; baseband::set_audiotx_data( divider, number_bw.value() * 1000, - 1, - tone_key_enabled, - (uint32_t)((tone_keys[tone_key_index].second / 1536000.0) * 0xFFFFFFFFULL) + 10, + TONES_F2D(tone_keys[tone_key_index].second), + 0.2 // 20% mix ); } diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 7346f89f..9ca339fd 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -136,6 +136,7 @@ set(CPPSRC ${COMMON}/chibios_cpp.cpp ${COMMON}/debug.cpp ${COMMON}/gcc.cpp + tone_gen.cpp ) # C sources to be compiled in ARM mode regardless of the global setting. diff --git a/firmware/baseband/proc_audiotx.cpp b/firmware/baseband/proc_audiotx.cpp index 7d422e36..cf39cfe8 100644 --- a/firmware/baseband/proc_audiotx.cpp +++ b/firmware/baseband/proc_audiotx.cpp @@ -52,16 +52,10 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){ as--; } - if (ctcss_enabled) { - ctcss_sample = sine_table_i8[(ctcss_phase & 0xFF000000U) >> 24]; - sample_mixed = ((sample * 205) + (ctcss_sample * 50)) / 256; // ~20% - ctcss_phase += ctcss_phase_inc; - } else { - sample_mixed = sample; - } + sample = tone_gen.process(sample); // FM - delta = sample_mixed * fm_delta; + delta = sample * fm_delta; phase += delta; sphase = phase + (64 << 24); @@ -82,9 +76,9 @@ void AudioTXProcessor::on_message(const Message* const msg) { case Message::ID::AudioTXConfig: fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000); divider = message.divider; - ctcss_enabled = message.ctcss_enabled; - ctcss_phase_inc = message.ctcss_phase_inc; as = 0; + + tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight); configured = true; break; diff --git a/firmware/baseband/proc_audiotx.hpp b/firmware/baseband/proc_audiotx.hpp index d5414093..d5a6d56e 100644 --- a/firmware/baseband/proc_audiotx.hpp +++ b/firmware/baseband/proc_audiotx.hpp @@ -26,6 +26,7 @@ #include "fifo.hpp" #include "baseband_processor.hpp" #include "baseband_thread.hpp" +#include "tone_gen.hpp" class AudioTXProcessor : public BasebandProcessor { public: @@ -41,14 +42,14 @@ private: int8_t audio_fifo_data[2048] { }; FIFO audio_fifo = { audio_fifo_data, 11 }; // 43ms @ 48000Hz + ToneGen tone_gen { }; + uint32_t fm_delta { 0 }; uint32_t divider { }; uint32_t as { 0 }; - bool ctcss_enabled { false }; - uint32_t ctcss_phase_inc { }; - uint32_t ctcss_phase { 0 }, phase { 0 }, sphase { 0 }; + uint32_t phase { 0 }, sphase { 0 }; int8_t out_sample { }; - int32_t ctcss_sample { 0 }, sample { 0 }, sample_mixed { }, delta { }; + int32_t sample { 0 }, delta { }; int8_t re { 0 }, im { 0 }; diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index d902093d..3d7c0610 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -39,48 +39,43 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ for (size_t i = 0; i < buffer.count; i++) { if (!play_beep) { - sample = audio_buffer.p[i >> 6] >> 8; // 1536000 / 64 = 24000 + sample = audio_buffer.p[i >> 6] >> 8; // 1536000 / 64 = 24000 sample = (sample * (int32_t)gain_x10) / 10; - power += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter - if (!as) { - as = divider; - level_message.value = power / (divider / 4); // Why ? - shared_memory.application_queue.push(level_message); - power = 0; + if (power_acc_count) { + power_acc_count--; } else { - as--; + power_acc_count = divider; + level_message.value = power_acc / (divider / 4); // Why ? + shared_memory.application_queue.push(level_message); + power_acc = 0; } } else { if (beep_timer) { beep_timer--; } else { - beep_timer = 76800; // 50ms @ 1536000Hz + beep_timer = baseband_fs * 0.05; // 50ms + if (beep_index == BEEP_TONES_NB) { configured = false; fm_delta = 0; // Zero-out the IQ output for the rest of the buffer shared_memory.application_queue.push(txprogress_message); } else { - beep_phase_inc = beep_deltas[beep_index]; + beep_gen.configure(beep_deltas[beep_index], 1.0); beep_index++; } } - sample = sine_table_i8[(beep_phase & 0xFF000000U) >> 24]; - beep_phase += beep_phase_inc; + + sample = beep_gen.process(0); } - if (ctcss_enabled) { - ctcss_sample = sine_table_i8[(ctcss_phase & 0xFF000000U) >> 24]; - sample_mixed = ((sample * 205) + (ctcss_sample * 50)) / 256; // ~20% - ctcss_phase += ctcss_phase_inc; - } else { - sample_mixed = sample; - } + sample = tone_gen.process(sample); // FM if (fm_delta) { - delta = sample_mixed * fm_delta; + delta = sample * fm_delta; phase += delta; sphase = phase + (64 << 24); @@ -105,8 +100,9 @@ void MicTXProcessor::on_message(const Message* const msg) { fm_delta = config_message.fm_delta * (0xFFFFFFULL / baseband_fs); gain_x10 = config_message.gain_x10; divider = config_message.divider; - ctcss_enabled = config_message.ctcss_enabled; - ctcss_phase_inc = config_message.ctcss_phase_inc; + power_acc_count = 0; + + tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); txprogress_message.done = true; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index 62ec047c..bb9ac11f 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -23,9 +23,10 @@ #ifndef __PROC_MICTX_H__ #define __PROC_MICTX_H__ -#include "audio_input.hpp" #include "baseband_processor.hpp" #include "baseband_thread.hpp" +#include "audio_input.hpp" +#include "tone_gen.hpp" class MicTXProcessor : public BasebandProcessor { public: @@ -47,17 +48,17 @@ private: }; AudioInput audio_input { }; + ToneGen tone_gen { }; + ToneGen beep_gen { }; uint32_t divider { }, gain_x10 { }; - uint32_t as { 0 }; - uint32_t fm_delta { 0 }; + uint64_t power_acc { 0 }; + uint32_t power_acc_count { 0 }; bool play_beep { false }; - bool ctcss_enabled { false }; - uint32_t ctcss_phase_inc { }; - uint32_t ctcss_phase { 0 }, phase { 0 }, sphase { 0 }; - int32_t ctcss_sample { 0 }, sample { 0 }, sample_mixed { }, delta { }; - uint32_t beep_phase { 0 }, beep_phase_inc { }, beep_index { }, beep_timer { }; - uint64_t power { 0 }; + uint32_t fm_delta { 0 }; + uint32_t phase { 0 }, sphase { 0 }; + int32_t sample { 0 }, delta { }; + uint32_t beep_index { }, beep_timer { }; int8_t re { 0 }, im { 0 }; diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp new file mode 100644 index 00000000..bbe5587e --- /dev/null +++ b/firmware/baseband/tone_gen.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * + * 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 "tone_gen.hpp" +#include "sine_table_int8.hpp" + +void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { + delta_ = delta; + tone_mix_weight_ = tone_mix_weight; + input_mix_weight_ = 1.0 - tone_mix_weight; +} + +int32_t ToneGen::process(const int32_t sample_in) { + if (!delta_) + return sample_in; + + int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24]; + tone_phase_ += delta_; + + return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); +} diff --git a/firmware/baseband/tone_gen.hpp b/firmware/baseband/tone_gen.hpp new file mode 100644 index 00000000..ef547f26 --- /dev/null +++ b/firmware/baseband/tone_gen.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2017 Furrtek + * + * 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 __TONE_GEN_H__ +#define __TONE_GEN_H__ + +#include +#include + +class ToneGen { +public: + /*ToneGen(const size_t sample_rate + ) : sample_rate_ { sample_rate } + {};*/ + + void configure(const uint32_t delta, const float tone_mix_weight); + int32_t process(const int32_t sample_in); + +private: + //size_t sample_rate_; + float input_mix_weight_ { 1 }; + float tone_mix_weight_ { 0 }; + uint32_t delta_ { 0 }; + uint32_t tone_phase_ { 0 }; +}; + +#endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 3fb4e898..63b2ae21 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -748,22 +748,22 @@ public: const uint32_t divider, const uint32_t fm_delta, const uint32_t gain_x10, - const uint32_t ctcss_phase_inc, - const bool ctcss_enabled + const uint32_t tone_key_delta, + const float tone_key_mix_weight ) : Message { ID::AudioTXConfig }, divider(divider), fm_delta(fm_delta), gain_x10(gain_x10), - ctcss_phase_inc(ctcss_phase_inc), - ctcss_enabled(ctcss_enabled) + tone_key_delta(tone_key_delta), + tone_key_mix_weight(tone_key_mix_weight) { } const uint32_t divider; const uint32_t fm_delta; const uint32_t gain_x10; - const uint32_t ctcss_phase_inc; - const bool ctcss_enabled; + const uint32_t tone_key_delta; + const float tone_key_mix_weight; }; class SigGenConfigMessage : public Message {