CWStudio is fast, computationally efficient and portable generator of various CW signals for telegraphy training purposes. Besides efficiency and portability, it is designed to simulate as much as possible a real air listening.

It can generate signals of various complexity, from one sine signal without any noise, to AGC-like complex air signal mix with possible hum, chirp, detuning, hand irregularities and so on.

The project was started in 2008 and after reaching any usability it was registered in April 2010 on SourceForge. From a simple command line tool, it has become a fully functional application with many features.

Why CWStudio?

Written in ANSI, pedantic C and C++. CLI is library independent, the other binaries depend only on ncurses or wxWidgets. Designed to be small and portable. Compiles and runs under DOS, Windows, Linux, FreeBSD, OpenBSD, NetBSD, Solaris and OpenSolaris.
One executable and portable file (with optional lame_enc.dll). No installer, simply download and run.
Optimized sound routines provide quick sound generation on slower machines. Well-considered memory management allows to use on vintage hardware.
Many parameters and switches. Simulation of a real AGC-like noise, QSB, chirp, hum, detuning, clicking etc.
Built-in database of real callsigns and most often used English words (inside executable!).
Both text and graphical user interfaces. Curses-compatible library is enough to compile and run. For GUI you need wxWidgets 2.8 or above.
Direct MP3 export through any external encoder compatible with lame_enc.dll.
The command line interface allows you to generate training texts in batch mode and pipe them to any external software (lame, ffmpeg etc.).
Used by increasing number of CW fans all over the world (see number of downloads!).
Free as in freedom and free as in beer. Open source, GPL3.



Retro TUI (text user interface) version. For description of parameters, see CWCLI manual.

