Initial commit of notifications spike
This commit is contained in:
parent
722dd5571a
commit
9dc2c99ebd
@ -253,6 +253,7 @@ set (wsjtx_CXXSRCS
|
||||
wsprnet.cpp
|
||||
WSPRBandHopping.cpp
|
||||
TransmitTextEdit.cpp
|
||||
NotificationAudio.cpp
|
||||
)
|
||||
|
||||
set (wsjt_CXXSRCS
|
||||
|
@ -530,6 +530,7 @@ private:
|
||||
|
||||
bool restart_sound_input_device_;
|
||||
bool restart_sound_output_device_;
|
||||
bool restart_notification_sound_output_device_;
|
||||
|
||||
Type2MsgGen type_2_msg_gen_;
|
||||
|
||||
@ -688,10 +689,15 @@ private:
|
||||
QAudioDeviceInfo audio_input_device_;
|
||||
bool default_audio_input_device_selected_;
|
||||
AudioDevice::Channel audio_input_channel_;
|
||||
|
||||
QAudioDeviceInfo audio_output_device_;
|
||||
bool default_audio_output_device_selected_;
|
||||
AudioDevice::Channel audio_output_channel_;
|
||||
|
||||
QAudioDeviceInfo notification_audio_output_device_;
|
||||
bool default_notification_audio_output_device_selected_;
|
||||
AudioDevice::Channel notification_audio_output_channel_;
|
||||
|
||||
friend class Configuration;
|
||||
};
|
||||
|
||||
@ -722,8 +728,11 @@ QAudioDeviceInfo const& Configuration::audio_input_device () const {return m_->a
|
||||
AudioDevice::Channel Configuration::audio_input_channel () const {return m_->audio_input_channel_;}
|
||||
QAudioDeviceInfo const& Configuration::audio_output_device () const {return m_->audio_output_device_;}
|
||||
AudioDevice::Channel Configuration::audio_output_channel () const {return m_->audio_output_channel_;}
|
||||
QAudioDeviceInfo const& Configuration::notification_audio_output_device () const {return m_->notification_audio_output_device_;}
|
||||
AudioDevice::Channel Configuration::notification_audio_output_channel () const {return m_->notification_audio_output_channel_;}
|
||||
bool Configuration::restart_audio_input () const {return m_->restart_sound_input_device_;}
|
||||
bool Configuration::restart_audio_output () const {return m_->restart_sound_output_device_;}
|
||||
bool Configuration::restart_notification_audio_output () const {return m_->restart_notification_sound_output_device_;}
|
||||
auto Configuration::type_2_msg_gen () const -> Type2MsgGen {return m_->type_2_msg_gen_;}
|
||||
bool Configuration::use_dynamic_grid() const {return m_->use_dynamic_info_; }
|
||||
QString Configuration::my_callsign () const {return m_->my_callsign_;}
|
||||
@ -1102,6 +1111,18 @@ template <typename T> void setUppercase(T* t){
|
||||
t->setFont(f);
|
||||
}
|
||||
|
||||
QWidget * centeredCheckBox(QWidget *parent, QCheckBox **ppCheckbox){
|
||||
auto w = new QWidget(parent);
|
||||
auto cb = new QCheckBox(parent);
|
||||
auto l = new QHBoxLayout(w);
|
||||
l->setContentsMargins(1, 1, 1, 1);
|
||||
l->setAlignment(Qt::AlignCenter);
|
||||
l->addWidget(cb);
|
||||
w->setLayout(l);
|
||||
if(ppCheckbox) *ppCheckbox = cb;
|
||||
return w;
|
||||
}
|
||||
|
||||
Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
QSettings * settings, QWidget * parent)
|
||||
: QDialog {parent}
|
||||
@ -1115,6 +1136,7 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
, writeable_data_dir_ {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}
|
||||
, restart_sound_input_device_ {false}
|
||||
, restart_sound_output_device_ {false}
|
||||
, restart_notification_sound_output_device_ {false}
|
||||
, frequencies_ {&bands_}
|
||||
, next_frequencies_ {&bands_}
|
||||
, stations_ {&bands_}
|
||||
@ -1277,8 +1299,12 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
|
||||
function<void (int)> cb (bind (&Configuration::impl::update_audio_channels, this, ui_->sound_input_combo_box, _1, ui_->sound_input_channel_combo_box, false));
|
||||
connect (ui_->sound_input_combo_box, static_cast<void (QComboBox::*)(int)> (&QComboBox::currentIndexChanged), cb);
|
||||
|
||||
cb = bind (&Configuration::impl::update_audio_channels, this, ui_->sound_output_combo_box, _1, ui_->sound_output_channel_combo_box, true);
|
||||
connect (ui_->sound_output_combo_box, static_cast<void (QComboBox::*)(int)> (&QComboBox::currentIndexChanged), cb);
|
||||
|
||||
cb = bind (&Configuration::impl::update_audio_channels, this, ui_->notification_sound_output_combo_box, _1, ui_->notification_sound_output_channel_combo_box, true);
|
||||
connect (ui_->notification_sound_output_combo_box, static_cast<void (QComboBox::*)(int)> (&QComboBox::currentIndexChanged), cb);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1335,6 +1361,63 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
ui_->frequencies_table_view->insertAction (nullptr, reset_frequencies_action_);
|
||||
connect (reset_frequencies_action_, &QAction::triggered, this, &Configuration::impl::reset_frequencies);
|
||||
|
||||
//
|
||||
// setup notifications table view
|
||||
//
|
||||
QMap<QString, QString> notifyRows = {
|
||||
{"notify_cq", "CQ Message Received"},
|
||||
{"notify_hb", "HB Message Received"},
|
||||
{"notify_directed", "Directed Message Received"},
|
||||
{"notify_relay", "Relay Message Received"},
|
||||
{"notify_new_call", "New Callsign Heard"},
|
||||
{"notify_worked_call", "Worked Callsign Heard"},
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
auto table = ui_->notifications_table_widget;
|
||||
foreach(QString key, notifyRows.keys()){
|
||||
QCheckBox *vcb;
|
||||
auto w1 = centeredCheckBox(this, &vcb);
|
||||
if(vcb){
|
||||
vcb->setChecked(true);
|
||||
}
|
||||
|
||||
QCheckBox *acb;
|
||||
auto w2 = centeredCheckBox(this, &acb);
|
||||
if(acb){
|
||||
acb->setChecked(true);
|
||||
}
|
||||
|
||||
QWidget *w3 = new QWidget(this);
|
||||
QHBoxLayout *l3 = new QHBoxLayout(w3);
|
||||
l3->setContentsMargins(9,1,1,1);
|
||||
w3->setLayout(l3);
|
||||
|
||||
QLabel *sflb = new QLabel(this);
|
||||
sflb->setText("/tmp/file.wav");
|
||||
l3->addWidget(sflb);
|
||||
|
||||
QPushButton *sfpb1 = new QPushButton(this);
|
||||
sfpb1->setText("Select");
|
||||
l3->addWidget(sfpb1);
|
||||
|
||||
QPushButton *sfpb3 = new QPushButton(this);
|
||||
sfpb3->setText("Clear");
|
||||
l3->addWidget(sfpb3);
|
||||
|
||||
|
||||
//
|
||||
table->insertRow(i);
|
||||
|
||||
auto labelItem = new QTableWidgetItem(notifyRows.value(key));
|
||||
table->setItem(i, 0, labelItem);
|
||||
table->setCellWidget(i, 1, w1);
|
||||
table->setCellWidget(i, 2, w2);
|
||||
table->setCellWidget(i, 3, w3);
|
||||
i++;
|
||||
}
|
||||
table->resizeColumnsToContents();
|
||||
|
||||
|
||||
//
|
||||
// setup stations table model & view
|
||||
@ -1371,12 +1454,15 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
//
|
||||
default_audio_input_device_selected_ = load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_);
|
||||
default_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_);
|
||||
default_notification_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->notification_sound_output_combo_box, ¬ification_audio_output_device_);
|
||||
|
||||
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
|
||||
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
|
||||
update_audio_channels (ui_->notification_sound_output_combo_box, ui_->notification_sound_output_combo_box->currentIndex (), ui_->notification_sound_output_channel_combo_box, true);
|
||||
|
||||
ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_);
|
||||
ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_);
|
||||
ui_->notification_sound_output_channel_combo_box->setCurrentIndex (notification_audio_output_channel_);
|
||||
|
||||
enumerate_rigs ();
|
||||
initialize_models ();
|
||||
@ -1718,9 +1804,36 @@ void Configuration::impl::read_settings ()
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//
|
||||
// retrieve notification audio output device
|
||||
//
|
||||
auto saved_name = settings_->value("NotificationSoundOutName").toString();
|
||||
|
||||
// deal with special Windows default audio devices
|
||||
auto default_device = QAudioDeviceInfo::defaultOutputDevice ();
|
||||
if (saved_name == default_device.deviceName ())
|
||||
{
|
||||
notification_audio_output_device_ = default_device;
|
||||
default_notification_audio_output_device_selected_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
default_notification_audio_output_device_selected_ = false;
|
||||
Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)) // available audio output devices
|
||||
{
|
||||
if (p.deviceName () == saved_name)
|
||||
{
|
||||
notification_audio_output_device_ = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve audio channel info
|
||||
audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ());
|
||||
audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ());
|
||||
notification_audio_output_channel_ = AudioDevice::fromString (settings_->value ("NotificationAudioOutputChannel", "Mono").toString ());
|
||||
|
||||
type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value<Configuration::Type2MsgGen> ();
|
||||
|
||||
@ -1903,8 +2016,19 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("SoundOutName", audio_output_device_.deviceName ());
|
||||
}
|
||||
|
||||
if (default_notification_audio_output_device_selected_)
|
||||
{
|
||||
settings_->setValue ("NotificationSoundOutName", QAudioDeviceInfo::defaultOutputDevice ().deviceName ());
|
||||
}
|
||||
else
|
||||
{
|
||||
settings_->setValue ("NotificationSoundOutName", notification_audio_output_device_.deviceName ());
|
||||
}
|
||||
|
||||
|
||||
settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_));
|
||||
settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_));
|
||||
settings_->setValue ("NotificationAudioOutputChannel", AudioDevice::toString (notification_audio_output_channel_));
|
||||
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
|
||||
settings_->setValue ("TransmitDirected", transmit_directed_);
|
||||
settings_->setValue ("AutoreplyOnAtStartup", autoreply_on_at_startup_);
|
||||
@ -2432,6 +2556,35 @@ void Configuration::impl::accept ()
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const& device_name = ui_->notification_sound_output_combo_box->currentText ();
|
||||
if (device_name != notification_audio_output_device_.deviceName ())
|
||||
{
|
||||
auto const& default_device = QAudioDeviceInfo::defaultOutputDevice ();
|
||||
if (device_name == default_device.deviceName ())
|
||||
{
|
||||
notification_audio_output_device_ = default_device;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found {false};
|
||||
Q_FOREACH (auto const& d, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput))
|
||||
{
|
||||
if (device_name == d.deviceName ())
|
||||
{
|
||||
notification_audio_output_device_ = d;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
notification_audio_output_device_ = default_device;
|
||||
}
|
||||
}
|
||||
restart_notification_sound_output_device_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_input_channel_ != static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ()))
|
||||
{
|
||||
audio_input_channel_ = static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ());
|
||||
@ -2446,6 +2599,13 @@ void Configuration::impl::accept ()
|
||||
}
|
||||
Q_ASSERT (audio_output_channel_ <= AudioDevice::Both);
|
||||
|
||||
if (notification_audio_output_channel_ != static_cast<AudioDevice::Channel> (ui_->notification_sound_output_channel_combo_box->currentIndex ()))
|
||||
{
|
||||
notification_audio_output_channel_ = static_cast<AudioDevice::Channel> (ui_->notification_sound_output_channel_combo_box->currentIndex ());
|
||||
restart_notification_sound_output_device_ = true;
|
||||
}
|
||||
Q_ASSERT (notification_audio_output_channel_ <= AudioDevice::Both);
|
||||
|
||||
auto_switch_bands_ = ui_->auto_switch_bands_check_box->isChecked();
|
||||
my_callsign_ = ui_->callsign_line_edit->text ().toUpper().trimmed();
|
||||
my_grid_ = ui_->grid_line_edit->text ().toUpper().trimmed();
|
||||
|
@ -86,6 +86,8 @@ public:
|
||||
AudioDevice::Channel audio_input_channel () const;
|
||||
QAudioDeviceInfo const& audio_output_device () const;
|
||||
AudioDevice::Channel audio_output_channel () const;
|
||||
QAudioDeviceInfo const& notification_audio_output_device () const;
|
||||
AudioDevice::Channel notification_audio_output_channel () const;
|
||||
|
||||
// These query methods should be used after a call to exec() to
|
||||
// determine if either the audio input or audio output stream
|
||||
@ -93,6 +95,7 @@ public:
|
||||
// re-opened if they return true.
|
||||
bool restart_audio_input () const;
|
||||
bool restart_audio_output () const;
|
||||
bool restart_notification_audio_output () const;
|
||||
|
||||
bool use_dynamic_grid() const;
|
||||
QString my_callsign () const;
|
||||
|
188
Configuration.ui
188
Configuration.ui
@ -23,7 +23,7 @@
|
||||
<string>Select tab to change configuration parameters.</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>6</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="general_tab">
|
||||
<attribute name="title">
|
||||
@ -793,8 +793,8 @@ text message.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>738</width>
|
||||
<height>453</height>
|
||||
<width>616</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
@ -1517,7 +1517,7 @@ a few, particularly some Kenwood rigs, require it).</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>494</width>
|
||||
<width>718</width>
|
||||
<height>490</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -1921,8 +1921,8 @@ this setting allows you to select which audio input will be used
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>266</width>
|
||||
<height>329</height>
|
||||
<width>760</width>
|
||||
<height>502</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
@ -1944,7 +1944,7 @@ this setting allows you to select which audio input will be used
|
||||
<string>Souncard</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Soundcard</string>
|
||||
<string>Modulation Soundcard</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="1" column="1">
|
||||
@ -2057,6 +2057,72 @@ both here.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="notification_soundcard_group_box">
|
||||
<property name="title">
|
||||
<string>Notification Soundcard</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_18">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="notification_sound_output_label">
|
||||
<property name="text">
|
||||
<string>O&utput:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sound_output_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="notification_sound_output_combo_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select the audio CODEC to use for transmitting.
|
||||
If this is your default device for system sounds then
|
||||
ensure that all system sounds are disabled otherwise
|
||||
you will broadcast any systems sounds generated during
|
||||
transmitting periods.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QComboBox" name="notification_sound_output_channel_combo_box">
|
||||
<property name="toolTip">
|
||||
<string>Select the audio channel used for transmission.
|
||||
Unless you have multiple radios connected on different
|
||||
channels; then you will usually want to select mono or
|
||||
both here.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mono</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Both</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="save_path_group_box">
|
||||
<property name="toolTip">
|
||||
@ -2201,6 +2267,9 @@ both here.</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
@ -2234,7 +2303,7 @@ both here.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<width>746</width>
|
||||
<height>663</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -2729,8 +2798,8 @@ for assessing propagation and system performance.</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>487</width>
|
||||
<height>341</height>
|
||||
<width>760</width>
|
||||
<height>502</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
@ -3045,6 +3114,95 @@ QListView::item:hover {
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="notifications_tab">
|
||||
<attribute name="title">
|
||||
<string>&Notifications</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_32">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea_12">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_11">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>502</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_35">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="notifications_table_widget">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||
<number>125</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Event</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Visual Alert?</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Audio Alert?</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Sound File</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="colors_tab">
|
||||
<attribute name="title">
|
||||
<string>&UI</string>
|
||||
@ -3110,8 +3268,8 @@ QListView::item:hover {
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>274</width>
|
||||
<height>690</height>
|
||||
<width>724</width>
|
||||
<height>418</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
@ -4370,12 +4528,12 @@ soundcard changes</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
158
NotificationAudio.cpp
Normal file
158
NotificationAudio.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
#include "NotificationAudio.h"
|
||||
|
||||
|
||||
NotificationAudio::NotificationAudio(QObject *parent) :
|
||||
QIODevice(parent),
|
||||
m_state(State::Stopped),
|
||||
m_input(&m_data),
|
||||
m_output(&m_data),
|
||||
m_decoder(nullptr),
|
||||
m_audio(nullptr)
|
||||
{
|
||||
setOpenMode(QIODevice::ReadOnly);
|
||||
|
||||
m_init = false;
|
||||
m_isDecodingFinished = false;
|
||||
}
|
||||
|
||||
// initialize an audio device
|
||||
void NotificationAudio::init(const QAudioDeviceInfo &device, const QAudioFormat& format) {
|
||||
m_device = device;
|
||||
m_format = format;
|
||||
|
||||
if(!m_decoder){
|
||||
m_decoder = new QAudioDecoder(this);
|
||||
connect(m_decoder, &QAudioDecoder::bufferReady, this, &NotificationAudio::bufferReady);
|
||||
connect(m_decoder, &QAudioDecoder::finished, this, &NotificationAudio::finished);
|
||||
}
|
||||
m_decoder->setAudioFormat(m_format);
|
||||
|
||||
if(!m_audio){
|
||||
m_audio = new QAudioOutput(m_device, m_format);
|
||||
}
|
||||
|
||||
if (!m_output.open(QIODevice::ReadOnly) || !m_input.open(QIODevice::WriteOnly)){
|
||||
m_init = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_init = true;
|
||||
emit initialized();
|
||||
}
|
||||
|
||||
// play an audio file
|
||||
void NotificationAudio::play(const QString &filePath) {
|
||||
QFile *file = new QFile(this);
|
||||
file->setFileName(filePath);
|
||||
if (!file->open(QIODevice::ReadOnly)){
|
||||
return;
|
||||
}
|
||||
|
||||
playFile(file);
|
||||
}
|
||||
|
||||
void NotificationAudio::playFile(QFile *file){
|
||||
if(!m_init || !m_decoder || !m_audio || !file){
|
||||
return;
|
||||
}
|
||||
|
||||
resetBuffers();
|
||||
|
||||
m_file = file;
|
||||
m_decoder->setSourceDevice(m_file);
|
||||
m_decoder->start();
|
||||
|
||||
m_state = State::Playing;
|
||||
emit stateChanged(m_state);
|
||||
|
||||
m_audio->start(this);
|
||||
}
|
||||
|
||||
// Stop playing audio
|
||||
void NotificationAudio::stop() {
|
||||
resetBuffers();
|
||||
m_state = State::Stopped;
|
||||
emit stateChanged(m_state);
|
||||
}
|
||||
|
||||
// Reset the internal buffers and ensure the decoder and audio device is stopped
|
||||
void NotificationAudio::resetBuffers() {
|
||||
if(m_audio){
|
||||
if(m_audio->state() != QAudio::StoppedState){
|
||||
m_audio->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_decoder){
|
||||
if(m_decoder->state() != QAudioDecoder::StoppedState){
|
||||
m_decoder->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_file){
|
||||
if(m_file->isOpen()){
|
||||
m_file->close();
|
||||
}
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
}
|
||||
|
||||
m_data.clear();
|
||||
m_isDecodingFinished = false;
|
||||
}
|
||||
|
||||
// io device, read into buffer.
|
||||
qint64 NotificationAudio::readData(char* data, qint64 maxlen) {
|
||||
memset(data, 0, maxlen);
|
||||
|
||||
if (m_state == State::Playing)
|
||||
{
|
||||
m_output.read(data, maxlen);
|
||||
|
||||
// There is we send readed audio data via signal, for ability get audio signal for the who listen this signal.
|
||||
// Other word this emulate QAudioProbe behaviour for retrieve audio data which of sent to output device (speaker).
|
||||
if (maxlen > 0)
|
||||
{
|
||||
QByteArray buff(data, maxlen);
|
||||
emit newData(buff);
|
||||
}
|
||||
|
||||
// Is finish of file
|
||||
if (atEnd())
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
// io device, unused.
|
||||
qint64 NotificationAudio::writeData(const char* data, qint64 len) {
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// io device, at end of device
|
||||
bool NotificationAudio::atEnd() const {
|
||||
return m_output.size()
|
||||
&& m_output.atEnd()
|
||||
&& m_isDecodingFinished;
|
||||
}
|
||||
|
||||
// handle buffered data ready
|
||||
void NotificationAudio::bufferReady() {
|
||||
const QAudioBuffer &buffer = m_decoder->read();
|
||||
|
||||
const int length = buffer.byteCount();
|
||||
const char *data = buffer.constData<char>();
|
||||
|
||||
m_input.write(data, length);
|
||||
}
|
||||
|
||||
// handle buffered data decoding is finished
|
||||
void NotificationAudio::finished() {
|
||||
m_isDecodingFinished = true;
|
||||
}
|
65
NotificationAudio.h
Normal file
65
NotificationAudio.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef NOTIFICATIONAUDIO_H
|
||||
#define NOTIFICATIONAUDIO_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QBuffer>
|
||||
#include <QAudioDecoder>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioFormat>
|
||||
#include <QAudioOutput>
|
||||
#include <QFile>
|
||||
|
||||
// Class for decode audio files like MP3 and push decoded audio data to QOutputDevice (like speaker) and also signal newData().
|
||||
// For decoding it uses QAudioDecoder which uses QAudioFormat for decode audio file for desire format, then put decoded data to buffer.
|
||||
// based on: https://github.com/Znurre/QtMixer
|
||||
class NotificationAudio : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NotificationAudio(QObject * parent=nullptr);
|
||||
|
||||
bool isInitialized() const { return m_init; }
|
||||
|
||||
enum State { Playing, Stopped };
|
||||
|
||||
bool atEnd() const override;
|
||||
|
||||
public slots:
|
||||
void init(const QAudioDeviceInfo &device, const QAudioFormat& format);
|
||||
void play(const QString &filePath);
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
|
||||
qint64 readData(char* data, qint64 maxlen) override;
|
||||
qint64 writeData(const char* data, qint64 len) override;
|
||||
|
||||
private:
|
||||
QFile *m_file;
|
||||
State m_state;
|
||||
QBuffer m_input;
|
||||
QBuffer m_output;
|
||||
QByteArray m_data;
|
||||
QAudioFormat m_format;
|
||||
QAudioDeviceInfo m_device;
|
||||
QAudioDecoder * m_decoder;
|
||||
QAudioOutput * m_audio;
|
||||
|
||||
bool m_init;
|
||||
bool m_isDecodingFinished;
|
||||
|
||||
void playFile(QFile *file);
|
||||
void resetBuffers();
|
||||
|
||||
private slots:
|
||||
void bufferReady();
|
||||
void finished();
|
||||
|
||||
signals:
|
||||
void initialized();
|
||||
void stateChanged(NotificationAudio::State state);
|
||||
void newData(const QByteArray& data);
|
||||
};
|
||||
|
||||
#endif // NOTIFICATIONAUDIO_H
|
@ -84,7 +84,8 @@ SOURCES += \
|
||||
messagewindow.cpp \
|
||||
SpotClient.cpp \
|
||||
TCPClient.cpp \
|
||||
TransmitTextEdit.cpp
|
||||
TransmitTextEdit.cpp \
|
||||
NotificationAudio.cpp
|
||||
|
||||
HEADERS += qt_helpers.hpp \
|
||||
pimpl_h.hpp pimpl_impl.hpp \
|
||||
@ -120,7 +121,8 @@ HEADERS += qt_helpers.hpp \
|
||||
SpotClient.h \
|
||||
TCPClient.h \
|
||||
logbook/n3fjp.h \
|
||||
TransmitTextEdit.h
|
||||
TransmitTextEdit.h \
|
||||
NotificationAudio.h
|
||||
|
||||
|
||||
INCLUDEPATH += qmake_only
|
||||
|
@ -72,6 +72,7 @@
|
||||
#include "jsc_checker.h"
|
||||
#include "Inbox.h"
|
||||
#include "messagewindow.h"
|
||||
#include "NotificationAudio.h"
|
||||
|
||||
#include "ui_mainwindow.h"
|
||||
#include "moc_mainwindow.cpp"
|
||||
@ -300,6 +301,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
m_soundInput {new SoundInput},
|
||||
m_modulator {new Modulator {TX_SAMPLE_RATE, NTMAX}},
|
||||
m_soundOutput {new SoundOutput},
|
||||
m_notification {new NotificationAudio},
|
||||
m_msErase {0},
|
||||
m_secBandChanged {0},
|
||||
m_freqNominal {0},
|
||||
@ -501,6 +503,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
m_modulator->moveToThread (&m_audioThread);
|
||||
m_soundInput->moveToThread (&m_audioThread);
|
||||
m_detector->moveToThread (&m_audioThread);
|
||||
m_notification->moveToThread(&m_audioThread);
|
||||
|
||||
// hook up sound output stream slots & signals and disposal
|
||||
connect (this, &MainWindow::initializeAudioOutputStream, m_soundOutput, &SoundOutput::setFormat);
|
||||
@ -509,6 +512,13 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
connect (this, &MainWindow::outAttenuationChanged, m_soundOutput, &SoundOutput::setAttenuation);
|
||||
connect (&m_audioThread, &QThread::finished, m_soundOutput, &QObject::deleteLater);
|
||||
|
||||
connect(this, &MainWindow::initializeNotificationAudioOutputStream, m_notification, &NotificationAudio::init);
|
||||
connect(m_notification, &NotificationAudio::initialized, this, [this](){
|
||||
emit playNotification("/tmp/test.wav");
|
||||
});
|
||||
connect(this, &MainWindow::playNotification, m_notification, &NotificationAudio::play);
|
||||
connect (&m_audioThread, &QThread::finished, m_notification, &QObject::deleteLater);
|
||||
|
||||
// hook up Modulator slots and disposal
|
||||
connect (this, &MainWindow::transmitFrequency, m_modulator, &Modulator::setFrequency);
|
||||
connect (this, &MainWindow::endTransmitMessage, m_modulator, &Modulator::stop);
|
||||
@ -3003,6 +3013,12 @@ void MainWindow::openSettings(int tab){
|
||||
m_msAudioOutputBuffered);
|
||||
}
|
||||
|
||||
if(m_config.restart_notification_audio_output ()) {
|
||||
Q_EMIT initializeNotificationAudioOutputStream(
|
||||
m_config.notification_audio_output_device(),
|
||||
m_config.notification_audio_output_device().preferredFormat());
|
||||
}
|
||||
|
||||
ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (FrequencyList_v2::frequency_mhz_column));
|
||||
|
||||
displayDialFrequency ();
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "SpotClient.h"
|
||||
#include "APRSISClient.h"
|
||||
#include "keyeater.h"
|
||||
#include "NotificationAudio.h"
|
||||
|
||||
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
|
||||
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
|
||||
@ -434,6 +435,8 @@ private slots:
|
||||
void refreshTextDisplay();
|
||||
|
||||
private:
|
||||
Q_SIGNAL void playNotification(const QString &name);
|
||||
Q_SIGNAL void initializeNotificationAudioOutputStream(QAudioDeviceInfo, QAudioFormat);
|
||||
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
|
||||
unsigned channels, unsigned msBuffered) const;
|
||||
Q_SIGNAL void stopAudioOutputStream () const;
|
||||
@ -502,6 +505,7 @@ private:
|
||||
SoundInput * m_soundInput;
|
||||
Modulator * m_modulator;
|
||||
SoundOutput * m_soundOutput;
|
||||
NotificationAudio * m_notification;
|
||||
QThread m_audioThread;
|
||||
|
||||
qint64 m_msErase;
|
||||
|
Loading…
Reference in New Issue
Block a user