dict.c
来自「WinCE平台上的语音识别程序」· C语言 代码 · 共 1,292 行 · 第 1/3 页
C
1,292 行
free(entry); } free(dict->ci_index); hash_table_free(dict->dict); free(dict);}static voiddict_load(dictT * dict, char *filename, int32 * word_id, int32 use_context){ static char const *rname = "dict_load"; char dict_str[1024]; char pronoun_str[1024]; dict_entry_t *entry; FILE *fs; int32 start_wid = *word_id; int32 err = 0; fs = myfopen(filename, "r"); fscanf(fs, "%s\n", dict_str); if (strcmp(dict_str, "!") != 0) { E_INFO("%s: first line of %s was %s, expecting '!'\n", rname, filename, dict_str); E_INFO("%s: will assume first line contains a word\n", rname); fseek(fs, 0, SEEK_SET); } pronoun_str[0] = '\0'; while (EOF != fscanf(fs, "%s%[^\n]\n", dict_str, pronoun_str)) { entry = _new_dict_entry(dict_str, pronoun_str, use_context); if (!entry) { E_ERROR("Failed to add %s to dictionary\n", dict_str); err = 1; continue; } _dict_list_add(dict, entry); hash_table_enter(dict->dict, entry->word, (void *) *word_id); entry->wid = *word_id; entry->fwid = *word_id; entry->lm_pprob = 0; pronoun_str[0] = '\0'; /* * Look for words of the form ".*(#)". These words are * alternate pronunciations. Also look for phrases * concatenated with '_'. */ { char *p = strrchr(dict_str, '('); /* * For alternate pron. the last car of the word must be ')' * This will handle the case where the word is something like * "(LEFT_PAREN" */ if (dict_str[strlen(dict_str) - 1] != ')') p = NULL; if (p != NULL) { void *wid; if (p) *p = '\0'; if (hash_table_lookup(dict->dict, dict_str, &wid) != 0) { E_FATAL ("%s: Missing first pronunciation for [%s]\nThis means that e.g. [%s(2)] was found with no [%s]\nPlease correct the dictionary and re-run.\n", rname, dict_str, dict_str, dict_str); exit(1); } DFPRINTF((stdout, "Alternate transcription for [%s](wid = %d)\n", entry->word, (int32) wid)); entry->wid = (int32) wid; entry->fwid = (int32) wid; { while (dict->dict_list[(int32) wid]->alt >= 0) wid = (void *) dict->dict_list[(int32) wid]->alt; dict->dict_list[(int32) wid]->alt = *word_id; } } } *word_id = *word_id + 1; } E_INFO("%6d = words in file [%s]\n", *word_id - start_wid, filename); if (fs) fclose(fs); if (err) { E_FATAL("Dictionary errors; cannot continue\n"); }}int32dictStrToWordId(dictT * dict, char const *dict_str, int verbose)/*------------------------------------------------------------* * return the dict id for dict_str *------------------------------------------------------------*/{ static char const *rname = "dict_to_id"; void * dict_id; if (hash_table_lookup(dict->dict, dict_str, &dict_id)) { if (verbose) fprintf(stderr, "%s: did not find %s\n", rname, dict_str); return NO_WORD; } return (int32)dict_id;}int32dict_to_id(dictT * dict, char const *dict_str){ return ((int32) dictStrToWordId(dict, dict_str, FALSE));}char const *dictid_to_str(dictT * dict, int32 id){ return (dict->dict_list[id]->word);}static dict_entry_t *_new_dict_entry(char *word_str, char *pronoun_str, int32 use_context){ dict_entry_t *entry; char *phone[MAX_PRONOUN_LEN]; int32 ciPhoneId[MAX_PRONOUN_LEN]; int32 triphone_ids[MAX_PRONOUN_LEN]; int32 pronoun_len = 0; int32 i; int32 lcTabId; int32 rcTabId; char triphoneStr[80]; char position[256]; /* phone position */ memset(position, 0, sizeof(position)); /* zero out the position matrix */ position[0] = 'b'; /* First phone is at begginging */ while (1) { if (pronoun_len >= MAX_PRONOUN_LEN) { E_ERROR("'%s': Too many phones for bogus hard-coded limit (%d), skipping\n", word_str, MAX_PRONOUN_LEN); return NULL; } phone[pronoun_len] = (char *) nxtarg(&pronoun_str, " \t"); if (*phone[pronoun_len] == 0) break; /* * An '&' in the phone string indicates that this is a word break and * and that the previous phone is in the end of word position and the * next phone is the begining of word position */ if (phone[pronoun_len][0] == '&') { position[pronoun_len - 1] = 'e'; position[pronoun_len] = 'b'; continue; } ciPhoneId[pronoun_len] = phone_to_id(phone[pronoun_len], TRUE); if (ciPhoneId[pronoun_len] == NO_PHONE) { E_ERROR("'%s': Unknown phone '%s'\n", word_str, phone[pronoun_len]); return NULL; } pronoun_len++; } position[pronoun_len - 1] = 'e'; /* Last phone is at the end */ /* * If the position marker sequence 'ee' appears or 'se' appears * the sequence should be '*s'. */ if (position[0] == 'e') /* Also handle single phone word case */ position[0] = 's'; for (i = 0; i < pronoun_len - 1; i++) { if (((position[i] == 'e') || (position[i] == 's')) && (position[i + 1] == 'e')) position[i + 1] = 's'; } if (pronoun_len >= 2) { i = 0; if (use_context) { sprintf(triphoneStr, "%s(%%s,%s)b", phone[i], phone[i + 1]); lcTabId = addToLeftContextTable(triphoneStr); triphone_ids[i] = lcTabId; } else { sprintf(triphoneStr, "%s(%s,%s)b", phone[i], "%s", phone[i + 1]); triphone_ids[i] = phone_to_id(triphoneStr, FALSE); if (triphone_ids[i] < 0) { triphone_ids[i] = phone_to_id(phone[i], TRUE); recordMissingTriphone(triphoneStr); } triphone_ids[i] = bin_mdef_pid2ssid(mdef, phone_map(triphone_ids[i])); } for (i = 1; i < pronoun_len - 1; i++) { sprintf(triphoneStr, "%s(%s,%s)%c", phone[i], phone[i - 1], phone[i + 1], position[i]); triphone_ids[i] = phone_to_id(triphoneStr, FALSE); if (triphone_ids[i] < 0) { triphone_ids[i] = phone_to_id(phone[i], TRUE); recordMissingTriphone(triphoneStr); } triphone_ids[i] = bin_mdef_pid2ssid(mdef,triphone_ids[i]); } if (use_context) { sprintf(triphoneStr, "%s(%s,%%s)e", phone[i], phone[i - 1]); rcTabId = addToRightContextTable(triphoneStr); triphone_ids[i] = rcTabId; } else { sprintf(triphoneStr, "%s(%s,%s)e", phone[i], phone[i - 1], "%s"); triphone_ids[i] = phone_to_id(triphoneStr, FALSE); if (triphone_ids[i] < 0) { triphone_ids[i] = phone_to_id(phone[i], TRUE); recordMissingTriphone(triphoneStr); } triphone_ids[i] = bin_mdef_pid2ssid(mdef,phone_map(triphone_ids[i])); } } /* * It's too hard to model both contexts so I choose to model only * the left context. */ if (pronoun_len == 1) { if (use_context) { sprintf(triphoneStr, "%s(%%s,SIL)s", phone[0]); lcTabId = addToLeftContextTable(triphoneStr); triphone_ids[0] = lcTabId; /* * Put the right context table in the 2 entry */ sprintf(triphoneStr, "%s(SIL,%%s)s", phone[0]); rcTabId = addToRightContextTable(triphoneStr); triphone_ids[1] = rcTabId; } else { sprintf(triphoneStr, "%s(%s,%s)s", phone[0], "%s", "%s"); triphone_ids[0] = phone_to_id(triphoneStr, FALSE); if (triphone_ids[0] < 0) { triphone_ids[0] = phone_to_id(phone[0], TRUE); } triphone_ids[i] = bin_mdef_pid2ssid(mdef,triphone_ids[i]); } } entry = (dict_entry_t *) calloc((size_t) 1, sizeof(dict_entry_t)); entry->word = ckd_salloc(word_str); entry->len = pronoun_len; entry->mpx = use_context; entry->alt = -1; if (pronoun_len != 0) { entry->ci_phone_ids = (int32 *) calloc((size_t) pronoun_len, sizeof(int32)); memcpy(entry->ci_phone_ids, ciPhoneId, pronoun_len * sizeof(int32)); /* * This is a HACK to handle the left right conflict on * single phone words */ if (use_context && (pronoun_len == 1)) pronoun_len += 1; entry->phone_ids = (int32 *) calloc((size_t) pronoun_len, sizeof(int32)); memcpy(entry->phone_ids, triphone_ids, pronoun_len * sizeof(int32)); } else { E_WARN("%s has no pronounciation, will treat as dummy word\n", word_str); } return (entry);}/* * Replace an existing dictionary entry with the given one. The existing entry * might be a dummy placeholder for new OOV words, in which case the new_entry argument * would be TRUE. (Some restrictions at this time on words that can be added; the code * should be self-explanatory.) * Return 1 if successful, 0 if not. */static int32replace_dict_entry(dictT * dict, dict_entry_t * entry, char const *word_str, char *pronoun_str, int32 use_context, int32 new_entry){ char *phone[MAX_PRONOUN_LEN]; int32 ciPhoneId[MAX_PRONOUN_LEN]; int32 triphone_ids[MAX_PRONOUN_LEN]; int32 pronoun_len = 0; int32 i; char triphoneStr[80]; void * idx; int32 basewid; /* For the moment assume left/right context words... */ assert(use_context); /* For the moment, no phrase dictionary stuff... */ while (1) { if (pronoun_len >= MAX_PRONOUN_LEN) { E_ERROR("'%s': Too many phones for bogus hard-coded limit (%d), skipping\n", word_str, MAX_PRONOUN_LEN); return 0; } phone[pronoun_len] = (char *) nxtarg(&pronoun_str, " \t"); if (*phone[pronoun_len] == 0) break; ciPhoneId[pronoun_len] = phone_to_id(phone[pronoun_len], TRUE); if (ciPhoneId[pronoun_len] == NO_PHONE) { E_ERROR("'%s': Unknown phone '%s'\n", word_str, phone[pronoun_len]); return 0; } pronoun_len++; } /* For the moment, no single phone new word... */ if (pronoun_len < 2) { E_ERROR("Pronunciation string too short\n"); return (0); } /* Check if it's an alternative pronunciation; if so base word must exist */ { char *p = strrchr(word_str, '('); if (p && (word_str[strlen(word_str) - 1] == ')')) { *p = '\0'; if (hash_table_lookup(dict->dict, word_str, &idx)) { *p = '('; E_ERROR("Base word missing for %s\n", word_str); return 0; } *p = '('; basewid = (int32) idx; } else basewid = -1; } /* Parse pron; for the moment, the boundary diphones must be already known... */ i = 0; sprintf(triphoneStr, "%s(%%s,%s)b", phone[i], phone[i + 1]); if (hash_table_lookup(lcHT, triphoneStr, &idx) < 0) { E_ERROR("Unknown left diphone '%s'\n", triphoneStr); return (0); } triphone_ids[i] = (int32) idx; for (i = 1; i < pronoun_len - 1; i++) { sprintf(triphoneStr, "%s(%s,%s)", phone[i], phone[i - 1], phone[i + 1]); triphone_ids[i] = phone_to_id(triphoneStr, FALSE); if (triphone_ids[i] < 0) triphone_ids[i] = phone_to_id(phone[i], TRUE); triphone_ids[i] = bin_mdef_pid2ssid(mdef,triphone_ids[i]); } sprintf(triphoneStr, "%s(%s,%%s)e", phone[i], phone[i - 1]); if (hash_table_lookup(rcHT, triphoneStr, &idx) < 0) { E_ERROR("Unknown right diphone '%s'\n", triphoneStr); return (0); } triphone_ids[i] = (int32) idx; /* * Set up dictionary entry. Free the existing attributes (where applicable) and * replace with new ones. */ entry->len = pronoun_len; entry->mpx = use_context; free(entry->word); free(entry->ci_phone_ids); free(entry->phone_ids); entry->word = ckd_salloc(word_str); entry->ci_phone_ids = ckd_calloc((size_t) pronoun_len, sizeof(int32)); entry->phone_ids = ckd_calloc((size_t) pronoun_len, sizeof(int32)); memcpy(entry->ci_phone_ids, ciPhoneId, pronoun_len * sizeof(int32)); memcpy(entry->phone_ids, triphone_ids, pronoun_len * sizeof(int32)); /* Update alternatives linking if adding a new entry (not updating existing one) */ if (new_entry) { entry->alt = -1; if (basewid >= 0) { entry->alt = dict->dict_list[(int32) basewid]->alt; dict->dict_list[(int32) basewid]->alt = entry->wid; entry->wid = entry->fwid = (int32) basewid; } } return (1);}/* * Add a new word to the dictionary, replacing a dummy placeholder. Or replace an * existing non-dummy word in the dictionary. * Return the word id of the entry updated if successful. If any error, return -1. */int32dict_add_word(dictT * dict, char const *word, char *pron){ dict_entry_t *entry; int32 wid, new_entry; /* Word already exists */ new_entry = 0; if ((wid = kb_get_word_id(word)) < 0) { if (first_dummy > last_dummy) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?