you C Coders might find this interesting, a virtually ZERO DELAY CW audio filter that totally cleans up a harsh CPO square wave click'N sidetone while shaping its edges

204 views
Skip to first unread message

Chuck Vaughn

unread,
Jul 25, 2024, 6:56:13 AM7/25/24
to iCW - internet CW
Here is the LIVE DEMO video of the CW AUDIO BANDpass filter in action

chatGPT wrote its c CODE:
(see attached txt file)

COMPILEd by this command:
gcc -o bandpassfilter3 bandpassfilter3.c -ljack -lm

runs by command line   
./bandpassfilter3 192000 1024 800 5
arguments are
   sample rate of sound card
   buffer frames of the jack audio connection kit
   CW pitch
   "Q" of the bandpass filter

c code  looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <jack/jack.h>
#include <math.h>
#include <signal.h>
#include <unistd.h>

#define PI 3.14159265358979323846

jack_port_t *input_port, *output_port;
jack_client_t *client;

typedef struct {
    double x1, x2, y1, y2;
} BiquadState;

typedef struct {
    double b0, b1, b2;
    double a0, a1, a2;
    BiquadState state;
} BiquadCoeffs;

BiquadCoeffs g_coeffs[2]; // Filter coefficients for a cascaded biquad filter

// Global variables for sample rate and running flag
int SAMPLE_RATE;
int running = 1; // Flag to control the main loop

// Signal handler for graceful termination
void signal_handler(int signum) {
    if (signum == SIGINT) {
        running = 0; // Set the flag to stop processing
    }
}

// Calculate filter coefficients
void calculate_coefficients(double f0, double Q) {
    double omega0 = 2.0 * PI * f0 / SAMPLE_RATE;
    double alpha = sin(omega0) / (2.0 * Q);
    double cos_omega0 = cos(omega0);

    // Low-pass filter coefficients (First biquad section)
    g_coeffs[0].b0 = (1 - cos_omega0) / 2;
    g_coeffs[0].b1 = 1 - cos_omega0;
    g_coeffs[0].b2 = (1 - cos_omega0) / 2;
    g_coeffs[0].a0 = 1 + alpha;
    g_coeffs[0].a1 = -2 * cos_omega0;
    g_coeffs[0].a2 = 1 - alpha;

    // High-pass filter coefficients (Second biquad section)
    g_coeffs[1].b0 = (1 + cos_omega0) / 2;
    g_coeffs[1].b1 = -(1 + cos_omega0);
    g_coeffs[1].b2 = (1 + cos_omega0) / 2;
    g_coeffs[1].a0 = 1 + alpha;
    g_coeffs[1].a1 = -2 * cos_omega0;
    g_coeffs[1].a2 = 1 - alpha;

    // Initialize state variables
    g_coeffs[0].state.x1 = g_coeffs[0].state.x2 = g_coeffs[0].state.y1 = g_coeffs[0].state.y2 = 0.0;
    g_coeffs[1].state.x1 = g_coeffs[1].state.x2 = g_coeffs[1].state.y1 = g_coeffs[1].state.y2 = 0.0;

    // Debugging: Print coefficients
    printf("Coefficients for filter:\n");
    printf("First Biquad Section (Low-pass):\n");
    printf("b0: %f, b1: %f, b2: %f\n", g_coeffs[0].b0, g_coeffs[0].b1, g_coeffs[0].b2);
    printf("a0: %f, a1: %f, a2: %f\n", g_coeffs[0].a0, g_coeffs[0].a1, g_coeffs[0].a2);
    printf("Second Biquad Section (High-pass):\n");
    printf("b0: %f, b1: %f, b2: %f\n", g_coeffs[1].b0, g_coeffs[1].b1, g_coeffs[1].b2);
    printf("a0: %f, a1: %f, a2: %f\n", g_coeffs[1].a0, g_coeffs[1].a1, g_coeffs[1].a2);
}

