Communication between Spectrum Lab and other programs

Introduction

Some sophisticated applications required the control of Spectrum Lab by other programs, and vice versa (Spectrum Lab controlling other programs). This chapter describes the two possibilities: using the tiny HTTP server which is integrated in SpecLab, and a system using windows messages. The latter may be a bit simpler if both programs run on the same machine.

The integrated HTTP server

For remotely controlled operation of Spectrum Lab, you can use the integrated HTTP server. This has the following advantages:

Downside: Sending HTTP requests, and receiving the response (from the client's point of view) is not as fast as exchanging WM_COPYDATA messages locally (as explained in the next chapter). Details about the HTTP server inside SL can be found in the server_pages directory after the installation. There some examples (in HTML with javascript) in the server_pages directory too. If you read this document while SpecLab runs on the same machine, with the server enabled, try this link to check the remote control examples:

http://127.0.0.1:80

(127.0.0.1 is a dummy IP address of the local machine, and 80 is the default port number for HTTP = hypertext transport protocol )

To configure the built-in HTTP server, select "Options"..."Configure and supervise HTTP Server" in SL's main menu.

Note: If -besides the HTTP server- you also use the Audio-via-TCP/IP-Server, take care not to use the same IP port number for these function. Both servers use the IP address of the machine on which they run, so you must use a different port number for the HTTP server and the audio server. BTW, the default port number for an HTTP server is 80.

Communication using WM_COPYDATA messages

For this task, a simple communication protocol which uses WM_COPYDATA messages was implemented. Detailed information about this protocol for fellow programmers can be found on the author's website, search for the file yhf_comm_info.htm, titled

Communication between windows programs using WM_COPYDATA messages

(If the link fails due to server problems, copy the title into your favourite search engine - you may find the file on my "backup" site too)

I didn't include it in the Spectrum Lab documentation because it is used in other projects too (and there shall not be outdated copies of that document all over the place.. ;-) . So follow the above link for the latest up-to-date description of DL4YHF's "YHF_COMM" protocol if you are considering to...

No idea what such an application could be ? You can send any interpreter command which is mentioned in the SL manual in a WM_COPYDATA message, so you could..

The other way around, you can also

All this is possible ... but, due to the unavoidable time lag in the windows message processing system, this message system is not suitable for "tough" real-time operation. Expect a delay of some milliseconds until the command you sent to SL has been executed, and your program receives the result message.

All you have to know -in addition to the general message protocol- are the MODULE-ID's and COMMAND-ID's which are used to invoke the interpreter commands and -functions through WM_COPYDATA messages. The next chapter gives an overview of these values.

To send a windows message to Spectrum Lab, you must know its windows handle. This can be found with a WinAPI function called "FindWindow". For convenience, don't search for the window's title (which may change depending on the version), use the window's class name (lpClassName, which is the second parameter for "FindWindow"). The class name of Spectrum Lab's main window is TSpectrumLab. But this is not the only possibility:
To support communication between two instances of SpecLab running on the same PC, the program now used the following additional names (for programmers: SL creates an extra invisible window for this purpose, which has a unique class name) :

The old class name "TSpectrumLab" (for the main window) remains for backward compatibility.

Hint:
For testing purposes, open the "Command Window" in Spectrum Lab, and let it show all received and sent traffic in the message list (in the command window: "Options".."show Inter-Application Comm's").

Module- and Command Identifiers in Spectrum Lab

Module Identifiers for DL4YHF's inter-application message handler
Module Identifier Meaning
CL Command Line Interpreter
AU Audio Data

The third and fourth character in the message's dwData parameter contain the "command". They are specific to the "module ID". Here are the most important "command IDs" for the Command Line Interpreter built inside DL4YHF's Spectrum Lab:

Command Identifiers for the command line interpreter in DL4YHF's Spectrum Lab
Command Identifier Meaning
CF Calculate Function (with result returned in response message)
EC Execute Command (no result, will not send a response message)

A practical example: To stop the spectrum analyser, send the following message..

 COPYDATASTRUCT cds;
 // Set module ID "CL"  + command ID "EC" :
 cds.dwData = ('C')+((DWORD)'L'>>8)+((DWORD)'E'>>16)+((DWORD)'C'>>24);
 cds.lpData = "spectrum.pause=1";        // command sent to SpecLab's interpreter
 cds.cbData = strlen((char*)cds.lpData); // count of bytes in data block
 SendMessage(hDestWindow,WM_COPYDATA,(WPARAM)MyWindowHandle,(LPARAM)&cds);

How to send audio streams per WM_COPYDATA is explained in the next chapter.

See also: Spectrum Lab's main index, Spectrum Lab's interpreter commands, interpreter functions (in separate documents).


Audio via WM_COPYDATA

Note: If possible, do not use this feature, because it is not available under non-windows operating systems; and both sender and receiver must be running on the same PC. Better use one of the UDP or TCP/IP-based methods mentioned here : They allow sending audio over a local network, and even work between PCs running different operating systems (like Windows and Linux).

How to send audio streams via WM_COPYDATA messages

As explained in the previous chapter, the four bytes (here: four characters) in the dwData parameter of the WM_COPYDATA message must contain the "module identifier" (here: "AU" for audio data), followed by the "command identifier" (here: "SD" = stream data).

Below is the sourcecode of a C function which sends a block of audio samples through a WM_COPYDATA message (actually taken from audiomsg.c). The T_AudioMsgBuffer structure contains the audio block, and some information about the audio stream (like the number of channels, the sampling rate, etc). It is defined in the file audiomsg.h which is available in the archive "SoundUtlSources.zip". The same data structures are used when sending audio streams via UDP or TCP/IP.

/***************************************************************************/
long AudioMsgBuf_SendAudio_WMSG( T_AudioMsgBuffer *pBuf, HWND hwndMyWindow, HWND hwndHisWindow )
  // Sends a block of audio data through a windows MESSAGE (actually WM_COPYDATA) .
  // Return value:
  //  The FREE NUMBER OF ENTRIES (single values) IN THE RECEIVER'S BUFFER !
  //  This allows the sender (here: the caller) to keep the receiver's buffer 'as full as possible'.
  //  The caller may decide how many values to send (and, possibly, WHEN to send the next block).
  // Note: The return value is a count of *buffer entries*, NOT NECESSARILY
  //       a count of "audio sampling points" (divide by pBuf->info.i32NumChannels for that)
  // Return=0 means "the receiver couldn't handle the data" .
{
 LRESULT lResult;
 COPYDATASTRUCT cds;

  if( pBuf==NULL || hwndMyWindow==NULL || hwndHisWindow==NULL)
      return AUDIOMSG_RESULT_CANT_SEND;
  if( hwndMyWindow==hwndHisWindow )
      return AUDIOMSG_RESULT_CANT_SEND;  // too dangerous to send a WM_COPYDATA message to "myself" !

  cds.dwData = ('A')+((DWORD)'U'>>8)+((DWORD)'S'>>16)+((DWORD)'D'>>24);
  // module="AU" + command="SD"(Stream Data)
  cds.cbData = sizeof(T_AudioMsgInfo) // count of bytes in data block (including info header)
             + sizeof(SHORT) * pBuf->info.i32NrSamplePointsInBlock * pBuf->info.i32NumChannels;
  cds.lpData = &pBuf->info;  // pointer to data block : we begin sending with the AUDIO INFO header,
                             // followed directly by the audio samples in T_AudioMsgBuffer .
                             // So the "receiver" will always know the most important parameters.
  lResult = SendMessage( // "SEND", not "POST"  ! (send may block the caller - see notes)
              (HWND)hwndHisWindow,  // HWND hWnd = handle of destination window
              WM_COPYDATA,          // UINT Msg  = message to send
              (WPARAM)hwndMyWindow, // HANDLE OF SENDING WINDOW
              (LPARAM)&cds ); // 2nd  msg parameter = pointer to COPYDATASTRUCT
     // Notes:
     //  - WM_COPYDATA can only be SENT, not POSTED !
     //  - If the destination window is this application itself,
     //    the SendMessage()-function will not return while we wait
     //    somewhere without calling the message loop !
     //    (Keep this in mind if AudioMsg_Send() *seems to* crash !
     //  - if SendMessage() cannot send, it returns ZERO = AUDIOMSG_RESULT_CANT_SEND
  return lResult;
}


See also: Spectrum Lab's main index, Spectrum Lab's
interpreter commands, interpreter
functions (in separate documents).
  
Last modified: 2008-02-27 (YYYY-MM-DD)