Код:
unit cwMain;
interface
uses
MMsystem, SysUtils, Classes, Windows, Messages, suCW;
procedure cwSetFormat(const CwFormat: TCwFormat); stdcall;
procedure cwMute(const bMute: WordBool); stdcall;
function cwOpen(const iNumSoundCard: Integer; const bManual: WordBool;
const hHwnd: THandle; CWProc: TCWProc): WordBool; stdcall;
procedure cwSend(const lKeyCode: Smallint); stdcall;
procedure cwStop; stdcall;
procedure cwClose; stdcall;
procedure cwSetOmniRig(const bEnabled: WordBool;
const iCWPin, iRigNumber: Integer); stdcall;
implementation
uses cwOmniRigModule, OmniRig_TLB;
const
SAMPLE_RATE = 44100; // Частота дискретизации
SINE_TABLE_SAMPLES = 1 shl 15; // Номер сэмпла в таблице синуса
MAX_BUFFER_SAMPLES = 56000; // Размер буфера
FRACT_BITS = 15;
type
{ Класс автоматического CW потока. }
TCwKeyboardOut = class(TThread)
private
procedure DoCWProc(const H: WordBool);
protected
procedure Execute; override;
end;
{ Класс ручного (от ключа) CW потока. }
TCwKeyOut = class(TThread)
private
procedure DoCWProc(const H: WordBool);
protected
procedure Execute; override;
end;
{ Для 16-битного аудио. }
TAudioSample = -32767..32767;
PSineTable = ^TSineTable;
TSineTable = array [0..SINE_TABLE_SAMPLES - 1] of TAudioSample;
{ Буфер. }
PBuffer = ^TBuffer;
TBuffer = array [0..MAX_BUFFER_SAMPLES - 1] of TAudioSample;
var
{ Переменные CW. }
pWavHdr : array [0..1] of PWaveHdr;
pWavBuf : array [0..1] of PBuffer; // Буферы вывода AUDIO
hWaveHdr : array [0..1] of THandle;
hWavBuf : array [0..1] of THandle;
pSinTable : PSineTable;
CwProp : TCwFormat; // Свойства CW
iLenDash : Integer; // Длина тире
CwKeyboardOut: TCwKeyboardOut; // Поток CW
CwKeyOut : TCwKeyOut; // Ручной CW поток
bCwOpen : Boolean; // Флаг открытия CW
hOut : HWAVEOUT; // Идентификатор устройства вывода CW
hOutEvent : THandle; // Событие вывода CW
sStrBuf : array [0..MAXBYTE] of String; // Временный строковый буфер
lLetter : array [0..MAXBYTE] of Smallint; // Буфер кода символа для CallBack
lInc : SmallInt = 0; // Индекс массива
bStop : Boolean; // Флаг останова передачи
hSendHwnd : THandle; // HWND текстового поля куда будет возвращён символ
iMemLevel : Integer; // Уровень начальной громкости
CWProcedure : TCWProc;
resourcestring
RES_MB_ERR_GAME = 'Игровое устройство (джойстик) не установлено.' + #13#10 +
'Для его установки воспользуйтесь панелью управления Windows.';
RES_MB_ERR_MEM = 'Системная ошибка. Ошибка выделения памяти.';
RES_MB_ERR_EVENT = 'Системная ошибка. Ошибка создания события.';
RES_MB_ERR_TITLE = 'Ошибка CW';
// =============================================================================
{ Вывод окна с сообщениями об ошибках загрузки библиотек.
Text - текст сообщения. }
procedure ShowMessage(Text: String; dwErr: MMRESULT = 0);
var
hHwnd : HWND;
lpBufErr: array [0..MAXBYTE] of Char;
begin
hHwnd := GetActiveWindow;
if dwErr <> MMSYSERR_NOERROR then
begin
waveOutGetErrorText(dwErr, lpBufErr, MAXBYTE + 1);
Text := String(lpBufErr);
end;
MessageBox(hHwnd, PChar(Text), PChar(RES_MB_ERR_TITLE), MB_ICONERROR);
end;
// =============================================================================
{ Таблица синуса. }
procedure DoSineTable;
var
i, uMax : Cardinal;
dVol, dSin: Double;
begin
uMax := SINE_TABLE_SAMPLES - 1;
{ Громкость. }
dVol := (CwProp.lLevel / 44.1) * 32767.0;
dSin := Pi / SINE_TABLE_SAMPLES;
for i := 0 to uMax do
pSinTable^[i] := Round(dVol * Sin(2.0 * i * dSin));
end;
procedure Sinewave(Buffer: PBuffer; var Index, Samples: Integer);
var
Sample : TAudioSample;
iDangle : Integer;
i, j : Integer;
iMaxAngle: Integer;
iMin : Integer;
iAngle : Integer;
dFreq : Double;
begin
iAngle := 0;
dFreq := CwProp.lFreq;
iDangle := Round((SINE_TABLE_SAMPLES shl FRACT_BITS) * dFreq / SAMPLE_RATE);
iMaxAngle := (SINE_TABLE_SAMPLES shl FRACT_BITS) - 1;
for i := 1 to Samples do
begin
Sample := pSinTable^[iAngle shr FRACT_BITS];
if i < 64 then
for j := i to 64 do
Sample := (Sample * 44) div 45;
iMin := Samples - 256;
if i > iMin then
for j := iMin to i do
Sample := (Sample * 44) div 45;
Buffer^[Index] := Sample;
Inc(Index);
Inc(iAngle, iDangle);
iAngle := iAngle and iMaxAngle;
end;
end;
procedure Silence(Buffer: PBuffer; var Index, Samples: Integer);
var
i, iMax: Integer;
begin
iMax := Samples - 1;
for i := 0 to iMax do
begin
Buffer^[Index] := 0;
Inc(Index);
end;
end;
// =============================================================================
{ Закрытие аудиокарты и освобождение памяти. }
procedure CloseAudio;
begin
if hOut <> 0 then
begin
waveOutReset(hOut);
waveOutClose(hOut);
hOut := 0;
end;
{ Закрываем указатель на событие. }
if hOutEvent <> INVALID_HANDLE_VALUE then
begin
CloseHandle(hOutEvent);
hOutEvent := INVALID_HANDLE_VALUE;
end;
{ Освобождение памяти. }
if hWaveHdr[0] <> 0 then
begin
GlobalUnlock(hWaveHdr[0]);
GlobalFree(hWaveHdr[0]);
end;
if hWavBuf[0] <> 0 then
begin
GlobalUnlock(hWavBuf[0]);
GlobalFree(hWavBuf[0]);
end;
if hWaveHdr[1] <> 0 then
begin
GlobalUnlock(hWaveHdr[1]);
GlobalFree(hWaveHdr[1]);
end;
if hWavBuf[1] <> 0 then
begin
GlobalUnlock(hWavBuf[1]);
GlobalFree(hWavBuf[1]);
end;
FreeMem(pSinTable, SizeOf(TSineTable));
pSinTable := nil;
bCwOpen := False;
end;
// =============================================================================
{ Установка свойств CW сигнала. CwFormat - структура формата телеграфного
сигнала. }
procedure cwSetFormat(const CwFormat: TCwFormat); stdcall;
begin
CwProp := CwFormat;
with CwProp do
begin
iSpeed := ((SAMPLE_RATE * 12) div 10) div CwFormat.iSpeed;
iLenDash := iSpeed * lPointDash;
// iSpace := iSpeed * (2 + CwFormat.iSpace);
iMemLevel := lLevel;
end;
{ Синус. }
{ Память под таблицу синуса. }
if pSinTable = nil then GetMem(pSinTable, SizeOf(TSineTable));
DoSineTable;
end;
// =============================================================================
{ Отключение/включение звука. iMute - флаг состояния }
procedure cwMute(const bMute: WordBool); stdcall;
begin
with CwProp do
if bMute then
begin
iMemLevel := lLevel;
lLevel := 0;
end
else
lLevel := iMemLevel;
{ Синус. }
{ Память под таблицу синуса. }
if pSinTable = nil then
GetMem(pSinTable, SizeOf(TSineTable));
DoSineTable;
end;
// =============================================================================
{ Открытие устройства аудиовывода. Здесь
iNumSoundCard - номер открываемой аудиокарты;
hHwnd - hwnd окна получающего сообщение с кодом текущего передаваемого
символа. }
function cwOpen(const iNumSoundCard: Integer; const bManual: WordBool;
const hHwnd: THandle; CWProc: TCWProc): WordBool; stdcall;
var
iBufferBytes: Integer;
WavFormat : TWAVEFORMATEX;
dwErr : MMRESULT;
JCaps : TJoyCaps;
begin
Result := False;
{ Закрываем устройство если оно открыто. }
if bCwOpen then cwClose;
try
{ Создаём событие. }
hOutEvent := CreateEvent(nil, False, False, nil);
if hOutEvent = INVALID_HANDLE_VALUE then
begin
ShowMessage(RES_MB_ERR_EVENT);
Exit;
end;
{ Открытие устройства вывода аудио. }
FillChar(WavFormat, SizeOf(WavFormat), #0);
with WavFormat do
begin
wFormatTag := WAVE_FORMAT_PCM; // Используется PCM формат
nChannels := 1; // Число каналов
nSamplesPerSec := SAMPLE_RATE; // Частота дискретизации
wBitsPerSample := 16; // Выборка
nBlockAlign := wBitsPerSample div 8 * nChannels; // Число байт в выборке
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign; // Число байт в секундном интервале
cbSize := 0; // Не используется
end;
dwErr := WaveOutOpen(@hOut, iNumSoundCard, @WavFormat,
hOutEvent, 0, CALLBACK_EVENT);
if dwErr <> MMSYSERR_NOERROR then
begin
CloseAudio;
ShowMessage(EmptyStr, dwErr);
Exit;
end;
{ Выделение памяти под заголовки. }
hWaveHdr[0] := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TWaveHdr));
if hWaveHdr[0] = 0 then
begin
CloseAudio;
ShowMessage(RES_MB_ERR_MEM);
Exit;
end;
pWavHdr[0] := PWaveHdr(GlobalLock(hWaveHdr[0]));
hWaveHdr[1] := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TWaveHdr));
if hWaveHdr[1] = 0 then
begin
CloseAudio;
ShowMessage(RES_MB_ERR_MEM);
Exit;
end;
pWavHdr[1] := PWaveHdr(GlobalLock(hWaveHdr[1]));
{ Размер буфера. }
iBufferBytes := 2 * MAX_BUFFER_SAMPLES;
{ Память под буферы. }
hWavBuf[0] := GlobalAlloc(GHND or GMEM_SHARE, iBufferBytes);
if hWavBuf[0] = 0 then
begin
CloseAudio;
ShowMessage(RES_MB_ERR_MEM);
Exit;
end;
pWavBuf[0] := PBuffer(GlobalLock(hWavBuf[0]));
hWavBuf[1] := GlobalAlloc(GHND or GMEM_SHARE, iBufferBytes);
if hWavBuf[1] = 0 then
begin
CloseAudio;
ShowMessage(RES_MB_ERR_MEM);
Exit;
end;
pWavBuf[1] := PBuffer(GlobalLock(hWavBuf[1]));
{ Подготовка буферов. }
FillChar(pWavHdr[0]^, SizeOf(TWaveHdr), #0);
pWavHdr[0].lpData := PChar(pWavBuf[0]);
FillChar(pWavHdr[1]^, SizeOf(TWaveHdr), #0);
pWavHdr[1].lpData := PChar(pWavBuf[1]);
{ Обнуление текстового буфера. }
FillChar(sStrBuf, SizeOf(sStrBuf), #0);
{ Начальные значения переменных. }
hSendHwnd := hHwnd;
lInc := 0;
bStop := False;
CWProcedure := CWProc;
{ Создание потока вывода CW. }
CwKeyboardOut := TCwKeyboardOut.Create(True);
CwKeyboardOut.Priority := tpTimeCritical;
{ Запуск потока опроса ключа. }
if bManual then
begin
{ Проверяем наличие игрового порта }
dwErr := joyGetDevCaps(JOYSTICKID1, @JCaps, SizeOf(TJoyCaps));
if dwErr = JOYERR_NOERROR then
begin
CwKeyOut := TCwKeyOut.Create(True);
with CwKeyOut do
begin
Priority := tpHighest;
Resume;
end;
end
else
ShowMessage(RES_MB_ERR_GAME);
end;
{ Устройство открыто }
bCwOpen := True;
Result := True;
except
CloseAudio;
end;
end;
// =============================================================================
{ Преобразование кода символа в код CW. KeyCode - код символа. }
function CoderCw(const KeyCode: Smallint): String;
begin
case KeyCode of
32: Result := '2'; // Пробел
33: Result := '110011'; // !
34: Result := '010010'; // "
39: Result := '011110'; // '
40, 41: Result := '101101'; // ()
44: Result := '010101'; // ,
45: Result := '100001'; // -
46: Result := '000000'; // .
48: Result := '11111'; // 0
49: Result := '01111'; // 1
50: Result := '00111'; // 2
51: Result := '00011'; // 3
52: Result := '00001'; // 4
53: Result := '00000'; // 5
54: Result := '10000'; // 6
55: Result := '11000'; // 7
56: Result := '11100'; // 8
57: Result := '11110'; // 9
58: Result := '111000'; // :
59: Result := '101010'; // ;
61: Result := '10001'; // =
63: Result := '001100'; // ?
92, 47: Result := '10010'; // / \
95: Result := '001101'; // _
97, 65, 224, 192: Result := '01'; // A
98, 66, 225, 193: Result := '1000'; // B
99, 67, 246, 214: Result := '1010'; // C
100, 68, 228, 196: Result := '100'; // D
101, 69, 229, 197,
168, 184 : Result := '0'; // E
102, 70, 244, 212: Result := '0010'; // F
103, 71, 227, 195: Result := '110'; // G
104, 72, 245, 213: Result := '0000'; // H
105, 73, 232, 200: Result := '00'; // I
106, 74, 233, 201: Result := '0111'; // J
107, 75, 234, 202: Result := '101'; // K
108, 76, 235, 203: Result := '0100'; // L
109, 77, 236, 204: Result := '11'; // M
110, 78, 237, 205: Result := '10'; // N
111, 79, 238, 206: Result := '111'; // O
112, 80, 239, 207: Result := '0110'; // P
113, 81, 249, 217: Result := '1101'; // Q
114, 82, 240, 208: Result := '010'; // R
115, 83, 241, 209: Result := '000'; // S
116, 84, 242, 210: Result := '1'; // T
117, 85, 243, 211: Result := '001'; // U
118, 86, 230, 198: Result := '0001'; // V
119, 87, 226, 194: Result := '011'; // W
120, 88, 252, 220: Result := '1001'; // X
121, 89, 251, 219: Result := '1011'; // Y
122, 90, 231, 199: Result := '1100'; // Z
248, 216: Result := '1111'; // Ш
253, 221: Result := '00100'; // Э
254, 222: Result := '0011'; // Ю
255, 223: Result := '0101'; // Я
247, 215: Result := '1110'; // Ч
250, 218: Result := '1001'; // Ъ
{ Специальные символы }
36: Result := '000101'; // $ (SK)
38: Result := '1000101'; // & (BK)
42: Result := '10001'; // * (BT)
43: Result := '01010'; // + (AR)
60: Result := '01000'; // < (AS)
62: Result := '10110'; // > (KN)
end;
end;
// =============================================================================
{ Заполнение буфера и передача текста. lKeyCode - код передаваемого символа. }
procedure cwSend(const lKeyCode: Smallint); stdcall;
begin
{ Если устройство закрыто. }
if not bCwOpen then Exit;
{ Превышена максимальная длина
массива буфера. }
if lInc > MAXBYTE then Exit;
{ Присваиваем значение массиву. }
sStrBuf[lInc] := CoderCw(lKeyCode);
{ Код символа. }
lLetter[lInc] := lKeyCode;
{ Увеличиваем индекс
массива. }
Inc(lInc);
{ Запуск потока на выполнение,
если он не запущен. }
bStop := False;
with CwKeyboardOut do
if Suspended then Resume;
end;
{ TCwKeyboardOut }
procedure TCwKeyboardOut.DoCWProc(const H: WordBool);
begin
if Assigned(CWProcedure) then CWProcedure(H);
if not OmniRigModule.OmniRigInst or not CATParams.bEnabled then Exit;
with OmniRigModule.OmniRigX1, CATParams do
case iRigNumber of
1: if iCWPin = 0 then Rig1.PortBits.Dtr := H else Rig1.PortBits.Rts := H;
2: if iCWPin = 0 then Rig2.PortBits.Dtr := H else Rig2.PortBits.Rts := H;
end;
end;
procedure TCwKeyboardOut.Execute;
var
i, j : SmallInt;
iSample: Integer;
pCurHdr: PWaveHdr;
lCurHdr: Smallint;
iSilens: Integer;
sMid : String;
begin
lCurHdr := 0;
pCurHdr := nil;
OmniRigModule := TOmniRigModule.Create(nil);
{ Бесконечный цикл до завершения потока. }
while not CwKeyboardOut.Terminated do
try
{ Цикл по массиву строкового буфера, где
LEN_BUF - верхняя граница массива. }
for i := 0 to MAXBYTE do
begin
if bStop then Break;
{ Если элемент массива не пуст. }
if Length(sStrBuf[i]) <> 0 then
begin
{ Очередной передаваемый символ. }
case lLetter[i] of
36: { SK }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('S')), 0);
SendMessage(hSendHwnd, WM_CHAR, 75, 0);
end;
38: { BK }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('B')), 0);
SendMessage(hSendHwnd, WM_CHAR, 75, 0);
end;
42: { BT }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('B')), 0);
SendMessage(hSendHwnd, WM_CHAR, 84, 0);
end;
43: { AR }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('A')), 0);
SendMessage(hSendHwnd, WM_CHAR, 82, 0);
end;
60: { AS }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('A')), 0);
SendMessage(hSendHwnd, WM_CHAR, 83, 0);
end;
62: { KN }
begin
SendMessage(hSendHwnd, WM_CHAR, Integer(PChar('K')), 0);
SendMessage(hSendHwnd, WM_CHAR, 78, 0);
end
else
SendMessage(hSendHwnd, WM_CHAR, lLetter[i], 0);
end;
{ Передача буфера. }
{ Цикл по символам массива где получаем очередной
символ из телеграфного буфера ('1' '0' или '2'). }
for j := 1 to Length(sStrBuf[i]) do
begin
pCurHdr := pWavHdr[lCurHdr];
lCurHdr := lCurHdr and 1;
sMid := Copy(sStrBuf[i], j, 1);
iSample := 0;
{ Точка. }
if sMid = '0' then
begin
Sinewave(PBuffer(pCurHdr.lpData), iSample, CwProp.iSpeed);
pCurHdr.dwBufferLength := iSample * 2;
DoCWProc(True);
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
DoCWProc(False);
end;
{ Тире. }
if sMid = '1' then
begin
Sinewave(PBuffer(pCurHdr.lpData), iSample, iLenDash);
pCurHdr.dwBufferLength := iSample * 2;
DoCWProc(True);
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
DoCWProc(False);
end;
{ Пауза между словами. }
if sMid = '2' then
begin
Silence(PBuffer(pCurHdr.lpData), iSample, CwProp.iSpace);
pCurHdr.dwBufferLength := iSample * 2;
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
end;
{ Пауза между знаками. }
iSample := 0;
iSilens := 2;//CwProp.iSpeed;
Silence(PBuffer(pCurHdr.lpData), iSample, iSilens);
pCurHdr.dwBufferLength := iSample;
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
end;
{ Пауза между буквами. }
iSample := 0;
Silence(PBuffer(pCurHdr.lpData), iSample, iLenDash);
pCurHdr.dwBufferLength := iSample * 2;
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
{ Элемент массива уже проигран,
его можно освободить. }
sStrBuf[i] := EmptyStr;
end;
end;
finally
{ Информируем приложение об окончании буфера. }
SendMessage(hSendHwnd, WM_CHAR, VK_RETURN, 0);
{ Поток остановлен. }
CwKeyboardOut.Suspend;
end;
OmniRigModule.Free;
end;
// =============================================================================
{ Остановка передачи текста из буфера буфера. }
procedure cwStop; stdcall;
begin
if bCwOpen then
begin
{ Останавливаем цикл. }
bStop := True;
{ Обнуление телеграфного буфера. }
FillChar(sStrBuf, SizeOf(sStrBuf), #0);
{ Обнуление индекса
массива. }
lInc := 0;
end;
end;
{ TCwKeyOut }
procedure TCwKeyOut.DoCWProc(const H: WordBool);
begin
if Assigned(CWProcedure) then CWProcedure(H);
if not OmniRigModule.OmniRigInst or not CATParams.bEnabled then Exit;
with OmniRigModule.OmniRigX1, CATParams do
case iRigNumber of
1: if iCWPin = 0 then Rig1.PortBits.Dtr := H else Rig1.PortBits.Rts := H;
2: if iCWPin = 0 then Rig2.PortBits.Dtr := H else Rig2.PortBits.Rts := H;
end;
end;
procedure TCwKeyOut.Execute;
var
JyInfo : JOYINFO;
pCurHdr: PWaveHdr;
lCurHdr: Smallint;
iSample: Integer;
begin
lCurHdr := 0;
{ Бесконечный цикл до завершения
потока. }
while not CwKeyOut.Terminated do
begin
try
pCurHdr := pWavHdr[lCurHdr];
lCurHdr := lCurHdr and 1;
joyGetPos(JOYSTICKID1, @JyInfo);
if (JyInfo.wButtons = JOY_BUTTON1) or
(JyInfo.wButtons = JOY_BUTTON3) then
begin
{ Нажата тире. }
iSample := 0;
Sinewave(PBuffer(pCurHdr.lpData), iSample, iLenDash);
Silence(PBuffer(pCurHdr.lpData), iSample, CwProp.iSpeed);
pCurHdr.dwBufferLength := iSample * 2;
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
DoCWProc(True);
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
DoCWProc(False);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
end
else if (JyInfo.wButtons = JOY_BUTTON2) or
(JyInfo.wButtons = JOY_BUTTON4) then
begin
{ Нажата точка. }
iSample := 0;
Sinewave(PBuffer(pCurHdr.lpData), iSample, CwProp.iSpeed);
Silence(PBuffer(pCurHdr.lpData), iSample, CwProp.iSpeed);
pCurHdr.dwBufferLength := iSample * 2;
waveOutPrepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
DoCWProc(True);
waveOutWrite(hOut, pCurHdr, SizeOf(TWaveHdr));
WaitForSingleObject(hOutEvent, INFINITE);
DoCWProc(False);
waveOutUnprepareHeader(hOut, pCurHdr, SizeOf(TWaveHdr));
end;
finally
{ Разгружаем процессор. }
Sleep(5);
end;
end;
end;
// =============================================================================
{ Завершение потоков и закрытие устройства аудиовывода. }
procedure cwClose; stdcall;
begin
if bCwOpen then
begin
CWProcedure := nil;
hSendHwnd := 0;
with CwKeyboardOut do
begin
Terminate;
while not Suspended do;
Free;
end;
if Assigned(CwKeyOut) then
with CwKeyOut do
begin
Terminate;
while not Suspended do;
Free;
end;
CloseAudio;
end;
end;
procedure cwSetOmniRig(const bEnabled: WordBool;
const iCWPin, iRigNumber: Integer); stdcall;
begin
CATParams.iCWPin := iCWPin;
CATParams.iRigNumber := iRigNumber;
CATParams.bEnabled := bEnabled;
end;
end.