ActiveX control MMVARI.ocx

	JE3HHT Makoto Mori
	Translated into English by JA7UDE Nobuyuki Oba

This document describes MMVARI ActiveX control, MMVAR.ocx.

~~~~~~~~
Contents
~~~~~~~~
o Version up history
o About MMVARI.ocx
o RX and TX channels
o Character transmission mechanism
o Sampling frequency
o MMVARI control property
o MMVARI control method
o MMVARI control event
o Multiple instance of MMVARI control
o About XMMVView control
o XMMVView control property
o XMMVView control method
o XMMVView control event
o About XMMVLvl control
o XMMVLvl control property
o XMMVLvl control method
o XMMVLvl control event
o Closing remarks


================
Version up history
================
- 2005.03.01 (Ver1.06)
	XMMVView control
		- wWidthFreq̒200HzɕύXiȑO500Hz)
- 2005.01.20 (Ver1.05)
	XMMVLvl control
		- Added DrawCustom method
- January 11, 2005 (version 1.04)
	MMVARI control
		- Fixed a bug (could not send Japanese half width kana)

- January 8, 2005 (version 1.03)
	MMVARI control
		- Added wRxCenter property
		- Added bCustomFilter and dblCustomSampleFreq properties
		- Added wNumNotches and wNotches properties
		- Added AddNotchFreq, FindNotchFreq, and DeleteNotch methods
		- Added CreateCustomFilter, DeleteCustomFilter, CreateCustomFilterByKW, CreateCustomFilterByIDFT, and CalcCustomCharacteristic methods
	XMMVView control
	- Added wMouseChannel and wMouseNotch properties

- December 29, 2004 (version 1.02)
	Added EXMMVARI.txt (TNX to JA7UDE)
	MMVARI control
		- Added bOverLevel property
		- Added bPTTLines property
	XMMVView, XMMVLvl control
		- Disabled getting the focus on mouse click
- December 28, 2004 (version 1.01)
	Fixed a bug in the XMMView (small waterfall)
- December 25, 2004 (version 1.00)
	First release


==================
About MMVARI.ocx
==================
MMVARI.ocx is an OLE custom control for VisualBasic6 programming.  It is equipped with a soundcard engine that supports four modes, GMSK, FSK, FSK-W, and BPSK, which can deal with the Varicode optimized for MBCS. In addition to these four modes, it is capable of three other standard modes, bpsk, rtty, and mfsk.

	MMVARI		Soundcard engine
	XMMVView	Paint control for spectrum, waterfall, and waveform
	XMMVLvl	Level meter control
	XMMVBtn	Toggle button control

This document does not explain XMMVBtn control. Refer to the sample container (Test) in this package for more information on XMMVBtn control.


Files in this package
~~~~~~~~~~~~~~~~
	MMVARI.ocx	Core file of the MMVARI ActiveX
	XMMVARI.txt	Japanese instruction manual
	EXMMVARI.txt	English instruction manual

The application using any control in MMVARI.ocx must include MMVARI.ocx in its distribution package. Generally, it is a good idea to have MMVARI.ocx in the same folder where the application resides.

To open the test container source code in the VisualBasic 6.0, you should have MMVARI.ocx in the folder that has your source code files.

MMVARI.ocx creates VariCode.tbl in the same folder when it is called for the first time. The object of the file is to boost the speed of the program startup next time and then. If MMVARI.ocx does not find the file at the start up, it automatically creates the file. Therefore, the application package does not have to include the file for distribution.

MMVARI.ocx supports the following Windows platforms:
	Windows@95, 98, 98SE, ME
	Windows@NT, 2000, XP



================================
RX and TX channels
================================
MMVARI control is equipped with nine RX channels (one for main, eight for sub), and one TX channel. The RX channels are indexed from 0 to 8. RX channel 0 is called the main channel. The mode and baud rate of the TX channel are always the same as those of RX channel 0.

Most properties of RX channel are implemented in an array form indexed by the channel number. Since array property cannot be seen in the VisualBasic6 form designer, you could use the object browser instead.

Examples
	strMode(nIndex As Integer) As String		Mode name
	dblSpeed(nIndex As Integer) As Double		Transfer speed

If you set True to bActive property, Channel 0 is made active, and bRxEnabled(0) becomes True. To make Channel 1 active, for example, do bRxEnabled(1)=True.


* As the number of RX channels increases, MMVARI uses more CPU resources.



============================
Character transmission mechanism
============================

MMVARI.ocx has two methods for sending characters. You can use either of them, or both at the same time.

Asynchronous method
~~~~~~~~~~~~~~~~~~
This method transmits characters through the circulate TX buffer equipped in MMVCARI.ocx. The buffer can hold up to 2048 characters. For this purpose, the following properties and methods are provided:

	wBufferCount As Integer
	Function SendText(strText As String) As Integer
	Function SendCWID(strText As String) As Integer
	Function SendChar(wChar As Integer) As Integer
	Function GetSendText() As String

For more information, see the property and method sections.

Synchronous method
~~~~~~~~~~~~~~~~
MMVARI.ocx requests one character on OnGetTxChar event. This method is suited for the scheme in which the user application peeks TX characters one bye one from its TX window and sends them to MMVARI.ocx.

* The sample container uses this method for reference.
* You could use the asynchronous and synchronous methods at the same time. MMVARI control checks if the TX buffer is empty; if so, it generates OnGetTxChar event to inquire the next character to transmit.



====================
Sampling frequency
====================
MMVARI control supports various sampling frequencies. The RX sampling frequency is defined by dblSampleFreq property. The offset for the TX sampling frequency can be defined by dblTxOffset property in Hz. Sampling frequencies that MMVARI supports are shown below. The default sampling frequency is 11025Hz.
11025Hz	One of the standard frequencies supported by all the soundcards
12000Hz	Frequency that is likely to have zero offset (TxOffset=0), but not supported by all soundcards
6000Hz	Low CPU load, but not supported by all soundcards
8000Hz
16000Hz
18000Hz
22050Hz	One of the standard frequencies, having no specific merit.
24000Hz
44100Hz	One of the standard frequencies, having no specific merit.
48000Hz	For an optical digital interface

* Use 6000Hz for old PCs.
* 8000Hz has some time lag in the spectrum and waterfall display from RX signals because of the number of FFT points misaligned.
* You can change the sampling frequency anytime on the fly.

The discrimination of the sampling frequency will not cause severe problems in MMVARI though it will in SSTV. However, the discrimination will result in the frequency mismatch in the practical QSO. It does not cause a trouble in normal QSOs when the AFC is engaged, but it does for receiving weak signals. For this reason, it is a good idea your application allows the user to adjust TxOffset.



