Digital Tape Recorder C/C++ Source Code Example
Digital Tape Recorder C/C++ Source Code Example of Using DirectDSP® software
Below is a C/C++ source code example of using off-the-shelf DSP/analog hardware to perform a
basic digital tape recorder function. Note the use of the DSShowHardwareSelector call to bring
up a list of supported hardware. Note also the DSAcquireWvfrmFile
and DSGenerateWvfrmFile calls used in asynchronous mode, which allows waveform files to be processed
in the background.
#include <windows.h>
#include <stdlib.h>
// DirectDSP® software package include files
#include "enmgr.h" // Engine Manager
#include "hwmgr.h" // Hardware Manager
#include "hwlib.h" // Hardware Library
// some global variables
...note: many variable and type declarations omitted for brevity...
HANDLE FAR hEngine = NULL; // declare at least one variable FAR to limit this
to a single-instance program
HANDLE hBoard = NULL;
BOOL fBoardInitialized = FALSE;
char szBoard[30];
HWND hdlgDtape = NULL;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInst, LPSTR lpszCmdParam, int nCmdShow) {
// comment this call if status messages from HwLib should not be visible
DSShowEngMgrStatusWindow(); // turn on debug status window in Engine Manager
// show hardware selector dialog (Hardware Manager); returns board designator string
// note: if hardware choice is fixed, then skip this call and use correct board designator
// string in DSAssignBoard call below
if (DSShowHardwareSelectorDlg(NULL, szBoard) == IDCANCEL) goto Cleanup;
// create tape recorder display panel as modeless dialog (see WM_INITDIALOG below)
hdlgDtape = CreateDialog(hInstance, "Dtape", NULL, (DLGPROC)DlgProc); // dialog box
in dtape.rc needs some bwcc controls
if (hdlgDtape == NULL) {
MessageBox(GetActiveWindow(), "could not create tape recorder dialog box",
szApp, MB_OK);
goto Cleanup;
}
ShowWindow(hdlgDtape, SW_SHOW);
UpdateWindow(hdlgDtape);
// open engine
hEngine = DSEngineOpen(DS_EO_HSM, NULL); // first try to open Hypersignal-Macro or
// Hypersignal-Macro EX as engine
if (IsWindowVisible(hdlgDtape)) SetActiveWindow(hdlgDtape);
if (!hEngine) {
hEngine = DSEngineOpen(DS_EO_HSA, NULL); // if that doesn't work, try
// Hypersignal-Acoustic
if (!hEngine) {
itoa(DSGetHWLibErrorStatus(), tmpstr, 10);
lstrcat(tmpstr, " is error code; DSEngineOpen failed");
MessageBox(GetActiveWindow(), tmpstr, szApp, MB_OK);
goto Cleanup;
}
}
// assign a board handle: engine handle, board designator string, instruction set,
IO base addr, Mem base addr
hBoard = DSAssignBoard(hEngine, szBoard, NULL, NULL, NULL); // use defaults where
possible
// initialize the board; make sure it's installed and responded
fBoardInitialized = DSInitBoard(hBoard);
if (!fBoardInitialized) {
itoa(DSGetEngineErrorStatus(hEngine), tmpstr, 10);
lstrcat(tmpstr, " is error code; DSInitBoard failed");
MessageBox(GetActiveWindow(), tmpstr, szApp, MB_OK);
goto Cleanup;
}
// register dialog box window to receive various messages from engine
DSRegisterEngineMsgWnd(hEngine, DS_REMW_SETPROGSTATUSMSG | DS_REMW_SETSTATISTICSMSG
| DS_REMW_SETBUFNUMMSG | DS_REMW_SETLEVELMSG, hdlgDtape);
// start processing dialog window messages
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(hdlgDtape, &msg)) continue;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
Cleanup:
if (hdlgDtape != NULL) SendMessage(hdlgDtape, WM_CLOSE, 0, 0L);
if (fBoardInitialized) DSDisableBoard(hBoard);
if (hBoard != NULL) DSFreeBoard(hBoard);
if (hEngine != NULL) DSEngineClose(hEngine);
return (int)hdlgDtape;
}
BOOL FAR PASCAL _export DlgProc(HWND hdlg, WORD wMsg, WORD wParam, LONG lParam) {
...note: most variable declarations omitted for brevity...
HCTRLITEMS hCtrlItems;
PCTRLITEMS pCtrlItems;
HGLOBAL hConvInfo;
PCONVERSIONINFO pConvInfo;
switch (wMsg) {
...note: other message-processing code omitted for brevity...
case WM_COMMAND:
switch (wParam) {
case DS_ATC_TAPEPAUSE:
if (State == PAUSE) {
DSSendEngineCommand(hEngine, DS_SEC_RESUME, DS_EEF_ASYNC);
State = BeforePauseState;
}
else {
if (State != IDLE) DSSendEngineCommand(hEngine, DS_SEC_PAUSE,
DS_EEF_ASYNC);
BeforePauseState = State;
State = PAUSE;
}
break;
case DS_ATC_TAPESTOP:
// if needed, "unclick" the PAUSE button (on separate toolbar),
cause return to pre-Pause state
if (State == PAUSE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPEPAUSE,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar, DS_ATC_TAPEPAUSE), BN_CLICKED));
if (State != IDLE) {
// clear menu checks, in case
if (State == PLAYING) DSSendMessageToolboxControl(hToolbar2,
DS_ATC_TAPEPLAY, WM_SETBUTTONSTATE, 0, 0L);
else if (State == RECORDING) DSSendMessageToolboxControl
(hToolbar2, DS_ATC_TAPERECORD, WM_SETBUTTONSTATE, 0, 0L);
State = IDLE; // change state
if (lParam != CMDNOTIFY) {
DSSendEngineCommand(hEngine, DS_SEC_IDLE, DS_EEF_SYNC);
// if message didn't come from WM_DSPENGINE_PROGSTATUS, tell engine to idle
(wait for confirmation)
}
}
break;
case DS_ATC_TAPEPLAY:
// if needed, "unclick" the PAUSE button (on separate toolbar), cause
return to pre-Pause state
if (State == PAUSE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPEPAUSE,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar, DS_ATC_TAPEPAUSE), BN_CLICKED));
// process Stop button if already running
PrevState = State; // save, because Stop button will set back to IDLE
if (State != IDLE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPESTOP,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar2, DS_ATC_TAPESTOP), BN_CLICKED));
if (PrevState == PLAYING) State = IDLE;
else State = PLAYING;
if (State == IDLE) break;
// get output filename
DSSendMessageToolboxControl(hToolbar3, OUTWAVFILENAME, WM_GETTEXT,
sizeof(szFilename), (LPARAM)(LPSTR)szFilename);
// create CONVERSIONINFO object memory
// NOTES:
// 1) zero-init of allocated memory sets most parameters to default
values
// 2) FOR D/A OUTPUT ONLY, a 0 value for number of channels, sampling
frequency,
// and number of samples causes engine to "auto configure",
initializing these
// values from waveform file header
hConvInfo = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
GMEM_DISCARDABLE, sizeof(CONVERSIONINFO));
pConvInfo = (PCONVERSIONINFO)GlobalLock(hConvInfo);
lstrcpy(pConvInfo->szFilename, szFilename);
pConvInfo->NumChan = 0; // auto-configure (see note above)
pConvInfo->Fs = 0; // "
pConvInfo->NumSamples = 0; // "
lstrcpy(pConvInfo->szGainList, "1"); // output gain/attenuation
(enterable in Volts, dB, channel-specific, or channel-range)
pConvInfo->DALooping = TRUE; // cause output to repeat
if (!DSGenerateWvfrmFile(hBoard, pConvInfo, DS_AWF_ASYNC))
{ // start playback (asynchronous operation--don't wait for file to complete)
if (State == PLAYING) SendMessage(hdlg, WM_COMMAND,
DS_ATC_TAPESTOP, CMDNOTIFY); // error: unstick button, etc. (use impossible value:
window handle == NULL, 2 is not menu or accelerator)
}
else {
// update play filename box with file being recorded
DSInsertControlItem(hOutputFileEntry, szFilename, 0); //
add to listbox
DSSetControlText(hOutputFileEntry, szFilename); // set edit text
}
GlobalUnlock(hConvInfo);
GlobalFree(hConvInfo);
break;
case DS_ATC_TAPEFASTFORWARD:
// if needed, "unclick" the PAUSE button (on separate toolbar),
cause return to pre-Pause state
if (State == PAUSE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPEPAUSE,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar, DS_ATC_TAPEPAUSE), BN_CLICKED));
// process Stop button if already running
if (State != IDLE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPESTOP,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar2, DS_ATC_TAPESTOP), BN_CLICKED));
State = IDLE;
break;
case DS_ATC_TAPEREWIND:
// if needed, "unclick" the PAUSE button (on separate toolbar), cause
return to pre-Pause state
if (State == PAUSE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPEPAUSE,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar, DS_ATC_TAPEPAUSE), BN_CLICKED));
// process Stop button if already running
if (State != IDLE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPESTOP,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar2, DS_ATC_TAPESTOP), BN_CLICKED));
State = IDLE;
break;
case DS_ATC_TAPERECORD:
// if needed, "unclick" the PAUSE button (on separate toolbar), cause
return to pre-Pause state
if (State == PAUSE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPEPAUSE,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar, DS_ATC_TAPEPAUSE), BN_CLICKED));
// process Stop button if already running
PrevState = State; // save, because Stop button will set back to IDLE
if (State != IDLE) SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPESTOP,
MAKELPARAM(DSGetToolboxControlWindow(hToolbar2, DS_ATC_TAPESTOP), BN_CLICKED));
if (PrevState == RECORDING) State = IDLE;
else State = RECORDING;
if (State == IDLE) break;
// get current record filename
DSSendMessageToolboxControl(hToolbar3, INWAVFILENAME, WM_GETTEXT,
sizeof(szFilename), (LPARAM)(LPSTR)szFilename);
// create CONVERSIONINFO object memory
// NOTES:
// 1) zero-init of allocated memory sets most parameters to default values
hConvInfo = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DISCARDABLE,
sizeof(CONVERSIONINFO));
pConvInfo = (PCONVERSIONINFO)GlobalLock(hConvInfo);
lstrcpy(pConvInfo->szFilename, szFilename);
pConvInfo->NumChan = 1; // one channel
for (j=0; jNumChan; j++) pConvInfo->ChanList[j] = j; //
example of initializing channel list
pConvInfo->Fs = 22050; // 22.05 kHz sampling rate
pConvInfo->NumSamples = 100000L; // 100,000 samples
lstrcpy(pConvInfo->szGainList, "1"); // input gain/attenuation
(enterable in Volts, dB, channel-specific, or channel-range)
pConvInfo->NumTrigChan = 1;
pConvInfo->TrigChanList[0] = 0;
pConvInfo->StoreOnAbort = TRUE; // store data if operation is aborted
pConvInfo->Monitor = fMonitorMode;
if (!DSAcquireWvfrmFile(hBoard, pConvInfo, DS_AWF_ASYNC)) { // start
record (asynchronous operation--don't wait for file to complete)
if (State == RECORDING) SendMessage(hdlg, WM_COMMAND,
DS_ATC_TAPESTOP, CMDNOTIFY); // error: unstick button, etc.
}
else {
// update both record and play filename boxes with file being recorded
DSInsertControlItem(hInputFileEntry, szFilename, 0); // add to listbox
DSSetControlText(hInputFileEntry, szFilename); // set edit text
DSInsertControlItem(hOutputFileEntry, szFilename, 0);
DSSetControlText(hOutputFileEntry, szFilename);
}
GlobalUnlock(hConvInfo);
GlobalFree(hConvInfo);
break;
case DS_ATC_MONITORMODE:
fMonitorMode ^= 1;
break;
}
break;
case WM_DSPENGINE_PROGSTATUS:
// if engine has returned to idle state because the current program is finished, ran
// into an error, etc. process STOP button to reflect the current status
if (State != IDLE && LOWORD(lParam) == DS_PS_PROGDONE) {
SendMessage(hdlg, WM_COMMAND, DS_ATC_TAPESTOP, CMDNOTIFY);
}
break;
default:
return FALSE;
}
return TRUE;
}
|