fix: replaying a QSO used the voice keyer's level and overdrove the rig
A panadapter shot settles it: answering an S5 station, the replayed recording goes out several times wider and taller than the station being answered — in WAV as well as MP3, so this is not the encoder. One setting served two sources that have nothing in common. A voice-keyer message is a microphone at speaking distance and legitimately wants 195%; a QSO recording is a receiver's line output, which is far hotter. The same 195% put it into the transmitter flat out, ALC pinned, noise and voice alike. The QSO playback now has its own level, defaulting to 100%. The voice keyer keeps the setting it had, so nobody's F-key messages change.
This commit is contained in:
@@ -141,11 +141,20 @@ const (
|
|||||||
keyAudioQSODir = "audio.qso_dir" // folder for QSO recordings
|
keyAudioQSODir = "audio.qso_dir" // folder for QSO recordings
|
||||||
keyAudioPreroll = "audio.preroll_seconds" // rolling-buffer pre-roll length
|
keyAudioPreroll = "audio.preroll_seconds" // rolling-buffer pre-roll length
|
||||||
keyAudioTXGain = "audio.tx_gain" // voice-keyer playback level % (100 = as recorded)
|
keyAudioTXGain = "audio.tx_gain" // voice-keyer playback level % (100 = as recorded)
|
||||||
keyAudioPTTMethod = "audio.ptt_method" // "none" (VOX) | "rts" | "dtr"
|
// Replaying a QSO recording needs its OWN level, and by a wide margin.
|
||||||
keyAudioPTTPort = "audio.ptt_port" // COM port for serial PTT
|
//
|
||||||
keyAudioFormat = "audio.qso_format" // "wav" | "mp3"
|
// A voice-keyer message is a microphone at speaking distance; a QSO
|
||||||
keyAudioFromGain = "audio.from_gain" // From Radio (RX) mix level, percent
|
// recording is a receiver's line output, which is far hotter. Sharing one
|
||||||
keyAudioMicGain = "audio.mic_gain" // mic mix level, percent
|
// setting meant the 195% an operator needs for their F-key messages was
|
||||||
|
// also applied to a recording, which then hit the transmitter flat out —
|
||||||
|
// visible on the panadapter as a signal several times the size of the S5
|
||||||
|
// station being answered.
|
||||||
|
keyAudioQSOPlayGain = "audio.qso_play_gain" // QSO-recording playback level %
|
||||||
|
keyAudioPTTMethod = "audio.ptt_method" // "none" (VOX) | "rts" | "dtr"
|
||||||
|
keyAudioPTTPort = "audio.ptt_port" // COM port for serial PTT
|
||||||
|
keyAudioFormat = "audio.qso_format" // "wav" | "mp3"
|
||||||
|
keyAudioFromGain = "audio.from_gain" // From Radio (RX) mix level, percent
|
||||||
|
keyAudioMicGain = "audio.mic_gain" // mic mix level, percent
|
||||||
|
|
||||||
keyAwardDefs = "awards.defs" // JSON array of award definitions (editable)
|
keyAwardDefs = "awards.defs" // JSON array of award definitions (editable)
|
||||||
keyAwardRefsUpdated = "awards.refs.updated." // + CODE → last list-update timestamp
|
keyAwardRefsUpdated = "awards.refs.updated." // + CODE → last list-update timestamp
|
||||||
@@ -6958,6 +6967,7 @@ type AudioSettings struct {
|
|||||||
FromGain int `json:"from_gain"` // From Radio (RX) mix level %, default 100
|
FromGain int `json:"from_gain"` // From Radio (RX) mix level %, default 100
|
||||||
MicGain int `json:"mic_gain"` // mic mix level %, default 100
|
MicGain int `json:"mic_gain"` // mic mix level %, default 100
|
||||||
TXGain int `json:"tx_gain"` // voice-keyer playback level %, default 100
|
TXGain int `json:"tx_gain"` // voice-keyer playback level %, default 100
|
||||||
|
QSOPlayGain int `json:"qso_play_gain"` // QSO-recording playback level %, default 100
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListAudioInputDevices / ListAudioOutputDevices enumerate WASAPI endpoints
|
// ListAudioInputDevices / ListAudioOutputDevices enumerate WASAPI endpoints
|
||||||
@@ -6967,14 +6977,14 @@ func (a *App) ListAudioOutputDevices() ([]audio.Device, error) { return audio.Li
|
|||||||
|
|
||||||
// GetAudioSettings returns the stored audio config (preroll defaults to 8s).
|
// GetAudioSettings returns the stored audio config (preroll defaults to 8s).
|
||||||
func (a *App) GetAudioSettings() (AudioSettings, error) {
|
func (a *App) GetAudioSettings() (AudioSettings, error) {
|
||||||
out := AudioSettings{PrerollSeconds: 8, PTTMethod: "none", Format: "wav", FromGain: 100, MicGain: 100, TXGain: 100}
|
out := AudioSettings{PrerollSeconds: 8, PTTMethod: "none", Format: "wav", FromGain: 100, MicGain: 100, TXGain: 100, QSOPlayGain: 100}
|
||||||
if a.settings == nil {
|
if a.settings == nil {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
m, err := a.settings.GetMany(a.ctx,
|
m, err := a.settings.GetMany(a.ctx,
|
||||||
keyAudioFromRadio, keyAudioToRadio, keyAudioRecDevice, keyAudioListenDevice,
|
keyAudioFromRadio, keyAudioToRadio, keyAudioRecDevice, keyAudioListenDevice,
|
||||||
keyAudioQSORecord, keyAudioQSODir, keyAudioPreroll, keyAudioPTTMethod, keyAudioPTTPort, keyAudioFormat,
|
keyAudioQSORecord, keyAudioQSODir, keyAudioPreroll, keyAudioPTTMethod, keyAudioPTTPort, keyAudioFormat,
|
||||||
keyAudioFromGain, keyAudioMicGain, keyAudioTXGain)
|
keyAudioFromGain, keyAudioMicGain, keyAudioTXGain, keyAudioQSOPlayGain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
@@ -7005,6 +7015,9 @@ func (a *App) GetAudioSettings() (AudioSettings, error) {
|
|||||||
if n, _ := strconv.Atoi(m[keyAudioTXGain]); n > 0 && n <= 400 {
|
if n, _ := strconv.Atoi(m[keyAudioTXGain]); n > 0 && n <= 400 {
|
||||||
out.TXGain = n
|
out.TXGain = n
|
||||||
}
|
}
|
||||||
|
if n, _ := strconv.Atoi(m[keyAudioQSOPlayGain]); n > 0 && n <= 400 {
|
||||||
|
out.QSOPlayGain = n
|
||||||
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7036,6 +7049,9 @@ func (a *App) SaveAudioSettings(s AudioSettings) error {
|
|||||||
}
|
}
|
||||||
// Up to 400 %: a mic recorded quietly needs real amplification, and the
|
// Up to 400 %: a mic recorded quietly needs real amplification, and the
|
||||||
// clamp in the player keeps it from wrapping into noise.
|
// clamp in the player keeps it from wrapping into noise.
|
||||||
|
if s.QSOPlayGain <= 0 || s.QSOPlayGain > 400 {
|
||||||
|
s.QSOPlayGain = 100
|
||||||
|
}
|
||||||
if s.TXGain <= 0 || s.TXGain > 400 {
|
if s.TXGain <= 0 || s.TXGain > 400 {
|
||||||
s.TXGain = 100
|
s.TXGain = 100
|
||||||
}
|
}
|
||||||
@@ -7053,6 +7069,7 @@ func (a *App) SaveAudioSettings(s AudioSettings) error {
|
|||||||
keyAudioFromGain: strconv.Itoa(s.FromGain),
|
keyAudioFromGain: strconv.Itoa(s.FromGain),
|
||||||
keyAudioMicGain: strconv.Itoa(s.MicGain),
|
keyAudioMicGain: strconv.Itoa(s.MicGain),
|
||||||
keyAudioTXGain: strconv.Itoa(s.TXGain),
|
keyAudioTXGain: strconv.Itoa(s.TXGain),
|
||||||
|
keyAudioQSOPlayGain: strconv.Itoa(s.QSOPlayGain),
|
||||||
} {
|
} {
|
||||||
if err := a.settings.Set(a.ctx, k, v); err != nil {
|
if err := a.settings.Set(a.ctx, k, v); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -7777,7 +7794,7 @@ func (a *App) QSOAudioPlayOnAir() error {
|
|||||||
a.dvkPttKeyed = true
|
a.dvkPttKeyed = true
|
||||||
a.pttMu.Unlock()
|
a.pttMu.Unlock()
|
||||||
}
|
}
|
||||||
if err := a.audioMgr.Play(cfg.ToRadio, path, cfg.TXGain); err != nil {
|
if err := a.audioMgr.Play(cfg.ToRadio, path, cfg.QSOPlayGain); err != nil {
|
||||||
applog.Printf("qso-rec: playback on %q failed: %v", cfg.ToRadio, err)
|
applog.Printf("qso-rec: playback on %q failed: %v", cfg.ToRadio, err)
|
||||||
a.pttMu.Lock()
|
a.pttMu.Lock()
|
||||||
keyed := a.dvkPttKeyed
|
keyed := a.dvkPttKeyed
|
||||||
|
|||||||
+4
-2
@@ -10,7 +10,8 @@
|
|||||||
"The \"From radio\" and mic levels take effect as you drag the slider, and the RX level now applies to what you HEAR through OpsLog, not only to recordings.",
|
"The \"From radio\" and mic levels take effect as you drag the slider, and the RX level now applies to what you HEAR through OpsLog, not only to recordings.",
|
||||||
"The padlocks on frequency, band, mode and times no longer flicker under the pointer and refuse the click.",
|
"The padlocks on frequency, band, mode and times no longer flicker under the pointer and refuse the click.",
|
||||||
"The callsign field is wider, taking the room from the RST pair.",
|
"The callsign field is wider, taking the room from the RST pair.",
|
||||||
"MP3 recordings no longer carry a hiss of their own: the 16→32 kHz conversion mirrored the whole spectrum only 7 dB down. It is now 57 dB down."
|
"MP3 recordings no longer carry a hiss of their own: the 16→32 kHz conversion mirrored the whole spectrum only 7 dB down. It is now 57 dB down.",
|
||||||
|
"Replaying a QSO recording on the air has its own level, separate from the voice keyer: a recording comes from a receiver line output and needs far less gain than a message spoken into a microphone."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Les filtres du cluster gagnent NEW POTA et NEW COUNTY, à côté des pastilles de statut existantes.",
|
"Les filtres du cluster gagnent NEW POTA et NEW COUNTY, à côté des pastilles de statut existantes.",
|
||||||
@@ -20,7 +21,8 @@
|
|||||||
"Les niveaux « From radio » et micro agissent pendant que vous déplacez le curseur, et le niveau RX s'applique désormais à ce que vous ENTENDEZ dans OpsLog, pas seulement aux enregistrements.",
|
"Les niveaux « From radio » et micro agissent pendant que vous déplacez le curseur, et le niveau RX s'applique désormais à ce que vous ENTENDEZ dans OpsLog, pas seulement aux enregistrements.",
|
||||||
"Les cadenas de fréquence, bande, mode et heures ne scintillent plus sous le curseur et acceptent le clic.",
|
"Les cadenas de fréquence, bande, mode et heures ne scintillent plus sous le curseur et acceptent le clic.",
|
||||||
"Le champ indicatif est plus large, la place venant de la paire RST.",
|
"Le champ indicatif est plus large, la place venant de la paire RST.",
|
||||||
"Les enregistrements MP3 ne portent plus un souffle qui leur est propre : la conversion 16→32 kHz recopiait tout le spectre à seulement 7 dB en dessous. Il est désormais à 57 dB."
|
"Les enregistrements MP3 ne portent plus un souffle qui leur est propre : la conversion 16→32 kHz recopiait tout le spectre à seulement 7 dB en dessous. Il est désormais à 57 dB.",
|
||||||
|
"La relecture d'un enregistrement de QSO a son propre niveau, distinct du manipulateur vocal : une prise vient de la sortie ligne d'un récepteur et demande bien moins de gain qu'un message dit au micro."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1198,13 +1198,13 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
|||||||
from_radio: string; to_radio: string; recording_device: string; listening_device: string;
|
from_radio: string; to_radio: string; recording_device: string; listening_device: string;
|
||||||
qso_record: boolean; qso_dir: string; preroll_seconds: number;
|
qso_record: boolean; qso_dir: string; preroll_seconds: number;
|
||||||
ptt_method: 'none' | 'cat' | 'rts' | 'dtr'; ptt_port: string; format: 'wav' | 'mp3';
|
ptt_method: 'none' | 'cat' | 'rts' | 'dtr'; ptt_port: string; format: 'wav' | 'mp3';
|
||||||
from_gain: number; mic_gain: number; tx_gain: number;
|
from_gain: number; mic_gain: number; tx_gain: number; qso_play_gain: number;
|
||||||
};
|
};
|
||||||
type AudioDev = { id: string; name: string; default: boolean };
|
type AudioDev = { id: string; name: string; default: boolean };
|
||||||
const [audioCfg, setAudioCfg] = useState<AudioSettings>({
|
const [audioCfg, setAudioCfg] = useState<AudioSettings>({
|
||||||
from_radio: '', to_radio: '', recording_device: '', listening_device: '',
|
from_radio: '', to_radio: '', recording_device: '', listening_device: '',
|
||||||
qso_record: false, qso_dir: '', preroll_seconds: 8, ptt_method: 'none', ptt_port: '', format: 'wav',
|
qso_record: false, qso_dir: '', preroll_seconds: 8, ptt_method: 'none', ptt_port: '', format: 'wav',
|
||||||
from_gain: 100, mic_gain: 100, tx_gain: 100,
|
from_gain: 100, mic_gain: 100, tx_gain: 100, qso_play_gain: 100,
|
||||||
});
|
});
|
||||||
const [audioInputs, setAudioInputs] = useState<AudioDev[]>([]);
|
const [audioInputs, setAudioInputs] = useState<AudioDev[]>([]);
|
||||||
const [audioOutputs, setAudioOutputs] = useState<AudioDev[]>([]);
|
const [audioOutputs, setAudioOutputs] = useState<AudioDev[]>([]);
|
||||||
@@ -5118,6 +5118,12 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
|||||||
onChange={(e) => { const v = parseInt(e.target.value, 10); setAudioField({ from_gain: v }); AudioApplyLevels(v, audioCfg.mic_gain); }} className="w-48 accent-primary" />
|
onChange={(e) => { const v = parseInt(e.target.value, 10); setAudioField({ from_gain: v }); AudioApplyLevels(v, audioCfg.mic_gain); }} className="w-48 accent-primary" />
|
||||||
<span className="font-mono text-xs w-12 text-right">{audioCfg.from_gain}%</span>
|
<span className="font-mono text-xs w-12 text-right">{audioCfg.from_gain}%</span>
|
||||||
</div>
|
</div>
|
||||||
|
<Label className="text-sm">{t('aud.qsoPlayLevel')}</Label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<input type="range" min={10} max={300} step={5} value={audioCfg.qso_play_gain}
|
||||||
|
onChange={(e) => setAudioField({ qso_play_gain: parseInt(e.target.value, 10) })} className="w-48 accent-primary" />
|
||||||
|
<span className="font-mono text-xs w-12 text-right">{audioCfg.qso_play_gain}%</span>
|
||||||
|
</div>
|
||||||
<Label className="text-sm">{t('aud.micLevel')}</Label>
|
<Label className="text-sm">{t('aud.micLevel')}</Label>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<input type="range" min={10} max={300} step={5} value={audioCfg.mic_gain}
|
<input type="range" min={10} max={300} step={5} value={audioCfg.mic_gain}
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ const en: Dict = {
|
|||||||
'aud.txOn': 'TRANSMITTING — mic → To Radio, PTT keyed. Click to stop.', 'aud.txHint': 'Live mic → rig with PTT (USB now; network TX later).',
|
'aud.txOn': 'TRANSMITTING — mic → To Radio, PTT keyed. Click to stop.', 'aud.txHint': 'Live mic → rig with PTT (USB now; network TX later).',
|
||||||
'aud.recorder': 'QSO recorder', 'aud.recordEvery': 'Record every QSO to an audio file (From Radio + your mic)', 'aud.recFolder': 'Recordings folder', 'aud.browse': 'Browse…',
|
'aud.recorder': 'QSO recorder', 'aud.recordEvery': 'Record every QSO to an audio file (From Radio + your mic)', 'aud.recFolder': 'Recordings folder', 'aud.browse': 'Browse…',
|
||||||
'aud.preroll': 'Pre-roll (seconds)', 'aud.format': 'File format', 'aud.wav': 'WAV (lossless, larger)', 'aud.mp3': 'MP3 (compressed, small)',
|
'aud.preroll': 'Pre-roll (seconds)', 'aud.format': 'File format', 'aud.wav': 'WAV (lossless, larger)', 'aud.mp3': 'MP3 (compressed, small)',
|
||||||
'aud.fromLevel': 'From Radio level', 'aud.txLevel': 'Voice keyer level', 'aud.txLevelHint': 'Level of the recorded messages sent to the radio. Raise it if your voice keyer is much quieter than your microphone; Play previews at this same level. If the radio transmits almost nothing, its modulation source is still the front microphone: on an FTDX10 set MENU → SSB MOD SOURCE to REAR (the USB input).', 'aud.micLevel': 'Mic level', 'aud.levelHint': 'If your voice is louder than the station, lower Mic level.',
|
'aud.fromLevel': 'From Radio level', 'aud.txLevel': 'Voice keyer level', 'aud.txLevelHint': 'Level of the recorded messages sent to the radio. Raise it if your voice keyer is much quieter than your microphone; Play previews at this same level. If the radio transmits almost nothing, its modulation source is still the front microphone: on an FTDX10 set MENU → SSB MOD SOURCE to REAR (the USB input).', 'aud.micLevel': 'Mic level', 'aud.qsoPlayLevel': 'QSO playback level', 'aud.levelHint': 'If your voice is louder than the station, lower Mic level.',
|
||||||
'aud.autoSend': 'Auto-send the recording to the station by e-mail when I log a QSO',
|
'aud.autoSend': 'Auto-send the recording to the station by e-mail when I log a QSO',
|
||||||
'aud.dvkTitle': 'Voice keyer messages (F1–F6)', 'aud.pttMethod': 'PTT method', 'aud.pttNone': 'None (VOX)', 'aud.pttCat': 'CAT (the radio link)', 'aud.pttRts': 'Serial RTS', 'aud.pttDtr': 'Serial DTR',
|
'aud.dvkTitle': 'Voice keyer messages (F1–F6)', 'aud.pttMethod': 'PTT method', 'aud.pttNone': 'None (VOX)', 'aud.pttCat': 'CAT (the radio link)', 'aud.pttRts': 'Serial RTS', 'aud.pttDtr': 'Serial DTR',
|
||||||
'aud.testPtt': 'Test PTT', 'aud.pttPort': 'PTT COM port', 'aud.pickPort': 'Pick a COM port', 'aud.selectPort': '— select —', 'aud.refresh': 'Refresh',
|
'aud.testPtt': 'Test PTT', 'aud.pttPort': 'PTT COM port', 'aud.pickPort': 'Pick a COM port', 'aud.selectPort': '— select —', 'aud.refresh': 'Refresh',
|
||||||
@@ -815,7 +815,7 @@ const fr: Dict = {
|
|||||||
'aud.txOn': 'ÉMISSION — micro → Vers la radio, PTT activé. Cliquez pour arrêter.', 'aud.txHint': "Micro direct → poste avec PTT (USB pour l'instant ; TX réseau plus tard).",
|
'aud.txOn': 'ÉMISSION — micro → Vers la radio, PTT activé. Cliquez pour arrêter.', 'aud.txHint': "Micro direct → poste avec PTT (USB pour l'instant ; TX réseau plus tard).",
|
||||||
'aud.recorder': 'Enregistreur de QSO', 'aud.recordEvery': 'Enregistrer chaque QSO dans un fichier audio (Depuis la radio + votre micro)', 'aud.recFolder': 'Dossier des enregistrements', 'aud.browse': 'Parcourir…',
|
'aud.recorder': 'Enregistreur de QSO', 'aud.recordEvery': 'Enregistrer chaque QSO dans un fichier audio (Depuis la radio + votre micro)', 'aud.recFolder': 'Dossier des enregistrements', 'aud.browse': 'Parcourir…',
|
||||||
'aud.preroll': 'Pré-enregistrement (secondes)', 'aud.format': 'Format de fichier', 'aud.wav': 'WAV (sans perte, plus volumineux)', 'aud.mp3': 'MP3 (compressé, léger)',
|
'aud.preroll': 'Pré-enregistrement (secondes)', 'aud.format': 'Format de fichier', 'aud.wav': 'WAV (sans perte, plus volumineux)', 'aud.mp3': 'MP3 (compressé, léger)',
|
||||||
'aud.fromLevel': 'Niveau depuis la radio', 'aud.txLevel': 'Niveau du voice keyer', 'aud.txLevelHint': "Niveau des messages enregistrés envoyés à la radio. Augmentez-le si votre voice keyer est bien plus faible que votre micro ; Lire fait entendre ce même niveau. Si la radio n'émet presque rien, c'est que sa source de modulation est restée le micro de façade : sur un FTDX10, réglez MENU → SSB MOD SOURCE sur REAR (l'entrée USB).", 'aud.micLevel': 'Niveau micro', 'aud.levelHint': 'Si votre voix est plus forte que la station, baissez le niveau micro.',
|
'aud.fromLevel': 'Niveau depuis la radio', 'aud.txLevel': 'Niveau du voice keyer', 'aud.txLevelHint': "Niveau des messages enregistrés envoyés à la radio. Augmentez-le si votre voice keyer est bien plus faible que votre micro ; Lire fait entendre ce même niveau. Si la radio n'émet presque rien, c'est que sa source de modulation est restée le micro de façade : sur un FTDX10, réglez MENU → SSB MOD SOURCE sur REAR (l'entrée USB).", 'aud.micLevel': 'Niveau micro', 'aud.qsoPlayLevel': 'Niveau de relecture QSO', 'aud.levelHint': 'Si votre voix est plus forte que la station, baissez le niveau micro.',
|
||||||
'aud.autoSend': "Envoyer automatiquement l'enregistrement à la station par e-mail lorsque j'enregistre un QSO",
|
'aud.autoSend': "Envoyer automatiquement l'enregistrement à la station par e-mail lorsque j'enregistre un QSO",
|
||||||
'aud.dvkTitle': 'Messages du manipulateur vocal (F1–F6)', 'aud.pttMethod': 'Méthode PTT', 'aud.pttNone': 'Aucune (VOX)', 'aud.pttCat': 'CAT (la liaison radio)', 'aud.pttRts': 'RTS série', 'aud.pttDtr': 'DTR série',
|
'aud.dvkTitle': 'Messages du manipulateur vocal (F1–F6)', 'aud.pttMethod': 'Méthode PTT', 'aud.pttNone': 'Aucune (VOX)', 'aud.pttCat': 'CAT (la liaison radio)', 'aud.pttRts': 'RTS série', 'aud.pttDtr': 'DTR série',
|
||||||
'aud.testPtt': 'Tester le PTT', 'aud.pttPort': 'Port COM du PTT', 'aud.pickPort': 'Choisir un port COM', 'aud.selectPort': '— choisir —', 'aud.refresh': 'Actualiser',
|
'aud.testPtt': 'Tester le PTT', 'aud.pttPort': 'Port COM du PTT', 'aud.pickPort': 'Choisir un port COM', 'aud.selectPort': '— choisir —', 'aud.refresh': 'Actualiser',
|
||||||
|
|||||||
@@ -1608,6 +1608,7 @@ export namespace main {
|
|||||||
from_gain: number;
|
from_gain: number;
|
||||||
mic_gain: number;
|
mic_gain: number;
|
||||||
tx_gain: number;
|
tx_gain: number;
|
||||||
|
qso_play_gain: number;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new AudioSettings(source);
|
return new AudioSettings(source);
|
||||||
@@ -1628,6 +1629,7 @@ export namespace main {
|
|||||||
this.from_gain = source["from_gain"];
|
this.from_gain = source["from_gain"];
|
||||||
this.mic_gain = source["mic_gain"];
|
this.mic_gain = source["mic_gain"];
|
||||||
this.tx_gain = source["tx_gain"];
|
this.tx_gain = source["tx_gain"];
|
||||||
|
this.qso_play_gain = source["qso_play_gain"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class AutostartLaunchResult {
|
export class AutostartLaunchResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user