F1 (1)help
F2 (2)save to WAV file
F3 (3)reset parameters
F4 (4)regenerate random
F5 (5), ENTERplay
F6 (6)stop
F7 (7)pause
F8 (8)noise mode
F9 (9)freq
F10 (0)exit
F11 (-)detune/qsb
F12 (=)mode (chars/words/callsigns)
Ctrl-Ins / Ctrl-Delpaste and copy
UP/DOWN (@/!)groups
Lload text file
LEFT/RIGHT (,/.)char spaces
Shift-LEFT/RIGHT ()word spaces
HOME/END ({/})charset
PGUP/PGDN ([/])tempo
BACKSPACE (\)shape
INS/DEL (:/")signals
Eeven harmonics
Oodd harmonics
Shift-HOME (:)dash length
Shift-END (')space length
SPACEenter text
MMP3 export
`DOS device change


The GUI version, made with wxWidgets. Editable text. For description of parameters, see CWCLI manual.


Currently, all sound functions are organized into internal libcwgen library, which is compiled and then linked with the main program. Its use is very simple, for example:

int main()
    char        *morsetext;
    cw_sample    asound, csound;
    cw_param    param;

    morsetext = cw_encode("VVV = CQ DE CWSTUDIO PSE K");
    cw_initsample(&asound, NULL);
    cw_initsample(&csound, &asound);
    cw_signals(&asound, param, morsetext);
    cw_convert(&asound, &csound, 16);
    cw_wavout("vvv.wav", &csound);

Example sounds

They are all containing text "VVV = CQ CQ DE CWSTUDIO PSE K"

Learn online

(Concise CW Course made with CWStudio)

I have published a small Polish book about CW learning in 2011, making a complete course (182 audio files in FLAC format) with CWStudio. These files come in 10 parts (can be burn as 10 audio CDs). Recordings are named number-letter-number, for example 04B3 is third recording from second (B) lesson on fourth CD. Below is short description to make this course usable for English-speaking users.

  • First three CDs are for letters learning - 600Hz, 3% harmonics, 10% noise 300 - 2400 Hz. Tempo 20 wpm with additional spaces. First file with 14 spaces (37 cpm resulting tempo), next 9(48), 6(58), 4(68) i 2(81) respectively. 13 lessons have subsequently added new characters. Last lessons focus on similar letters.
  • CD 04 is analogous for learning of digits.
  • CD 05 is for training mixed reception. Lesson A - digits with larger and larger amounts of added letters. Lesson B is reverse - adding more and more digits to letters. Parameters similar to first CDs.
  • CD06 - texts without additional spaces, with increasing tempo 100, 110, 120, 130, 140, 150, 180 i 200 (8 texts for each lesson). Lesson A is with letters only, B - digits and special characters, C - mixed texts.
  • CD07 - training difficult signals. Three mixed signals: 600, 200 and 1000 Hz, tempo 1, 4/3 and 2/3 of original, respectively. Different additional difficulties: click, hum, bug key, straight key, sweep etc. Each signal transmits the same text in loop.
  • CD08 - real callsigns from contest databases. Five mixed signals: 1, 0.333, 1.666, 0.5, 1.5 of base frequency, 1, 1.333, 0.666, 1.25, 0.8 of base tempo, 1, 0.2, 0.2, 0.5, 0.5 base amplitude. True pileup feeling. Last recording is very narrow and all signals are very close to each other.
  • CD09 and CD10 - training most common English words, to recognize them as whole pattern, not focusing on letters. Words without spaces, 35 additional dots between words. Tempo: 100, 110, 120, 130, 140, 150, 180 i 200 cpm.

Since January 2015 the complete course in video version is available as Youtube Channel (reuploaded in December 2016 due to some problems). All recordings are available under CC-BY-NC-ND license (different than CWStudio software itself!)


Download link: Download cwstudio

Project page: Download cwstudio

When downloading any MP3 external encoder, be sure to download 32-bit or 64-bit DLL according to your binary.

Current release: 0.9.5 (2017-01-01, New Year Release).

  • Small bug in 8-bit wav saving fixed
  • Endless playing bug under OSS fixed
  • SNDIO and AUDIOIO drivers implemented (BSD and Solaris)
  • Retro fun! DOS Sound added (SB16, PC Speaker, Covox)
  • Icons in better resolution, including SVG
  • Clipboard support in Windows version of cwcurses
  • Cwcurses contains buttons clickable by mouse
  • Cwcurses allows to load text from file and enter it manually
  • Small fixes for wxWidgets 3.0 compatibility

Previous release: 0.9.4 (2015-02-14, Valentine's Day Release).

  • Added MP3 Support (via external encoder compatible with lame_enc.dll). Be sure to download 32-bit or 64-bit dll release according to your binaries, otherwise it will not work.
  • Sound generation only if needed
  • Compiles on systems without getopt_long_only()

If you are looking for abandoned QedKey, the CWStudio predecessor written in Delphi, the open-source version under MIT License can be downloaded here.



cwcli [--play] [--noplay] [--silent] [--verbose] [--groups] [--words] [--calls] [--agc 0-100] [--bits bits] [--click 0-100] [--chars nchars] [--charset charset] [--cspaces 0-100] [--dashlen 100-10000] [--detune 0-100] [--even 0-100] [--freq 50-4000] [--number 1-100] [--hand 0-100] [--highcut 300-10000] [--hum 0-100] [--lowcut 50-1000] [--noise 0-100] [--odd 0-100] [--output outfile] [--qsb 0-100] [--samplerate samplerate] [--seed 1-32767] [--shape -10 - 10] [--signals 1-5] [--spacelen 20-300] [--sweep -4000 - 4000] [--sweepness 0 - 10000] [--tempo 5-500] [--window 0-1000] [--wordset 0-1000] [--wspaces 0-100]  


Generates 1-5 mixed CW signals of various properties, adds optional noise and saves it to a WAV file. If compiled on proper environment, it can play the result. Command line parameters are also interpreted in interactive mode!.

All text output is written to stderr; if stdout is redirected, the created file is written here. If stdin is redirected, the generated text is taken from it.

Optional CWPARAM environment variable can be set to hold some parameters, for example CWPARAM="--even 10 --odd 10".  


--play --noplay
Play the result (default), otherwise only save the WAV file.
--silent --verbose
Verbose mode gives full output (default), silent mode presents only generated text.
--groups --words --calls
The "groups" mode generates random five-letter groups. The "words" mode generates most common English words. The "calls" mode generates real amateur callsigns.
--agc 0-100
Simulate AGC response of receiver by varying noise volume along RMS of the signal. Default is 100.
--bits bits
Set bitrate. Default is 16.
--click 0-100
Simulate click by lowering sustain part of tone at given level (in dB) below attack phase. Default is 1 dB.
--chars nchars
Take first "nchars" from default charset in "groups" mode.
--charset charset
Set customized charset for random group generation in "groups" mode.
--cspaces 0-100
Set additional spaces (one space has a length of a dot) between chars. Default is 0.
--dashlen 100-1000
Length of dash, in percentage of dot. Default is 300% (3:1).
--detune 0-100
Simulate frequency drift of the signal. Default is 0.
--even 0-100
Enhance the signal by given percent of even harmonics. Default is 0. Values 0-5 are most valuable in practice.
--freq 50-4000
Use given frequency in Hz..
--number 1-100
Generate given number of groups/words/calls. Default is 20.
--hand 0-100
Simulate hand transmitting by introduce random errors in dash/dot lengths.
--highcut 300-10000
Set high cutoff frequency (Hz) of generated noise. Default is 2400.
--hum 0-100
Add given percentage of 50 Hz mains hum. Default is 0.
--lowcut 50-1000
Set low cutoff frequency (Hz) of generated noise. Default is 300.
--noise 0-100
Add given percentage of noise. Default is 100.
--odd odd
Enhance the signal by given percent of odd harmonics. Default is 0. Values 0-5 are most valuable in practice.
--output outfile
Store the result in a WAV file of given name. Default is output.wav.
--qsb 0-100
Add given amount of signal QSB. Default is 0.
--samplerate samplerate
Set given samplerate. Default is 44100.
--seed 0-32767
Set explicitly the seed of random generator. If not set or set to 0, seed is also random generated. Otherwise it is set to given value, resulting in a possibility of repetitive random content generation.
--shape -50 - +50
Set the shape of random generated numbers. Positive value increases the fraction of higher numbers (last letters, words, calls). Negative values prefer first ones. Zero means flat uniform distribution. Can be used to increase the number of newly learned letters/words. In practice, values -10 to 10 are well working.
--signals 1-5
Generate given number of mixed signals, each of hardcoded frequency ratio, tempo ratio and amplitude ratio. Every signal plays the same text in a loop. Default is 3.
--spacelen 20-300
Space length (between dots and dashes) in percentage of dot. Default is 100% (1:1).
--sweep -4000 - 4000
Simulate sweep (chirp or filter ringing according to parameters) by starting each tone from given frequency (can be negative, which results in zero crossing). Frequency is then changed exponentially to this given in --freq with a rate given by --sweepness. Default is 0.
--sweepness 0-10000
The rate of exponential frequency change from --sweep to --freq. Default is 0 (no sweep).
--tempo 5-500
Tempo of generated main signal in cpm (chars per minute) according to PARIS group.
--window 0-1000
Raised cosine window width (used to avoid clicks in each tone). Default is 100 samples.
--wordset 0-1000
Take only first given number of most common English words in "words" mode.
--wspaces 0-100
Set additional spaces between words/groups/calls. Default is zero.



CWStudio returns 0 if everything is OK. In the case of error, return value is different.