================================
MMVARI control property
================================

bActive As Boolean
~~~~~~~~~~~~~~~~~~
This property is used to start and stop the MMVARI control. Upon putting True to bActive, MMVARI opens the soundcard and starts receiving the main channel in the default mode. Upon putting False to bActive, MMVARI closes the soundcard and releases all the resources, such as a COM port.

* When bActive is False, MMVARI does not generate any event.

* When the MMVARI control is discarded, all the resources that MMVARI uses are automatically released. The application does not have to set False to bActive on exit.


bAddStartCR As Boolean
~~~~~~~~~~~~~~~~~~~~~~
If True, MMVARI sends CR/LF at the beginning of the transmission.


bAddStopCR As Boolean
~~~~~~~~~~~~~~~~~~~~~
If True, MMVARI sends CR/LF at the end of the transmission.


bATC As Boolean
~~~~~~~~~~~~~~~
If True, Automatic Timing Control (ATC) is turned on. In the rtty mode, ATC is always off irrespective of this property. In the mfsk mode, on the other hand, ATC is always on irrespective of this property. 

*It is recommended to keep ATC on all the time for better signal decoding.


bLoopExternal As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~
If True, the sound loopback mode is set to External. This is used for adjusting the TX timing or for satellite communication.


bNET As Boolean
~~~~~~~~~~~~~~~
If True, the NET is on, that is, the TX frequency follows the RX frequency.


bPlayBack As Boolean
~~~~~~~~~~~~~~~~~~~~
If True, the sound playback function is enabled. To start the playback function, call PlayBack method.

* The sound playback function stores the PCM sound data for the latest 60 seconds in the MMVARI control. In case of the 11025Hz sampling frequency, it uses about 1.3MB memory space for the sound playback.


bReqRX As Boolean
~~~~~~~~~~~~~~~~~
If True, MMVARI automatically returns to RX when the encoder enters an idle phase (i.e., no characters remain in the TX buffer).


