private void buttonInputOpen_Click(object sender, EventArgs e) { uint devIndex = (uint)comboBoxWaveIn.SelectedIndex; uint channel = radioButtonInputLeft.Checked ? 0u : 1u; if (waveDevicePlayer != null) { waveDevicePlayer.Dispose(); } waveDevicePlayer = new XD.WaveDevicePlayer(); if (!waveDevicePlayer.Open(devIndex, channel, demodulator.GetRealTimeRxSink())) { MessageBox.Show("Failed to open wave input"); waveDevicePlayer.Dispose(); waveDevicePlayer = null; } else { labelInputState.Text = "Paused"; buttonPlayFile.Enabled = false; buttonOpenWaveIn.Enabled = false; buttonInputClose.Enabled = true; buttonInputResume.Enabled = true; var series = chartSpectrum.Series[0]; series.Points.Clear(); } }
private void MainForm_FormClosed(object sender, FormClosedEventArgs e) { /* Failure to call Dispose will keep certain Windows handles * on, for example, shared memory, active for an interminate amount * of time before garbage collection. Its OK to fail if this process * is exiting: the OS will clean up. But if your process instances * multiple forms, then you had better do the Dispose's */ if (demodulator != null) { demodulator.Dispose(); } demodulator = null; if (wsjtExe != null) { wsjtExe.Dispose(); } wsjtExe = null; if (wsjtSharedMem != null) { wsjtSharedMem.Dispose(); } wsjtSharedMem = null; if (waveDevicePlayer != null) { waveDevicePlayer.Dispose(); } waveDevicePlayer = null; }
/* Note to programmers reading this for the first time: * Please do NOT be intimidated by all the comments in InitDemodulator! * They describe everything in gory detail. All you MUST know is this: * Instance these three objects from the XDft8 namespace: * Demodulator * WsjtSharedMemory * WsjtExe * * For the last two, choose the names in their properties carefully IF you * are going to run multiple instances of the Demodulator on the same PC. * * Set the Demodulator's callback delegate for decoded messages. * ...and do nothing more at initialization time. * * You also need a timer to call Demodulator.Clock(). See below. */ private void InitDemodulator(SetupForm sf) { // The objects implement IDisposable. If you fail to // dispose of one you quit using, its Windows resources // remain allocated until garbage collection. if (null != demodulator) { demodulator.Dispose(); } demodulator = null; if (null != wsjtSharedMem) { wsjtSharedMem.Dispose(); } wsjtSharedMem = null; if (null != wsjtExe) { wsjtExe.Dispose(); } wsjtExe = null; if (null != waveDevicePlayer) { waveDevicePlayer.Dispose(); } waveDevicePlayer = null; // The demodulator invokes the wsjtx decoder demodulator = new XDft.Demodulator(); // the names of its parameters are verbatim from the wsjt-x source code. // Don't ask this author what they mean. demodulator.nftx = 1500; demodulator.nfqso = 1500; demodulator.nQSOProgress = 5; demodulator.nzhsym = digiMode == XDft.DigiMode.DIGI_FT8 ? 50 : 18; mycall = sf.myCall.ToUpper(); demodulator.mycall = mycall; if (xmitForm != null) { xmitForm.mycall = mycall; } demodulator.digiMode = digiMode; // When the decoder finds an FT8 message, it calls us back... // ...on a foreign thread. Call BeginInvoke to get back on this one. See below. demodulator.DemodulatorResultCallback = new XDft.DemodResult(Decoded); // The wsjt-x code is run in a subprocess and we communicate with it using // cross-process shared memory. Such a construct requires the parent/sub-process // to agree on a name. That name must be unique to all the parent/sub's running // concurrently. That means that whatever name you give here must NOT // also be given to a copy of this programming running concurrently on the // same PC. For the test program, we leave it up to the user in the setup form. // that is a VERY bad idea for production...you have been warned. wsjtSharedMem = new XDft.WsjtSharedMemory(sf.sharedMemoryKey, false); if (!wsjtSharedMem.CreateWsjtSharedMem()) { MessageBox.Show("Failed to create Shared Memory from " + sf.sharedMemoryKey); return; } // The subprocess itself is managed by the XDft wsjtExe = new XDft.WsjtExe(); wsjtExe.AppDataName = sf.appDataName; if (!wsjtExe.CreateWsjtProcess(wsjtSharedMem)) { MessageBox.Show("Failed to launch wsjt exe"); demodulator.Dispose(); wsjtExe.Dispose(); wsjtExe = null; wsjtSharedMem.Dispose(); wsjtSharedMem = null; demodulator = null; return; } checkBoxEnableAP.Checked = demodulator.lft8apon; comboBoxnDepth.SelectedIndex = demodulator.ndepth - 1; #if DEBUG /* demonstrate how to use a native C++ dll to process ** incoming audio. Processing does not affect decoding. This is useful if you want to ** multi-instance XDft.Demodulator. Only one of XDft.Demodulator ** can call GetSignalSpectrum. The AudioProcessor interface can be instanced ** for multiple decodes concurrently and you can, for example, compute ** a spectrum in this processor .*/ IntPtr ip = XDft8RxAudioProcess.RxAudio.GetAudioProcessor(); demodulator.SetAudioSamplesCallback(new XDft.AudioCallback(SamplesCallback), 1000, 512, ip); #endif }