// Filter a single sample
double filter_sample(double sample) {
    // Apply the first biquad section (Low-pass)
    double y0 = (g_coeffs[0].b0 * sample + g_coeffs[0].b1 * g_coeffs[0].state.x1 + g_coeffs[0].b2 * g_coeffs[0].state.x2
                - g_coeffs[0].a1 * g_coeffs[0].state.y1 - g_coeffs[0].a2 * g_coeffs[0].state.y2) / g_coeffs[0].a0;

    // Update state variables for the first biquad section
    g_coeffs[0].state.x2 = g_coeffs[0].state.x1;
    g_coeffs[0].state.x1 = sample;
    g_coeffs[0].state.y2 = g_coeffs[0].state.y1;
    g_coeffs[0].state.y1 = y0;

    // Apply the second biquad section (High-pass)
    double y1 = (g_coeffs[1].b0 * y0 + g_coeffs[1].b1 * g_coeffs[1].state.x1 + g_coeffs[1].b2 * g_coeffs[1].state.x2
                - g_coeffs[1].a1 * g_coeffs[1].state.y1 - g_coeffs[1].a2 * g_coeffs[1].state.y2) / g_coeffs[1].a0;

    // Update state variables for the second biquad section
    g_coeffs[1].state.x2 = g_coeffs[1].state.x1;
    g_coeffs[1].state.x1 = y0;
    g_coeffs[1].state.y2 = g_coeffs[1].state.y1;
    g_coeffs[1].state.y1 = y1;

    return y1;
}

// JACK process callback function
int process(jack_nframes_t nframes, void *arg) {
    jack_default_audio_sample_t *in, *out;

    in = (jack_default_audio_sample_t *)jack_port_get_buffer(input_port, nframes);
    out = (jack_default_audio_sample_t *)jack_port_get_buffer(output_port, nframes);

    for (int i = 0; i < nframes; i++) {
        out[i] = filter_sample(in[i]);
    }

    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 4 || argc > 5) {
        fprintf(stderr, "Usage: %s <sample_rate> <buffer_size> <center_freq> [Q]\n", argv[0]);
        return 1;
    }

    SAMPLE_RATE = atoi(argv[1]);
    int buffer_size = atoi(argv[2]);
    double f0 = atof(argv[3]); // Center frequency
    double Q = (argc == 5) ? atof(argv[4]) : 8.0; // Quality factor, default to 8.0 if not provided

    if (SAMPLE_RATE <= 0 || buffer_size <= 0 || f0 <= 0 || Q <= 0) {
        fprintf(stderr, "Invalid arguments. Sample rate, buffer size, center frequency, and Q must be positive numbers.\n");
        return 1;
    }

    jack_status_t status;

    client = jack_client_open("bandpass_filter", JackNoStartServer, &status);
    if (client == NULL) {
        fprintf(stderr, "Failed to open JACK client\n");
        return 1;
    }

    if (status & JackServerStarted) {
        fprintf(stderr, "JACK server started\n");
    }

    if (status & JackNameNotUnique) {
        const char *client_name = jack_get_client_name(client);
        fprintf(stderr, "Unique name `%s' assigned\n", client_name);
    }

    input_port = jack_port_register(client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
    output_port = jack_port_register(client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
    if (input_port == NULL || output_port == NULL) {
        fprintf(stderr, "Failed to register JACK ports\n");
        jack_client_close(client);
        return 1;
    }

    calculate_coefficients(f0, Q);

    jack_set_process_callback(client, process, 0);

    if (jack_activate(client)) {
        fprintf(stderr, "Failed to activate JACK client\n");
        jack_client_close(client);
        return 1;
    }

    // Set up signal handler for graceful termination
    signal(SIGINT, signal_handler);

    printf("Press Ctrl+C to quit...\n");

    while (running) {
        // Main loop can be filled with additional logic if needed
        // For now, it just waits for the signal to terminate
        sleep(1);
    }

    // Attempt to close the JACK client gracefully
    if (jack_client_close(client)) {
        fprintf(stderr, "Error closing JACK client\n");
        return 1;
    }

    return 0;
}
bandpassfilter3.c

df7t...@gmail.com

unread,
Jul 28, 2024, 9:48:07 PM7/28/24
to iCW - internet CW
Hello Chuck,

No C Coder here, but to take care, especially of hams using a paddle at high speeds, who need a near-zero latency of the monitor tone, is great!


TNX, 73
Tom

aa0hw

unread,
Dec 4, 2024, 11:38:47 AM12/4/24
to iCW - internet CW
Here is some python code that does an even better job 
since it produces RAISED COSINE EDGES, (instead of R/C exponential from the earlier C CODE version)
and still takes less than 1ms to go from input to output
LIVE VIDEO DEMO HERE:


df7t...@gmail.com

unread,
Dec 4, 2024, 1:28:58 PM12/4/24
to iCW - internet CW
Very nice Chuck,
...and only about 100 (with nice comments) lines in Python.
Thank you for sharing!

I assume "the magic" (reading input, applying filter and scaling volume, writing output)
 happens between line 75 and 90 of your code.
That's well readable code -- even to me :)



Recently I became aware of a fresh attempt to make something like RufzXP in Python.

                      https://github.com/actionwatcher/MorseCodeX

As far, as I remember, MorseCodeX uses raised the cosine shape as well.

The GUI is still basic, but it worked here under Windows10.
The maximum speed being 65 wpm at present.

CU 73
Tom

S. Steltzer

unread,
Dec 4, 2024, 6:06:55 PM12/4/24
to 'joe living' via iCW - internet CW
That  certainly makes good sounding code.

73!
Steve, WF3T

aa0hw

unread,
Dec 5, 2024, 8:49:37 AM12/5/24
to iCW - internet CW
Here is an upgraded PYTHON CW AUDIO FILTER, with raised cosine edges that has dynamic input, you can change
the filter settings on the 'fly'    and includes a volume slider to adjust the volume to your preference after you change settings

here are some pictures of the UPgraded Python filter APP in action:
with a 700 hertz center frequency

filtercontrolgui.png
filterDITpython.png
filterBANDwidthpython.png

the UPgraded python APP's FILE,  can be downloaded here:

df7t...@gmail.com

unread,
Dec 5, 2024, 11:08:04 AM12/5/24
to iCW - internet CW
What a nice shape and outstanding spectrum Chuck!

Absolutely nothing in the spectrum below from 20 to 400 Hz !

Thanks again for the code -- will try it as soon as possible.

73
Tom

aa0hw

unread,
Dec 5, 2024, 1:12:33 PM12/5/24
to iCW - internet CW
Here is a python CW KEYBOARD that goes with the python cw audio bandpass filter via jack clients
operating on this demo code from a jack sample rate of 192Khz & 1024 buffer frames / 4 periods
see attached python code file...   this python cw keyboard is a pure sine wave, with no edge rise/fall time
so it needs a filter to smooth it out...   eventually, hoping to get GPT to combine the SINC BP FILTER python code
with the python MORSE CODE KEYBOARD, so that they both work together inside the same code file... 

some HIDDEN FEATUREs  not defined in file descriptors are 
   1.   if you hit the TAB button,  it will stop sending and ignore whatever is left in the buffer  
    2.   you can change the FONT, and the FONT SIZE by just replacing what is in the code and hit SAVE
    3.  you can change the MORSE CODE MAP e.g.  if you want 7 silent spaces instead of sending a period
    4.   change the CW PITCH,   in the file location,  just re-save it
    5.  you can adjust the inter-character, inter-word timing by doing the same, adjust the numbers in the code and re-save

this is just chatGPT's early version...
it takes HOURS of working with chatGPT to get it this far...
it makes mistakes over and over again, you have to report what they are
and GPT tries something different next time,  and finally maybe it will work  : )


