[GreenKeys] Precise Baud Timing
Zach Tumbusch
zach.tumbusch at gmail.com
Wed Nov 12 15:09:07 EST 2025
I went through a few iterations testing with Node, PHP, and C# but settled
on this example. The bigger challenge was sorting the popping on the fast
frequency transition. I tested this up to 9600 baud with my ST-8000. The
bit stream is 8 bit characters "A": "01100011" 11000 with 1 start bit and
2 stop bits. The actual bitrate at 45.45 baud is around 22ms. but since I
am directly converting points to a wav file I keep track of that based on
how many samples. Prints well on all my machines. Model 28 / UGC-136BX /
Hal. See the working example. https://w8zjt.net/itty
73, de W8ZJT
async generateAFSKWav(bitstream: string, baud, mark, space): Promise<
Blob> {
const sampleRate = 16000; // Sample rate in Hz
const fadeDuration = 50; // Number of samples for smooth
frequency transition
const samplesPerBit = Math.round(sampleRate / baud);
const totalSamples = bitstream.length * samplesPerBit;
let audioSamples: Float32Array = new Float32Array(totalSamples);
let phase = 0.0;
let currentFreq = bitstream[0] === "1" ? mark : space;
let currentPhaseIncrement = (2 * Math.PI * currentFreq) / sampleRate
;
for (let bitIndex = 0; bitIndex < bitstream.length; bitIndex++) {
const newFreq = bitstream[bitIndex] === "1" ? mark : space;
const newPhaseIncrement = (2 * Math.PI * newFreq) / sampleRate;
for (let i = 0; i < samplesPerBit; i++) {
if (i < fadeDuration) {
// Smooth frequency transition (interpolation)
const fadeFactor = i / fadeDuration;
const interpolatedFreq = currentFreq * (1 - fadeFactor)
+ newFreq * fadeFactor;
currentPhaseIncrement = (2 * Math.PI * interpolatedFreq)
/ sampleRate;
} else {
currentPhaseIncrement = newPhaseIncrement;
}
// Generate waveform sample
audioSamples[bitIndex * samplesPerBit + i] = Math.sin(phase
);
phase += currentPhaseIncrement;
if (phase >= 2 * Math.PI) {
phase -= 2 * Math.PI;
}
}
currentFreq = newFreq;
}
// Convert to WAV format
const wavBuffer = await WavEncoder.encode({
sampleRate: sampleRate,
channelData: [audioSamples] // Mono channel
});
On Wed, Nov 12, 2025 at 1:57 PM Steve <zarco at sonic.net> wrote:
> Much easier to do in hardware with just a few chips.
> 555 timer and shift register. A couple more chips and
> send R-Y test. You can use a scope or period counter to
> accurately setup the 555 clock. Can be implemented in Baudot
> or ASCII.
>
> With a uP, use the programmable timer which in most these
> days is internal. This should be largely independent of the
> code if done right.
>
> Projects like this are fun...enjoy!
> Steve W6SSP
> ______________________________________________________________
> GreenKeys mailing list
> Home: http://mailman.qth.net/mailman/listinfo/greenkeys
> Help: http://mailman.qth.net/mmfaq.htm
> Post: mailto:GreenKeys at mailman.qth.net
>
> >>> Jordan Spencer Cunningham's GreenKeys Search Tool:
> https://teletype.net/gksearch
> >>> 2002-to-present greenkeys archive:
> http://mailman.qth.net/pipermail/greenkeys/
> >>> 1998-to-2001 greenkeys archive:
> http://mailman.qth.net/archive/greenkeys/greenkeys.html
> >>> Randy Guttery's 2001-to-2009 GreenKeys Search Tool:
> http://comcents.com/tty/greenkeyssearch.html
>
> This list hosted by: http://www.qsl.net
> Please help support this email list: http://www.qsl.net/donate.html
> Message delivered to zach.tumbusch at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.qth.net/pipermail/greenkeys/attachments/20251112/de1820a6/attachment.html>
More information about the GreenKeys
mailing list