/* 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 }