pythoncwkeyboardgui.png
gptcwkeyboard16.py

df7t...@gmail.com

unread,
Dec 5, 2024, 1:49:11 PM12/5/24
to iCW - internet CW

I have never before used ChatGPT, but it seems to work :)

To test it, I just entered "Python emulate JK FlipFlop" ... and at least some code, looking senseful, appeared "automagically".

So it looks as if the CMOS Super Keyer (circuit publilshed in QST 1981) timing may be achieved by simulating the important part of the circuit (about 10 logic ICs)

(A few days ago, someone shared his (Arduino) code for the ACCU Keyer -- simulating /emulating the circuit -- on the CWops list and that triggered my interest in doing something
similar for the CMOS Super Keyer. At present, its timing is only available as the default V0 emulation of some Idiompress/LogiKey keyers - the source code is not public.
Once you are used to this timing, it is hard to change to standard mode B at speeds above 40 wpm).

73
Tom

df7t...@gmail.com

unread,
Dec 7, 2024, 4:54:42 PM12/7/24
to iCW - internet CW
Just made a (very) quick and dirty Python3 setup on the AVLinux-netbook

Tested the testbpf6.py using a 702 Hz square wave from the WinKeyer to a Behringer UCA222.
Output was sent to the internal sound card.

I only ran the file in the Python IDE (IDLE) -- so no compilation done -- ignore the Warnings -- they are due to the bad setup on my side :)

