99
1010/* ---------------------------------------------------- INCLUDES ---------------------------------------------------- */
1111
12+ #include <math.h>
1213#include <stdbool.h>
1314#include <stdint.h>
1415#include <stdlib.h>
6667static bool s_keyed = false; /**< Is the keyer hardware currently keyed? */
6768static bool s_panicked = false; /**< Was the keyer panic activated? */
6869static bool s_trainer_mode = false; /**< Is trainer mode on? */
70+ static float s_humanizer_level = KEYER_HUMANIZER_OFF ;/**< Humanizer level. */
6971
7072static state_t s_state = STATE_OFF ; /**< Currently active keyer state. */
7173
@@ -188,6 +190,12 @@ static bool get_keyed( void );
188190 */
189191static state_t get_next_state ( void );
190192
193+ /**
194+ * @fn humanize_delay( tick_t )
195+ * @brief Applies a random variation to the specified delay.
196+ */
197+ static tick_t humanize_delay ( tick_t delay );
198+
191199/**
192200 * @fn set_keyed( bool )
193201 * @brief Sets whether the keyer hardware is keying or not.
@@ -253,6 +261,13 @@ size_t keyer_autokey_str_ex( char const * str, keyer_autokey_flag_field_t flags
253261} /* keyer_autokey_str() */
254262
255263
264+ float keyer_get_humanizer_level ( void )
265+ {
266+ return ( s_humanizer_level );
267+
268+ } /* keyer_get_humanizer_level() */
269+
270+
256271bool keyer_get_on ( void )
257272{
258273 return ( get_keyed () );
@@ -287,6 +302,7 @@ void keyer_init( void )
287302 s_keyed = false;
288303 s_panicked = false;
289304 s_trainer_mode = false;
305+ s_humanizer_level = KEYER_HUMANIZER_OFF ;
290306 s_state = STATE_OFF ;
291307 s_el = WPM_ELEMENT_NONE ;
292308 s_lockout_el = WPM_ELEMENT_NONE ;
@@ -316,6 +332,13 @@ void keyer_panic( void )
316332} /* keyer_panic() */
317333
318334
335+ void keyer_set_humanizer_level ( float level )
336+ {
337+ s_humanizer_level = clamp ( level , KEYER_HUMANIZER_LEVEL_MIN , KEYER_HUMANIZER_LEVEL_MAX );
338+
339+ } /* keyer_set_humanizer_level() */
340+
341+
319342void keyer_set_paddle_invert ( bool invert )
320343{
321344 config_t config ;
@@ -877,21 +900,24 @@ static void do_state_autokey( tick_t tick, bool new_state )
877900 if ( wpm_element_is_keyed ( s_el ) )
878901 {
879902 s_lockout_el = s_el ;
880- s_el_stop_tick = tick + s_ticks [ s_el ];
903+ s_el_stop_tick = tick
904+ + humanize_delay ( s_ticks [ s_el ] );
881905 s_el_stop_tick_vld = true;
882- s_el_start_tick = tick + s_ticks [ s_el ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ];
906+ s_el_start_tick = tick
907+ + humanize_delay ( s_ticks [ s_el ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] );
883908 s_el_start_tick_vld = true;
884909 set_keyed ( true );
885910 }
886911 else
887912 {
888913 s_el_stop_tick = 0 ;
889914 s_el_stop_tick_vld = false;
890- s_el_start_tick = tick + s_ticks [ s_el ]
891- - ( prev_lockout_el_was_keyed ?
892- s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] : 0 )
893- - ( prev_el_was_letter_space ?
894- ( s_ticks [ WPM_ELEMENT_LETTER_SPACE ] - s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] ) : 0 );
915+ s_el_start_tick = tick
916+ + humanize_delay ( s_ticks [ s_el ]
917+ - ( prev_lockout_el_was_keyed ?
918+ s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] : 0 )
919+ - ( prev_el_was_letter_space ?
920+ ( s_ticks [ WPM_ELEMENT_LETTER_SPACE ] - s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] ) : 0 ) );
895921 s_el_start_tick_vld = true;
896922 }
897923 }
@@ -913,9 +939,11 @@ static void do_state_dashes( tick_t tick, bool new_state )
913939 // Activate keyer hardware
914940 s_el = WPM_ELEMENT_DASH ;
915941 s_lockout_el = s_el ;
916- s_el_stop_tick = tick + s_ticks [ WPM_ELEMENT_DASH ];
942+ s_el_stop_tick = tick
943+ + humanize_delay ( s_ticks [ WPM_ELEMENT_DASH ] );
917944 s_el_stop_tick_vld = true;
918- s_el_start_tick = tick + s_ticks [ WPM_ELEMENT_DASH ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ];
945+ s_el_start_tick = tick
946+ + humanize_delay ( s_ticks [ WPM_ELEMENT_DASH ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] );
919947 s_el_start_tick_vld = true;
920948 set_keyed ( true );
921949 }
@@ -937,9 +965,11 @@ static void do_state_dots( tick_t tick, bool new_state )
937965 // Activate keyer hardware
938966 s_el = WPM_ELEMENT_DOT ;
939967 s_lockout_el = s_el ;
940- s_el_stop_tick = tick + s_ticks [ WPM_ELEMENT_DOT ];
968+ s_el_stop_tick = tick
969+ + humanize_delay ( s_ticks [ WPM_ELEMENT_DOT ] );
941970 s_el_stop_tick_vld = true;
942- s_el_start_tick = tick + s_ticks [ WPM_ELEMENT_DOT ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ];
971+ s_el_start_tick = tick
972+ + humanize_delay ( s_ticks [ WPM_ELEMENT_DOT ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] );
943973 s_el_start_tick_vld = true;
944974 set_keyed ( true );
945975 }
@@ -961,9 +991,11 @@ static void do_state_interleaved( tick_t tick, bool new_state )
961991 // Activate keyer hardware
962992 s_el = ( s_lockout_el == WPM_ELEMENT_DOT ? WPM_ELEMENT_DASH : WPM_ELEMENT_DOT );
963993 s_lockout_el = s_el ;
964- s_el_stop_tick = tick + s_ticks [ s_el ];
994+ s_el_stop_tick = tick
995+ + humanize_delay ( s_ticks [ s_el ] );
965996 s_el_stop_tick_vld = true;
966- s_el_start_tick = tick + s_ticks [ s_el ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ];
997+ s_el_start_tick = tick
998+ + humanize_delay ( s_ticks [ s_el ] + s_ticks [ WPM_ELEMENT_ELEMENT_SPACE ] );
967999 s_el_start_tick_vld = true;
9681000 set_keyed ( true );
9691001 }
@@ -1113,6 +1145,20 @@ static state_t get_next_state( void )
11131145} /* get_next_state() */
11141146
11151147
1148+ static tick_t humanize_delay ( tick_t delay )
1149+ {
1150+ // Early check to avoid expensive floating point operations if not needed
1151+ if ( s_humanizer_level == KEYER_HUMANIZER_OFF )
1152+ return ( delay );
1153+
1154+ float rand = ( float )random () / ( float )RANDOM_MAX ;
1155+ tick_t offset = ( tick_t )roundf ( ( rand * s_humanizer_level ) * ( 0.5f * s_ticks [ WPM_ELEMENT_DOT ] ) );
1156+
1157+ return ( delay + offset );
1158+
1159+ } /* humanize_delay() */
1160+
1161+
11161162static void set_keyed ( bool keyed )
11171163{
11181164 s_keyed = keyed ;
0 commit comments