So, how do I get a Morse code signal into my decoding program? PortAudio reads Morse code audio just fine.
I have spent years playing around with audio components to get sampled audio into a Delphi program. Recently, I have settled on PortAudio to do the job.
PortAudio is a free, cross-platform, open-source, audio I/O library. Installed as a dynamic link library, I can use PortAudio to access any of the native audio API on Microsoft Windows. As long as your receiver can output audio as either a PC audio input or through a virtual audio cable, you can get audio into your program.
Below, you can see a callback function which accepts an audio stream and moves it into your program in real time. In my case, I am using Direct Sound with a VAC.
function ExternalCallback(const inputBuffer: Pointer; outputBuffer: Pointer;
framesPerBuffer: Cardinal; const timeInfo: PPaStreamCallbackTimeInfo;
statusFlags: TPaStreamCallbackFlags; userData: Pointer): Integer; cdecl;
begin
if AudioProcessor.Active then
AudioProcessor.ProcessBlock(inputBuffer, framesPerBuffer);
Move(inputBuffer^, outputBuffer^, framesPerBuffer * 2); // if PaInt16
MorseReceiver.ProcessBlock(inputBuffer, framesPerBuffer);
Result := paContinue;
end;
PortAudio reads Morse in buffers which you can then easily process. In my case, I am using 8000 samples per second of 16 bit audio.
procedure TfrmMain.StartAudio;
begin
Active := true;
fillchar(InputParams, SizeOf(InputParams), 0);
with InputParams do
begin
ChannelCount := 1;
Device := AudioIn; // Direct Sound from Receiver
SampleFormat := paInt16;
suggestedLatency := Pa_GetDeviceInfo(AudioIn).defaultLowInputLatency;
end;
fillchar(OutputParams, SizeOf(OutputParams), 0);
with OutputParams do
begin
ChannelCount := 1;
Device := AudioOut; // Direct Sound to PC Speaker
SampleFormat := paInt16;
suggestedLatency := Pa_GetDeviceInfo(AudioOut).defaultLowOutputLatency;
end;
CheckPA(Pa_OpenStream(Stream, @InputParams, @OutputParams, C_SAMPLERATE, 0,
paNoFlag, @ExternalCallback, nil));
CheckPA(Pa_StartStream(Stream));
Report('External Stream Started');
end;
PortAudio Reads Morse Code Audio
When the audio arrives, I can apply several filters to reduce bandwidth and noise. Then, the sounds are transferred to the Morse Receiver section where the decoding is managed.
I use a timer to stop the audio stream, which gives the Direct Sound buffers time to empty, as they are being provided by Windows.
procedure TfrmMain.StopAudio(Sender: TObject); begin StopTimer.Enabled := false; CheckPA(Pa_StopStream(Stream)); sleep(500); Active := false; end;
If you are writing software to process an audio stream, I recommend that you give PortAudio a try. It is stable and simple to use.