...But it works!!

Nice!, TNX
Tom
AVLinux-testbpf6.-py.mp4

df7t...@gmail.com

unread,
Dec 8, 2024, 6:34:52 PM12/8/24
to iCW - internet CW
testbpf6_mod_BW_percent

Using Center Frequency and Bandwidth (10 to 60%) instead of f_low, f_high as input parameters.

testbpf6_mod_BW_percent.png

73
Tom
testbpf6_mod_BW_percent.py

df7t...@gmail.com

unread,
Dec 9, 2024, 3:21:53 AM12/9/24
to iCW - internet CW

testbpf6_MOD_bw_percent_1_199

Widening the range of allowed relative BW; now 1 to 199%.

It may be fun to experiment with extreme BW values.

Note: GLADE may be a suitable tool to prepare graphical parts of a GUI.
I think the result will not look "super sharp" -- but its use may facilitate the job.

73
Tom
testbpf6_MOD_bw_percent_1_199.py

df7t...@gmail.com

unread,
Dec 9, 2024, 4:10:19 AM12/9/24
to iCW - internet CW

testbpf6

Glade



Note, however:

"Glade 3.40.0 released Wednesday 10 August 2022 by Juan Pablo Ugarte

Glade 3.40.0 is now available for download.

This is the last stable release.

Glade is not being actively developed or maintained anymore. If you are interested in becoming a maintainer please contact us on gitlab."


Video: https://www.youtube.com/watch?v=Ko0NTS0IpfI

(Example starts at about minute 24 of the video)


Python GLADE Examples: https://github.com/jsowers34/PythonGladeExamples/tree/main



Perhaps Cambalache (again by Juan Pablo Ugarte) may become a (future) alternative

https://blogs.gnome.org/xjuan/2024/11/26/cambalache-0-94-released/


73

Tom


Chuck Vaughn

unread,
Dec 9, 2024, 7:05:10 AM12/9/24
to i_...@googlegroups.com
very good work TOM, I LIKE what you modified to get
CENTER FREQ and bandwidth on the GUI INPUT 
TOMsFILTER.png

--

---
You received this message because you are subscribed to the Google Groups "iCW - internet CW" group.
To unsubscribe from this group and stop receiving emails from it, send an email to i_cw+uns...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/i_cw/81764847-ffdd-4877-8b34-329795c590a9n%40googlegroups.com.

df7t...@gmail.com

unread,
Dec 9, 2024, 7:17:02 AM12/9/24
to iCW - internet CW
Glad that you like the Center Frequency / rel. BW input Chuck,

Even better would be  to be able to set rise (=fall) time instead of rel. BW -- but that needs some/much extra work :)

Tom

Chuck Vaughn

unread,
Dec 9, 2024, 7:28:12 AM12/9/24
to i_...@googlegroups.com
I like the bandwidth feature on the bandpass filter, and i would vote to keep it in there...
however, perhaps a diagnostic way of having the filter code determine,
based on all current parameters,  what the FINAL CW NOTE coming out of the filter, what its rise/fall time is in real time...
and then show that on the GUI in...  text form(be great to have an actual MATH LAB like picture of the current wave shape)  

 i have found working with BP filters and filtering CW NOTEs,  that the bandwidth/centerFREQ  was a crucial element of getting the 
sound i was hoping for... adjusting the rise/fall time only, did not produce the desired result
however,  adjusting bandpass filter width along with adjusting the RISE/FALL time on the actual morse code output generator
that goes to the input of the bandpass filter,  was even more effective...
c
...

df7t...@gmail.com

unread,
Dec 9, 2024, 7:50:09 AM12/9/24
to iCW - internet CW
" be great to have an actual MATH LAB like picture of the current wave shape ..."

well perhaps with Python matplotlib

like here

...well only as long as the CPU load doesn't get so high that the sound is disturbed :)

Tom

Chuck Vaughn

