X-Git-Url: https://git.cworth.org/git?p=mnemon;a=blobdiff_plain;f=mnemon.c;h=f869993061de67ad9332bbe3b77a8753ab882310;hp=054e21cb59494210f1eccfb6b236482beb6ca92f;hb=e213a74c688dc475578348ac5e0e438055d11311;hpb=76e8fc87b1de4f8967ad86287aa026956074c284 diff --git a/mnemon.c b/mnemon.c index 054e21c..f869993 100644 --- a/mnemon.c +++ b/mnemon.c @@ -1,9 +1,10 @@ -/* - * Copyright © 2006 Carl Worth +/* mnemon - A memory training library + * + * Copyright © 2006,2011 Carl Worth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) + * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, @@ -16,6 +17,8 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." */ +#include "mnemon.h" + /* for asprintf */ #define _GNU_SOURCE #include @@ -26,6 +29,7 @@ #include #include +#include #include #include #include @@ -41,6 +45,8 @@ do { \ assert (NOT_REACHED); \ } while (0) +#define unused(foo) foo __attribute__((unused)) + typedef int bool_t; typedef struct _item { @@ -49,12 +55,12 @@ typedef struct _item { char *response; } item_t; -typedef struct _bin { +struct _bin { int score; int items_size; int num_items; item_t **items; -} bin_t; +}; typedef enum { CATEGORY_ORDER_RANDOM, @@ -64,10 +70,12 @@ typedef enum { typedef enum { CHALLENGE_TYPE_TEXT, CHALLENGE_TYPE_IMAGE, - CHALLENGE_TYPE_AUDIO + CHALLENGE_TYPE_AUDIO, + CHALLENGE_TYPE_MIDI, + CHALLENGE_TYPE_TEXT_TO_SPEECH } challenge_type_t; -typedef struct _category { +struct _category { char *name; int items_size; int num_items; @@ -80,24 +88,9 @@ typedef struct _category { int bin_zero_head; /* Support challenges of non-text types (image, audio, etc.) */ challenge_type_t challenge_type; -} category_t; - -typedef struct _mnemon { - char *dir_name; - - int categories_size; - int num_categories; - category_t *categories; - - int bins_size; - int num_bins; - bin_t *bins; - - int to_introduce; - int to_master; - int unlearned; - int mastered; -} mnemon_t; + /* Whether to repeat afterwards (for a little extra reinforcement) */ + bool_t repeat; +}; static void * xmalloc (size_t size) @@ -208,6 +201,7 @@ category_init (category_t *category, category->time_limit = 0.0; category->bin_zero_head = 0; category->challenge_type = CHALLENGE_TYPE_TEXT; + category->repeat = 0; } static void @@ -288,9 +282,17 @@ category_print (category_t *category, case CHALLENGE_TYPE_AUDIO: fprintf (file, "audio"); break; + case CHALLENGE_TYPE_MIDI: + fprintf (file, "midi"); + break; + case CHALLENGE_TYPE_TEXT_TO_SPEECH: + fprintf (file, "text-to-speech"); + break; } fprintf (file, "\n\n"); + fprintf (file, "repeat = %d\n\n", category->repeat); + for (i = 0; i < category->num_items; i++) { item = &category->items[i]; if (i != 0) @@ -394,7 +396,7 @@ bin_num_items_matching (bin_t *bin, return num_items; } -static void +void mnemon_init (mnemon_t *mnemon) { char *home; @@ -419,7 +421,7 @@ mnemon_init (mnemon_t *mnemon) mnemon->mastered = -1; } -static void +void mnemon_fini (mnemon_t *mnemon) { int i; @@ -563,7 +565,7 @@ trim_space (char *string) return string; } -static void +void mnemon_load_category (mnemon_t *mnemon, const char *name) { @@ -575,6 +577,7 @@ mnemon_load_category (mnemon_t *mnemon, char *path; category_t *category; int i; + struct stat st; path = xmalloc (strlen (mnemon->dir_name) + 1 + strlen (name) + 1); sprintf (path, "%s/%s", mnemon->dir_name, name); @@ -586,6 +589,12 @@ mnemon_load_category (mnemon_t *mnemon, exit (1); } + fstat (fileno(file), &st); + if (! S_ISREG(st.st_mode)) { + fprintf (stderr, "Error: File %s is not a regular file.\n", path); + exit (1); + } + category = mnemon_get_category (mnemon, name); #define READ_LINE do { \ @@ -654,11 +663,20 @@ mnemon_load_category (mnemon_t *mnemon, category->challenge_type = CHALLENGE_TYPE_IMAGE; } else if (strcmp (value, "audio") == 0) { category->challenge_type = CHALLENGE_TYPE_AUDIO; + } else if (strcmp (value, "midi") == 0) { + category->challenge_type = CHALLENGE_TYPE_MIDI; + } else if (strcmp (value, "text-to-speech") == 0) { + category->challenge_type = CHALLENGE_TYPE_TEXT_TO_SPEECH; } else { fprintf (stderr, "Unknown value for \"challenge\" option \"%s\" at %s:%d\n", value, path, line_count); exit (1); } + } else if (strcmp (name, "repeat") == 0) { + if (strcmp (value, "0") == 0) + category->repeat = 0; + else + category->repeat = 1; } else { fprintf (stderr, "Unknown option %s at %s:%d\n", name, path, line_count); @@ -718,7 +736,7 @@ mnemon_load_category (mnemon_t *mnemon, } } -static void +void mnemon_load (mnemon_t *mnemon) { DIR *dir; @@ -747,7 +765,7 @@ mnemon_load (mnemon_t *mnemon) closedir (dir); } -static void +void mnemon_save (mnemon_t *mnemon) { int i, err; @@ -886,7 +904,7 @@ mnemon_item_in_category_of_length (void *closure, item_t *item) item_in_category_of_length_closure_t *iicolc = closure; mnemon_t *mnemon = iicolc->mnemon; category_t *category = iicolc->category; - int length = iicolc->length; + unsigned int length = iicolc->length; if (mnemon_item_category (mnemon, item) != category) return 0; @@ -979,7 +997,7 @@ print_histogram_bar (double size, printf ("\n"); } -static void +void mnemon_print_histogram (mnemon_t *mnemon, const char *category_name, int length) @@ -1041,6 +1059,7 @@ mnemon_handle_command (mnemon_t *mnemon, const char *arg; int len; switch (command[0]) { + /* 'h' for histogram */ case 'h': { char *category = NULL; @@ -1059,6 +1078,12 @@ mnemon_handle_command (mnemon_t *mnemon, mnemon_print_histogram (mnemon, category, length); } break; + /* 'r' for repeat */ + case 'r': + { + /* Nothing necessary for repeating. */ + } + break; default: printf ("Unknown command: %s\n", command); break; @@ -1093,13 +1118,11 @@ mnemon_handle_response (mnemon_t *mnemon, (time_limit == 0.0 || response_time < time_limit)) { item->score++; - mnemon->to_master--; /* We reserve an item score of 0 for an item that has * never been asked. */ if (item->score == 0) { item->score = 1; mnemon->unlearned--; - mnemon->to_master--; printf ("You got it!"); } else if (item->score < 0) { printf ("Yes---just give me %d more.", @@ -1108,6 +1131,8 @@ mnemon_handle_response (mnemon_t *mnemon, printf ("On your first try, no less!"); } else { printf ("Masterful (%dx).", item->score); + if (mnemon->to_master) + mnemon->to_master--; } } else { if (! correct) @@ -1123,12 +1148,13 @@ mnemon_handle_response (mnemon_t *mnemon, printf (" Oops, you knew that, right? (%dx)\n ", item->score); mnemon->unlearned++; - /* We add three here, (rather than just 2 to track the - * change in the item's score below), as an extra - * penalty. If the user is forgetting stuff learned - * previously, then more time should be spent on mastering - * than learning new items. */ - mnemon->to_master += item->score + 3; + /* We increase to_master here as an extra penalty. If the + * user is forgetting stuff learned previously, then more + * time should be spent on mastering than learning new + * items. Note that we only do this during the initial + * phase while new items are still being introduced. */ + if (mnemon->to_introduce) + mnemon->to_master++; /* We go to -2 to force a little extra reinforcement * when re-learning an item, (otherwise, it will often * get asked again immediately where it is easy to get @@ -1136,7 +1162,6 @@ mnemon_handle_response (mnemon_t *mnemon, item->score = -2; } else { item->score--; - mnemon->to_master++; } } @@ -1182,6 +1207,12 @@ mnemon_show_challenge (mnemon_t *mnemon, case CHALLENGE_TYPE_AUDIO: program = "play"; break; + case CHALLENGE_TYPE_MIDI: + program = "timidity -Os"; + break; + case CHALLENGE_TYPE_TEXT_TO_SPEECH: + program = "mnemon-tts"; + break; } xasprintf (&command, "%s %s/%s >/dev/null 2>&1 &", @@ -1193,7 +1224,8 @@ mnemon_show_challenge (mnemon_t *mnemon, } static void -mnemon_hide_challenge (mnemon_t *mnemon, challenge_type_t challenge_type) +mnemon_hide_challenge (unused (mnemon_t *mnemon), + challenge_type_t challenge_type) { char * command; @@ -1208,7 +1240,7 @@ mnemon_hide_challenge (mnemon_t *mnemon, challenge_type_t challenge_type) free (command); } -static void +void mnemon_do_challenges (mnemon_t *mnemon) { bin_t *bin; @@ -1291,43 +1323,14 @@ mnemon_do_challenges (mnemon_t *mnemon) free (response); /* Replay audio challenges for reinforcement. */ - if (category->challenge_type == CHALLENGE_TYPE_AUDIO) { + if (category->repeat) + { mnemon_show_challenge (mnemon, category->challenge_type, item->challenge); - sleep (1); + printf ("%s\n", item->challenge); + sleep (2); } } while (mnemon->to_introduce || mnemon->unlearned || mnemon->to_master > 0); } - -int -main (int argc, char *argv[]) -{ - mnemon_t mnemon; - char *response; - - srand (time (NULL)); - - mnemon_init (&mnemon); - - mnemon_load (&mnemon); - - mnemon_do_challenges (&mnemon); - - mnemon_save (&mnemon); - - mnemon_fini (&mnemon); - - mnemon_init (&mnemon); - mnemon_load (&mnemon); - - printf ("Great job.\nHere are your current results:\n"); - mnemon_print_histogram (&mnemon, NULL, 0); - response = readline ("Press enter to quit.\n"); - free (response); - - mnemon_fini (&mnemon); - - return 0; -}