swift
soundcardsampleprovider.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include "config/buildconfig.h"
7 #include "misc/metadatautils.h"
8 
9 using namespace swift::config;
10 using namespace swift::misc;
11 using namespace swift::sound::sample_provider;
12 
13 namespace swift::core::afv::audio
14 {
15  CSoundcardSampleProvider::CSoundcardSampleProvider(int sampleRate, const QVector<quint16> &transceiverIDs,
16  QObject *parent)
17  : ISampleProvider(parent), m_mixer(new CMixingSampleProvider())
18  {
19  const QString on = QStringLiteral("%1 sample rate: %2, transceivers: %3")
20  .arg(classNameShort(this))
21  .arg(sampleRate)
22  .arg(transceiverIDs.size());
23  this->setObjectName(on);
24 
25  m_waveFormat.setSampleRate(sampleRate);
26  m_waveFormat.setChannelCount(1);
27  m_waveFormat.setSampleFormat(QAudioFormat::Int16);
28  static_assert(Q_BYTE_ORDER == Q_LITTLE_ENDIAN);
29 
30  m_mixer = new CMixingSampleProvider(this);
31  m_receiverIDs = transceiverIDs;
32 
33  constexpr int voiceInputNumber = 4; // number of CallsignSampleProviders
34  for (quint16 transceiverID : transceiverIDs)
35  {
36  CReceiverSampleProvider *transceiverInput =
37  new CReceiverSampleProvider(m_waveFormat, transceiverID, voiceInputNumber, m_mixer);
38  connect(transceiverInput, &CReceiverSampleProvider::receivingCallsignsChanged, this,
40  m_receiverInputs.push_back(transceiverInput);
41  m_receiverIDs.push_back(transceiverID);
42  m_mixer->addMixerInput(transceiverInput);
43  }
44  }
45 
47  {
48  for (CReceiverSampleProvider *receiverInput : std::as_const(m_receiverInputs))
49  {
50  receiverInput->setBypassEffects(value);
51  }
52  }
53 
54  void CSoundcardSampleProvider::pttUpdate(bool active, const QVector<TxTransceiverDto> &txTransceivers)
55  {
56  if (active)
57  {
58  if (!txTransceivers.isEmpty())
59  {
60  QVector<TxTransceiverDto> txTransceiversFiltered = txTransceivers;
61 
62  txTransceiversFiltered.erase(
63  std::remove_if(txTransceiversFiltered.begin(), txTransceiversFiltered.end(),
64  [this](const TxTransceiverDto &d) { return !m_receiverIDs.contains(d.id); }),
65  txTransceiversFiltered.end());
66 
67  for (const TxTransceiverDto &txTransceiver : txTransceiversFiltered)
68  {
69  auto it = std::find_if(
70  m_receiverInputs.begin(), m_receiverInputs.end(),
71  [txTransceiver](const CReceiverSampleProvider *p) { return p->getId() == txTransceiver.id; });
72 
73  if (it != m_receiverInputs.end()) { (*it)->setMute(true); }
74  }
75  }
76  }
77  else
78  {
79  for (CReceiverSampleProvider *receiverInput : std::as_const(m_receiverInputs))
80  {
81  receiverInput->setMute(false);
82  }
83  }
84  }
85 
86  int CSoundcardSampleProvider::readSamples(QVector<float> &samples, qint64 count)
87  {
88  return m_mixer->readSamples(samples, count);
89  }
90 
92  const QVector<RxTransceiverDto> &rxTransceivers)
93  {
94  QVector<RxTransceiverDto> rxTransceiversFilteredAndSorted = rxTransceivers;
95 
96  rxTransceiversFilteredAndSorted.erase(
97  std::remove_if(rxTransceiversFilteredAndSorted.begin(), rxTransceiversFilteredAndSorted.end(),
98  [this](const RxTransceiverDto &r) { return !m_receiverIDs.contains(r.id); }),
99  rxTransceiversFilteredAndSorted.end());
100 
101  std::sort(rxTransceiversFilteredAndSorted.begin(), rxTransceiversFilteredAndSorted.end(),
102  [](const RxTransceiverDto &a, const RxTransceiverDto &b) -> bool {
103  return a.distanceRatio > b.distanceRatio;
104  });
105 
106  if (!rxTransceiversFilteredAndSorted.isEmpty())
107  {
108  bool audioPlayed = false;
109  QVector<quint16> handledTransceiverIDs;
110  for (int i = 0; i < rxTransceiversFilteredAndSorted.size(); i++)
111  {
112  const RxTransceiverDto rxTransceiver = rxTransceiversFilteredAndSorted[i];
113  if (!handledTransceiverIDs.contains(rxTransceiver.id))
114  {
115  handledTransceiverIDs.push_back(rxTransceiver.id);
116 
117  CReceiverSampleProvider *receiverInput = nullptr;
118  auto it = std::find_if(
119  m_receiverInputs.begin(), m_receiverInputs.end(),
120  [rxTransceiver](const CReceiverSampleProvider *p) { return p->getId() == rxTransceiver.id; });
121 
122  if (it != m_receiverInputs.end()) { receiverInput = *it; }
123 
124  if (!receiverInput) { continue; }
125  if (receiverInput->getMute()) { continue; }
126 
127  if (!audioPlayed)
128  {
129  receiverInput->addOpusSamples(audioDto, rxTransceiver.frequency, rxTransceiver.distanceRatio);
130  audioPlayed = true;
131  }
132  else
133  {
134  receiverInput->addSilentSamples(audioDto, rxTransceiver.frequency, rxTransceiver.distanceRatio);
135  }
136 
137  // debug ONLY
138  if (CBuildConfig::isLocalDeveloperDebugBuild())
139  {
140  receiverInput->logVoiceInputs(QStringLiteral("Transceiver %1 ").arg(rxTransceiver.id), 1500);
141  }
142  }
143  } // each transceiver
144  } // filtered rx transceivers
145  }
146 
147  void CSoundcardSampleProvider::updateRadioTransceivers(const QVector<TransceiverDto> &radioTransceivers)
148  {
149  for (const TransceiverDto &radioTransceiver : radioTransceivers)
150  {
151  auto it = std::find_if(
152  m_receiverInputs.begin(), m_receiverInputs.end(),
153  [radioTransceiver](const CReceiverSampleProvider *p) { return p->getId() == radioTransceiver.id; });
154 
155  if (it != m_receiverInputs.end()) { (*it)->setFrequency(radioTransceiver.frequencyHz); }
156  }
157 
158  for (CReceiverSampleProvider *receiverInput : std::as_const(m_receiverInputs))
159  {
160  const quint16 transceiverID = receiverInput->getId();
161  const bool contains = std::any_of(radioTransceivers.cbegin(), radioTransceivers.cend(),
162  [transceiverID](const auto &tx) { return transceiverID == tx.id; });
163  if (!contains) { receiverInput->setFrequency(0); }
164  }
165  }
166 
167  QString CSoundcardSampleProvider::getReceivingCallsignsString(quint16 transceiverID) const
168  {
169  return m_receiverInputs.at(transceiverID)->getReceivingCallsignsString();
170  }
171 
172  bool CSoundcardSampleProvider::setGainRatioForTransceiver(quint16 transceiverID, double gainRatio)
173  {
174  auto receiverInput = std::find_if(m_receiverInputs.begin(), m_receiverInputs.end(),
175  [&](const auto receiver) { return receiver->getId() == transceiverID; });
176  if (receiverInput == m_receiverInputs.end()) { return false; }
177  return (*receiverInput)->setGainRatio(gainRatio);
178  }
179 
181  {
182  return m_receiverInputs.at(transceiverID)->getReceivingCallsigns();
183  }
184 
185 } // namespace swift::core::afv::audio
void addSilentSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio)
Add samples.
void receivingCallsignsChanged(const TransceiverReceivingCallsignsChangedArgs &args)
Receving callsigns have changed.
void addOpusSamples(const IAudioDto &audioDto, uint frequency, float distanceRatio)
Add samples.
int readSamples(QVector< float > &samples, qint64 count)
Read samples.
bool setGainRatioForTransceiver(quint16 transceiverID, double gainRatio)
Setting gain for specified receiver.
swift::misc::aviation::CCallsignSet getReceivingCallsigns(quint16 transceiverID) const
Receiving callsign as single string.
void receivingCallsignsChanged(const TransceiverReceivingCallsignsChangedArgs &args)
Changed callsigns.
void updateRadioTransceivers(const QVector< TransceiverDto > &radioTransceivers)
Update all tranceivers.
QString getReceivingCallsignsString(quint16 transceiverID) const
Receiving callsign as single string.
void pttUpdate(bool active, const QVector< TxTransceiverDto > &txTransceivers)
Update PTT.
void addOpusSamples(const IAudioDto &audioDto, const QVector< RxTransceiverDto > &rxTransceivers)
Add OPUS samples.
Value object for a set of callsigns.
Definition: callsignset.h:26
virtual int readSamples(QVector< float > &samples, qint64 count)
Read samples.
void addMixerInput(ISampleProvider *provider)
Add a provider.
Free functions in swift::misc.
QString classNameShort(const QObject *object)
Class name as from QMetaObject::className without namespace.
Receive transceiver DTO.
Definition: dto.h:206
uint16_t id
Properties.
Definition: dto.h:209
float distanceRatio
Properties.
Definition: dto.h:211
uint32_t frequency
Properties.
Definition: dto.h:210
Transceiver DTO.
Definition: dto.h:117
Transmit transceiver DTO.
Definition: dto.h:220