unread,
Dec 9, 2024, 8:10:46 AM12/9/24
to i_...@googlegroups.com
good point, THE CPU on my linux laptop is already showing 30 percent load
with the current python bpf as is.... so adding more CPU load,  i dont think would be good for sure...
one of the downsides/upsides to having passthrough latency less than one millisecond, is
higher CPU use (according to the A-EYEs i've been working with on this)

Chuck Vaughn

unread,
Dec 9, 2024, 8:15:38 AM12/9/24
to i_...@googlegroups.com
another feature i would like to explore, on the CW KEYBOARD python code,
is having an adjustable background shading controller on the GUI
to be able to adjust so you can pick what shading you might like for the 
PYTHON MORSE CODE typing screen...  here is a slightly darker theme
i picked,  but it is a bit difficult to get the right hex code easily... i had to use RECRI KEYBOARD's background hex code selector
and then hard code it into the program itself and re-save
backgroundhardcoded.png

On Mon, Dec 9, 2024 at 6:50 AM df7t...@gmail.com <df7t...@gmail.com> wrote:

df7t...@gmail.com

unread,
Dec 9, 2024, 10:49:24 AM12/9/24
to iCW - internet CW

aa0hw

unread,
Dec 10, 2024, 6:07:07 AM12/10/24
to iCW - internet CW
Thanks for that Tom
the tkinter color chooser is exactly what i was trying to find

df7t...@gmail.com

unread,
Dec 10, 2024, 8:32:26 AM12/10/24
to iCW - internet CW
Good Chuck!

BTW: It seems that for setting colors of parts of a GUI in Python, the use of a CSS (Cascaded Style Sheet) file is recommended.
I use one simple CSS file for my hompages and it makes it easy to have the same "look" on every page.
But at present, I don't know how one may interactively change the content of a CSS file.
They are very well readable and could be edited by a user, independently of the  main code for the filter.

The advantage of TKinker, even so it does not offer fancy, modern widgets, is that it is a standard part of all Python distributions.

What I want to do next, is to change the Volume slider. I would like to achieve "Silence/Muted" at the leftmost position and some kind of senseful
maximum value (+ 10 dB perhaps) at the rightmost position. In between the behaviour will be strongly "logarithmic-ish" to achieve that about 70%
of the whole slider bar movement is available for the most useful range of Volume ( -20 to 0 dB, perhaps).
I would also like to have the displayed value of Volume to be editable -- so the user (e.g) may
enter a value known to work nicely with Mumble directly.

Apart from that, I think the Hamming window/Sinc filter, that you have chosen, is a good selection. Nevertheless, I will see how a Blackman-Harris (3- or 4-term) window
will behave/sound. If it makes sense to have two differnt windows available, "Radio Buttons" could be used to toggle between them.

Your idea of having an oscillosscope display of the signal might be done by not having a "realtime" display, but by just recording a single DIT at the present speed
(or a fixed burst of 40 ms or so) and display it, as soon as a change to the BW setting (or window type) happened (Enter key pressed). The display would have a fixed content until
the next change of relevant settings.

73
Tom

aa0hw

unread,
Dec 10, 2024, 2:35:39 PM12/10/24
to iCW - internet CW
Here is a short DEMO of combing in series, 3 python morse code programs that will interact with each other and also be able to communicate between 2 CWops over ip using the same programs...
for a QSO over IP   all in python setup:
CW KEYBOARD to input of CW AUDIO FILTER to input of HD AUDIO OVER IP communication pipelines, for 2 cw ops, full duplex, fast QSK over internet

aa0hw

unread,
Dec 10, 2024, 2:38:53 PM12/10/24
to iCW - internet CW
Here is a DESKTOP SNAPSHOT of all 3 morse code python programs in operation:
qsomorsebypython.png

df7t...@gmail.com

unread,
Dec 10, 2024, 3:20:38 PM12/10/24
to iCW - internet CW
Thank you for the nice video Chuck!

Perhaps some other CW operators will be motivated to contribute to that project.

73
Tom

df7t...@gmail.com

unread,
Dec 13, 2024, 11:32:40 AM12/13/24
to iCW - internet CW
testbpf6...


When entering odd numbers for the filter taps (num_taps) the program loops with an error message:

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "<__array_function__ internals>", line 200, in pad

File "/usr/lib/python3/dist-packages/numpy/lib/arraypad.py", line 744, in pad

pad_width = _as_pairs(pad_width, array.ndim, as_index=True)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/usr/lib/python3/dist-packages/numpy/lib/arraypad.py", line 510, in _as_pairs

raise ValueError("index can't contain negative values")

ValueError: index can't contain negative values

Exception ignored from cffi callback <function Client.set_process_callback.<locals>.callback_wrapper at 0x7f2bcf020900>:

Traceback (most recent call last):

File "/usr/lib/python3/dist-packages/jack.py", line 801, in callback_wrapper

callback(frames)

File "/home/thomas/Documents/Python-CW-Filter/testbpf6_MOD_bw_percent_1_199.py", line 140, in process

filtered_signal = np.pad(filtered_signal, (0, frames - len(filtered_signal)), mode="constant")

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^




As a quick fix, I made the following changes to the routine checking the input values.

Now, only even numbers are accepted.



73

Tom




elif param_name == "num_taps":

if value < 4 or value > 10000: # Valid range for num_taps CHANGED minimum "3" to "4" (Must be even number)

print(f"Invalid num_taps value: {value}. Must be between 4 and 10000.")

return

num_taps = max(4, int(value)) # Minimum 4 taps

if (value % 2) == 1: # ADDED: Must be even number, odd numbers generate errors

print(f"Invalid num_taps value: {value}. Must be even number.")

return

num_taps = max(4, int(value)) # Minimum 4 taps


73

Tom

Chuck Vaughn

unread,
Dec 13, 2024, 12:08:56 PM12/13/24
to i_...@googlegroups.com
i just tested it, and your fix worked perfectly

there may be an issue with the indents, which i changed to look like the indents
at similar points and looks like this:

elif param_name == "num_taps":
            if value < 4 or value > 10000:  # Valid range for num_taps
                print(f"Invalid num_taps value: {value}. Must be between 4 and 10000.")
                return
            num_taps = max(4, int(value))  # Minimum 4 taps
            if (value % 2) == 1: # ADDED: Must be even number, odd numbers generate errors
                print(f"Invalid num_taps value: {value}. Must be even number.")
                return
            num_taps = max(4, int(value)) # Minimum 4 taps

aa0hw

unread,
Dec 13, 2024, 12:52:18 PM12/13/24
to iCW - internet CW
Here is another PYTHON CW KEYBOARD version written by chatGPT,
LIVE VIDEO DEMO
this keyboard also can send text files, and keep them repeating, has PAUSE/RESUME
adjust pitch and speed on the fly 

df7t...@gmail.com

unread,
Dec 13, 2024, 2:11:30 PM12/13/24
to iCW - internet CW
Nice again Chuck,

you added a lot of funtionality!

Concerning the even/odd filter taps number: Principally, from the DSP filter definitions (firwin2), I don't think that odd numbers should be a problem, but ...well at least the error does no longer appear.
Perhaps we should check that again later.

Did you make the additional buttons with GTK/GI only, or are you using TKinter now?

There is an additional library for TKinter, "ttk", which makes it look much better -- Not Windows 3.1, 1990 style :)