bRxEnabled(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

If True, RX channel(nIndex) becomes active. BRxEnabled(0) is equivalent with bActive property. Activating any of RX channels changes bActive property to True.


bSQ(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX chennel #

This property gives the squelch status of RX channel(nIndex).


bSync(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property shows the synchronization status of RX channel(nIndex).


bTX As Boolean
~~~~~~~~~~~~~~
This property is used to switch TX and RX. Putting False to bTX instantaneously makes MMVARI return to RX even during the transmission. Use bReqRX property for normal TX termination, which performs the proper amplitude control.


bHPF As Boolean
~~~~~~~~~~~~~~~
If True, the high-pass filter is engaged for RX. Although this is unnecessary for most soundcards, it sometimes is effective for eliminating hum in the input audio.


bNotch As Boolean
~~~~~~~~~~~~~~~~~
If True, the notch filter is engaged. Use wNotchFreq to specify the notch filter frequency.

* MMVARI.ocx still has this property for the backward compatibility for version 1.02 or older versions. MMVARI.ocx version 1.03 and later can have multiple notch frequencies. Use wNotches property, and AddNotchFreq, FindNotchFreq and DeleteNotch methods.


bMetricSqMFSK As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~
If True, mfsk metric level is used for the squelch. If False, the S/N level is used for the squelch. This property is effective only for mfsk.


bTreatCenterMFSK As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If True, the center frequency is used for the carrier frequency. If False, the base tone frequency is used for the carrier frequency.


bUOS(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

If True, RTTY UOS is active for RX channel(nIndex). This property is effective only for RTTY.


bPTTLock As Boolean
~~~~~~~~~~~~~~~~~~~
If True, MMVARI exclusively uses the PTT port specified by strPTTPort. If False, MMVARI opens the PTT port only during TX. In case strPTTPort is NONE, this property has no effect.


bCodeMM(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

bCodeMM specifies the MMVARI code. The code is VariJA, VariHL, VariBV, or VariBY. This property is affected by wCharset property and the RX mode.


bPTTLines(nLine As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the state of the PTT control lines. If strPPTPort is NONE, this property is not effective.

	0 = pttlineRTS	RTS
	1 = pttlineDTR	DTR
	2 = pttlineTXD	TXD

Example:
	bPTTLines(pttlineRTS) = True
	bPTTLines(pttlineDTR) = False


bOverLevel(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX chennel #

This property shows the overflow status of RX channel(nIndex).

bCustomFilter As Boolean (RaadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows if the RX custom filter is engaged.


dblCustomSampleFreq As Double (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property is the sampling frequency (Hz) of the RX custom filter. See CreateCustomFilter method section.


dblFFTSampleFreq As Double (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property is the FFT sampling frequency in Hz.


dblSampleFreq As Double
~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the RX sampling frequency.


dblTxOffset As Double
~~~~~~~~~~~~~~~~~~~~~
This property specifies the TX sampling frequency offset with respect to the RX sampling frequency.


dblSpeed(nIndex As Integer) As Double
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property specifies the baud rate of RX channel(nIndex).

dblFreqError(nIndex As Integer) As Double (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property shows the RX frequency discrimination (-0.5 to 0.5). When AFC is on, this value will converge to 0.


dblBandWidth(nIndex As Integer) As Double (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property shows the bandwidth of RX channel(nIndex). In the standard RTTY, it is 170Hz. It should be noted, however, that this property value is different from the bandwidth for actual signal transmission, which actually requires wider bandwidth. 


dblTxShift As Double
~~~~~~~~~~~~~~~~~~~~
This property specifies the TX shift width in Hz for RTTY and FSK-W. If the shift widths for TX and RX are far different, the loopback will not function during TX.


dblRxShift(nIndex As Integer) As Double
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property specifies the RX shift width in Hz for RTTY and FSK-W.


dwATC As Long
~~~~~~~~~~~~~
This property specifies the adjustment offset in ppm for the RX sampling frequency. When bATC is True, MMVARI automatically manages the dwATC value.


dwHandle As Long (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the object handle of the MMVARI control. This handle is used for XMMVLvl and XMMVView controls.

Once the MMVARI object has been established, dwHandle never changes. Therefore, you could use a static variable as shown below.

	Dim g_dwHandle As Long

	Private Sub Form_Load()
	    g_dwHandle = MMVARI.dwHandle
		|
	End Sub

	Private Sub MMVARI_OnDrawFFT(ByVal wCount As Integer, pArray As Long)
	    Call XMMVView.Draw(g_dwHandle)
	    Call XMMVLvl.Draw(g_dwHandle, 0)
	End Sub


dwSampleBase As Long (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property gives the base sampling frequency. It, for example, is 11025 or 12000.


nBPF As Integer
~~~~~~~~~~~~~~~
This property specifies the bandwidth of the RX BPF. MMVARI automatically adjusts the width in accordance with the mode and speed. It affects all the RX channels.

	0 - Wide
	1 - Middle
	2 - Narrow
	3 - Ultra narrow


statIsPlaying As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property indicates if the sound playback function is running.


statLostRX As Integer
~~~~~~~~~~~~~~~~~~~~~
This property indicates if a part of the RX sound is lost. When the sound lost is detected, this property becomes non-zero for approximately three seconds.


statLostTX As Integer
~~~~~~~~~~~~~~~~~~~~~
This property indicates if a part of the TX sound is lost. When the sound lost is detected, this property becomes non-zero for approximately three seconds.


statSoundOpen As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the status of the soundcard.
	1 - Opened as input
	2 - Opened as output
	3 - Opened as input/output


statComOpen As Integer
~~~~~~~~~~~~~~~~~~~~~~
This property shows the COM port status.
	0 - Not in use
	1 - Opened
	-1 - Failed to open


strVersion As String (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property has the version number of the MMVARI control.


strPTTPort As String
~~~~~~~~~~~~~~~~~~~~
This property specifies the COM port name for PTT. Put "NONE" to this property if you do not use the PTT control function build in MMVARI. The COM port for PTT will not be opened until True is set to bActive property.

Example:	strPTTPort = "COM1"

Use OnPTT event for PTT make/break control.


strSoundID As String
~~~~~~~~~~~~~~~~~~~~
This property specifies the soundcard ID(s).

	-1	Windows default
	0	First soundcard
	1	Second soundcard
	:		:

To specify different soundcards for RX and TX, specify two numbers with a comma in between like:
	0,1	(RX uses the first soundcard and TX uses the second soundcard)

To specify a custom sound, put the name (e.g., WLClient) to this property.

Examples:
	strSoundID = "-1"	'Use Windows default (sound mapper)
	strSoundID = "0,1"
	strSoundID = "WLClient"


strModeList(nIndex As Integer) As String (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property returns the modes supported by the MMVARI control. nIndex is the mode number, and must be between 0 and wModeMax-1.

Example code:	CBMode.Clear
	For i = 0 To MMVARI.wModeMax - 1 Step 1
		CBMode.AddItem (MMVARI.strModeList(i))
	Next i

The current version supports the following modes:
	GMSK		MBCS experiment (HF)
	FSK		MBCS experiment (V/UHF)
	FSK-W		MBCS experiment (V/UHF, satellite)
	BPSK		MBCS experiment (HF)
	bpsk		Standard bpsk
	rtty-L		BAUDOT (LSB)
	rtty-U		BAUDOT (USB)
	mfsk-L		MFSK (LSB)
	mfsk-U		MFSK (USB)

* In the non-MBCS code set, BPSK and bpsk work in the same manner.

* In future MMVARI versions, more modes will be implemented. It is a good idea for the application to have a mode combo-box by referring to wModeMax and strModeList.

strMode(nIndex As Integer) As String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the mode in the Channel(nIndex). If nIndex is 0, the TX mode is also set.
Example:	strMode(0) = "bpsk"

* The mode change will induce the speed change. For example, the mode is changed from bpsk to rtty-L, MMVARI changes the baud rate to 45.45bps. In such a case, MMVARI generates OnSpeed event.


wChannels As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property returns the maximum number of RX channels supported in the current version. Version 1.00 returns 9.


wModeMax As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property returns the number of modes supported in the current version. Version 1.00 returns 9. To get each mode name, use strModeList property.


wCharset(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #

This property specifies the font character set for RX channel(nIndex). MMVARI defines the MBCS VARICODE based on the character set specified here. The application supporting two or more code sets, put the character set to this property.
Example:	MMVARI.wCharset(0) = RxWindow.Font.Charset

To get the VARICODE of the specified MBCS language, call GetVariType.

* RTTY uses BAUDOT code only.


wFFTType As Integer
~~~~~~~~~~~~~~~~~~~
This property specifies the amplitude of the FFT display.
	0 - dB
	1 - Squared amplitude


wFFTWidth As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property has the number of points used in the FFT calculation. It is less than or equal to 2048.


wWaveMax As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the maximum number of points in the waveform data. The value depends on the mode, speed, and sampling frequency.


wModGain As Integer
~~~~~~~~~~~~~~~~~~~
This property specifies the digital output level in the rage of 0 to 32767. The default is 16384.


wRxCarrier(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the RX carrier frequency of RX channel(nIndex).


wRxCenter(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the center frequency (Hz) of the RX carrier of RX chennle(nIndex). In case bTreatCenterMFSK is False and the mode is mfsk, this property has a value different from wRxCarrier.


wSN(nIndex As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the S/N ratio (dB * 100) of RX channel(nIndex).


wSoundCH As Integer
~~~~~~~~~~~~~~~~~~~
This property specifies the sound input channel. The default is 0 (=Monaural).
	0 - Monaural
	1 - Left
	2 - Right


wSoundRxFIFO As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the depth of the RX FIFO. The valid value is 4 to 32.


wSoundTxFIFO As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the depth of the TX FIFO. The valid value is 4 to 32.


wSQLevel(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the squelch level (db * 100) of RX channel(nIndex). The default is 300 (=3db).


wTxCarrier As Integer
~~~~~~~~~~~~~~~~~~~~~
This property specifies the TX carrier frequency.


wMode(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the mode of RX channel(nIndex). If nIndex is 0, the TX mode is also set. This property uses the index number of modes. Use strMode for setting the mode by name.

Example:	wMode(0) = 4	' bpsk


wAFCLevel As Integer
~~~~~~~~~~~~~~~~~~~~
This property specifies the S/N level (dB) for the wide AFC. In case wAFCWidth is less than or equal to 50Hz, the wide AFC does not function and wAFCLevel is ignored. This property is applied to all the RX channels.


wAFCWidth As Integer
~~~~~~~~~~~~~~~~~~~~
This property specifies the frequency sweeping width (+/-Hz) for the AFC. This property is applied to all the RX channels.


wBufferMax As Integer
~~~~~~~~~~~~~~~~~~~~~
This property returns the maximum number of characters buffered in the TX circulate FIFO. The value of MMVARI.ocx version 1.00 is 2048.


wBufferCount As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property shows the number of characters remaining in the circulate TX buffer. The value cannot be increased. Every MBCS character, such as Japanese Kanji, is treated one character.
Examples:
	' Clear the buffer
	MMVARI.wBufferCount = 0

	' Delete one character
	MMVARI.wBufferCount = MMVARI.wBufferCount - 1


wCollectType As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property selects the collecting scheme of the waveform data. When the property value has 1 or 2, MMVARI generates OnDrawWave event at the end of wave draw.
	0 - collectNONE	No wave collection
	1 - collectSYNC	Decode signal collection
	2 - collectWAVE	Wave signal collection


wNotchFreq As Integer
~~~~~~~~~~~~~~~~~~~~~
This property specifies the notch filter frequency.

* MMVARI.ocx still has this property for the backward compatibility for version 1.02 or older versions. MMVARI.ocx version 1.03 and later can have multiple notch frequencies. Use wNotches property, and AddNotchFreq, FindNotchFreq and DeleteNotch methods.


wCWSpeed As Integer
~~~~~~~~~~~~~~~~~~~
This property specifies the CWID speed. The valid value is 10 to 60.


wDiddleRTTY As Integer
~~~~~~~~~~~~~~~~~~~~~~
This property specifies the diddle code in the RTTY idle state.
	0 - LTR
	1 - BRK


wTxState As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the TX/RX status.
	0 - txstateRX		RX
	1 - txstateTX		TX
	2 - txstateREQRX		TX and waiting for idle
	3 - txstateWAIT		Switching to RX (flushing PCM data in the sound buffer)
	4 - txstateTONE		Transmitting a single tone

wMetricMFSK(nIndex As Integer, nPhase As Integer) As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : RX channel #
nPhase : 0 = RX metric level, 1 = Even phase metric level, 2 = Odd phase metric level

This property indicates the metric level (0 to 2047) of RX channel(nIndex). MFSK16 at 15.625 baud has no odd phase.


wLang As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property returns the default language ID.


wDefaultCharset As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property returns the default character set. Non-MBCS language returns ANSI_CHARSET.

wNumNotches As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property has the number of eliminating frequencies the notch filter has.


wNotches(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nIndex : index of eliminating frequencies

This property specifies the eliminating frequencies in Hz (nIndex) of the notch filters. The number of active eliminating frequencies can be retrieved by referring to wNumNotches property, If nIndex is larger than wNumNothes, a new eliminating frequency is added. Put 0 to the property to deactivate the eliminating frequency.

The following example sets three eliminating frequencies, that is, 1000, 1500, and 2000Hz, to the notch filter.
	MMVARI.wNotches(0) = 1000
	MMVARI.wNotches(1) = 1500
	MMVARI.wNotches(2) = 2000

The next example deactivates the first eliminating frequency.
	MMVARI.wNotches(0) = 0

* The value of this property is 0 if the specified nIndex frequency has no eliminating frequency.
* If an eliminating frequency is deleted, the frequency indexes will be changed. Use FindNotchFreq method to retrieve the index of the particular frequency,.


wNotchTaps As Integer
~~~~~~~~~~~~~~~~~~~~~
This property is used to specify the number of taps of the notch filter. The default value is 128. MMVARI.ocx automatically calibrates the filter shape by changing the number of taps with respect to the sampling frequency. For example, wNotchTaps 128 with sampling frequency 6000Hz actually has 70 taps.

* The notch filter with larger number of taps gives a steeper shape factor, but it requires more CPU power.


==============================
MMVARI control method
==============================

Sub SetTX(wCmd As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~
This method is used to switch TX/RX. wCmd can be one of the following values:

	0=cmdtxRX	Switch to RX (same as bTX = False)
	1=cmdtxTX	Switch to TX (same as bTX = True)
	2=cmdtxREQRX	Switch to RX if idle (same as bReqRX = True)
	3=cmdtxCW	Switch to TX in the CW mode (MMVARI does not send an idle tone at the beginning and end of the transmission)
	4=cmdtxTONE	Send an unmodulated tone

The following sample sequence sends a CW ID and returns to RX immediately.
	MMVARI.wBufferCount = 0	' Clear buffer
	Call MMVARI.SendCWID("de JE3HHT")
	Call MMVARI.SetTX(cmdtxREQRX)
	Call MMVARI.SetTX(cmdtxCW)


Function GetSendText() As String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method returns all the characters in the TX buffer. The characters remain in the TX buffer.

	[Example]
	Dim strText As String
	strText = MMVARI.GetSendText()
	MMVARI.wBufferCount = 0	MMVARI.SendText ("<Insert>" & strText)


Function SendText(strText As String) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method appends String strText into the TX buffer and returns the number of characters in the TX buffer. It can be called in OnGetTxChar event. See OnGetTxChar section for details.


Function SendChar(wChar As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method appends a character wChar into the TX buffer and returns the number of characters in the TX buffer. It can be called in OnGetTxChar event. See OnGetTxChar section for details. wChar must be ANSI or MBCS character code.

  
Function SendCWID(strText As String) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method appends CW string strText into the TX buffer and returns the number of characters in the TX buffer. It can be called in OnGetTxChar event. See OnGetTxChar section for details.

The following characters are used for special CW codes:
	@	AS
	:	SK (VA)
	;	AR
	=	BT
	]	KN


Function GetVariType(nIndex As Integer) As String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method returns the VARICODE format of RX channel(nIndex).


Function PlayBack(wSec As Integer) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method executes the sound playback for wSec seconds. The valid value of wSec is 0 to 60. If wSec is 0, MMVARI stops the playback. If bPlayBack property is False, this method fails.


Sub SetClockAdjust(wTone As Integer, dblSampleFreq As Double)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wTone : Tone frequency of one second signal (Hz)
  dblSampleFreq : Sampling frequency of one second signal (Hz)

This method specifies the tuning parameters of the RX clock adjustment function.


Sub AdjustClock(wWidth As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wWidth : Width of the scan window for clock adjustment

This method starts the clock adjustment. You have to provide a graphic window with wWidth width. For more information, refer to the OnClockAdjust event section. To stop the clock adjustment, put 0 to wWidth and call this method.


Sub AttachLongArray(pDist As Long, pSrc As Long, wSize As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  pDist : Pointer to the destination array for copy
  pSrc : Pointer to the source array for copy
  wSize : Number of characters to copy
This method copies the array data. It works as the following VisualBasic6 code:

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Call CopyMemory(pDist, pSrc, wSize * 4)	'Windows API CopyMemory()


Function CreateVaricodeList(strName As String) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method creates the VARICODE list of file name strName.


Function ReadFFT(pArray As Long, wCount As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  pArray : Pointer to the array of FFT data
  wCount : Number of data

This method reads the FFT data asynchronously. The data is the same as the data given by OnDrawFFT event. You can call this method in OnDrawFFT event. The method returns the number of data being read if succeeded.

	Dim dwAmp(1023) As Long
	Call MMVARI.ReadFFT(dwAmp(0), 1024)


Sub AddNotchFreq(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : New eliminating frequency (Hz)

This method adds a new eliminating frequency to the notch filter. If the notch filter already has the same frequency, the method does nothing.

	Call MMVARI.AddNotchFreq(1000)


Function FindNotchFreq(wFreq As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Eliminating frequency to search (Hz)

This method searches for the specified frequency and returns the index if the frequency is found. If the frequency is not found, it returns -1.

	Dim nIndex As Integer
	nIndex = MMVARI.FindNotchFreq(1000)
	If nIndex >= 0 Then
		Call MMVARI.DeleteNotch(nIndex)
	End If


Sub DeleteNotch(nIndex As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : Index of the eliminating frequency

This method deletes the specified eliminating frequency. If nIndex is -1, all the frequencies are deleted and the notch filter is disengaged.


Function CreateCustomFilter(nTaps As Integer, pCoeff As Double) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nTaps : Number of taps of the filter
  pCoeff : Coefficient data array (nTaps+1)

The method creates a custom RX filter. Using this method, the user can create a filter with arbitrary parameters. The filter is of nTaps+1 FIR type. MMVARI.ocx uses this filter as a notch filter (the built-in notch filter is automatically disengaged). The sampling frequency can be referred to by dblCustomSampleFreq property.

The number of coefficient data is nTaps+1. 64 tap filter, for example, requires 65 coefficient data. You can make a steep filter by using a large number of taps, but you need more CPU power.

	Dim dblCoeff[64] As Double
	' To do : Put coefficient data to dblCoeff(0 to 64)
	Call MMVARI.CreateCustomFilter(64, dblCoeff(0))

See DSP documents to calculate the coefficients for the filter. For creating a simple filter, MMVARI.ocx provides CreateCustomFilterByKW and CreateCustomFilterbyIDFT methods.

* The filter is inserted just after the subsamping stage (sound front end), just before the FFT processing.
* Activating the built-in notch filter automatically disables the custom filter.


Sub DeleteCustomFilter()
~~~~~~~~~~~~~~~~~~~~~~~~
This method deletes the custom RX filter.


Function CreateCustomFilterByKW(nType As Integer, nTaps As Integer, dblFC1 As Double, dblFC2 As Double, wDB As Integer) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nType : Filter type (0-LPF, 1-HPF, 2-BPF, 3-BEF)
  nTaps : Filter order (must be an even number)
  dblFC1 : First cut-off frequency in Hz
  dblFC2 : Second cut-off frequency in Hz
  wDB : Attenuation value (dB) for the eliminating frequency range

This method creates a custom RX filter. MMVARI calculates the impulse response using the given parameters and calls CreateCustomFilter method. If wDB is 0, the filter coefficients are compliant to the impulse response. LPF and HPF do not use dblFC2. If an odd number is assigned in nTaps, this method fails.

	Dim dblF1 As Double
	Dim dblF2 As Double
	dblF1 = MMVARI.wRxCenter(0) - MMVARI.dblBandWidth(0)
	dblF2 = MMVARI.wRxCenter(0) + MMVARI.dblBandWidth(0)
	Call MMVARI.CreateCustomFilterByKW(2, 128, dblF1, dblF2, 60)


Function CreateCustomFilterByIDFT(nTaps As Integer, pFreqSamp As Double, wDB As Integer) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nTaps : Filter order (must be an even number)
  pFreqSamp : Array of frequency-gain data (nTaps/2)
  wDB : Attenuation value (dB) for the eliminating frequency range

This method creates a custom RX filter using the frequency-gain data. MMVARI control calculates the filter coefficients using the given frequency-gain data, and calls CreateCustomFilter method. If wDB is zero, the filter coefficients are compliant to the impulse response. If an odd number is assigned in nTaps, the method fails.

The frequency-gain data must be in the range of 0 to 1. The resolution must be dblCustomSampleFreq/nTaps. MMVARI uses nTaps/2 data. The example below has array X and tone frequency Freq.

	X = Freq * nTaps / dblCustomSampleFreq
	Freq = X * dblCustomSampleFreq / nTaps

 	[Example]
	Const NumTAPS = 132
	Dim dblFreqSamp(NumTAPS / 2) As Double
	Dim i As Integer
	For i = 0 To (NumTAPS / 2) Step 1
		dblFreqSamp(i) = 0#
	Next i
	dblFreqSamp(1000# * NumTAPS / MMVARI.dblCustomSampleFreq) = 1#
	Call MMVARI.CreateCustomFilterByIDFT(NumTAPS, dblFreqSamp(0), 60)


Function CalcCustomCharacteristic(pAmp As Double, pPhase As Double, wWidth As Integer, wMaxFreq As Integer) As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  pAmp : Array for gain characteristics
  pPhase : Array for phase characteristics
  wWidth : Array size
  wMaxFreq : Maximum frequency (Hz)

This method calculates the frequency gain phase characteristics of the custom RX filter. If no custom filter is created, the method fails. In the range of 0 to wMaxFreq (Hz), wMaxFreq/wWidth data are calculated. Supposing X be an array and Freq be frequency, the following equations are given.

	Freq = X * wMaxFreq / wWidth
	X = Freq * wWidth / wMaxFreq

The gain values are in the range of 0 to 1.0 for a standard filters with gain 1. The phase values are in the range of -pi to +pi.


	Dim dblAmp(800-1) As Double
	Dim dblPhase(800-1) As Double
	Call MMVARI.CalcCustomCharacteristic(dblAmp(0), dblPhase(0), 800, 3000)
	' To do : Draw a graph using dblAmp and dblPhase values.


==============================
MMVARI control event
==============================

OnGetTxChar(wChar As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wChar : Character to send (ANSI or MBCS)

This event is generated just before the idle. Put a character (ANSI or MBCS) in wChar to send. If wChar is 0, MMVARI sends an idle character.

	Private Sub MMVARI_OnGetTxChar(wChar As Integer)
		wChar = &H41	'Send A
	End Sub

You can call SendText method in the OnGetTxChar event handler. In that case, you cannot put any character in wChar.

	Private Sub MMVARI_OnGetTxChar(wChar As Integer)
		Call MMVARI.SendText ("Hello")
	End Sub

* The sample container in this package has an example code of this event.

* The sound processor has a buffer, and therefore you will receive several OnGetTxChar events before the sound buffer is fulfilled.

* To send a CW code, add 256 to the ASCII code and put it in wChar. For example, the CW code for 'A' is 321. Alternatively, you can call SendCWID method.


OnRxChar(ByVal nIndex As Integer, ByVal strChar As String, ByVal wChar As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX channel #
  strChar : Received character (BSTR)
  wChar : Received character (ANSI or MBCS)

This event occurs when a character is received in RX channel(nIndex). You do not have to care about odd delimiters even in MBCS. strChar and wChar are the same data expressed in different formats, so you could use either of them as you like.


OnRxCarrier(nIndex As Integer, wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX channel #
  wFreq : RX frequency

This event occurs when the RX frequency is changed in RX channel(nIndex). This event also occurs immediately after the RX channel is activated.


OnTxCarrier(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : TX frequency

This event occurs when the TX frequency is changed. This event also occurs immediately after the MMVARI control is activated.


OnDrawFFT(wCount As Integer, pArray As Long)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wCount : Number of effective FFT data points
  pArray : Array of FFT data

This event occurs at the update timing of the spectrum drawing. The number of effective FFT data points is less than half of the number of FFT points (sFFTWidth). You can draw the spectrum or waterfall view triggered by this event.

The relation between the FFT data position (X) and the tone frequency (Freq) is defined as follows. 
	Freq = X * dblFFTSampleFreq / wFFTWidth
	X = Freq * wFFTWidth / dblFFTSampleFreq

MMVARI will perform sub-sampling in some sampling frequencies. Since the FFT sampling frequency during TX can be affected by dblTxOffset, it is recommended you refer to dblFFTSampleFreq and wFFTWidth for drawing the spectrum.

The value held in each cell of the array is 0 to 10900. When the FFT data is in the dB format, 10900 corresponds to 100dB.

Private Sub MMVARI_OnDrawFFT(ByVal wCount As Integer, pArray As Long)
	If wCount Then
		Dim fft(2047) As Long
		Call MMVARI.AttachLongArray(fft(0), pArray, wCount)
		' To do : See array fft here and draw the spectrum or waterfall
	End If
End Sub

* From statistical perspective, this event occurs every wFFTWidth/dblFFTSampleFreq seconds. For example, it occurs every 186msec for dblSampleFreq=11025Hz. During the sound playback, the events occur more frequently.

* While MMVARI is trying to open a soundcard, it generates this event every one second (wCount=0).

* You can print the S/N ratio level using this event timing.

To use XMMVView and XMMVLvl controls, just call them with the object handle like the sample shown below. 

Private Sub MMVARI_OnDrawFFT(ByVal wCount As Integer, pArray As Long)
	Call XMMVView.Draw( MMVARI.dwHnalde )
	Call XMMVLvl.Draw( MMVARI.dwHandle, 0 )
End Sub


OnDrawWave(wCount As Integer, pArray1 As Long, pArray2 As Long)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wCount : Number of effective data
  pArray1 : Pointer to the array of replay clock signals and decoded data
  pArray2 : Pointer to the array of decoded data or wave data (PCM data)

This event occurs at the timing of waveform redraw. The number of effective data varies depending on the mode and speed, but it never exceeds wWaveMax. You redraw the scope in your application using this event timing.

Each data in pArray1 and pArray2 has value between -16384 and 16384. Replay clock signals and decoded data always fit in this range. Wave data, on the other hand, are affected by the RX signal level. Therefore, you might want to engage a simple AGC function.

	wCollectType = collectSYNC		pArray1 = replay clock signals, pArray2 = decoded signals
	wCollectType = collectWAVE		pArray1 = decoded signals, pArray2 = wave signals

To use XMMVView control, you just call it with the MMVARI object handle like the sample below.

Private Sub MMVARI_OnDrawWave(wCount As Integer, pArray1 As Long, pArray2 As Long)
	Call XMMVView.DrawWave( MMVARI.dwHnalde )
End Sub


OnPTT(wTX As Integer)
~~~~~~~~~~~~~~~~~~~~~
  wTX : 0 - PTT OFF, 1 - PTT ON

This event occurs when the PTT make/break is required. If you do not use the PTT controller in MMVARI, you should make/break PTT using this event.


OnNET(bNET As Integer)
~~~~~~~~~~~~~~~~~~~~~~
  bNET : NET state

This event occurs when the NET state is changed.


OnTxState(wState As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This event occurs when the TX/RX state is changed. wState is defined as follows:
	0=txstateRX	Switched to RX
	1=txstateTX	Switched to TX
	2=txstateREQRX	Switched to idle
	3=txstateWAIT	Switching to RX (flushing the PCM data in the TX sound buffer)
	4=txstateTONE	Switched to single TX tone


OnMode(nIndex As Integer, mIndex As Integer, strMode As String)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX channel #
  mIndex : Mode number (0-)
  strMode : Mode name

This event occurs when the mode of RX channel(nIndex) is changed. It also occurs just after the RX channel is activated.


OnSpeed(nIndex As Integer, dblSpeed As Double)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX channel #
  dblSpeed : Speed (Baud)

This event occurs when the speed of RX channel(nIndex) is changed. It also occurs just after the RX channel is activated.


OnTiming(nIndex As Integer, dwTiming As Long, wUnit As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  nIndex : RX channel #
  dwTiming : Timing value
  wUnit : Unit of timing value (0=PPM, 1=ms multiplied by 100)
This event occurs when the RX clock timing is changed in RX chennel(nIndex). In the RTTY mode, the unit of the timing value is ms multiplied by 100. 0 means MMVARI is calculating the timing. In all the modes other than RTTY, the unit of the timing value is ppm.


OnPlayBack(wStat As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wStat : Playback status: 0=end, 1=start

This event occurs when the sound playback is started or ended.


OnClockAdjust(pArray As Long)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  pArray : Pointer to the array of level values (the number of values is defined by wWidth of AdjustClock method)

This event occurs when MMVARI is ready for offering one scan like data every one second. You read the data in pArray and converts to the brightness or color to draw the graphic, just like FAX and SSTV.
The level value in each cell is in the range of 0 to 16384, but it varies depending on RX signal level, condx, and tuning. You should do fine tuning of the graphic drawing by receiving WWV tick sound. You may want to implement a simple AGC in your code.

The next sample is a code that draws a picture with width 800 pixels.

Call SetClockAdjust(1000, 11025.0)
Call AdjustClock(800)
	|

Private Sub MMVARI_OnClockAdjust(pArray As Long)
	Dim level(800-1) As Long
	Call MMVARI.AttachLongArray(level(0), pArray, 800)
	'To do: Draw one line in the graphic window
End Sub


OnError(nErrorCode As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This event occurs when MMVARI detects an error. nErrorCode is:

	1=errorLostRX	Lost RX sound
	2=errorLostTX	Lost TX sound
	3=errorSoundOpen	Failed to open the soundcard
	4=errorComOpen	Failed to open the COM port


===================================
Multiple instances of MMVARI control
===================================

You can make two or more MMVARI instances at the same time. For example, if you place two or more MMVARI control using the form designer, each MMVARI control works independently. This situation is just like two or more programs that use the soundcard running simultaneously, and therefore please pay attention to the following points:

1) Some conventional sound drivers will not allow two or more programs to access the sound card simultaneously. In this case, you will see only one MMVARI control successfully opens the sound card and the others return an error. You might want to specify different sound IDs for different MMVARI instances.

2) The same COM port cannot be shared. You will have to assign a different COM port to each instance. If you do not use the MMVARI PTT control, you have no problem.



==============================
About XMMVView control
==============================

XMMVView control is a supplemental control for displaying the spectrum and waterfall. It has a fixed skin, and therefore I would not recommend it for serious use. I trust, however, that it is useful for experimental use.

XMMVView control is supposed to use with VisualBasic6 form designer. There is no limit in the number of controls to allocate. For example, if you want to place the spectrum and waterfall on the window, you could place two XMMVView control. The small waterfall for subchannels can be allocated in each subwindow.

* In response to mouse left button click, XMMVView control automatically sends a message to MMVARI control. If you want to disable this function, set False to bAttachMouse property.


==================================
XMMVView control property
==================================

wType As Integer
~~~~~~~~~~~~~~~~
This property defines the display content.
	0=viewtypeFFT		Specturm
	1=viewtypeWATER		Waterfall
	2=viewtypeWAVE		Waveform
	3=viewtypeFREQERR	AFC level meter
	4=viewtypeSMALLWATER	Waterfall without scale


bFollowRxFreq As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~
If True, XMMVView automatically adjust wBaseFreq so that the main channel frequency is always visible in the scope.


bAttachMouse As Boolean
~~~~~~~~~~~~~~~~~~~~~~~
If True, XMMVView automatically sends a message to MMVARI in response to left mouse click. If False, the application is in charge of all the mouse related events.


bLSB As Boolean
~~~~~~~~~~~~~~~
Set True to this property if the receiver is in the LSB mode. It is not effective if dwFreqHz is 0.


bWaterAGC As Boolean
~~~~~~~~~~~~~~~~~~~~
If True, the AGC is engaged in the waterfall display.


bShowSync As Boolean
~~~~~~~~~~~~~~~~~~~~
If True, XMMVView shows SYNC status at the top left corner of the window.


bHighQuality As Boolean
~~~~~~~~~~~~~~~~~~~~~~~
If True, the spectrum is displayed in the fine mode. It is useful for small wWidthFreq.


bShowErrorMsg As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~
If True, XMMVView displays the error information (strErroMsg) at the bottom right corner of the window.


bWindowsMouseEvent As Boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If True, XMMVView sends a message to the application in response to a Windows mouse event. The mouse event is defined by the name of OnWindowsXXXX. The cursor position included in the message is the pixel position in the control client region. Use wPixelXW and wPixelYW for the conversion.


ColorFFT(nIndex As Integer) As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the colors of the items in the spectrum.

	nIndex	Item
	0	Background color
	1	Signal color
	2	Character color
	3	Scale line color
	4	RX cursor color
	5	TX cursor color


ColorWater(nIndex As Integer) As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the colors of the items in the waterfall.

	nIndex	Item
	0	Background color
	1	Signal strength 0 color
	2	Character color
	3	Marker frame color
	4	RX marker color
	5	TX marker color
	6	Signal strength 1 color
	7	Signal strength 2 color
	8	Signal strength 3 color 
	9	Signal strength 4 color 
	10	Signal strength 5 color 
	11	Signal strength 6 color 

XMMVView automatically generates 256-level colors in WaterPallete property by referring to Signal strength 0 to 6 colors and wWaterLevel property.


ColorWave(nIndex As Integer) As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the waveform colors.
	nIndex	Item
	0	Background color
	1	Signal color
	2	Character color
	3	Horizontal scale line color


ColorFreqErr(nIndex As Integer) As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the colors of the items in the AFC level meter.
	nIndex	Item
	0	Background color
	1	Level color (AFC off)
	2	Level color (AFC on)
	3	Level color (Overflow)
	4	Center line color


WaterPalette(nIndex As Integer) As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property defines the waterfall pallet specified by nIndex, which is in the range of 0 to 255. XMMVView control converts the FFT signals to 256 levels and defines the colors by referring to this palette.

When you set a value to ColorWater or wWaterLevel property, XMMVView automatically updates WaterPalette property. In case you explicitly use the palette, therefore, you should not set a value directly to ColorWater or wWaterLevel property.


dwFreqHz As Long
~~~~~~~~~~~~~~~~
This property specifies the transceiver frequency. To put 14.073MHz in the transceiver, write 14073000 to this property. If dwFreqHz is 0, XMMVView displays the tone frequency on the scale. To display the transceiver frequency on the scale, you should set appropriate values to dwFreqHz and bLSB properties.


wBaseFreq As Integer
~~~~~~~~~~~~~~~~~~~~
This property specifies the left end frequency (Hz) of the spectrum or waterfall.


wWidthFreq As Integer
~~~~~~~~~~~~~~~~~~~~~
This property specifies the width of the frequency (Hz) displayed on the spectrum or waterfall.


wWaterLevel(nIndex As Integer) As Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the signal level (0 - 255) of nIndex. XMMVView generates 256-level WaterPalette property by referring to wWaterLevel and WaterColor properties. The default values are:

	0 = 10
	1 = 60
	2 = 134
	3 = 192
	4 = 220
	5 = 240


wWaterNoise As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property shows the noise floor (dB) during the waterfall drawing.
During RX, XMMVView automatically calculates the noise floor, which works as the start point of the drawing. The waterfall color is calculated with respect to this noise floor. The upper and lower limits are defined by the next two properties.


wWaterNoiseH As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the upper limit (dB) of the noise floor. The default value is 65.

wWaterNoiseL As Integer
~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the lower limit (dB) of the nose floor. The default value is 35.

wCursorFreq As Integer
~~~~~~~~~~~~~~~~~~~~~~
This property specifies the frequency of the tone cursor displayed on the waterfall. If 0, no cursor is displayed.


wPixelXW As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the control width in pixel.


wPixelYW As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the control height in pixel.


wMouseChannel As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property holds the subchannel number (1~) when the mouse cursor is on the subchannel indicator. 


wMouseNotch As Integer (ReadOnly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property holds the notch number (index+1) when the mouse cursor is on the notch indicator.


strMsg(nIndex As Integer) As String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property draws a message in the view. The position is defined by nIndex.

	0	Center
	1	Upper left
	2	Upper right
	3	Lower right
	4	Lower left

* If you want to draw a message in the localized language, you must set the font property of the control.

strErrorMsg(nIndex As Integer) As String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This property specifies the error message displayed in the view. nIndex specifies the error reason as follows:

	1=errorLostRX	RX sound was lost
	2=errorLostTX	TX sound was lost
	3=errorSoundOpen	Soundcard could not be opened
	4=errorComOpen	COM port could not be opened

* If you want to use the localized language, you must set the font property to the language.



================================
XMMVView control method
================================

Sub Draw(dwHandle As Long)
~~~~~~~~~~~~~~~~~~~~~~~~~~
This method draws the spectrum or waterfall. dwHandle is the object handle of theMMVARI control. dwHandle must be retrieved through MMVARI.dwHandle.

XMMVView control draws the spectrum or waterfall by referring to the FFT data (sampling frequency, number of data points, and metrics), TX/RX frequencies, and the notch frequency.

If this method is called at least once, XMMVView sends requests, such as frequency change, to MMVARI in response to mouse left click.

Sub DrawWave(dwHandle As Long)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method draws the waveform. dwHandle is the object handle of the MMVARI control. dwHandle must be retrieved through MMVARI.dwHandle. XMMVView draw the waveform by referring to the waveform data (number of points and metrics).


Sub DrawSmallWater(dwHandle As Long, nIndex As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method draws the small waterfall of RX channel(nIndex). dwHandle is the object handle of the MMVARI control. XMMVView draws the waterfall by referring to the FFT data (sampling frequency, number of data points, and metrics) and the RX frequency.

If this method is called at least once, XMMVView sends requests, such as frequency change, to MMVARI in response to the mouse left click.

* This drawing is supposed to be used in the status bar of the subchannel.
* This drawing automatically adjusts the wBaseFreq so that the RX frequency is always visible.


Sub DrawFreqErr(dwHandle As Long, nIndex As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This method draws the AFC level meter of RX channel(nIndex). dwHandle is the object handle of the MMVARI control. XMMVView draws the meter by referring to MMVARI's dblFreqError.


Sub ClearWater()
~~~~~~~~~~~~~~~~
This method clears the waterfall.


================================
XMMVView control event
================================

OnLMouseDown(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)
This event occurs when the mouse left button is depressed on the spectrum or waterfall.


OnLMouseUp(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)

This event occurs when the mouse left button is released on the spectrum or waterfall.


OnLMouseMove(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)

This event occurs when the mouse is moved over the spectrum or waterfall with the left button depressed.


OnRMouseDown(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)

This event occurs when the mouse right button is depressed on the spectrum or waterfall.


OnRMouseUp(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)

This event occurs when the mouse right button is released on the spectrum or waterfall.


OnRMouseMove(wFreq As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wFreq : Tone frequency (Hz)

This event occurs when the mouse is moved over the spectrum or waterfall with the right button depressed.


OnWindowsLMouseDown(wX As Integer, wY As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wX : Pixel position (X)
  wY : Pixel position (Y)

This event occurs when the Windows mouse event, WM_LBUTTONDOWN, is detected.


OnWindowsLMouseUp(wX As Integer, wY As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wX : Pixel position (X)
  wY : Pixel position (Y)

This event occurs when the windows mouse event, WM_LBUTTONUP, is detected.


OnWindowsRMouseDown(wX As Integer, wY As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wX : Pixel position (X)
  wY : Pixel position (Y)

This event occurs when the windows mouse event, WM_RBUTTONDOWN, is detected.


OnWindowsRMouseUp(wX As Integer, wY As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wX : Pixel position (X)
  wY : Pixel position (Y)

This event occurs when the windows mouse event, WM_RBUTTONUP, is detected.


OnWindowsMouseMove(dwFlag As Long, wX As Integer, wY As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@dwFlag : Button status (see a Windows API document)
  wX : Pixel position (X)
  wY : Pixel position (Y)

This event occurs when the Windows mouse envent, WM_MOUSEMOVE, is detected.

=============================
About XMMVLvl control
=============================
XMMVLvl is a supplemental control that draws a signal level meter. It is supposed to be located on the form using the VisualBasic6 form designer. There is no limit in the number of XMMVLvl control objects to allocate on the form. To support two or more RX channels, allocate the same number of XMMVLvl controls.
The meter swings horizontally or vertically by referring to the height/width aspect ratio of the control view. When the height is larger than the width, the meter swings vertically. When the height is smaller than the width, the meter swings horizontally.



=================================
XMMVLvl control property
=================================

BackColor As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~~
This property defines the background color.


MaxLevel As Integer
~~~~~~~~~~~~~~~~~~~
This property specifies the maximum S/N ratio multiplied by 100 (or MFSK metrics). The default value is 2048 (=20.48dB).


OffColor As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~~
This property defines the signal color when the squelch is closed.


OnColor As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~
This property defines the signal color when the squelch is opened.


TxColor As OLE_COLOR
~~~~~~~~~~~~~~~~~~~~
This property defines the signal color for TX.



===============================
XMMVLvl control method
===============================

Sub Draw(dwHandle As Long, nIndex As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  dwHandle : Object handle of the MMVARI control
  nIndex : RX channel number to draw

This method draws the level meter. dwHandle is the object handle of MMVARI control. dwHandle is the object handle of MMVARI control. Use the value of MMVARI.dwHandle. XMMVLvl control draws the meter by referring to the signal and squelch levels of the RX channel.

After this method is called at least once, XMMVLvl sends the squelch level change request to MMVARI in response to the mouse left click.

Sub DrawCustom(wSig As Integer, wSq As Integer, fOver As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  wSig: Signal level
  wSq: Squelch level
  fOver: Overflow

This method draws a level meter. You can use this function even if you do not instantiate an MMVARI control.


===============================
XMMVLvl control event
===============================

OnLMouseDown(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse left button is pressed.


OnLMouseUp(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse left button is released.


OnLMouseMove(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse is moved with the left button pressed.


OnRMouseDown(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse right button is depressed.


OnRMouseUp(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse right button is released.


OnRMouseMove(level As Integer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  level : Signal level (dB * 100)

This event occurs when the mouse is moved with the right button pressed.



=============
Closing remarks
=============

As I am not familiar with VisualBasic6, it took much more time for me to read tons of the manuals and make a sample container than to make this ActiveX. It is my great pleasure if this sample code is helpful for your programming.

MMVARI.ocx is freeware for amateur ham radio. You can freely use, modify, and distribute this package for commercial and non-commercial usage. You do not have to inform me anything about the license.

* If you implement the mfsk mode in a commercial program, you will have to get the permission from M. Greenman ZL1BPU and Nino Porcino IZ8BLY.

Good luck and 73,
Mako