73
Tom

Chuck Vaughn

unread,
Dec 13, 2024, 4:26:01 PM12/13/24
to i_...@googlegroups.com
additional buttons are from GTK...not started the tkinter
pathway just yet....

df7t...@gmail.com

unread,
Dec 13, 2024, 4:35:28 PM12/13/24
to iCW - internet CW
OK Chuck,
just saw the new source code and it is still well readable.

73

aa0hw

unread,
Dec 13, 2024, 4:43:10 PM12/13/24
to iCW - internet CW
here is yet another CW KEYBOARD python code version along with a python CW KEYBOARD COMMUNICATOR audio over iP showing 
two CWops using python cw keyboards and communicating with each other over ip:

aa0hw

unread,
Dec 15, 2024, 2:05:49 PM12/15/24
to iCW - internet CW
here is a MULTi-Tasking CW KEYBOARD,  this doubles as a normal CW KEYBOARD for sending in real time, text as you type,  AND it will copy/paste or LOAD a text file and send it too...
  this is the latest  improved model,   which now has a REPEAT TEXT mode(button) that keeps repeating text until you un-toggle the REPEAT button - for sending TEXT FILEs for COPY PRACTICE
    and the punctuation is finally working(sending , . ?  etc...  in this model,   thanks to ROGER from Recri Keyer
multitaskcwkeyboard.png

S. Steltzer

unread,
Dec 15, 2024, 7:52:09 PM12/15/24
to 'joe living' via iCW - internet CW
Absolutely beautiful keying envelopes!

On Sun, Dec 15, 2024, at 1:05 PM, aa0hw wrote:
here is a MULTi-Tasking CW KEYBOARD,  this doubles as a normal CW KEYBOARD for sending in real time, text as you type,  AND it will copy/paste or LOAD a text file and send it too...
  this is the latest  improved model,   which now has a REPEAT TEXT mode(button) that keeps repeating text until you un-toggle the REPEAT button - for sending TEXT FILEs for COPY PRACTICE
    and the punctuation is finally working(sending , . ?  etc...  in this model,   thanks to ROGER from Recri Keyer
multitaskcwkeyboard.png



aa0hw

unread,
Dec 16, 2024, 9:50:25 AM12/16/24
to iCW - internet CW
Here is a stress test for setting up a QRQ CW practice session, using 10 instances of this python multitask CW KEYBOARD
at 10 different VLF/LF frequencies(directly from the keyboard's output), using 10 different text files on continuous REPEAT
a simple RECRI KEYER SDR RECEIVER module tunes in each CW VLF/LF frequency to isolate each CW SIGNAL for COPY PRACTICE...
QRQ CW speeds are set from 60 wpm to 105 wpm,  for a total of 10 different speeds... 

here is a live video demo of this in action

aa0hw

unread,
Dec 16, 2024, 12:28:12 PM12/16/24
to iCW - internet CW
Here is an updated/upgraded version of the python multi-task CW KEYBOARD,
this version provides background shading into the typing screen, adds borders to the typing screen
and you can change font styles and font sizes     here is the link to version 2 of the python code:
here is a picture of what the code looks like when you bring up the KEYBOARD
gptkbmultitask2.png

S. Steltzer

unread,
Dec 16, 2024, 4:00:53 PM12/16/24
to 'joe living' via iCW - internet CW
Wow, an AI bot actually wrote that program? How the heck does that work?  I just spent 3 or 4 days converting a control program for the TS590 to the TS890 and I already had most of the GUI work done with the original.  

And the CW sounds great.  Sure makes me wish I'd gotten into Linux 25 years ago.  Too darn old to dive into that now.  Now I feel blessed when I can remember how to get home when I go to the store :-)

Good work both of you!
73,
Steve, WF3T  

df7t...@gmail.com

unread,
Dec 17, 2024, 10:46:06 AM12/17/24
to iCW - internet CW
gptcwkbmultitask2

Hello Chuck,
just tested the version of today (on AV Linux) --- here all ten spaces were sent correctly, I think.
Sometimes the message is sent twice when using "Send Morse Code" after having typed a message.

Recording attached

73
Tom

shot-2024-12-17_16-34-45.jpg
MorseCodeKeyboard-10-spaces-test.mp3

Chuck Vaughn

unread,
Dec 17, 2024, 11:03:00 AM12/17/24
to i_...@googlegroups.com
ok...thanks for testing...  i noticed a bug that so far, not being solved by hours with the ai's is this repeat behavior
when the REPEAT BUTTON is not activated...    it usually just does that once, with 1 repeat then stops doing it...
so there is a phantom line of code or two in there somewhere causing this behavior   but still is hiding from
chatGPT so far,   after multiple attempts to correct that behavior with all sorts of mods... and mods that ended up
in crashing the whole program... YIKES !    beware of these code ai's   the free versions anyway...
i had a previous copy so was able to recover... but at least the spaces are doing what they are supposed to now...
looks like you were using an earlier version, since your snapshot did not show the CLEAR ALL TEXT button at the bottom of the GUI
which is helpful to be able to clear all text without having to hit the STOP SENDING button...
here is a link just in case... 


--

---
You received this message because you are subscribed to the Google Groups "iCW - internet CW" group.
To unsubscribe from this group and stop receiving emails from it, send an email to i_cw+uns...@googlegroups.com.

df7t...@gmail.com

unread,
Dec 17, 2024, 11:11:08 AM12/17/24
to iCW - internet CW
gptcwkbmultitask4

Thanks -- downloaded the new version 4

Will have a look at it later.

BTW -- don't analyze my recording with Audacity -- it does not look nice, even so it sounds ok.

But that's a problem with my audio setup on the Linux notebook --  not with the keyboard / filter code :)

Tom

aa0hw

unread,
Dec 20, 2024, 8:07:13 AM12/20/24
to iCW - internet CW
Here is an upgraded python CW KEYBOARD version, that has been optimized by AI, "copilot", for lower CPU use. lower DSP LOAD use,  
and also adjusted for proper typing screen CSS STYLING background shading(no longer reports any deprecated python methods) 

aa0hw

unread,
Dec 20, 2024, 10:24:13 AM12/20/24
to iCW - internet CW
just tested how light weight the python CW KEYBOARD runs ,  on an ANCIENT RASPBERRY PI 2B
and it runs with hardly any CPU use, or DSP LOAD
here is a LIVE DEMO  on the pi2b with the latest version,  3 ,  for this PYTHON CW KEYBOARD project

df7t...@gmail.com

unread,
Dec 20, 2024, 2:01:52 PM12/20/24
to iCW - internet CW
very nice Chuck...

just had a flight with the new copilot:

copilot3-shot.png


73
Tom

Chuck Vaughn

unread,
Dec 20, 2024, 2:30:12 PM12/20/24
to i_...@googlegroups.com
EXCELLENT TOM !
thanks for sharing the snapshot !


aa0hw

unread,
Dec 21, 2024, 9:39:32 AM12/21/24
to iCW - internet CW
another slight improvement,   the TYPING SCREEN and the way it looks, and operated can have a significant impact
on how smooth qrq cw typing by touch/   here in this simple mod with 2 lines of code above the CSS STYLING,
the place where the first letter on the LEFT, instead of being at the extreme left position of the shaded background typing screen
is moved to the right   ,  the right margin of the last letter typed per row before the word moves to the next line is also set by the 2nd line of code
here is what it looks like,  for the adjustable height and width that your preference can move about with the whole cw keyboard GUI
pariscwkbmarginsfix.png
the LETTER's  first position on the LEFT of the shaded area for typing,  has been moved to the right
to match how it looks at the RIGHT MARGIN with this particular KEYBOARD GUI WIDTH

here is the code block IN BOLD that you only need to place above the CSS STYLING code BLOCK


        # Set left and right margins directly in the TextView
        self.text_view.set_left_margin(20)  # Add 20px space on the left
        self.text_view.set_right_margin(10)  # Add 10px space on the right



        # Apply CSS for font and color
        css_provider = Gtk.CssProvider()
        css_provider.load_from_data(b"""
            textview {
                font-family: 'Comic Sans MS';
                font-size: 32px;
                border: 1px solid black;
                padding: 2px;
            }
            textview text {
                background-color: rgba(204, 204, 204, 1);
                color: rgba(0, 0, 0, 1);
            }
        """)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            css_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

        self.text_view.connect("key-press-event", self.on_key_press)

        self.scrolled_window.add(self.text_view)
        self.box.pack_start(self.scrolled_window, True, True, 0)

aa0hw

unread,
Dec 22, 2024, 6:35:14 AM12/22/24
to iCW - internet CW
Here is the next upgraded MODEL of the python CW KEYBOARD
this one produces a visual array to choose color for  
TEXT,  sent text, background shading,  and FONT SIZE and FONT STYLE
PLUS it has a new feature where the text changes color as it is sent from the buffer
so if you type ahead of the buffer the color will change when it is actually sent..

python code is here for this latest iteration upgrade:

S. Steltzer

unread,
Dec 22, 2024, 9:48:43 AM12/22/24
to 'joe living' via iCW - internet CW
Again, nice work guys!

73,
Steve, WF3T

df7t...@gmail.com

unread,
Dec 23, 2024, 5:54:05 PM12/23/24
to iCW - internet CW
aa0hw
ungelesen,
22.12.2024, 12:35:14 (gestern) 
an iCW - internet CW
Here is the next upgraded MODEL of the python CW KEYBOARD
this one produces a visual array to choose color for  
TEXT,  sent text, background shading,  and FONT SIZE and FONT STYLE
PLUS it has a new feature where the text changes color as it is sent from the buffer
so if you type ahead of the buffer the color will change when it is actually sent..

python code is here for this latest iteration upgrade:


plot-shapes.py
Reply all
Reply to author
Forward
0 new messages